Decompiled source of ValheimCartographer v1.0.1

plugins\ValheimCartographer\ValheimCartographer.dll

Decompiled 3 months 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.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;
using ValheimCartographer.Compass;
using ValheimCartographer.State;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ValheimCartographer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Restrict map access to cartography table interactions")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("ValheimCartographer")]
[assembly: AssemblyTitle("ValheimCartographer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimCartographer
{
	[BepInPlugin("valheimcartographer.mapgate", "ValheimCartographer", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class ValheimCartographerPlugin : BaseUnityPlugin
	{
		public const string ModGuid = "valheimcartographer.mapgate";

		public const string ModName = "ValheimCartographer";

		public const string ModVersion = "1.0.1";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> ModEnabled;

		internal static ConfigEntry<bool> HideMinimapWhenLocked;

		internal static ConfigEntry<bool> BlockBossStoneMapPing;

		internal static ConfigEntry<bool> DebugLogging;

		internal static ConfigEntry<bool> CompassEnabled;

		internal static ConfigEntry<int> CompassIronCost;

		internal static ConfigEntry<int> CompassWoodCost;

		internal static ConfigEntry<float> CompassHudOffsetY;

		internal static ConfigEntry<float> CompassRibbonUsableWidth;

		internal static ConfigEntry<float> CompassHudTrackOffsetY;

		internal static ConfigEntry<float> CompassHudScale;

		internal static ConfigEntry<float> CompassHudSlidePixels;

		internal static ConfigEntry<float> CompassHudSlideSmoothTime;

		internal static ConfigEntry<int> CompassHudSortOffsetFromHud;

		private Harmony _harmony;

		internal static ValheimCartographerPlugin Instance { get; private set; }

		private void Awake()
		{
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable map gating.");
			HideMinimapWhenLocked = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "HideMinimapWhenLocked", true, "Hide the small minimap when map access is not granted via a cartography table.");
			BlockBossStoneMapPing = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "BlockBossStoneMapPing", true, "Prevent boss stones and similar from opening or pinging the map.");
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "Verbose Harmony / state logging.");
			CompassEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Compass", "Enabled", true, "Enable the craftable compass item and HUD.");
			CompassIronCost = ((BaseUnityPlugin)this).Config.Bind<int>("Compass", "IronCost", 1, "Iron ingots required to craft the compass at a forge.");
			CompassWoodCost = ((BaseUnityPlugin)this).Config.Bind<int>("Compass", "WoodCost", 5, "Fine wood (Finewood) required to craft the compass at a forge.");
			CompassHudOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Compass", "HudTopInsetY", 10f, "Distance from the top of the screen to the compass (pixels at 1080p reference). Lower = closer to the top edge.");
			CompassRibbonUsableWidth = ((BaseUnityPlugin)this).Config.Bind<float>("Compass", "RibbonUsableWidth", 873f, "Width of the clipped ribbon viewport over Ribbon_backing (pixels at 1080p reference).");
			CompassHudTrackOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Compass", "HudTrackOffsetY", 0f, "Additional vertical offset of the ribbon mask within the backing; positive moves the mask down (pixels at 1080p reference).");
			CompassHudScale = ((BaseUnityPlugin)this).Config.Bind<float>("Compass", "HudStripScale", 0.28f, "Uniform scale for the whole compass HUD (backing + ribbon). 1 = native pixel size at 1080p reference; lower = smaller on screen.");
			CompassHudSlidePixels = ((BaseUnityPlugin)this).Config.Bind<float>("Compass", "HudSlidePixels", 220f, "When hiding for UI (inventory, map, etc.), how far to slide the compass on the Y axis (reference pixels). Positive = off toward the top of the screen; flip sign if it moves the wrong way.");
			CompassHudSlideSmoothTime = ((BaseUnityPlugin)this).Config.Bind<float>("Compass", "HudSlideSmoothTime", 0.12f, "Seconds for the compass slide when opening/closing other UI.");
			CompassHudSortOffsetFromHud = ((BaseUnityPlugin)this).Config.Bind<int>("Compass", "HudCanvasSortOffset", -1, "Added to vanilla Hud canvas sortingOrder (read at runtime from the same canvas as the teleport/sleep black screen). Negative draws the compass under that overlay so portal fades cover it; adjust if layering looks wrong.");
			CompassItemSetup.Register();
			new GameObject("ValheimCartographer_CompassHud").AddComponent<CompassHud>();
			_harmony = new Harmony("valheimcartographer.mapgate");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			Log.LogInfo((object)"ValheimCartographer 1.0.1 loaded.");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchAll("valheimcartographer.mapgate");
			}
			((BaseUnityPlugin)this).Config.Save();
		}

		internal static void LogDebug(string message)
		{
			if (DebugLogging.Value)
			{
				Log.LogDebug((object)message);
			}
		}
	}
}
namespace ValheimCartographer.State
{
	public static class MapAccessState
	{
		public static bool IsCartographyAccessActive { get; private set; }

		public static MapTable? ActiveTable { get; private set; }

		public static void BeginCartographyAccess(MapTable table)
		{
			IsCartographyAccessActive = true;
			ActiveTable = table;
		}

