Decompiled source of ExploredMapTeleport v0.3.0

plugins/Valheim.MapTeleport.dll

Decompiled 3 days ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("KenJorissen")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.0.0")]
[assembly: AssemblyInformationalVersion("0.3.0")]
[assembly: AssemblyProduct("Valheim.MapTeleport")]
[assembly: AssemblyTitle("Valheim.MapTeleport")]
[assembly: AssemblyVersion("0.3.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimMapTeleport
{
	internal static class DestinationPolicy
	{
		internal static bool IsFinite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		internal static bool IsValidPoint(float x, float z, float radius)
		{
			if (IsFinite(x) && IsFinite(z) && IsFinite(radius) && radius > 0f)
			{
				return (double)x * (double)x + (double)z * (double)z < (double)radius * (double)radius;
			}
			return false;
		}

		internal static bool IsSafeTerrain(float height, float waterLevel, float normalY, float maxSlope, float maxWaterDepth = 0f)
		{
			if (IsFinite(height) && IsFinite(waterLevel) && IsFinite(normalY) && normalY >= -1f && normalY <= 1f && IsFinite(maxSlope) && maxSlope >= 0f && maxSlope < 90f && IsFinite(maxWaterDepth) && maxWaterDepth >= 0f && ((maxWaterDepth == 0f) ? (height > waterLevel + 0.3f) : (height >= waterLevel - maxWaterDepth)))
			{
				return normalY >= (float)Math.Cos((double)maxSlope * Math.PI / 180.0);
			}
			return false;
		}
	}
	[BepInPlugin("kenjorissen.mods.exploredmapteleport", "Explored Map Teleport", "0.3.0")]
	public sealed class MapTeleportPlugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(Minimap), "Start")]
		private static class MapStartPatch
		{
			private static void Postfix(Minimap __instance)
			{
				Instance?.CreateToggle(__instance);
			}
		}

		[HarmonyPatch(typeof(Minimap), "OnMapLeftClick")]
		private static class MapClickPatch
		{
			private static bool Prefix(Minimap __instance)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Invalid comparison between Unknown and I4
				MapTeleportPlugin instance = Instance;
				if ((Object)(object)instance == (Object)null || !instance.enabledSetting.Value || !instance.armed || (int)__instance.m_mode != 2)
				{
					return true;
				}
				instance.RequestTeleport(__instance);
				return false;
			}
		}

		[HarmonyPatch(typeof(Minimap), "OnMapDblClick")]
		private static class MapDoubleClickPatch
		{
			private static bool Prefix()
			{
				if (!((Object)(object)Instance == (Object)null))
				{
					if (!Instance.armed)
					{
						return !Object.op_Implicit((Object)(object)Instance.activePlayer);
					}
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(Minimap), "SetMapMode")]
		private static class MapModePatch
		{
			private static void Postfix(Minimap __instance)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Invalid comparison between Unknown and I4
				if ((int)__instance.m_mode != 2)
				{
					Instance?.SetArmed(value: false);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "UpdateTeleport")]
		private static class TeleportPatch
		{
			private static void Prefix(Player __instance)
			{
				MapTeleportPlugin instance = Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return;
				}
				try
				{
					instance.ValidateBeforeArrival(__instance);
					if ((Object)(object)instance.activePlayer == (Object)(object)__instance && ((Character)__instance).IsTeleporting() && !instance.validated && !instance.returning)
					{
						TeleportTimer.Invoke(__instance) = Mathf.Min(TeleportTimer.Invoke(__instance), 4f);
					}
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)instance).Logger.LogError((object)("Landing validation failed: " + ex));
					if ((Object)(object)instance.activePlayer == (Object)(object)__instance && !instance.returning)
					{
						instance.ReturnToOrigin(__instance, "Could not verify a safe landing.");
					}
				}
			}

			private static void Postfix(Player __instance)
			{
				MapTeleportPlugin instance = Instance;
				if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.activePlayer != (Object)(object)__instance) && !((Character)__instance).IsTeleporting())
				{
					Tell(__instance, instance.returning ? "Map teleport cancelled; returned to the starting point." : "Map teleport complete.");
					((BaseUnityPlugin)instance).Logger.LogInfo((object)(instance.returning ? "Map teleport returned to origin." : "Map teleport complete."));
					instance.activePlayer = null;
					instance.activeWorld = null;
					instance.activeMap = null;
				}
			}
		}

		public const string PluginGuid = "kenjorissen.mods.exploredmapteleport";

		public const string PluginName = "Explored Map Teleport";

		public const string PluginVersion = "0.3.0";

		private static MapTeleportPlugin? Instance;

		private static readonly Func<Minimap, Vector3, Vector3> ScreenToWorld = AccessTools.MethodDelegate<Func<Minimap, Vector3, Vector3>>(AccessTools.Method(typeof(Minimap), "ScreenToWorldPoint", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<Minimap, Vector3, bool> IsExplored = AccessTools.MethodDelegate<Func<Minimap, Vector3, bool>>(AccessTools.Method(typeof(Minimap), "IsExplored", (Type[])null, (Type[])null), (object)null, true);

		private static readonly FieldRef<Player, Vector3> TargetPosition = AccessTools.FieldRefAccess<Player, Vector3>("m_teleportTargetPos");

		private static readonly FieldRef<Player, Quaternion> TargetRotation = AccessTools.FieldRefAccess<Player, Quaternion>("m_teleportTargetRot");

		private static readonly FieldRef<Player, float> TeleportTimer = AccessTools.FieldRefAccess<Player, float>("m_teleportTimer");

		private ConfigEntry<bool> enabledSetting;

		private ConfigEntry<float> maxSlope;

		private ConfigEntry<float> maxRadius;

		private ConfigEntry<float> maxWaterDepth;

		private ConfigEntry<bool> searchNearby;

		private ConfigEntry<float> innerRadius;

		private ConfigEntry<float> outerRadius;

		private Harmony? harmony;

		private Toggle? mapToggle;

		private bool armed;

		private Player? activePlayer;

		private WorldGenerator? activeWorld;

		private Minimap? activeMap;

		private Vector3 origin;

		private Quaternion originRotation;

		private Vector3 requested;

		private float startedAt;

		private float nextLandingCheck;

		private bool validated;

		private bool returning;

		private int obstructionMask;

		private void Awake()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Expected O, but got Unknown
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Expected O, but got Unknown
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Expected O, but got Unknown
			Instance = this;
			enabledSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Show the map teleport toggle. The toggle itself always starts OFF.");
			maxSlope = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "MaximumSlopeDegrees", 55f, new ConfigDescription("Maximum landing slope. Steeper ground may cause sliding; existing configured values are retained.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 70f), Array.Empty<object>()));
			maxRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "MaximumWorldRadius", 10000f, new ConfigDescription("Reject destinations at/beyond this radius. Increase only for an expanded world.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 100000f), Array.Empty<object>()));
			maxWaterDepth = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "MaximumWaterDepthMetres", 1f, new ConfigDescription("Maximum water depth above the terrain, measured against the mean water level. Waves may be deeper. Zero restores the original dry-land margin.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			searchNearby = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "SearchNearby", true, "If the clicked point is unsafe, try eight directions on each of two nearby rings. Every centre must be explored and pass all safety checks.");
			innerRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "InnerSearchRadiusMetres", 4f, new ConfigDescription("First search ring radius. The smaller configured radius is always tried first.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 16f), Array.Empty<object>()));
			outerRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "OuterSearchRadiusMetres", 8f, new ConfigDescription("Second search ring radius. Two distinct radii give at most 16 alternatives.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 16f), Array.Empty<object>()));
			obstructionMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "piece", "terrain", "vehicle", "character" });
			harmony = new Harmony("kenjorissen.mods.exploredmapteleport");
			harmony.PatchAll(typeof(MapTeleportPlugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Explored Map Teleport v0.3.0 loaded. Map toggle starts OFF; no XPortalNetworks dependency.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Landing settings: slope={maxSlope.Value:0.#} degrees, water depth={maxWaterDepth.Value:0.#}m, nearby={searchNearby.Value}, rings={innerRadius.Value:0.#}m/{outerRadius.Value:0.#}m.");
		}

		private void OnDestroy()
		{
			Harmony? obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if (Object.op_Implicit((Object)(object)mapToggle))
			{
				Object.Destroy((Object)(object)((Component)mapToggle).gameObject);
			}
			Instance = null;
		}

		private void Update()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Invalid comparison between Unknown and I4
			if (Object.op_Implicit((Object)(object)mapToggle))
			{
				((Component)mapToggle).gameObject.SetActive(enabledSetting.Value);
			}
			if (!enabledSetting.Value || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)Minimap.instance) || (int)Minimap.instance.m_mode != 2)
			{
				SetArmed(value: false);
			}
			if (activePlayer != null && (!Object.op_Implicit((Object)(object)activePlayer) || (Object)(object)activePlayer != (Object)(object)Player.m_localPlayer || activeWorld != WorldGenerator.instance || activeMap != Minimap.instance))
			{
				activePlayer = null;
				activeWorld = null;
				activeMap = null;
			}
		}

		private void CreateToggle(Minimap map)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: 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_00f8: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)mapToggle))
			{
				Object.Destroy((Object)(object)((Component)mapToggle).gameObject);
			}
			if (!Object.op_Implicit((Object)(object)map.m_publicPosition))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Cannot add map toggle: vanilla public-position toggle is missing.");
				return;
			}
			mapToggle = Object.Instantiate<Toggle>(map.m_publicPosition, ((Component)map.m_publicPosition).transform.parent);
			((Object)mapToggle).name = "ExploredMapTeleportToggle";
			mapToggle.group = null;
			mapToggle.onValueChanged = new ToggleEvent();
			Localize[] componentsInChildren = ((Component)mapToggle).GetComponentsInChildren<Localize>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren[i]);
			}
			TMP_Text[] componentsInChildren2 = ((Component)mapToggle).GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].text = "Map teleport (explored)";
			}
			RectTransform val = (RectTransform)((Component)mapToggle).transform;
			val.anchoredPosition += new Vector2(0f, 40f);
			mapToggle.SetIsOnWithoutNotify(false);
			((UnityEvent<bool>)(object)mapToggle.onValueChanged).AddListener((UnityAction<bool>)delegate(bool value)
			{
				armed = enabledSetting.Value && value;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Map teleport toggle " + (armed ? "ON" : "OFF")));
			});
			armed = false;
			((Component)mapToggle).gameObject.SetActive(enabledSetting.Value);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Map teleport toggle added to standard map.");
		}

		private void SetArmed(bool value)
		{
			armed = value;
			if (Object.op_Implicit((Object)(object)mapToggle) && mapToggle.isOn != value)
			{
				mapToggle.SetIsOnWithoutNotify(value);
			}
		}

		private static void Tell(Player player, string message)
		{
			((Character)player).Message((MessageType)2, message, 0, (Sprite)null, false);
		}

		private void RequestTeleport(Minimap map)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)activePlayer) || ((Character)localPlayer).IsTeleporting())
			{
				Tell(localPlayer, "A teleport is already in progress.");
			}
			else if (((Character)localPlayer).IsDead() || ((Character)localPlayer).InCutscene() || ((Character)localPlayer).InInterior() || ((Character)localPlayer).IsAttached() || ((Character)localPlayer).IsAttachedToShip() || localPlayer.GetDoodadController() != null)
			{
				Tell(localPlayer, "Map teleport is unavailable in your current state.");
			}
			else
			{
				if (WorldGenerator.instance == null || !Object.op_Implicit((Object)(object)ZoneSystem.instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance))
				{
					return;
				}
				Vector3 val = ScreenToWorld(map, ZInput.pointerPosition);
				if (!DestinationPolicy.IsValidPoint(val.x, val.z, maxRadius.Value) || !IsExplored(map, val))
				{
					Tell(localPlayer, "Choose an explored location inside the world boundary.");
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Rejected map teleport: unexplored or out-of-bounds destination.");
					return;
				}
				if (!((Humanoid)localPlayer).IsTeleportable(false))
				{
					Tell(localPlayer, "Your inventory contains items that cannot be teleported.");
					return;
				}
				if (!TryLoadingPosition(map, val, out var position))
				{
					Tell(localPlayer, "No suitable ground or shallow water at that point or nearby.");
					return;
				}
				origin = ((Component)localPlayer).transform.position;
				originRotation = ((Component)localPlayer).transform.rotation;
				if (!((Character)localPlayer).TeleportTo(position, originRotation, true))
				{
					Tell(localPlayer, "Teleport unavailable; wait a moment and try again.");
					return;
				}
				requested = val;
				activePlayer = localPlayer;
				activeWorld = WorldGenerator.instance;
				activeMap = map;
				startedAt = Time.realtimeSinceStartup;
				nextLandingCheck = startedAt;
				validated = false;
				returning = false;
				SetArmed(value: false);
				map.SetMapMode((MapMode)1);
				Tell(localPlayer, "Loading destination and checking the landing...");
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"Map teleport requested: ({val.x:0.0}, {val.z:0.0}).");
			}
		}

		private bool EligibleCentre(Minimap map, Vector3 point)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (DestinationPolicy.IsValidPoint(point.x, point.z, maxRadius.Value))
			{
				return IsExplored(map, point);
			}
			return false;
		}

		private bool TryLoadingPosition(Minimap map, Vector3 centre, out Vector3 position)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			Vector3 selected = Vector3.zero;
			LandingResult num = NearbyLandingSearch.Find(centre.x, centre.z, searchNearby.Value, innerRadius.Value, outerRadius.Value, delegate(float x, float z)
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: 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)
				//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val = default(Vector3);
				((Vector3)(ref val))..ctor(x, 0f, z);
				if (!EligibleCentre(map, val))
				{
					return LandingResult.Rejected;
				}
				float num2 = WorldGenerator.instance.GetHeight(x, z);
				float num3 = default(float);
				if (ZoneSystem.instance.GetGroundHeight(val, ref num3))
				{
					num2 = num3;
				}
				if (!DestinationPolicy.IsSafeTerrain(num2, ZoneSystem.instance.m_waterLevel, 1f, maxSlope.Value, maxWaterDepth.Value) || ZoneSystem.IsLavaPreHeightmap(val, 0.6f))
				{
					return LandingResult.Rejected;
				}
				selected = new Vector3(x, Mathf.Max(num2, ZoneSystem.instance.m_waterLevel) + 2f, z);
				return LandingResult.Found;
			});
			position = selected;
			return num == LandingResult.Found;
		}

		private LandingResult CheckLanding(Player player, Vector3 candidate, out Vector3 landing)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			landing = candidate;
			if (!Object.op_Implicit((Object)(object)Minimap.instance) || !EligibleCentre(Minimap.instance, candidate))
			{
				return LandingResult.Rejected;
			}
			if (!ZNetScene.instance.IsAreaReady(candidate) || !ZoneSystem.instance.IsZoneLoaded(candidate))
			{
				return LandingResult.WaitingForLoad;
			}
			Vector3 val = default(Vector3);
			Biome val2 = default(Biome);
			BiomeArea val3 = default(BiomeArea);
			Heightmap val4 = default(Heightmap);
			ZoneSystem.instance.GetGroundData(ref landing, ref val, ref val2, ref val3, ref val4);
			if (!Object.op_Implicit((Object)(object)val4) || !DestinationPolicy.IsSafeTerrain(landing.y, ZoneSystem.instance.m_waterLevel, val.y, maxSlope.Value, maxWaterDepth.Value) || ZoneSystem.instance.IsLava(landing, true))
			{
				return LandingResult.Rejected;
			}
			landing.y += 0.3f;
			Collider[] array = Physics.OverlapCapsule(landing + Vector3.up * 0.5f, landing + Vector3.up * 1.6f, 0.35f, obstructionMask, (QueryTriggerInteraction)1);
			foreach (Collider val5 in array)
			{
				if (Object.op_Implicit((Object)(object)val5) && !((Component)val5).transform.IsChildOf(((Component)player).transform))
				{
					return LandingResult.Rejected;
				}
			}
			return LandingResult.Found;
		}

		private void ValidateBeforeArrival(Player player)
		{
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: 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_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player != (Object)(object)activePlayer || !((Character)player).IsTeleporting() || validated || returning)
			{
				return;
			}
			if (activeWorld != WorldGenerator.instance || activeMap != Minimap.instance)
			{
				activePlayer = null;
				activeWorld = null;
				activeMap = null;
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup - startedAt > 25f)
			{
				ReturnToOrigin(player, "Destination loading timed out.");
			}
			else
			{
				if (!Object.op_Implicit((Object)(object)ZNetScene.instance) || !Object.op_Implicit((Object)(object)ZoneSystem.instance) || realtimeSinceStartup < nextLandingCheck)
				{
					return;
				}
				nextLandingCheck = realtimeSinceStartup + 0.1f;
				Vector3 selected = Vector3.zero;
				switch (NearbyLandingSearch.Find(requested.x, requested.z, searchNearby.Value, innerRadius.Value, outerRadius.Value, delegate(float x, float z)
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_0024: Unknown result type (might be due to invalid IL or missing references)
					//IL_0025: Unknown result type (might be due to invalid IL or missing references)
					Vector3 landing;
					LandingResult num2 = CheckLanding(player, new Vector3(x, 0f, z), out landing);
					if (num2 == LandingResult.Found)
					{
						selected = landing;
					}
					return num2;
				}))
				{
				case LandingResult.WaitingForLoad:
					break;
				default:
					ReturnToOrigin(player, "No safe explored landing at that point or nearby.");
					break;
				case LandingResult.Found:
				{
					TargetPosition.Invoke(player) = selected;
					validated = true;
					float num = Vector2.Distance(new Vector2(requested.x, requested.z), new Vector2(selected.x, selected.z));
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"Landing validated at ({selected.x:0.0}, {selected.y:0.0}, {selected.z:0.0}); nearby offset={num:0.0}m.");
					break;
				}
				}
			}
		}

		private void ReturnToOrigin(Player player, string reason)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			TargetPosition.Invoke(player) = origin;
			TargetRotation.Invoke(player) = originRotation;
			TeleportTimer.Invoke(player) = 0f;
			returning = true;
			((BaseUnityPlugin)this).Logger.LogWarning((object)(reason + " Returning to the starting point."));
			Tell(player, reason + " Returning to your starting point.");
		}
	}
	internal enum LandingResult
	{
		Rejected,
		WaitingForLoad,
		Found
	}
	internal static class NearbyLandingSearch
	{
		private const float Diagonal = 0.70710677f;

		private static readonly float[] X = new float[8] { 1f, 0.70710677f, 0f, -0.70710677f, -1f, -0.70710677f, 0f, 0.70710677f };

		private static readonly float[] Z = new float[8] { 0f, 0.70710677f, 1f, 0.70710677f, 0f, -0.70710677f, -1f, -0.70710677f };

		internal static int CandidateCount(bool nearby, float radiusA, float radiusB)
		{
			if (!nearby || !DestinationPolicy.IsFinite(radiusA) || !DestinationPolicy.IsFinite(radiusB) || radiusA <= 0f || radiusB <= 0f)
			{
				return 1;
			}
			if (radiusA != radiusB)
			{
				return 17;
			}
			return 9;
		}

		internal static bool Offset(int index, bool nearby, float radiusA, float radiusB, out float x, out float z)
		{
			x = (z = 0f);
			int num = CandidateCount(nearby, radiusA, radiusB);
			if (index < 0 || index >= num)
			{
				return false;
			}
			if (index == 0)
			{
				return true;
			}
			float num2 = ((index <= 8) ? Math.Min(radiusA, radiusB) : Math.Max(radiusA, radiusB));
			int num3 = (index - 1) % 8;
			x = X[num3] * num2;
			z = Z[num3] * num2;
			return true;
		}

		internal static LandingResult Find(float originX, float originZ, bool nearby, float radiusA, float radiusB, Func<float, float, LandingResult> check)
		{
			if (!DestinationPolicy.IsFinite(originX) || !DestinationPolicy.IsFinite(originZ))
			{
				return LandingResult.Rejected;
			}
			bool flag = false;
			int num = CandidateCount(nearby, radiusA, radiusB);
			for (int i = 0; i < num; i++)
			{
				Offset(i, nearby, radiusA, radiusB, out var x, out var z);
				LandingResult landingResult = check(originX + x, originZ + z);
				switch (landingResult)
				{
				case LandingResult.Found:
					return landingResult;
				case LandingResult.WaitingForLoad:
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				return LandingResult.Rejected;
			}
			return LandingResult.WaitingForLoad;
		}
	}
}