Decompiled source of MapRoutes v0.3.0

MapRoutes.dll

Decompiled 4 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Events;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("garcipat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Draw dotted routes on the map with a quill.")]
[assembly: AssemblyFileVersion("0.3.0.0")]
[assembly: AssemblyInformationalVersion("0.3.0+a40bbf15729b5920f15a907741a42b3bb22595cd")]
[assembly: AssemblyProduct("Map Routes")]
[assembly: AssemblyTitle("MapRoutes")]
[assembly: AssemblyVersion("0.3.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 ValheimMapRoutes
{
	internal static class BiomeBorders
	{
		private const int SmoothRadius = 2;

		private const int SmoothPasses = 2;

		private const float Tolerance = 0.4f;

		private const int MinEdges = 4;

		private const float ShallowDepth = 3f;

		private static readonly FieldInfo HasGeneratedField = AccessTools.Field(typeof(Minimap), "m_hasGenerated");

		private static readonly FieldInfo HeightTextureField = AccessTools.Field(typeof(Minimap), "m_heightTexture");

		private static readonly FieldInfo ExploredField = AccessTools.Field(typeof(Minimap), "m_explored");

		private static readonly FieldInfo ExploredOthersField = AccessTools.Field(typeof(Minimap), "m_exploredOthers");

		private static Minimap _owner;

		private static bool _broken;

		private static BitArray _explored;

		private static BitArray _exploredOthers;

		private static int _size;

		private static float _pixelSize;

		internal static readonly List<List<Vector3>> Lines = new List<List<Vector3>>();

		internal static bool Refresh(Minimap minimap)
		{
			if (_broken)
			{
				return false;
			}
			if ((Object)(object)_owner == (Object)(object)minimap)
			{
				return true;
			}
			object obj = HasGeneratedField?.GetValue(minimap);
			if (!(obj is bool) || !(bool)obj)
			{
				return false;
			}
			object? obj2 = HeightTextureField?.GetValue(minimap);
			Texture2D val = (Texture2D)((obj2 is Texture2D) ? obj2 : null);
			_explored = ExploredField?.GetValue(minimap) as BitArray;
			_exploredOthers = ExploredOthersField?.GetValue(minimap) as BitArray;
			if ((Object)(object)minimap.m_mapTexture == (Object)null || (Object)(object)val == (Object)null || _explored == null)
			{
				_broken = true;
				Plugin.Log.LogError((object)"Biome borders disabled: the map textures were not found in this game version");
				return false;
			}
			_owner = minimap;
			_size = ((Texture)minimap.m_mapTexture).width;
			_pixelSize = minimap.m_pixelSize;
			Trace(minimap.m_mapTexture.GetPixels32(), val);
			return true;
		}

		internal static bool IsExplored(Vector3 world)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			int num = _size / 2;
			int num2 = Mathf.FloorToInt(world.x / _pixelSize + (float)num);
			int num3 = Mathf.FloorToInt(world.z / _pixelSize + (float)num);
			if (num2 < 0 || num3 < 0 || num2 >= _size || num3 >= _size)
			{
				return false;
			}
			int index = num3 * _size + num2;
			if (!_explored[index])
			{
				if (_exploredOthers != null)
				{
					return _exploredOthers[index];
				}
				return false;
			}
			return true;
		}

		private static void Trace(Color32[] colors, Texture2D heights)
		{
			Lines.Clear();
			int size = _size;
			float water = (((Object)(object)ZoneSystem.instance != (Object)null) ? ZoneSystem.instance.m_waterLevel : 30f);
			int num = size + 1;
			Dictionary<int, List<int>> dictionary = new Dictionary<int, List<int>>();
			int num2 = 0;
			for (int i = 0; i < size; i++)
			{
				for (int j = 0; j < size; j++)
				{
					int num3 = i * size + j;
					if (j + 1 < size && Differs(colors, heights, water, num3, j, i, num3 + 1, j + 1, i))
					{
						Link(dictionary, i * num + j + 1, (i + 1) * num + j + 1);
						num2++;
					}
					if (i + 1 < size && Differs(colors, heights, water, num3, j, i, num3 + size, j, i + 1))
					{
						Link(dictionary, (i + 1) * num + j, (i + 1) * num + j + 1);
						num2++;
					}
				}
			}
			HashSet<long> hashSet = new HashSet<long>();
			int num4 = 0;
			bool[] array = new bool[2] { false, true };
			foreach (bool flag in array)
			{
				foreach (KeyValuePair<int, List<int>> item in dictionary)
				{
					if (!flag && item.Value.Count == 2)
					{
						continue;
					}
					foreach (int item2 in item.Value)
					{
						if (!hashSet.Contains(Key(item.Key, item2)))
						{
							List<int> list = Walk(dictionary, hashSet, item.Key, item2);
							if (list.Count > 4)
							{
								List<Vector3> list2 = ToWorld(Thin(Smooth(list, num)));
								num4 += list2.Count;
								Lines.Add(list2);
							}
						}
					}
				}
			}
			Plugin.Log.LogInfo((object)$"Biome borders: {num2} border edges on land, {Lines.Count} lines, {num4} points");
		}

		private static bool Differs(Color32[] colors, Texture2D heights, float water, int a, int ax, int ay, int b, int bx, int by)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			Color32 val = colors[a];
			Color32 val2 = colors[b];
			if (val.r == val2.r && val.g == val2.g && val.b == val2.b)
			{
				return false;
			}
			if (IsLand(val, heights.GetPixel(ax, ay).r, water))
			{
				return IsLand(val2, heights.GetPixel(bx, by).r, water);
			}
			return false;
		}

		private static bool IsLand(Color32 color, float height, float water)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			bool flag = color.r == byte.MaxValue && color.g == byte.MaxValue && color.b == byte.MaxValue;
			return height >= (flag ? water : (water - 3f));
		}

		private static void Link(Dictionary<int, List<int>> links, int a, int b)
		{
			Add(links, a, b);
			Add(links, b, a);
		}

		private static void Add(Dictionary<int, List<int>> links, int from, int to)
		{
			if (!links.TryGetValue(from, out var value))
			{
				value = (links[from] = new List<int>(2));
			}
			value.Add(to);
		}

		private static long Key(int a, int b)
		{
			if (a >= b)
			{
				return ((long)b << 32) | (uint)a;
			}
			return ((long)a << 32) | (uint)b;
		}

		private static List<int> Walk(Dictionary<int, List<int>> links, HashSet<long> used, int start, int next)
		{
			List<int> list = new List<int> { start };
			int num = start;
			int num2 = next;
			used.Add(Key(num, num2));
			while (true)
			{
				list.Add(num2);
				List<int> list2 = links[num2];
				if (list2.Count != 2 || num2 == start)
				{
					return list;
				}
				int num3 = ((list2[0] == num) ? list2[1] : list2[0]);
				if (!used.Add(Key(num2, num3)))
				{
					break;
				}
				num = num2;
				num2 = num3;
			}
			return list;
		}

		private static List<Vector2> Smooth(List<int> corners, int stride)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: 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_00bf: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			List<Vector2> list = corners.ConvertAll((Converter<int, Vector2>)((int c) => new Vector2((float)(c % stride), (float)(c / stride))));
			bool flag = corners[0] == corners[corners.Count - 1];
			int num = (flag ? (list.Count - 1) : list.Count);
			for (int num2 = 0; num2 < 2; num2++)
			{
				List<Vector2> list2 = new List<Vector2>(list);
				for (int num3 = ((!flag) ? 1 : 0); num3 < (flag ? num : (num - 1)); num3++)
				{
					Vector2 val = Vector2.zero;
					int num4 = 0;
					for (int num5 = -2; num5 <= 2; num5++)
					{
						int num6 = num3 + num5;
						if (flag)
						{
							num6 = (num6 % num + num) % num;
						}
						else if (num6 < 0 || num6 >= num)
						{
							continue;
						}
						val += list[num6];
						num4++;
					}
					list2[num3] = val / (float)num4;
				}
				if (flag)
				{
					list2[num] = list2[0];
				}
				list = list2;
			}
			return list;
		}

		private static List<Vector2> Thin(List<Vector2> points)
		{
			//IL_005b: 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_0075: 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)
			bool[] array = new bool[points.Count];
			array[0] = true;
			array[points.Count - 1] = true;
			Stack<KeyValuePair<int, int>> stack = new Stack<KeyValuePair<int, int>>();
			stack.Push(new KeyValuePair<int, int>(0, points.Count - 1));
			while (stack.Count > 0)
			{
				KeyValuePair<int, int> keyValuePair = stack.Pop();
				int num = -1;
				float num2 = 0.4f;
				for (int i = keyValuePair.Key + 1; i < keyValuePair.Value; i++)
				{
					float num3 = RouteMap.DistanceToSegment(points[i], points[keyValuePair.Key], points[keyValuePair.Value]);
					if (num3 > num2)
					{
						num2 = num3;
						num = i;
					}
				}
				if (num >= 0)
				{
					array[num] = true;
					stack.Push(new KeyValuePair<int, int>(keyValuePair.Key, num));
					stack.Push(new KeyValuePair<int, int>(num, keyValuePair.Value));
				}
			}
			List<Vector2> list = new List<Vector2>();
			for (int j = 0; j < points.Count; j++)
			{
				if (array[j])
				{
					list.Add(points[j]);
				}
			}
			return list;
		}

		private static List<Vector3> ToWorld(List<Vector2> points)
		{
			int half = _size / 2;
			return points.ConvertAll((Converter<Vector2, Vector3>)((Vector2 p) => new Vector3((p.x - (float)half) * _pixelSize, 0f, (p.y - (float)half) * _pixelSize)));
		}
	}
	internal static class PinHotkey
	{
		private const float SameSpot = 10f;

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

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

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

		private static readonly MethodInfo MessageMethod = AccessTools.Method(typeof(Character), "Message", (Type[])null, (Type[])null);

		private static bool _failed;

		private static KeyboardShortcut Key => Plugin.PinHotkey.Value;

		internal static string Hint(Player player)
		{
			//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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut key = Key;
			if ((int)((KeyboardShortcut)(ref key)).MainKey == 0 || (Object)(object)player == (Object)null || ((Character)player).InInterior() || !PinTargets.TryGet(((Humanoid)player).GetHoverObject(), out var _, out var _, out var _))
			{
				return null;
			}
			key = Key;
			return $"[<color=yellow><b>{((KeyboardShortcut)(ref key)).MainKey}</b></color>] Pin on map";
		}

		internal static void Update(Player player)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			if (_failed || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			KeyboardShortcut key = Key;
			if ((int)((KeyboardShortcut)(ref key)).MainKey == 0)
			{
				return;
			}
			key = Key;
			if (!((KeyboardShortcut)(ref key)).IsDown() || (Object)(object)Minimap.instance == (Object)null || ((Character)player).InInterior() || !TakesInput(player))
			{
				return;
			}
			try
			{
				GameObject hoverObject = ((Humanoid)player).GetHoverObject();
				if ((Object)(object)hoverObject == (Object)null)
				{
					return;
				}
				string name;
				PinType type;
				Vector3 position;
				bool flag = PinTargets.TryGet(hoverObject, out name, out type, out position);
				Plugin.Log.LogInfo((object)("Pin hotkey on " + PinTargets.Describe(hoverObject) + ": " + (flag ? $"{type} '{name}'" : "nothing to pin")));
				if (flag)
				{
					if (HasPinNear(Minimap.instance, type, name, position))
					{
						Message(player, "Already pinned");
						return;
					}
					AddPin(Minimap.instance, position, type, name);
					Message(player, (name.Length == 0) ? "Pinned portal" : ("Pinned " + name));
				}
			}
			catch (Exception arg)
			{
				_failed = true;
				Plugin.Log.LogError((object)$"Pin hotkey failed and is off until restart: {arg}");
			}
		}

		private static bool TakesInput(Player player)
		{
			if (!(TakeInputMethod == null))
			{
				return (bool)TakeInputMethod.Invoke(player, Args(TakeInputMethod));
			}
			return true;
		}

		private static bool HasPinNear(Minimap minimap, PinType type, string name, Vector3 position)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			if (!(PinsField?.GetValue(minimap) is IList list))
			{
				return false;
			}
			foreach (PinData item in list)
			{
				PinData val = item;
				float num = val.m_pos.x - position.x;
				float num2 = val.m_pos.z - position.z;
				if (val.m_type == type && num * num + num2 * num2 <= 100f && string.Equals(val.m_name?.Trim(), name, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		private static void AddPin(Minimap minimap, Vector3 position, PinType type, string name)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			AddPinMethod.Invoke(minimap, Args(AddPinMethod, position, type, name, true, false));
		}

		private static void Message(Player player, string text)
		{
			MessageMethod.Invoke(player, Args(MessageMethod, (object)(MessageType)1, text));
		}

		private static object[] Args(MethodInfo method, params object[] given)
		{
			return method.GetParameters().Select((ParameterInfo parameter, int i) => (i >= given.Length) ? DefaultOf(parameter) : given[i]).ToArray();
		}

		private static object DefaultOf(ParameterInfo parameter)
		{
			object defaultValue = parameter.DefaultValue;
			Type parameterType = parameter.ParameterType;
			if ((defaultValue == null || defaultValue is DBNull || defaultValue == Missing.Value) && parameterType.IsValueType)
			{
				return Activator.CreateInstance(parameterType);
			}
			if (!(defaultValue is DBNull) && defaultValue != Missing.Value)
			{
				return defaultValue;
			}
			return null;
		}
	}
	internal static class PinIcons
	{
		private sealed class Icon
		{
			internal readonly string[] Plain;

			internal readonly string[] Labeled;

			internal Icon(string[] plain, string[] labeled = null)
			{
				Plain = plain;
				Labeled = labeled ?? new string[0];
			}
		}

		private const PinType CirclePin = (PinType)3;

		private const int CellSize = 128;

		private const int Columns = 7;

		private static readonly Icon[] Icons = new Icon[23]
		{
			new Icon(new string[1] { "Cave" }, new string[2] { "Troll cave", "Frost cave" }),
			new Icon(new string[1] { "Crypt" }, new string[1] { "Sunken crypt" }),
			new Icon(new string[1] { "Dungeon" }, new string[1] { "Burial chamber" }),
			new Icon(new string[2] { "Village", "Camp" }, new string[2] { "Fuling village", "Fuling camp" }),
			new Icon(new string[1] { "Portal" }),
			new Icon(new string[1] { "Ship" }, new string[3] { "Boat", "Karve", "Longship" }),
			new Icon(new string[1] { "Ore" }, new string[5] { "Copper", "Tin", "Silver", "Iron", "Obsidian" }),
			new Icon(new string[1] { "Tar" }, new string[1] { "Tar pit" }),
			new Icon(new string[1] { "Berries" }, new string[3] { "Raspberries", "Blueberries", "Cloudberries" }),
			new Icon(new string[1] { "Mushroom" }, new string[4] { "Yellow mushroom", "Blue mushroom", "Jotun puffs", "Magecap" }),
			new Icon(new string[1] { "Egg" }, new string[1] { "Dragon egg" }),
			new Icon(new string[1] { "Nest" }, new string[1] { "Greydwarf nest" }),
			new Icon(new string[1] { "Surtling" }, new string[1] { "Fire geyser" }),
			new Icon(new string[2] { "Leviathan", "Turtle" }),
			new Icon(new string[1] { "Forest" }, new string[1] { "Black forest" }),
			new Icon(new string[1] { "Swamp" }),
			new Icon(new string[1] { "Mountain" }),
			new Icon(new string[1] { "Plains" }),
			new Icon(new string[2] { "Mistlands", "Mist" }),
			new Icon(new string[2] { "Ashlands", "Ash" }),
			new Icon(new string[2] { "Deep North", "North" }),
			new Icon(new string[1] { "Lox" }),
			new Icon(new string[1] { "Mine" }, new string[1] { "Infested mine" })
		};

		private static readonly Dictionary<string, KeyValuePair<int, bool>> Names = BuildNames();

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

		private static readonly FieldInfo IconElementField = AccessTools.Field(typeof(PinData), "m_iconElement");

		private static readonly FieldInfo NameDataField = AccessTools.Field(typeof(PinData), "m_NamePinData");

		private static readonly PropertyInfo NameObjectProperty = ((NameDataField == null) ? null : AccessTools.Property(NameDataField.FieldType, "PinNameGameObject"));

		private static Sprite[] _sprites;

		private static bool _spritesTried;

		private static bool _failed;

		internal static void Apply(Minimap minimap)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Invalid comparison between Unknown and I4
			if (_failed)
			{
				return;
			}
			try
			{
				bool num = !_spritesTried;
				Sprite[] array = Sprites();
				if (num && array != null)
				{
					Sprite icon = minimap.m_icons.Find((SpriteData val2) => (int)val2.m_name == 3).m_icon;
					Plugin.Log.LogInfo((object)string.Format("Pin icons replace the {0} pin, sprite '{1}'", (object)(PinType)3, ((Object)(object)icon == (Object)null) ? "none" : ((Object)icon).name));
				}
				if (array == null || !(PinsField?.GetValue(minimap) is IList list))
				{
					return;
				}
				foreach (PinData item in list)
				{
					PinData val = item;
					if ((int)val.m_type == 3)
					{
						ApplyTo(val, array);
					}
				}
			}
			catch (Exception arg)
			{
				_failed = true;
				Plugin.Log.LogError((object)$"Drawing pin icons failed, pins keep the game's icons: {arg}");
			}
		}

		private static void ApplyTo(PinData pin, Sprite[] sprites)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			object? value = IconElementField.GetValue(pin);
			Behaviour val = (Behaviour)((value is Behaviour) ? value : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			int index;
			bool showName;
			bool flag = TryMatch(pin.m_name, out index, out showName);
			Sprite val2 = (flag ? sprites[index] : pin.m_icon);
			if ((Object)(object)Ui.GetSprite(val) != (Object)(object)val2)
			{
				Ui.SetSprite(val, val2);
			}
			object obj = ((NameObjectProperty == null) ? null : NameDataField.GetValue(pin));
			GameObject val3 = (GameObject)((obj == null) ? null : /*isinst with value type is only supported in some contexts*/);
			if ((Object)(object)val3 != (Object)null)
			{
				Vector3 val4 = ((flag && !showName) ? Vector3.zero : Vector3.one);
				if (val3.transform.localScale != val4)
				{
					val3.transform.localScale = val4;
				}
			}
		}

		private static bool TryMatch(string name, out int index, out bool showName)
		{
			if (!string.IsNullOrEmpty(name) && Names.TryGetValue(name.Trim(), out var value))
			{
				index = value.Key;
				showName = value.Value;
				return true;
			}
			index = -1;
			showName = true;
			return false;
		}

		private static Dictionary<string, KeyValuePair<int, bool>> BuildNames()
		{
			Dictionary<string, KeyValuePair<int, bool>> dictionary = new Dictionary<string, KeyValuePair<int, bool>>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < Icons.Length; i++)
			{
				string[] plain = Icons[i].Plain;
				foreach (string key in plain)
				{
					dictionary[key] = new KeyValuePair<int, bool>(i, value: false);
				}
				plain = Icons[i].Labeled;
				foreach (string key2 in plain)
				{
					dictionary[key2] = new KeyValuePair<int, bool>(i, value: true);
				}
			}
			return dictionary;
		}

		private static Sprite[] Sprites()
		{
			//IL_00a7: 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)
			if (_spritesTried)
			{
				return _sprites;
			}
			_spritesTried = true;
			if (IconElementField == null || PinsField == null || !Ui.Available)
			{
				Plugin.Log.LogError((object)"Pin icons are off: the game's pin fields were not found");
				return null;
			}
			Texture2D val = RouteArt.LoadPng("pin-icons.png", mipmaps: true);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			int num = ((Texture)val).height / 128;
			Sprite[] array = (Sprite[])(object)new Sprite[Icons.Length];
			for (int i = 0; i < Icons.Length; i++)
			{
				int num2 = i % 7 * 128;
				int num3 = (num - 1 - i / 7) * 128;
				array[i] = Sprite.Create(val, new Rect((float)num2, (float)num3, 128f, 128f), new Vector2(0.5f, 0.5f));
			}
			_sprites = array;
			Plugin.Log.LogInfo((object)$"Pin icons ready: {Icons.Length} icons, {Names.Count} names");
			return _sprites;
		}
	}
	internal static class PinTargets
	{
		internal const PinType CirclePin = (PinType)3;

		private const PinType RunePin = (PinType)6;

		private static readonly KeyValuePair<string, string>[] Entrances = new KeyValuePair<string, string>[5]
		{
			new KeyValuePair<string, string>("SunkenCrypt", "Crypt"),
			new KeyValuePair<string, string>("Crypt", "Dungeon"),
			new KeyValuePair<string, string>("TrollCave", "Cave"),
			new KeyValuePair<string, string>("MountainCave", "Cave"),
			new KeyValuePair<string, string>("Mistlands_DvergrTownEntrance", "Mine")
		};

		private static readonly Dictionary<string, string> Pickables = new Dictionary<string, string>
		{
			{ "Raspberry", "Berries" },
			{ "Blueberries", "Berries" },
			{ "Cloudberry", "Berries" },
			{ "Mushroom", "Mushroom" },
			{ "MushroomYellow", "Mushroom" },
			{ "MushroomBlue", "Mushroom" },
			{ "MushroomJotunPuffs", "Mushroom" },
			{ "MushroomMagecap", "Mushroom" },
			{ "Tar", "Tar" },
			{ "DragonEgg", "Egg" }
		};

		private static readonly HashSet<string> Ores = new HashSet<string> { "CopperOre", "TinOre", "SilverOre" };

		private static readonly FieldInfo[] DestructibleSpawnFields = new FieldInfo[2]
		{
			AccessTools.Field(typeof(Destructible), "m_spawnWhenDamaged"),
			AccessTools.Field(typeof(Destructible), "m_spawnWhenDestroyed")
		};

		internal static bool TryGet(GameObject hoverObject, out string name, out PinType type, out Vector3 position)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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)
			name = null;
			type = (PinType)3;
			position = Vector3.zero;
			Component val = (Component)(((Object)(object)hoverObject == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			position = val.transform.position;
			TeleportWorld val2 = (TeleportWorld)(object)((val is TeleportWorld) ? val : null);
			if (val2 != null)
			{
				name = val2.GetText()?.Trim() ?? "";
				type = (PinType)6;
				return true;
			}
			name = NameFor(val);
			return name != null;
		}

		internal static string Describe(GameObject hoverObject)
		{
			Component val = (Component)(((Object)(object)hoverObject == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
			if ((Object)(object)val == (Object)null)
			{
				return "nothing";
			}
			string text = string.Join(", ", (from c in val.GetComponents<Component>()
				where (Object)(object)c != (Object)null && !(c is Transform)
				select ((object)c).GetType().Name).ToArray());
			Location componentInParent = val.GetComponentInParent<Location>();
			string text2 = (((Object)(object)componentInParent == (Object)null) ? "" : (" in location '" + PrefabName(((Component)componentInParent).gameObject) + "'"));
			return "'" + PrefabName(val.gameObject) + "' (" + text + ")" + text2;
		}

		private static string NameFor(Component hoverable)
		{
			if (!(hoverable is Teleport))
			{
				if (!(hoverable is ShipControlls))
				{
					Pickable val = (Pickable)(object)((hoverable is Pickable) ? hoverable : null);
					if (val == null)
					{
						ItemDrop val2 = (ItemDrop)(object)((hoverable is ItemDrop) ? hoverable : null);
						if (val2 == null)
						{
							MineRock val3 = (MineRock)(object)((hoverable is MineRock) ? hoverable : null);
							if (val3 == null)
							{
								MineRock5 val4 = (MineRock5)(object)((hoverable is MineRock5) ? hoverable : null);
								if (val4 != null)
								{
									return OreIn(val4.m_dropItems);
								}
								return OreOf(hoverable.gameObject, followDestructible: true);
							}
							return OreIn(val3.m_dropItems);
						}
						GameObject val5 = val2.m_itemData?.m_dropPrefab;
						if (!((Object)(object)val5 != (Object)null) || !(((Object)val5).name == "DragonEgg"))
						{
							return null;
						}
						return "Egg";
					}
					if (!((Object)(object)val.m_itemPrefab != (Object)null) || !Pickables.TryGetValue(((Object)val.m_itemPrefab).name, out var value))
					{
						return null;
					}
					return value;
				}
				return "Ship";
			}
			Location componentInParent = hoverable.GetComponentInParent<Location>();
			string text = (((Object)(object)componentInParent == (Object)null) ? "" : PrefabName(((Component)componentInParent).gameObject));
			KeyValuePair<string, string>[] entrances = Entrances;
			for (int i = 0; i < entrances.Length; i++)
			{
				KeyValuePair<string, string> keyValuePair = entrances[i];
				if (text.StartsWith(keyValuePair.Key, StringComparison.Ordinal))
				{
					return keyValuePair.Value;
				}
			}
			return "Dungeon";
		}

		private static string OreOf(GameObject go, bool followDestructible)
		{
			MineRock5 componentInParent = go.GetComponentInParent<MineRock5>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				return OreIn(componentInParent.m_dropItems);
			}
			MineRock componentInParent2 = go.GetComponentInParent<MineRock>();
			if ((Object)(object)componentInParent2 != (Object)null)
			{
				return OreIn(componentInParent2.m_dropItems);
			}
			DropOnDestroyed componentInParent3 = go.GetComponentInParent<DropOnDestroyed>();
			string text = (((Object)(object)componentInParent3 == (Object)null) ? null : OreIn(componentInParent3.m_dropWhenDestroyed));
			if (text != null || !followDestructible)
			{
				return text;
			}
			Destructible componentInParent4 = go.GetComponentInParent<Destructible>();
			if ((Object)(object)componentInParent4 == (Object)null)
			{
				return null;
			}
			FieldInfo[] destructibleSpawnFields = DestructibleSpawnFields;
			for (int i = 0; i < destructibleSpawnFields.Length; i++)
			{
				object? obj = destructibleSpawnFields[i]?.GetValue(componentInParent4);
				GameObject val = (GameObject)((obj is GameObject) ? obj : null);
				if (val != null && (Object)(object)val != (Object)null)
				{
					text = OreOf(val, followDestructible: false);
					if (text != null)
					{
						return text;
					}
				}
			}
			return null;
		}

		private static string OreIn(DropTable table)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (table?.m_drops == null)
			{
				return null;
			}
			foreach (DropData drop in table.m_drops)
			{
				if ((Object)(object)drop.m_item != (Object)null && Ores.Contains(((Object)drop.m_item).name))
				{
					return "Ore";
				}
			}
			return null;
		}

		private static string PrefabName(GameObject go)
		{
			string name = ((Object)go).name;
			int num = name.IndexOf('(');
			return ((num < 0) ? name : name.Substring(0, num)).Trim();
		}
	}
	[BepInPlugin("dev.pgarcia.valheim.maproutes", "Map Routes", "0.3.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "dev.pgarcia.valheim.maproutes";

		public const string PluginName = "Map Routes";

		public const string PluginVersion = "0.3.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> BiomeBordersEnabled;

		internal static ConfigEntry<KeyboardShortcut> PinHotkey;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			BiomeBordersEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "BiomeBorders", false, "Draw faint dotted lines along the borders between land biomes on the large map, where it is explored.");
			PinHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "PinHotkey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Key that pins what you look at (berries, mushrooms, copper, tin, silver, tar, dragon eggs, cave and dungeon entrances, portals, ships) on the map with its icon. None turns it off.");
			_harmony = new Harmony("dev.pgarcia.valheim.maproutes");
			_harmony.PatchAll();
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			RouteArt.ResetCursor();
		}
	}
	internal static class RouteArt
	{
		private const int SampleSize = 32;

		private static readonly Vector2 CursorHotspot = new Vector2(3f, 28f);

		private static readonly Color FallbackRed = new Color(0.8f, 0.15f, 0.1f, 1f);

		private static Sprite _dot;

		private static Sprite _quill;

		private static bool _quillTried;

		private static Texture2D _cursor;

		private static bool _cursorTried;

		private static bool _cursorShown;

		private static Color? _red;

		internal static Sprite Dot
		{
			get
			{
				if ((Object)(object)_dot == (Object)null)
				{
					_dot = MakeDot();
				}
				return _dot;
			}
		}

		internal static Sprite Quill()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (!_quillTried)
			{
				_quillTried = true;
				Texture2D val = LoadPng("quill.png");
				if ((Object)(object)val != (Object)null)
				{
					_quill = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
				}
			}
			return _quill;
		}

		internal static Color Red(Minimap minimap)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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)
			if (!_red.HasValue)
			{
				_red = Brighten((Color)(((??)ReadCrossColor(minimap)) ?? FallbackRed));
				Plugin.Log.LogInfo((object)$"Route color {_red.Value}");
			}
			return _red.Value;
		}

		internal static void ShowQuillCursor(bool show)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (show != _cursorShown)
			{
				if (show && !_cursorTried)
				{
					_cursorTried = true;
					_cursor = LoadPng("quill-cursor.png");
				}
				if (!show || !((Object)(object)_cursor == (Object)null))
				{
					_cursorShown = show;
					Cursor.SetCursor(show ? _cursor : null, show ? CursorHotspot : Vector2.zero, (CursorMode)0);
				}
			}
		}

		internal static void ResetCursor()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (_cursorShown)
			{
				_cursorShown = false;
				Cursor.SetCursor((Texture2D)null, Vector2.zero, (CursorMode)0);
			}
		}

		private static Sprite MakeDot()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false)
			{
				filterMode = (FilterMode)1
			};
			float num = 15.5f;
			float num2 = 15f;
			for (int i = 0; i < 32; i++)
			{
				for (int j = 0; j < 32; j++)
				{
					float num3 = Mathf.Sqrt(((float)j - num) * ((float)j - num) + ((float)i - num) * ((float)i - num));
					val.SetPixel(j, i, new Color(1f, 1f, 1f, Mathf.Clamp01(num2 - num3 + 0.5f)));
				}
			}
			val.Apply();
			return Sprite.Create(val, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f));
		}

		private static Color Brighten(Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			float num = default(float);
			float num2 = default(float);
			float num3 = default(float);
			Color.RGBToHSV(color, ref num, ref num2, ref num3);
			return Color.HSVToRGB(num, num2, Mathf.Max(num3, 0.8f));
		}

		private static Color? ReadCrossColor(Minimap minimap)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: 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_0159: 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_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Transform val = (((Object)(object)minimap.m_pinPrefab == (Object)null) ? null : minimap.m_pinPrefab.transform.Find("Checked"));
				Behaviour val2 = (((Object)(object)val == (Object)null) ? null : Ui.GetImage((Component)(object)val));
				if ((Object)(object)val2 == (Object)null)
				{
					return null;
				}
				Color color = Ui.GetColor(val2);
				if (color.r < 0.95f || color.g < 0.95f || color.b < 0.95f)
				{
					Plugin.Log.LogInfo((object)$"Route color from the cross tint {color}");
					return new Color(color.r, color.g, color.b, 1f);
				}
				Sprite sprite = Ui.GetSprite(val2);
				if ((Object)(object)sprite == (Object)null)
				{
					return null;
				}
				Color[] pixels = Rasterize(sprite, 32).GetPixels();
				float num = 0f;
				float num2 = 0f;
				float num3 = 0f;
				float num4 = 0f;
				Color[] array = pixels;
				float num5 = default(float);
				float num6 = default(float);
				float num7 = default(float);
				foreach (Color val3 in array)
				{
					Color.RGBToHSV(val3, ref num5, ref num6, ref num7);
					if (val3.a > 0.5f && num6 > 0.4f && num7 > 0.25f)
					{
						num += val3.r * val3.a;
						num2 += val3.g * val3.a;
						num3 += val3.b * val3.a;
						num4 += val3.a;
					}
				}
				Plugin.Log.LogInfo((object)$"Route color from the cross sprite, {num4:0} weight of colorful pixels");
				return (num4 > 0f) ? new Color?(new Color(num / num4, num2 / num4, num3 / num4, 1f)) : ((Color?)null);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Reading the crossed-out pin color failed: {arg}");
				return null;
			}
		}

		private static Texture2D Rasterize(Sprite sprite, int size)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			Texture2D texture = sprite.texture;
			Rect textureRect = sprite.textureRect;
			RenderTexture temporary = RenderTexture.GetTemporary(size, size, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
			RenderTexture active = RenderTexture.active;
			try
			{
				Graphics.Blit((Texture)(object)texture, temporary, new Vector2(((Rect)(ref textureRect)).width / (float)((Texture)texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)texture).height), new Vector2(((Rect)(ref textureRect)).x / (float)((Texture)texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)texture).height));
				RenderTexture.active = temporary;
				Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
				val.ReadPixels(new Rect(0f, 0f, (float)size, (float)size), 0, 0);
				val.Apply();
				return val;
			}
			finally
			{
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
			}
		}

		internal static Texture2D LoadPng(string name, bool mipmaps = false)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			try
			{
				using Stream stream = typeof(RouteArt).Assembly.GetManifestResourceStream("ValheimMapRoutes." + name);
				if (stream == null)
				{
					Plugin.Log.LogError((object)("Embedded " + name + " not found"));
					return null;
				}
				byte[] array = new byte[stream.Length];
				int num;
				for (int i = 0; i < array.Length; i += num)
				{
					num = stream.Read(array, i, array.Length - i);
					if (num <= 0)
					{
						throw new EndOfStreamException();
					}
				}
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, mipmaps)
				{
					filterMode = (FilterMode)1
				};
				return ImageConversion.LoadImage(val, array) ? val : null;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Loading {name} failed: {arg}");
				return null;
			}
		}
	}
	internal static class RouteMap
	{
		private sealed class DotLayer
		{
			internal readonly List<Behaviour> Dots = new List<Behaviour>();

			internal readonly List<Color> Colors = new List<Color>();

			internal RectTransform Root;

			internal float Size;

			internal float Spacing;

			internal int Used;
		}

		private struct MapView
		{
			internal RectTransform Rect;

			internal Rect Uv;

			internal Vector2 Size;

			internal float TextureSize;

			internal float PixelSize;

			internal static bool Get(Minimap minimap, out MapView view, bool small = false)
			{
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Expected O, but got Unknown
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				//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_0060: 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)
				view = default(MapView);
				object? obj = (small ? SmallMapField : LargeMapField)?.GetValue(minimap);
				Component val = (Component)((obj is Component) ? obj : null);
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				view.Rect = (RectTransform)val.transform;
				view.Uv = Ui.UvRect(val);
				Rect rect = view.Rect.rect;
				view.Size = ((Rect)(ref rect)).size;
				view.TextureSize = minimap.m_textureSize;
				view.PixelSize = minimap.m_pixelSize;
				if (view.Size.x > 0f)
				{
					return view.Size.y > 0f;
				}
				return false;
			}

			internal Vector2 ToLocal(Vector3 world)
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				int num = (int)TextureSize / 2;
				float num2 = (world.x / PixelSize + (float)num) / TextureSize;
				float num3 = (world.z / PixelSize + (float)num) / TextureSize;
				return new Vector2((num2 - ((Rect)(ref Uv)).xMin) / ((Rect)(ref Uv)).width * Size.x, (num3 - ((Rect)(ref Uv)).yMin) / ((Rect)(ref Uv)).height * Size.y);
			}

			internal Vector3 ToWorld(Vector2 local)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0087: Unknown result type (might be due to invalid IL or missing references)
				int num = (int)TextureSize / 2;
				float num2 = ((Rect)(ref Uv)).xMin + local.x / Size.x * ((Rect)(ref Uv)).width;
				float num3 = ((Rect)(ref Uv)).yMin + local.y / Size.y * ((Rect)(ref Uv)).height;
				return new Vector3((num2 * TextureSize - (float)num) * PixelSize, 0f, (num3 * TextureSize - (float)num) * PixelSize);
			}

			internal bool Pointer(out Vector2 local)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				local = Vector2.zero;
				Vector2 val = default(Vector2);
				if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(Rect, PointerPosition(), (Camera)null, ref val))
				{
					return false;
				}
				Vector2 val2 = val;
				Rect rect = Rect.rect;
				local = val2 - ((Rect)(ref rect)).min;
				rect = Rect.rect;
				return ((Rect)(ref rect)).Contains(val);
			}
		}

		private const float DotSize = 4.5f;

		private const float DotSpacing = 9f;

		private const float FullSizeZoom = 0.05f;

		private const float ZoomPower = 0.4f;

		private const float MinZoomScale = 0.45f;

		private const float HitRadius = 12f;

		private const float StrokeStep = 4f;

		private const float StrokeTolerance = 1.5f;

		private const float DragThreshold = 6f;

		private const int MaxDots = 6000;

		private const float DashLength = 6f;

		private const float DashGap = 5f;

		private const float DashThickness = 1.5f;

		private static readonly Color BorderColor = new Color(0.86f, 0.86f, 0.82f, 0.3f);

		private static readonly MethodInfo PointerPositionGetter = AccessTools.PropertyGetter(typeof(ZInput), "pointerPosition");

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

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

		private static readonly FieldInfo SelectedTypeField = AccessTools.Field(typeof(Minimap), "m_selectedType");

		private static readonly FieldRef<Minimap, Vector3> MapOffsetRef = AccessTools.FieldRefAccess<Minimap, Vector3>("m_mapOffset");

		private static readonly Func<int, bool> GetMouseButton = MouseButtonMethod("GetMouseButton");

		private static readonly Func<int, bool> GetMouseButtonDown = MouseButtonMethod("GetMouseButtonDown");

		private static readonly FieldInfo LargeMapField = AccessTools.Field(typeof(Minimap), "m_mapImageLarge");

		private static readonly FieldInfo SmallMapField = AccessTools.Field(typeof(Minimap), "m_mapImageSmall");

		private static readonly FieldInfo[] VanillaFrameFields = new FieldInfo[8]
		{
			AccessTools.Field(typeof(Minimap), "m_selectedIcon0"),
			AccessTools.Field(typeof(Minimap), "m_selectedIcon1"),
			AccessTools.Field(typeof(Minimap), "m_selectedIcon2"),
			AccessTools.Field(typeof(Minimap), "m_selectedIcon3"),
			AccessTools.Field(typeof(Minimap), "m_selectedIcon4"),
			AccessTools.Field(typeof(Minimap), "m_selectedIconDeath"),
			AccessTools.Field(typeof(Minimap), "m_selectedIconBoss"),
			AccessTools.Field(typeof(Minimap), "m_selectedIconPing")
		};

		private static readonly DotLayer LargeDots = new DotLayer();

		private static readonly DotLayer SmallDots = new DotLayer();

		private static readonly DotLayer BorderDots = new DotLayer();

		private static GameObject _button;

		private static Behaviour _buttonFrame;

		private static bool _broken;

		private static List<Vector3> _current;

		private static bool _rightHeld;

		private static Vector2 _rightPressedAt;

		private static Vector2 _rightLast;

		internal static bool Drawing { get; private set; }

		internal static void Update(Minimap minimap)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Invalid comparison between Unknown and I4
			if (_broken || (int)minimap.m_mode == 0)
			{
				return;
			}
			if (!Ui.Available)
			{
				_broken = true;
				Plugin.Log.LogError((object)"Map Routes disabled: UnityEngine.UI types not found in this game version");
				return;
			}
			if ((int)minimap.m_mode == 1)
			{
				if (RouteStore.Refresh() && MapView.Get(minimap, out var view, small: true))
				{
					float scale = ((minimap.m_pinSizeLarge > 0f) ? (minimap.m_pinSizeSmall / minimap.m_pinSizeLarge) : 1f);
					DrawRoutes(minimap, view, SmallDots, scale);
				}
				return;
			}
			if ((Object)(object)_button == (Object)null)
			{
				CreateButton(minimap);
			}
			if (RouteStore.Refresh() && MapView.Get(minimap, out var view2))
			{
				if (_current != null && !RouteStore.Routes.Contains(_current))
				{
					_current = null;
				}
				RouteArt.ShowQuillCursor(Drawing);
				if (Drawing)
				{
					ContinueStroke(view2);
					Pan(minimap, view2);
				}
				DrawBorders(minimap, view2);
				DrawRoutes(minimap, view2, LargeDots, 1f);
			}
		}

		internal static void ToggleDrawing(Minimap minimap)
		{
			if (Drawing)
			{
				StopDrawing(minimap);
				return;
			}
			Drawing = true;
			FieldInfo[] vanillaFrameFields = VanillaFrameFields;
			for (int i = 0; i < vanillaFrameFields.Length; i++)
			{
				object? obj = vanillaFrameFields[i]?.GetValue(minimap);
				Behaviour val = (Behaviour)((obj is Behaviour) ? obj : null);
				if (val != null && (Object)(object)val != (Object)null)
				{
					val.enabled = false;
				}
			}
			if ((Object)(object)_buttonFrame != (Object)null)
			{
				_buttonFrame.enabled = true;
			}
		}

		internal static void StopDrawing(Minimap minimap)
		{
			if (Drawing)
			{
				Drawing = false;
				EndStroke(minimap);
				_rightHeld = false;
				if ((Object)(object)_buttonFrame != (Object)null)
				{
					_buttonFrame.enabled = false;
				}
				RouteArt.ShowQuillCursor(show: false);
				object obj = SelectedTypeField?.GetValue(minimap);
				if (obj != null)
				{
					SelectIconMethod?.Invoke(minimap, new object[1] { obj });
				}
			}
		}

		internal static void StartStroke(Minimap minimap)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			EndStroke(minimap);
			if (RouteStore.Refresh() && MapView.Get(minimap, out var view) && view.Pointer(out var local))
			{
				_current = new List<Vector3> { view.ToWorld(local) };
				RouteStore.Routes.Add(_current);
			}
		}

		internal static void EndStroke(Minimap minimap)
		{
			if (_current != null)
			{
				FinishStroke(MapView.Get(minimap, out var view) ? new MapView?(view) : ((MapView?)null));
			}
		}

		private static void ContinueStroke(MapView view)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (_current == null)
			{
				return;
			}
			Vector2 local;
			if (GetMouseButton != null && !GetMouseButton(0))
			{
				FinishStroke(view);
			}
			else if (view.Pointer(out local))
			{
				Vector2 val = view.ToLocal(_current[_current.Count - 1]) - local;
				if (((Vector2)(ref val)).magnitude >= 4f)
				{
					_current.Add(view.ToWorld(local));
				}
			}
		}

		private static void FinishStroke(MapView? view)
		{
			if (_current.Count < 2)
			{
				RouteStore.Routes.Remove(_current);
			}
			else if (view.HasValue)
			{
				Thin(_current, view.Value);
			}
			_current = null;
			RouteStore.Save();
		}

		private static void Pan(Minimap minimap, MapView view)
		{
			//IL_000f: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			if (GetMouseButton == null || GetMouseButtonDown == null)
			{
				return;
			}
			Vector2 val = PointerPosition();
			if (GetMouseButtonDown(1) && view.Pointer(out var _))
			{
				_rightHeld = true;
				_rightPressedAt = val;
				_rightLast = val;
			}
			else
			{
				if (!_rightHeld)
				{
					return;
				}
				if (!GetMouseButton(1))
				{
					_rightHeld = false;
					return;
				}
				Vector2 val2 = default(Vector2);
				Vector2 val3 = default(Vector2);
				if (RectTransformUtility.ScreenPointToLocalPointInRectangle(view.Rect, _rightLast, (Camera)null, ref val2) && RectTransformUtility.ScreenPointToLocalPointInRectangle(view.Rect, val, (Camera)null, ref val3))
				{
					float num = ((Rect)(ref view.Uv)).width * view.TextureSize * view.PixelSize / view.Size.x;
					Vector2 val4 = (val3 - val2) * num;
					ref Vector3 reference = ref MapOffsetRef.Invoke(minimap);
					reference -= new Vector3(val4.x, 0f, val4.y);
				}
				_rightLast = val;
			}
		}

		internal static bool RightDragged()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (Drawing)
			{
				Vector2 val = PointerPosition() - _rightPressedAt;
				return ((Vector2)(ref val)).magnitude > 6f;
			}
			return false;
		}

		private static void Thin(List<Vector3> route, MapView view)
		{
			//IL_007e: 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_0098: 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)
			if (route.Count < 3)
			{
				return;
			}
			List<Vector2> list = route.ConvertAll(((MapView)view).ToLocal);
			bool[] array = new bool[route.Count];
			array[0] = true;
			array[route.Count - 1] = true;
			Stack<KeyValuePair<int, int>> stack = new Stack<KeyValuePair<int, int>>();
			stack.Push(new KeyValuePair<int, int>(0, route.Count - 1));
			while (stack.Count > 0)
			{
				KeyValuePair<int, int> keyValuePair = stack.Pop();
				int num = -1;
				float num2 = 1.5f;
				for (int i = keyValuePair.Key + 1; i < keyValuePair.Value; i++)
				{
					float num3 = DistanceToSegment(list[i], list[keyValuePair.Key], list[keyValuePair.Value]);
					if (num3 > num2)
					{
						num2 = num3;
						num = i;
					}
				}
				if (num >= 0)
				{
					array[num] = true;
					stack.Push(new KeyValuePair<int, int>(keyValuePair.Key, num));
					stack.Push(new KeyValuePair<int, int>(num, keyValuePair.Value));
				}
			}
			List<Vector3> list2 = new List<Vector3>();
			for (int j = 0; j < route.Count; j++)
			{
				if (array[j])
				{
					list2.Add(route[j]);
				}
			}
			route.Clear();
			route.AddRange(list2);
		}

		internal static bool RemoveRouteUnderPointer(Minimap minimap)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_0079: 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)
			if (!RouteStore.Refresh() || !MapView.Get(minimap, out var view) || !view.Pointer(out var local))
			{
				return false;
			}
			if (GetClosestPinToCursorMethod != null && GetClosestPinToCursorMethod.Invoke(minimap, null) != null)
			{
				return false;
			}
			List<Vector3> list = null;
			float num = 12f;
			foreach (List<Vector3> route in RouteStore.Routes)
			{
				for (int i = 1; i < route.Count; i++)
				{
					float num2 = DistanceToSegment(local, view.ToLocal(route[i - 1]), view.ToLocal(route[i]));
					if (num2 < num)
					{
						num = num2;
						list = route;
					}
				}
			}
			if (list == null)
			{
				return false;
			}
			if (list == _current)
			{
				_current = null;
			}
			RouteStore.Routes.Remove(list);
			RouteStore.Save();
			return true;
		}

		private static void CreateButton(Minimap minimap)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			object? obj = VanillaFrameFields[0]?.GetValue(minimap);
			Component val = (Component)((obj is Component) ? obj : null);
			RectTransform val2 = (RectTransform)(((Object)(object)val == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			try
			{
				LogLayout(minimap);
				GameObject obj2 = Object.Instantiate<GameObject>(((Component)val2).gameObject, ((Transform)val2).parent);
				((Object)obj2).name = "MapRoutesQuill";
				_button = obj2;
				RectTransform val3 = (RectTransform)obj2.transform;
				((Transform)val3).SetSiblingIndex(((Transform)val2).GetSiblingIndex());
				if (!Ui.HasLayoutGroup(((Transform)val2).parent))
				{
					object? obj3 = VanillaFrameFields[1]?.GetValue(minimap);
					Component val4 = (Component)((obj3 is Component) ? obj3 : null);
					RectTransform val5 = (RectTransform)(((Object)(object)val4 == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
					? val6;
					if (!((Object)(object)val5 == (Object)null))
					{
						val6 = val5.anchoredPosition - val2.anchoredPosition;
					}
					else
					{
						Rect rect = val2.rect;
						val6 = new Vector2(0f, 0f - ((Rect)(ref rect)).height);
					}
					Vector2 val7 = (Vector2)val6;
					Transform parent = ((Transform)val2).parent;
					MakeRoom((RectTransform)(object)((parent is RectTransform) ? parent : null), -val7);
					val3.anchoredPosition = val2.anchoredPosition - val7;
				}
				Behaviour image = Ui.GetImage((Component)(object)obj2.transform);
				if ((Object)(object)image != (Object)null)
				{
					Sprite val8 = RouteArt.Quill();
					if ((Object)(object)val8 != (Object)null)
					{
						Ui.SetSprite(image, val8, preserveAspect: true);
					}
					Ui.SetColor(image, Color.white);
				}
				Transform val9 = obj2.transform.Find(((Object)val).name);
				_buttonFrame = (((Object)(object)val9 == (Object)null) ? null : Ui.GetImage((Component)(object)val9));
				if ((Object)(object)_buttonFrame != (Object)null)
				{
					_buttonFrame.enabled = Drawing;
				}
				Rewire(obj2, minimap);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Adding the quill button failed: {arg}");
			}
		}

		private static void MakeRoom(RectTransform panel, Vector2 growth)
		{
			//IL_000a: 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)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Expected O, but got Unknown
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: 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_0209: 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)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)panel == (Object)null || panel.anchorMin != panel.anchorMax || growth == Vector2.zero)
			{
				return;
			}
			List<KeyValuePair<RectTransform, Vector3>> list = new List<KeyValuePair<RectTransform, Vector3>>();
			foreach (Transform item in (Transform)panel)
			{
				object obj = (object)item;
				RectTransform val = (RectTransform)((obj is RectTransform) ? obj : null);
				if (val != null && val.anchorMin == val.anchorMax)
				{
					list.Add(new KeyValuePair<RectTransform, Vector3>(val, ((Transform)val).position));
				}
			}
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(Mathf.Abs(growth.x), Mathf.Abs(growth.y));
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor((growth.x > 0f) ? (panel.pivot.x * val2.x) : ((0f - (1f - panel.pivot.x)) * val2.x), (growth.y > 0f) ? (panel.pivot.y * val2.y) : ((0f - (1f - panel.pivot.y)) * val2.y));
			panel.sizeDelta += val2;
			panel.anchoredPosition += val3;
			foreach (KeyValuePair<RectTransform, Vector3> item2 in list)
			{
				((Transform)item2.Key).position = item2.Value;
			}
			Rect val4 = WorldRect(panel);
			Vector3 val5 = ((Transform)panel).TransformVector(Vector2.op_Implicit(growth));
			foreach (Transform item3 in ((Transform)panel).parent)
			{
				Transform val6 = item3;
				if ((Object)(object)val6 == (Object)(object)panel)
				{
					continue;
				}
				RectTransform val7 = (RectTransform)(object)((val6 is RectTransform) ? val6 : null);
				if (val7 != null && !(val7.anchorMin != val7.anchorMax) && !((Object)(object)Ui.GetImage((Component)(object)val6) == (Object)null))
				{
					Rect val8 = WorldRect(val7);
					if (((Rect)(ref val8)).Overlaps(val4))
					{
						((Transform)val7).position = ((Transform)val7).position + val5;
					}
				}
			}
		}

		private static Rect WorldRect(RectTransform rect)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			rect.GetWorldCorners(array);
			return Rect.MinMaxRect(array[0].x, array[0].y, array[2].x, array[2].y);
		}

		private static void LogLayout(Minimap minimap)
		{
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Expected O, but got Unknown
			List<Transform> list = new List<Transform>();
			FieldInfo[] vanillaFrameFields = VanillaFrameFields;
			foreach (FieldInfo fieldInfo in vanillaFrameFields)
			{
				object? obj = fieldInfo?.GetValue(minimap);
				object? obj2 = ((obj is Component) ? obj : null);
				Transform obj3 = ((obj2 != null) ? ((Component)obj2).transform.parent : null);
				RectTransform val = (RectTransform)(object)((obj3 is RectTransform) ? obj3 : null);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Plugin.Log.LogInfo((object)("Map button " + fieldInfo.Name + ": " + Describe((Transform)(object)val)));
				Transform parent = ((Transform)val).parent;
				while ((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)minimap.m_largeRoot.transform.parent)
				{
					if (!list.Contains(parent))
					{
						list.Add(parent);
					}
					parent = parent.parent;
				}
			}
			foreach (Transform item in list)
			{
				Plugin.Log.LogInfo((object)("Map panel " + Path(item, minimap) + ": " + Describe(item)));
				foreach (Transform item2 in item)
				{
					Transform val2 = item2;
					if (!list.Contains(val2) && (Object)(object)Ui.GetImage((Component)(object)val2) != (Object)null)
					{
						Plugin.Log.LogInfo((object)("  child " + ((Object)val2).name + ": " + Describe(val2)));
					}
				}
			}
		}

		private static string Describe(Transform transform)
		{
			//IL_010d: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			Behaviour image = Ui.GetImage((Component)(object)transform);
			string text = (Ui.HasLayoutGroup(transform) ? ", layout group" : "");
			object obj;
			if (!((Object)(object)image != (Object)null) || !image.enabled)
			{
				obj = "";
			}
			else
			{
				Sprite sprite = Ui.GetSprite(image);
				obj = ", image " + (((sprite != null) ? ((Object)sprite).name : null) ?? "none");
			}
			string text2 = (string)obj;
			if (!((Object)(object)val == (Object)null))
			{
				string text3 = $"{((Object)transform).name}, anchored {val.anchoredPosition}, anchors {val.anchorMin}-{val.anchorMax}, ";
				object[] obj2 = new object[5] { val.pivot, null, null, null, null };
				Rect rect = val.rect;
				obj2[1] = ((Rect)(ref rect)).size;
				obj2[2] = ((Transform)val).position;
				obj2[3] = text2;
				obj2[4] = text;
				return text3 + string.Format("pivot {0}, size {1}, world {2}{3}{4}", obj2);
			}
			return $"{((Object)transform).name} world {transform.position}";
		}

		private static string Path(Transform transform, Minimap minimap)
		{
			string text = ((Object)transform).name;
			Transform parent = transform.parent;
			while ((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)((Component)minimap).transform)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text;
		}

		private static void Rewire(GameObject copy, Minimap minimap)
		{
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Expected O, but got Unknown
			Component[] componentsInChildren = copy.GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				string name = ((object)val).GetType().Name;
				if (name == "UIGamePad")
				{
					Object.Destroy((Object)(object)val);
					continue;
				}
				if (name == "UITooltip")
				{
					AccessTools.Field(((object)val).GetType(), "m_text")?.SetValue(val, "Draw route");
				}
				Type type = ((object)val).GetType();
				while (type != null && type != typeof(Component))
				{
					FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (FieldInfo fieldInfo in fields)
					{
						if (typeof(UnityEventBase).IsAssignableFrom(fieldInfo.FieldType) && !fieldInfo.FieldType.IsAbstract && fieldInfo.FieldType.GetConstructor(Type.EmptyTypes) != null)
						{
							fieldInfo.SetValue(val, Activator.CreateInstance(fieldInfo.FieldType));
						}
					}
					type = type.BaseType;
				}
			}
			Ui.OnClick(copy, (UnityAction)delegate
			{
				ToggleDrawing(minimap);
			});
		}

		private static void DrawRoutes(Minimap minimap, MapView view, DotLayer layer, float scale)
		{
			//IL_000f: 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_002d: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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)
			//IL_006c: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			Prepare(layer, view, scale, "MapRoutes");
			Color color = RouteArt.Red(minimap);
			foreach (List<Vector3> route in RouteStore.Routes)
			{
				DrawLine(layer, view, route, color);
				if (route.Count == 1)
				{
					Vector2 val = view.ToLocal(route[0]);
					if (val.x >= 0f && val.y >= 0f && val.x <= view.Size.x && val.y <= view.Size.y)
					{
						PlaceDot(layer, val, color);
					}
				}
			}
			HideUnused(layer);
		}

		private static void DrawBorders(Minimap minimap, MapView view)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			Prepare(BorderDots, view, 1f, "MapRoutesBiomeBorders", below: true);
			if (Plugin.BiomeBordersEnabled.Value && BiomeBorders.Refresh(minimap))
			{
				float num = BorderDots.Size / 4.5f;
				Vector2 dash = default(Vector2);
				((Vector2)(ref dash))..ctor(6f * num, 1.5f * num);
				float period = 11f * num;
				foreach (List<Vector3> line in BiomeBorders.Lines)
				{
					DrawDashes(view, line, dash, period);
				}
			}
			HideUnused(BorderDots);
		}

		private static void Prepare(DotLayer layer, MapView view, float scale, string name, bool below = false)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)layer.Root == (Object)null)
			{
				GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
				layer.Root = (RectTransform)val.transform;
				((Transform)layer.Root).SetParent((Transform)(object)view.Rect, false);
				if (below)
				{
					((Transform)layer.Root).SetAsFirstSibling();
				}
				layer.Root.anchorMin = Vector2.zero;
				layer.Root.anchorMax = Vector2.one;
				layer.Root.offsetMin = Vector2.zero;
				layer.Root.offsetMax = Vector2.zero;
				layer.Dots.Clear();
				layer.Colors.Clear();
			}
			scale *= Mathf.Clamp(Mathf.Pow(0.05f / Mathf.Max(((Rect)(ref view.Uv)).width, 0.0001f), 0.4f), 0.45f, 1f);
			layer.Size = 4.5f * scale;
			layer.Spacing = 9f * scale;
			layer.Used = 0;
		}

		private static void DrawLine(DotLayer layer, MapView view, List<Vector3> line, Color color)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//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)
			float along = 0f;
			for (int i = 1; i < line.Count; i++)
			{
				along = DrawSegment(layer, view.ToLocal(line[i - 1]), view.ToLocal(line[i]), along, view.Size, color);
			}
		}

		private static void DrawDashes(MapView view, List<Vector3> line, Vector2 dash, float period)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_006f: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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_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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			for (int i = 1; i < line.Count; i++)
			{
				Vector2 val = view.ToLocal(line[i - 1]);
				Vector2 val2 = view.ToLocal(line[i]);
				Vector2 val3 = val2 - val;
				float magnitude = ((Vector2)(ref val3)).magnitude;
				if (magnitude >= 0.01f && Clip(val, val2, view.Size, out var t, out var t2))
				{
					Vector2 val4 = (val2 - val) / magnitude;
					float num2 = Mathf.Atan2(val4.y, val4.x) * 57.29578f;
					for (float num3 = Mathf.Ceil((num + t * magnitude) / period) * period - num; num3 <= t2 * magnitude; num3 += period)
					{
						Vector2 val5 = val + val4 * (num3 + dash.x / 2f);
						if (BiomeBorders.IsExplored(view.ToWorld(val5)))
						{
							if (!PlaceDot(BorderDots, val5, BorderColor))
							{
								return;
							}
							RectTransform val6 = (RectTransform)((Component)BorderDots.Dots[BorderDots.Used - 1]).transform;
							val6.sizeDelta = dash;
							((Transform)val6).localRotation = Quaternion.Euler(0f, 0f, num2);
						}
					}
				}
				num += magnitude;
			}
		}

		private static void HideUnused(DotLayer layer)
		{
			for (int i = layer.Used; i < layer.Dots.Count; i++)
			{
				if (((Component)layer.Dots[i]).gameObject.activeSelf)
				{
					((Component)layer.Dots[i]).gameObject.SetActive(false);
				}
			}
		}

		private static float DrawSegment(DotLayer layer, Vector2 a, Vector2 b, float along, Vector2 size, Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = b - a;
			float magnitude = ((Vector2)(ref val)).magnitude;
			if (magnitude < 0.01f || !Clip(a, b, size, out var t, out var t2))
			{
				return along + magnitude;
			}
			Vector2 val2 = (b - a) / magnitude;
			for (float num = Mathf.Ceil((along + t * magnitude) / layer.Spacing) * layer.Spacing - along; num <= t2 * magnitude && PlaceDot(layer, a + val2 * num, color); num += layer.Spacing)
			{
			}
			return along + magnitude;
		}

		private static bool PlaceDot(DotLayer layer, Vector2 position, Color color)
		{
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_006f: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			if (layer.Used >= 6000)
			{
				return false;
			}
			if (layer.Used == layer.Dots.Count)
			{
				GameObject val = new GameObject("Dot", new Type[1] { typeof(RectTransform) });
				val.transform.SetParent((Transform)(object)layer.Root, false);
				Behaviour val2 = Ui.AddImage(val);
				Ui.SetSprite(val2, RouteArt.Dot);
				Ui.SetRaycastTarget(val2, value: false);
				Ui.SetColor(val2, color);
				RectTransform val3 = (RectTransform)val.transform;
				val3.anchorMin = Vector2.zero;
				val3.anchorMax = Vector2.zero;
				val3.pivot = new Vector2(0.5f, 0.5f);
				layer.Dots.Add(val2);
				layer.Colors.Add(color);
			}
			Behaviour val4 = layer.Dots[layer.Used];
			if (layer.Colors[layer.Used] != color)
			{
				Ui.SetColor(val4, color);
				layer.Colors[layer.Used] = color;
			}
			layer.Used++;
			RectTransform val5 = (RectTransform)((Component)val4).transform;
			val5.anchoredPosition = position;
			val5.sizeDelta = new Vector2(layer.Size, layer.Size);
			if (!((Component)val4).gameObject.activeSelf)
			{
				((Component)val4).gameObject.SetActive(true);
			}
			return true;
		}

		private static bool Clip(Vector2 a, Vector2 b, Vector2 size, out float t0, out float t1)
		{
			//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)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			t0 = 0f;
			t1 = 1f;
			Vector2 val = b - a;
			if (ClipEdge(0f - val.x, a.x, ref t0, ref t1) && ClipEdge(val.x, size.x - a.x, ref t0, ref t1) && ClipEdge(0f - val.y, a.y, ref t0, ref t1))
			{
				return ClipEdge(val.y, size.y - a.y, ref t0, ref t1);
			}
			return false;
		}

		private static bool ClipEdge(float p, float q, ref float t0, ref float t1)
		{
			if (Mathf.Approximately(p, 0f))
			{
				return q >= 0f;
			}
			float num = q / p;
			if (p < 0f)
			{
				if (num > t1)
				{
					return false;
				}
				t0 = Mathf.Max(t0, num);
			}
			else
			{
				if (num < t0)
				{
					return false;
				}
				t1 = Mathf.Min(t1, num);
			}
			return true;
		}

		internal static float DistanceToSegment(Vector2 p, Vector2 a, Vector2 b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = b - a;
			float num = ((((Vector2)(ref val)).sqrMagnitude < 0.0001f) ? 0f : Mathf.Clamp01(Vector2.Dot(p - a, val) / ((Vector2)(ref val)).sqrMagnitude));
			Vector2 val2 = p - (a + val * num);
			return ((Vector2)(ref val2)).magnitude;
		}

		private static Func<int, bool> MouseButtonMethod(string name)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(ZInput), name, new Type[1] { typeof(int) }, (Type[])null);
			if (!(methodInfo == null))
			{
				return AccessTools.MethodDelegate<Func<int, bool>>(methodInfo, (object)null, true);
			}
			return null;
		}

		private static Vector2 PointerPosition()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (PointerPositionGetter != null)
			{
				return Vector2.op_Implicit((Vector3)PointerPositionGetter.Invoke(null, null));
			}
			return Vector2.op_Implicit(Input.mousePosition);
		}
	}
	internal static class RouteStore
	{
		private const string KeyPrefix = "dev.pgarcia.maproutes.Routes.";

		private static readonly FieldRef<Player, Dictionary<string, string>> CustomDataRef = AccessTools.FieldRefAccess<Player, Dictionary<string, string>>("m_customData");

		private static Player _loadedFor;

		private static string _loadedKey;

		internal static readonly List<List<Vector3>> Routes = new List<List<Vector3>>();

		internal static bool Refresh()
		{
			Player localPlayer = Player.m_localPlayer;
			string text = Key();
			if ((Object)(object)localPlayer == (Object)null || text == null)
			{
				return false;
			}
			if ((Object)(object)localPlayer == (Object)(object)_loadedFor && text == _loadedKey)
			{
				return true;
			}
			_loadedFor = localPlayer;
			_loadedKey = text;
			Routes.Clear();
			try
			{
				if (CustomDataRef.Invoke(localPlayer).TryGetValue(text, out var value) && !string.IsNullOrEmpty(value))
				{
					Parse(value);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Loading routes failed: {arg}");
			}
			return true;
		}

		internal static void Save()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)localPlayer != (Object)(object)_loadedFor || _loadedKey == null)
			{
				return;
			}
			try
			{
				Dictionary<string, string> dictionary = CustomDataRef.Invoke(localPlayer);
				string text = Format();
				if (text.Length == 0)
				{
					dictionary.Remove(_loadedKey);
				}
				else
				{
					dictionary[_loadedKey] = text;
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Saving routes failed: {arg}");
			}
		}

		private static string Key()
		{
			if (!((Object)(object)ZNet.instance == (Object)null))
			{
				return "dev.pgarcia.maproutes.Routes." + ZNet.instance.GetWorldUID().ToString(CultureInfo.InvariantCulture);
			}
			return null;
		}

		private static void Parse(string data)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			string[] array = data.Split(new char[1] { '\n' });
			foreach (string obj in array)
			{
				List<Vector3> list = new List<Vector3>();
				string[] array2 = obj.Split(new char[1] { ';' });
				for (int j = 0; j < array2.Length; j++)
				{
					string[] array3 = array2[j].Split(new char[1] { ',' });
					if (array3.Length == 2 && float.TryParse(array3[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array3[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
					{
						list.Add(new Vector3(result, 0f, result2));
					}
				}
				if (list.Count >= 2)
				{
					Routes.Add(list);
				}
			}
		}

		private static string Format()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder();
			foreach (List<Vector3> route in Routes)
			{
				if (route.Count < 2)
				{
					continue;
				}
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('\n');
				}
				for (int i = 0; i < route.Count; i++)
				{
					if (i > 0)
					{
						stringBuilder.Append(';');
					}
					stringBuilder.Append(route[i].x.ToString("0.#", CultureInfo.InvariantCulture)).Append(',').Append(route[i].z.ToString("0.#", CultureInfo.InvariantCulture));
				}
			}
			return stringBuilder.ToString();
		}
	}
	internal static class Ui
	{
		internal static readonly Type ImageType = AccessTools.TypeByName("UnityEngine.UI.Image");

		private static readonly Type ButtonType = AccessTools.TypeByName("UnityEngine.UI.Button");

		private static readonly Type LayoutGroupType = AccessTools.TypeByName("UnityEngine.UI.LayoutGroup");

		private static readonly PropertyInfo SpriteProperty = AccessTools.Property(ImageType, "sprite");

		private static readonly PropertyInfo PreserveAspectProperty = AccessTools.Property(ImageType, "preserveAspect");

		private static readonly PropertyInfo ColorProperty = AccessTools.Property(AccessTools.TypeByName("UnityEngine.UI.Graphic"), "color");

		private static readonly PropertyInfo RaycastTargetProperty = AccessTools.Property(AccessTools.TypeByName("UnityEngine.UI.Graphic"), "raycastTarget");

		private static readonly PropertyInfo UvRectProperty = AccessTools.Property(AccessTools.TypeByName("UnityEngine.UI.RawImage"), "uvRect");

		private static readonly PropertyInfo OnClickProperty = AccessTools.Property(ButtonType, "onClick");

		internal static bool Available
		{
			get
			{
				if (ImageType != null && ButtonType != null && SpriteProperty != null && ColorProperty != null && RaycastTargetProperty != null && UvRectProperty != null)
				{
					return OnClickProperty != null;
				}
				return false;
			}
		}

		internal static Behaviour GetImage(Component component)
		{
			if (!((Object)(object)component == (Object)null))
			{
				Component component2 = component.GetComponent(ImageType);
				return (Behaviour)(object)((component2 is Behaviour) ? component2 : null);
			}
			return null;
		}

		internal static Behaviour AddImage(GameObject go)
		{
			Component obj = go.AddComponent(ImageType);
			return (Behaviour)(object)((obj is Behaviour) ? obj : null);
		}

		internal static Sprite GetSprite(Behaviour image)
		{
			object? value = SpriteProperty.GetValue(image, null);
			return (Sprite)((value is Sprite) ? value : null);
		}

		internal static void SetSprite(Behaviour image, Sprite sprite, bool preserveAspect = false)
		{
			SpriteProperty.SetValue(image, sprite, null);
			PreserveAspectProperty?.SetValue(image, preserveAspect, null);
		}

		internal static Color GetColor(Behaviour graphic)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return (Color)ColorProperty.GetValue(graphic, null);
		}

		internal static void SetColor(Behaviour graphic, Color color)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			ColorProperty.SetValue(graphic, color, null);
		}

		internal static void SetRaycastTarget(Behaviour graphic, bool value)
		{
			RaycastTargetProperty.SetValue(graphic, value, null);
		}

		internal static Rect UvRect(Component rawImage)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return (Rect)UvRectProperty.GetValue(rawImage, null);
		}

		internal static bool HasLayoutGroup(Transform transform)
		{
			if (LayoutGroupType != nu