Decompiled source of AdjustablePortals v0.4.0

plugins/AdjustablePortals.dll

Decompiled 6 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using AdjustablePortals.common;
using AdjustablePortals.modules;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("AdjustablePortals")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AdjustablePortals")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.4.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.4.0.0")]
namespace AdjustablePortals
{
	[BepInPlugin("MidnightsFX.AdjustablePortals", "AdjustablePortals", "0.4.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal class AdjustablePortals : BaseUnityPlugin
	{
		public const string PluginGUID = "MidnightsFX.AdjustablePortals";

		public const string PluginName = "AdjustablePortals";

		public const string PluginVersion = "0.4.0";

		internal static Harmony Harmony = new Harmony("MidnightsFX.AdjustablePortals");

		public static CustomLocalization Localization = LocalizationManager.Instance.GetLocalization();

		internal static ManualLogSource Log;

		internal static AdjustablePortals Instance;

		public void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			new ValConfig(((BaseUnityPlugin)this).Config);
			TeleportItems.SetupTeleportLists();
			Compatibility.CheckModCompat();
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			Harmony.PatchAll(executingAssembly);
			Compatibility.TargetPortalCompat();
		}
	}
	internal class Logger
	{
		public static LogLevel Level = (LogLevel)16;

		public static void enableDebugLogging(object sender, EventArgs e)
		{
			//IL_0016: 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)
			if (ValConfig.EnableDebugMode.Value)
			{
				Level = (LogLevel)32;
			}
			else
			{
				Level = (LogLevel)16;
			}
		}

		public static void setDebugLogging(bool state)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (state)
			{
				Level = (LogLevel)32;
			}
			else
			{
				Level = (LogLevel)16;
			}
		}

		public static void LogDebug(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Level >= 32)
			{
				AdjustablePortals.Log.LogInfo((object)message);
			}
		}

