Decompiled source of VikingsPortals v1.0.0

plugins/VikingsPortals.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Groups;
using Guilds;
using HarmonyLib;
using JetBrains.Annotations;
using LocalizationManager;
using Microsoft.CodeAnalysis;
using ServerSync;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using VikingsAscensionAPI;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.ObjectPool;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Callbacks;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: AssemblyTitle("VikingsPortals")]
[assembly: AssemblyProduct("VikingsPortals")]
[assembly: AssemblyInformationalVersion("1.0.0+15dbe340bdad566954a87d2bb37f562a4bc93a15")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCompany("VikingsPortals")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: <2dea9613-89dc-4972-ac37-d2600ff957a3>RefSafetyRules(11)]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<9673c41f-ef17-4443-8b62-bb449451d413>Embedded]
	internal sealed class <9673c41f-ef17-4443-8b62-bb449451d413>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[<9673c41f-ef17-4443-8b62-bb449451d413>Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class <7a806118-b484-4911-b895-cee4047d3ab8>NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public <7a806118-b484-4911-b895-cee4047d3ab8>NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public <7a806118-b484-4911-b895-cee4047d3ab8>NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	[<9673c41f-ef17-4443-8b62-bb449451d413>Embedded]
	[CompilerGenerated]
	internal sealed class <596d02bc-cb07-4f28-80d1-942233a59b21>NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public <596d02bc-cb07-4f28-80d1-942233a59b21>NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	[<9673c41f-ef17-4443-8b62-bb449451d413>Embedded]
	internal sealed class <2dea9613-89dc-4972-ac37-d2600ff957a3>RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public <2dea9613-89dc-4972-ac37-d2600ff957a3>RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LocalizationManager
{
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	[PublicAPI]
	public class Localizer
	{
		private static readonly Dictionary<string, Dictionary<string, Func<string>>> PlaceholderProcessors;

		private static readonly Dictionary<string, Dictionary<string, string>> loadedTexts;

		private static readonly ConditionalWeakTable<Localization, string> localizationLanguage;

		private static readonly List<WeakReference<Localization>> localizationObjects;

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		private static BaseUnityPlugin _plugin;

		private static readonly List<string> fileExtensions;

		private static BaseUnityPlugin plugin
		{
			get
			{
				//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b2: Expected O, but got Unknown
				if (_plugin == null)
				{
					IEnumerable<TypeInfo> source;
					try
					{
						source = Assembly.GetExecutingAssembly().DefinedTypes.ToList();
					}
					catch (ReflectionTypeLoadException ex)
					{
						source = from t in ex.Types
							where t != null
							select t.GetTypeInfo();
					}
					_plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First([<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t)));
				}
				return _plugin;
			}
		}

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		[method: <596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(2)]
		[field: <7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		public static event Action OnLocalizationComplete;

		private static void UpdatePlaceholderText(Localization localization, string key)
		{
			localizationLanguage.TryGetValue(localization, out var value);
			string text = loadedTexts[value][key];
			if (PlaceholderProcessors.TryGetValue(key, out var value2))
			{
				text = value2.Aggregate(text, [<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(0)] (string current, KeyValuePair<string, Func<string>> kv) => current.Replace("{" + kv.Key + "}", kv.Value()));
			}
			localization.AddWord(key, text);
		}

		public static void AddPlaceholder<T>(string key, string placeholder, ConfigEntry<T> config, [<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(new byte[] { 2, 1, 1 })] Func<T, string> convertConfigValue = null)
		{
			if (convertConfigValue == null)
			{
				convertConfigValue = (T val) => val.ToString();
			}
			if (!PlaceholderProcessors.ContainsKey(key))
			{
				PlaceholderProcessors[key] = new Dictionary<string, Func<string>>();
			}
			config.SettingChanged += [<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(0)] (object _, EventArgs _) =>
			{
				UpdatePlaceholder();
			};
			if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage()))
			{
				UpdatePlaceholder();
			}
			void UpdatePlaceholder()
			{
				PlaceholderProcessors[key][placeholder] = () => convertConfigValue(config.Value);
				UpdatePlaceholderText(Localization.instance, key);
			}
		}

		public static void AddText(string key, string text)
		{
			List<WeakReference<Localization>> list = new List<WeakReference<Localization>>();
			foreach (WeakReference<Localization> localizationObject in localizationObjects)
			{
				if (localizationObject.TryGetTarget(out var target))
				{
					Dictionary<string, string> dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)];
					if (!target.m_translations.ContainsKey(key))
					{
						dictionary[key] = text;
						target.AddWord(key, text);
					}
				}
				else
				{
					list.Add(localizationObject);
				}
			}
			foreach (WeakReference<Localization> item in list)
			{
				localizationObjects.Remove(item);
			}
		}

		public static void Load()
		{
			_ = plugin;
		}

		public static void LoadLocalizationLater(Localization __instance)
		{
			LoadLocalization(Localization.instance, __instance.GetSelectedLanguage());
		}

		public static void SafeCallLocalizeComplete()
		{
			Localizer.OnLocalizationComplete?.Invoke();
		}

		private static void LoadLocalization(Localization __instance, string language)
		{
			if (!localizationLanguage.Remove(__instance))
			{
				localizationObjects.Add(new WeakReference<Localization>(__instance));
			}
			localizationLanguage.Add(__instance, language);
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			foreach (string item in from f in Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), plugin.Info.Metadata.Name + ".*", SearchOption.AllDirectories)
				where fileExtensions.IndexOf(Path.GetExtension(f)) >= 0
				select f)
			{
				string[] array = Path.GetFileNameWithoutExtension(item).Split(new char[1] { '.' });
				if (array.Length >= 2)
				{
					string text = array[1];
					if (dictionary.ContainsKey(text))
					{
						Debug.LogWarning((object)("Duplicate key " + text + " found for " + plugin.Info.Metadata.Name + ". The duplicate file found at " + item + " will be skipped."));
					}
					else
					{
						dictionary[text] = item;
					}
				}
			}
			byte[] array2 = LoadTranslationFromAssembly("English");
			if (array2 == null)
			{
				throw new Exception("Found no English localizations in mod " + plugin.Info.Metadata.Name + ". Expected an embedded resource translations/English.json or translations/English.yml.");
			}
			Dictionary<string, string> dictionary2 = new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(Encoding.UTF8.GetString(array2));
			if (dictionary2 == null)
			{
				throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Localization file was empty.");
			}
			string text2 = null;
			if (language != "English")
			{
				if (dictionary.TryGetValue(language, out var value))
				{
					text2 = File.ReadAllText(value);
				}
				else
				{
					byte[] array3 = LoadTranslationFromAssembly(language);
					if (array3 != null)
					{
						text2 = Encoding.UTF8.GetString(array3);
					}
				}
			}
			if (text2 == null && dictionary.TryGetValue("English", out var value2))
			{
				text2 = File.ReadAllText(value2);
			}
			if (text2 != null)
			{
				foreach (KeyValuePair<string, string> item2 in new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(text2) ?? new Dictionary<string, string>())
				{
					dictionary2[item2.Key] = item2.Value;
				}
			}
			loadedTexts[language] = dictionary2;
			foreach (KeyValuePair<string, string> item3 in dictionary2)
			{
				UpdatePlaceholderText(__instance, item3.Key);
			}
		}

		static Localizer()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			PlaceholderProcessors = new Dictionary<string, Dictionary<string, Func<string>>>();
			loadedTexts = new Dictionary<string, Dictionary<string, string>>();
			localizationLanguage = new ConditionalWeakTable<Localization, string>();
			localizationObjects = new List<WeakReference<Localization>>();
			fileExtensions = new List<string>(2) { ".json", ".yml" };
			Harmony val = new Harmony("org.bepinex.helpers.LocalizationManager");
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "SetupLanguage", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "SetupGui", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalizationLater", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "SafeCallLocalizeComplete", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		[return: <7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		private static byte[] LoadTranslationFromAssembly(string language)
		{
			foreach (string fileExtension in fileExtensions)
			{
				byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension);
				if (array != null)
				{
					return array;
				}
			}
			return null;
		}

		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(2)]
		public static byte[] ReadEmbeddedFileBytes([<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(1)] string resourceFileName, Assembly containingAssembly = null)
		{
			using MemoryStream memoryStream = new MemoryStream();
			if ((object)containingAssembly == null)
			{
				containingAssembly = Assembly.GetCallingAssembly();
			}
			string text = containingAssembly.GetManifestResourceNames().FirstOrDefault([<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(0)] (string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal));
			if (text != null)
			{
				containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream);
			}
			return (memoryStream.Length == 0L) ? null : memoryStream.ToArray();
		}
	}
	public static class LocalizationManagerVersion
	{
		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(1)]
		public const string Version = "1.4.1";
	}
}
namespace VikingsPortals
{
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	internal static class AscensionBridge
	{
		public static bool GuildsActive()
		{
			return ReadGuildsActive();
		}

		public static int OwnGuildId()
		{
			return ReadOwnGuildId();
		}

		public static int PlayerGuildId(string playerId, string playerName)
		{
			return (!string.IsNullOrEmpty(playerId)) ? ReadPlayerGuildId(playerId, playerName ?? "") : 0;
		}

		public static string GuildName(int id)
		{
			return (id == 0) ? "" : ReadGuildName(id);
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool ReadGuildsActive()
		{
			return AscensionAPI.AscensionIsGuildsActive();
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static int ReadOwnGuildId()
		{
			return AscensionAPI.AscensionGetOwnGuildId();
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static int ReadPlayerGuildId(string playerId, string playerName)
		{
			return AscensionAPI.AscensionGetPlayerGuildId(playerId, playerName);
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static string ReadGuildName(int id)
		{
			return AscensionAPI.AscensionGetGuildName(id) ?? "";
		}
	}
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	internal static class GroupsBridge
	{
		private const string PluginId = "org.bepinex.plugins.groups";

		public static bool Loaded()
		{
			if (!Chainloader.PluginInfos.ContainsKey("org.bepinex.plugins.groups"))
			{
				return false;
			}
			try
			{
				return ApiLoaded();
			}
			catch
			{
				return false;
			}
		}

		public static bool SameGroupAsOwner(string ownerId)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(ownerId) || !Loaded())
			{
				return false;
			}
			if (!FindOnlinePlayer(ownerId, out var found))
			{
				return false;
			}
			try
			{
				return GroupContains(found);
			}
			catch
			{
				return false;
			}
		}

		private unsafe static bool FindOnlinePlayer(string playerId, out PlayerInfo found)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			found = default(PlayerInfo);
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			List<PlayerInfo> playerList = ZNet.instance.GetPlayerList();
			if (playerList == null)
			{
				return false;
			}
			foreach (PlayerInfo item in playerList)
			{
				PlatformUserID id = item.m_userInfo.m_id;
				if (!string.Equals(((object)(*(PlatformUserID*)(&id))/*cast due to .constrained prefix*/).ToString(), playerId, StringComparison.Ordinal))
				{
					continue;
				}
				found = item;
				return true;
			}
			return false;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool ApiLoaded()
		{
			return Groups.API.IsLoaded();
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool GroupContains(PlayerInfo owner)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			return Groups.API.GroupPlayers()?.Contains(Groups.PlayerReference.fromPlayerInfo(owner)) ?? false;
		}
	}
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	internal static class GuildBridge
	{
		public const int SourceNone = 0;

		public const int SourceGuilds = 1;

		public const int SourceAscension = 2;

		public static int ActiveSource()
		{
			if (AscensionBridge.GuildsActive())
			{
				return 2;
			}
			if (GuildsBridge.Loaded())
			{
				return 1;
			}
			return 0;
		}

		public static int OwnGuildId(int source)
		{
			return source switch
			{
				2 => AscensionBridge.GuildsActive() ? AscensionBridge.OwnGuildId() : 0, 
				1 => GuildsBridge.OwnGuildId(), 
				_ => 0, 
			};
		}

		public static int PlayerGuildId(int source, string playerId, string playerName)
		{
			return source switch
			{
				2 => AscensionBridge.GuildsActive() ? AscensionBridge.PlayerGuildId(playerId, playerName) : 0, 
				1 => GuildsBridge.PlayerGuildId(playerId, playerName), 
				_ => 0, 
			};
		}

		public static string GuildName(int source, int id)
		{
			if (id == 0)
			{
				return "";
			}
			return source switch
			{
				2 => AscensionBridge.GuildName(id), 
				1 => GuildsBridge.GuildName(id), 
				_ => "", 
			};
		}

		public static bool LocalInGuild(ZDO zdo)
		{
			(int, int) tuple = PortalRecord.Guild(zdo);
			if (tuple.Item1 == 0 || tuple.Item2 == 0)
			{
				return false;
			}
			return OwnGuildId(tuple.Item2) == tuple.Item1;
		}
	}
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	internal static class GuildsBridge
	{
		private const string PluginId = "org.bepinex.plugins.guilds";

		public static bool Loaded()
		{
			if (!Chainloader.PluginInfos.ContainsKey("org.bepinex.plugins.guilds"))
			{
				return false;
			}
			try
			{
				return ApiLoaded();
			}
			catch
			{
				return false;
			}
		}

		public static int OwnGuildId()
		{
			if (!Loaded())
			{
				return 0;
			}
			try
			{
				return ReadOwnGuildId();
			}
			catch
			{
				return 0;
			}
		}

		public static int PlayerGuildId(string playerId, string playerName)
		{
			if (string.IsNullOrEmpty(playerId) || !Loaded())
			{
				return 0;
			}
			try
			{
				return ReadPlayerGuildId(playerId, playerName ?? "");
			}
			catch
			{
				return 0;
			}
		}

		public static string GuildName(int id)
		{
			if (id == 0 || !Loaded())
			{
				return "";
			}
			try
			{
				return ReadGuildName(id);
			}
			catch
			{
				return "";
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool ApiLoaded()
		{
			return Guilds.API.IsLoaded();
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static int ReadOwnGuildId()
		{
			return Guilds.API.GetOwnGuild()?.General.id ?? 0;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static int ReadPlayerGuildId(string playerId, string playerName)
		{
			return Guilds.API.GetPlayerGuild(new Guilds.PlayerReference
			{
				id = playerId,
				name = playerName
			})?.General.id ?? 0;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static string ReadGuildName(int id)
		{
			return Guilds.API.GetGuild(id)?.Name ?? "";
		}
	}
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	internal readonly struct PortalFacts
	{
		public PortalMode Mode { get; }

		public string OwnerId { get; }

		public PortalFacts(PortalMode mode, string ownerId)
		{
			Mode = mode;
			OwnerId = ownerId;
		}
	}
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	internal readonly struct ViewerFacts
	{
		public string Id { get; }

		public bool IsAdmin { get; }

		public ViewerFacts(string id, bool isAdmin)
		{
			Id = id;
			IsAdmin = isAdmin;
		}
	}
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	internal static class AccessRules
	{
		public static bool IsOwner(PortalFacts p, ViewerFacts v)
		{
			return !string.IsNullOrEmpty(p.OwnerId) && string.Equals(p.OwnerId, v.Id, StringComparison.Ordinal);
		}

		public static bool CanUse(PortalFacts p, ViewerFacts v, Func<bool> sameGroup, Func<bool> sameGuild)
		{
			if (IsOwner(p, v) || v.IsAdmin)
			{
				return true;
			}
			return p.Mode switch
			{
				PortalMode.Public => true, 
				PortalMode.Group => sameGroup(), 
				PortalMode.Guild => sameGuild(), 
				_ => false, 
			};
		}

		public static bool CanEdit(PortalFacts p, ViewerFacts v, bool adminBypass, bool groupAccess, bool guildAccess, Func<bool> sameGroup, Func<bool> sameGuild)
		{
			if (string.IsNullOrEmpty(p.OwnerId))
			{
				return v.IsAdmin;
			}
			if (IsOwner(p, v))
			{
				return true;
			}
			if (v.IsAdmin && adminBypass)
			{
				return true;
			}
			if (p.Mode == PortalMode.Group)
			{
				return groupAccess && sameGroup();
			}
			if (p.Mode == PortalMode.Guild)
			{
				return guildAccess && sameGuild();
			}
			return false;
		}

		public static bool CanChangeMode(PortalFacts p, ViewerFacts v)
		{
			return IsOwner(p, v) || v.IsAdmin;
		}
	}
	internal static class ModeColors
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		public static Color Parse(string hex, Color fallback)
		{
			//IL_000d: 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)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(hex))
			{
				return fallback;
			}
			string text = hex.Trim();
			if (text.StartsWith("#"))
			{
				text = text.Substring(1);
			}
			if (text.Length != 6 && text.Length != 8)
			{
				return fallback;
			}
			string text2 = text;
			foreach (char c in text2)
			{
				if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F'))
				{
					return fallback;
				}
			}
			byte b = byte.Parse(text.Substring(0, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
			byte b2 = byte.Parse(text.Substring(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
			byte b3 = byte.Parse(text.Substring(4, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
			byte b4 = ((text.Length == 8) ? byte.Parse(text.Substring(6, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture) : byte.MaxValue);
			return new Color((float)(int)b / 255f, (float)(int)b2 / 255f, (float)(int)b3 / 255f, (float)(int)b4 / 255f);
		}

		public static Color Default(PortalMode mode)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			Color val = default(Color);
			((Color)(ref val))..ctor(1f, 1f, 1f, 1f);
			return (Color)(mode switch
			{
				PortalMode.Public => Parse("#FFC830", val), 
				PortalMode.Private => Parse("#3DA5FF", val), 
				PortalMode.Group => Parse("#40FF60", val), 
				PortalMode.Guild => Parse("#B040FF", val), 
				PortalMode.Admin => Parse("#FF4040", val), 
				_ => val, 
			});
		}
	}
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	internal static class FavoriteList
	{
		private const char Separator = ';';

		public static HashSet<string> Read(string stored)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			if (string.IsNullOrEmpty(stored))
			{
				return hashSet;
			}
			string[] array = stored.Split(new char[1] { ';' });
			foreach (string text in array)
			{
				string text2 = text.Trim();
				if (text2.Length > 0)
				{
					hashSet.Add(text2);
				}
			}
			return hashSet;
		}

		public static string Write(IEnumerable<string> keys)
		{
			if (keys == null)
			{
				return "";
			}
			IOrderedEnumerable<string> values = (from k in keys
				where !string.IsNullOrEmpty(k)
				select k.Trim() into k
				where k.Length > 0
				select k).Distinct<string>(StringComparer.Ordinal).OrderBy<string, string>([<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(0)] (string k) => k, StringComparer.Ordinal);
			return string.Join(';'.ToString(), values);
		}

		public static string Key(Vector3 position)
		{
			//IL_0009: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			return Axis(position.x) + "," + Axis(position.y) + "," + Axis(position.z);
		}

		public static IReadOnlyList<T> Favorites<[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)] T>(IEnumerable<T> items, Func<T, string> name, Func<T, bool> isFavorite)
		{
			if (items == null)
			{
				return new List<T>();
			}
			return items.Where(isFavorite).OrderBy<T, string>([<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(0)] (T item) => name(item) ?? "", StringComparer.InvariantCultureIgnoreCase).ThenBy<T, string>([<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(0)] (T item) => name(item) ?? "", StringComparer.Ordinal)
				.ToList();
		}

		private static string Axis(float value)
		{
			double num = Math.Round(value, 1, MidpointRounding.AwayFromZero);
			if (num == 0.0)
			{
				num = 0.0;
			}
			return num.ToString("F1", CultureInfo.InvariantCulture);
		}
	}
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	internal static class Identity
	{
		public static string Local
		{
			get
			{
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				IDistributionPlatform distributionPlatform = PlatformManager.DistributionPlatform;
				ILocalUser val = ((distributionPlatform != null) ? distributionPlatform.LocalUser : null);
				string text = ((val != null) ? ((object)((IUser)val).PlatformUserID/*cast due to .constrained prefix*/).ToString() : null);
				return text ?? "";
			}
		}

		[return: <7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		public static string SteamNumber(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				return null;
			}
			string text = (id.StartsWith("Steam_", StringComparison.Ordinal) ? id.Substring(6) : id);
			if (text.Length == 0)
			{
				return null;
			}
			string text2 = text;
			foreach (char c in text2)
			{
				if (c < '0' || c > '9')
				{
					return null;
				}
			}
			return text;
		}
	}
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	internal static class LimitTable
	{
		public static Dictionary<string, int> Parse(string yaml, List<string> warnings)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			if (string.IsNullOrWhiteSpace(yaml))
			{
				return dictionary;
			}
			List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
			try
			{
				Parser parser = new Parser(new StringReader(yaml));
				parser.Consume<YamlDotNet.Core.Events.StreamStart>();
				if (!parser.TryConsume<YamlDotNet.Core.Events.DocumentStart>(out var _))
				{
					return dictionary;
				}
				if (!parser.TryConsume<MappingStart>(out var _))
				{
					warnings.Add("PortalLimits.yml could not be read: the root is not a mapping");
					return dictionary;
				}
				MappingEnd event3;
				while (!parser.TryConsume<MappingEnd>(out event3))
				{
					string value = parser.Consume<YamlDotNet.Core.Events.Scalar>().Value;
					string value2 = "";
					if (parser.TryConsume<YamlDotNet.Core.Events.Scalar>(out var event4))
					{
						value2 = event4.Value;
					}
					else
					{
						SkipNode(parser);
					}
					list.Add(new KeyValuePair<string, string>(value, value2));
				}
			}
			catch (Exception ex)
			{
				warnings.Add("PortalLimits.yml could not be read: " + ex.Message);
				return new Dictionary<string, int>();
			}
			foreach (KeyValuePair<string, string> item in list)
			{
				string text = (item.Key ?? "").Trim();
				int result;
				if (!IsDigits(text))
				{
					warnings.Add("Invalid Steam ID in PortalLimits.yml: " + text);
				}
				else if (!int.TryParse((item.Value ?? "").Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out result) || result < 0)
				{
					warnings.Add("Invalid limit for " + text + " in PortalLimits.yml: " + item.Value);
				}
				else if (dictionary.ContainsKey(text))
				{
					warnings.Add("Duplicate Steam ID in PortalLimits.yml, later entry ignored: " + text);
				}
				else
				{
					dictionary[text] = result;
				}
			}
			return dictionary;
		}

		public static int LimitFor(string ownerId, int defaultLimit, IReadOnlyDictionary<string, int> table)
		{
			string text = Identity.SteamNumber(ownerId);
			if (text != null && table.TryGetValue(text, out var value))
			{
				return value;
			}
			return defaultLimit;
		}

		private static void SkipNode(Parser parser)
		{
			int num = 0;
			do
			{
				ParsingEvent parsingEvent = parser.Consume<ParsingEvent>();
				if (parsingEvent is SequenceStart || parsingEvent is MappingStart)
				{
					num++;
				}
				else if (parsingEvent is SequenceEnd || parsingEvent is MappingEnd)
				{
					num--;
				}
			}
			while (num > 0);
		}

		private static bool IsDigits(string text)
		{
			if (text.Length == 0)
			{
				return false;
			}
			foreach (char c in text)
			{
				if (c < '0' || c > '9')
				{
					return false;
				}
			}
			return true;
		}
	}
	internal static class LimitRules
	{
		public static bool CanPlace(int count, int limit, bool isAdmin)
		{
			return isAdmin || limit <= 0 || count < limit;
		}
	}
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	internal static class LimitSync
	{
		public static string Write([<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(new byte[] { 1, 1, 0 })] IReadOnlyDictionary<string, (int Count, int Limit)> data)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<string, (int, int)> datum in data)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('\n');
				}
				stringBuilder.Append(Uri.EscapeDataString(datum.Key)).Append('|').Append(datum.Value.Item1.ToString(CultureInfo.InvariantCulture))
					.Append('|')
					.Append(datum.Value.Item2.ToString(CultureInfo.InvariantCulture));
			}
			return stringBuilder.ToString();
		}

		[return: <7a806118-b484-4911-b895-cee4047d3ab8>Nullable(new byte[] { 1, 1, 0 })]
		public static Dictionary<string, (int Count, int Limit)> Read(string text)
		{
			Dictionary<string, (int, int)> dictionary = new Dictionary<string, (int, int)>();
			if (string.IsNullOrEmpty(text))
			{
				return dictionary;
			}
			string[] array = text.Split(new char[1] { '\n' });
			foreach (string text2 in array)
			{
				string[] array2 = text2.Split(new char[1] { '|' });
				if (array2.Length != 3)
				{
					return new Dictionary<string, (int, int)>();
				}
				if (!int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || !int.TryParse(array2[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2))
				{
					return new Dictionary<string, (int, int)>();
				}
				string text3;
				try
				{
					text3 = Uri.UnescapeDataString(array2[0]);
				}
				catch (Exception)
				{
					return new Dictionary<string, (int, int)>();
				}
				if (text3.Length == 0)
				{
					return new Dictionary<string, (int, int)>();
				}
				dictionary[text3] = (result, result2);
			}
			return dictionary;
		}
	}
	internal enum PortalMode
	{
		Public,
		Private,
		Group,
		Guild,
		Admin
	}
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	internal static class ModeRules
	{
		private static readonly PortalMode[] AllModes = new PortalMode[5]
		{
			PortalMode.Public,
			PortalMode.Private,
			PortalMode.Group,
			PortalMode.Guild,
			PortalMode.Admin
		};

		public static bool TryParse(string text, out PortalMode mode)
		{
			switch ((text ?? "").Trim().ToLowerInvariant())
			{
			case "public":
				mode = PortalMode.Public;
				return true;
			case "private":
				mode = PortalMode.Private;
				return true;
			case "group":
				mode = PortalMode.Group;
				return true;
			case "guild":
				mode = PortalMode.Guild;
				return true;
			case "admin":
				mode = PortalMode.Admin;
				return true;
			default:
				mode = PortalMode.Private;
				return false;
			}
		}

		public static bool IsValid(int value)
		{
			if ((uint)value <= 4u)
			{
				return true;
			}
			return false;
		}

		public static string Key(PortalMode mode)
		{
			return mode switch
			{
				PortalMode.Public => "public", 
				PortalMode.Private => "private", 
				PortalMode.Group => "group", 
				PortalMode.Guild => "guild", 
				PortalMode.Admin => "admin", 
				_ => "private", 
			};
		}

		public static IReadOnlyList<PortalMode> ParseList(string text)
		{
			List<PortalMode> list = new List<PortalMode>();
			if (string.IsNullOrWhiteSpace(text))
			{
				return list;
			}
			string[] array = text.Split(new char[1] { ',' });
			foreach (string text2 in array)
			{
				if (TryParse(text2, out var mode) && !list.Contains(mode))
				{
					list.Add(mode);
				}
			}
			return list;
		}

		private static List<PortalMode> Allowed(IReadOnlyList<PortalMode> playerModes, bool isAdmin, bool groupsLoaded, bool guildAvailable)
		{
			List<PortalMode> list = new List<PortalMode>();
			PortalMode[] allModes = AllModes;
			foreach (PortalMode portalMode in allModes)
			{
				if ((isAdmin || Contains(playerModes, portalMode)) && (portalMode != PortalMode.Group || groupsLoaded) && (portalMode != PortalMode.Guild || guildAvailable))
				{
					list.Add(portalMode);
				}
			}
			return list;
		}

		private static bool Contains(IReadOnlyList<PortalMode> modes, PortalMode mode)
		{
			for (int i = 0; i < modes.Count; i++)
			{
				if (modes[i] == mode)
				{
					return true;
				}
			}
			return false;
		}

		public static PortalMode Next(PortalMode current, IReadOnlyList<PortalMode> playerModes, bool isAdmin, bool groupsLoaded, bool guildAvailable)
		{
			List<PortalMode> list = Allowed(playerModes, isAdmin, groupsLoaded, guildAvailable);
			if (list.Count == 0)
			{
				return current;
			}
			foreach (PortalMode item in list)
			{
				if (item > current)
				{
					return item;
				}
			}
			return list[0];
		}

		public static PortalMode Initial(PortalMode configured, IReadOnlyList<PortalMode> playerModes, bool isAdmin, bool groupsLoaded, bool guildAvailable)
		{
			List<PortalMode> list = Allowed(playerModes, isAdmin, groupsLoaded, guildAvailable);
			if (list.Contains(configured))
			{
				return configured;
			}
			return (list.Count <= 0) ? PortalMode.Private : list[0];
		}
	}
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	internal static class PngImage
	{
		private static readonly byte[] Signature = new byte[8] { 137, 80, 78, 71, 13, 10, 26, 10 };

		public static bool TryDecode(byte[] data, out int width, out int height, out Color32[] pixels)
		{
			width = 0;
			height = 0;
			pixels = Array.Empty<Color32>();
			try
			{
				return Decode(data, ref width, ref height, ref pixels);
			}
			catch (Exception)
			{
				width = 0;
				height = 0;
				pixels = Array.Empty<Color32>();
				return false;
			}
		}

		private static bool Decode(byte[] data, ref int width, ref int height, ref Color32[] pixels)
		{
			//IL_03ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ef: Unknown result type (might be due to invalid IL or missing references)
			if (data == null || data.Length < Signature.Length + 12)
			{
				return false;
			}
			for (int i = 0; i < Signature.Length; i++)
			{
				if (data[i] != Signature[i])
				{
					return false;
				}
			}
			int num = 0;
			MemoryStream memoryStream = new MemoryStream();
			int num2;
			for (int j = Signature.Length; j + 12 <= data.Length; j += 12 + num2)
			{
				num2 = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | data[j + 3];
				if (num2 < 0 || j + 12 + num2 > data.Length)
				{
					return false;
				}
				string text = new string(new char[4]
				{
					(char)data[j + 4],
					(char)data[j + 5],
					(char)data[j + 6],
					(char)data[j + 7]
				});
				int num3 = j + 8;
				switch (text)
				{
				case "IHDR":
				{
					if (num2 < 13)
					{
						return false;
					}
					width = (data[num3] << 24) | (data[num3 + 1] << 16) | (data[num3 + 2] << 8) | data[num3 + 3];
					height = (data[num3 + 4] << 24) | (data[num3 + 5] << 16) | (data[num3 + 6] << 8) | data[num3 + 7];
					byte b = data[num3 + 8];
					byte b2 = data[num3 + 9];
					byte b3 = data[num3 + 12];
					if (b != 8 || b3 != 0)
					{
						return false;
					}
					switch (b2)
					{
					case 6:
						num = 4;
						break;
					case 2:
						num = 3;
						break;
					default:
						return false;
					}
					continue;
				}
				case "IDAT":
					memoryStream.Write(data, num3, num2);
					continue;
				default:
					continue;
				case "IEND":
					break;
				}
				break;
			}
			if (num == 0 || width <= 0 || height <= 0 || memoryStream.Length < 2)
			{
				return false;
			}
			int num4 = width * num;
			byte[] array = new byte[(num4 + 1) * height];
			memoryStream.Position = 2L;
			using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Decompress))
			{
				int num5;
				for (int k = 0; k < array.Length; k += num5)
				{
					num5 = deflateStream.Read(array, k, array.Length - k);
					if (num5 <= 0)
					{
						return false;
					}
				}
			}
			byte[] array2 = new byte[num4];
			byte[] array3 = new byte[num4];
			Color32[] array4 = (Color32[])(object)new Color32[width * height];
			for (int l = 0; l < height; l++)
			{
				int num6 = l * (num4 + 1);
				byte b4 = array[num6];
				for (int m = 0; m < num4; m++)
				{
					int num7 = array[num6 + 1 + m];
					int num8 = ((m >= num) ? array3[m - num] : 0);
					int num9 = array2[m];
					int upLeft = ((m >= num) ? array2[m - num] : 0);
					switch (b4)
					{
					case 1:
						num7 += num8;
						break;
					case 2:
						num7 += num9;
						break;
					case 3:
						num7 += num8 + num9 >> 1;
						break;
					case 4:
						num7 += Paeth(num8, num9, upLeft);
						break;
					default:
						return false;
					case 0:
						break;
					}
					array3[m] = (byte)num7;
				}
				int num10 = (height - 1 - l) * width;
				for (int n = 0; n < width; n++)
				{
					int num11 = n * num;
					byte b5 = ((num == 4) ? array3[num11 + 3] : byte.MaxValue);
					array4[num10 + n] = new Color32(array3[num11], array3[num11 + 1], array3[num11 + 2], b5);
				}
				byte[] array5 = array2;
				array2 = array3;
				array3 = array5;
			}
			pixels = array4;
			return true;
		}

		private static int Paeth(int left, int up, int upLeft)
		{
			int num = left + up - upLeft;
			int num2 = Math.Abs(num - left);
			int num3 = Math.Abs(num - up);
			int num4 = Math.Abs(num - upLeft);
			if (num2 <= num3 && num2 <= num4)
			{
				return left;
			}
			if (num3 <= num4)
			{
				return up;
			}
			return upLeft;
		}
	}
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	internal sealed class RevisionTracker<TKey>
	{
		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(new byte[] { 1, 1, 0 })]
		private readonly Dictionary<TKey, (uint Data, ushort Owner)> _seen = new Dictionary<TKey, (uint, ushort)>();

		public int Count => _seen.Count;

		public bool Changed(TKey key, uint dataRevision, ushort ownerRevision)
		{
			(uint, ushort) tuple = (dataRevision, ownerRevision);
			if (_seen.TryGetValue(key, out (uint, ushort) value))
			{
				var (num, num2) = value;
				var (num3, num4) = tuple;
				if (num == num3 && num2 == num4)
				{
					return false;
				}
			}
			_seen[key] = tuple;
			return true;
		}

		public void Prune(ICollection<TKey> present)
		{
			if (_seen.Count == 0)
			{
				return;
			}
			List<TKey> list = new List<TKey>();
			foreach (TKey key in _seen.Keys)
			{
				if (!present.Contains(key))
				{
					list.Add(key);
				}
			}
			foreach (TKey item in list)
			{
				_seen.Remove(item);
			}
		}

		public void Remove(TKey key)
		{
			_seen.Remove(key);
		}

		public void Clear()
		{
			_seen.Clear();
		}
	}
	internal static class LimitClient
	{
		private static int _pending;

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(1)]
		private static string _lastText = "";

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(new byte[] { 1, 1, 0 })]
		private static Dictionary<string, (int Count, int Limit)> _data = new Dictionary<string, (int, int)>();

		public static void Reset()
		{
			_pending = 0;
			_lastText = "";
			_data = new Dictionary<string, (int, int)>();
		}

		public static void AddPending()
		{
			_pending++;
		}

		public static (int Count, int Limit) Mine()
		{
			string text = LimitServer.Published.Value ?? "";
			if (!string.Equals(text, _lastText, StringComparison.Ordinal))
			{
				_lastText = text;
				int num;
				if (_data.TryGetValue(Identity.Local, out (int, int) value))
				{
					(num, _) = value;
				}
				else
				{
					num = -1;
				}
				int num2 = num;
				_data = LimitSync.Read(text);
				int num3;
				if (_data.TryGetValue(Identity.Local, out (int, int) value2))
				{
					(num3, _) = value2;
				}
				else
				{
					num3 = -1;
				}
				int num4 = num3;
				if (num2 != num4)
				{
					_pending = 0;
				}
			}
			int value3 = VikingsPortalsPlugin.LimitPerAccount.Value;
			if (!_data.TryGetValue(Identity.Local, out (int, int) value4))
			{
				return (Count: _pending, Limit: value3);
			}
			return (Count: value4.Item1 + _pending, Limit: value4.Item2);
		}
	}
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	[HarmonyPatch(typeof(Player), "TryPlacePiece", new Type[] { typeof(Piece) })]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	internal static class Player_TryPlacePiece_Limits
	{
		private static bool Prefix(Piece piece, ref bool __result)
		{
			if ((Object)(object)piece == (Object)null || (Object)(object)((Component)piece).GetComponent<TeleportWorld>() == (Object)null)
			{
				return true;
			}
			if (VikingsPortalsPlugin.IsLocalAdmin())
			{
				return true;
			}
			if (!LimitRules.CanPlace(PortalRegistry.Count, VikingsPortalsPlugin.LimitWorld.Value, isAdmin: false))
			{
				PortalProtection.Notify("$vportals_world_limit");
				__result = false;
				return false;
			}
			(int, int) tuple = LimitClient.Mine();
			if (!LimitRules.CanPlace(tuple.Item1, tuple.Item2, isAdmin: false))
			{
				string token = Localization.instance.Localize("$vportals_account_limit", new string[1] { tuple.Item2.ToString(CultureInfo.InvariantCulture) });
				PortalProtection.Notify(token);
				__result = false;
				return false;
			}
			return true;
		}

		private static void Postfix(Piece piece, bool __result)
		{
			if (__result && (Object)(object)piece != (Object)null && (Object)(object)((Component)piece).GetComponent<TeleportWorld>() != (Object)null)
			{
				LimitClient.AddPending();
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Awake")]
	internal static class ZNet_Awake_ResetLimitClient
	{
		private static void Postfix()
		{
			LimitClient.Reset();
		}
	}
	[HarmonyPatch(typeof(ZNet), "Shutdown")]
	internal static class ZNet_Shutdown_ResetLimitClient
	{
		private static void Postfix()
		{
			LimitClient.Reset();
		}
	}
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	internal static class LimitServer
	{
		public const string SyncKey = "VPortals_Limits";

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(new byte[] { 2, 1 })]
		private static CustomSyncedValue<string> _published;

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		private static FileSystemWatcher _watcher;

		private static Dictionary<string, int> _table = new Dictionary<string, int>();

		private static string _path = "";

		private static long _lastWrite;

		private static bool _reloadScheduled;

		private static bool _started;

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		private static string _lastPublished;

		public static CustomSyncedValue<string> Published
		{
			get
			{
				if (_published == null)
				{
					_published = new CustomSyncedValue<string>(VikingsPortalsPlugin.Sync, "VPortals_Limits", "");
				}
				return _published;
			}
		}

		public static void Start()
		{
			Stop();
			_started = true;
			_lastPublished = null;
			string text = Path.Combine(Paths.ConfigPath, "VikingsPortals");
			_path = Path.Combine(text, "PortalLimits.yml");
			try
			{
				Directory.CreateDirectory(text);
				if (!File.Exists(_path))
				{
					File.WriteAllText(_path, "");
				}
			}
			catch (Exception ex)
			{
				VikingsPortalsPlugin.Log.LogWarning((object)("PortalLimits.yml could not be created: " + ex.Message));
			}
			Load();
			StartWatcher(text);
			PortalRegistry.Changed += Publish;
			VikingsPortalsPlugin.LimitPerAccount.SettingChanged += OnSettingChanged;
			Publish();
			((MonoBehaviour)ZNet.instance).StartCoroutine(RecountLoop());
		}

		private static IEnumerator RecountLoop()
		{
			while (_started)
			{
				yield return (object)new WaitForSeconds(5f);
				if (_started)
				{
					Publish();
				}
			}
		}

		public static void Stop()
		{
			if (!_started)
			{
				return;
			}
			_started = false;
			PortalRegistry.Changed -= Publish;
			VikingsPortalsPlugin.LimitPerAccount.SettingChanged -= OnSettingChanged;
			if (_watcher != null)
			{
				try
				{
					_watcher.EnableRaisingEvents = false;
					_watcher.Dispose();
				}
				catch (Exception)
				{
				}
				_watcher = null;
			}
			_reloadScheduled = false;
		}

		private static void OnSettingChanged(object sender, EventArgs args)
		{
			Publish();
		}

		private static void StartWatcher(string folder)
		{
			try
			{
				_watcher = new FileSystemWatcher(folder, "PortalLimits.yml")
				{
					IncludeSubdirectories = false,
					NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite),
					SynchronizingObject = ThreadingHelper.SynchronizingObject
				};
				_watcher.Changed += OnFileChanged;
				_watcher.Created += OnFileChanged;
				_watcher.Renamed += [<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(0)] (object sender, RenamedEventArgs args) =>
				{
					OnFileChanged(sender, args);
				};
				_watcher.EnableRaisingEvents = true;
			}
			catch (Exception ex)
			{
				_watcher?.Dispose();
				_watcher = null;
				VikingsPortalsPlugin.Log.LogWarning((object)("Automatic PortalLimits.yml reload is unavailable: " + ex.Message));
			}
		}

		private static void OnFileChanged(object sender, FileSystemEventArgs args)
		{
			_lastWrite = Stopwatch.GetTimestamp();
			if (!_reloadScheduled && !((Object)(object)ZNet.instance == (Object)null))
			{
				_reloadScheduled = true;
				((MonoBehaviour)ZNet.instance).StartCoroutine(ReloadAfterQuietPeriod());
			}
		}

		private static IEnumerator ReloadAfterQuietPeriod()
		{
			try
			{
				while (_started && (double)(Stopwatch.GetTimestamp() - _lastWrite) / (double)Stopwatch.Frequency < 0.75)
				{
					yield return null;
				}
				if (_started)
				{
					Load();
					Publish();
				}
			}
			finally
			{
				_reloadScheduled = false;
			}
		}

		private static void Load()
		{
			List<string> list = new List<string>();
			string yaml = "";
			try
			{
				if (File.Exists(_path))
				{
					yaml = File.ReadAllText(_path);
				}
			}
			catch (Exception ex)
			{
				VikingsPortalsPlugin.Log.LogWarning((object)("PortalLimits.yml could not be read: " + ex.Message));
				return;
			}
			_table = LimitTable.Parse(yaml, list);
			foreach (string item in list)
			{
				VikingsPortalsPlugin.Log.LogWarning((object)item);
			}
		}

		private static void Publish()
		{
			int value = VikingsPortalsPlugin.LimitPerAccount.Value;
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			foreach (ZDO item in PortalRegistry.All)
			{
				string text = item.GetString("VPortals_OwnerId", "");
				if (text.Length != 0)
				{
					dictionary.TryGetValue(text, out var value2);
					dictionary[text] = value2 + 1;
				}
			}
			Dictionary<string, (int, int)> dictionary2 = new Dictionary<string, (int, int)>();
			foreach (KeyValuePair<string, int> item2 in dictionary)
			{
				dictionary2[item2.Key] = (item2.Value, LimitTable.LimitFor(item2.Key, value, _table));
			}
			foreach (KeyValuePair<string, int> item3 in _table)
			{
				string key = "Steam_" + item3.Key;
				if (!dictionary2.ContainsKey(key))
				{
					dictionary2[key] = (0, item3.Value);
				}
			}
			string text2 = LimitSync.Write(dictionary2);
			if (!string.Equals(text2, _lastPublished, StringComparison.Ordinal))
			{
				_lastPublished = text2;
				Published.Value = text2;
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Awake")]
	internal static class ZNet_Awake_StartLimits
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static void Postfix(ZNet __instance)
		{
			if (__instance.IsServer())
			{
				LimitServer.Start();
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Shutdown")]
	internal static class ZNet_Shutdown_StopLimits
	{
		private static void Prefix()
		{
			LimitServer.Stop();
		}
	}
	internal class PortalExitWatcher : MonoBehaviour
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private void OnTriggerExit(Collider other)
		{
			if (!PortalSelection.Active || (Object)(object)other == (Object)null)
			{
				return;
			}
			Player component = ((Component)other).GetComponent<Player>();
			if ((Object)(object)component == (Object)null || (Object)(object)component != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			ZDO source = PortalSelection.Source;
			if (source != null)
			{
				ZNetView componentInParent = ((Component)this).GetComponentInParent<ZNetView>();
				ZDO val = (((Object)(object)componentInParent != (Object)null && componentInParent.IsValid()) ? componentInParent.GetZDO() : null);
				if (val != source)
				{
					return;
				}
			}
			if ((Object)(object)Minimap.instance != (Object)null)
			{
				Minimap.instance.SetMapMode((MapMode)1);
			}
			PortalSelection.End();
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ZNetScene_Awake_PortalExitWatcher
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		[HarmonyPriority(0)]
		private static void Postfix(ZNetScene __instance)
		{
			foreach (GameObject prefab in __instance.m_prefabs)
			{
				if (!((Object)(object)prefab == (Object)null) && !((Object)(object)prefab.GetComponent<TeleportWorld>() == (Object)null))
				{
					Transform val = prefab.transform.Find("TELEPORT");
					if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).GetComponent<PortalExitWatcher>() != (Object)null))
					{
						((Component)val).gameObject.AddComponent<PortalExitWatcher>();
					}
				}
			}
		}
	}
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	internal static class PortalFavorites
	{
		public const string DataKey = "VPortals_Favorites";

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		[method: <596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(2)]
		[field: <7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		public static event Action Changed;

		public static HashSet<string> Current()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || localPlayer.m_customData == null)
			{
				return new HashSet<string>(StringComparer.Ordinal);
			}
			localPlayer.m_customData.TryGetValue("VPortals_Favorites", out var value);
			return FavoriteList.Read(value ?? "");
		}

		public static bool IsFavorite(HashSet<string> favorites, ZDO portal)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return portal != null && favorites.Contains(FavoriteList.Key(portal.GetPosition()));
		}

		public static void Toggle(ZDO portal)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && localPlayer.m_customData != null && portal != null && portal.IsValid())
			{
				HashSet<string> hashSet = Current();
				string item = FavoriteList.Key(portal.GetPosition());
				if (!hashSet.Remove(item))
				{
					hashSet.Add(item);
				}
				string text = FavoriteList.Write(hashSet);
				if (text.Length == 0)
				{
					localPlayer.m_customData.Remove("VPortals_Favorites");
				}
				else
				{
					localPlayer.m_customData["VPortals_Favorites"] = text;
				}
				PortalFavorites.Changed?.Invoke();
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "Update")]
	internal static class Minimap_Update_FavoritesPanel
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static void Postfix(Minimap __instance)
		{
			FavoritesPanel.Refresh(__instance);
		}
	}
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	internal static class FavoritesPanel
	{
		private static readonly Color PanelColor = new Color(0f, 0f, 0f, 0.75f);

		private static readonly Color RowColor = new Color(1f, 1f, 1f, 0.05f);

		private static readonly Color RowHoverColor = new Color(1f, 1f, 1f, 0.15f);

		private static readonly Color FavoriteColor = new Color(1f, 0.82f, 0.3f, 1f);

		private static readonly List<FavoritesPanelRow> Rows = new List<FavoritesPanelRow>();

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		private static GameObject _root;

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		private static RectTransform _content;

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		private static TMP_FontAsset _font;

		private static bool _subscribed;

		private static bool _dirty = true;

		private static bool _visible;

		private static int _count;

		public static bool PointerOver()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			if ((Object)(object)_root == (Object)null || !_root.activeInHierarchy)
			{
				return false;
			}
			return RectTransformUtility.RectangleContainsScreenPoint((RectTransform)_root.transform, Vector2.op_Implicit(ZInput.pointerPosition), (Camera)null);
		}

		public static void Refresh(Minimap minimap)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			if (!((Object)(object)Player.m_localPlayer != (Object)null) || (int)minimap.m_mode != 2 || PortalPins.Shown.Count <= 0)
			{
				_visible = false;
				if ((Object)(object)_root != (Object)null && _root.activeSelf)
				{
					_root.SetActive(false);
				}
			}
			else if (Ensure(minimap) && !((Object)(object)_root == (Object)null))
			{
				if (!_visible)
				{
					_visible = true;
					_dirty = true;
				}
				if (_dirty)
				{
					Rebuild();
				}
				bool flag = _count > 0;
				if (_root.activeSelf != flag)
				{
					_root.SetActive(flag);
				}
			}
		}