		public static void EndCartographyAccess()
		{
			IsCartographyAccessActive = false;
			ActiveTable = null;
		}
	}
}
namespace ValheimCartographer.Patches
{
	[HarmonyPatch]
	public static class CartographyTablePatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(MapTable), "OnRead", new Type[]
		{
			typeof(Switch),
			typeof(Humanoid),
			typeof(ItemData)
		})]
		[HarmonyPatch(typeof(MapTable), "OnRead", new Type[]
		{
			typeof(Switch),
			typeof(Humanoid),
			typeof(ItemData),
			typeof(bool)
		})]
		private static void OnReadPrefix(MapTable __instance, ItemData? item)
		{
			if (ValheimCartographerPlugin.ModEnabled.Value && !((Object)(object)Player.m_localPlayer == (Object)null) && item == null)
			{
				MapAccessState.BeginCartographyAccess(__instance);
				ValheimCartographerPlugin.LogDebug("Cartography access begin (MapTable.OnRead prefix)");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(MapTable), "OnRead", new Type[]
		{
			typeof(Switch),
			typeof(Humanoid),
			typeof(ItemData)
		})]
		[HarmonyPatch(typeof(MapTable), "OnRead", new Type[]
		{
			typeof(Switch),
			typeof(Humanoid),
			typeof(ItemData),
			typeof(bool)
		})]
		private static void OnReadPostfix(ItemData? item)
		{
			if (ValheimCartographerPlugin.ModEnabled.Value && !((Object)(object)Player.m_localPlayer == (Object)null) && item == null)
			{
				Minimap.instance.SetMapMode((MapMode)2);
				ValheimCartographerPlugin.LogDebug("Map opened from MapTable.OnRead postfix");
			}
		}
	}
	[HarmonyPatch(typeof(Minimap))]
	public static class MinimapPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch("SetMapMode")]
		private static bool SetMapMode_Prefix(MapMode mode)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			if (!ValheimCartographerPlugin.ModEnabled.Value)
			{
				return true;
			}
			if ((int)mode == 2 && !MapAccessState.IsCartographyAccessActive)
			{
				ValheimCartographerPlugin.LogDebug("Blocked SetMapMode(Large) — not at cartography table");
				return false;
			}
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch("SetMapMode")]
		private static void SetMapMode_Postfix(MapMode mode)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (ValheimCartographerPlugin.ModEnabled.Value && (int)mode <= 1)
			{
				MapAccessState.EndCartographyAccess();
				ValheimCartographerPlugin.LogDebug($"Map closed or minimized ({mode}); cartography access cleared");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Update")]
		private static void Update_Postfix(Minimap __instance)
		{
			if (ValheimCartographerPlugin.ModEnabled.Value && ValheimCartographerPlugin.HideMinimapWhenLocked.Value && (Object)(object)__instance.m_smallRoot != (Object)null && !MapAccessState.IsCartographyAccessActive)
			{
				__instance.m_smallRoot.SetActive(false);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("ShowPointOnMap")]
		private static bool ShowPointOnMap_Prefix()
		{
			if (!ValheimCartographerPlugin.ModEnabled.Value || !ValheimCartographerPlugin.BlockBossStoneMapPing.Value)
			{
				return true;
			}
			if (!MapAccessState.IsCartographyAccessActive)
			{
				ValheimCartographerPlugin.LogDebug("Blocked ShowPointOnMap");
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Player))]
	public static class PlayerPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("UpdateStations")]
		private static void CloseMapWhenTooFarFromTable(Player __instance)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (!ValheimCartographerPlugin.ModEnabled.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !MapAccessState.IsCartographyAccessActive || (Object)(object)MapAccessState.ActiveTable == (Object)null)
			{
				return;
			}
			MapTable activeTable = MapAccessState.ActiveTable;
			if (!((Object)(object)activeTable == (Object)null))
			{
				float num = Vector3.Distance(((Component)__instance).transform.position, ((Component)activeTable).transform.position);
				float num2 = __instance.m_maxInteractDistance + 1.75f;
				if (num > num2)
				{
					ValheimCartographerPlugin.LogDebug("Closing map — player left cartography table range");
					Minimap.instance.SetMapMode((MapMode)1);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateWishbone")]
	public static class PlayerWishboneGuard
	{
		private static bool Prepare()
		{
			return AccessTools.Method(typeof(Player), "UpdateWishbone", (Type[])null, (Type[])null) != null;
		}

		private static bool Prefix(Player __instance)
		{
			if (!ValheimCartographerPlugin.ModEnabled.Value)
			{
				return true;
			}
			if (CompassItemSetup.IsCompassEquipped(__instance))
			{
				return false;
			}
			return true;
		}
	}
}
namespace ValheimCartographer.Compass
{
	public static class CompassConstants
	{
		public const string PrefabName = "VC_CartographerCompass";

		public const string NameToken = "$vc_cartographer_compass";

		public const string DescToken = "$vc_cartographer_compass_desc";
	}
	internal static class CompassCustomModelLoader
	{
		private static class SimpleObjLoader
		{
			private readonly struct Corner
			{
				public readonly Vector3 Pos;

				public readonly Vector2 Uv;

				public readonly Vector3 Normal;

				public Corner(Vector3 pos, Vector2 uv, Vector3 normal)
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					//IL_0002: Unknown result type (might be due to invalid IL or missing references)
					//IL_0008: Unknown result type (might be due to invalid IL or missing references)
					//IL_0009: Unknown result type (might be due to invalid IL or missing references)
					//IL_000f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0010: Unknown result type (might be due to invalid IL or missing references)
					Pos = pos;
					Uv = uv;
					Normal = normal;
				}
			}

			public static bool TryLoad(string path, out Mesh? mesh)
			{
				//IL_0088: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_029c: Unknown result type (might be due to invalid IL or missing references)
				//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
				//IL_02ad: Expected O, but got Unknown
				//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
				//IL_020c: Unknown result type (might be due to invalid IL or missing references)
				//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
				//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
				mesh = null;
				List<Vector3> list = new List<Vector3>();
				List<Vector2> list2 = new List<Vector2>();
				List<Vector3> list3 = new List<Vector3>();
				string[] array;
				try
				{
					array = File.ReadAllLines(path, Encoding.UTF8);
				}
				catch
				{
					return false;
				}
				string[] array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					string text = array2[i].Trim();
					if (text.Length == 0 || text[0] == '#')
					{
						continue;
					}
					if (text.StartsWith("v ", StringComparison.Ordinal))
					{
						float[] array3 = SplitFloats(text, 3);
						if (array3 != null)
						{
							list.Add(new Vector3(array3[0], array3[1], array3[2]));
						}
					}
					else if (text.StartsWith("vt ", StringComparison.Ordinal))
					{
						float[] array4 = SplitFloats(text, 2);
						if (array4 != null)
						{
							list2.Add(new Vector2(array4[0], array4[1]));
						}
					}
					else if (text.StartsWith("vn ", StringComparison.Ordinal))
					{
						float[] array5 = SplitFloats(text, 3);
						if (array5 != null)
						{
							list3.Add(new Vector3(array5[0], array5[1], array5[2]));
						}
					}
				}
				List<(string, List<string>)> list4 = CollectFaceGroups(array);
				if (list4.Count == 0)
				{
					return false;
				}
				var (arg, list5) = ChooseLargestFaceGroup(list4);
				if (list5 == null || list5.Count == 0)
				{
					return false;
				}
				if (ValheimCartographerPlugin.DebugLogging.Value && list4.Count > 1)
				{
					ValheimCartographerPlugin.Log.LogInfo((object)$"Compass OBJ: {list4.Count} object/group(s); using \"{arg}\" ({list5.Count} face line(s)).");
				}
				List<Vector3> list6 = new List<Vector3>();
				List<Vector2> list7 = new List<Vector2>();
				List<Vector3> list8 = new List<Vector3>();
				List<int> list9 = new List<int>();
				foreach (string item in list5)
				{
					List<Corner> list10 = ParseFaceCorners(item, list, list2, list3);
					if (list10.Count < 3)
					{
						continue;
					}
					int count = list6.Count;
					foreach (Corner item2 in list10)
					{
						list6.Add(item2.Pos);
						list7.Add(item2.Uv);
						list8.Add(item2.Normal);
					}
					for (int j = 1; j < list10.Count - 1; j++)
					{
						list9.Add(count);
						list9.Add(count + j);
						list9.Add(count + j + 1);
					}
				}
				if (list6.Count == 0 || list9.Count < 3)
				{
					return false;
				}
				mesh = new Mesh
				{
					name = "CompassObjMesh"
				};
				mesh.indexFormat = (IndexFormat)(list6.Count > 65535);
				mesh.SetVertices(list6);
				mesh.SetUVs(0, list7);
				bool flag = false;
				foreach (Vector3 item3 in list8)
				{
					Vector3 current2 = item3;
					if (((Vector3)(ref current2)).sqrMagnitude > 1E-08f)
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					mesh.SetNormals(list8);
				}
				else
				{
					mesh.RecalculateNormals();
				}
				mesh.SetTriangles(list9, 0);
				mesh.RecalculateBounds();
				return true;
			}

			private static List<(string name, List<string> faces)> CollectFaceGroups(string[] lines)
			{
				List<(string, List<string>)> list = new List<(string, List<string>)>();
				List<string> list2 = null;
				string item = "default";
				for (int i = 0; i < lines.Length; i++)
				{
					string text = lines[i].Trim();
					if (text.Length == 0 || text[0] == '#')
					{
						continue;
					}
					if (text.StartsWith("o ", StringComparison.Ordinal) || text.StartsWith("g ", StringComparison.Ordinal))
					{
						string text2 = text.Substring(2).Trim();
						if (string.IsNullOrEmpty(text2))
						{
							text2 = "unnamed";
						}
						item = text2;
						list2 = new List<string>();
						list.Add((item, list2));
					}
					else if (text.StartsWith("f ", StringComparison.Ordinal))
					{
						if (list2 == null)
						{
							list2 = new List<string>();
							list.Add((item, list2));
						}
						list2.Add(text);
					}
				}
				return list;
			}

			private static int EstimateTriangleFanCount(string fLine)
			{
				int num = fLine.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries).Length - 1;
				if (num < 3)
				{
					return 0;
				}
				return num - 2;
			}

			private static (string name, List<string>? faces) ChooseLargestFaceGroup(List<(string name, List<string> faces)> groups)
			{
				List<string> list = null;
				string text = "";
				int num = -1;
				foreach (var (text2, list2) in groups)
				{
					if (list2.Count == 0)
					{
						continue;
					}
					int num2 = 0;
					foreach (string item in list2)
					{
						num2 += EstimateTriangleFanCount(item);
					}
					if (num2 > 0)
					{
						if (num2 > num)
						{
							num = num2;
							list = list2;
							text = text2;
						}
						else if (num2 == num && list != null && LooksLikeReferencePlane(text) && !LooksLikeReferencePlane(text2))
						{
							list = list2;
							text = text2;
						}
					}
				}
				return (text, list);
			}

			private static bool LooksLikeReferencePlane(string name)
			{
				if (string.IsNullOrEmpty(name))
				{
					return false;
				}
				string text = name.Trim().ToLowerInvariant();
				if (!(text == "plane"))
				{
					return text.StartsWith("plane.", StringComparison.Ordinal);
				}
				return true;
			}

			private static List<Corner> ParseFaceCorners(string line, List<Vector3> vIn, List<Vector2> vtIn, List<Vector3> vnIn)
			{
				//IL_00d5: 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_00dc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_0118: Unknown result type (might be due to invalid IL or missing references)
				//IL_011d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0155: Unknown result type (might be due to invalid IL or missing references)
				//IL_0157: Unknown result type (might be due to invalid IL or missing references)
				//IL_0159: Unknown result type (might be due to invalid IL or missing references)
				//IL_0111: 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_014d: 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)
				string[] array = line.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
				List<Corner> list = new List<Corner>();
				for (int i = 1; i < array.Length; i++)
				{
					string obj = array[i];
					int result = 0;
					int result2 = 0;
					int result3 = 0;
					string[] array2 = obj.Split(new char[1] { '/' });
					if (array2.Length != 0 && array2[0].Length > 0)
					{
						int.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out result);
					}
					if (array2.Length > 1 && array2[1].Length > 0)
					{
						int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out result2);
					}
					if (array2.Length > 2 && array2[2].Length > 0)
					{
						int.TryParse(array2[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out result3);
					}
					int num = ResolveIndex(result, vIn.Count);
					if (num < 0 || num >= vIn.Count)
					{
						continue;
					}
					Vector3 pos = vIn[num];
					Vector2 uv = Vector2.zero;
					if (result2 != 0 && vtIn.Count > 0)
					{
						int num2 = ResolveIndex(result2, vtIn.Count);
						if (num2 >= 0 && num2 < vtIn.Count)
						{
							uv = vtIn[num2];
						}
					}
					Vector3 normal = Vector3.zero;
					if (result3 != 0 && vnIn.Count > 0)
					{
						int num3 = ResolveIndex(result3, vnIn.Count);
						if (num3 >= 0 && num3 < vnIn.Count)
						{
							normal = vnIn[num3];
						}
					}
					list.Add(new Corner(pos, uv, normal));
				}
				return list;
			}

			private static float[]? SplitFloats(string line, int count)
			{
				string[] array = line.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
				if (array.Length < count + 1)
				{
					return null;
				}
				float[] array2 = new float[count];
				for (int i = 0; i < count; i++)
				{
					if (!float.TryParse(array[i + 1], NumberStyles.Float, CultureInfo.InvariantCulture, out array2[i]))
					{
						return null;
					}
				}
				return array2;
			}

			private static int ResolveIndex(int idx, int count)
			{
				if (count <= 0)
				{
					return -1;
				}
				if (idx > 0)
				{
					return idx - 1;
				}
				if (idx < 0)
				{
					return count + idx;
				}
				return -1;
			}
		}

		private const string BundleFileNoExt = "valheimcartographer_compass";

		private const string BundleFileAlt = "valheimcartographer_compass.bundle";

		private static readonly string[] s_objCandidates = new string[2] { "CompassModel.obj", "compass_model.obj" };

		private static readonly string[] s_textureFallbacks = new string[1] { "DarkTexture.png" };

		public static bool TryApply(GameObject compassPrefab)
		{
			if ((Object)(object)compassPrefab == (Object)null)
			{
				return false;
			}
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			if (string.IsNullOrEmpty(directoryName))
			{
				return false;
			}
			if (TryApplyFromAssetBundle(compassPrefab, directoryName))
			{
				return true;
			}
			if (TryApplyFromObjAndTexture(compassPrefab, directoryName))
			{
				return true;
			}
			return false;
		}

		private static bool TryApplyFromAssetBundle(GameObject compassPrefab, string dir)
		{
			string[] array = new string[2] { "valheimcartographer_compass", "valheimcartographer_compass.bundle" };
			foreach (string text in array)
			{
				string text2 = Path.Combine(dir, text);
				if (!File.Exists(text2))
				{
					continue;
				}
				AssetBundle val = null;
				try
				{
					val = AssetBundle.LoadFromFile(text2);
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					string[] array2 = new string[4] { "CompassWorld", "CompassPrefab", "compass_model", "CompassMesh" };
					foreach (string text3 in array2)
					{
						GameObject val2 = val.LoadAsset<GameObject>(text3);
						if ((Object)(object)val2 != (Object)null && CompassPickupVisual.TryCopyMeshesFromSource(compassPrefab, val2))
						{
							ValheimCartographerPlugin.Log.LogInfo((object)("Compass world model loaded from AssetBundle \"" + text + "\" asset \"" + text3 + "\"."));
							return true;
						}
					}
					GameObject[] array3 = val.LoadAllAssets<GameObject>();
					foreach (GameObject val3 in array3)
					{
						if ((Object)(object)val3 != (Object)null && CompassPickupVisual.TryCopyMeshesFromSource(compassPrefab, val3))
						{
							ValheimCartographerPlugin.Log.LogInfo((object)("Compass world model loaded from AssetBundle \"" + text + "\" asset \"" + ((Object)val3).name + "\"."));
							return true;
						}
					}
				}
				finally
				{
					if (val != null)
					{
						val.Unload(false);
					}
				}
			}
			return false;
		}

		private static bool TryApplyFromObjAndTexture(GameObject compassPrefab, string dir)
		{
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			if (!TryResolveObjPath(dir, out string objPath, out string label))
			{
				return false;
			}
			if (!SimpleObjLoader.TryLoad(objPath, out Mesh mesh) || (Object)(object)mesh == (Object)null)
			{
				ValheimCartographerPlugin.Log.LogWarning((object)("Failed to parse " + label + ". Export OBJ from Blender (File → Export → Wavefront OBJ). Raw FBX is not loaded at runtime."));
				return false;
			}
			Texture2D val = LoadDiffuseTexture(dir, objPath);
			MeshFilter[] componentsInChildren = compassPrefab.GetComponentsInChildren<MeshFilter>(true);
			if (componentsInChildren.Length == 0)
			{
				Object.Destroy((Object)(object)mesh);
				return false;
			}
			MeshRenderer component = ((Component)componentsInChildren[0]).GetComponent<MeshRenderer>();
			Material val2 = (((Object)(object)component != (Object)null) ? ((Renderer)component).sharedMaterial : null);
			if ((Object)(object)val2 == (Object)null)
			{
				ObjectDB instance = ObjectDB.instance;
				GameObject val3 = ((instance != null) ? instance.GetItemPrefab("AmberPearl") : null);
				if ((Object)(object)val3 != (Object)null)
				{
					MeshRenderer componentInChildren = val3.GetComponentInChildren<MeshRenderer>(true);
					val2 = (((Object)(object)componentInChildren != (Object)null) ? ((Renderer)componentInChildren).sharedMaterial : null);
				}
			}
			componentsInChildren[0].sharedMesh = mesh;
			if ((Object)(object)component != (Object)null && (Object)(object)val2 != (Object)null)
			{
				Material val4 = new Material(val2);
				if ((Object)(object)val != (Object)null)
				{
					if (val4.HasProperty("_MainTex"))
					{
						val4.SetTexture("_MainTex", (Texture)(object)val);
					}
					else if (val4.HasProperty("_Diffuse"))
					{
						val4.SetTexture("_Diffuse", (Texture)(object)val);
					}
				}
				((Renderer)component).sharedMaterial = val4;
			}
			string text = (((Object)(object)val != (Object)null) ? (" with texture \"" + ((Object)val).name + "\".") : ".");
			ValheimCartographerPlugin.Log.LogInfo((object)("Compass world model loaded from " + label + text));
			return true;
		}

		private static bool TryResolveObjPath(string dir, out string objPath, out string label)
		{
			string[] array = s_objCandidates;
			foreach (string text in array)
			{
				string text2 = Path.Combine(dir, text);
				if (File.Exists(text2))
				{
					objPath = text2;
					label = text;
					return true;
				}
			}
			objPath = "";
			label = "";
			return false;
		}

		private static Texture2D? LoadDiffuseTexture(string pluginDir, string objPath)
		{
			string text = Path.GetDirectoryName(objPath);
			if (string.IsNullOrEmpty(text))
			{
				text = pluginDir;
			}
			string text2 = ReadMtllibNameFromObj(objPath);
			string[] array = new string[2]
			{
				text2,
				Path.GetFileNameWithoutExtension(objPath) + ".mtl"
			};
			foreach (string text3 in array)
			{
				if (string.IsNullOrEmpty(text3))
				{
					continue;
				}
				string text4 = Path.Combine(text, text3);
				if (!File.Exists(text4))
				{
					continue;
				}
				string text5 = TryParseMapKdFromMtl(text4);
				if (!string.IsNullOrEmpty(text5))
				{
					string path = text5.Replace('/', Path.DirectorySeparatorChar);
					Texture2D val = TryLoadTextureFile(Path.GetFullPath(Path.Combine(text, path)));
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
			}
			array = s_textureFallbacks;
			foreach (string path2 in array)
			{
				Texture2D val2 = TryLoadTextureFile(Path.Combine(pluginDir, path2));
				if ((Object)(object)val2 != (Object)null)
				{
					return val2;
				}
			}
			return null;
		}

		private static string? ReadMtllibNameFromObj(string objPath)
		{
			try
			{
				foreach (string item in File.ReadLines(objPath, Encoding.UTF8))
				{
					string text = item.Trim();
					if (text.Length != 0 && text[0] != '#' && text.StartsWith("mtllib ", StringComparison.Ordinal))
					{
						string text2 = text.Substring(7).Trim();
						return string.IsNullOrEmpty(text2) ? null : text2;
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private static string? TryParseMapKdFromMtl(string mtlPath)
		{
			try
			{
				foreach (string item in File.ReadLines(mtlPath, Encoding.UTF8))
				{
					string text = item.Trim();
					if (text.Length == 0 || text[0] == '#' || !text.StartsWith("map_Kd", StringComparison.OrdinalIgnoreCase))
					{
						continue;
					}
					string[] array = text.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
					if (array.Length < 2)
					{
						continue;
					}
					int num = 1;
					while (num < array.Length && array[num].StartsWith("-", StringComparison.Ordinal))
					{
						switch (array[num].ToLowerInvariant())
						{
						case "-o":
						case "-s":
						case "-t":
							num += 4;
							break;
						case "-bm":
						case "-mm":
						case "-clamp":
							num += 2;
							break;
						case "-cc":
						case "-blendu":
						case "-blendv":
						case "-imfchan":
							num += 2;
							break;
						default:
							num++;
							break;
						}
					}
					if (num < array.Length)
					{
						string text2 = string.Join(" ", array, num, array.Length - num).Trim('"', ' ', '\t');
						return string.IsNullOrEmpty(text2) ? null : text2;
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private static Texture2D? TryLoadTextureFile(string path)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if (!File.Exists(path))
			{
				return null;
			}
			try
			{
				byte[] bytes = File.ReadAllBytes(path);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!CompassIconLoader.TryLoadImageBytes(val, bytes))
				{
					Object.Destroy((Object)(object)val);
					return null;
				}
				((Object)val).name = Path.GetFileNameWithoutExtension(path);
				((Texture)val).wrapMode = (TextureWrapMode)0;
				return val;
			}
			catch
			{
				return null;
			}
		}
	}
	internal static class CompassEquipment
	{
		private static MethodInfo? s_getEquippedInSlot;

		private static object? s_utilitySlotEnum;

		private static bool s_resolved;

		private static void EnsureResolved()
		{
			if (s_resolved)
			{
				return;
			}
			s_resolved = true;
			MethodInfo[] methods = typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name != "GetEquippedItemInSlot")
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length != 1)
				{
					continue;
				}
				Type parameterType = parameters[0].ParameterType;
				if (parameterType.IsEnum)
				{
					try
					{
						s_utilitySlotEnum = Enum.Parse(parameterType, "Utility");
						s_getEquippedInSlot = methodInfo;
						break;
					}
					catch
					{
					}
				}
			}
		}

		public static ItemData? GetUtilityItem(Player? player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return null;
			}
			EnsureResolved();
			if (s_getEquippedInSlot != null && s_utilitySlotEnum != null)
			{
				object? obj = s_getEquippedInSlot.Invoke(inventory, new object[1] { s_utilitySlotEnum });
				ItemData val = (ItemData)((obj is ItemData) ? obj : null);
				if (val != null && val.m_shared?.m_name == "$vc_cartographer_compass")
				{
					return val;
				}
				return null;
			}
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (allItem.m_equipped && !(allItem.m_shared?.m_name != "$vc_cartographer_compass"))
				{
					return allItem;
				}
			}
			return null;
		}
	}
	public sealed class CompassHud : MonoBehaviour
	{
		private Canvas? _canvas;

		private RectTransform? _compassRootRt;

		private RectTransform? _ribbon0;

		private RectTransform? _ribbon1;

		private float _ribbonWidth;

		private float _halfViewport;

		private float _pixelsPerDegree;

		private bool _assetsReady;

		private float _currentRootY;

		private float _smoothVel;

		private bool _hadEquipped;

		private bool _canvasSortSynced;

		private void Awake()
		{
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			BuildUi();
		}

		private void BuildUi()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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_012e: Expected O, but got Unknown
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Expected O, but got Unknown
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			_canvas = ((Component)this).gameObject.AddComponent<Canvas>();
			_canvas.renderMode = (RenderMode)0;
			_canvas.sortingOrder = 400;
			CanvasScaler obj = ((Component)this).gameObject.AddComponent<CanvasScaler>();
			obj.uiScaleMode = (ScaleMode)1;
			obj.referenceResolution = new Vector2(1920f, 1080f);
			((Component)this).gameObject.AddComponent<GraphicRaycaster>();
			if (!CompassUiTextureLoader.TryLoadSprite("Ribbon_backing.png", new Vector2(0.5f, 0.5f), out Sprite sprite) || !CompassUiTextureLoader.TryLoadSprite("Ribbon.png", new Vector2(0f, 0.5f), out Sprite ribbonSprite))
			{
				ValheimCartographerPlugin.Log.LogWarning((object)"Compass HUD: Ribbon.png and/or Ribbon_backing.png missing next to the DLL; compass ribbon will not show.");
				_assetsReady = false;
				((Behaviour)_canvas).enabled = false;
				return;
			}
			Texture2D texture = sprite.texture;
			Texture2D ribbonTex = ribbonSprite.texture;
			_ribbonWidth = ((Texture)ribbonTex).width;
			_pixelsPerDegree = _ribbonWidth / 360f;
			float value = ValheimCartographerPlugin.CompassRibbonUsableWidth.Value;
			float value2 = ValheimCartographerPlugin.CompassHudTrackOffsetY.Value;
			_halfViewport = value * 0.5f;
			GameObject val = new GameObject("CompassRoot");
			val.transform.SetParent(((Component)this).transform, false);
			RectTransform val2 = (_compassRootRt = val.AddComponent<RectTransform>());
			val2.anchorMin = new Vector2(0.5f, 1f);
			val2.anchorMax = new Vector2(0.5f, 1f);
			val2.pivot = new Vector2(0.5f, 1f);
			float value3 = ValheimCartographerPlugin.CompassHudOffsetY.Value;
			_currentRootY = 0f - value3;
			val2.anchoredPosition = new Vector2(0f, _currentRootY);
			val2.sizeDelta = new Vector2((float)((Texture)texture).width, (float)((Texture)texture).height);
			float num = Mathf.Clamp(ValheimCartographerPlugin.CompassHudScale.Value, 0.08f, 1.5f);
			((Transform)val2).localScale = new Vector3(num, num, 1f);
			GameObject val3 = new GameObject("RibbonBacking");
			val3.transform.SetParent(val.transform, false);
			RectTransform obj2 = val3.AddComponent<RectTransform>();
			obj2.anchorMin = Vector2.zero;
			obj2.anchorMax = Vector2.one;
			obj2.offsetMin = Vector2.zero;
			obj2.offsetMax = Vector2.zero;
			Image obj3 = val3.AddComponent<Image>();
			obj3.sprite = sprite;
			obj3.preserveAspect = false;
			((Graphic)obj3).raycastTarget = false;
			GameObject maskGo = new GameObject("RibbonScrollMask");
			maskGo.transform.SetParent(val.transform, false);
			RectTransform obj4 = maskGo.AddComponent<RectTransform>();
			obj4.anchorMin = new Vector2(0.5f, 1f);
			obj4.anchorMax = new Vector2(0.5f, 1f);
			obj4.pivot = new Vector2(0.5f, 0.5f);
			float num2 = (float)(-((Texture)texture).height) * 0.5f - value2;
			obj4.anchoredPosition = new Vector2(0f, num2);
			obj4.sizeDelta = new Vector2(value, (float)((Texture)ribbonTex).height);
			maskGo.AddComponent<RectMask2D>();
			AddRibbon("Ribbon0", out _ribbon0);
			AddRibbon("Ribbon1", out _ribbon1);
			_assetsReady = true;
			((Behaviour)_canvas).enabled = false;
			void AddRibbon(string name, out RectTransform rt)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Expected O, but got Unknown
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				//IL_008e: Unknown result type (might be due to invalid IL or missing references)
				GameObject val4 = new GameObject(name);
				val4.transform.SetParent(maskGo.transform, false);
				rt = val4.AddComponent<RectTransform>();
				rt.anchorMin = new Vector2(0f, 0.5f);
				rt.anchorMax = new Vector2(0f, 0.5f);
				rt.pivot = new Vector2(0f, 0.5f);
				rt.anchoredPosition = Vector2.zero;
				rt.sizeDelta = new Vector2((float)((Texture)ribbonTex).width, (float)((Texture)ribbonTex).height);
				Image obj5 = val4.AddComponent<Image>();
				obj5.sprite = ribbonSprite;
				obj5.type = (Type)0;
				obj5.preserveAspect = false;
				((Graphic)obj5).raycastTarget = false;
			}
		}

		private void TrySyncCanvasSortingBehindHud()
		{
			if (!_canvasSortSynced && !((Object)(object)_canvas == (Object)null) && !((Object)(object)Hud.instance == (Object)null))
			{
				Canvas val = null;
				if ((Object)(object)Hud.instance.m_loadingScreen != (Object)null)
				{
					val = ((Component)Hud.instance.m_loadingScreen).GetComponentInParent<Canvas>();
				}
				if ((Object)(object)val == (Object)null && (Object)(object)Hud.instance.m_rootObject != (Object)null)
				{
					val = Hud.instance.m_rootObject.GetComponent<Canvas>();
				}
				if (!((Object)(object)val == (Object)null))
				{
					_canvas.sortingOrder = val.sortingOrder + ValheimCartographerPlugin.CompassHudSortOffsetFromHud.Value;
					_canvasSortSynced = true;
				}
			}
		}

		private static float NormalizeYawDegrees(float eulerY)
		{
			float num = eulerY % 360f;
			if (num < 0f)
			{
				num += 360f;
			}
			return num;
		}

		private void Update()
		{
			//IL_0156: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: 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)
			if (!_assetsReady || (Object)(object)_canvas == (Object)null || (Object)(object)_compassRootRt == (Object)null || (Object)(object)_ribbon0 == (Object)null || (Object)(object)_ribbon1 == (Object)null)
			{
				return;
			}
			TrySyncCanvasSortingBehindHud();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !CompassItemSetup.IsCompassEquipped(localPlayer))
			{
				((Behaviour)_canvas).enabled = false;
				_hadEquipped = false;
				return;
			}
			float num = 0f - ValheimCartographerPlugin.CompassHudOffsetY.Value;
			float num2 = num + ValheimCartographerPlugin.CompassHudSlidePixels.Value;
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				((Behaviour)_canvas).enabled = false;
				return;
			}
			((Behaviour)_canvas).enabled = true;
			if (!_hadEquipped)
			{
				_hadEquipped = true;
				bool flag = CompassHudVisibility.ShouldHideAnimated();
				_currentRootY = (flag ? num2 : num);
				_smoothVel = 0f;
				_compassRootRt.anchoredPosition = new Vector2(0f, _currentRootY);
			}
			float num3 = (CompassHudVisibility.ShouldHideAnimated() ? num2 : num);
			float num4 = Mathf.Max(0.01f, ValheimCartographerPlugin.CompassHudSlideSmoothTime.Value);
			_currentRootY = Mathf.SmoothDamp(_currentRootY, num3, ref _smoothVel, num4, float.PositiveInfinity, Time.unscaledDeltaTime);
			_compassRootRt.anchoredPosition = new Vector2(0f, _currentRootY);
			float num5 = NormalizeYawDegrees(((Component)main).transform.eulerAngles.y);
			float num6 = Mathf.Repeat(_halfViewport - (num5 + 360f) * _pixelsPerDegree, _ribbonWidth);
			if (num6 > 0.0001f)
			{
				num6 -= _ribbonWidth;
			}
			_ribbon0.anchoredPosition = new Vector2(num6, 0f);
			_ribbon1.anchoredPosition = new Vector2(num6 + _ribbonWidth, 0f);
		}
	}
	internal static class CompassHudVisibility
	{
		internal static bool ShouldHideAnimated()
		{
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return true;
			}
			if (Game.IsPaused())
			{
				return true;
			}
			if (Time.timeScale <= 0f)
			{
				return true;
			}
			if (InventoryGui.IsVisible())
			{
				return true;
			}
			if (TextInput.IsVisible())
			{
				return true;
			}
			if (Minimap.IsOpen())
			{
				return true;
			}
			if (Menu.IsVisible())
			{
				return true;
			}
			if (StoreGui.IsVisible())
			{
				return true;
			}
			if (Console.IsVisible())
			{
				return true;
			}
			return false;
		}
	}
	internal static class CompassIconLoader
	{
		private static readonly MethodInfo? s_imageConversionLoadImage = ResolveImageConversionLoadImage();

		private static MethodInfo? ResolveImageConversionLoadImage()
		{
			return Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule")?.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
			{
				typeof(Texture2D),
				typeof(byte[])
			}, null);
		}

		internal static bool TryLoadImageBytes(Texture2D tex, byte[] bytes)
		{
			if (s_imageConversionLoadImage == null)
			{
				return false;
			}
			object obj = s_imageConversionLoadImage.Invoke(null, new object[2] { tex, bytes });
			if (obj is bool)
			{
				return (bool)obj;
			}
			return false;
		}

		public static Sprite? TryLoadSprite()
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			if (string.IsNullOrEmpty(directoryName))
			{
				return null;
			}
			string text = null;
			string[] array = new string[3] { "icon.png", "Icon.png", "CompassSprite.png" };
			foreach (string path in array)
			{
				string text2 = Path.Combine(directoryName, path);
				if (File.Exists(text2))
				{
					text = text2;
					break;
				}
			}
			if (text == null)
			{
				ValheimCartographerPlugin.Log.LogWarning((object)"No icon.png, Icon.png, or CompassSprite.png next to the plugin DLL; compass will use the wishbone icon.");
				return null;
			}
			byte[] bytes;
			try
			{
				bytes = File.ReadAllBytes(text);
			}
			catch (IOException ex)
			{
				ValheimCartographerPlugin.Log.LogWarning((object)("Could not read " + text + ": " + ex.Message));
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!TryLoadImageBytes(val, bytes))
			{
				ValheimCartographerPlugin.Log.LogWarning((object)((s_imageConversionLoadImage == null) ? "UnityEngine.ImageConversion.LoadImage is not available; compass will use the wishbone icon." : ("Could not decode image: " + text)));
				return null;
			}
			Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			((Object)obj).name = "VC_CartographerIcon";
			return obj;
		}
	}
	internal static class CompassItemPostprocess
	{
		private static readonly FieldInfo[] s_statusEffectFields = ResolveStatusEffectFields();

		private static FieldInfo[] ResolveStatusEffectFields()
		{
			Type nestedType = typeof(ItemData).GetNestedType("SharedData", BindingFlags.Public | BindingFlags.NonPublic);
			if (nestedType == null)
			{
				return Array.Empty<FieldInfo>();
			}
			string[] obj = new string[4] { "m_equipStatusEffect", "m_setStatusEffect", "m_holdStatusEffect", "m_consumeStatusEffect" };
			List<FieldInfo> list = new List<FieldInfo>();
			string[] array = obj;
			foreach (string name in array)
			{
				FieldInfo field = nestedType.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null && typeof(StatusEffect).IsAssignableFrom(field.FieldType))
				{
					list.Add(field);
				}
			}
			return list.ToArray();
		}

		public static void StripWishboneStatusEffects(ItemDrop itemDrop)
		{
			SharedData val = itemDrop.m_itemData?.m_shared;
			if (val == null)
			{
				return;
			}
			FieldInfo[] array = s_statusEffectFields;
			foreach (FieldInfo fieldInfo in array)
			{
				try
				{
					fieldInfo.SetValue(val, null);
				}
				catch
				{
				}
			}
		}
	}
	public static class CompassItemSetup
	{
		private static bool _registered;

		public static void Register()
		{
			if (!_registered)
			{
				PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable;
			}
		}

		private static void OnVanillaPrefabsAvailable()
		{
			//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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable;
			int value = ValheimCartographerPlugin.CompassIronCost.Value;
			int value2 = ValheimCartographerPlugin.CompassWoodCost.Value;
			ItemConfig val = new ItemConfig
			{
				Name = "$vc_cartographer_compass",
				Description = "$vc_cartographer_compass_desc",
				CraftingStation = CraftingStations.Forge,
				MinStationLevel = 1
			};
			val.AddRequirement("Iron", value, 1);
			val.AddRequirement("FineWood", value2, 1);
			Sprite val2 = CompassIconLoader.TryLoadSprite();
			if ((Object)(object)val2 != (Object)null)
			{
				val.Icon = val2;
			}
			CustomItem val3 = new CustomItem("VC_CartographerCompass", "Wishbone", val);
			ItemManager.Instance.AddItem(val3);
			CompassItemPostprocess.StripWishboneStatusEffects(val3.ItemDrop);
			CompassPickupVisual.ApplyToPrefab(val3.ItemPrefab);
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			string text2 = "$vc_cartographer_compass";
			localization.AddTranslation(ref text, ref text2, "Cartographer's Compass");
			text = "English";
			text2 = "$vc_cartographer_compass_desc";
			localization.AddTranslation(ref text, ref text2, "A simple compass for reading the land. Equip in the utility slot to see a heading strip at the top of the screen.");
			_registered = true;
			ValheimCartographerPlugin.Log.LogInfo((object)"Compass item registered.");
		}

		public static bool IsCompassEquipped(Player? player)
		{
			if ((Object)(object)player == (Object)null || !ValheimCartographerPlugin.CompassEnabled.Value)
			{
				return false;
			}
			ItemData utilityItem = CompassEquipment.GetUtilityItem(player);
			if (utilityItem != null)
			{
				return utilityItem.m_shared?.m_name == "$vc_cartographer_compass";
			}
			return false;
		}
	}
	internal static class CompassPickupVisual
	{
		private static readonly string[] s_sourcePrefabNames = new string[3] { "AmberPearl", "Ruby", "Coins" };

		public static void ApplyToPrefab(GameObject compassPrefab)
		{
			if ((Object)(object)compassPrefab == (Object)null || CompassCustomModelLoader.TryApply(compassPrefab))
			{
				return;
			}
			string[] array = s_sourcePrefabNames;
			foreach (string text in array)
			{
				GameObject val = ResolveItemPrefab(text);
				if (!((Object)(object)val == (Object)null) && TryCopyMeshes(compassPrefab, val))
				{
					ValheimCartographerPlugin.Log.LogInfo((object)("Compass world model meshes copied from vanilla prefab \"" + text + "\"."));
					return;
				}
			}
			ValheimCartographerPlugin.Log.LogWarning((object)"Could not replace compass world meshes; dropped item may still look like a wishbone.");
		}

		private static GameObject? ResolveItemPrefab(string name)
		{
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(name);
				if ((Object)(object)itemPrefab != (Object)null)
				{
					return itemPrefab;
				}
			}
			PrefabManager instance = PrefabManager.Instance;
			if (instance == null)
			{
				return null;
			}
			return instance.GetPrefab(name);
		}

		internal static bool TryCopyMeshesFromSource(GameObject compassPrefab, GameObject sourcePrefab)
		{
			return TryCopyMeshes(compassPrefab, sourcePrefab);
		}

		private static bool TryCopyMeshes(GameObject compassPrefab, GameObject sourcePrefab)
		{
			MeshFilter[] componentsInChildren = sourcePrefab.GetComponentsInChildren<MeshFilter>(true);
			MeshFilter[] componentsInChildren2 = compassPrefab.GetComponentsInChildren<MeshFilter>(true);
			if (componentsInChildren.Length != 0 && componentsInChildren2.Length != 0)
			{
				int num = Mathf.Min(componentsInChildren.Length, componentsInChildren2.Length);
				for (int i = 0; i < num; i++)
				{
					componentsInChildren2[i].sharedMesh = componentsInChildren[i].sharedMesh;
					MeshRenderer component = ((Component)componentsInChildren2[i]).GetComponent<MeshRenderer>();
					MeshRenderer component2 = ((Component)componentsInChildren[i]).GetComponent<MeshRenderer>();
					if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null)
					{
						((Renderer)component).sharedMaterials = ((Renderer)component2).sharedMaterials;
					}
				}
				return true;
			}
			SkinnedMeshRenderer[] componentsInChildren3 = sourcePrefab.GetComponentsInChildren<SkinnedMeshRenderer>(true);
			SkinnedMeshRenderer[] componentsInChildren4 = compassPrefab.GetComponentsInChildren<SkinnedMeshRenderer>(true);
			if (componentsInChildren3.Length != 0 && componentsInChildren4.Length != 0)
			{
				int num2 = Mathf.Min(componentsInChildren3.Length, componentsInChildren4.Length);
				for (int j = 0; j < num2; j++)
				{
					componentsInChildren4[j].sharedMesh = componentsInChildren3[j].sharedMesh;
					((Renderer)componentsInChildren4[j]).sharedMaterials = ((Renderer)componentsInChildren3[j]).sharedMaterials;
				}
				return true;
			}
			return false;
		}
	}
	internal static class CompassUiTextureLoader
	{
		internal static bool TryLoadSprite(string fileName, Vector2 pivot, out Sprite sprite)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			sprite = null;
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			if (string.IsNullOrEmpty(directoryName))
			{
				return false;
			}
			string path = Path.Combine(directoryName, fileName);
			if (!File.Exists(path))
			{
				return false;
			}
			byte[] bytes;
			try
			{
				bytes = File.ReadAllBytes(path);
			}
			catch (IOException)
			{
				return false;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!CompassIconLoader.TryLoadImageBytes(val, bytes))
			{
				return false;
			}
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Texture)val).filterMode = (FilterMode)1;
			sprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), pivot, 100f);
			((Object)sprite).name = "VC_" + fileName;
			return true;
		}
	}
}