		public static void LogInfo(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Level >= 16)
			{
				AdjustablePortals.Log.LogInfo((object)message);
			}
		}

		public static void LogWarning(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)Level >= 4)
			{
				AdjustablePortals.Log.LogWarning((object)message);
			}
		}

		public static void LogError(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)Level >= 2)
			{
				AdjustablePortals.Log.LogError((object)message);
			}
		}
	}
	internal class ValConfig
	{
		public static ConfigFile cfg;

		public static ConfigEntry<bool> EnableDebugMode;

		public static ConfigEntry<float> PortalPieceActivationDistance;

		public static ConfigEntry<int> PortalNearbyPiecesForActivation;

		public static ConfigEntry<string> DefeatedEikthyrAllowedItems;

		public static ConfigEntry<string> DefeatedElderAllowedItems;

		public static ConfigEntry<string> DefeatedBonemassAllowedItems;

		public static ConfigEntry<string> DefeatedModerAllowItems;

		public static ConfigEntry<string> DefeatedYagluthAllowItems;

		public static ConfigEntry<string> DefeatedQueenAllowItems;

		public static ConfigEntry<string> DefeatedFaderAllowItems;

		public static ConfigEntry<bool> EnablePortalPieceRequirements;

		public static ConfigEntry<bool> EnablePortalRequireFuel;

		public static ConfigEntry<int> PortalFuelUsagesPerBatch;

		public static ConfigEntry<int> PortalFuelBatchSize;

		public static ConfigEntry<string> PortalFuelPrefab;

		public static ConfigEntry<bool> EnableTeleportMounts;

		public static ConfigEntry<bool> EnableTeleportTames;

		public static ConfigEntry<float> TeleportTamesRadius;

		public static ConfigEntry<int> TeleportTamesMaxCount;

		public static ConfigEntry<bool> TeleportTamesRequireFollowing;

		public static ConfigEntry<bool> EnableTeleportCarts;

		public static ConfigEntry<bool> ReattachCartAfterTeleport;

		private static FileSystemWatcher configWatcher;

		public ValConfig(ConfigFile cf)
		{
			cfg = cf;
			cfg.SaveOnConfigSet = true;
			CreateConfigValues(cf);
			Logger.setDebugLogging(EnableDebugMode.Value);
			SetupMainFileWatcher();
		}

		private void CreateConfigValues(ConfigFile Config)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			EnableDebugMode = Config.Bind<bool>("Client config", "EnableDebugMode", false, new ConfigDescription("Enables Debug logging.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdvanced = true
			} }));
			EnableDebugMode.SettingChanged += Logger.enableDebugLogging;
			EnablePortalPieceRequirements = BindServerConfig("PortalActivation", "EnablePortalPieceRequirements", value: true, "When enabled, portals require a set number of building pieces around them in order to activate");
			PortalNearbyPiecesForActivation = BindServerConfig("PortalActivation", "PortalNearbyPiecesForActivation", 300, "The number of building pieces required nearby in order for a portal to be activated.", advanced: false, 0, 10000);
			PortalPieceActivationDistance = BindServerConfig("PortalActivation", "PortalPieceActivationDistance", 100f, "The distance that will be checked for nearby building pieces to meet the required structures nearby.");
			EnablePortalRequireFuel = BindServerConfig("PortalActivation", "EnablePortalRequireFuel", value: false, "When enabled, portals require a fuel item to teleport users");
			PortalFuelUsagesPerBatch = BindServerConfig("PortalActivation", "PortalFuelUsagesPerBatch", 20, "The number of usages that one batch of the fuel type provides");
			PortalFuelBatchSize = BindServerConfig("PortalActivation", "PortalFuelBatchSize", 1, "The number of the portal fuel required for activation.");
			PortalFuelPrefab = BindServerConfig("PortalActivation", "PortalFuelPrefab", "SurtlingCore", "The prefab name that will be used for the portal costs.");
			EnableTeleportMounts = BindServerConfig("PortalCompanions", "EnableTeleportMounts", value: true, "When enabled, a player riding a mount into a portal takes the mount with them and is put back in the saddle on arrival.");
			EnableTeleportTames = BindServerConfig("PortalCompanions", "EnableTeleportTames", value: true, "When enabled, tamed creatures near the portal travel with the player to the destination.");
			TeleportTamesRadius = BindServerConfig("PortalCompanions", "TeleportTamesRadius", 5f, "The distance around the portal that tamed creatures are collected from.", advanced: false, 0f, 50f);
			TeleportTamesMaxCount = BindServerConfig("PortalCompanions", "TeleportTamesMaxCount", 5, "The most tamed creatures that one teleport will take along. The closest to the portal go first.", advanced: false, 0, 50);
			TeleportTamesRequireFollowing = BindServerConfig("PortalCompanions", "TeleportTamesRequireFollowing", value: true, "When enabled, only tames that have been told to follow the teleporting player travel with them. Turn this off to take every tame standing near the portal, penned livestock included.");
			EnableTeleportCarts = BindServerConfig("PortalCompanions", "EnableTeleportCarts", value: true, "When enabled, a cart the player is pulling travels with them. The cart may only hold items that the player themselves could teleport with, and blocks the teleport otherwise.");
			ReattachCartAfterTeleport = BindServerConfig("PortalCompanions", "ReattachCartAfterTeleport", value: true, "When enabled, a cart that travelled through a portal is hitched back up on arrival instead of being left loose at the destination.", null, advanced: true);
			DefeatedEikthyrAllowedItems = BindServerConfig("PortalProgression", "DefeatedEikthyrAllowedItems", "", "Comma seperated list of prefab items that will be allowed to teleported once Eikthyr is defeated.");
			DefeatedEikthyrAllowedItems.SettingChanged += TeleportItems.EikthyrAllowedTeleportsChanged;
			DefeatedElderAllowedItems = BindServerConfig("PortalProgression", "DefeatedElderAllowedItems", "", "Comma seperated list of prefab items that will be allowed to be teleported once The Elder is defeated.");
			DefeatedElderAllowedItems.SettingChanged += TeleportItems.ElderAllowedTeleportsChanged;
			DefeatedBonemassAllowedItems = BindServerConfig("PortalProgression", "DefeatedBonemassAllowedItems", "Bronze,Copper,Tin,CopperOre,TinOre,BronzeScrap", "Comma seperated list of prefab items that will be allowed to be teleported once Bonemass is defeated.");
			DefeatedBonemassAllowedItems.SettingChanged += TeleportItems.BonemassAllowedTeleportsChanged;
			DefeatedModerAllowItems = BindServerConfig("PortalProgression", "DefeatedModerAllowItems", "Iron,IronOre,Ironpit,IronScrap,chest_hildir1,chest_hildir2,chest_hildir3", "Comma seperated list of prefab items that will be allowed to be teleported once Moder is defeated.");
			DefeatedModerAllowItems.SettingChanged += TeleportItems.ModerAllowedTeleportsChanged;
			DefeatedYagluthAllowItems = BindServerConfig("PortalProgression", "DefeatedYagluthAllowItems", "Silver,SilverOre,DragonEgg", "Comma seperated list of prefab items that will be allowed to be teleported once Yagluth is defeated.");
			DefeatedYagluthAllowItems.SettingChanged += TeleportItems.YagluthAllowedTeleportsChanged;
			DefeatedQueenAllowItems = BindServerConfig("PortalProgression", "DefeatedQueenAllowItems", "MechanicalSpring,BlackMetal,BlackMetalScrap", "Comma seperated list of prefab items that will be allowed to be teleported once The Seeker Queen is defeated.");
			DefeatedQueenAllowItems.SettingChanged += TeleportItems.QueenAllowedTeleportsChanged;
			DefeatedFaderAllowItems = BindServerConfig("PortalProgression", "DefeatedFaderAllowItems", "DvergrNeedle", "Comma seperated list of prefab items that will be allowed to be teleported once Fader is defeated.");
			DefeatedFaderAllowItems.SettingChanged += TeleportItems.FaderAllowedTeleportsChanged;
		}

		internal static void SetupMainFileWatcher()
		{
			configWatcher = new FileSystemWatcher();
			configWatcher.NotifyFilter = NotifyFilters.LastWrite;
			configWatcher.Path = Path.GetDirectoryName(cfg.ConfigFilePath);
			configWatcher.Filter = Path.GetFileName(cfg.ConfigFilePath);
			configWatcher.Changed += OnConfigFileChanged;
			configWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			configWatcher.EnableRaisingEvents = true;
		}

		private static void OnConfigFileChanged(object sender, FileSystemEventArgs e)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				Logger.LogInfo("Configuration file has been changed, reloading settings.");
				cfg.Reload();
			}
		}

		public static ConfigEntry<List<string>> BindServerConfig(string catagory, string key, List<string> value, string description, bool advanced = false)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			return cfg.Bind<List<string>>(catagory, key, value, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<float[]> BindServerConfig(string catagory, string key, float[] value, string description, bool advanced = false, float valmin = 0f, float valmax = 150f)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			return cfg.Bind<float[]>(catagory, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(valmin, valmax), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<bool> BindServerConfig(string catagory, string key, bool value, string description, AcceptableValueBase acceptableValues = null, bool advanced = false)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			return cfg.Bind<bool>(catagory, key, value, new ConfigDescription(description, acceptableValues, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<int> BindServerConfig(string catagory, string key, int value, string description, bool advanced = false, int valmin = 0, int valmax = 150)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			return cfg.Bind<int>(catagory, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(valmin, valmax), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<float> BindServerConfig(string catagory, string key, float value, string description, bool advanced = false, float valmin = 0f, float valmax = 150f)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			return cfg.Bind<float>(catagory, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(valmin, valmax), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<string> BindServerConfig(string catagory, string key, string value, string description, AcceptableValueList<string> acceptableValues = null, bool advanced = false)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			return cfg.Bind<string>(catagory, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)acceptableValues, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}
	}
}
namespace AdjustablePortals.modules
{
	internal static class ActivationRequirements
	{
		[HarmonyPatch(typeof(TeleportWorld))]
		internal static class PortalInstanceActivatable
		{
			private struct PortalPieceState
			{
				public int Pieces;

				public float NextScanTime;
			}

			private static readonly string fuelKey = "AJP_FUEL";

			private static readonly string nearbyPiecesKey = "AJP_PORT_BUILD_NEARBY";

			private const float ScanIntervalSeconds = 10f;

			private const float InitialGraceSeconds = 5f;

			private const float InitialScanSpreadSeconds = 10f;

			private const float StaleEntrySeconds = 60f;

			private const float PruneIntervalSeconds = 60f;

			private static readonly Dictionary<ZDOID, PortalPieceState> nearbyPiecesByPortal = new Dictionary<ZDOID, PortalPieceState>();

			private static float nextPruneTime = 0f;

			private static readonly List<ZDOID> pruneBuffer = new List<ZDOID>();

			private static TeleportWorld lastFuelChargePortal = null;

			private static int lastFuelChargeFrame = -1;

			private static int GetPieceCount(TeleportWorld instance)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
				ZDO zDO = instance.m_nview.GetZDO();
				ZDOID uid = zDO.m_uid;
				if (nearbyPiecesByPortal.TryGetValue(uid, out var value))
				{
					if (Time.time < value.NextScanTime)
					{
						return value.Pieces;
					}
					PruneUnloadedPortals();
					value.Pieces = PieceProximity.CountWithin(((Component)instance).transform.position, ValConfig.PortalPieceActivationDistance.Value);
					value.NextScanTime = Time.time + 10f;
					nearbyPiecesByPortal[uid] = value;
					if (instance.m_nview.IsOwner())
					{
						zDO.Set(nearbyPiecesKey, value.Pieces);
					}
					return value.Pieces;
				}
				value.Pieces = zDO.GetInt(nearbyPiecesKey, 0);
				value.NextScanTime = Time.time + 5f + Random.Range(0f, 10f);
				nearbyPiecesByPortal[uid] = value;
				return value.Pieces;
			}

			private static void PruneUnloadedPortals()
			{
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				if (Time.time < nextPruneTime)
				{
					return;
				}
				nextPruneTime = Time.time + 60f;
				float num = Time.time - 60f;
				pruneBuffer.Clear();
				foreach (KeyValuePair<ZDOID, PortalPieceState> item in nearbyPiecesByPortal)
				{
					if (item.Value.NextScanTime < num)
					{
						pruneBuffer.Add(item.Key);
					}
				}
				for (int i = 0; i < pruneBuffer.Count; i++)
				{
					nearbyPiecesByPortal.Remove(pruneBuffer[i]);
				}
				pruneBuffer.Clear();
			}

			[HarmonyPatch(typeof(TeleportWorld), "HaveTarget")]
			[HarmonyBefore(new string[] { "org.bepinex.plugins.targetportal" })]
			[HarmonyPrefix]
			internal static bool Activator(TeleportWorld __instance, ref bool __result)
			{
				return CheckActivationRequirements(__instance, ref __result);
			}

			public static void ConsumeFuel(TeleportWorld instance)
			{
				if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.m_nview == (Object)null) && instance.m_nview.IsValid() && ValConfig.EnablePortalRequireFuel.Value && (!((Object)(object)lastFuelChargePortal == (Object)(object)instance) || lastFuelChargeFrame != Time.frameCount))
				{
					int num = instance.m_nview.GetZDO().GetInt(fuelKey, 0);
					if (num > 0)
					{
						lastFuelChargePortal = instance;
						lastFuelChargeFrame = Time.frameCount;
						instance.m_nview.ClaimOwnership();
						instance.m_nview.GetZDO().Set(fuelKey, num - 1);
						Logger.LogDebug("Consumed 1 usage of portal fuel.");
					}
				}
			}

			public static bool AreActivationRequirementsMet(TeleportWorld instance, out string reason)
			{
				reason = "";
				bool result = true;
				if ((Object)(object)instance.m_nview == (Object)null || !instance.m_nview.IsValid())
				{
					return result;
				}
				if (ValConfig.EnablePortalPieceRequirements.Value)
				{
					int pieceCount = GetPieceCount(instance);
					if (pieceCount < ValConfig.PortalNearbyPiecesForActivation.Value)
					{
						reason = $"More nearby structures required ({pieceCount}/{ValConfig.PortalNearbyPiecesForActivation.Value})";
						result = false;
					}
				}
				if (ValConfig.EnablePortalRequireFuel.Value && instance.m_nview.GetZDO().GetInt(fuelKey, 0) <= 0)
				{
					reason = $"Fuel is required, add {ValConfig.PortalFuelPrefab.Value} x {ValConfig.PortalFuelBatchSize.Value}";
					result = false;
				}
				return result;
			}

			public static bool CheckActivationRequirements(TeleportWorld __instance, ref bool __result)
			{
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid())
				{
					return true;
				}
				if (!ValConfig.EnablePortalPieceRequirements.Value && !ValConfig.EnablePortalRequireFuel.Value)
				{
					return true;
				}
				if (!Compatibility.IsTargetPortalInstalled && __instance.m_nview.GetZDO().GetConnectionZDOID((ConnectionType)1) == ZDOID.None)
				{
					__result = false;
					return false;
				}
				__result = AreActivationRequirementsMet(__instance, out var reason);
				if (!__result)
				{
					Logger.LogDebug($"Is portal active? {__result} {reason}");
				}
				return false;
			}

			[HarmonyPatch(typeof(TeleportWorld), "GetHoverText")]
			[HarmonyPostfix]
			internal static void OnHoverHelp(TeleportWorld __instance, ref string __result)
			{
				if ((Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid())
				{
					return;
				}
				if (ValConfig.EnablePortalPieceRequirements.Value)
				{
					int pieceCount = GetPieceCount(__instance);
					if (pieceCount < ValConfig.PortalNearbyPiecesForActivation.Value)
					{
						__result += Localization.instance.Localize($"\nMore nearby structures required ({pieceCount}/{ValConfig.PortalNearbyPiecesForActivation.Value})");
					}
				}
				if (ValConfig.EnablePortalRequireFuel.Value)
				{
					int num = __instance.m_nview.GetZDO().GetInt(fuelKey, 0);
					if (num <= 0)
					{
						__result += Localization.instance.Localize($"\nFuel is required, add <color=red>{ValConfig.PortalFuelPrefab.Value}</color> x {ValConfig.PortalFuelBatchSize.Value}");
					}
					else
					{
						__result += Localization.instance.Localize($"\nCurrent Fuel {num}.");
					}
				}
			}

			[HarmonyPatch(typeof(TeleportWorld), "TargetFound")]
			[HarmonyPostfix]
			internal static void TargetFoundPrevention(TeleportWorld __instance, ref bool __result)
			{
				if (__result && !((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsValid() && (ValConfig.EnablePortalPieceRequirements.Value || ValConfig.EnablePortalRequireFuel.Value) && !AreActivationRequirementsMet(__instance, out var reason))
				{
					Logger.LogDebug("Portal blocked: " + reason);
					__result = false;
				}
			}

			[HarmonyPatch(typeof(TeleportWorld), "UseItem")]
			[HarmonyPrefix]
			internal static bool AddFuelOnUseItem(TeleportWorld __instance, Humanoid user, ItemData item, ref bool __result)
			{
				if ((Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || !ValConfig.EnablePortalRequireFuel.Value)
				{
					return true;
				}
				if ((Object)(object)user == (Object)null || user.m_inventory == null || item == null || (Object)(object)item.m_dropPrefab == (Object)null || ((Object)item.m_dropPrefab).name != ValConfig.PortalFuelPrefab.Value)
				{
					return true;
				}
				int value = ValConfig.PortalFuelBatchSize.Value;
				if (user.m_inventory.CountItemsByPrefab(ValConfig.PortalFuelPrefab.Value) < value || !user.m_inventory.RemoveItemByPrefab(ValConfig.PortalFuelPrefab.Value, value))
				{
					((Character)user).Message((MessageType)2, $"Requires at least {ValConfig.PortalFuelPrefab.Value}x{value}.", 0, (Sprite)null, false);
					__result = true;
					return false;
				}
				__instance.m_nview.ClaimOwnership();
				int num = __instance.m_nview.GetZDO().GetInt(fuelKey, 0) + ValConfig.PortalFuelUsagesPerBatch.Value;
				__instance.m_nview.GetZDO().Set(fuelKey, num);
				((Character)user).Message((MessageType)2, $"Added {ValConfig.PortalFuelPrefab.Value}x{value} for {ValConfig.PortalFuelUsagesPerBatch.Value} fuel.", 0, (Sprite)null, false);
				__result = true;
				return false;
			}

			[HarmonyPatch(typeof(TeleportWorld), "Teleport")]
			[HarmonyPrefix]
			internal static void ConsumeFuelAfterTeleportPrefix(Player player, out bool __state)
			{
				__state = (Object)(object)player != (Object)null && ((Character)player).IsTeleporting();
			}

			[HarmonyPatch(typeof(TeleportWorld), "Teleport")]
			[HarmonyPostfix]
			internal static void ConsumeFuelAfterTeleport(TeleportWorld __instance, Player player, bool __state)
			{
				if (!__state && !((Object)(object)player == (Object)null) && ((Character)player).IsTeleporting())
				{
					ConsumeFuel(__instance);
				}
			}

			internal static void ClearPortalPieceCache()
			{
				nearbyPiecesByPortal.Clear();
				pruneBuffer.Clear();
				nextPruneTime = 0f;
				PieceProximity.Clear();
				lastFuelChargePortal = null;
				lastFuelChargeFrame = -1;
			}
		}

		[HarmonyPatch(typeof(ZNetScene))]
		internal static class PortalCacheLifetime
		{
			[HarmonyPatch("Shutdown")]
			[HarmonyPostfix]
			private static void OnShutdown()
			{
				PortalInstanceActivatable.ClearPortalPieceCache();
				TeleportCompanions.ClearSessionState();
			}
		}
	}
	internal static class Compatibility
	{
		public static bool IsTargetPortalInstalled;

		private static TeleportWorld activeSourcePortal;

		private static float activeSourcePortalExpiry;

		private const float ActiveSourcePortalLifetime = 30f;

		internal static TeleportWorld GetActiveSourcePortal()
		{
			if ((Object)(object)activeSourcePortal == (Object)null || Time.time > activeSourcePortalExpiry)
			{
				return null;
			}
			return activeSourcePortal;
		}

		internal static void CheckModCompat()
		{
			try
			{
				Dictionary<string, BaseUnityPlugin> plugins = BepInExUtils.GetPlugins(false);
				if (plugins != null && Enumerable.Contains(plugins.Keys, "org.bepinex.plugins.targetportal"))
				{
					IsTargetPortalInstalled = true;
				}
			}
			catch
			{
				Logger.LogWarning("Unable to check mod compatibility. Ensure that Bepinex can load.");
			}
		}

		internal static void TargetPortalCompat()
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			if (IsTargetPortalInstalled)
			{
				Logger.LogInfo("TargetPortal detected, applying compatibility patches...");
				Type type = AccessTools.TypeByName("TargetPortal.Map")?.GetNestedType("OpenMapOnPortalEnter", AccessTools.all);
				MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "Prefix", (Type[])null, (Type[])null) : null);
				if (methodInfo == null)
				{
					Logger.LogWarning("Could not find TargetPortal.Map.OpenMapOnPortalEnter.Prefix - TargetPortal compatibility patches will not be applied.");
					return;
				}
				HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(Compatibility), "BlockOrTrackPortalEntry", (Type[])null, (Type[])null));
				AdjustablePortals.Harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				MethodInfo methodInfo2 = AccessTools.Method(typeof(Player), "TeleportTo", (Type[])null, (Type[])null);
				HarmonyMethod val2 = new HarmonyMethod(AccessTools.Method(typeof(Compatibility), "TeleportToPostfix", (Type[])null, (Type[])null));
				AdjustablePortals.Harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Logger.LogInfo("TargetPortal compatibility patches applied.");
			}
		}

		private static bool BlockOrTrackPortalEntry(TeleportWorldTrigger __0)
		{
			if ((Object)(object)__0 == (Object)null || (Object)(object)__0.m_teleportWorld == (Object)null)
			{
				return true;
			}
			if (!ActivationRequirements.PortalInstanceActivatable.AreActivationRequirementsMet(__0.m_teleportWorld, out var reason))
			{
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					((Character)Player.m_localPlayer).Message((MessageType)2, reason, 0, (Sprite)null, false);
				}
				return false;
			}
			activeSourcePortal = __0.m_teleportWorld;
			activeSourcePortalExpiry = Time.time + 30f;
			return true;
		}

		private static void TeleportToPostfix(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Object)(object)activeSourcePortal == (Object)null))
			{
				if (Time.time > activeSourcePortalExpiry)
				{
					activeSourcePortal = null;
					return;
				}
				ActivationRequirements.PortalInstanceActivatable.ConsumeFuel(activeSourcePortal);
				activeSourcePortal = null;
			}
		}
	}
	internal static class TeleportCompanions
	{
		private struct PortalTrip
		{
			public bool FromPortal;

			public Vector3 Center;

			public Vector3 Destination;

			public Character Mount;

			public Vagon Cart;

			public string CartBlockedBy;
		}

		[HarmonyPatch(typeof(TeleportWorld))]
		internal static class PortalTripSource
		{
			[HarmonyPatch("Teleport")]
			[HarmonyPrefix]
			private static bool OnPortalTeleport(TeleportWorld __instance, Player player)
			{
				vanillaSourcePortal = __instance;
				vanillaSourcePortalFrame = Time.frameCount;
				if (!ValConfig.EnableTeleportCarts.Value || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
				{
					return true;
				}
				Vagon attachedCart = GetAttachedCart(player);
				if ((Object)(object)attachedCart == (Object)null)
				{
					return true;
				}
				if (!__instance.TargetFound())
				{
					return true;
				}
				if (IsCartTeleportable(attachedCart, __instance.m_allowAllItems, out var blockedBy))
				{
					return true;
				}
				((Character)player).Message((MessageType)2, Localization.instance.Localize("$msg_noteleport (" + blockedBy + ")"), 0, (Sprite)null, false);
				Logger.LogDebug("Teleport blocked, cart contains: " + blockedBy);
				return false;
			}
		}

		[HarmonyPatch(typeof(Humanoid))]
		internal static class LoadedCartBlocksTeleport
		{
			[HarmonyPatch("IsTeleportable")]
			[HarmonyPostfix]
			[HarmonyPriority(0)]
			private static void Postfix(Humanoid __instance, bool allowAllItems, ref bool __result)
			{
				if (__result && ValConfig.EnableTeleportCarts.Value && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					Vagon attachedCart = GetAttachedCart(Player.m_localPlayer);
					if (!((Object)(object)attachedCart == (Object)null) && !IsCartTeleportable(attachedCart, allowAllItems, out var _))
					{
						__result = false;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player))]
		internal static class CarryCompanionsThroughPortal
		{
			[HarmonyPatch("TeleportTo")]
			[HarmonyPrefix]
			private static void Prefix(Player __instance, Vector3 pos, out PortalTrip __state)
			{
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_006d: Unknown result type (might be due to invalid IL or missing references)
				__state = default(PortalTrip);
				if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || (!ValConfig.EnableTeleportTames.Value && !ValConfig.EnableTeleportCarts.Value && !ValConfig.EnableTeleportMounts.Value))
				{
					return;
				}
				TeleportWorld val = ResolveSourcePortal();
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				__state.FromPortal = true;
				__state.Center = ((Component)val).transform.position;
				__state.Destination = pos;
				if (ValConfig.EnableTeleportMounts.Value)
				{
					__state.Mount = GetRiddenMount(__instance);
				}
				if (!ValConfig.EnableTeleportCarts.Value)
				{
					return;
				}
				Vagon attachedCart = GetAttachedCart(__instance);
				if ((Object)(object)attachedCart != (Object)null)
				{
					if (IsCartTeleportable(attachedCart, val.m_allowAllItems, out var blockedBy))
					{
						__state.Cart = attachedCart;
					}
					else
					{
						__state.CartBlockedBy = blockedBy;
					}
				}
			}

			[HarmonyPatch("TeleportTo")]
			[HarmonyPostfix]
			private static void Postfix(Player __instance, bool __result, PortalTrip __state)
			{
				if (__state.FromPortal && __result)
				{
					if (!string.IsNullOrEmpty(__state.CartBlockedBy))
					{
						((Character)__instance).Message((MessageType)2, "Cart left behind (" + __state.CartBlockedBy + ")", 0, (Sprite)null, false);
					}
					CarryCompanions(__instance, __state);
				}
			}

			private static TeleportWorld ResolveSourcePortal()
			{
				if ((Object)(object)vanillaSourcePortal != (Object)null && vanillaSourcePortalFrame == Time.frameCount)
				{
					return vanillaSourcePortal;
				}
				return Compatibility.GetActiveSourcePortal();
			}
		}

		private static TeleportWorld vanillaSourcePortal = null;

		private static int vanillaSourcePortalFrame = -1;

		private const float CompanionSpacing = 1.6f;

		private const float GoldenAngleDegrees = 137.5f;

		private const float ArrivalTimeoutSeconds = 20f;

		private const int MaxBlockingItemsListed = 3;

		private static readonly List<Character> tameBuffer = new List<Character>();

		private static readonly List<string> blockedItemBuffer = new List<string>();

		internal static void ClearSessionState()
		{
			vanillaSourcePortal = null;
			vanillaSourcePortalFrame = -1;
			tameBuffer.Clear();
			blockedItemBuffer.Clear();
		}

		private static Vector3 CompanionOffset(int index)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			float num = (float)index * 137.5f * ((float)Math.PI / 180f);
			float num2 = 1.6f * Mathf.Sqrt((float)(index + 1));
			return new Vector3(Mathf.Cos(num) * num2, 0f, Mathf.Sin(num) * num2);
		}

		internal static Vagon GetAttachedCart(Player player)
		{
			if ((Object)(object)player == (Object)null || Vagon.m_instances == null)
			{
				return null;
			}
			GameObject gameObject = ((Component)player).gameObject;
			foreach (Vagon instance in Vagon.m_instances)
			{
				if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.m_attachJoin == (Object)null))
				{
					if ((Object)(object)instance.m_attachedObject == (Object)(object)gameObject)
					{
						return instance;
					}
					if ((Object)(object)((Joint)instance.m_attachJoin).connectedBody != (Object)null && (Object)(object)((Component)((Joint)instance.m_attachJoin).connectedBody).gameObject == (Object)(object)gameObject)
					{
						return instance;
					}
				}
			}
			return null;
		}

		private static Character GetRiddenMount(Player player)
		{
			if ((Object)(object)player == (Object)null || !((Character)player).IsRiding())
			{
				return null;
			}
			IDoodadController doodadController = player.GetDoodadController();
			Sadle val = (Sadle)(object)((doodadController is Sadle) ? doodadController : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Character character = val.GetCharacter();
			if ((Object)(object)character == (Object)null || character.IsDead() || (Object)(object)character.m_nview == (Object)null || !character.m_nview.IsValid())
			{
				return null;
			}
			return character;
		}

		internal static bool IsCartTeleportable(Vagon cart, bool allowAllItems, out string blockedBy)
		{
			blockedBy = "";
			if ((Object)(object)cart == (Object)null || (Object)(object)cart.m_container == (Object)null)
			{
				return true;
			}
			Inventory inventory = cart.m_container.GetInventory();
			if (inventory == null)
			{
				return true;
			}
			bool flag = (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)35);
			blockedItemBuffer.Clear();
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (allItem != null && allItem.m_shared != null && (allItem.m_shared.m_toolTier >= 1000 || (!(allowAllItems || flag) && !TeleportItems.PerPlayerTeleportableItems.IsItemTeleportable(allItem))))
				{
					string item = Localization.instance.Localize(allItem.m_shared.m_name);
					if (!blockedItemBuffer.Contains(item))
					{
						blockedItemBuffer.Add(item);
					}
				}
			}
			if (blockedItemBuffer.Count == 0)
			{
				return true;
			}
			int num = Mathf.Min(blockedItemBuffer.Count, 3);
			blockedBy = string.Join(", ", blockedItemBuffer.GetRange(0, num).ToArray());
			if (blockedItemBuffer.Count > num)
			{
				blockedBy += $", +{blockedItemBuffer.Count - num}";
			}
			blockedItemBuffer.Clear();
			return false;
		}

		private static bool IsFollowing(Character tame, Player player)
		{
			MonsterAI component = ((Component)tame).GetComponent<MonsterAI>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.GetFollowTarget() == (Object)(object)((Component)player).gameObject)
			{
				return true;
			}
			ZDO zDO = tame.m_nview.GetZDO();
			if (zDO != null)
			{
				return zDO.GetString(ZDOVars.s_follow, "") == player.GetPlayerName();
			}
			return false;
		}

		private static void GatherTames(Player player, Vector3 center, Character exclude, List<Character> into)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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)
			into.Clear();
			float num = ValConfig.TeleportTamesRadius.Value * ValConfig.TeleportTamesRadius.Value;
			bool value = ValConfig.TeleportTamesRequireFollowing.Value;
			List<Character> allCharacters = Character.GetAllCharacters();
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)exclude) && !val.IsPlayer() && !val.IsDead() && !((Object)(object)val.m_nview == (Object)null) && val.m_nview.IsValid() && val.IsTamed() && !(Utils.DistanceSqr(((Component)val).transform.position, center) > num))
				{
					Sadle componentInChildren = ((Component)val).GetComponentInChildren<Sadle>();
					if ((!((Object)(object)componentInChildren != (Object)null) || !componentInChildren.HaveValidUser()) && (!value || IsFollowing(val, player)))
					{
						into.Add(val);
					}
				}
			}
			into.Sort((Character a, Character b) => Utils.DistanceSqr(((Component)a).transform.position, center).CompareTo(Utils.DistanceSqr(((Component)b).transform.position, center)));
			int value2 = ValConfig.TeleportTamesMaxCount.Value;
			if (into.Count > value2)
			{
				into.RemoveRange(value2, into.Count - value2);
			}
		}

		private static void MoveToDestination(ZNetView nview, Transform transform, Vector3 destination)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			nview.ClaimOwnership();
			transform.position = destination;
			nview.GetZDO().SetPosition(destination);
		}

		private static void MoveTame(Character tame, Vector3 destination)
		{
			//IL_000c: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			MoveToDestination(tame.m_nview, ((Component)tame).transform, destination);
			if ((Object)(object)tame.m_body != (Object)null)
			{
				tame.m_body.position = destination;
				tame.m_body.linearVelocity = Vector3.zero;
				tame.m_body.angularVelocity = Vector3.zero;
			}
			tame.m_maxAirAltitude = destination.y;
		}

		private static void MoveCart(Vagon cart, Vector3 destination)
		{
			//IL_000c: 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: 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)
			MoveToDestination(cart.m_nview, ((Component)cart).transform, destination);
			if (cart.m_bodies == null)
			{
				return;
			}
			Rigidbody[] bodies = cart.m_bodies;
			foreach (Rigidbody val in bodies)
			{
				if (!((Object)(object)val == (Object)null))
				{
					val.position = ((Component)val).transform.position;
					val.linearVelocity = Vector3.zero;
					val.angularVelocity = Vector3.zero;
				}
			}
		}

		private static void CarryCompanions(Player player, PortalTrip trip)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			if ((Object)(object)trip.Mount != (Object)null && (Object)(object)trip.Mount.m_nview != (Object)null && trip.Mount.m_nview.IsValid())
			{
				ZDOID uid = trip.Mount.m_nview.GetZDO().m_uid;
				player.StopDoodadControl();
				MoveTame(trip.Mount, trip.Destination + CompanionOffset(num));
				num++;
				Logger.LogDebug("Took a ridden mount through the portal.");
				StartArrivalCoroutine(player, uid, "Mount", Remount);
			}
			if (ValConfig.EnableTeleportTames.Value)
			{
				GatherTames(player, trip.Center, trip.Mount, tameBuffer);
				foreach (Character item in tameBuffer)
				{
					MoveTame(item, trip.Destination + CompanionOffset(num));
					num++;
				}
				if (tameBuffer.Count > 0)
				{
					Logger.LogDebug($"Took {tameBuffer.Count} tamed creature(s) through the portal.");
				}
				tameBuffer.Clear();
			}
			if ((Object)(object)trip.Cart != (Object)null && (Object)(object)trip.Cart.m_nview != (Object)null && trip.Cart.m_nview.IsValid())
			{
				ZDOID uid2 = trip.Cart.m_nview.GetZDO().m_uid;
				trip.Cart.Detach();
				MoveCart(trip.Cart, trip.Destination + CompanionOffset(num));
				Logger.LogDebug("Took a cart through the portal.");
				StartArrivalCoroutine(player, uid2, "Cart", SettleCart);
			}
		}

		private static void StartArrivalCoroutine(Player player, ZDOID id, string what, Func<Player, GameObject, IEnumerator> arrived)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)AdjustablePortals.Instance != (Object)null)
			{
				((MonoBehaviour)AdjustablePortals.Instance).StartCoroutine(AfterArrival(player, id, what, arrived));
			}
		}

		private static IEnumerator AfterArrival(Player player, ZDOID id, string what, Func<Player, GameObject, IEnumerator> arrived)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			float deadline = Time.time + 20f;
			while (Time.time < deadline && (Object)(object)player != (Object)null && ((Character)player).IsTeleporting())
			{
				yield return null;
			}
			GameObject instance = null;
			while (Time.time < deadline && (Object)(object)player != (Object)null)
			{
				instance = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.FindInstance(id) : null);
				if ((Object)(object)instance != (Object)null)
				{
					break;
				}
				yield return null;
			}
			if ((Object)(object)player == (Object)null || (Object)(object)instance == (Object)null)
			{
				Logger.LogDebug(what + " did not turn up at the destination in time, leaving it where it landed.");
			}
			else
			{
				yield return ((MonoBehaviour)AdjustablePortals.Instance).StartCoroutine(arrived(player, instance));
			}
		}

		private static IEnumerator SettleCart(Player player, GameObject instance)
		{
			Vagon cart = instance.GetComponent<Vagon>();
			if ((Object)(object)cart == (Object)null || (Object)(object)cart.m_nview == (Object)null || !cart.m_nview.IsValid())
			{
				yield break;
			}
			Vector3 val = cart.m_attachPoint.position - ((Component)cart).transform.position;
			MoveCart(cart, ((Component)player).transform.position + cart.m_attachOffset - val);
			if (ValConfig.ReattachCartAfterTeleport.Value)
			{
				yield return null;
				if ((Object)(object)player != (Object)null && (Object)(object)cart != (Object)null && !((Character)player).IsTeleporting())
				{
					cart.AttachTo(((Component)player).gameObject);
				}
			}
		}

		private static IEnumerator Remount(Player player, GameObject instance)
		{
			Sadle componentInChildren = instance.GetComponentInChildren<Sadle>();
			if (!((Object)(object)componentInChildren == (Object)null) && !((Character)player).IsDead() && !((Character)player).IsAttached() && player.GetDoodadController() == null)
			{
				if (!componentInChildren.InUseDistance((Humanoid)(object)player))
				{
					Logger.LogDebug("Mount landed out of reach of the player, leaving it unridden.");
				}
				else
				{
					componentInChildren.Interact((Humanoid)(object)player, false, false);
				}
			}
			yield break;
		}
	}
	public static class TeleportItems
	{
		[HarmonyPatch(typeof(Humanoid))]
		private static class AllowConfiguredTeleportableItems
		{
			[HarmonyPatch("IsTeleportable")]
			private static void Postfix(Humanoid __instance, ref bool __result)
			{
				if (__result || __instance.m_inventory.GetAllItems().Any((ItemData x) => x.m_shared.m_toolTier >= 1000))
				{
					return;
				}
				List<ItemData> list = (from x in __instance.m_inventory.GetAllItems()
					where !x.m_shared.m_teleportable
					select x).Distinct().ToList();
				List<string> list2 = new List<string>();
				foreach (ItemData item in list)
				{
					if (!PerPlayerTeleportableItems.IsItemTeleportable(item))
					{
						list2.Add(((Object)item.m_dropPrefab).name);
					}
				}
				if (list2.Count == 0)
				{
					__result = true;
					return;
				}
				Logger.LogDebug("The following items are not teleportable " + string.Join(", ", list2));
				__result = false;
			}
		}

		[HarmonyPatch(typeof(ZoneSystem))]
		public static class ClearTeleportableCache
		{
			[HarmonyPostfix]
			[HarmonyPatch(typeof(ZoneSystem), "GlobalKeyAdd", new Type[]
			{
				typeof(string),
				typeof(bool)
			})]
			private static void GlobalKeyAdded(string keyStr)
			{
				PlayerItemsAllowTeleport.Clear();
			}

			[HarmonyPostfix]
			[HarmonyPatch(typeof(ZoneSystem), "ClearGlobalKeys")]
			private static void GlobalKeysCleared()
			{
				PlayerItemsAllowTeleport.Clear();
			}
		}

		[HarmonyPatch(typeof(InventoryGrid))]
		public static class PerPlayerTeleportableItems
		{
			[HarmonyTranspiler]
			[HarmonyPatch("UpdateGui")]
			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Expected O, but got Unknown
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Expected O, but got Unknown
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Expected O, but got Unknown
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0072: Expected O, but got Unknown
				CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null);
				val.MatchStartForward((CodeMatch[])(object)new CodeMatch[3]
				{
					new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction instruction) => CodeInstructionExtensions.IsLdloc(instruction, (LocalBuilder)null)), (string)null),
					new CodeMatch((OpCode?)OpCodes.Ldfld, (object)null, (string)null),
					new CodeMatch((OpCode?)OpCodes.Ldfld, (object)AccessTools.Field(typeof(SharedData), "m_teleportable"), (string)null)
				}).ThrowIfNotMatch("Unable to patch item teleport visual display.", Array.Empty<CodeMatch>());
				CodeInstruction val2 = val.Instruction.Clone();
				val.RemoveInstructions(3).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[2]
				{
					val2,
					Transpilers.EmitDelegate<Func<ItemData, bool>>((Func<ItemData, bool>)IsItemTeleportable)
				});
				return val.Instructions();
			}

			public static bool IsItemTeleportable(ItemData item)
			{
				if (item == null || item.m_shared == null || (Object)(object)item.m_dropPrefab == (Object)null)
				{
					return true;
				}
				string name = ((Object)item.m_dropPrefab).name;
				if (PlayerItemsAllowTeleport.ContainsKey(name))
				{
					return PlayerItemsAllowTeleport[name];
				}
				bool flag = item.m_shared.m_teleportable;
				if (!flag && ZoneSystem.instance.GetGlobalKey((GlobalKeys)42) && EikthyrAllowedTeleports.Contains(name))
				{
					flag = true;
				}
				if (!flag && ZoneSystem.instance.GetGlobalKey((GlobalKeys)45) && ElderAllowedTeleports.Contains(name))
				{
					flag = true;
				}
				if (!flag && ZoneSystem.instance.GetGlobalKey((GlobalKeys)46) && BonemassAllowedTeleports.Contains(name))
				{
					flag = true;
				}
				if (!flag && ZoneSystem.instance.GetGlobalKey((GlobalKeys)43) && ModerAllowedTeleports.Contains(name))
				{
					flag = true;
				}
				if (!flag && ZoneSystem.instance.GetGlobalKey((GlobalKeys)44) && YagluthAllowedTeleports.Contains(name))
				{
					flag = true;
				}
				if (!flag && ZoneSystem.instance.GetGlobalKey("defeated_queen") && QueenAllowedTeleports.Contains(name))
				{
					flag = true;
				}
				if (!flag && ZoneSystem.instance.GetGlobalKey("defeated_fader") && FaderAllowedTeleports.Contains(name))
				{
					flag = true;
				}
				if (!PlayerItemsAllowTeleport.ContainsKey(name))
				{
					PlayerItemsAllowTeleport.Add(name, flag);
				}
				return flag;
			}
		}

		internal static List<string> EikthyrAllowedTeleports = new List<string>();

		internal static List<string> ElderAllowedTeleports = new List<string>();

		internal static List<string> BonemassAllowedTeleports = new List<string>();

		internal static List<string> ModerAllowedTeleports = new List<string>();

		internal static List<string> YagluthAllowedTeleports = new List<string>();

		internal static List<string> QueenAllowedTeleports = new List<string>();

		internal static List<string> FaderAllowedTeleports = new List<string>();

		private static Dictionary<string, bool> PlayerItemsAllowTeleport = new Dictionary<string, bool>();

		internal static void SetupTeleportLists()
		{
			ConfigListChanged(EikthyrAllowedTeleports, ValConfig.DefeatedEikthyrAllowedItems.Value);
			ConfigListChanged(ElderAllowedTeleports, ValConfig.DefeatedElderAllowedItems.Value);
			ConfigListChanged(BonemassAllowedTeleports, ValConfig.DefeatedBonemassAllowedItems.Value);
			ConfigListChanged(ModerAllowedTeleports, ValConfig.DefeatedModerAllowItems.Value);
			ConfigListChanged(YagluthAllowedTeleports, ValConfig.DefeatedYagluthAllowItems.Value);
			ConfigListChanged(QueenAllowedTeleports, ValConfig.DefeatedQueenAllowItems.Value);
			ConfigListChanged(FaderAllowedTeleports, ValConfig.DefeatedFaderAllowItems.Value);
		}

		internal static void EikthyrAllowedTeleportsChanged(object s, EventArgs e)
		{
			ConfigListChanged(EikthyrAllowedTeleports, ValConfig.DefeatedEikthyrAllowedItems.Value);
		}

		internal static void ElderAllowedTeleportsChanged(object s, EventArgs e)
		{
			ConfigListChanged(ElderAllowedTeleports, ValConfig.DefeatedElderAllowedItems.Value);
		}

		internal static void BonemassAllowedTeleportsChanged(object s, EventArgs e)
		{
			ConfigListChanged(BonemassAllowedTeleports, ValConfig.DefeatedBonemassAllowedItems.Value);
		}

		internal static void ModerAllowedTeleportsChanged(object s, EventArgs e)
		{
			ConfigListChanged(ModerAllowedTeleports, ValConfig.DefeatedModerAllowItems.Value);
		}

		internal static void YagluthAllowedTeleportsChanged(object s, EventArgs e)
		{
			ConfigListChanged(YagluthAllowedTeleports, ValConfig.DefeatedYagluthAllowItems.Value);
		}

		internal static void QueenAllowedTeleportsChanged(object s, EventArgs e)
		{
			ConfigListChanged(QueenAllowedTeleports, ValConfig.DefeatedQueenAllowItems.Value);
		}

		internal static void FaderAllowedTeleportsChanged(object s, EventArgs e)
		{
			ConfigListChanged(FaderAllowedTeleports, ValConfig.DefeatedFaderAllowItems.Value);
		}

		private static void ConfigListChanged(List<string> targetList, string configValue)
		{
			PlayerItemsAllowTeleport.Clear();
			try
			{
				List<string> list = new List<string>();
				string[] array = configValue.Split(new char[1] { ',' });
				foreach (string item in array)
				{
					list.Add(item);
				}
				if (list.Count > 0)
				{
					targetList.Clear();
					targetList.AddRange(list);
				}
			}
			catch (Exception arg)
			{
				Logger.LogWarning($"Error parsing ConfigList: {arg}");
			}
		}
	}
}
namespace AdjustablePortals.common
{
	internal static class Extensions
	{
		public static int CountItemsByPrefab(this Inventory inv, string prefab)
		{
			int num = 0;
			foreach (ItemData allItem in inv.GetAllItems())
			{
				if ((Object)(object)allItem.m_dropPrefab != (Object)null && ((Object)allItem.m_dropPrefab).name == prefab && allItem.m_stack > 0)
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}

		public static bool RemoveItemByPrefab(this Inventory inv, string prefab, int countToRemove)
		{
			if (countToRemove <= 0)
			{
				return true;
			}
			if (inv.CountItemsByPrefab(prefab) < countToRemove)
			{
				Logger.LogDebug($"Remove summary: {prefab}x{countToRemove} not available, removing nothing.");
				return false;
			}
			List<ItemData> list = new List<ItemData>();
			foreach (ItemData allItem in inv.GetAllItems())
			{
				if ((Object)(object)allItem.m_dropPrefab != (Object)null && ((Object)allItem.m_dropPrefab).name == prefab && allItem.m_stack > 0)
				{
					list.Add(allItem);
				}
			}
			int num = countToRemove;
			foreach (ItemData item in list)
			{
				if (num <= 0)
				{
					break;
				}
				int num2 = Mathf.Min(item.m_stack, num);
				inv.RemoveItem(item, num2);
				num -= num2;
			}
			Logger.LogDebug($"Remove summary: {prefab}x{countToRemove} successfully removed: {countToRemove - num}");
			return num == 0;
		}
	}
	internal static class PieceProximity
	{
		private struct PieceRefs
		{
			public Piece Piece;