		internal static void MarkDirty()
		{
			_dirty = true;
		}

		private static void Rebuild()
		{
			_dirty = false;
			if ((Object)(object)_content == (Object)null)
			{
				return;
			}
			HashSet<string> favorites = PortalFavorites.Current();
			IReadOnlyList<KeyValuePair<PinData, ZDO>> readOnlyList = FavoriteList.Favorites(PortalPins.Shown, [<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(0)] [return: <7a806118-b484-4911-b895-cee4047d3ab8>Nullable(1)] (KeyValuePair<PinData, ZDO> pair) => pair.Key.m_name, [<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(0)] (KeyValuePair<PinData, ZDO> pair) => PortalFavorites.IsFavorite(favorites, pair.Value));
			for (int num = 0; num < readOnlyList.Count; num++)
			{
				if (num >= Rows.Count)
				{
					Rows.Add(CreateRow((Transform)(object)_content));
				}
				KeyValuePair<PinData, ZDO> keyValuePair = readOnlyList[num];
				Rows[num].Show(keyValuePair.Key, keyValuePair.Value);
			}
			for (int num2 = readOnlyList.Count; num2 < Rows.Count; num2++)
			{
				Rows[num2].Hide();
			}
			_count = readOnlyList.Count;
		}

		private static bool Ensure(Minimap minimap)
		{
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Expected O, but got Unknown
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: 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)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Expected O, but got Unknown
			if ((Object)(object)_root != (Object)null)
			{
				return true;
			}
			if ((Object)(object)minimap.m_largeRoot == (Object)null || Localization.instance == null)
			{
				return false;
			}
			Rows.Clear();
			if (!_subscribed)
			{
				_subscribed = true;
				PortalPins.PinsChanged += MarkDirty;
				PortalFavorites.Changed += MarkDirty;
			}
			_font = (((Object)(object)minimap.m_biomeNameLarge != (Object)null) ? minimap.m_biomeNameLarge.font : null);
			_root = new GameObject("VPortals_FavoritesPanel", new Type[1] { typeof(RectTransform) });
			_root.SetActive(false);
			_root.transform.SetParent(minimap.m_largeRoot.transform, false);
			_root.transform.SetAsLastSibling();
			RectTransform val = (RectTransform)_root.transform;
			val.anchorMin = new Vector2(0f, 0.5f);
			val.anchorMax = new Vector2(0f, 0.5f);
			val.pivot = new Vector2(0f, 0.5f);
			val.anchoredPosition = new Vector2(30f, 0f);
			val.sizeDelta = new Vector2(320f, 560f);
			Image val2 = _root.AddComponent<Image>();
			((Graphic)val2).color = PanelColor;
			((Graphic)val2).raycastTarget = true;
			VerticalLayoutGroup val3 = _root.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)val3).padding = new RectOffset(10, 10, 10, 10);
			((HorizontalOrVerticalLayoutGroup)val3).spacing = 8f;
			((HorizontalOrVerticalLayoutGroup)val3).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)val3).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)val3).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)val3).childForceExpandHeight = false;
			TextMeshProUGUI val4 = CreateText(_root.transform, "Title", 22f);
			((TMP_Text)val4).text = Localization.instance.Localize("$vportals_favorites");
			((TMP_Text)val4).fontStyle = (FontStyles)1;
			((TMP_Text)val4).alignment = (TextAlignmentOptions)514;
			Fixed(((Component)val4).gameObject, 30f);
			_content = CreateList(_root.transform);
			_dirty = true;
			return true;
		}

		private static RectTransform CreateList(Transform parent)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Expected O, but got Unknown
			GameObject val = new GameObject("List", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			LayoutElement val2 = val.AddComponent<LayoutElement>();
			val2.flexibleHeight = 1f;
			Image val3 = val.AddComponent<Image>();
			((Graphic)val3).color = new Color(0f, 0f, 0f, 0.01f);
			val.AddComponent<RectMask2D>();
			GameObject val4 = new GameObject("Content", new Type[1] { typeof(RectTransform) });
			val4.transform.SetParent(val.transform, false);
			RectTransform val5 = (RectTransform)val4.transform;
			val5.anchorMin = new Vector2(0f, 1f);
			val5.anchorMax = new Vector2(1f, 1f);
			val5.pivot = new Vector2(0.5f, 1f);
			val5.offsetMin = Vector2.zero;
			val5.offsetMax = Vector2.zero;
			VerticalLayoutGroup val6 = val4.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)val6).spacing = 2f;
			((HorizontalOrVerticalLayoutGroup)val6).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)val6).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)val6).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)val6).childForceExpandHeight = false;
			ContentSizeFitter val7 = val4.AddComponent<ContentSizeFitter>();
			val7.verticalFit = (FitMode)2;
			ScrollRect val8 = val.AddComponent<ScrollRect>();
			val8.viewport = (RectTransform)val.transform;
			val8.content = val5;
			val8.horizontal = false;
			val8.vertical = true;
			val8.movementType = (MovementType)2;
			val8.scrollSensitivity = 30f;
			return val5;
		}

		private static FavoritesPanelRow CreateRow(Transform parent)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0035: 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_0056: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Row", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			Image val2 = val.AddComponent<Image>();
			((Graphic)val2).color = RowColor;
			HorizontalLayoutGroup val3 = val.AddComponent<HorizontalLayoutGroup>();
			((LayoutGroup)val3).padding = new RectOffset(6, 6, 3, 3);
			((HorizontalOrVerticalLayoutGroup)val3).spacing = 8f;
			((LayoutGroup)val3).childAlignment = (TextAnchor)3;
			((HorizontalOrVerticalLayoutGroup)val3).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)val3).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)val3).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)val3).childForceExpandHeight = false;
			Fixed(val, 30f);
			GameObject val4 = new GameObject("Icon", new Type[1] { typeof(RectTransform) });
			val4.transform.SetParent(val.transform, false);
			Image val5 = val4.AddComponent<Image>();
			val5.sprite = PortalPins.Icon;
			val5.preserveAspect = true;
			((Graphic)val5).raycastTarget = false;
			LayoutElement val6 = val4.AddComponent<LayoutElement>();
			val6.preferredWidth = 24f;
			val6.preferredHeight = 24f;
			val6.minWidth = 24f;
			val6.minHeight = 24f;
			TextMeshProUGUI val7 = CreateText(val.transform, "Name", 18f);
			((TMP_Text)val7).alignment = (TextAlignmentOptions)4097;
			((TMP_Text)val7).overflowMode = (TextOverflowModes)1;
			((TMP_Text)val7).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)val7).richText = false;
			((Component)val7).gameObject.AddComponent<LayoutElement>().flexibleWidth = 1f;
			FavoritesPanelRow favoritesPanelRow = val.AddComponent<FavoritesPanelRow>();
			favoritesPanelRow.Setup(val2, val7, RowColor, RowHoverColor, FavoriteColor);
			return favoritesPanelRow;
		}

		private static TextMeshProUGUI CreateText(Transform parent, string name, float size)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
			if ((Object)(object)_font != (Object)null)
			{
				((TMP_Text)val2).font = _font;
			}
			((TMP_Text)val2).fontSize = size;
			((Graphic)val2).color = Color.white;
			((Graphic)val2).raycastTarget = false;
			return val2;
		}

		private static void Fixed(GameObject go, float height)
		{
			LayoutElement val = go.GetComponent<LayoutElement>();
			if ((Object)(object)val == (Object)null)
			{
				val = go.AddComponent<LayoutElement>();
			}
			val.minHeight = height;
			val.preferredHeight = height;
		}
	}
	internal class FavoritesPanelRow : MonoBehaviour, IPointerClickHandler, IEventSystemHandler, IPointerEnterHandler, IPointerExitHandler
	{
		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		private Image _background;

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		private TextMeshProUGUI _label;

		private Color _normal;

		private Color _hover;

		private Color _favorite;

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		private PinData _pin;

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		private ZDO _portal;

		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		public void Setup(Image background, TextMeshProUGUI label, Color normal, Color hover, Color favorite)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0021: Unknown result type (might be due to invalid IL or missing references)
			_background = background;
			_label = label;
			_normal = normal;
			_hover = hover;
			_favorite = favorite;
		}

		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		public void Show(PinData pin, ZDO portal)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			_pin = pin;
			_portal = portal;
			if ((Object)(object)_label != (Object)null)
			{
				((TMP_Text)_label).text = (string.IsNullOrEmpty(pin.m_name) ? "?" : pin.m_name);
				((Graphic)_label).color = _favorite;
			}
			if ((Object)(object)_background != (Object)null)
			{
				((Graphic)_background).color = _normal;
			}
			if (!((Component)this).gameObject.activeSelf)
			{
				((Component)this).gameObject.SetActive(true);
			}
		}

		public void Hide()
		{
			_pin = null;
			_portal = null;
			if (((Component)this).gameObject.activeSelf)
			{
				((Component)this).gameObject.SetActive(false);
			}
		}

		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		public void OnPointerClick(PointerEventData eventData)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Invalid comparison between Unknown and I4
			if (_pin == null || _portal == null)
			{
				return;
			}
			if ((int)eventData.button == 0)
			{
				if (PortalSelection.Active)
				{
					PortalSelection.TryTeleport(_portal, _pin);
				}
			}
			else if ((int)eventData.button == 1)
			{
				PortalFavorites.Toggle(_portal);
			}
		}

		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		public void OnPointerEnter(PointerEventData eventData)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_background != (Object)null)
			{
				((Graphic)_background).color = _hover;
			}
		}

		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		public void OnPointerExit(PointerEventData eventData)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_background != (Object)null)
			{
				((Graphic)_background).color = _normal;
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "UpdateMap")]
	internal static class Minimap_UpdateMap_PanelWheel
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static void Prefix(Minimap __instance, ref bool takeInput)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			if (takeInput && (int)__instance.m_mode == 2 && FavoritesPanel.PointerOver())
			{
				takeInput = false;
			}
		}
	}
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(2)]
	internal static class PortalPins
	{
		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(1)]
		public const string IconResource = "VikingsPortals.assets.portal_icon.png";

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(1)]
		private static readonly Dictionary<PinData, ZDO> ShownPins = new Dictionary<PinData, ZDO>();

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(1)]
		private static readonly Dictionary<ZDO, PinData> PinsByPortal = new Dictionary<ZDO, PinData>();

		private static Sprite _icon;

		private static bool _dirty;

		public static int PinType { get; private set; } = -1;

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(1)]
		public static IReadOnlyDictionary<PinData, ZDO> Shown
		{
			[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
			get
			{
				return ShownPins;
			}
		}

		public static bool Visible { get; private set; }

		internal static bool[] IconTypes { get; private set; }

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(new byte[] { 2, 1 })]
		[field: <7a806118-b484-4911-b895-cee4047d3ab8>Nullable(new byte[] { 2, 1 })]
		internal static List<PinData> AllPins
		{
			[return: <7a806118-b484-4911-b895-cee4047d3ab8>Nullable(new byte[] { 2, 1 })]
			get;
			[param: <7a806118-b484-4911-b895-cee4047d3ab8>Nullable(new byte[] { 2, 1 })]
			private set;
		}

		internal static Sprite Icon
		{
			get
			{
				if ((Object)(object)_icon == (Object)null)
				{
					_icon = LoadIcon();
				}
				return _icon;
			}
		}

		public static event Action PinsChanged;

		public static void Refresh()
		{
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			Minimap instance = Minimap.instance;
			if ((Object)(object)instance == (Object)null || PinType < 0)
			{
				return;
			}
			Dictionary<ZDO, string> dictionary = new Dictionary<ZDO, string>();
			foreach (ZDO item in PortalRegistry.All)
			{
				if (item != null && item.IsValid() && PortalRecord.LocalCanUse(item))
				{
					dictionary[item] = item.GetString(ZDOVars.s_tag, "");
				}
			}
			bool flag = false;
			List<ZDO> list = new List<ZDO>();
			foreach (KeyValuePair<ZDO, PinData> item2 in PinsByPortal)
			{
				if (!dictionary.TryGetValue(item2.Key, out var value) || item2.Value.m_name != value || item2.Value.m_pos != item2.Key.GetPosition())
				{
					list.Add(item2.Key);
				}
			}
			foreach (ZDO item3 in list)
			{
				PinData val = PinsByPortal[item3];
				instance.RemovePin(val);
				ShownPins.Remove(val);
				PinsByPortal.Remove(item3);
				flag = true;
			}
			foreach (KeyValuePair<ZDO, string> item4 in dictionary)
			{
				if (!PinsByPortal.ContainsKey(item4.Key))
				{
					PinData val2 = instance.AddPin(item4.Key.GetPosition(), (PinType)PinType, item4.Value, false, false, 0L, default(PlatformUserID));
					ShownPins[val2] = item4.Key;
					PinsByPortal[item4.Key] = val2;
					flag = true;
				}
			}
			if (flag)
			{
				PortalPins.PinsChanged?.Invoke();
			}
		}

		public static void Clear()
		{
			Minimap instance = Minimap.instance;
			bool flag = ShownPins.Count > 0;
			if ((Object)(object)instance != (Object)null)
			{
				foreach (PinData key in ShownPins.Keys)
				{
					instance.RemovePin(key);
				}
			}
			ShownPins.Clear();
			PinsByPortal.Clear();
			if (flag)
			{
				PortalPins.PinsChanged?.Invoke();
			}
		}

		public static void ToggleVisible()
		{
			Visible = !Visible;
			if (!PortalSelection.Active)
			{
				if (Visible)
				{
					Refresh();
				}
				else
				{
					Clear();
				}
			}
		}

		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		internal static void Register(Minimap minimap, ref bool[] visibleIconTypes, List<PinData> pins)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			ShownPins.Clear();
			PinsByPortal.Clear();
			PortalSelection.Reset();
			int num = visibleIconTypes.Length;
			bool[] array = new bool[num + 1];
			Array.Copy(visibleIconTypes, array, num);
			array[num] = true;
			visibleIconTypes = array;
			minimap.m_icons.Add(new SpriteData
			{
				m_name = (PinType)num,
				m_icon = Icon
			});
			PinType = num;
			IconTypes = array;
			AllPins = pins;
			((MonoBehaviour)minimap).StartCoroutine(RefreshLoop());
		}

		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		internal static void Track(bool[] visibleIconTypes, List<PinData> pins)
		{
			IconTypes = visibleIconTypes;
			AllPins = pins;
		}

		internal static void MarkDirty()
		{
			_dirty = true;
		}

		internal static bool ConsumeDirty()
		{
			if (!_dirty)
			{
				return false;
			}
			_dirty = false;
			return true;
		}

		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		[return: <7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		internal static PinData PinNear(Minimap minimap, Vector3 screenPoint)
		{
			//IL_001d: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			if (ShownPins.Count == 0)
			{
				return null;
			}
			if (!ScreenToWorld(minimap, screenPoint, out var world))
			{
				return null;
			}
			float num = minimap.m_removeRadius * minimap.LargeZoom * 2f;
			PinData result = null;
			float num2 = float.MaxValue;
			foreach (PinData key in ShownPins.Keys)
			{
				if (!((Object)(object)key.m_uiElement == (Object)null) && ((Component)key.m_uiElement).gameObject.activeInHierarchy)
				{
					float num3 = Utils.DistanceXZ(world, key.m_pos);
					if (num3 < num && num3 < num2)
					{
						result = key;
						num2 = num3;
					}
				}
			}
			return result;
		}

		internal static bool KeyDown()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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)
			KeyboardShortcut value = VikingsPortalsPlugin.MapPinsKey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0)
			{
				return false;
			}
			if (!ZInput.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey, false))
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
			{
				if (!ZInput.GetKey(modifier, false))
				{
					return false;
				}
			}
			return true;
		}

		internal static bool TakesInput()
		{
			if (GameCamera.InFreeFly())
			{
				return false;
			}
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return false;
			}
			if (Menu.IsVisible() || Console.IsVisible() || TextInput.IsVisible() || Minimap.InTextInput())
			{
				return false;
			}
			if ((Object)(object)Hud.instance != (Object)null && (Object)(object)Hud.instance.m_buildUi != (Object)null && Hud.instance.m_buildUi.SearchFieldFocused)
			{
				return false;
			}
			if (ZInput.IsGamepadActive() && (Minimap.IsOpen() || InventoryGui.IsVisible() || StoreGui.IsVisible() || Hud.IsPieceSelectionVisible()))
			{
				return false;
			}
			return !PlayerCustomizaton.IsBarberGuiVisible();
		}

		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static bool ScreenToWorld(Minimap minimap, Vector3 screenPoint, out Vector3 world)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: 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_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)
			world = Vector3.zero;
			RawImage mapImageLarge = minimap.m_mapImageLarge;
			if ((Object)(object)mapImageLarge == (Object)null)
			{
				return false;
			}
			RectTransform rectTransform = ((Graphic)mapImageLarge).rectTransform;
			Vector2 val = default(Vector2);
			if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, Vector2.op_Implicit(screenPoint), (Camera)null, ref val))
			{
				return false;
			}
			Rect rect = rectTransform.rect;
			if (!((Rect)(ref rect)).Contains(val))
			{
				return false;
			}
			Vector2 val2 = Rect.PointToNormalized(rectTransform.rect, val);
			Rect uvRect = mapImageLarge.uvRect;
			int num = minimap.m_textureSize / 2;
			float num2 = (((Rect)(ref uvRect)).xMin + val2.x * ((Rect)(ref uvRect)).width) * (float)minimap.m_textureSize - (float)num;
			float num3 = (((Rect)(ref uvRect)).yMin + val2.y * ((Rect)(ref uvRect)).height) * (float)minimap.m_textureSize - (float)num;
			world = new Vector3(num2 * minimap.m_pixelSize, 0f, num3 * minimap.m_pixelSize);
			return true;
		}

		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static IEnumerator RefreshLoop()
		{
			yield return null;
			while (true)
			{
				if (Visible && !PortalSelection.Active)
				{
					Refresh();
				}
				yield return (object)new WaitForSeconds(1f);
			}
		}

		private static Sprite LoadIcon()
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_00a3: 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)
			using Stream stream = typeof(PortalPins).Assembly.GetManifestResourceStream("VikingsPortals.assets.portal_icon.png");
			if (stream == null)
			{
				return null;
			}
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			if (!PngImage.TryDecode(memoryStream.ToArray(), out var width, out var height, out var pixels))
			{
				return null;
			}
			Texture2D val = new Texture2D(width, height, (TextureFormat)4, false);
			val.SetPixels32(pixels);
			val.Apply();
			((Object)val).name = "VPortals_Icon";
			Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
			((Object)val2).name = "VPortals_Icon";
			return val2;
		}
	}
	[HarmonyPatch(typeof(Minimap), "Start")]
	internal static class Minimap_Start_PortalPins
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static void Postfix(Minimap __instance, ref bool[] ___m_visibleIconTypes, List<PinData> ___m_pins)
		{
			PortalPins.Register(__instance, ref ___m_visibleIconTypes, ___m_pins);
		}
	}
	[HarmonyPatch(typeof(Minimap), "Update")]
	internal static class Minimap_Update_PortalKeys
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static void Prefix(Minimap __instance, bool[] ___m_visibleIconTypes, List<PinData> ___m_pins, ref bool ___m_pinUpdateRequired)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Invalid comparison between Unknown and I4
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			PortalPins.Track(___m_visibleIconTypes, ___m_pins);
			if (PortalPins.ConsumeDirty())
			{
				___m_pinUpdateRequired = true;
			}
			if (!((Object)(object)Player.m_localPlayer == (Object)null) && (VikingsPortalsPlugin.MapPinsOnMinimap.Value ? ((int)__instance.m_mode > 0) : ((int)__instance.m_mode == 2)) && PortalPins.KeyDown() && PortalPins.TakesInput())
			{
				PortalPins.ToggleVisible();
			}
		}
	}
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(2)]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	internal static class PortalSelection
	{
		private static bool[] _savedIconTypes;

		private static bool _sourceAllowsAllItems;

		public static bool Active { get; private set; }

		public static ZDO Source { get; private set; }

		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		public static void Begin(TeleportWorld source)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Invalid comparison between Unknown and I4
			Minimap instance = Minimap.instance;
			if ((Object)(object)source == (Object)null || (Object)(object)instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			if (Active)
			{
				End();
			}
			bool noMap = Game.m_noMap;
			Game.m_noMap = false;
			try
			{
				instance.ShowPointOnMap(((Component)source).transform.position);
			}
			finally
			{
				Game.m_noMap = noMap;
			}
			if ((int)instance.m_mode == 2)
			{
				ZNetView component = ((Component)source).GetComponent<ZNetView>();
				Source = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null);
				_sourceAllowsAllItems = source.m_allowAllItems;
				Active = true;
				if (InventoryGui.IsVisible())
				{
					InventoryGui.instance.Hide();
				}
				PortalPins.Refresh();
				if (VikingsPortalsPlugin.MapHidePins.Value)
				{
					HideOtherIcons(instance);
				}
			}
		}

		public static void End()
		{
			if (Active)
			{
				Active = false;
				Source = null;
				RestoreIcons();
				if (!PortalPins.Visible)
				{
					PortalPins.Clear();
				}
			}
		}

		internal static void Reset()
		{
			Active = false;
			Source = null;
			_savedIconTypes = null;
		}

		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static void HideOtherIcons(Minimap minimap)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Expected I4, but got Unknown
			bool[] iconTypes = PortalPins.IconTypes;
			if (iconTypes == null || _savedIconTypes != null)
			{
				return;
			}
			_savedIconTypes = (bool[])iconTypes.Clone();
			HashSet<int> hashSet = new HashSet<int> { PortalPins.PinType };
			if (VikingsPortalsPlugin.MapShowPlayers.Value)
			{
				hashSet.Add(10);
			}
			HashSet<Sprite> hashSet2 = new HashSet<Sprite>();
			foreach (LocationSpriteData locationIcon in minimap.m_locationIcons)
			{
				if ((Object)(object)locationIcon.m_icon != (Object)null)
				{
					hashSet2.Add(locationIcon.m_icon);
				}
			}
			List<PinData> allPins = PortalPins.AllPins;
			if (allPins != null)
			{
				foreach (PinData item in allPins)
				{
					if ((Object)(object)item.m_icon != (Object)null && hashSet2.Contains(item.m_icon))
					{
						hashSet.Add((int)item.m_type);
					}
				}
			}
			for (int i = 0; i < iconTypes.Length; i++)
			{
				if (!hashSet.Contains(i))
				{
					iconTypes[i] = false;
				}
			}
			PortalPins.MarkDirty();
		}

		private static void RestoreIcons()
		{
			bool[] savedIconTypes = _savedIconTypes;
			_savedIconTypes = null;
			bool[] iconTypes = PortalPins.IconTypes;
			if (savedIconTypes == null || iconTypes == null)
			{
				return;
			}
			int num = Mathf.Min(savedIconTypes.Length, iconTypes.Length);
			for (int i = 0; i < num; i++)
			{
				if (savedIconTypes[i] && !iconTypes[i])
				{
					iconTypes[i] = true;
				}
			}
			PortalPins.MarkDirty();
		}

		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		public static bool TryTeleport(ZDO target, PinData pin)
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Active || (Object)(object)localPlayer == (Object)null || target == null || pin == null || !target.IsValid())
			{
				return false;
			}
			if (!PortalRecord.LocalCanUse(target))
			{
				((Character)localPlayer).Message((MessageType)2, "$vportals_no_access", 0, (Sprite)null, false);
				return false;
			}
			string text = WorldBlock();
			if (text != null)
			{
				((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
				return false;
			}
			ItemRule value = VikingsPortalsPlugin.TeleportItemRule.Value;
			if ((value == ItemRule.Strict || (value == ItemRule.Portal && !_sourceAllowsAllItems)) && !((Humanoid)localPlayer).IsTeleportable(false))
			{
				((Character)localPlayer).Message((MessageType)2, "$msg_noteleport", 0, (Sprite)null, false);
				return false;
			}
			Quaternion rotation = target.GetRotation();
			End();
			if ((Object)(object)Minimap.instance != (Object)null)
			{
				Minimap.instance.SetMapMode((MapMode)1);
			}
			if (!((Character)localPlayer).TeleportTo(pin.m_pos + rotation * Vector3.forward + Vector3.up, rotation, true))
			{
				return false;
			}
			if ((Object)(object)Game.instance != (Object)null)
			{
				Game.instance.IncrementPlayerStat((PlayerStatType)15, 1f, false);
			}
			return true;
		}

		public static string WorldBlock()
		{
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			if (instance.GetGlobalKey((GlobalKeys)32))
			{
				return "$msg_blocked";
			}
			if (!instance.GetGlobalKey((GlobalKeys)33))
			{
				return null;
			}
			bool flag = (Object)(object)RandEventSystem.instance != (Object)null && RandEventSystem.instance.GetBossEvent() != null;
			float num = default(float);
			bool flag2 = instance.GetGlobalKey((GlobalKeys)47, ref num) && num > 0f;
			return (flag || flag2) ? "$msg_blockedbyboss" : null;
		}
	}
	[HarmonyPatch(typeof(TeleportWorldTrigger), "OnTriggerEnter")]
	internal static class TeleportWorldTrigger_OnTriggerEnter_Select
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static bool Prefix(Collider colliderIn, TeleportWorld ___m_teleportWorld)
		{
			if ((Object)(object)colliderIn == (Object)null)
			{
				return true;
			}
			Player component = ((Component)colliderIn).GetComponent<Player>();
			if ((Object)(object)component == (Object)null || (Object)(object)component != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if ((Object)(object)___m_teleportWorld == (Object)null || !PortalRecord.IsManaged(___m_teleportWorld))
			{
				return true;
			}
			ZDO val = PortalRecord.ZdoOf((Component)(object)___m_teleportWorld);
			if (val == null)
			{
				return true;
			}
			if (!PortalRecord.LocalCanUse(val))
			{
				((Character)component).Message((MessageType)2, "$vportals_no_access", 0, (Sprite)null, false);
				return false;
			}
			string text = PortalSelection.WorldBlock();
			if (text != null)
			{
				((Character)component).Message((MessageType)2, text, 0, (Sprite)null, false);
				return false;
			}
			PortalSelection.Begin(___m_teleportWorld);
			return false;
		}
	}
	[HarmonyPatch(typeof(Minimap), "SetMapMode")]
	internal static class Minimap_SetMapMode_EndSelection
	{
		private static void Postfix(MapMode mode)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)mode != 2)
			{
				PortalSelection.End();
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "OnMapDblClick")]
	internal static class Minimap_OnMapDblClick_BlockSelection
	{
		private static bool Prefix()
		{
			return !PortalSelection.Active;
		}
	}
	[HarmonyPatch(typeof(Minimap), "OnMapMiddleClick")]
	internal static class Minimap_OnMapMiddleClick_BlockSelection
	{
		private static bool Prefix()
		{
			return !PortalSelection.Active;
		}
	}
	[HarmonyPatch(typeof(Minimap), "RemovePinUnderPointer")]
	internal static class Minimap_RemovePinUnderPointer_BlockSelection
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static bool Prefix(Minimap __instance)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (!PortalSelection.Active)
			{
				return true;
			}
			PinData val = PortalPins.PinNear(__instance, ZInput.pointerPosition);
			if (val != null && PortalPins.Shown.TryGetValue(val, out var value))
			{
				PortalFavorites.Toggle(value);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Minimap), "OnMapLeftClick")]
	internal static class Minimap_OnMapLeftClick_Teleport
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static bool Prefix(Minimap __instance)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (!PortalSelection.Active)
			{
				return true;
			}
			PinData val = PortalPins.PinNear(__instance, ZInput.pointerPosition);
			if (val != null && PortalPins.Shown.TryGetValue(val, out var value))
			{
				PortalSelection.TryTeleport(value, val);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "HaveTarget")]
	internal static class TeleportWorld_HaveTarget_Managed
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static bool Prefix(TeleportWorld __instance, ref bool __result)
		{
			if (!PortalRecord.IsManaged(__instance))
			{
				return true;
			}
			__result = true;
			return false;
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "TargetFound")]
	internal static class TeleportWorld_TargetFound_Managed
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static bool Prefix(TeleportWorld __instance, ref bool __result)
		{
			if (!PortalRecord.IsManaged(__instance))
			{
				return true;
			}
			__result = VikingsPortalsPlugin.GlowEnabled.Value;
			return false;
		}
	}
	[HarmonyPatch(typeof(Game), "ConnectPortals")]
	internal static class Game_ConnectPortals_Skip
	{
		private static bool Prefix()
		{
			return VikingsPortalsPlugin.PortalVanillaOnly.Value;
		}
	}
	[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
	[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(0)]
	internal static class PortalRegistry
	{
		private static HashSet<ZDO> _portals = new HashSet<ZDO>();

		private static readonly RevisionTracker<ZDOID> Sent = new RevisionTracker<ZDOID>();

		public static IReadOnlyCollection<ZDO> All => _portals;

		public static int Count => _portals.Count;

		[<7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		[method: <596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(2)]
		[field: <7a806118-b484-4911-b895-cee4047d3ab8>Nullable(2)]
		public static event Action Changed;

		public static void Clear()
		{
			Sent.Clear();
			if (_portals.Count != 0)
			{
				_portals = new HashSet<ZDO>();
				PortalRegistry.Changed?.Invoke();
			}
		}

		public static void Add(ZDO zdo)
		{
			if (zdo != null && _portals.Add(zdo))
			{
				PortalRegistry.Changed?.Invoke();
			}
		}

		public static void Remove(ZDO zdo)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (zdo != null)
			{
				Sent.Remove(zdo.m_uid);
				if (_portals.Remove(zdo))
				{
					PortalRegistry.Changed?.Invoke();
				}
			}
		}

		public static IEnumerator Scan()
		{
			while (true)
			{
				if (ZDOMan.instance != null && (Object)(object)ZNet.instance != (Object)null)
				{
					HashSet<ZDO> found = new HashSet<ZDO>();
					foreach (KeyValuePair<SectorIndex, List<ZDO>> portal in ZDOMan.instance.GetPortals())
					{
						foreach (ZDO zdo in portal.Value)
						{
							if (PortalRecord.IsManagedPrefab(zdo.GetPrefab()))
							{
								found.Add(zdo);
							}
						}
					}
					if (ZNet.instance.IsServer())
					{
						HashSet<ZDOID> ids = new HashSet<ZDOID>();
						foreach (ZDO zdo2 in found)
						{
							ids.Add(zdo2.m_uid);
							if (Sent.Changed(zdo2.m_uid, zdo2.DataRevision, zdo2.OwnerRevision))
							{
								ZDOMan.instance.ForceSendZDO(zdo2.m_uid);
							}
						}
						Sent.Prune(ids);
					}
					bool changed = found.Count != _portals.Count || !found.SetEquals(_portals);
					_portals = found;
					if (changed)
					{
						PortalRegistry.Changed?.Invoke();
					}
				}
				yield return (object)new WaitForSeconds(5f);
			}
		}
	}
	[HarmonyPatch(typeof(Game), "Start")]
	internal static class Game_Start_ScanPortals
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static void Postfix(Game __instance)
		{
			PortalRegistry.Clear();
			((MonoBehaviour)__instance).StartCoroutine(PortalRegistry.Scan());
		}
	}
	[HarmonyPatch(typeof(ZDOMan), "AddPeer")]
	internal static class ZDOMan_AddPeer_SendPortals
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static void Postfix(ZDOMan __instance, ZNetPeer netPeer)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			foreach (ZDO item in PortalRegistry.All)
			{
				__instance.ForceSendZDO(netPeer.m_uid, item.m_uid);
			}
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "Awake")]
	internal static class TeleportWorld_Awake_Register
	{
		[<596d02bc-cb07-4f28-80d1-942233a59b21>NullableContext(1)]
		private static void Postfix(TeleportWorld __instance, ZNetView ___m_nview)
		{
			if (ZNetView.m_forceDisableInit)
			{
				return;
			}
			if ((Object)(object)___m_nview == (Object)null)
			{
				return;
			}
			ZDO zdo = ___m_nview.GetZDO();
			if (zdo == null || !PortalRecord.IsManagedPrefab(zdo.GetPrefab()))
			{
				return;
			}
			PortalRegistry.Add(zdo);
			WearNTear component = ((Component)__instance).GetComponent<WearNTear>();
			if (!((Object)(object)component == (Object)null))
			{
				Action previous = component