Decompiled source of BetterPortals v0.4.7

plugins/FraileyPortalSelector.dll

Decompiled 2 hours ago
using System;
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 BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
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("FraileyPortalSelector")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.4.7.0")]
[assembly: AssemblyInformationalVersion("0.4.7+d00154020f09ce26374950d6b5ed9ba8f39b3265")]
[assembly: AssemblyProduct("BetterPortals")]
[assembly: AssemblyTitle("FraileyPortalSelector")]
[assembly: AssemblyVersion("0.4.7.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 FraileyPortalSelector
{
	[BepInPlugin("com.fraileywoodworks.portalselector", "BetterPortals", "0.4.7")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.fraileywoodworks.portalselector";

		public const string Name = "BetterPortals";

		public const string Version = "0.4.7";

		internal const int MaxNameLength = 32;

		internal static Plugin Instance;

		internal static readonly Harmony Harmony = new Harmony("com.fraileywoodworks.portalselector");

		private void Awake()
		{
			Instance = this;
			Harmony.PatchAll();
			if (!Application.isBatchMode)
			{
				PortalVisualSettings.Bind(((BaseUnityPlugin)this).Config);
				((Component)this).gameObject.AddComponent<PortalController>();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded; portal names capped at {2} characters", "BetterPortals", "0.4.7", 32));
		}

		private void OnDestroy()
		{
			Harmony.UnpatchSelf();
		}

		internal static void LogDebug(string message)
		{
			Plugin instance = Instance;
			if (instance != null)
			{
				((BaseUnityPlugin)instance).Logger.LogDebug((object)message);
			}
		}
	}
	internal static class PortalVisualSettings
	{
		internal const float DefaultTitleFontSize = 40f;

		internal const float DefaultEntryFontSize = 31f;

		internal const float DefaultHintFontSize = 17f;

		internal const float DefaultBiomeFontSize = 9.3f;

		internal const float DefaultHomeIconSize = 13.2f;

		internal const float DefaultOutlineWidth = 0f;

		internal const float DefaultHoverScale = 1.1f;

		internal const float DefaultHoverExpandSeconds = 0.08f;

		internal const float DefaultHoverContractSeconds = 0.1f;

		internal const float DefaultPanelWidth = 620f;

		internal const float DefaultPanelYOffset = 0f;

		internal const float DefaultRowHeight = 46f;

		internal const float DefaultRowSpacing = 2f;

		internal const float DefaultMaxListHeight = 414f;

		internal const float DefaultBackdropOpacity = 1f;

		internal const float DefaultFadeInSeconds = 0.06f;

		internal const float DefaultFadeOutSeconds = 0.05f;

		internal const float DefaultTriggerMultiplier = 1.5625f;

		internal const float DefaultRowKnotGap = 18f;

		private const string DefaultTitleColor = "#FF8F00FF";

		private const string DefaultEntryColor = "#FFFFFFFF";

		private const string DefaultHintColor = "#B8B8B3FF";

		private const string DefaultBiomeColor = "#FFFFFFFF";

		private const string DefaultOutlineColor = "#000000D9";

		private const string DefaultOrnamentColor = "#FF8F00FF";

		private static ConfigEntry<float> titleFontSize;

		private static ConfigEntry<float> entryFontSize;

		private static ConfigEntry<float> hintFontSize;

		private static ConfigEntry<float> biomeFontSize;

		private static ConfigEntry<float> homeIconSize;

		private static ConfigEntry<string> titleColor;

		private static ConfigEntry<string> entryColor;

		private static ConfigEntry<string> hintColor;

		private static ConfigEntry<string> biomeColor;

		private static ConfigEntry<string> outlineColor;

		private static ConfigEntry<float> outlineWidth;

		private static ConfigEntry<float> hoverScale;

		private static ConfigEntry<float> hoverExpandSeconds;

		private static ConfigEntry<float> hoverContractSeconds;

		private static ConfigEntry<float> panelWidth;

		private static ConfigEntry<float> panelYOffset;

		private static ConfigEntry<float> rowHeight;

		private static ConfigEntry<float> rowSpacing;

		private static ConfigEntry<float> maxListHeight;

		private static ConfigEntry<float> backdropOpacity;

		private static ConfigEntry<string> ornamentColor;

		private static ConfigEntry<bool> showMenuOrnament;

		private static ConfigEntry<bool> showRowKnots;

		private static ConfigEntry<float> rowKnotGap;

		private static ConfigEntry<float> fadeInSeconds;

		private static ConfigEntry<float> fadeOutSeconds;

		private static ConfigEntry<float> triggerMultiplier;

		private static ConfigEntry<bool> showBiomeSubtitle;

		private static ConfigEntry<bool> preferHomeOnOpen;

		private static ConfigEntry<bool> showControlHints;

		private static ConfigEntry<KeyboardShortcut> setHomeKeyboardShortcut;

		internal static float TitleFontSize => Clamp(titleFontSize, 40f, 12f, 96f);

		internal static float EntryFontSize => Clamp(entryFontSize, 31f, 12f, 72f);

		internal static float HintFontSize => Clamp(hintFontSize, 17f, 8f, 48f);

		internal static float BiomeFontSize => Clamp(biomeFontSize, 9.3f, 8f, 48f);

		internal static float HomeIconSize => Clamp(homeIconSize, 13.2f, 12f, 36f);

		internal static Color TitleColor => ParseColor(titleColor, "#FF8F00FF");

		internal static Color EntryColor => ParseColor(entryColor, "#FFFFFFFF");

		internal static Color HintColor => ParseColor(hintColor, "#B8B8B3FF");

		internal static Color BiomeColor => ParseColor(biomeColor, "#FFFFFFFF");

		internal static Color OutlineColor => ParseColor(outlineColor, "#000000D9");

		internal static float OutlineWidth => Clamp(outlineWidth, 0f, 0f, 1f);

		internal static float HoverScale => Clamp(hoverScale, 1.1f, 1f, 1.5f);

		internal static float HoverExpandSeconds => Clamp(hoverExpandSeconds, 0.08f, 0.01f, 1f);

		internal static float HoverContractSeconds => Clamp(hoverContractSeconds, 0.1f, 0.01f, 1f);

		internal static float PanelWidth => Clamp(panelWidth, 620f, 320f, 1400f);

		internal static float PanelYOffset => Clamp(panelYOffset, 0f, -500f, 500f);

		internal static float RowHeight => Clamp(rowHeight, 46f, 28f, 96f);

		internal static float RowSpacing => Clamp(rowSpacing, 2f, 0f, 24f);

		internal static float MaxListHeight => Clamp(maxListHeight, 414f, 80f, 900f);

		internal static float BackdropOpacity => Clamp(backdropOpacity, 1f, 0f, 1f);

		internal static Color OrnamentColor => ParseColor(ornamentColor, "#FF8F00FF");

		internal static bool ShowMenuOrnament => showMenuOrnament?.Value ?? true;

		internal static bool ShowRowKnots => showRowKnots?.Value ?? true;

		internal static float RowKnotGap => Clamp(rowKnotGap, 18f, 0f, 100f);

		internal static float FadeInSeconds => Clamp(fadeInSeconds, 0.06f, 0.01f, 1f);

		internal static float FadeOutSeconds => Clamp(fadeOutSeconds, 0.05f, 0.01f, 1f);

		internal static float TriggerMultiplier => Clamp(triggerMultiplier, 1.5625f, 1f, 2f);

		internal static bool ShowBiomeSubtitle => showBiomeSubtitle?.Value ?? true;

		internal static bool PreferHomeOnOpen => preferHomeOnOpen?.Value ?? true;

		internal static bool ShowControlHints => showControlHints?.Value ?? true;

		internal static KeyboardShortcut SetHomeKeyboardShortcut => (KeyboardShortcut)(((??)setHomeKeyboardShortcut?.Value) ?? new KeyboardShortcut((KeyCode)104, Array.Empty<KeyCode>()));

		internal static void Bind(ConfigFile config)
		{
			//IL_045e: Unknown result type (might be due to invalid IL or missing references)
			titleFontSize = BindRange(config, "Visual - Typography", "Title Font Size", 40f, 12f, 96f, "Portal selector heading size.");
			entryFontSize = BindRange(config, "Visual - Typography", "Entry Font Size", 31f, 12f, 72f, "Destination row text size.");
			hintFontSize = BindRange(config, "Visual - Typography", "Hint Font Size", 17f, 8f, 48f, "Size of the close-instruction text below the heading.");
			biomeFontSize = BindRange(config, "Visual - Typography", "Biome Font Size", 9.3f, 8f, 48f, "Size of the optional biome subtitle beneath each portal name.");
			homeIconSize = BindRange(config, "Visual - Typography", "Home Icon Size", 13.2f, 12f, 36f, "Size of Valheim's native favorite-star icon beside the selected Home portal.");
			titleColor = BindColor(config, "Visual - Typography", "Title Color", "#FF8F00FF", "Heading color as #RRGGBB or #RRGGBBAA.");
			entryColor = BindColor(config, "Visual - Typography", "Entry Color", "#FFFFFFFF", "Destination text color as #RRGGBB or #RRGGBBAA.");
			hintColor = BindColor(config, "Visual - Typography", "Hint Color", "#B8B8B3FF", "Instruction text color as #RRGGBB or #RRGGBBAA.");
			biomeColor = BindColor(config, "Visual - Typography", "Biome Color", "#FFFFFFFF", "Biome subtitle color as #RRGGBB or #RRGGBBAA.");
			outlineColor = BindColor(config, "Visual - Typography", "Font Outline Color", "#000000D9", "Text outline color as #RRGGBB or #RRGGBBAA.");
			outlineWidth = BindRange(config, "Visual - Typography", "Font Outline Width", 0f, 0f, 1f, "TextMesh Pro outline width for all selector text.");
			hoverScale = BindRange(config, "Visual - Hover", "Hover Scale", 1.1f, 1f, 1.5f, "Scale of the selected or hovered destination label.");
			hoverExpandSeconds = BindRange(config, "Visual - Hover", "Hover Expand Duration", 0.08f, 0.01f, 1f, "Seconds used for the eased hover expansion.");
			hoverContractSeconds = BindRange(config, "Visual - Hover", "Hover Contract Duration", 0.1f, 0.01f, 1f, "Seconds used for the eased hover contraction.");
			panelWidth = BindRange(config, "Visual - Layout", "Panel Width", 620f, 320f, 1400f, "Width of the centered portal selector in native UI units.");
			panelYOffset = BindRange(config, "Visual - Layout", "Panel Y Offset", 0f, -500f, 500f, "Vertical offset from screen center in native UI units.");
			rowHeight = BindRange(config, "Visual - Layout", "Row Height", 46f, 28f, 96f, "Height of each destination row.");
			rowSpacing = BindRange(config, "Visual - Layout", "Row Spacing", 2f, 0f, 24f, "Vertical spacing between destination rows.");
			maxListHeight = BindRange(config, "Visual - Layout", "Maximum List Height", 414f, 80f, 900f, "Maximum visible destination-list height before scrolling.");
			backdropOpacity = BindRange(config, "Visual - Layout", "Dark Backdrop Opacity", 1f, 0f, 1f, "Opacity multiplier for Valheim's native dark backdrop; 1 preserves the v20 appearance.");
			ornamentColor = BindColor(config, "Visual - Ornaments", "Ornament and Knot Color", "#FF8F00FF", "Menu ornament and row-knot color as #RRGGBB or #RRGGBBAA.");
			showMenuOrnament = config.Bind<bool>("Visual - Ornaments", "Show Menu Ornament", true, "Show Valheim's native menu ornament behind the selector.");
			showRowKnots = config.Bind<bool>("Visual - Ornaments", "Show Row Knots", true, "Show the native knot marks beside a hovered or controller-selected destination.");
			rowKnotGap = BindRange(config, "Visual - Ornaments", "Row Knot Gap", 18f, 0f, 100f, "Horizontal gap between the rendered destination label and each native knot mark.");
			fadeInSeconds = BindRange(config, "Visual - Animation", "Fade In Duration", 0.06f, 0.01f, 1f, "Seconds used for the selector fade-in.");
			fadeOutSeconds = BindRange(config, "Visual - Animation", "Fade Out Duration", 0.05f, 0.01f, 1f, "Seconds used for the selector fade-out.");
			triggerMultiplier = BindRange(config, "Portal Interaction", "Portal Trigger Multiplier", 1.5625f, 1f, 2f, "Client-local trigger and open-menu range multiplier. The server enforces a fixed 9.375-metre safety limit.");
			showBiomeSubtitle = config.Bind<bool>("Portal List", "Show Biome Subtitle", true, "Show the portal's biome in smaller white text beneath its name.");
			preferHomeOnOpen = config.Bind<bool>("Portal List", "Prefer Home On Open", true, "Select and scroll to the Home portal when the list opens.");
			showControlHints = config.Bind<bool>("Portal List", "Show Control Hints", true, "Show short keyboard or controller instructions above the destination list.");
			setHomeKeyboardShortcut = config.Bind<KeyboardShortcut>("Portal List", "Set Home Keyboard Shortcut", new KeyboardShortcut((KeyCode)104, Array.Empty<KeyCode>()), "Keyboard shortcut that sets or clears Home on the selected destination.");
			MigrateLegacyVisualDefaults(config);
			Watch<float>(titleFontSize);
			Watch<float>(entryFontSize);
			Watch<float>(hintFontSize);
			Watch<float>(biomeFontSize);
			Watch<float>(homeIconSize);
			Watch<string>(titleColor);
			Watch<string>(entryColor);
			Watch<string>(hintColor);
			Watch<string>(biomeColor);
			Watch<string>(outlineColor);
			Watch<float>(outlineWidth);
			Watch<float>(hoverScale);
			Watch<float>(hoverExpandSeconds);
			Watch<float>(hoverContractSeconds);
			Watch<float>(panelWidth);
			Watch<float>(panelYOffset);
			Watch<float>(rowHeight);
			Watch<float>(rowSpacing);
			Watch<float>(maxListHeight);
			Watch<float>(backdropOpacity);
			Watch<string>(ornamentColor);
			Watch<bool>(showMenuOrnament);
			Watch<bool>(showRowKnots);
			Watch<float>(rowKnotGap);
			Watch<float>(fadeInSeconds);
			Watch<float>(fadeOutSeconds);
			Watch<float>(triggerMultiplier);
			Watch<bool>(showBiomeSubtitle);
			Watch<bool>(preferHomeOnOpen);
			Watch<bool>(showControlHints);
			Watch<KeyboardShortcut>(setHomeKeyboardShortcut);
		}

		private static void MigrateLegacyVisualDefaults(ConfigFile config)
		{
			bool flag = false;
			if (Mathf.Approximately(biomeFontSize.Value, 15.5f))
			{
				biomeFontSize.Value = 9.3f;
				flag = true;
			}
			if (Mathf.Approximately(homeIconSize.Value, 22f))
			{
				homeIconSize.Value = 13.2f;
				flag = true;
			}
			if (Mathf.Approximately(panelYOffset.Value, 120f))
			{
				panelYOffset.Value = 0f;
				flag = true;
			}
			if (Mathf.Approximately(triggerMultiplier.Value, 1.25f))
			{
				triggerMultiplier.Value = 1.5625f;
				flag = true;
			}
			if (string.Equals(entryColor.Value?.Trim(), "#DBDBDBFF", StringComparison.OrdinalIgnoreCase))
			{
				entryColor.Value = "#FFFFFFFF";
				flag = true;
			}
			if (flag)
			{
				config.Save();
			}
		}

		private static ConfigEntry<float> BindRange(ConfigFile config, string section, string key, float value, float minimum, float maximum, string description)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			return config.Bind<float>(section, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(minimum, maximum), Array.Empty<object>()));
		}

		private static ConfigEntry<string> BindColor(ConfigFile config, string section, string key, string value, string description)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			return config.Bind<string>(section, key, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
		}

		private static void Watch<T>(ConfigEntry<T> entry)
		{
			entry.SettingChanged += OnSettingChanged;
		}

		private static void OnSettingChanged(object sender, EventArgs args)
		{
			PortalController.Instance?.MarkVisualsDirty();
		}

		private static float Clamp(ConfigEntry<float> entry, float fallback, float minimum, float maximum)
		{
			return Mathf.Clamp(entry?.Value ?? fallback, minimum, maximum);
		}

		private static Color ParseColor(ConfigEntry<string> entry, string fallback)
		{
			//IL_004b: 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)
			string text = entry?.Value;
			if (!string.IsNullOrWhiteSpace(text))
			{
				text = text.Trim();
				if (!text.StartsWith("#", StringComparison.Ordinal))
				{
					text = "#" + text;
				}
				Color result = default(Color);
				if (ColorUtility.TryParseHtmlString(text, ref result))
				{
					return result;
				}
			}
			Color result2 = default(Color);
			ColorUtility.TryParseHtmlString(fallback, ref result2);
			return result2;
		}
	}
	internal static class PortalNames
	{
		internal static string Sanitize(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return string.Empty;
			}
			string text = new string(value.Where((char c) => c >= ' ' && c != '\u007f').Take(32).ToArray());
			if (text.Length > 0 && char.IsHighSurrogate(text[text.Length - 1]))
			{
				text = text.Substring(0, text.Length - 1);
			}
			return text;
		}
	}
	internal static class PortalHome
	{
		private const string KeyPrefix = "com.fraileywoodworks.portalselector.home.v1.";

		private static string CurrentKey()
		{
			ZNet instance = ZNet.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				return "com.fraileywoodworks.portalselector.home.v1." + instance.GetWorldUID();
			}
			return null;
		}

		internal static bool TryGet(out ZDOID id)
		{
			//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_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)
			//IL_008f: 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)
			id = ZDOID.None;
			Player localPlayer = Player.m_localPlayer;
			string text = CurrentKey();
			if (!Object.op_Implicit((Object)(object)localPlayer) || string.IsNullOrEmpty(text) || localPlayer.m_customData == null || !localPlayer.m_customData.TryGetValue(text, out var value))
			{
				return false;
			}
			string[] array = value.Split(new char[1] { ':' });
			if (array.Length != 2 || !long.TryParse(array[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || !uint.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2))
			{
				return false;
			}
			id = new ZDOID(result, result2);
			return id != ZDOID.None;
		}

		internal static bool Set(ZDOID id)
		{
			//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)
			Player localPlayer = Player.m_localPlayer;
			string text = CurrentKey();
			if (!Object.op_Implicit((Object)(object)localPlayer) || string.IsNullOrEmpty(text) || id == ZDOID.None)
			{
				return false;
			}
			Player val = localPlayer;
			if (val.m_customData == null)
			{
				val.m_customData = new Dictionary<string, string>();
			}
			localPlayer.m_customData[text] = ((ZDOID)(ref id)).UserID.ToString(CultureInfo.InvariantCulture) + ":" + ((ZDOID)(ref id)).ID.ToString(CultureInfo.InvariantCulture);
			return true;
		}

		internal static bool Clear()
		{
			Player localPlayer = Player.m_localPlayer;
			string text = CurrentKey();
			if (Object.op_Implicit((Object)(object)localPlayer) && !string.IsNullOrEmpty(text) && localPlayer.m_customData != null)
			{
				return localPlayer.m_customData.Remove(text);
			}
			return false;
		}
	}
	internal static class PortalBiomes
	{
		internal static Biome Normalize(int value)
		{
			//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_000e: Unknown result type (might be due to invalid IL or missing references)
			Biome val = (Biome)value;
			if (Rank(val) >= 9)
			{
				return (Biome)0;
			}
			return val;
		}

		internal static int Rank(Biome biome)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Invalid comparison between Unknown and I4
			//IL_0005: 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_001d: Expected I4, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Invalid comparison between Unknown and I4
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Invalid comparison between Unknown and I4
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Invalid comparison between Unknown and I4
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Invalid comparison between Unknown and I4
			if ((int)biome <= 16)
			{
				switch (biome - 1)
				{
				default:
					if ((int)biome != 8)
					{
						if ((int)biome != 16)
						{
							break;
						}
						return 4;
					}
					return 1;
				case 0:
					return 0;
				case 1:
					return 2;
				case 3:
					return 3;
				case 2:
					break;
				}
			}
			else if ((int)biome <= 64)
			{
				if ((int)biome == 32)
				{
					return 6;
				}
				if ((int)biome == 64)
				{
					return 7;
				}
			}
			else
			{
				if ((int)biome == 256)
				{
					return 8;
				}
				if ((int)biome == 512)
				{
					return 5;
				}
			}
			return 9;
		}

		internal static string DisplayName(Biome biome)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Invalid comparison between Unknown and I4
			//IL_0005: 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_001d: Expected I4, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Invalid comparison between Unknown and I4
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Invalid comparison between Unknown and I4
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Invalid comparison between Unknown and I4
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Invalid comparison between Unknown and I4
			if ((int)biome <= 16)
			{
				switch (biome - 1)
				{
				default:
					if ((int)biome != 8)
					{
						if ((int)biome != 16)
						{
							break;
						}
						return "Plains";
					}
					return "Black Forest";
				case 0:
					return "Meadows";
				case 1:
					return "Swamp";
				case 3:
					return "Mountains";
				case 2:
					break;
				}
			}
			else if ((int)biome <= 64)
			{
				if ((int)biome == 32)
				{
					return "Ashlands";
				}
				if ((int)biome == 64)
				{
					return "Deep North";
				}
			}
			else
			{
				if ((int)biome == 256)
				{
					return "Ocean";
				}
				if ((int)biome == 512)
				{
					return "Mistlands";
				}
			}
			return "Other";
		}
	}
	internal static class PortalOrderLedger
	{
		private static readonly Dictionary<ZDOID, long> Orders = new Dictionary<ZDOID, long>();

		private static long loadedWorld;

		private static long nextOrder = 1L;

		private static bool initialized;

		private static bool loadingWorld;

		internal static void BeginWorldLoad()
		{
			loadingWorld = true;
		}

		internal static void EndWorldLoad(ZDOMan manager)
		{
			if (loadingWorld)
			{
				loadingWorld = false;
				if (manager != null)
				{
					Ensure(manager.GetPortalList());
				}
			}
		}

		internal static void PrepareObservation()
		{
			if (!loadingWorld && !initialized && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				ZDOMan instance = ZDOMan.instance;
				IEnumerable<ZDO> enumerable = ((instance != null) ? instance.GetPortalList() : null);
				Ensure(enumerable ?? Enumerable.Empty<ZDO>());
			}
		}

		internal static void Ensure(IEnumerable<ZDO> portals)
		{
			//IL_00c0: 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_00cb: 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 ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			LoadCurrentWorld();
			bool flag = false;
			foreach (ZDOID item in from id in (from z in portals
					where z != null && z.IsValid()
					select z.m_uid).Distinct()
				orderby (ulong)((ZDOID)(ref id)).UserID, ((ZDOID)(ref id)).ID
				select id)
			{
				if (!Orders.ContainsKey(item))
				{
					Orders[item] = nextOrder++;
					flag = true;
				}
			}
			initialized = true;
			if (flag)
			{
				Save();
			}
		}

		internal static long Get(ZDOID id)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (!Orders.TryGetValue(id, out var value))
			{
				return long.MaxValue;
			}
			return value;
		}

		internal static void Observe(ZDO zdo)
		{
			//IL_0051: 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)
			if (!loadingWorld && initialized && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && zdo != null && zdo.IsValid())
			{
				if (ZNet.instance.GetWorldUID() != loadedWorld)
				{
					initialized = false;
				}
				else if (!Orders.ContainsKey(zdo.m_uid))
				{
					Orders[zdo.m_uid] = nextOrder++;
					Save();
				}
			}
		}

		private static void LoadCurrentWorld()
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			long worldUID = ZNet.instance.GetWorldUID();
			if (initialized && loadedWorld == worldUID)
			{
				return;
			}
			loadedWorld = worldUID;
			nextOrder = 1L;
			initialized = false;
			Orders.Clear();
			try
			{
				string path = CurrentPath();
				if (!File.Exists(path))
				{
					return;
				}
				string[] array = File.ReadAllLines(path);
				for (int i = 0; i < array.Length; i++)
				{
					string[] array2 = array[i].Split(new char[1] { '\t' });
					if (array2.Length == 3 && long.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && uint.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) && long.TryParse(array2[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3) && result3 > 0)
					{
						Orders[new ZDOID(result, result2)] = result3;
						nextOrder = Math.Max(nextOrder, result3 + 1);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.LogDebug("Could not read portal creation-order ledger: " + ex.GetType().Name);
			}
		}

		private static string CurrentPath()
		{
			return Path.Combine(Paths.ConfigPath, $"BetterPortals.portal-order.{loadedWorld}.tsv");
		}

		private static void Save()
		{
			string text = CurrentPath();
			string text2 = text + ".tmp";
			try
			{
				File.WriteAllLines(text2, Orders.OrderBy((KeyValuePair<ZDOID, long> pair) => pair.Value).Select(delegate(KeyValuePair<ZDOID, long> pair)
				{
					//IL_000a: Unknown result type (might be due to invalid IL or missing references)
					//IL_000f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0031: 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)
					string[] array = new string[5];
					ZDOID key = pair.Key;
					array[0] = ((ZDOID)(ref key)).UserID.ToString(CultureInfo.InvariantCulture);
					array[1] = "\t";
					key = pair.Key;
					array[2] = ((ZDOID)(ref key)).ID.ToString(CultureInfo.InvariantCulture);
					array[3] = "\t";
					array[4] = pair.Value.ToString(CultureInfo.InvariantCulture);
					return string.Concat(array);
				}));
				if (File.Exists(text))
				{
					try
					{
						File.Replace(text2, text, null);
						return;
					}
					catch (PlatformNotSupportedException)
					{
						File.Delete(text);
						File.Move(text2, text);
						return;
					}
				}
				File.Move(text2, text);
			}
			catch (Exception ex2)
			{
				Plugin.LogDebug("Could not save portal creation-order ledger: " + ex2.GetType().Name);
			}
			finally
			{
				try
				{
					if (File.Exists(text2))
					{
						File.Delete(text2);
					}
				}
				catch
				{
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZDOMan), "Load")]
	internal static class PortalOrderLoadPatch
	{
		private static void Prefix()
		{
			PortalOrderLedger.BeginWorldLoad();
		}

		private static void Postfix(ZDOMan __instance)
		{
			PortalOrderLedger.EndWorldLoad(__instance);
		}

		private static Exception Finalizer(Exception __exception, ZDOMan __instance)
		{
			PortalOrderLedger.EndWorldLoad(__instance);
			return __exception;
		}
	}
	[HarmonyPatch(typeof(ZDOMan), "AddIfPortal")]
	internal static class PortalOrderObservationPatch
	{
		private static bool IsPortalPrefab(int prefabHash)
		{
			Game instance = Game.instance;
			if (Object.op_Implicit((Object)(object)instance) && instance.PortalPrefabHash != null)
			{
				return instance.PortalPrefabHash.Contains(prefabHash);
			}
			return false;
		}

		private static void Prefix(int __1, out bool __state)
		{
			__state = IsPortalPrefab(__1);
			if (__state)
			{
				PortalOrderLedger.PrepareObservation();
			}
		}

		private static void Postfix(ZDO __0, bool __state)
		{
			if (__state)
			{
				PortalOrderLedger.Observe(__0);
			}
		}
	}
	internal static class PortalRanges
	{
		internal const float MaximumServerDistance = 9.375f;

		internal static float TriggerMultiplier => PortalVisualSettings.TriggerMultiplier;

		internal static float ClientDistance(TeleportWorld portal)
		{
			if (!Object.op_Implicit((Object)(object)portal) || !(portal.m_activationRange > 0f))
			{
				return 9.375f;
			}
			return Mathf.Min(9.375f, portal.m_activationRange * TriggerMultiplier);
		}
	}
	[HarmonyPatch(typeof(TextInput), "RequestText")]
	internal static class PortalNameInputPatch
	{
		private static void Prefix(TextReceiver __0, ref int __2)
		{
			if (__0 is TeleportWorld)
			{
				__2 = 32;
			}
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "SetText")]
	internal static class PortalNameSendPatch
	{
		private static void Prefix(ref string __0)
		{
			__0 = PortalNames.Sanitize(__0);
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "RPC_SetTag")]
	internal static class PortalNameReceivePatch
	{
		private static void Prefix(ref string __1)
		{
			__1 = PortalNames.Sanitize(__1);
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "GetHoverText")]
	internal static class PortalHoverTextPatch
	{
		private static bool Prepare()
		{
			return !Application.isBatchMode;
		}

		private static void Postfix(ref string __result)
		{
			if (!string.IsNullOrEmpty(__result))
			{
				int num = __result.IndexOf('\n');
				string text = ((num >= 0) ? __result.Substring(0, num) : __result);
				int num2 = text.LastIndexOf(" [", StringComparison.Ordinal);
				if (num2 >= 0 && text.EndsWith("]", StringComparison.Ordinal))
				{
					__result = text.Substring(0, num2) + ((num >= 0) ? __result.Substring(num) : string.Empty);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Game), "Start")]
	internal static class RpcRegistrationPatch
	{
		private static void Postfix()
		{
			PortalRpc.Register();
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "Teleport")]
	internal static class PortalTravelPatch
	{
		private static bool Prepare()
		{
			return !Application.isBatchMode;
		}

		private static bool Prefix(TeleportWorld __instance, Player __0)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (Application.isBatchMode || (Object)(object)__0 != (Object)(object)Player.m_localPlayer || PortalController.BypassOnce)
			{
				return true;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || component.GetZDO() == null)
			{
				return true;
			}
			PortalController.Instance.Begin(__instance, component.GetZDO().m_uid);
			return false;
		}
	}
	[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
	internal static class PortalCursorPatch
	{
		private static bool Prepare()
		{
			return !Application.isBatchMode;
		}

		private static bool Prefix()
		{
			if (Application.isBatchMode || !PortalController.CapturesInput)
			{
				return true;
			}
			if (!PortalController.WantsCursor)
			{
				return true;
			}
			PortalController.ApplySelectorCursor(center: false);
			return false;
		}
	}
	[HarmonyPatch(typeof(Hud), "UpdateCrosshair")]
	internal static class PortalCrosshairPatch
	{
		private static bool Prepare()
		{
			return !Application.isBatchMode;
		}

		private static bool Prefix(Hud __instance)
		{
			if (Application.isBatchMode || !PortalController.CapturesInput)
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)__instance.m_crosshair))
			{
				((Component)__instance.m_crosshair).gameObject.SetActive(false);
			}
			if (Object.op_Implicit((Object)(object)__instance.m_crosshairBow))
			{
				((Component)__instance.m_crosshairBow).gameObject.SetActive(false);
			}
			if (Object.op_Implicit((Object)(object)__instance.m_hoverName))
			{
				((TMP_Text)__instance.m_hoverName).text = string.Empty;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerController), "InInventoryEtc")]
	internal static class PortalPlayerInputPatch
	{
		private static bool Prepare()
		{
			return !Application.isBatchMode;
		}

		private static void Postfix(ref bool __result)
		{
			if (!Application.isBatchMode && PortalController.CapturesInput)
			{
				__result = true;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "TakeInput")]
	internal static class PortalCharacterInputPatch
	{
		private static bool Prepare()
		{
			return !Application.isBatchMode;
		}

		private static void Postfix(Player __instance, ref bool __result)
		{
			if (!Application.isBatchMode && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && PortalController.CapturesInput)
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(Menu), "Show")]
	internal static class PortalEscapeMenuPatch
	{
		private static bool Prepare()
		{
			return !Application.isBatchMode;
		}

		private static bool Prefix()
		{
			if (Application.isBatchMode || !PortalController.CapturesInput)
			{
				return true;
			}
			PortalController.Instance?.DismissFromMenuInput();
			return false;
		}
	}
	[HarmonyPatch(typeof(Chat), "Update")]
	internal static class PortalChatInputPatch
	{
		private static bool Prepare()
		{
			return !Application.isBatchMode;
		}

		private static bool Prefix()
		{
			if (!Application.isBatchMode)
			{
				return !PortalController.CapturesInput;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Chat), "InputText")]
	internal static class PortalChatOpenPatch
	{
		private static bool Prepare()
		{
			return !Application.isBatchMode;
		}

		private static bool Prefix()
		{
			if (!Application.isBatchMode)
			{
				return !PortalController.CapturesInput;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(TeleportWorldTrigger), "Awake")]
	internal static class PortalExitWatcherPatch
	{
		private static bool Prepare()
		{
			return !Application.isBatchMode;
		}

		private static void Postfix(TeleportWorldTrigger __instance)
		{
			if (!Application.isBatchMode)
			{
				(((Component)__instance).GetComponent<PortalExitWatcher>() ?? ((Component)__instance).gameObject.AddComponent<PortalExitWatcher>()).Initialize(((Component)__instance).GetComponentInParent<TeleportWorld>(), __instance);
			}
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "UpdatePortal")]
	internal static class PortalGlowUpdateContextPatch
	{
		[ThreadStatic]
		private static TeleportWorld updating;

		private static bool Prepare()
		{
			return !Application.isBatchMode;
		}

		internal static bool IsUpdating(TeleportWorld portal)
		{
			return (Object)(object)updating == (Object)(object)portal;
		}

		private static void Prefix(TeleportWorld __instance)
		{
			if (!Application.isBatchMode)
			{
				updating = __instance;
			}
		}

		private static void Postfix()
		{
			updating = null;
		}

		private static Exception Finalizer(Exception __exception)
		{
			updating = null;
			return __exception;
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "TargetFound")]
	internal static class UnpairedPortalGlowPatch
	{
		private static bool Prepare()
		{
			return !Application.isBatchMode;
		}

		private static void Postfix(TeleportWorld __instance, ref bool __result)
		{
			//IL_0071: 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 (!(Application.isBatchMode | __result) && PortalGlowUpdateContextPatch.IsUpdating(__instance))
			{
				Player localPlayer = Player.m_localPlayer;
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)component) && component.IsValid() && component.GetZDO() != null && Object.op_Implicit((Object)(object)__instance.m_proximityRoot) && !string.IsNullOrWhiteSpace(component.GetZDO().GetString("tag", "")) && !(Vector3.Distance(((Component)localPlayer).transform.position, __instance.m_proximityRoot.position) > __instance.m_activationRange) && ((Humanoid)localPlayer).IsTeleportable(__instance.m_allowAllItems))
				{
					__result = true;
				}
			}
		}
	}
	internal sealed class PortalExitWatcher : MonoBehaviour
	{
		private readonly HashSet<Collider> localColliders = new HashSet<Collider>();

		private TeleportWorld portal;

		private BoxCollider[] boxes = Array.Empty<BoxCollider>();

		private Vector3[] originalBoxSizes = Array.Empty<Vector3>();

		private SphereCollider[] spheres = Array.Empty<SphereCollider>();

		private float[] originalSphereRadii = Array.Empty<float>();

		private CapsuleCollider[] capsules = Array.Empty<CapsuleCollider>();

		private float[] originalCapsuleRadii = Array.Empty<float>();

		private float[] originalCapsuleHeights = Array.Empty<float>();

		private float appliedMultiplier = -1f;

		private bool rangesCaptured;

		internal void Initialize(TeleportWorld sourcePortal, TeleportWorldTrigger trigger)
		{
			portal = sourcePortal;
			if (!rangesCaptured && Object.op_Implicit((Object)(object)trigger))
			{
				boxes = ((Component)trigger).GetComponents<BoxCollider>();
				originalBoxSizes = boxes.Select((BoxCollider box) => box.size).ToArray();
				spheres = ((Component)trigger).GetComponents<SphereCollider>();
				originalSphereRadii = spheres.Select((SphereCollider sphere) => sphere.radius).ToArray();
				capsules = ((Component)trigger).GetComponents<CapsuleCollider>();
				originalCapsuleRadii = capsules.Select((CapsuleCollider capsule) => capsule.radius).ToArray();
				originalCapsuleHeights = capsules.Select((CapsuleCollider capsule) => capsule.height).ToArray();
				rangesCaptured = true;
			}
			ApplyTriggerMultiplier();
		}

		private void Update()
		{
			if (!Mathf.Approximately(appliedMultiplier, PortalRanges.TriggerMultiplier))
			{
				ApplyTriggerMultiplier();
			}
		}

		private void ApplyTriggerMultiplier()
		{
			//IL_0031: 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)
			if (!rangesCaptured)
			{
				return;
			}
			float triggerMultiplier = PortalRanges.TriggerMultiplier;
			for (int i = 0; i < boxes.Length; i++)
			{
				if (Object.op_Implicit((Object)(object)boxes[i]))
				{
					boxes[i].size = originalBoxSizes[i] * triggerMultiplier;
				}
			}
			for (int j = 0; j < spheres.Length; j++)
			{
				if (Object.op_Implicit((Object)(object)spheres[j]))
				{
					spheres[j].radius = originalSphereRadii[j] * triggerMultiplier;
				}
			}
			for (int k = 0; k < capsules.Length; k++)
			{
				if (Object.op_Implicit((Object)(object)capsules[k]))
				{
					capsules[k].radius = originalCapsuleRadii[k] * triggerMultiplier;
					capsules[k].height = originalCapsuleHeights[k] * triggerMultiplier;
				}
			}
			appliedMultiplier = triggerMultiplier;
		}

		private void OnTriggerEnter(Collider other)
		{
			localColliders.RemoveWhere((Collider collider) => !Object.op_Implicit((Object)(object)collider));
			if (IsLocalPlayer(other))
			{
				localColliders.Add(other);
			}
		}

		private void OnTriggerExit(Collider other)
		{
			if (IsLocalPlayer(other))
			{
				localColliders.RemoveWhere((Collider collider) => !Object.op_Implicit((Object)(object)collider));
				localColliders.Remove(other);
				if (localColliders.Count == 0)
				{
					PortalController.Instance?.CloseIfSource(portal);
				}
			}
		}

		private void OnDestroy()
		{
			localColliders.Clear();
			PortalController.Instance?.CloseIfSource(portal);
		}

		private static bool IsLocalPlayer(Collider collider)
		{
			Player val = ((Component)collider).GetComponent<Player>() ?? ((Component)collider).GetComponentInParent<Player>();
			if (Object.op_Implicit((Object)(object)val))
			{
				return (Object)(object)val == (Object)(object)Player.m_localPlayer;
			}
			return false;
		}
	}
	internal static class PortalRpc
	{
		private readonly struct RequestWindow
		{
			internal readonly float Start;

			internal readonly int Count;

			internal RequestWindow(float start, int count)
			{
				Start = start;
				Count = count;
			}
		}

		private readonly struct ServerSession
		{
			internal readonly ZDOID Source;

			internal readonly long Nonce;

			internal readonly float Expires;

			internal readonly HashSet<ZDOID> Destinations;

			internal ServerSession(ZDOID source, long nonce, float expires, IEnumerable<ZDOID> destinations)
			{
				//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)
				Source = source;
				Nonce = nonce;
				Expires = expires;
				Destinations = new HashSet<ZDOID>(destinations);
			}
		}

		private const int ProtocolVersion = 2;

		private const string DirectoryRequest = "com.fraileywoodworks.portalselector.v2.directory.request";

		private const string DirectoryResponse = "com.fraileywoodworks.portalselector.v2.directory.response";

		private const string TravelRequest = "com.fraileywoodworks.portalselector.v2.travel.request";

		private const string TravelResponse = "com.fraileywoodworks.portalselector.v2.travel.response";

		private const float ServerSessionLifetime = 60f;

		private static readonly Dictionary<long, RequestWindow> Windows = new Dictionary<long, RequestWindow>();

		private static readonly Dictionary<long, ServerSession> Sessions = new Dictionary<long, ServerSession>();

		private static ZRoutedRpc registeredOn;

		internal static bool Register()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance == null)
			{
				return false;
			}
			if (registeredOn == instance)
			{
				return true;
			}
			instance.Register<ZPackage>("com.fraileywoodworks.portalselector.v2.directory.request", (Action<long, ZPackage>)OnDirectoryRequest);
			instance.Register<ZPackage>("com.fraileywoodworks.portalselector.v2.directory.response", (Action<long, ZPackage>)OnDirectoryResponse);
			instance.Register<ZPackage>("com.fraileywoodworks.portalselector.v2.travel.request", (Action<long, ZPackage>)OnTravelRequest);
			instance.Register<ZPackage>("com.fraileywoodworks.portalselector.v2.travel.response", (Action<long, ZPackage>)OnTravelResponse);
			registeredOn = instance;
			return true;
		}

		internal static bool AskDirectory(ZDOID source, ZDOID savedHome, long nonce)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_0020: 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_0028: 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_0038: 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)
			if (!Register() || !TryServerId(out var server))
			{
				return false;
			}
			ZPackage val = new ZPackage();
			val.Write(2);
			val.Write(source);
			val.Write(savedHome != ZDOID.None);
			if (savedHome != ZDOID.None)
			{
				val.Write(savedHome);
			}
			val.Write(nonce);
			ZRoutedRpc.instance.InvokeRoutedRPC(server, "com.fraileywoodworks.portalselector.v2.directory.request", new object[1] { val });
			return true;
		}

		internal static bool AskTravel(ZDOID source, ZDOID destination, long nonce)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_0020: 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)
			if (!Register() || !TryServerId(out var server))
			{
				return false;
			}
			ZPackage val = new ZPackage();
			val.Write(2);
			val.Write(source);
			val.Write(destination);
			val.Write(nonce);
			ZRoutedRpc.instance.InvokeRoutedRPC(server, "com.fraileywoodworks.portalselector.v2.travel.request", new object[1] { val });
			return true;
		}

		private static bool TryServerId(out long server)
		{
			server = 0L;
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			if (ZNet.instance.IsServer())
			{
				server = ZNet.GetUID();
				return true;
			}
			ZNetPeer serverPeer = ZNet.instance.GetServerPeer();
			if (serverPeer == null)
			{
				return false;
			}
			server = serverPeer.m_uid;
			return true;
		}

		internal static bool TryPortal(ZDOID id, out ZDO portal)
		{
			//IL_0007: 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)
			ZDOMan instance = ZDOMan.instance;
			portal = ((instance == null) ? null : instance.GetPortalList()?.FirstOrDefault((Func<ZDO, bool>)((ZDO z) => z != null && z.IsValid() && z.m_uid == id)));
			return portal != null;
		}

		private static bool NearSource(long sender, ZDO source)
		{
			//IL_0061: 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)
			//IL_0038: 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)
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null || source == null)
			{
				return false;
			}
			if (instance.IsServer() && sender == ZNet.GetUID())
			{
				Player localPlayer = Player.m_localPlayer;
				if (Object.op_Implicit((Object)(object)localPlayer))
				{
					return Vector3.Distance(((Component)localPlayer).transform.position, source.GetPosition()) <= 9.375f;
				}
				return false;
			}
			ZNetPeer peer = instance.GetPeer(sender);
			if (peer != null)
			{
				return Vector3.Distance(peer.m_refPos, source.GetPosition()) <= 9.375f;
			}
			return false;
		}

		private static bool RateAllowed(long sender)
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (Windows.TryGetValue(sender, out var value) && realtimeSinceStartup - value.Start < 2f)
			{
				if (value.Count >= 4)
				{
					return false;
				}
				Windows[sender] = new RequestWindow(value.Start, value.Count + 1);
			}
			else
			{
				Windows[sender] = new RequestWindow(realtimeSinceStartup, 1);
			}
			return true;
		}

		private static void OnDirectoryRequest(long sender, ZPackage request)
		{
			//IL_0031: 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_004c: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Expected O, but got Unknown
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Expected I4, but got Unknown
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				if (request.ReadInt() != 2)
				{
					return;
				}
				ZDOID sourceId = request.ReadZDOID();
				ZDOID savedHome = (request.ReadBool() ? request.ReadZDOID() : ZDOID.None);
				long num = request.ReadLong();
				if (!RateAllowed(sender) || !TryPortal(sourceId, out var portal) || !NearSource(sender, portal))
				{
					return;
				}
				WorldGenerator generator = WorldGenerator.instance;
				List<ZDO> list = (from z in ZDOMan.instance.GetPortalList()
					where z != null && z.IsValid()
					select z).ToList();
				PortalOrderLedger.Ensure(list);
				List<PortalInfo> source = (from z in list
					where z.m_uid != sourceId
					select new PortalInfo(z.m_uid, PortalNames.Sanitize(z.GetString("tag", "")), (Biome)((generator != null) ? ((int)generator.GetBiome(z.GetPosition())) : 0), PortalOrderLedger.Get(z.m_uid)) into p
					where !string.IsNullOrWhiteSpace(p.Name)
					orderby PortalBiomes.Rank(p.Biome), p.CreationOrder
					select p).ThenBy(delegate(PortalInfo p)
				{
					//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)
					ZDOID id = p.Id;
					return (ulong)((ZDOID)(ref id)).UserID;
				}).ThenBy((PortalInfo p) => ((ZDOID)(ref p.Id)).ID).ToList();
				bool flag = savedHome != ZDOID.None && list.Any((ZDO zdo) => zdo.m_uid == savedHome && !string.IsNullOrWhiteSpace(PortalNames.Sanitize(zdo.GetString("tag", ""))));
				List<PortalInfo> list2 = source.Take(512).ToList();
				if (flag && savedHome != sourceId && !list2.Any((PortalInfo portalInfo) => portalInfo.Id == savedHome))
				{
					list2[list2.Count - 1] = source.First((PortalInfo portalInfo) => portalInfo.Id == savedHome);
					list2 = (from p in list2
						orderby PortalBiomes.Rank(p.Biome), p.CreationOrder
						select p).ThenBy(delegate(PortalInfo p)
					{
						//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)
						ZDOID id = p.Id;
						return (ulong)((ZDOID)(ref id)).UserID;
					}).ThenBy((PortalInfo p) => ((ZDOID)(ref p.Id)).ID).ToList();
				}
				Sessions[sender] = new ServerSession(sourceId, num, Time.realtimeSinceStartup + 60f, list2.Select((PortalInfo portalInfo) => portalInfo.Id));
				ZPackage val = new ZPackage();
				val.Write(2);
				val.Write(num);
				val.Write(flag);
				val.Write(list2.Count);
				foreach (PortalInfo item in list2)
				{
					val.Write(item.Id);
					val.Write(item.Name);
					val.Write((int)item.Biome);
					val.Write(item.CreationOrder);
				}
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "com.fraileywoodworks.portalselector.v2.directory.response", new object[1] { val });
			}
			catch (Exception ex)
			{
				Plugin.LogDebug("Rejected malformed portal directory request: " + ex.GetType().Name);
			}
		}

		private static void OnDirectoryResponse(long sender, ZPackage package)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_0080: 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_00aa: 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)
			if (!TryServerId(out var server) || sender != server)
			{
				return;
			}
			try
			{
				if (package.ReadInt() != 2)
				{
					return;
				}
				long responseNonce = package.ReadLong();
				bool homeValid = package.ReadBool();
				int num = package.ReadInt();
				if (num < 0 || num > 512)
				{
					throw new InvalidDataException("Portal directory count was outside the protocol bounds.");
				}
				List<PortalInfo> list = new List<PortalInfo>(num);
				for (int i = 0; i < num; i++)
				{
					ZDOID val = package.ReadZDOID();
					string text = PortalNames.Sanitize(package.ReadString());
					Biome biome = PortalBiomes.Normalize(package.ReadInt());
					long num2 = package.ReadLong();
					if (val == ZDOID.None || string.IsNullOrWhiteSpace(text) || num2 <= 0)
					{
						throw new InvalidDataException("Portal directory record was invalid.");
					}
					list.Add(new PortalInfo(val, text, biome, num2));
				}
				PortalController.Instance?.Show(responseNonce, homeValid, list);
			}
			catch (Exception ex)
			{
				Plugin.LogDebug("Rejected malformed portal directory response: " + ex.GetType().Name);
			}
		}

		private static void OnTravelRequest(long sender, ZPackage request)
		{
			//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_0031: 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_004f: 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_009c: 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_00b0: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				if (request.ReadInt() == 2)
				{
					ZDOID val = request.ReadZDOID();
					ZDOID val2 = request.ReadZDOID();
					long num = request.ReadLong();
					ServerSession value;
					bool flag = Sessions.TryGetValue(sender, out value) && value.Source == val && value.Nonce == num && value.Expires >= Time.realtimeSinceStartup && value.Destinations.Contains(val2);
					Sessions.Remove(sender);
					if (!RateAllowed(sender) || !flag || !TryPortal(val, out var portal) || !NearSource(sender, portal) || !TryPortal(val2, out var portal2) || val2 == val || string.IsNullOrWhiteSpace(PortalNames.Sanitize(portal2.GetString("tag", ""))))
					{
						SendTravelResponse(sender, num, approved: false, null);
					}
					else
					{
						SendTravelResponse(sender, num, approved: true, portal2);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.LogDebug("Rejected malformed portal travel request: " + ex.GetType().Name);
			}
		}

		private static void OnTravelResponse(long sender, ZPackage package)
		{
			//IL_0044: 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_0040: 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_004e: 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)
			if (!TryServerId(out var server) || sender != server)
			{
				return;
			}
			try
			{
				if (package.ReadInt() == 2)
				{
					long responseNonce = package.ReadLong();
					bool flag = package.ReadBool();
					PortalController.Instance?.Complete(responseNonce, flag, (Vector3)(flag ? package.ReadVector3() : default(Vector3)), (Quaternion)(flag ? package.ReadQuaternion() : default(Quaternion)));
				}
			}
			catch (Exception ex)
			{
				Plugin.LogDebug("Rejected malformed portal travel response: " + ex.GetType().Name);
			}
		}

		private static void SendTravelResponse(long sender, long nonce, bool approved, ZDO destination)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0023: 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)
			ZPackage val = new ZPackage();
			val.Write(2);
			val.Write(nonce);
			val.Write(approved);
			if (approved && destination != null)
			{
				val.Write(destination.GetPosition());
				val.Write(destination.GetRotation());
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(sender, "com.fraileywoodworks.portalselector.v2.travel.response", new object[1] { val });
		}
	}
	internal readonly struct PortalInfo
	{
		internal readonly ZDOID Id;

		internal readonly string Name;

		internal readonly Biome Biome;

		internal readonly long CreationOrder;

		internal PortalInfo(ZDOID id, string name, Biome biome, long creationOrder)
		{
			//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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected I4, but got Unknown
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			Id = id;
			Name = name;
			Biome = PortalBiomes.Normalize((int)biome);
			CreationOrder = Math.Max(1L, creationOrder);
		}
	}
	internal sealed class PortalController : MonoBehaviour
	{
		private const float DirectoryTimeout = 5f;

		private const float SessionLifetime = 60f;

		private const float TravelTimeout = 3f;

		private const float FirstEntryRetryWindow = 6f;

		private const float FirstEntryRetryInterval = 0.1f;

		private const float DirectoryResponseRetryInterval = 0.75f;

		internal static PortalController Instance;

		internal static bool BypassOnce;

		private ZDOID source;

		private TeleportWorld sourcePortal;

		private long nonce;

		private float requestStarted;

		private float sessionDeadline;

		private float nextOpenAllowed;

		private float travelDeadline;

		private GameObject panel;

		private CanvasGroup canvasGroup;

		private Transform content;

		private LayoutElement scrollLayout;

		private ScrollRect destinationScroll;

		private Button firstSelectable;

		private Button homeSelectable;

		private bool? previousMouseInput;

		private Vector3 openingMousePosition;

		private bool mouseChoiceArmed;

		private int cursorCenterFrames;

		private float fadeTarget;

		private bool resetAfterFade;

		private bool travelPending;

		private bool directoryReady;

		private bool pendingTeleport;

		private Vector3 pendingPosition;

		private Quaternion pendingRotation;

		private TeleportWorld deferredPortal;

		private ZDOID deferredSource;

		private float deferredStarted;

		private float deferredDeadline;

		private float nextDeferredAttempt;

		private RectTransform panelRect;

		private VerticalLayoutGroup panelLayout;

		private VerticalLayoutGroup contentLayout;

		private TMP_Text titleText;

		private TMP_Text hintText;

		private GameObject darkBackdrop;

		private CanvasGroup darkBackdropGroup;

		private GameObject menuOrnament;

		private Graphic[] menuOrnamentGraphics = Array.Empty<Graphic>();

		private float[] menuOrnamentBaseAlphas = Array.Empty<float>();

		private bool visualsDirty;

		private readonly List<GameObject> rows = new List<GameObject>();

		private readonly List<PortalEntryHover> portalRows = new List<PortalEntryHover>();

		private readonly List<PortalInfo> currentPortals = new List<PortalInfo>();

		private static TMP_FontAsset nativeFont;

		private static Material nativeFontMaterial;

		private static Sprite nativeHomeSprite;

		private static int nativeHomeSpriteSearchFrame = -1;

		private static bool cursorWarpPrepared;

		private static PropertyInfo inputMouseCurrentProperty;

		private static MethodInfo inputMouseWarpMethod;

		internal static bool CapturesInput
		{
			get
			{
				if ((Object)(object)Instance != (Object)null)
				{
					if (!Object.op_Implicit((Object)(object)Instance.panel) || !Instance.panel.activeSelf)
					{
						return Instance.travelPending;
					}
					return true;
				}
				return false;
			}
		}

		internal static bool WantsCursor
		{
			get
			{
				if ((Object)(object)Instance != (Object)null && Object.op_Implicit((Object)(object)Instance.panel) && Instance.panel.activeSelf && Instance.fadeTarget > 0f)
				{
					return !Instance.travelPending;
				}
				return false;
			}
		}

		private void Awake()
		{
			Instance = this;
			visualsDirty = true;
			PrepareCursorWarp();
		}

		internal void MarkVisualsDirty()
		{
			visualsDirty = true;
		}

		internal void Begin(TeleportWorld portal, ZDOID sourceId)
		{
			//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_004c: 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_00a5: 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)
			if (Object.op_Implicit((Object)(object)portal) && !CapturesInput && nonce == 0L && !Object.op_Implicit((Object)(object)deferredPortal) && !(Time.realtimeSinceStartup < nextOpenAllowed) && !AnotherModalIsVisible() && PortalCandidateIsUsable(portal, sourceId))
			{
				deferredPortal = portal;
				deferredSource = sourceId;
				deferredStarted = Time.realtimeSinceStartup;
				deferredDeadline = deferredStarted + 6f;
				nextDeferredAttempt = deferredStarted + 0.1f;
				if (!TryStartRequest(portal, sourceId))
				{
					Plugin.LogDebug($"Portal entry deferred for up to {6f:0.0}s while the world portal registry and routed RPC finish initializing.");
				}
				else if (deferredSource != ZDOID.None && !directoryReady)
				{
					nextDeferredAttempt = Time.realtimeSinceStartup + 0.75f;
					Plugin.LogDebug("Portal directory request sent; waiting for server acceptance.");
				}
			}
		}

		private bool TryStartRequest(TeleportWorld portal, ZDOID sourceId)
		{
			//IL_0001: 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_0024: 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_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_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_00a7: 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)
			if (!PortalCandidateIsUsable(portal, sourceId) || !PortalRpc.Register() || !PortalRpc.TryPortal(sourceId, out var _))
			{
				return false;
			}
			sourcePortal = portal;
			source = sourceId;
			if (!SourceIsUsable())
			{
				sourcePortal = null;
				source = ZDOID.None;
				return false;
			}
			nonce = DateTime.UtcNow.Ticks;
			directoryReady = false;
			requestStarted = Time.realtimeSinceStartup;
			sessionDeadline = requestStarted + 60f - 2f;
			PortalHome.TryGet(out var id);
			if (!PortalRpc.AskDirectory(source, id, nonce))
			{
				sourcePortal = null;
				source = ZDOID.None;
				nonce = 0L;
				requestStarted = 0f;
				sessionDeadline = 0f;
				return false;
			}
			return true;
		}

		private static bool PortalCandidateIsUsable(TeleportWorld portal, ZDOID sourceId)
		{
			//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_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_0079: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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)
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)portal) || !Object.op_Implicit((Object)(object)localPlayer) || sourceId == ZDOID.None)
			{
				return false;
			}
			ZNetView component = ((Component)portal).GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || component.GetZDO() == null || component.GetZDO().m_uid != sourceId)
			{
				return false;
			}
			Vector3 val = (Object.op_Implicit((Object)(object)portal.m_proximityRoot) ? portal.m_proximityRoot.position : component.GetZDO().GetPosition());
			return Vector3.Distance(((Component)localPlayer).transform.position, val) <= PortalRanges.ClientDistance(portal);
		}

		private void AdvanceDeferredBegin()
		{
			//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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: 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_0110: Unknown result type (might be due to invalid IL or missing references)
			if (deferredSource == ZDOID.None)
			{
				return;
			}
			if (!Object.op_Implicit((Object)(object)deferredPortal))
			{
				ClearDeferredBegin();
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup >= deferredDeadline)
			{
				Plugin.LogDebug($"Deferred portal entry timed out after {Mathf.Max(0f, realtimeSinceStartup - deferredStarted):0.00}s; leave and re-enter the portal to retry.");
				ResetSession(0f);
			}
			else if (realtimeSinceStartup < nextOpenAllowed || AnotherModalIsVisible() || !PortalCandidateIsUsable(deferredPortal, deferredSource))
			{
				Plugin.LogDebug("Deferred portal entry canceled because the player left range, opened another interface, or entered the post-travel cooldown.");
				ResetSession(0f);
			}
			else
			{
				if (realtimeSinceStartup < nextDeferredAttempt)
				{
					return;
				}
				if (nonce == 0L)
				{
					nextDeferredAttempt = realtimeSinceStartup + 0.1f;
					if (TryStartRequest(deferredPortal, deferredSource))
					{
						nextDeferredAttempt = realtimeSinceStartup + 0.75f;
						Plugin.LogDebug("Deferred portal directory request sent; waiting for server acceptance.");
					}
				}
				else if (!directoryReady)
				{
					nextDeferredAttempt = realtimeSinceStartup + 0.75f;
					PortalHome.TryGet(out var id);
					if (!PortalRpc.AskDirectory(source, id, nonce))
					{
						nextDeferredAttempt = realtimeSinceStartup + 0.1f;
					}
				}
			}
		}

		private void ClearDeferredBegin()
		{
			//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)
			deferredPortal = null;
			deferredSource = ZDOID.None;
			deferredStarted = 0f;
			deferredDeadline = 0f;
			nextDeferredAttempt = 0f;
		}

		internal void Show(long responseNonce, bool homeValid, List<PortalInfo> portals)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_042c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0436: Expected O, but got Unknown
			//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			if (responseNonce != nonce || travelPending || directoryReady)
			{
				return;
			}
			if (!SourceIsUsable())
			{
				ResetSession(0f);
				return;
			}
			directoryReady = true;
			if (deferredSource != ZDOID.None)
			{
				float num = Mathf.Max(0f, Time.realtimeSinceStartup - deferredStarted);
				Plugin.LogDebug($"Deferred portal entry started successfully after {num:0.00}s and server acceptance.");
				ClearDeferredBegin();
			}
			EnsureUi();
			foreach (GameObject row in rows)
			{
				Object.Destroy((Object)(object)row);
			}
			rows.Clear();
			portalRows.Clear();
			currentPortals.Clear();
			firstSelectable = null;
			homeSelectable = null;
			currentPortals.AddRange((from p in portals
				orderby PortalBiomes.Rank(p.Biome), p.CreationOrder
				select p).ThenBy(delegate(PortalInfo p)
			{
				//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)
				ZDOID id = p.Id;
				return (ulong)((ZDOID)(ref id)).UserID;
			}).ThenBy((PortalInfo p) => ((ZDOID)(ref p.Id)).ID));
			Dictionary<string, int> dictionary = currentPortals.GroupBy<PortalInfo, string>((PortalInfo p) => p.Name, StringComparer.OrdinalIgnoreCase).ToDictionary<IGrouping<string, PortalInfo>, string, int>((IGrouping<string, PortalInfo> g) => g.Key, (IGrouping<string, PortalInfo> g) => g.Count(), StringComparer.OrdinalIgnoreCase);
			Dictionary<string, int> dictionary2 = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
			if (PortalHome.TryGet(out var home) && (!homeValid || (home != source && !currentPortals.Any((PortalInfo portal) => portal.Id == home))))
			{
				PortalHome.Clear();
				home = ZDOID.None;
				ShowStatus("Home portal unavailable — choose a new Home");
			}
			foreach (PortalInfo currentPortal in currentPortals)
			{
				dictionary2.TryGetValue(currentPortal.Name, out var value);
				value = (dictionary2[currentPortal.Name] = value + 1);
				string label = ((dictionary[currentPortal.Name] > 1) ? $"{currentPortal.Name}  ({value}/{dictionary[currentPortal.Name]})" : currentPortal.Name);
				PortalInfo destination = currentPortal;
				Button val = AddRow(label, PortalBiomes.DisplayName(currentPortal.Biome), currentPortal.Id, delegate
				{
					//IL_0011: Unknown result type (might be due to invalid IL or missing references)
					ActivateDestination(destination.Id);
				}, delegate
				{
					ToggleHome(destination);
				}, currentPortal.Id == home);
				if (!Object.op_Implicit((Object)(object)firstSelectable))
				{
					firstSelectable = val;
				}
				if (currentPortal.Id == home)
				{
					homeSelectable = val;
				}
			}
			if (currentPortals.Count == 0)
			{
				AddRow("No named destinations found", string.Empty, ZDOID.None, null, null, isHome: false);
			}
			ConfigureRowNavigation();
			UpdateHintText();
			ApplyVisualSettings();
			canvasGroup.alpha = 0f;
			canvasGroup.interactable = true;
			canvasGroup.blocksRaycasts = true;
			fadeTarget = 1f;
			resetAfterFade = false;
			panel.SetActive(true);
			LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)panel.transform);
			previousMouseInput = null;
			mouseChoiceArmed = false;
			SynchronizeInputSelection(centerMouse: true);
			if (Object.op_Implicit((Object)(object)homeSelectable) && PortalVisualSettings.PreferHomeOnOpen)
			{
				ScrollIntoView(((Component)homeSelectable).gameObject);
			}
		}

		internal void Complete(long responseNonce, bool approved, Vector3 position, Quaternion rotation)
		{
			//IL_0031: 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_0038: 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)
			if (responseNonce != nonce)
			{
				return;
			}
			travelPending = false;
			if (!approved || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				RequestClose(invalidateRequest: true);
				return;
			}
			pendingTeleport = true;
			pendingPosition = position;
			pendingRotation = rotation;
			BeginFadeOut(resetWhenHidden: false);
			if (!Object.op_Implicit((Object)(object)panel) || !panel.activeSelf)
			{
				PerformPendingTeleport();
			}
		}

		internal void CloseIfSource(TeleportWorld portal)
		{
			if (Object.op_Implicit((Object)(object)portal) && (Object)(object)portal == (Object)(object)deferredPortal)
			{
				Plugin.LogDebug("Deferred portal entry canceled when the player left the source trigger.");
				ClearDeferredBegin();
			}
			if (Object.op_Implicit((Object)(object)portal) && (Object)(object)portal == (Object)(object)sourcePortal && nonce != 0L)
			{
				RequestClose(invalidateRequest: true);
			}
		}

		internal void DismissFromMenuInput()
		{
			RequestClose(invalidateRequest: true);
		}

		private void Update()
		{
			//IL_008e: 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)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)panel) && Object.op_Implicit((Object)(object)Menu.instance) && Object.op_Implicit((Object)(object)Menu.instance.m_continueButton))
			{
				EnsureUi();
			}
			AdvanceDeferredBegin();
			if (visualsDirty)
			{
				ApplyVisualSettings();
			}
			if (nonce != 0L && !SourceIsUsable())
			{
				RequestClose(invalidateRequest: true);
			}
			if (Object.op_Implicit((Object)(object)panel) && panel.activeSelf)
			{
				SynchronizeInputSelection();
				AdvanceCursorCentering();
				ArmMouseChoiceAfterMovement();
				KeyboardShortcut setHomeKeyboardShortcut = PortalVisualSettings.SetHomeKeyboardShortcut;
				if (((KeyboardShortcut)(ref setHomeKeyboardShortcut)).IsDown() || ZInput.GetButtonDown("JoyButtonX"))
				{
					ToggleSelectedHome();
				}
				else if (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271) || ZInput.GetButtonDown("JoyButtonA"))
				{
					ConfirmSelected();
				}
				else if (Input.GetKeyDown((KeyCode)27) || ZInput.GetButtonDown("JoyButtonB") || AnotherModalIsVisible())
				{
					RequestClose(invalidateRequest: true);
				}
				KeepControllerSelectionVisible();
				AdvanceFade();
			}
			if (nonce != 0L && Time.realtimeSinceStartup >= sessionDeadline)
			{
				RequestClose(invalidateRequest: true);
			}
			if (travelPending && Time.realtimeSinceStartup >= travelDeadline)
			{
				RequestClose(invalidateRequest: true);
			}
			if (nonce != 0L && deferredSource == ZDOID.None && !travelPending && (!Object.op_Implicit((Object)(object)panel) || !panel.activeSelf) && Time.realtimeSinceStartup - requestStarted >= 5f)
			{
				ResetSession(0f);
			}
			if (pendingTeleport && (!Object.op_Implicit((Object)(object)panel) || !panel.activeSelf))
			{
				PerformPendingTeleport();
			}
		}

		private void EnsureUi()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Expected O, but got Unknown
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Expected O, but got Unknown
			//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_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Expected O, but got Unknown
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_037f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Expected O, but got Unknown
			//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e4: Expected O, but got Unknown
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0408: Expected O, but got Unknown
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0434: Expected O, but got Unknown
			//IL_045b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0462: Expected O, but got Unknown
			//IL_046e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0484: Unknown result type (might be due to invalid IL or missing references)
			//IL_049a: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_053b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0545: Expected O, but got Unknown
			if (Object.op_Implicit((Object)(object)panel))
			{
				return;
			}
			GameObject val = new GameObject("BetterPortals Canvas", new Type[3]
			{
				typeof(Canvas),
				typeof(CanvasScaler),
				typeof(GraphicRaycaster)
			});
			val.transform.SetParent(((Component)this).transform, false);
			Canvas component = val.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.overrideSorting = true;
			RectTransform component2 = val.GetComponent<RectTransform>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				component2.anchorMin = Vector2.zero;
				component2.anchorMax = Vector2.one;
				component2.pivot = new Vector2(0.5f, 0.5f);
				component2.anchoredPosition = Vector2.zero;
				component2.sizeDelta = Vector2.zero;
			}
			Menu instance = Menu.instance;
			Canvas val2 = ((instance != null) ? ((Component)instance).GetComponentInParent<Canvas>() : null);
			component.sortingOrder = (Object.op_Implicit((Object)(object)val2) ? (val2.sortingOrder + 1) : 1701);
			ConfigureScaler(val.GetComponent<CanvasScaler>());
			panel = new GameObject("Floating Portal Menu", new Type[4]
			{
				typeof(RectTransform),
				typeof(CanvasGroup),
				typeof(VerticalLayoutGroup),
				typeof(ContentSizeFitter)
			});
			panel.transform.SetParent(val.transform, false);
			panelRect = (RectTransform)panel.transform;
			RectTransform obj = panelRect;
			RectTransform obj2 = panelRect;
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(0.5f, 0.5f);
			obj2.anchorMax = val3;
			obj.anchorMin = val3;
			panelRect.pivot = new Vector2(0.5f, 0.5f);
			canvasGroup = panel.GetComponent<CanvasGroup>();
			panelLayout = panel.GetComponent<VerticalLayoutGroup>();
			((LayoutGroup)panelLayout).padding = new RectOffset(16, 16, 12, 12);
			((HorizontalOrVerticalLayoutGroup)panelLayout).spacing = 4f;
			((LayoutGroup)panelLayout).childAlignment = (TextAnchor)4;
			((HorizontalOrVerticalLayoutGroup)panelLayout).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)panelLayout).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)panelLayout).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)panelLayout).childForceExpandWidth = true;
			panel.GetComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			darkBackdrop = CloneNativeDecoration("darken", panel.transform, 0);
			if (Object.op_Implicit((Object)(object)darkBackdrop))
			{
				darkBackdropGroup = darkBackdrop.GetComponent<CanvasGroup>() ?? darkBackdrop.AddComponent<CanvasGroup>();
			}
			menuOrnament = CloneNativeDecoration("ornament", panel.transform, 1);
			if (Object.op_Implicit((Object)(object)menuOrnament))
			{
				menuOrnamentGraphics = menuOrnament.GetComponentsInChildren<Graphic>(true);
				menuOrnamentBaseAlphas = menuOrnamentGraphics.Select((Graphic graphic) => graphic.color.a).ToArray();
			}
			titleText = (TMP_Text)(object)AddText(panel.transform, "CHOOSE DESTINATION", PortalVisualSettings.TitleFontSize, (FontStyles)0, PortalVisualSettings.TitleColor);
			hintText = (TMP_Text)(object)AddText(panel.transform, "Walk away or press Escape to close", PortalVisualSettings.HintFontSize, (FontStyles)0, PortalVisualSettings.HintColor);
			GameObject val4 = new GameObject("Destinations", new Type[3]
			{
				typeof(RectTransform),
				typeof(ScrollRect),
				typeof(LayoutElement)
			});
			val4.transform.SetParent(panel.transform, false);
			scrollLayout = val4.GetComponent<LayoutElement>();
			scrollLayout.preferredHeight = 320f;
			GameObject val5 = new GameObject("Viewport", new Type[2]
			{
				typeof(RectTransform),
				typeof(RectMask2D)
			});
			val5.transform.SetParent(val4.transform, false);
			Stretch((RectTransform)val5.transform);
			GameObject val6 = new GameObject("Content", new Type[2]
			{
				typeof(VerticalLayoutGroup),
				typeof(ContentSizeFitter)
			});
			val6.transform.SetParent(val5.transform, false);
			content = val6.transform;
			RectTransform val7 = (RectTransform)content;
			val7.anchorMin = new Vector2(0f, 1f);
			val7.anchorMax = new Vector2(1f, 1f);
			val7.pivot = new Vector2(0.5f, 1f);
			val7.anchoredPosition = Vector2.zero;
			val7.sizeDelta = Vector2.zero;
			contentLayout = val6.GetComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)contentLayout).spacing = 2f;
			((LayoutGroup)contentLayout).childAlignment = (TextAnchor)1;
			((HorizontalOrVerticalLayoutGroup)contentLayout).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)contentLayout).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)contentLayout).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)contentLayout).childForceExpandWidth = true;
			val6.GetComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			destinationScroll = val4.GetComponent<ScrollRect>();
			destinationScroll.viewport = (RectTransform)val5.transform;
			destinationScroll.content = val7;
			destinationScroll.horizontal = false;
			destinationScroll.vertical = true;
			destinationScroll.movementType = (MovementType)2;
			destinationScroll.scrollSensitivity = 32f;
			panel.SetActive(false);
			ApplyVisualSettings();
		}

		private static GameObject CloneNativeDecoration(string name, Transform parent, int siblingIndex)
		{
			Menu instance = Menu.instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				Transform menuDialog = instance.m_menuDialog;
				obj = ((menuDialog != null) ? menuDialog.Find(name) : null);
			}
			Transform val = (Transform)obj;
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, parent, false);
			((Object)val2).name = "Portal " + name;
			val2.SetActive(true);
			(val2.GetComponent<LayoutElement>() ?? val2.AddComponent<LayoutElement>()).ignoreLayout = true;
			Graphic[] componentsInChildren = val2.GetComponentsInChildren<Graphic>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].raycastTarget = false;
			}
			val2.transform.SetSiblingIndex(Mathf.Clamp(siblingIndex, 0, parent.childCount - 1));
			return val2;
		}

		private void ApplyVisualSettings()
		{
			//IL_0025: 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_009e: 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_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: 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)
			//IL_0194: 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_01a9: Unknown result type (might be due to invalid IL or missing references)
			visualsDirty = false;
			if (!Object.op_Implicit((Object)(object)panel))
			{
				return;
			}
			panelRect.anchoredPosition = new Vector2(0f, PortalVisualSettings.PanelYOffset);
			panelRect.sizeDelta = new Vector2(PortalVisualSettings.PanelWidth, 0f);
			if (Object.op_Implicit((Object)(object)contentLayout))
			{
				((HorizontalOrVerticalLayoutGroup)contentLayout).spacing = PortalVisualSettings.RowSpacing;
			}
			if (Object.op_Implicit((Object)(object)destinationScroll))
			{
				destinationScroll.scrollSensitivity = Mathf.Max(16f, PortalVisualSettings.RowHeight * 0.7f);
			}
			ApplyTextAppearance(titleText, PortalVisualSettings.TitleFontSize, PortalVisualSettings.TitleColor);
			ApplyTextAppearance(hintText, PortalVisualSettings.HintFontSize, PortalVisualSettings.HintColor);
			foreach (GameObject row in rows)
			{
				if (Object.op_Implicit((Object)(object)row))
				{
					row.GetComponent<PortalEntryHover>()?.ApplyVisualSettings();
				}
			}
			UpdateHintText();
			if (Object.op_Implicit((Object)(object)darkBackdrop))
			{
				darkBackdrop.SetActive(PortalVisualSettings.BackdropOpacity > 0.001f);
				if (Object.op_Implicit((Object)(object)darkBackdropGroup))
				{
					darkBackdropGroup.alpha = PortalVisualSettings.BackdropOpacity;
				}
			}
			if (Object.op_Implicit((Object)(object)menuOrnament))
			{
				menuOrnament.SetActive(PortalVisualSettings.ShowMenuOrnament);
				Color ornamentColor = PortalVisualSettings.OrnamentColor;
				for (int i = 0; i < menuOrnamentGraphics.Length; i++)
				{
					Graphic val = menuOrnamentGraphics[i];
					if (Object.op_Implicit((Object)(object)val))
					{
						val.color = new Color(ornamentColor.r, ornamentColor.g, ornamentColor.b, menuOrnamentBaseAlphas[i] * ornamentColor.a);
					}
				}
			}
			UpdateListHeight();
			if (panel.activeSelf)
			{
				LayoutRebuilder.ForceRebuildLayoutImmediate(panelRect);
			}
		}

		private void UpdateListHeight()
		{
			if (Object.op_Implicit((Object)(object)scrollLayout))
			{
				List<GameObject> list = rows.Where((GameObject row) => Object.op_Implicit((Object)(object)row) && row.activeSelf).ToList();
				int num = Mathf.Max(1, list.Count);
				float num2 = list.Sum(delegate(GameObject row)
				{
					LayoutElement component = row.GetComponent<LayoutElement>();
					return (component == null) ? PortalVisualSettings.RowHeight : component.preferredHeight;
				}) + (float)Mathf.Max(0, num - 1) * PortalVisualSettings.RowSpacing;
				float num3 = Mathf.Min(PortalVisualSettings.MaxListHeight, Mathf.Max(54f, PortalVisualSettings.RowHeight));
				scrollLayout.preferredHeight = Mathf.Clamp(num2, num3, PortalVisualSettings.MaxListHeight);
			}
		}

		internal static void ApplyTextAppearance(TMP_Text text, float size, Color color)
		{
			//IL_0011: 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)
			if (Object.op_Implicit((Object)(object)text))
			{
				text.fontSize = size;
				((Graphic)text).color = color;
				text.outlineColor = Color32.op_Implicit(PortalVisualSettings.OutlineColor);
				text.outlineWidth = PortalVisualSettings.OutlineWidth;
			}
		}

		private void ConfigureRowNavigation()
		{
			//IL_005f: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			List<Button> list = (from row in rows
				select (!Object.op_Implicit((Object)(object)row)) ? null : row.GetComponent<Button>() into button
				where Object.op_Implicit((Object)(object)button) && ((Selectable)button).interactable
				select button).ToList();
			for (int num = 0; num < list.Count; num++)
			{
				Navigation navigation = ((Selectable)list[num]).navigation;
				((Navigation)(ref navigation)).mode = (Mode)4;
				((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)list[(num + list.Count - 1) % list.Count];
				((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)list[(num + 1) % list.Count];
				((Selectable)list[num]).navigation = navigation;
			}
		}

		private void SynchronizeInputSelection(bool centerMouse = false)
		{
			//IL_009a: 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)
			EventSystem current = EventSystem.current;
			if (!Object.op_Implicit((Object)(object)current))
			{
				return;
			}
			bool flag = ZInput.IsMouseActive();
			if (previousMouseInput.HasValue && previousMouseInput.Value == flag)
			{
				return;
			}
			bool flag2 = previousMouseInput.HasValue && !previousMouseInput.Value && flag;
			previousMouseInput = flag;
			GameObject currentSelectedGameObject = current.currentSelectedGameObject;
			if (flag)
			{
				ApplySelectorCursor(centerMouse || flag2);
				if (centerMouse || flag2)
				{
					cursorCenterFrames = 1;
					openingMousePosition = new Vector3((float)Screen.width * 0.5f, (float)Screen.height * 0.5f, 0f);
					mouseChoiceArmed = false;
				}
				if (Object.op_Implicit((Object)(object)currentSelectedGameObject) && Object.op_Implicit((Object)(object)panel) && currentSelectedGameObject.transform.IsChildOf(panel.transform))
				{
					current.SetSelectedGameObject((GameObject)null);
				}
			}
			else if (Object.op_Implicit((Object)(object)firstSelectable))
			{
				ApplySelectorCursor(center: false);
				Button val = ((PortalVisualSettings.PreferHomeOnOpen && Object.op_Implicit((Object)(object)homeSelectable)) ? homeSelectable : firstSelectable);
				current.SetSelectedGameObject(((Component)val).gameObject);
				ScrollIntoView(((Component)val).gameObject);
			}
			UpdateHintText();
		}

		private void AdvanceCursorCentering()
		{
			//IL_002e: 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)
			if (cursorCenterFrames > 0 && ZInput.IsMouseActive())
			{
				ApplySelectorCursor(center: true);
				cursorCenterFrames--;
				if (cursorCenterFrames == 0)
				{
					openingMousePosition = Input.mousePosition;
				}
			}
		}

		private void ArmMouseChoiceAfterMovement()
		{
			//IL_0019: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			if (!mouseChoiceArmed && cursorCenterFrames <= 0 && ZInput.IsMouseActive())
			{
				Vector3 val = Input.mousePosition - openingMousePosition;
				if (((Vector3)(ref val)).sqrMagnitude > 9f)
				{
					mouseChoiceArmed = true;
				}
			}
		}

		private void KeepControllerSelectionVisible()
		{
			if (!ZInput.IsMouseActive() && Object.op_Implicit((Object)(object)destinationScroll) && Object.op_Implicit((Object)(object)destinationScroll.viewport) && Object.op_Implicit((Object)(object)destinationScroll.content))
			{
				EventSystem current = EventSystem.current;
				GameObject selected = ((current != null) ? current.currentSelectedGameObject : null);
				ScrollIntoView(selected);
			}
		}

		private void ScrollIntoView(GameObject selected)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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_0082: 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_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: 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)
			if (Object.op_Implicit((Object)(object)selected) && Object.op_Implicit((Object)(object)destinationScroll) && Object.op_Implicit((Object)(object)destinationScroll.viewport) && Object.op_Implicit((Object)(object)destinationScroll.content) && selected.transform.IsChildOf(content))
			{
				Canvas.ForceUpdateCanvases();
				Bounds val = RectTransformUtility.CalculateRelativeRectTransformBounds((Transform)(object)destinationScroll.viewport, selected.transform);
				Rect rect = destinationScroll.viewport.rect;
				float num = 0f;
				if (((Bounds)(ref val)).min.y < ((Rect)(ref rect)).yMin)
				{
					num = ((Rect)(ref rect)).yMin - ((Bounds)(ref val)).min.y;
				}
				else if (((Bounds)(ref val)).max.y > ((Rect)(ref rect)).yMax)
				{
					num = ((Rect)(ref rect)).yMax - ((Bounds)(ref val)).max.y;
				}
				if (!Mathf.Approximately(num, 0f))
				{
					Vector2 anchoredPosition = destinationScroll.content.anchoredPosition;
					anchoredPosition.y += num;
					destinationScroll.content.anchoredPosition = anchoredPosition;
				}
			}
		}

		private void ToggleHome(PortalInfo portal)
		{
			//IL_0016: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			ZDOID id;
			bool flag = PortalHome.TryGet(out id) && id == portal.Id;
			if (!(flag ? PortalHome.Clear() : PortalHome.Set(portal.Id)))
			{
				return;
			}
			foreach (PortalEntryHover portalRow in portalRows)
			{
				portalRow.SetHome(!flag && portalRow.PortalId == portal.Id);
			}
			object obj;
			if (!flag)
			{
				PortalEntryHover? portalEntryHover = portalRows.FirstOrDefault((PortalEntryHover row) => row.PortalId == portal.Id);
				obj = ((portalEntryHover != null) ? ((Component)portalEntryHover).GetComponent<Button>() : null);
			}
			else
			{
				obj = null;
			}
			homeSelectable = (Button)obj;
			UpdateHintText();
			Plugin.LogDebug(flag ? "Home portal cleared." : ("Home portal set to " + portal.Name + "."));
		}

		private PortalEntryHover SelectedPortalRow()
		{
			EventSystem current = EventSystem.current;
			GameObject obj = ((current != null) ? current.currentSelectedGameObject : null);
			object obj2 = ((obj != null) ? obj.GetComponent<PortalEntryHover>() : null);
			if (obj2 == null)
			{
				obj2 = portalRows.FirstOrDefault((PortalEntryHover row) => row.PointerInside);
				if (obj2 == null)
				{
					if (!PortalVisualSettings.PreferHomeOnOpen || !Object.op_Implicit((Object)(object)homeSelectable))
					{
						Button obj3 = firstSelectable;
						if (obj3 == null)
						{
							return null;
						}
						return ((Component)obj3).GetComponent<PortalEntryHover>();
					}
					obj2 = ((Component)homeSelectable).GetComponent<PortalEntryHover>();
				}
			}
			return (PortalEntryHover)obj2;
		}

		private void ToggleSelectedHome()
		{
			SelectedPortalRow()?.SetAsHome();
		}

		private void ConfirmSelected()
		{
			if (!travelPending)
			{
				((ZInput.IsMouseActive() && !mouseChoiceArmed && Object.op_Implicit((Object)(object)homeSelectable)) ? ((Component)homeSelectable).GetComponent<PortalEntryHover>() : SelectedPortalRow())?.Activate();
			}
		}

		private void ActivateDestination(ZDOID destination)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			SelectDestination(destination);
		}

		private void UpdateHintText()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)hintText))
			{
				((Component)hintText).gameObject.SetActive(PortalVisualSettings.ShowControlHints);
				if (PortalVisualSettings.ShowControlHints)
				{
					hintText.text = (ZInput.IsMouseActive() ? $"Enter Travel     {PortalVisualSettings.SetHomeKeyboardShortcut} Set Home     Esc Close" : "A Travel     X Set Home     B Close");
				}
			}
		}

		private static void ShowStatus(string message)
		{
			MessageHud instance = MessageHud.instance;
			if (Object.op_Implicit((Object)(object)instance))
			{
				instance.ShowMessage((MessageType)1, message, 0, ResolveHomeSprite(), false, false);
			}
		}

		internal static void ApplySelectorCursor(bool center)
		{
			if (Application.isBatchMode)
			{
				return;
			}
			if (!ZInput.IsMouseActive())
			{
				if (ZCursor.IsVisible)
				{
					ZCursor.Hide();
				}
				ZCursor.LockState = (CursorLockMode)1;
				return;
			}
			ZCursor.LockState = (CursorLockMode)0;
			if (!ZCursor.IsVisible)
			{
				ZCursor.Show();
			}
			if (center)
			{
				CenterPointer();
			}
		}

		private static void PrepareCursorWarp()
		{
			if (cursorWarpPrepared)
			{
				return;
			}
			cursorWarpPrepared = true;
			try
			{
				Type type = Acce