			public GameObject GameObject;

			public Transform Transform;
		}

		private const float CellSize = 32f;

		private const float SnapshotLifetimeSeconds = 10f;

		private static readonly Dictionary<long, List<Vector3>> cells = new Dictionary<long, List<Vector3>>();

		private static PieceRefs[] known = Array.Empty<PieceRefs>();

		private static int knownCount = 0;

		private static float nextRebuildTime = 0f;

		private static bool built = false;

		internal static int CountWithin(Vector3 center, float radius)
		{
			//IL_0013: 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)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			if (radius <= 0f)
			{
				return 0;
			}
			RebuildIfStale();
			float num = radius * radius;
			int num2 = CellIndex(center.x - radius);
			int num3 = CellIndex(center.x + radius);
			int num4 = CellIndex(center.z - radius);
			int num5 = CellIndex(center.z + radius);
			int num6 = 0;
			for (int i = num2; i <= num3; i++)
			{
				for (int j = num4; j <= num5; j++)
				{
					if (!cells.TryGetValue(CellKey(i, j), out var value))
					{
						continue;
					}
					for (int k = 0; k < value.Count; k++)
					{
						Vector3 val = value[k] - center;
						if (((Vector3)(ref val)).sqrMagnitude < num)
						{
							num6++;
						}
					}
				}
			}
			return num6;
		}

