Decompiled source of PortalSkidmarks v0.4.0

PortalSkidmarks.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("Adam Robichaud")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2026 Adam Robichaud")]
[assembly: AssemblyDescription("Draws portal connections on the Valheim map.")]
[assembly: AssemblyFileVersion("0.4.0.0")]
[assembly: AssemblyInformationalVersion("0.4.0+a6a38e1a59525528c76e63c9d5e4802b788831c3")]
[assembly: AssemblyProduct("PortalSkidmarks")]
[assembly: AssemblyTitle("PortalSkidmarks")]
[assembly: AssemblyVersion("0.4.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 PortalSkidmarks
{
	internal static class MapTooltip
	{
		private const float OffsetX = 18f;

		private const float OffsetY = 18f;

		private static RectTransform _root;

		private static TextMeshProUGUI _text;

		private static string _shown;

		internal static void Reset()
		{
			_root = null;
			_text = null;
			_shown = null;
		}

		internal static void Show(Minimap map, string label, Vector2 screenPoint)
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: 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_00c4: 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_00cc: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: 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_0144: 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_012d: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(label))
			{
				Hide();
				return;
			}
			RectTransform val = (RectTransform)(((Object)(object)map.m_largeRoot != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val == (Object)null || ((Object)(object)_root == (Object)null && !Create(map, val)))
			{
				return;
			}
			if (!((Component)_root).gameObject.activeSelf)
			{
				((Component)_root).gameObject.SetActive(true);
			}
			((Transform)_root).SetAsLastSibling();
			if (_shown != label)
			{
				_shown = label;
				((TMP_Text)_text).text = label;
				LayoutRebuilder.ForceRebuildLayoutImmediate(_root);
			}
			Vector2 val2 = default(Vector2);
			if (RectTransformUtility.ScreenPointToLocalPointInRectangle(val, screenPoint, (Camera)null, ref val2))
			{
				Rect rect = _root.rect;
				Vector2 size = ((Rect)(ref rect)).size;
				Rect rect2 = val.rect;
				float num = val2.x + 18f;
				float num2 = val2.y - 18f;
				if (num + size.x > ((Rect)(ref rect2)).xMax)
				{
					num = val2.x - 18f - size.x;
				}
				if (num2 - size.y < ((Rect)(ref rect2)).yMin)
				{
					num2 = val2.y + 18f + size.y;
				}
				((Transform)_root).localPosition = new Vector3(num, num2, 0f);
			}
		}

		internal static void Hide()
		{
			if ((Object)(object)_root != (Object)null && ((Component)_root).gameObject.activeSelf)
			{
				((Component)_root).gameObject.SetActive(false);
			}
		}

		private static bool Create(Minimap map, RectTransform parent)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0084: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("PortalSkidmarks_Tooltip", new Type[5]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image),
				typeof(HorizontalLayoutGroup),
				typeof(ContentSizeFitter)
			});
			_root = val.GetComponent<RectTransform>();
			((Transform)_root).SetParent((Transform)(object)parent, false);
			RectTransform root = _root;
			RectTransform root2 = _root;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			root2.anchorMax = val2;
			root.anchorMin = val2;
			_root.pivot = new Vector2(0f, 1f);
			((Transform)_root).localScale = Vector3.one;
			Image component = val.GetComponent<Image>();
			((Graphic)component).color = new Color(0f, 0f, 0f, 0.8f);
			((Graphic)component).raycastTarget = false;
			HorizontalLayoutGroup component2 = val.GetComponent<HorizontalLayoutGroup>();
			((LayoutGroup)component2).padding = new RectOffset(10, 10, 5, 5);
			((HorizontalOrVerticalLayoutGroup)component2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)component2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)component2).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)component2).childForceExpandHeight = false;
			ContentSizeFitter component3 = val.GetComponent<ContentSizeFitter>();
			component3.horizontalFit = (FitMode)2;
			component3.verticalFit = (FitMode)2;
			GameObject val3 = new GameObject("Text", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(TextMeshProUGUI)
			});
			((Transform)val3.GetComponent<RectTransform>()).SetParent((Transform)(object)_root, false);
			_text = val3.GetComponent<TextMeshProUGUI>();
			TMP_Text val4 = map.m_biomeNameLarge;
			if ((Object)(object)val4 == (Object)null || (Object)(object)val4.font == (Object)null)
			{
				val4 = Object.FindFirstObjectByType<TMP_Text>();
			}
			if ((Object)(object)val4 != (Object)null && (Object)(object)val4.font != (Object)null)
			{
				((TMP_Text)_text).font = val4.font;
				((TMP_Text)_text).fontSharedMaterial = val4.fontSharedMaterial;
			}
			((TMP_Text)_text).fontSize = 20f;
			((Graphic)_text).color = Color.white;
			((TMP_Text)_text).alignment = (TextAlignmentOptions)513;
			((TMP_Text)_text).richText = false;
			((Graphic)_text).raycastTarget = false;
			_shown = null;
			val.SetActive(false);
			return true;
		}
	}
	public static class OverlayToggle
	{
		[HarmonyPatch(typeof(Terminal), "InitTerminal")]
		private static class Terminal_InitTerminal_Patch
		{
			[Serializable]
			[CompilerGenerated]
			private sealed class <>c
			{
				public static readonly <>c <>9 = new <>c();

				public static ConsoleEvent <>9__0_0;

				internal void <Postfix>b__0_0(ConsoleEventArgs args)
				{
					bool flag;
					switch ((args.Length > 1) ? args[1].ToLowerInvariant() : "")
					{
					case "1":
					case "show":
					case "true":
					case "on":
						flag = true;
						break;
					case "0":
					case "hide":
					case "off":
					case "false":
						flag = false;
						break;
					case "":
						flag = !Visible;
						break;
					default:
					{
						Terminal context = args.Context;
						if (context != null)
						{
							context.AddString("Usage: portals [on|off]");
						}
						return;
					}
					}
					Set(flag, announce: false);
					Terminal context2 = args.Context;
					if (context2 != null)
					{
						context2.AddString(flag ? "Portal overlay: on" : "Portal overlay: off");
					}
				}
			}

			private static void Postfix()
			{
				//IL_0033: 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_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Expected O, but got Unknown
				object obj = <>c.<>9__0_0;
				if (obj == null)
				{
					ConsoleEvent val = delegate(ConsoleEventArgs args)
					{
						bool flag;
						switch ((args.Length > 1) ? args[1].ToLowerInvariant() : "")
						{
						case "1":
						case "show":
						case "true":
						case "on":
							flag = true;
							break;
						case "0":
						case "hide":
						case "off":
						case "false":
							flag = false;
							break;
						case "":
							flag = !Visible;
							break;
						default:
						{
							Terminal context = args.Context;
							if (context != null)
							{
								context.AddString("Usage: portals [on|off]");
							}
							return;
						}
						}
						Set(flag, announce: false);
						Terminal context2 = args.Context;
						if (context2 != null)
						{
							context2.AddString(flag ? "Portal overlay: on" : "Portal overlay: off");
						}
					};
					<>c.<>9__0_0 = val;
					obj = (object)val;
				}
				new ConsoleCommand("portals", "[on|off] Show or hide the PortalSkidmarks portal overlay on the map", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			}
		}

		private const string ToggleName = "PortalSkidmarks_Toggle";

		private static Toggle _mapToggle;

		private static RectTransform _mapRow;

		private static RectTransform _publicRow;

		private static RectTransform _sharedRow;

		private static readonly Vector3[] _corners = (Vector3[])(object)new Vector3[4];

		public static bool Visible => Plugin.ShowOverlay.Value;

		public static void Set(bool visible, bool announce)
		{
			if (Plugin.ShowOverlay.Value != visible)
			{
				Plugin.ShowOverlay.Value = visible;
			}
			if (announce && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				((Character)Player.m_localPlayer).Message((MessageType)1, visible ? "Portal overlay: on" : "Portal overlay: off", 0, (Sprite)null, false);
			}
		}

		internal static void Tick(Minimap map)
		{
			HandleHotkey();
			SyncMapToggle(map);
		}

		internal static void OnMinimapDestroyed()
		{
			_mapToggle = null;
			_mapRow = null;
			_publicRow = null;
			_sharedRow = null;
		}

		private static void HandleHotkey()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = Plugin.ToggleKey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey, false))
			{
				return;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
			{
				if (!ZInput.GetKey(modifier, false))
				{
					return;
				}
			}
			if (!IsTyping())
			{
				Set(!Visible, announce: true);
			}
		}

		private static bool IsTyping()
		{
			if (Minimap.InTextInput())
			{
				return true;
			}
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return true;
			}
			if (Console.IsVisible())
			{
				return true;
			}
			if (TextInput.IsVisible())
			{
				return true;
			}
			if (Menu.IsVisible())
			{
				return true;
			}
			return false;
		}

		private static void SyncMapToggle(Minimap map)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Invalid comparison between Unknown and I4
			if (!((Object)(object)map == (Object)null) && !((Object)(object)map.m_publicPosition == (Object)null) && (!((Object)(object)_mapToggle == (Object)null) || (Plugin.ShowMapToggle.Value && CreateMapRow(map))))
			{
				bool value = Plugin.ShowMapToggle.Value;
				if (((Component)_mapRow).gameObject.activeSelf != value)
				{
					((Component)_mapRow).gameObject.SetActive(value);
				}
				if (_mapToggle.isOn != Visible)
				{
					_mapToggle.SetIsOnWithoutNotify(Visible);
				}
				if (value && (int)map.m_mode == 2)
				{
					PositionMapRow();
				}
			}
		}

		private static bool CreateMapRow(Minimap map)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Expected O, but got Unknown
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Expected O, but got Unknown
			try
			{
				Transform stopAt = (((Object)(object)map.m_largeRoot != (Object)null) ? map.m_largeRoot.transform : null);
				_publicRow = RowOf((RectTransform)((Component)map.m_publicPosition).transform, stopAt);
				_sharedRow = null;
				if ((Object)(object)map.m_sharedMapHint != (Object)null)
				{
					Transform transform = map.m_sharedMapHint.transform;
					RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
					if (val != null)
					{
						RectTransform val2 = RowOf(val, stopAt);
						if ((Object)(object)val2 != (Object)(object)_publicRow && !((Transform)val2).IsChildOf((Transform)(object)_publicRow) && !((Transform)_publicRow).IsChildOf((Transform)(object)val2))
						{
							_sharedRow = val2;
						}
					}
				}
				GameObject val3 = Object.Instantiate<GameObject>(((Component)_publicRow).gameObject, ((Transform)_publicRow).parent);
				((Object)val3).name = "PortalSkidmarks_Toggle";
				UIGamePad[] componentsInChildren = val3.GetComponentsInChildren<UIGamePad>(true);
				foreach (UIGamePad val4 in componentsInChildren)
				{
					if ((Object)(object)val4.m_hint != (Object)null)
					{
						Object.DestroyImmediate((Object)(object)val4.m_hint);
					}
					Object.DestroyImmediate((Object)(object)val4);
				}
				MonoBehaviour[] componentsInChildren2 = val3.GetComponentsInChildren<MonoBehaviour>(true);
				foreach (MonoBehaviour val5 in componentsInChildren2)
				{
					if ((Object)(object)val5 != (Object)null && ((object)val5).GetType().Name.Contains("Locali"))
					{
						Object.DestroyImmediate((Object)(object)val5);
					}
				}
				Toggle componentInChildren = val3.GetComponentInChildren<Toggle>(true);
				if ((Object)(object)componentInChildren == (Object)null)
				{
					throw new InvalidOperationException("copied row has no Toggle");
				}
				componentInChildren.onValueChanged = new ToggleEvent();
				componentInChildren.group = null;
				componentInChildren.SetIsOnWithoutNotify(Visible);
				((UnityEvent<bool>)(object)componentInChildren.onValueChanged).AddListener((UnityAction<bool>)delegate(bool v)
				{
					Set(v, announce: false);
				});
				SetLabel(val3, "Portals");
				_mapRow = (RectTransform)val3.transform;
				_mapToggle = componentInChildren;
				if ((Object)(object)((Component)((Transform)_mapRow).parent).GetComponent<LayoutGroup>() != (Object)null)
				{
					int num = ((Transform)_publicRow).GetSiblingIndex();
					if ((Object)(object)_sharedRow != (Object)null && (Object)(object)((Transform)_sharedRow).parent == (Object)(object)((Transform)_publicRow).parent)
					{
						num = Mathf.Min(num, ((Transform)_sharedRow).GetSiblingIndex());
					}
					((Transform)_mapRow).SetSiblingIndex(num);
				}
				val3.SetActive(Plugin.ShowMapToggle.Value);
				Plugin.Log.LogInfo((object)("Added 'Portals' row to the large map (copied '" + PathOf((Transform)(object)_publicRow) + "', cartography row '" + PathOf((Transform)(object)_sharedRow) + "')"));
				return true;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"Could not add the map checkbox, use the hotkey or 'portals' command instead: {arg}");
				_mapToggle = null;
				_mapRow = null;
				Plugin.ShowMapToggle.Value = false;
				return false;
			}
		}

		private static RectTransform RowOf(RectTransform start, Transform stopAt)
		{
			//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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = start.rect;
			float height = ((Rect)(ref rect)).height;
			float num = Mathf.Max(height * 1.75f, height + 20f);
			RectTransform result = start;
			Transform parent = ((Transform)start).parent;
			while ((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)stopAt)
			{
				RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
				if ((Object)(object)val == (Object)null)
				{
					break;
				}
				rect = val.rect;
				if (((Rect)(ref rect)).height > num)
				{
					break;
				}
				result = val;
				parent = parent.parent;
			}
			return result;
		}

		private static void PositionMapRow()
		{
			//IL_004a: 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)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00a6: 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_00ae: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_mapRow == (Object)null) && !((Object)(object)_publicRow == (Object)null) && (!((Object)(object)((Transform)_mapRow).parent != (Object)null) || !((Object)(object)((Component)((Transform)_mapRow).parent).GetComponent<LayoutGroup>() != (Object)null)))
			{
				Rect pub = WorldRect(_publicRow);
				float num = ((Rect)(ref pub)).yMax;
				if ((Object)(object)_sharedRow != (Object)null && IsShown(_sharedRow))
				{
					float num2 = num;
					Rect val = WorldRect(_sharedRow);
					num = Mathf.Max(num2, ((Rect)(ref val)).yMax);
				}
				Vector2 value = Plugin.MapToggleOffset.Value;
				Vector3 lossyScale = ((Transform)_mapRow).lossyScale;
				Rect val2 = WorldRect(_mapRow);
				float num3 = num + RowGap(pub) + value.y * lossyScale.y - ((Rect)(ref val2)).yMin;
				float num4 = ((Rect)(ref pub)).center.x + value.x * lossyScale.x - ((Rect)(ref val2)).center.x;
				if (Mathf.Abs(num4) > 0.01f || Mathf.Abs(num3) > 0.01f)
				{
					RectTransform mapRow = _mapRow;
					((Transform)mapRow).position = ((Transform)mapRow).position + new Vector3(num4, num3, 0f);
				}
			}
		}

		private static float RowGap(Rect pub)
		{
			//IL_0012: 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)
			if ((Object)(object)_sharedRow != (Object)null)
			{
				Rect val = WorldRect(_sharedRow);
				float num = ((((Rect)(ref val)).yMin >= ((Rect)(ref pub)).yMax) ? (((Rect)(ref val)).yMin - ((Rect)(ref pub)).yMax) : (((Rect)(ref pub)).yMin - ((Rect)(ref val)).yMax));
				if (num >= 0f && num < ((Rect)(ref pub)).height)
				{
					return num;
				}
			}
			return ((Rect)(ref pub)).height * 0.2f;
		}

		private static bool IsShown(RectTransform row)
		{
			Transform val = (Transform)(object)row;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)((Transform)_publicRow).parent)
			{
				if (!((Component)val).gameObject.activeSelf)
				{
					return false;
				}
				val = val.parent;
			}
			return true;
		}

		private static Rect WorldRect(RectTransform rt)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			rt.GetWorldCorners(_corners);
			return Rect.MinMaxRect(_corners[0].x, _corners[0].y, _corners[2].x, _corners[2].y);
		}

		private static string PathOf(Transform t)
		{
			if ((Object)(object)t == (Object)null)
			{
				return "none";
			}
			string text = ((Object)t).name;
			Transform parent = t.parent;
			while ((Object)(object)parent != (Object)null && (Object)(object)parent.parent != (Object)null)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text;
		}

		private static void SetLabel(GameObject go, string text)
		{
			TMP_Text componentInChildren = go.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = text;
				return;
			}
			Text componentInChildren2 = go.GetComponentInChildren<Text>(true);
			if ((Object)(object)componentInChildren2 != (Object)null)
			{
				componentInChildren2.text = text;
			}
		}
	}
	[BepInPlugin("com.puhpuhburr.portalskidmarks", "PortalSkidmarks", "0.4.0")]
	public class Plugin : BaseUnityPlugin
	{
		public enum ColorMode
		{
			PerTag,
			Single
		}

		public const string GUID = "com.puhpuhburr.portalskidmarks";

		public const string NAME = "PortalSkidmarks";

		public const string VERSION = "0.4.0";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> BroadcastInterval;

		internal static ConfigEntry<float> LineThickness;

		internal static ConfigEntry<float> IdleOpacity;

		internal static ConfigEntry<float> HoverOpacity;

		internal static ConfigEntry<bool> ShowTooltip;

		internal static ConfigEntry<ColorMode> LineColorMode;

		internal static ConfigEntry<Color> SingleLineColor;

		internal static ConfigEntry<bool> ShowPortalPins;

		internal static ConfigEntry<bool> ShowUnconnectedPins;

		internal static ConfigEntry<bool> MarkUnconnected;

		internal static ConfigEntry<bool> ShowOnMinimap;

		internal static ConfigEntry<bool> ShowOverlay;

		internal static ConfigEntry<KeyboardShortcut> ToggleKey;

		internal static ConfigEntry<bool> ShowMapToggle;

		internal static ConfigEntry<Vector2> MapToggleOffset;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Expected O, but got Unknown
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "Master switch. When off, nothing is drawn and the server sends nothing.");
			BroadcastInterval = ((BaseUnityPlugin)this).Config.Bind<float>("1 - General", "BroadcastInterval", 5f, new ConfigDescription("Server only. Seconds between checks for portal changes to broadcast to clients.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>()));
			LineThickness = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Display", "LineThickness", 3f, new ConfigDescription("Thickness of connection lines on the large map, in UI pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 12f), Array.Empty<object>()));
			IdleOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Display", "IdleOpacity", 0.2f, new ConfigDescription("Opacity of portal markers and connection lines when the mouse is not over them.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>()));
			HoverOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Display", "HoverOpacity", 1f, new ConfigDescription("Opacity of a portal pair (both markers and their line) while the mouse is over any part of it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>()));
			ShowTooltip = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Display", "ShowTooltip", true, "Show the portal name next to the mouse while hovering a portal marker or connection line on the large map.");
			LineColorMode = ((BaseUnityPlugin)this).Config.Bind<ColorMode>("2 - Display", "LineColorMode", ColorMode.PerTag, "PerTag gives every portal tag its own colour so linked pairs are easy to tell apart. Single uses SingleLineColor for everything.");
			SingleLineColor = ((BaseUnityPlugin)this).Config.Bind<Color>("2 - Display", "SingleLineColor", new Color(0.35f, 0.85f, 1f), "Line colour used when LineColorMode is Single.");
			ShowPortalPins = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Display", "ShowPortalPins", true, "Add a portal pin (with its tag as the name) for every known portal.");
			ShowUnconnectedPins = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Display", "ShowUnconnectedPins", true, "Also add pins for portals that currently have no partner.");
			MarkUnconnected = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Display", "MarkUnconnected", true, "Append ' (no link)' to the pin name of unconnected portals.");
			ShowOnMinimap = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Display", "ShowOnMinimap", false, "Also draw connection lines on the small corner minimap.");
			ShowOverlay = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Toggle", "ShowOverlay", true, "Whether the portal overlay is shown. The hotkey, the map checkbox and the 'portals' console command all flip this, and the last state is remembered between sessions.");
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("3 - Toggle", "ToggleKey", new KeyboardShortcut((KeyCode)112, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Hotkey that toggles the overlay. Works anywhere in game except while typing in chat, the console or a text box. Set to None to disable.");
			ShowMapToggle = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Toggle", "ShowMapToggle", true, "Add a 'Portals' row to the large map, above the 'Cartography Table' row if shown, otherwise above 'Visible to other players'.");
			MapToggleOffset = ((BaseUnityPlugin)this).Config.Bind<Vector2>("3 - Toggle", "MapToggleOffset", Vector2.zero, "Extra offset in UI pixels for the map 'Portals' row, if it overlaps something in your UI layout.");
			_harmony = new Harmony("com.puhpuhburr.portalskidmarks");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"PortalSkidmarks 0.4.0 loaded");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	public struct PortalInfo
	{
		public ZDOID Id;

		public Vector3 Position;

		public string Tag;

		public ZDOID Target;

		public bool IsConnected => !((ZDOID)(ref Target)).IsNone();
	}
	public sealed class PortalSnapshot
	{
		public const int FormatVersion = 1;

		public readonly List<PortalInfo> Portals = new List<PortalInfo>();

		public int Fingerprint { get; private set; }

		public static PortalSnapshot FromWorld()
		{
			//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_004a: 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)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			PortalSnapshot portalSnapshot = new PortalSnapshot();
			if (ZDOMan.instance == null)
			{
				return portalSnapshot;
			}
			foreach (ZDO portal in ZDOMan.instance.GetPortalList())
			{
				if (portal != null)
				{
					portalSnapshot.Portals.Add(new PortalInfo
					{
						Id = portal.m_uid,
						Position = portal.GetPosition(),
						Tag = (portal.GetString(ZDOVars.s_tag, "") ?? string.Empty),
						Target = portal.GetConnectionZDOID((ConnectionType)1)
					});
				}
			}
			portalSnapshot.SortAndFingerprint();
			return portalSnapshot;
		}

		public void Write(ZPackage pkg)
		{
			//IL_0030: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			pkg.Write(1);
			pkg.Write(Portals.Count);
			foreach (PortalInfo portal in Portals)
			{
				pkg.Write(portal.Id);
				pkg.Write(portal.Position);
				pkg.Write(portal.Tag ?? string.Empty);
				pkg.Write(portal.Target);
			}
		}

		public static PortalSnapshot Read(ZPackage pkg)
		{
			//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_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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			PortalSnapshot portalSnapshot = new PortalSnapshot();
			int num = pkg.ReadInt();
			if (num != 1)
			{
				Plugin.Log.LogWarning((object)$"Received portal snapshot with format {num}, expected {1}. Ignoring.");
				return null;
			}
			int num2 = pkg.ReadInt();
			if (num2 < 0 || num2 > 200000)
			{
				return null;
			}
			for (int i = 0; i < num2; i++)
			{
				portalSnapshot.Portals.Add(new PortalInfo
				{
					Id = pkg.ReadZDOID(),
					Position = pkg.ReadVector3(),
					Tag = pkg.ReadString(),
					Target = pkg.ReadZDOID()
				});
			}
			portalSnapshot.SortAndFingerprint();
			return portalSnapshot;
		}

		private unsafe void SortAndFingerprint()
		{
			//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_0065: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			Portals.Sort(delegate(PortalInfo a, PortalInfo b)
			{
				int num4 = ((ZDOID)(ref a.Id)).UserID.CompareTo(((ZDOID)(ref b.Id)).UserID);
				return (num4 == 0) ? ((ZDOID)(ref a.Id)).ID.CompareTo(((ZDOID)(ref b.Id)).ID) : num4;
			});
			int num = 17;
			foreach (PortalInfo portal in Portals)
			{
				int num2 = num * 31;
				ZDOID id = portal.Id;
				num = num2 + ((object)(*(ZDOID*)(&id))/*cast due to .constrained prefix*/).GetHashCode();
				int num3 = num * 31;
				id = portal.Target;
				num = num3 + ((object)(*(ZDOID*)(&id))/*cast due to .constrained prefix*/).GetHashCode();
				num = num * 31 + (portal.Tag?.GetHashCode() ?? 0);
				num = num * 31 + Mathf.RoundToInt(portal.Position.x);
				num = num * 31 + Mathf.RoundToInt(portal.Position.z);
			}
			Fingerprint = num;
		}
	}
	public static class PortalMapRenderer
	{
		private struct DrawnLine
		{
			public Image Img;

			public Vector2 A;

			public Vector2 B;

			public long Key;

			public ZDOID IdA;

			public ZDOID IdB;

			public string Label;

			public string Tag;
		}

		private struct PortalPin
		{
			public PinData Pin;

			public ZDOID Id;
		}

		[HarmonyPatch(typeof(Minimap), "Update")]
		private static class Minimap_Update_Patch
		{
			private static void Postfix(Minimap __instance)
			{
				try
				{
					OnMinimapUpdate(__instance);
				}
				catch (Exception arg)
				{
					Plugin.Log.LogError((object)$"PortalSkidmarks render error: {arg}");
				}
			}
		}

		[HarmonyPatch(typeof(Minimap), "OnDestroy")]
		private static class Minimap_OnDestroy_Patch
		{
			private static void Prefix()
			{
				_lineRootLarge = null;
				_lineRootSmall = null;
				_poolLarge.Clear();
				_poolSmall.Clear();
				_linesLarge.Clear();
				_linesSmall.Clear();
				_pins.Clear();
				_renderedPinRevision = -1;
				_fallback = null;
				ClearHover();
				MapTooltip.Reset();
				OverlayToggle.OnMinimapDestroyed();
			}
		}

		private const string LineRootName = "PortalSkidmarks_Lines";

		private static int _renderedPinRevision = -1;

		private static float _lastFallbackScan;

		private static PortalSnapshot _fallback;

		private static RectTransform _lineRootLarge;

		private static RectTransform _lineRootSmall;

		private static readonly List<Image> _poolLarge = new List<Image>();

		private static readonly List<Image> _poolSmall = new List<Image>();

		private static readonly List<DrawnLine> _linesLarge = new List<DrawnLine>();

		private static readonly List<DrawnLine> _linesSmall = new List<DrawnLine>();

		private static readonly List<PortalPin> _pins = new List<PortalPin>();

		private static readonly HashSet<long> _drawnPairs = new HashSet<long>();

		private static readonly Dictionary<ZDOID, PortalInfo> _byId = new Dictionary<ZDOID, PortalInfo>();

		private static readonly HashSet<ZDOID> _hoverIds = new HashSet<ZDOID>();

		private static long _hoverKey;

		private static bool _hoverHasLine;

		private static void OnMinimapUpdate(Minimap map)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Invalid comparison between Unknown and I4
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Invalid comparison between Unknown and I4
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)map == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null))
			{
				OverlayToggle.Tick(map);
				bool flag = Plugin.Enabled.Value && OverlayToggle.Visible;
				PortalSnapshot portalSnapshot = (flag ? GetSnapshot() : null);
				SyncPins(map, portalSnapshot, flag);
				bool flag2 = flag && portalSnapshot != null && (int)map.m_mode == 2;
				bool draw = flag && portalSnapshot != null && (int)map.m_mode == 1 && Plugin.ShowOnMinimap.Value;
				if (portalSnapshot != null)
				{
					IndexPortals(portalSnapshot);
				}
				LayoutLines(map, portalSnapshot, map.m_mapImageLarge, map.m_pinRootLarge, ref _lineRootLarge, _poolLarge, _linesLarge, flag2);
				LayoutLines(map, portalSnapshot, map.m_mapImageSmall, map.m_pinRootSmall, ref _lineRootSmall, _poolSmall, _linesSmall, draw);
				ClearHover();
				string text = null;
				Vector2 screen = Vector2.zero;
				if (flag2 && TryGetPointer(map, out screen))
				{
					text = FindHover(map, portalSnapshot, screen);
				}
				ColorLines(_linesLarge);
				ColorLines(_linesSmall);
				ColorPins();
				if (flag2 && Plugin.ShowTooltip.Value && text != null)
				{
					MapTooltip.Show(map, text, screen);
				}
				else
				{
					MapTooltip.Hide();
				}
			}
		}

		private static PortalSnapshot GetSnapshot()
		{
			if (PortalSync.Current != null)
			{
				return PortalSync.Current;
			}
			if (Time.time - _lastFallbackScan > 2f)
			{
				_lastFallbackScan = Time.time;
				PortalSnapshot portalSnapshot = PortalSync.LocalFallback();
				if (_fallback == null || portalSnapshot.Fingerprint != _fallback.Fingerprint)
				{
					_fallback = portalSnapshot;
					_renderedPinRevision = -1;
				}
			}
			return _fallback;
		}

		private static void IndexPortals(PortalSnapshot snap)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			_byId.Clear();
			foreach (PortalInfo portal in snap.Portals)
			{
				_byId[portal.Id] = portal;
			}
		}

		private static string DisplayName(PortalInfo p)
		{
			string text = (string.IsNullOrEmpty(p.Tag) ? "(no tag)" : p.Tag);
			if (!p.IsConnected && Plugin.MarkUnconnected.Value)
			{
				text += " (no link)";
			}
			return text;
		}

		private static bool ShowsPin(PortalInfo p)
		{
			if (Plugin.ShowPortalPins.Value)
			{
				if (!p.IsConnected)
				{
					return Plugin.ShowUnconnectedPins.Value;
				}
				return true;
			}
			return false;
		}

		private static void SyncPins(Minimap map, PortalSnapshot snap, bool enabled)
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			bool flag = enabled && snap != null && Plugin.ShowPortalPins.Value;
			int num = ((!flag) ? (-2) : ((PortalSync.Current != null) ? PortalSync.Revision : snap.Fingerprint));
			if (num == _renderedPinRevision && (!flag || PinsStillPresent(map)))
			{
				return;
			}
			_renderedPinRevision = num;
			foreach (PortalPin pin in _pins)
			{
				map.RemovePin(pin.Pin);
			}
			_pins.Clear();
			if (!flag)
			{
				return;
			}
			foreach (PortalInfo portal in snap.Portals)
			{
				if (ShowsPin(portal))
				{
					PinData val = map.AddPin(portal.Position, (PinType)6, DisplayName(portal), false, false, 0L, default(PlatformUserID));
					if (val != null)
					{
						_pins.Add(new PortalPin
						{
							Pin = val,
							Id = portal.Id
						});
					}
				}
			}
		}

		private static bool PinsStillPresent(Minimap map)
		{
			if (_pins.Count == 0)
			{
				return true;
			}
			return Traverse.Create((object)map).Field<List<PinData>>("m_pins").Value?.Contains(_pins[0].Pin) ?? true;
		}

		private static void ColorPins()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//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_006b: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			float value = Plugin.IdleOpacity.Value;
			float value2 = Plugin.HoverOpacity.Value;
			foreach (PortalPin pin2 in _pins)
			{
				float num = (_hoverIds.Contains(pin2.Id) ? value2 : value);
				PinData pin = pin2.Pin;
				if ((Object)(object)pin.m_iconElement != (Object)null)
				{
					Color color = ((Graphic)pin.m_iconElement).color;
					if (!Mathf.Approximately(color.a, num))
					{
						color.a = num;
						((Graphic)pin.m_iconElement).color = color;
					}
				}
				if (pin.m_NamePinData != null && (Object)(object)pin.m_NamePinData.PinNameText != (Object)null)
				{
					Color color2 = ((Graphic)pin.m_NamePinData.PinNameText).color;
					if (!Mathf.Approximately(color2.a, num))
					{
						color2.a = num;
						((Graphic)pin.m_NamePinData.PinNameText).color = color2;
					}
				}
			}
		}

		private static void LayoutLines(Minimap map, PortalSnapshot snap, RawImage mapImage, RectTransform pinRoot, ref RectTransform lineRoot, List<Image> pool, List<DrawnLine> drawn, bool draw)
		{
			//IL_0075: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_010b: 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_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: 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_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			drawn.Clear();
			if ((Object)(object)mapImage == (Object)null || (Object)(object)pinRoot == (Object)null)
			{
				return;
			}
			if ((Object)(object)lineRoot == (Object)null)
			{
				lineRoot = CreateLineRoot(pinRoot);
				pool.Clear();
			}
			if (!draw)
			{
				if (((Component)lineRoot).gameObject.activeSelf)
				{
					((Component)lineRoot).gameObject.SetActive(false);
				}
				return;
			}
			if (!((Component)lineRoot).gameObject.activeSelf)
			{
				((Component)lineRoot).gameObject.SetActive(true);
			}
			Rect uvRect = mapImage.uvRect;
			Rect rect = ((Graphic)mapImage).rectTransform.rect;
			float value = Plugin.LineThickness.Value;
			_drawnPairs.Clear();
			int num = 0;
			foreach (PortalInfo portal in snap.Portals)
			{
				if (!portal.IsConnected || !_byId.TryGetValue(portal.Target, out var value2))
				{
					continue;
				}
				long num2 = PairKey(portal.Id, value2.Id);
				if (_drawnPairs.Add(num2))
				{
					Vector2 p = WorldToGui(map, portal.Position, uvRect, rect);
					Vector2 p2 = WorldToGui(map, value2.Position, uvRect, rect);
					if (ClipToRect(ref p, ref p2, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height))
					{
						Image line = GetLine(lineRoot, pool, num++);
						Vector2 val = p2 - p;
						RectTransform rectTransform = ((Graphic)line).rectTransform;
						rectTransform.anchoredPosition = p;
						rectTransform.sizeDelta = new Vector2(((Vector2)(ref val)).magnitude, value);
						((Transform)rectTransform).localRotation = Quaternion.Euler(0f, 0f, Mathf.Atan2(val.y, val.x) * 57.29578f);
						drawn.Add(new DrawnLine
						{
							Img = line,
							A = p,
							B = p2,
							Key = num2,
							IdA = portal.Id,
							IdB = value2.Id,
							Label = DisplayName(portal),
							Tag = portal.Tag
						});
					}
				}
			}
			for (int i = num; i < pool.Count; i++)
			{
				if ((Object)(object)pool[i] != (Object)null && ((Component)pool[i]).gameObject.activeSelf)
				{
					((Component)pool[i]).gameObject.SetActive(false);
				}
			}
		}

		private static void ColorLines(List<DrawnLine> drawn)
		{
			//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_0062: Unknown result type (might be due to invalid IL or missing references)
			float value = Plugin.IdleOpacity.Value;
			float value2 = Plugin.HoverOpacity.Value;
			foreach (DrawnLine item in drawn)
			{
				bool flag = _hoverHasLine && item.Key == _hoverKey;
				Color color = LineColor(item.Tag);
				color.a = (flag ? value2 : value);
				((Graphic)item.Img).color = color;
				if (flag)
				{
					((Transform)((Graphic)item.Img).rectTransform).SetAsLastSibling();
				}
			}
		}

		private static RectTransform CreateLineRoot(RectTransform pinRoot)
		{
			//IL_0018: 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_0036: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = new GameObject("PortalSkidmarks_Lines", new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)pinRoot, false);
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.pivot = Vector2.zero;
			component.anchoredPosition = Vector2.zero;
			component.sizeDelta = Vector2.zero;
			((Transform)component).localScale = Vector3.one;
			((Transform)component).SetAsFirstSibling();
			return component;
		}

		private static Image GetLine(RectTransform root, List<Image> pool, int index)
		{
			//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_004b: 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_006b: 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)
			while (pool.Count <= index)
			{
				GameObject val = new GameObject("line", new Type[3]
				{
					typeof(RectTransform),
					typeof(CanvasRenderer),
					typeof(Image)
				});
				RectTransform component = val.GetComponent<RectTransform>();
				((Transform)component).SetParent((Transform)(object)root, false);
				component.anchorMin = Vector2.zero;
				component.anchorMax = Vector2.zero;
				component.pivot = new Vector2(0f, 0.5f);
				((Transform)component).localScale = Vector3.one;
				Image component2 = val.GetComponent<Image>();
				((Graphic)component2).raycastTarget = false;
				component2.sprite = null;
				pool.Add(component2);
			}
			Image val2 = pool[index];
			if (!((Component)val2).gameObject.activeSelf)
			{
				((Component)val2).gameObject.SetActive(true);
			}
			return val2;
		}

		private static void ClearHover()
		{
			_hoverIds.Clear();
			_hoverKey = 0L;
			_hoverHasLine = false;
		}

		private static bool TryGetPointer(Minimap map, out Vector2 screen)
		{
			//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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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_0032: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)map.m_gamepadCrosshair != (Object)null && ((Component)map.m_gamepadCrosshair).gameObject.activeInHierarchy)
			{
				screen = RectTransformUtility.WorldToScreenPoint((Camera)null, ((Transform)map.m_gamepadCrosshair).position);
			}
			else
			{
				screen = Vector2.op_Implicit(ZInput.pointerPosition);
			}
			RectTransform rectTransform = ((Graphic)map.m_mapImageLarge).rectTransform;
			Vector2 val = default(Vector2);
			if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screen, (Camera)null, ref val))
			{
				return false;
			}
			Rect rect = rectTransform.rect;
			return ((Rect)(ref rect)).Contains(val);
		}

		private static string FindHover(Minimap map, PortalSnapshot snap, Vector2 screen)
		{
			//IL_0014: 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_0038: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: 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_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_lineRootLarge == (Object)null)
			{
				return null;
			}
			Vector2 val = default(Vector2);
			if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(_lineRootLarge, screen, (Camera)null, ref val))
			{
				return null;
			}
			Rect uvRect = map.m_mapImageLarge.uvRect;
			Rect rect = ((Graphic)map.m_mapImageLarge).rectTransform.rect;
			float num = map.m_pinSizeLarge * 0.5f;
			float num2 = num * num;
			bool flag = false;
			PortalInfo p = default(PortalInfo);
			foreach (PortalInfo portal in snap.Portals)
			{
				if (ShowsPin(portal))
				{
					Vector2 val2 = WorldToGui(map, portal.Position, uvRect, rect) - val;
					float sqrMagnitude = ((Vector2)(ref val2)).sqrMagnitude;
					if (sqrMagnitude < num2)
					{
						num2 = sqrMagnitude;
						p = portal;
						flag = true;
					}
				}
			}
			if (flag)
			{
				_hoverIds.Add(p.Id);
				if (p.IsConnected && _byId.ContainsKey(p.Target))
				{
					_hoverIds.Add(p.Target);
					_hoverKey = PairKey(p.Id, p.Target);
					_hoverHasLine = true;
				}
				return DisplayName(p);
			}
			float num3 = Mathf.Max(Plugin.LineThickness.Value * 0.5f + 4f, 6f);
			float num4 = num3 * num3;
			int num5 = -1;
			for (int i = 0; i < _linesLarge.Count; i++)
			{
				float num6 = SqrDistanceToSegment(val, _linesLarge[i].A, _linesLarge[i].B);
				if (num6 < num4)
				{
					num4 = num6;
					num5 = i;
				}
			}
			if (num5 < 0)
			{
				return null;
			}
			DrawnLine drawnLine = _linesLarge[num5];
			_hoverIds.Add(drawnLine.IdA);
			_hoverIds.Add(drawnLine.IdB);
			_hoverKey = drawnLine.Key;
			_hoverHasLine = true;
			return drawnLine.Label;
		}

		private static float SqrDistanceToSegment(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_0028: 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_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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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_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)
			//IL_0050: 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_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_001f: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = b - a;
			float sqrMagnitude = ((Vector2)(ref val)).sqrMagnitude;
			Vector2 val2;
			if (sqrMagnitude < 1E-06f)
			{
				val2 = p - a;
				return ((Vector2)(ref val2)).sqrMagnitude;
			}
			float num = Mathf.Clamp01(Vector2.Dot(p - a, val) / sqrMagnitude);
			val2 = p - (a + val * num);
			return ((Vector2)(ref val2)).sqrMagnitude;
		}

		private static Vector2 WorldToGui(Minimap map, Vector3 world, Rect uv, Rect rect)
		{
			//IL_000e: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			float num = (float)map.m_textureSize / 2f;
			float num2 = (world.x / map.m_pixelSize + num) / (float)map.m_textureSize;
			float num3 = (world.z / map.m_pixelSize + num) / (float)map.m_textureSize;
			return new Vector2((num2 - ((Rect)(ref uv)).xMin) / ((Rect)(ref uv)).width * ((Rect)(ref rect)).width, (num3 - ((Rect)(ref uv)).yMin) / ((Rect)(ref uv)).height * ((Rect)(ref rect)).height);
		}

		private static bool ClipToRect(ref Vector2 p0, ref Vector2 p1, float w, float h)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_0091: 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_0099: 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_00a6: 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_00b0: 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_00b5: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			float t = 0f;
			float t2 = 1f;
			float num = p1.x - p0.x;
			float num2 = p1.y - p0.y;
			if (!ClipEdge(0f - num, p0.x, ref t, ref t2))
			{
				return false;
			}
			if (!ClipEdge(num, w - p0.x, ref t, ref t2))
			{
				return false;
			}
			if (!ClipEdge(0f - num2, p0.y, ref t, ref t2))
			{
				return false;
			}
			if (!ClipEdge(num2, h - p0.y, ref t, ref t2))
			{
				return false;
			}
			Vector2 val = p0 + new Vector2(num, num2) * t;
			Vector2 val2 = p0 + new Vector2(num, num2) * t2;
			p0 = val;
			p1 = val2;
			return true;
		}

		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;
				}
				if (num > t0)
				{
					t0 = num;
				}
			}
			else
			{
				if (num < t0)
				{
					return false;
				}
				if (num < t1)
				{
					t1 = num;
				}
			}
			return true;
		}

		private unsafe static long PairKey(ZDOID a, ZDOID b)
		{
			int num = ((object)(*(ZDOID*)(&a))/*cast due to .constrained prefix*/).GetHashCode();
			int num2 = ((object)(*(ZDOID*)(&b))/*cast due to .constrained prefix*/).GetHashCode();
			if (num > num2)
			{
				int num3 = num;
				num = num2;
				num2 = num3;
			}
			return ((long)num << 32) ^ (uint)num2;
		}

		private static Color LineColor(string tag)
		{
			//IL_0012: 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 (Plugin.LineColorMode.Value == Plugin.ColorMode.Single)
			{
				return Plugin.SingleLineColor.Value;
			}
			return Color.HSVToRGB((float)((double)((!string.IsNullOrEmpty(tag)) ? ((uint)StringExtensionMethods.GetStableHashCode(tag)) : 0u) * 0.6180339887498949 % 1.0), 0.75f, 1f);
		}
	}
	public static class PortalSync
	{
		[HarmonyPatch(typeof(Game), "Start")]
		private static class Game_Start_Patch
		{
			private static void Postfix()
			{
				Register();
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnDestroy")]
		private static class ZNet_OnDestroy_Patch
		{
			private static void Postfix()
			{
				Reset();
			}
		}

		[HarmonyPatch(typeof(Game), "ConnectPortals")]
		private static class Game_ConnectPortals_Patch
		{
			private static void Postfix()
			{
				ServerTick();
			}
		}

		private const string RpcPortals = "PortalSkidmarks_Portals";

		private const string RpcRequest = "PortalSkidmarks_RequestPortals";

		private static int _lastBroadcastFingerprint;

		private static float _lastBroadcastTime;

		private static bool _registered;

		private static readonly HashSet<long> _peersUpToDate = new HashSet<long>();

		public static PortalSnapshot Current { get; private set; }

		public static int Revision { get; private set; }

		public static bool ServerHasMod { get; private set; }

		internal static void Reset()
		{
			Current = null;
			Revision++;
			ServerHasMod = false;
			_lastBroadcastFingerprint = 0;
			_lastBroadcastTime = 0f;
			_registered = false;
			_peersUpToDate.Clear();
		}

		private static void Register()
		{
			if (!_registered && ZRoutedRpc.instance != null)
			{
				_registered = true;
				_peersUpToDate.Clear();
				ZRoutedRpc.instance.Register<ZPackage>("PortalSkidmarks_Portals", (Action<long, ZPackage>)RPC_Portals);
				ZRoutedRpc.instance.Register("PortalSkidmarks_RequestPortals", (Action<long>)RPC_RequestPortals);
				if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer())
				{
					ZRoutedRpc.instance.InvokeRoutedRPC("PortalSkidmarks_RequestPortals", Array.Empty<object>());
					Plugin.Log.LogInfo((object)"Requested portal list from server");
				}
			}
		}

		private static void ServerTick()
		{
			if (!Plugin.Enabled.Value || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ZRoutedRpc.instance == null || (_lastBroadcastFingerprint != 0 && Time.time - _lastBroadcastTime < Plugin.BroadcastInterval.Value))
			{
				return;
			}
			PortalSnapshot portalSnapshot = PortalSnapshot.FromWorld();
			bool flag = portalSnapshot.Fingerprint != _lastBroadcastFingerprint;
			bool flag2 = false;
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer.IsReady() && !_peersUpToDate.Contains(peer.m_uid))
				{
					flag2 = true;
					break;
				}
			}
			if (!flag && !flag2)
			{
				return;
			}
			Broadcast(portalSnapshot, 0L);
			_lastBroadcastFingerprint = portalSnapshot.Fingerprint;
			_lastBroadcastTime = Time.time;
			_peersUpToDate.Clear();
			foreach (ZNetPeer peer2 in ZNet.instance.GetPeers())
			{
				if (peer2.IsReady())
				{
					_peersUpToDate.Add(peer2.m_uid);
				}
			}
			if (flag)
			{
				Plugin.Log.LogInfo((object)$"Broadcast {portalSnapshot.Portals.Count} portals to clients");
			}
		}

		private static void Broadcast(PortalSnapshot snap, long target)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			snap.Write(val);
			ZRoutedRpc.instance.InvokeRoutedRPC(target, "PortalSkidmarks_Portals", new object[1] { val });
		}

		private static void RPC_RequestPortals(long sender)
		{
			if (Plugin.Enabled.Value && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				PortalSnapshot portalSnapshot = PortalSnapshot.FromWorld();
				Broadcast(portalSnapshot, sender);
				_peersUpToDate.Add(sender);
				Plugin.Log.LogInfo((object)$"Sent {portalSnapshot.Portals.Count} portals to peer {sender} on request");
			}
		}

		private static void RPC_Portals(long sender, ZPackage pkg)
		{
			if (pkg == null || (Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			long num = (ZNet.instance.IsServer() ? Traverse.Create((object)ZRoutedRpc.instance).Field<long>("m_id").Value : (ZNet.instance.GetServerPeer()?.m_uid ?? 0));
			if (sender != num)
			{
				Plugin.Log.LogWarning((object)$"Ignoring portal snapshot from non-server peer {sender}");
				return;
			}
			PortalSnapshot portalSnapshot = PortalSnapshot.Read(pkg);
			if (portalSnapshot != null)
			{
				ServerHasMod = true;
				if (Current == null || Current.Fingerprint != portalSnapshot.Fingerprint)
				{
					Current = portalSnapshot;
					Revision++;
					Plugin.Log.LogInfo((object)$"Portal list updated: {portalSnapshot.Portals.Count} portals");
				}
			}
		}

		public static PortalSnapshot LocalFallback()
		{
			return PortalSnapshot.FromWorld();
		}
	}
}