		internal static void Clear()
		{
			cells.Clear();
			Array.Clear(known, 0, knownCount);
			knownCount = 0;
			nextRebuildTime = 0f;
			built = false;
		}

		private static void RebuildIfStale()
		{
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			float time = Time.time;
			if (built && time < nextRebuildTime)
			{
				return;
			}
			foreach (List<Vector3> value2 in cells.Values)
			{
				value2.Clear();
			}
			int s_ghostLayer = Piece.s_ghostLayer;
			List<Piece> s_allPieces = Piece.s_allPieces;
			int count = s_allPieces.Count;
			if (known.Length < count)
			{
				Array.Resize(ref known, Mathf.Max(count, known.Length * 2));
			}
			long num = 0L;
			List<Vector3> list = null;
			for (int i = 0; i < count; i++)
			{
				Piece val = s_allPieces[i];
				GameObject gameObject;
				Transform transform;
				if (known[i].Piece == val)
				{
					gameObject = known[i].GameObject;
					transform = known[i].Transform;
				}
				else
				{
					gameObject = ((Component)val).gameObject;
					transform = ((Component)val).transform;
					known[i].Piece = val;
					known[i].GameObject = gameObject;
					known[i].Transform = transform;
				}
				if (gameObject.layer == s_ghostLayer)
				{
					continue;
				}
				Vector3 position = transform.position;
				long num2 = CellKey(CellIndex(position.x), CellIndex(position.z));
				if (list != null && num2 == num)
				{
					list.Add(position);
					continue;
				}
				if (!cells.TryGetValue(num2, out var value))
				{
					value = new List<Vector3>(16);
					cells[num2] = value;
				}
				value.Add(position);
				num = num2;
				list = value;
			}
			for (int j = count; j < knownCount; j++)
			{
				known[j] = default(PieceRefs);
			}
			knownCount = count;
			nextRebuildTime = time + 10f;
			built = true;
		}

		private static int CellIndex(float world)
		{
			return Mathf.FloorToInt(world / 32f);
		}

		private static long CellKey(int cellX, int cellZ)
		{
			return ((long)cellX << 32) | (uint)cellZ;
		}
	}
}