Decompiled source of EasyRelocate v1.1.1

EasyRelocate.dll

Decompiled 6 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: AssemblyCompany("EasyRelocate")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1")]
[assembly: AssemblyProduct("EasyRelocate")]
[assembly: AssemblyTitle("EasyRelocate")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace EasyRelocate
{
	internal static class CombatInputSuppression
	{
		internal static void ClearCombatInput(Humanoid humanoid)
		{
			if (!((Object)(object)humanoid == (Object)null))
			{
				((Character)humanoid).m_attack = false;
				((Character)humanoid).m_attackHold = false;
				((Character)humanoid).m_secondaryAttack = false;
				((Character)humanoid).m_secondaryAttackHold = false;
				((Character)humanoid).m_blocking = false;
				Player val = (Player)(object)((humanoid is Player) ? humanoid : null);
				if (val != null)
				{
					val.m_queuedAttackTimer = 0f;
					val.m_queuedSecondAttackTimer = 0f;
				}
				humanoid.m_internalBlockingState = false;
				humanoid.m_blockTimer = -1f;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "SetControls")]
	internal static class Player_SetControls_Patch
	{
		private static void Postfix(Player __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && RelocateController.ShouldSuppressCombatInput)
			{
				CombatInputSuppression.ClearCombatInput((Humanoid)(object)__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "StartAttack")]
	internal static class Humanoid_StartAttack_Patch
	{
		private static bool Prefix(Humanoid __instance, ref bool __result)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (RelocateController.ShouldSuppressCombatInput)
			{
				CombatInputSuppression.ClearCombatInput(__instance);
				__result = false;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Player), "PlayerAttackInput")]
	internal static class Player_PlayerAttackInput_Patch
	{
		private static void Prefix(Player __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && RelocateController.ShouldSuppressCombatInput)
			{
				CombatInputSuppression.ClearCombatInput((Humanoid)(object)__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "UpdateBlock")]
	internal static class Humanoid_UpdateBlock_Patch
	{
		private static bool Prefix(Humanoid __instance)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (RelocateController.ShouldSuppressCombatInput)
			{
				CombatInputSuppression.ClearCombatInput(__instance);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(ZInput), "GetMouseScrollWheel")]
	internal static class ZInput_GetMouseScrollWheel_Patch
	{
		private static void Postfix(ref float __result)
		{
			if (RelocateController.IsActive)
			{
				__result = 0f;
			}
		}
	}
	internal static class ColliderPlacement
	{
		private const float ProbeDistance = 50f;

		internal static bool TryResolve(GameObject ghost, Vector3 hitPoint, Vector3 surfaceNormal, Quaternion rotation, out Vector3 position)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			position = hitPoint;
			if ((Object)(object)ghost == (Object)null)
			{
				return false;
			}
			surfaceNormal = ((!(((Vector3)(ref surfaceNormal)).sqrMagnitude < 0.001f)) ? ((Vector3)(ref surfaceNormal)).normalized : Vector3.up);
			Vector3 val = hitPoint + surfaceNormal * 50f;
			ghost.transform.SetPositionAndRotation(val, rotation);
			Collider[] componentsInChildren = ghost.GetComponentsInChildren<Collider>(true);
			Vector3 val2 = hitPoint;
			float num = float.MaxValue;
			bool flag = false;
			Collider[] array = componentsInChildren;
			foreach (Collider val3 in array)
			{
				if ((Object)(object)val3 == (Object)null || !val3.enabled || val3.isTrigger)
				{
					continue;
				}
				MeshCollider val4 = (MeshCollider)(object)((val3 is MeshCollider) ? val3 : null);
				if (val4 == null || val4.convex)
				{
					Vector3 val5 = val3.ClosestPoint(hitPoint);
					float num2 = Vector3.Distance(val5, hitPoint);
					if (num2 < num)
					{
						num = num2;
						val2 = val5;
						flag = true;
					}
				}
			}
			if (!flag)
			{
				return false;
			}
			position = hitPoint + (val - val2);
			return true;
		}
	}
	internal static class ConfigMigration
	{
		private const string LegacyConfigFileName = "dev.modded.pressutorelocate.cfg";

		private const string NewConfigFileName = "ModdedWolf.EasyRelocate.cfg";

		internal static bool TryMigrateLegacyConfig(ManualLogSource logger)
		{
			string configPath = Paths.ConfigPath;
			string text = Path.Combine(configPath, "dev.modded.pressutorelocate.cfg");
			string text2 = Path.Combine(configPath, "ModdedWolf.EasyRelocate.cfg");
			if (!File.Exists(text) || File.Exists(text2))
			{
				return false;
			}
			File.Copy(text, text2);
			if (logger != null)
			{
				logger.LogInfo((object)"Migrated settings from Press U To Relocate config.");
			}
			return true;
		}
	}
	internal static class FreePlacementRotationCompat
	{
		private static readonly string[] TargetTypes = new string[2] { "ValheimPlus.Player_UpdatePlacementGhost_Transpile", "PerfectPlacement.Patches.Player_UpdatePlacementGhost_Transpile" };

		private static bool _attempted;

		internal static void TryApply(Harmony harmony)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			if (!_attempted && harmony != null)
			{
				_attempted = true;
				HarmonyMethod prefix = new HarmonyMethod(typeof(FreePlacementRotationCompat), "GetRotation_Prefix", (Type[])null);
				string[] targetTypes = TargetTypes;
				foreach (string typeName in targetTypes)
				{
					TryPatch(harmony, typeName, prefix);
				}
			}
		}

		private static void TryPatch(Harmony harmony, string typeName, HarmonyMethod prefix)
		{
			try
			{
				Type type = AccessTools.TypeByName(typeName);
				if (type == null)
				{
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(type, "GetRotation", (Type[])null, (Type[])null);
				if (!(methodInfo == null) && !(methodInfo.ReturnType != typeof(Quaternion)) && methodInfo.GetParameters().Length != 0 && !(methodInfo.GetParameters()[0].ParameterType != typeof(Player)))
				{
					harmony.Patch((MethodBase)methodInfo, prefix, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					ManualLogSource log = RelocatePlugin.Log;
					if (log != null)
					{
						log.LogInfo((object)("Free placement rotation compat: patched " + typeName + ".GetRotation"));
					}
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log2 = RelocatePlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)$"Free placement rotation compat: failed to patch {typeName}: {arg}");
				}
			}
		}

		private static bool GetRotation_Prefix(Player __0, ref Quaternion __result)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (!RelocateController.IsMoving || (Object)(object)__0 == (Object)null)
			{
				return true;
			}
			__result = Quaternion.Euler(0f, __0.m_placeRotationDegrees * (float)__0.m_placeRotation, 0f);
			return false;
		}
	}
	internal static class GhostBuilder
	{
		private static readonly Dictionary<Material, float> RippleDistances = new Dictionary<Material, float>();

		internal static GameObject Create(Piece sourcePiece, GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null && (Object)(object)sourcePiece != (Object)null)
			{
				prefab = ((Component)sourcePiece).gameObject;
			}
			if ((Object)(object)prefab == (Object)null)
			{
				return null;
			}
			bool forceDisableInit = ZNetView.m_forceDisableInit;
			bool forceDisableTerrainOps = TerrainOp.m_forceDisableTerrainOps;
			try
			{
				ZNetView.m_forceDisableInit = true;
				TerrainOp.m_forceDisableTerrainOps = true;
				GameObject obj = Object.Instantiate<GameObject>(prefab);
				((Object)obj).name = ((Object)prefab).name;
				PrepareGhost(obj);
				SetValid(obj, valid: true);
				return obj;
			}
			finally
			{
				ZNetView.m_forceDisableInit = forceDisableInit;
				TerrainOp.m_forceDisableTerrainOps = forceDisableTerrainOps;
			}
		}

		internal static void SetValid(GameObject ghost, bool valid)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)ghost == (Object)null))
			{
				Piece component = ghost.GetComponent<Piece>();
				if ((Object)(object)component != (Object)null)
				{
					component.SetInvalidPlacementHeightlight(!valid);
					return;
				}
				Color tint = (valid ? RelocatePlugin.GhostColor.Value : RelocatePlugin.BlockedColor.Value);
				TintRenderers(ghost, tint);
			}
		}

		internal static void DestroyGhost(ref GameObject ghost)
		{
			if ((Object)(object)ghost != (Object)null)
			{
				Object.Destroy((Object)(object)ghost);
				ghost = null;
			}
			RippleDistances.Clear();
		}

		private static void PrepareGhost(GameObject ghost)
		{
			Joint[] componentsInChildren = ghost.GetComponentsInChildren<Joint>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren[i]);
			}
			Rigidbody[] componentsInChildren2 = ghost.GetComponentsInChildren<Rigidbody>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren2[i]);
			}
			FilterGhostColliders(ghost);
			int num = LayerMask.NameToLayer("ghost");
			if (num >= 0)
			{
				Transform[] componentsInChildren3 = ghost.GetComponentsInChildren<Transform>(true);
				for (int i = 0; i < componentsInChildren3.Length; i++)
				{
					((Component)componentsInChildren3[i]).gameObject.layer = num;
				}
			}
			ZNetView[] componentsInChildren4 = ghost.GetComponentsInChildren<ZNetView>(true);
			for (int i = 0; i < componentsInChildren4.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren4[i]);
			}
			MonoBehaviour[] componentsInChildren5 = ghost.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren5)
			{
				if (!((Object)(object)val == (Object)null))
				{
					string name = ((object)val).GetType().Name;
					if (name.Contains("Container") || name.Contains("CraftingStation") || name.Contains("Switch") || name.Contains("Door") || name.Contains("Smelter") || name.Contains("Incinerator") || name.Contains("CookingStation") || name.Contains("Beehive") || name.Contains("Trap") || name.Contains("MineRock") || name.Contains("Hoverable") || name.Contains("WearNTear"))
					{
						Object.Destroy((Object)(object)val);
					}
				}
			}
			Transform val2 = ghost.transform.Find("_GhostOnly");
			if ((Object)(object)val2 != (Object)null)
			{
				((Component)val2).gameObject.SetActive(true);
			}
			CleanupGhostMaterials<MeshRenderer>(ghost);
			CleanupGhostMaterials<SkinnedMeshRenderer>(ghost);
		}

		private static void FilterGhostColliders(GameObject ghost)
		{
			Player localPlayer = Player.m_localPlayer;
			int num = (((Object)(object)localPlayer != (Object)null) ? localPlayer.m_placeRayMask : (-1));
			Collider val = null;
			Collider[] componentsInChildren = ghost.GetComponentsInChildren<Collider>(true);
			foreach (Collider val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					if (val2.enabled = ((1 << ((Component)val2).gameObject.layer) & num) != 0)
					{
						val = val2;
					}
					else if ((Object)(object)val == (Object)null && !val2.isTrigger)
					{
						val = val2;
					}
				}
			}
			if (!((Object)(object)val != (Object)null))
			{
				return;
			}
			bool flag2 = false;
			componentsInChildren = ghost.GetComponentsInChildren<Collider>(true);
			foreach (Collider val3 in componentsInChildren)
			{
				if ((Object)(object)val3 != (Object)null && val3.enabled)
				{
					flag2 = true;
					break;
				}
			}
			if (!flag2)
			{
				val.enabled = true;
			}
		}

		private static void CleanupGhostMaterials<T>(GameObject ghost) where T : Renderer
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			T[] componentsInChildren = ghost.GetComponentsInChildren<T>(true);
			foreach (T val in componentsInChildren)
			{
				if ((Object)(object)((Renderer)val).sharedMaterial == (Object)null)
				{
					continue;
				}
				Material[] sharedMaterials = ((Renderer)val).sharedMaterials;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					Material val2 = sharedMaterials[j];
					if (!((Object)(object)val2 == (Object)null))
					{
						Material val3 = new Material(val2);
						if (val3.HasProperty("_RippleDistance"))
						{
							RippleDistances[val3] = val3.GetFloat("_RippleDistance");
						}
						if (val3.HasProperty("_ValueNoise"))
						{
							val3.SetFloat("_ValueNoise", 0f);
						}
						if (val3.HasProperty("_TriplanarLocalPos"))
						{
							val3.SetFloat("_TriplanarLocalPos", 1f);
						}
						sharedMaterials[j] = val3;
					}
				}
				((Renderer)val).sharedMaterials = sharedMaterials;
				((Renderer)val).shadowCastingMode = (ShadowCastingMode)0;
			}
		}

		private static void TintRenderers(GameObject ghost, Color tint)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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)
			Renderer[] componentsInChildren = ghost.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				Material[] materials = val.materials;
				foreach (Material val2 in materials)
				{
					if (!((Object)(object)val2 == (Object)null))
					{
						Color val3 = tint;
						val3.a = 1f;
						if (val2.HasProperty("_Color"))
						{
							val2.SetColor("_Color", val3);
						}
						if (val2.HasProperty("_BaseColor"))
						{
							val2.SetColor("_BaseColor", val3);
						}
					}
				}
				val.materials = materials;
			}
		}
	}
	[HarmonyPatch(typeof(Location), "IsInsideNoBuildLocation")]
	internal static class Location_IsInsideNoBuildLocation_RelocatePatch
	{
		private static bool Prefix(ref bool __result)
		{
			if (!RelocateController.IsMoving || RelocatePlugin.RequireBuildAccess.Value)
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(PrivateArea), "CheckAccess")]
	internal static class PrivateArea_CheckAccess_RelocatePatch
	{
		private static bool Prefix(ref bool __result)
		{
			if (!RelocateController.IsMoving || RelocatePlugin.RespectWards.Value)
			{
				return true;
			}
			__result = true;
			return false;
		}
	}
	[HarmonyPatch(typeof(Piece), "SetInvalidPlacementHeightlight")]
	internal static class Piece_SetInvalidPlacementHeightlight_RelocatePatch
	{
		private static bool Prefix(Piece __instance, bool enabled)
		{
			if (!RelocateController.IsMoving)
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)((Component)__instance).gameObject != (Object)(object)localPlayer.m_placementGhost)
			{
				return true;
			}
			return !GhostTint.TryApply(((Component)__instance).gameObject, enabled);
		}
	}
	[HarmonyPatch(typeof(PieceTable), "GetSelectedPrefab")]
	internal static class PieceTable_GetSelectedPrefab_RelocatePatch
	{
		private static bool Prefix(PieceTable __instance, ref GameObject __result)
		{
			if ((Object)(object)RelocateController.RelocatePrefab == (Object)null)
			{
				return true;
			}
			if (RelocateController.IsMoving || RelocateController.IsDummyBuildPieces(__instance))
			{
				__result = RelocateController.RelocatePrefab;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
	internal static class Player_UpdatePlacementGhost_OrphanGuardPatch
	{
		private static bool Prefix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.m_placementGhost == (Object)null)
			{
				return true;
			}
			PieceTable buildPieces = __instance.m_buildPieces;
			if (!((Object)(object)buildPieces == (Object)null) && (RelocateController.IsMoving || !RelocateController.IsDummyBuildPieces(buildPieces)))
			{
				return true;
			}
			Object.Destroy((Object)(object)__instance.m_placementGhost);
			__instance.m_placementGhost = null;
			return false;
		}
	}
	internal static class GhostTint
	{
		internal static bool TryApply(GameObject ghost, bool invalid)
		{
			if ((Object)(object)MaterialMan.instance == (Object)null)
			{
				return false;
			}
			try
			{
				Apply(ghost, invalid);
				return true;
			}
			catch (MissingMethodException)
			{
				return false;
			}
		}

		private static void Apply(GameObject ghost, bool invalid)
		{
			//IL_0067: 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)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_0030: 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_0075: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			if (invalid)
			{
				Color val = OpaqueRgb(RelocatePlugin.BlockedColor.Value);
				MaterialMan.instance.SetValue<Color>(ghost, ShaderProps._Color, val, false);
				MaterialMan.instance.SetValue<Color>(ghost, ShaderProps._EmissionColor, val * 0.7f, false);
				return;
			}
			MaterialMan.instance.ResetValue(ghost, ShaderProps._Color);
			MaterialMan.instance.ResetValue(ghost, ShaderProps._EmissionColor);
			Color value = RelocatePlugin.GhostColor.Value;
			if (WantsCustomGhostTint(value))
			{
				value = OpaqueRgb(value);
				MaterialMan.instance.SetValue<Color>(ghost, ShaderProps._Color, value, false);
				MaterialMan.instance.SetValue<Color>(ghost, ShaderProps._EmissionColor, value * 0.7f, false);
			}
		}

		private static Color OpaqueRgb(Color color)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			color.a = 1f;
			return color;
		}

		private static bool WantsCustomGhostTint(Color tint)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			Color val = default(Color);
			((Color)(ref val))..ctor(0.35f, 0.95f, 0.45f, 1f);
			if (!(Mathf.Abs(tint.r - val.r) > 0.001f) && !(Mathf.Abs(tint.g - val.g) > 0.001f))
			{
				return Mathf.Abs(tint.b - val.b) > 0.001f;
			}
			return true;
		}
	}
	internal static class PlacementRay
	{
		internal struct HitInfo
		{
			internal Vector3 Point;

			internal Vector3 Normal;

			internal Piece HitPiece;

			internal Heightmap Heightmap;

			internal Collider HitCollider;

			internal Collider WaterSurface;

			internal bool HasHit;
		}

		private const float PhysicsRayLength = 50f;

		private const float VerticalSurfaceThreshold = 0.5f;

		internal static bool TryCast(Player player, Piece sourcePiece, bool water, out HitInfo hit)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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)
			hit = default(HitInfo);
			if ((Object)(object)player == (Object)null || (Object)(object)GameCamera.instance == (Object)null)
			{
				return false;
			}
			Transform eye = ((Character)player).m_eye;
			if ((Object)(object)eye == (Object)null)
			{
				return false;
			}
			int num = (water ? player.m_placeWaterRayMask : player.m_placeRayMask);
			Vector3 position = ((Component)GameCamera.instance).transform.position;
			Vector3 forward = ((Component)GameCamera.instance).transform.forward;
			float maxEyeDistance = GetMaxEyeDistance(sourcePiece);
			Vector3 position2 = eye.position;
			RaycastHit[] array = Physics.RaycastAll(position, forward, 50f, num, (QueryTriggerInteraction)1);
			if (array == null || array.Length == 0)
			{
				return false;
			}
			Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
			RaycastHit[] array2 = array;
			foreach (RaycastHit rayHit in array2)
			{
				if (IsValidHit(rayHit, position2, maxEyeDistance))
				{
					return TryBuildHitInfo(rayHit, out hit);
				}
			}
			return false;
		}

		internal static bool IsLookingTowardWall(Vector3 lookDirection, Vector3 wallNormal)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (((Vector3)(ref lookDirection)).sqrMagnitude < 0.001f || ((Vector3)(ref wallNormal)).sqrMagnitude < 0.001f)
			{
				return false;
			}
			((Vector3)(ref lookDirection)).Normalize();
			((Vector3)(ref wallNormal)).Normalize();
			return Vector3.Dot(lookDirection, -wallNormal) > 0.55f;
		}

		internal static bool TryProjectOnWallPlane(Player player, Piece sourcePiece, Vector3 planePoint, Vector3 planeNormal, Piece wallPiece, Collider wallCollider, out HitInfo hit)
		{
			//IL_0037: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			hit = default(HitInfo);
			if ((Object)(object)player == (Object)null || (Object)(object)GameCamera.instance == (Object)null)
			{
				return false;
			}
			planeNormal = ((((Vector3)(ref planeNormal)).sqrMagnitude > 0.001f) ? ((Vector3)(ref planeNormal)).normalized : Vector3.zero);
			if (((Vector3)(ref planeNormal)).sqrMagnitude < 0.001f)
			{
				return false;
			}
			Vector3 position = ((Component)GameCamera.instance).transform.position;
			Vector3 forward = ((Component)GameCamera.instance).transform.forward;
			if (!IsLookingTowardWall(forward, planeNormal))
			{
				return false;
			}
			float num = Vector3.Dot(planeNormal, forward);
			if (Mathf.Abs(num) < 0.001f)
			{
				return false;
			}
			float num2 = Vector3.Dot(planePoint - position, planeNormal) / num;
			if (num2 < 0f)
			{
				return false;
			}
			Vector3 val = position + forward * num2;
			if ((Object)(object)((Character)player).m_eye != (Object)null && Vector3.Distance(((Character)player).m_eye.position, val) > GetMaxEyeDistance(sourcePiece))
			{
				return false;
			}
			if ((Object)(object)wallCollider != (Object)null)
			{
				Vector3 val2 = -planeNormal;
				Vector3 val3 = wallCollider.ClosestPoint(val + val2 * 0.5f);
				if (Vector3.Distance(val, val3) > 0.4f)
				{
					return false;
				}
				val = val3;
			}
			hit.Point = val;
			hit.Normal = planeNormal;
			hit.HitPiece = wallPiece;
			hit.HitCollider = wallCollider;
			hit.Heightmap = null;
			hit.WaterSurface = null;
			hit.HasHit = true;
			return true;
		}

		internal static Vector3 ClampToEyeDistance(Player player, Vector3 targetPoint, Piece sourcePiece)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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_0047: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((Character)(player?)).m_eye == (Object)null)
			{
				return targetPoint;
			}
			Vector3 position = ((Character)player).m_eye.position;
			Vector3 val = targetPoint - position;
			float magnitude = ((Vector3)(ref val)).magnitude;
			float maxEyeDistance = GetMaxEyeDistance(sourcePiece);
			if (magnitude <= maxEyeDistance || magnitude < 0.001f)
			{
				return targetPoint;
			}
			return position + val * (maxEyeDistance / magnitude);
		}

		internal static float EyeDistance(Player player, Vector3 point)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((Character)(player?)).m_eye == (Object)null)
			{
				return Vector3.Distance(((Object)(object)player != (Object)null) ? ((Component)player).transform.position : point, point);
			}
			return Vector3.Distance(((Character)player).m_eye.position, point);
		}

		private static float GetMaxEyeDistance(Piece sourcePiece)
		{
			float num = RelocatePlugin.MaxPlaceDistance.Value;
			if ((Object)(object)sourcePiece != (Object)null)
			{
				num += (float)sourcePiece.m_extraPlacementDistance;
			}
			return num;
		}

		private static bool IsValidHit(RaycastHit rayHit, Vector3 eyePosition, float maxEyeDistance)
		{
			//IL_0021: 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)
			Collider collider = ((RaycastHit)(ref rayHit)).collider;
			if ((Object)(object)collider == (Object)null || (Object)(object)collider.attachedRigidbody != (Object)null)
			{
				return false;
			}
			return Vector3.Distance(eyePosition, ((RaycastHit)(ref rayHit)).point) <= maxEyeDistance;
		}

		internal static bool IsWallSurfaceHit(RaycastHit rayHit)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			if (((RaycastHit)(ref rayHit)).normal.y >= 0.5f)
			{
				return false;
			}
			Piece componentInParent = ((Component)((RaycastHit)(ref rayHit)).collider).GetComponentInParent<Piece>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				return ((Component)componentInParent).GetComponentInParent<Hoverable>() == null;
			}
			return (Object)(object)((Component)((RaycastHit)(ref rayHit)).collider).GetComponent<Heightmap>() == (Object)null;
		}

		private static bool TryBuildHitInfo(RaycastHit rayHit, out HitInfo hit)
		{
			//IL_001d: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			hit = default(HitInfo);
			Collider collider = ((RaycastHit)(ref rayHit)).collider;
			if ((Object)(object)collider == (Object)null)
			{
				return false;
			}
			hit.Point = ((RaycastHit)(ref rayHit)).point;
			Vector3 normal = ((RaycastHit)(ref rayHit)).normal;
			Vector3 normal2;
			if (!(((Vector3)(ref normal)).sqrMagnitude > 0.001f))
			{
				normal2 = Vector3.up;
			}
			else
			{
				normal = ((RaycastHit)(ref rayHit)).normal;
				normal2 = ((Vector3)(ref normal)).normalized;
			}
			hit.Normal = normal2;
			hit.HitCollider = collider;
			hit.HitPiece = ((Component)collider).GetComponentInParent<Piece>();
			hit.Heightmap = ((Component)collider).GetComponent<Heightmap>();
			hit.WaterSurface = ((((Component)collider).gameObject.layer == LayerMask.NameToLayer("Water")) ? collider : null);
			hit.HasHit = true;
			return true;
		}
	}
	internal static class PlacementTransform
	{
		private const float VerticalSurfaceThreshold = 0.5f;

		private const float GroundSurfaceOffset = 0.02f;

		internal static bool TryResolve(Piece piece, GameObject ghost, Player player, bool rayHit, Vector3 hitPoint, Vector3 hitNormal, Heightmap heightmap, Collider hitCollider, Quaternion targetRotation, WallPlacement.MountContext mountContext, out Vector3 position, out Quaternion rotation, out Vector3 surfaceNormal)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: 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_00e9: 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_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: 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_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: 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_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: 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_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			position = hitPoint;
			rotation = targetRotation;
			surfaceNormal = ((((Vector3)(ref hitNormal)).sqrMagnitude > 0.001f) ? ((Vector3)(ref hitNormal)).normalized : Vector3.up);
			if (!rayHit || (Object)(object)piece == (Object)null || (Object)(object)player == (Object)null)
			{
				return false;
			}
			if (surfaceNormal.y < 0.5f)
			{
				rotation = targetRotation;
				if ((Object)(object)ghost == (Object)null)
				{
					position = hitPoint + surfaceNormal * 0.02f;
					return true;
				}
				position = WallPlacement.ResolveWallPosition(ghost, hitPoint, surfaceNormal, rotation, hitCollider, mountContext);
				return true;
			}
			if (piece.m_notOnFloor || piece.m_inCeilingOnly)
			{
				return false;
			}
			int num;
			if (!piece.m_groundPiece)
			{
				num = (piece.m_groundOnly ? 1 : 0);
				if (num == 0)
				{
					goto IL_00ee;
				}
			}
			else
			{
				num = 1;
			}
			if ((Object)(object)heightmap != (Object)null)
			{
				surfaceNormal = Vector3.up;
			}
			goto IL_00ee;
			IL_00ee:
			if (num != 0)
			{
				Vector3 worldPos = hitPoint;
				worldPos.y = ((Component)player).transform.position.y + 2f;
				if (RelocateUtils.TryFindFloorY(worldPos, 8f, out var floorY))
				{
					position = new Vector3(hitPoint.x, floorY + 0.02f, hitPoint.z);
					surfaceNormal = Vector3.up;
					rotation = targetRotation;
					return true;
				}
				return false;
			}
			rotation = targetRotation;
			if (surfaceNormal.y >= 0.5f)
			{
				surfaceNormal = Vector3.up;
			}
			if ((Object)(object)ghost != (Object)null && ColliderPlacement.TryResolve(ghost, hitPoint, surfaceNormal, rotation, out var position2))
			{
				position = position2;
				return true;
			}
			position = hitPoint + surfaceNormal * 0.02f;
			if ((Object)(object)heightmap == (Object)null && RelocateUtils.TryFindFloorY(position, 4f, out var floorY2))
			{
				position.y = floorY2 + 0.02f;
			}
			return true;
		}
	}
	internal static class PlacementValidator
	{
		internal static bool IsValid(Piece piece, Player player, Vector3 pos, Quaternion rot, Vector3 normal, Heightmap heightmap, Collider waterSurface, Piece hitPiece, Collider hitCollider, Piece sourcePiece, GameObject ghost)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Invalid comparison between Unknown and I4
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Invalid comparison between Unknown and I4
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)piece == (Object)null || (Object)(object)player == (Object)null)
			{
				return false;
			}
			bool flag = piece.m_notOnFloor || piece.m_inCeilingOnly;
			float num = RelocatePlugin.MaxPlaceDistance.Value;
			if ((Object)(object)sourcePiece != (Object)null)
			{
				num += (float)sourcePiece.m_extraPlacementDistance;
			}
			if (PlacementRay.EyeDistance(player, pos) > num)
			{
				return false;
			}
			if (RelocatePlugin.RequireBuildAccess.Value && Location.IsInsideNoBuildLocation(pos))
			{
				return false;
			}
			if (RelocatePlugin.RespectWards.Value)
			{
				PrivateArea component = ((Component)piece).GetComponent<PrivateArea>();
				float num2 = (((Object)(object)component != (Object)null) ? component.m_radius : 0f);
				bool flag2 = (Object)(object)component != (Object)null;
				if (!PrivateArea.CheckAccess(pos, num2, false, flag2))
				{
					return false;
				}
			}
			WearNTear val = (((Object)(object)hitPiece != (Object)null) ? ((Component)hitPiece).GetComponent<WearNTear>() : null);
			StationExtension component2 = ((Component)piece).GetComponent<StationExtension>();
			if ((Object)(object)component2 != (Object)null && (Object)(object)component2.FindClosestStationInRange(pos) == (Object)null)
			{
				return false;
			}
			if ((Object)(object)component2 != (Object)null && component2.OtherExtensionInRange(piece.m_spaceRequirement))
			{
				return false;
			}
			if (piece.m_waterPiece && (Object)(object)waterSurface == (Object)null)
			{
				return false;
			}
			if (piece.m_noInWater && (Object)(object)waterSurface != (Object)null)
			{
				return false;
			}
			if (piece.m_groundPiece && (Object)(object)heightmap == (Object)null)
			{
				return false;
			}
			if (piece.m_groundOnly && (Object)(object)heightmap == (Object)null)
			{
				return false;
			}
			if (piece.m_cultivatedGroundOnly && ((Object)(object)heightmap == (Object)null || !heightmap.IsCultivated(pos)))
			{
				return false;
			}
			if (piece.m_vegetationGroundOnly)
			{
				bool flag3 = (Object)(object)heightmap == (Object)null;
				if (!flag3)
				{
					Biome biome = heightmap.GetBiome(pos, 0.02f, false);
					float vegetationMask = heightmap.GetVegetationMask(pos);
					flag3 = (((int)biome == 32) ? (vegetationMask > 0.1f) : (vegetationMask < 0.25f));
				}
				if (flag3)
				{
					return false;
				}
			}
			if (piece.m_notOnWood && (Object)(object)hitPiece != (Object)null && (Object)(object)val != (Object)null && ((int)val.m_materialType == 0 || (int)val.m_materialType == 3))
			{
				return false;
			}
			if (piece.m_notOnTiltingSurface && normal.y > 0.5f && normal.y < 0.8f)
			{
				return false;
			}
			if (piece.m_inCeilingOnly && normal.y > -0.5f)
			{
				return false;
			}
			if (flag && normal.y > 0.1f)
			{
				return false;
			}
			if (piece.m_onlyInTeleportArea && !Object.op_Implicit((Object)(object)EffectArea.IsPointInsideArea(pos, (Type)16, 0f)))
			{
				return false;
			}
			if (!piece.m_allowedInDungeons && ((Character)player).InInterior() && !EnvMan.instance.CheckInteriorBuildingOverride() && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)34))
			{
				return false;
			}
			if ((int)piece.m_onlyInBiome != 0 && (Heightmap.FindBiome(pos) & piece.m_onlyInBiome) == 0)
			{
				return false;
			}
			if ((Object)(object)val != (Object)null && !val.m_supports && (Object)(object)hitPiece != (Object)null && (Object)(object)hitPiece != (Object)(object)sourcePiece && (!flag || !IsStructuralPiece(hitPiece)))
			{
				return false;
			}
			if (IsBlockedByOtherPiece(piece, player, sourcePiece, hitPiece, ghost, pos, rot))
			{
				return false;
			}
			if (piece.m_noClipping && (Object)(object)ghost != (Object)null && TestGhostClippingExcluding(player, ghost, 0.2f, hitCollider, hitPiece, sourcePiece))
			{
				return false;
			}
			return true;
		}

		private static bool TestGhostClippingExcluding(Player player, GameObject ghost, float maxDepth, Collider mountCollider, Piece mountPiece, Piece sourcePiece)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			HashSet<Collider> hashSet = new HashSet<Collider>();
			AddExcludedCollider(hashSet, mountCollider);
			AddExcludedCollidersFromPiece(hashSet, mountPiece);
			AddExcludedCollidersFromPiece(hashSet, sourcePiece);
			Collider[] componentsInChildren = ghost.GetComponentsInChildren<Collider>(true);
			if (componentsInChildren == null || componentsInChildren.Length == 0)
			{
				return false;
			}
			Vector3 position = ghost.transform.position;
			Collider[] array = Physics.OverlapSphere(position, 10f, player.m_placeRayMask, (QueryTriggerInteraction)1);
			Collider[] array2 = componentsInChildren;
			Vector3 val3 = default(Vector3);
			float num = default(float);
			foreach (Collider val in array2)
			{
				if ((Object)(object)val == (Object)null || !val.enabled)
				{
					continue;
				}
				Collider[] array3 = array;
				foreach (Collider val2 in array3)
				{
					if (!((Object)(object)val2 == (Object)null) && !val2.isTrigger && !hashSet.Contains(val2) && (!((Object)(object)mountPiece != (Object)null) || !((Component)val2).transform.IsChildOf(((Component)mountPiece).transform)) && (!((Object)(object)sourcePiece != (Object)null) || !((Component)val2).transform.IsChildOf(((Component)sourcePiece).transform)) && Physics.ComputePenetration(val, position, ghost.transform.rotation, val2, ((Component)val2).transform.position, ((Component)val2).transform.rotation, ref val3, ref num) && num > maxDepth)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static void AddExcludedCollider(HashSet<Collider> excluded, Collider collider)
		{
			if (excluded != null && (Object)(object)collider != (Object)null)
			{
				excluded.Add(collider);
			}
		}

		private static void AddExcludedCollidersFromPiece(HashSet<Collider> excluded, Piece piece)
		{
			if (excluded == null || (Object)(object)piece == (Object)null)
			{
				return;
			}
			Collider[] componentsInChildren = ((Component)piece).GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null)
				{
					excluded.Add(val);
				}
			}
		}

		private static bool IsBlockedByOtherPiece(Piece piece, Player player, Piece sourcePiece, Piece hitPiece, GameObject ghost, Vector3 pos, Quaternion rot)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ghost == (Object)null || (Object)(object)player == (Object)null)
			{
				return false;
			}
			player.m_tempPieces.Clear();
			if (player.IsOverlappingOtherPiece(pos, rot, ((Object)ghost).name, player.m_tempPieces, piece.m_allowRotatedOverlap))
			{
				return true;
			}
			int mask = LayerMask.GetMask(new string[1] { "piece" });
			Collider[] array = Physics.OverlapSphere(pos, 0.25f, mask, (QueryTriggerInteraction)1);
			string name = ((Object)ghost).name;
			bool flag = piece.m_notOnFloor || piece.m_inCeilingOnly;
			Collider[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				Piece componentInParent = ((Component)array2[i]).GetComponentInParent<Piece>();
				if (!((Object)(object)componentInParent == (Object)null) && !((Object)(object)componentInParent == (Object)(object)sourcePiece) && !((Object)(object)componentInParent == (Object)(object)hitPiece) && !Utils.CustomStartsWith(((Object)((Component)componentInParent).gameObject).name, name) && !RelocateUtils.IsSamePieceType(piece, componentInParent) && (!flag || !IsStructuralPiece(componentInParent)) && Vector3.Distance(pos, ((Component)componentInParent).transform.position) < 0.05f && (!piece.m_allowRotatedOverlap || Quaternion.Angle(((Component)componentInParent).transform.rotation, rot) > 10f))
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsStructuralPiece(Piece piece)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return false;
			}
			return ((Component)piece).GetComponentInParent<Hoverable>() == null;
		}
	}
	internal static class PortalIndex
	{
		private static readonly List<SectorIndex> TempKeys = new List<SectorIndex>();

		private static readonly List<ZDO> TempReAdd = new List<ZDO>();

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

		internal static bool IsPortal(ZDO zdo)
		{
			if (zdo != null && (Object)(object)Game.instance != (Object)null)
			{
				return Game.instance.PortalPrefabHash.Contains(zdo.GetPrefab());
			}
			return false;
		}

		internal static bool IsLivePortal(ZDOMan man, ZDO zdo)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (zdo != null && !((ZDOID)(ref zdo.m_uid)).IsNone() && man.m_objectsByID.TryGetValue(zdo.m_uid, out var value) && value == zdo)
			{
				return IsPortal(zdo);
			}
			return false;
		}

		private static bool IsLiveIndexedPortal(ZDOMan man, ZDO zdo)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			if (IsLivePortal(man, zdo) && man.m_portalObjects.TryGetValue(zdo.GetSectorIndex(), out var value))
			{
				return ContainsReference(value, zdo);
			}
			return false;
		}

		internal static int HealLinks(Game game)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: 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_0145: Unknown result type (might be due to invalid IL or missing references)
			ZDOMan man = ZDOMan.instance;
			if (man == null || (Object)(object)game == (Object)null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return 0;
			}
			game.m_currentlyConnectingPortals.RemoveAll((ConnectingPortals pair) => !IsLiveIndexedPortal(man, pair.PortalA) || !IsLiveIndexedPortal(man, pair.PortalB));
			int num = 0;
			foreach (ZDO portal in man.GetPortalList())
			{
				ZDOID connectionZDOID = portal.GetConnectionZDOID((ConnectionType)1);
				if (((ZDOID)(ref connectionZDOID)).IsNone())
				{
					continue;
				}
				ZDO zDO = man.GetZDO(connectionZDOID);
				if (zDO != null && !IsLiveIndexedPortal(man, zDO))
				{
					ManualLogSource log = RelocatePlugin.Log;
					if (log != null)
					{
						log.LogWarning((object)(string.Format("Easy Relocate: unlinked portal {0} tag=\"{1}\" at {2:F0} ", portal.m_uid, portal.GetString(ZDOVars.s_tag, ""), portal.GetPosition()) + $"from invalid partner {connectionZDOID} prefab={DescribePrefab(zDO.GetPrefab())} at {zDO.GetPosition():F0}"));
					}
					game.SetConnection(portal, ZDOID.None, false);
					if (zDO.GetConnectionZDOID((ConnectionType)1) == portal.m_uid)
					{
						game.SetConnection(zDO, ZDOID.None, false);
					}
					num++;
				}
			}
			return num;
		}

		private static string DescribePrefab(int hash)
		{
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(hash) : null);
			if (!((Object)(object)val != (Object)null))
			{
				return hash.ToString();
			}
			return ((Object)val).name;
		}

		internal static void Rebucket(ZDO zdo)
		{
			//IL_0020: 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_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_004b: Unknown result type (might be due to invalid IL or missing references)
			ZDOMan instance = ZDOMan.instance;
			if (instance != null && IsPortal(zdo) && !((ZDOID)(ref zdo.m_uid)).IsNone())
			{
				SectorIndex sectorIndex = zdo.GetSectorIndex();
				bool flag = RemoveFromOtherBuckets(instance, zdo, sectorIndex);
				if (!instance.m_portalObjects.TryGetValue(sectorIndex, out var value))
				{
					value = new List<ZDO>();
					instance.m_portalObjects[sectorIndex] = value;
				}
				if (!ContainsReference(value, zdo))
				{
					value.Add(zdo);
					flag = true;
				}
				if (flag)
				{
					instance.DirtyPortalObjects = true;
				}
			}
		}

		internal static int Repair()
		{
			//IL_0067: 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_0073: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			ZDOMan instance = ZDOMan.instance;
			if (instance == null || (Object)(object)Game.instance == (Object)null || instance.m_portalObjects == null)
			{
				return 0;
			}
			int num = 0;
			TempKeys.Clear();
			TempReAdd.Clear();
			TempSeen.Clear();
			TempKeys.AddRange(instance.m_portalObjects.Keys);
			foreach (SectorIndex tempKey in TempKeys)
			{
				List<ZDO> list = instance.m_portalObjects[tempKey];
				for (int num2 = list.Count - 1; num2 >= 0; num2--)
				{
					ZDO val = list[num2];
					bool flag = IsLivePortal(instance, val);
					if (!flag || tempKey.Sector != val.GetSectorIndex().Sector || !TempSeen.Add(val.m_uid))
					{
						list.RemoveAt(num2);
						num++;
						if (flag && tempKey.Sector != val.GetSectorIndex().Sector)
						{
							TempReAdd.Add(val);
						}
					}
				}
				if (list.Count == 0)
				{
					instance.m_portalObjects.Remove(tempKey);
				}
			}
			foreach (ZDO item in TempReAdd)
			{
				Rebucket(item);
			}
			if (num > 0)
			{
				instance.DirtyPortalObjects = true;
				ManualLogSource log = RelocatePlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"Portal index repair: removed {num} stale or misplaced portal entries");
				}
			}
			TempKeys.Clear();
			TempReAdd.Clear();
			TempSeen.Clear();
			return num;
		}

		private static bool RemoveFromOtherBuckets(ZDOMan man, ZDO zdo, SectorIndex keep)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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)
			bool result = false;
			TempKeys.Clear();
			TempKeys.AddRange(man.m_portalObjects.Keys);
			foreach (SectorIndex tempKey in TempKeys)
			{
				if (tempKey.Sector == keep.Sector)
				{
					continue;
				}
				List<ZDO> list = man.m_portalObjects[tempKey];
				for (int num = list.Count - 1; num >= 0; num--)
				{
					ZDO val = list[num];
					if (val == zdo || (val != null && val.m_uid == zdo.m_uid))
					{
						list.RemoveAt(num);
						result = true;
					}
				}
				if (list.Count == 0)
				{
					man.m_portalObjects.Remove(tempKey);
				}
			}
			TempKeys.Clear();
			return result;
		}

		private static bool ContainsReference(List<ZDO> list, ZDO zdo)
		{
			foreach (ZDO item in list)
			{
				if (item == zdo)
				{
					return true;
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(ZDOMan), "AddIfPortal")]
	internal static class ZDOMan_AddIfPortal_RebucketPatch
	{
		private static void Postfix(ZDO zdo, int prefabHash)
		{
			if (!((Object)(object)Game.instance == (Object)null) && Game.instance.PortalPrefabHash.Contains(prefabHash))
			{
				PortalIndex.Rebucket(zdo);
			}
		}
	}
	[HarmonyPatch(typeof(Game), "ConnectPortals")]
	internal static class Game_ConnectPortals_RepairPatch
	{
		private static void Prefix(Game __instance)
		{
			PortalIndex.Repair();
			PortalIndex.HealLinks(__instance);
		}
	}
	[HarmonyPatch(typeof(Game), "FindRandomUnconnectedPortal")]
	internal static class Game_FindRandomUnconnectedPortal_FilterPatch
	{
		private static void Prefix(ref List<ZDO> portals)
		{
			ZDOMan man = ZDOMan.instance;
			if (man == null || portals == null)
			{
				return;
			}
			foreach (ZDO portal in portals)
			{
				if (!PortalIndex.IsLivePortal(man, portal))
				{
					portals = portals.FindAll((ZDO p) => PortalIndex.IsLivePortal(man, p));
					break;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZDOMan), "GetSaveClonePerChunk")]
	internal static class ZDOMan_GetSaveClonePerChunk_RepairPatch
	{
		private static void Prefix()
		{
			PortalIndex.Repair();
		}
	}
	internal static class RelocateApplier
	{
		internal static bool ApplyOwnerRelocate(ZNetView nview, Piece piece, Vector3 position, Quaternion rotation)
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)nview == (Object)null || !nview.IsValid())
			{
				return false;
			}
			RelocateNetwork.EnsureRegistered(nview);
			nview.ClaimOwnership();
			ZDO zDO = nview.GetZDO();
			if (zDO == null || !nview.IsOwner())
			{
				ManualLogSource log = RelocatePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)$"Relocate aborted: could not take ownership of {zDO?.m_uid} (owner {((zDO != null) ? new long?(zDO.GetOwner()) : ((long?)null))})");
				}
				return false;
			}
			ApplyVisual(nview, piece, position, rotation);
			zDO.SetPosition(position);
			zDO.SetRotation(rotation);
			PortalIndex.Rebucket(zDO);
			ZSyncTransform component = ((Component)nview).GetComponent<ZSyncTransform>();
			if ((Object)(object)component != (Object)null)
			{
				((Component)nview).transform.hasChanged = true;
				component.SyncNow();
			}
			Physics.SyncTransforms();
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				RelocateNetwork.BroadcastMoved(zDO.m_uid, position, rotation);
			}
			return true;
		}

		internal static void ApplyRemoteRelocate(ZDO zdo, Vector3 position, Quaternion rotation)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (zdo != null && !zdo.IsOwner())
			{
				zdo.InternalSetPosition(position);
				zdo.m_rotation = ((Quaternion)(ref rotation)).eulerAngles;
				PortalIndex.Rebucket(zdo);
				ZNetView val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.FindInstance(zdo) : null);
				if (!((Object)(object)val == (Object)null) && val.IsValid())
				{
					Piece component = ((Component)val).GetComponent<Piece>();
					ApplyVisual(val, component, position, rotation);
					RefreshSupport(component);
				}
			}
		}

		internal static void RefreshSupport(Piece piece)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return;
			}
			UpdateBedSpawnPoint(piece);
			WearNTear componentInChildren = ((Component)piece).GetComponentInChildren<WearNTear>();
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				Physics.SyncTransforms();
				ResetWearNTearAfterMove(componentInChildren);
				if (!((Object)(object)componentInChildren.m_nview == (Object)null) && componentInChildren.m_nview.IsValid() && componentInChildren.m_nview.IsOwner())
				{
					componentInChildren.UpdateSupport();
					RestoreFullHealth(componentInChildren);
				}
			}
		}

		private static void ResetWearNTearAfterMove(WearNTear wear)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)wear == (Object)null))
			{
				wear.OnPlaced();
				wear.ClearCachedSupport();
				wear.m_colliders = null;
				if ((Object)(object)wear.m_connectedHeightMap != (Object)null)
				{
					wear.m_connectedHeightMap.m_clearConnectedWearNTearCache -= wear.ClearCachedSupport;
				}
				wear.m_connectedHeightMap = Heightmap.FindHeightmap(((Component)wear).transform.position);
				if ((Object)(object)wear.m_connectedHeightMap != (Object)null)
				{
					wear.m_connectedHeightMap.m_clearConnectedWearNTearCache += wear.ClearCachedSupport;
				}
			}
		}

		private static void RestoreFullHealth(WearNTear wear)
		{
			if (!((Object)(object)wear == (Object)null) && !((Object)(object)wear.m_nview == (Object)null) && wear.m_nview.IsValid())
			{
				ZDO zDO = wear.m_nview.GetZDO();
				if (zDO != null && !(zDO.GetFloat(ZDOVars.s_health, wear.m_health) >= wear.m_health))
				{
					zDO.Set(ZDOVars.s_health, wear.m_health);
					wear.m_nview.InvokeRPC(ZNetView.Everybody, "RPC_HealthChanged", new object[1] { wear.m_health });
				}
			}
		}

		private static void UpdateBedSpawnPoint(Piece piece)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)piece == (Object)null || (Object)(object)Game.instance == (Object)null)
			{
				return;
			}
			Bed componentInChildren = ((Component)piece).GetComponentInChildren<Bed>();
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				PlayerProfile playerProfile = Game.instance.GetPlayerProfile();
				if (playerProfile != null && componentInChildren.GetOwner() == playerProfile.GetPlayerID() && !(playerProfile.GetCustomSpawnPoint() != componentInChildren.GetSpawnPoint()))
				{
					playerProfile.SetCustomSpawnPoint(componentInChildren.GetSpawnPoint());
				}
			}
		}

		internal static void ApplyVisual(ZNetView nview, Piece piece, Vector3 position, Quaternion rotation)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)nview == (Object)null || !nview.IsValid())
			{
				return;
			}
			((Component)nview).transform.SetPositionAndRotation(position, rotation);
			if ((Object)(object)piece != (Object)null)
			{
				((Component)piece).transform.SetPositionAndRotation(position, rotation);
			}
			Rigidbody[] componentsInChildren = ((Component)(((Object)(object)piece != (Object)null) ? ((Component)piece).transform : ((Component)nview).transform)).GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					if (!val.isKinematic)
					{
						val.linearVelocity = Vector3.zero;
						val.angularVelocity = Vector3.zero;
					}
					val.position = ((Component)val).transform.position;
					val.rotation = ((Component)val).transform.rotation;
				}
			}
			Physics.SyncTransforms();
		}
	}
	internal static class RelocateCommands
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ConsoleEvent <0>__RemoveHovered;

			public static ConsoleEvent <1>__RemovePortalTarget;
		}

		internal const string RemoveHoveredCommand = "easyrelocate_remove_hovered";

		internal const string RemovePortalTargetCommand = "easyrelocate_remove_portal_target";

		private static bool _registered;

		internal static void Register()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			if (!_registered)
			{
				_registered = true;
				object obj = <>O.<0>__RemoveHovered;
				if (obj == null)
				{
					ConsoleEvent val = RemoveHovered;
					<>O.<0>__RemoveHovered = val;
					obj = (object)val;
				}
				new ConsoleCommand("easyrelocate_remove_hovered", "[Easy Relocate] Admin only: deletes the hovered piece even if it cannot be damaged or removed (stuck portal copies).", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
				object obj2 = <>O.<1>__RemovePortalTarget;
				if (obj2 == null)
				{
					ConsoleEvent val2 = RemovePortalTarget;
					<>O.<1>__RemovePortalTarget = val2;
					obj2 = (object)val2;
				}
				new ConsoleCommand("easyrelocate_remove_portal_target", "[Easy Relocate] Admin only: look at a portal to show what it is linked to; add 'confirm' to delete that linked portal (removes invisible leftover portals).", (ConsoleEvent)obj2, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			}
		}

		private static void RemovePortalTarget(ConsoleEventArgs args)
		{
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: 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_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.LocalPlayerIsAdminOrHost())
			{
				Terminal context = args.Context;
				if (context != null)
				{
					context.AddString("Easy Relocate: admin or host only.");
				}
				return;
			}
			GameObject val = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Humanoid)Player.m_localPlayer).GetHoverObject() : null);
			TeleportWorld val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInParent<TeleportWorld>() : null);
			ZNetView val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<ZNetView>() : null);
			ZDO val4 = (((Object)(object)val3 != (Object)null && val3.IsValid()) ? val3.GetZDO() : null);
			if (val4 == null)
			{
				Terminal context2 = args.Context;
				if (context2 != null)
				{
					context2.AddString("Easy Relocate: look at a portal and run the command again.");
				}
				return;
			}
			ZDOID connectionZDOID = val4.GetConnectionZDOID((ConnectionType)1);
			if (((ZDOID)(ref connectionZDOID)).IsNone())
			{
				Terminal context3 = args.Context;
				if (context3 != null)
				{
					context3.AddString("Easy Relocate: this portal is not linked to anything.");
				}
				return;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(connectionZDOID);
			if (zDO == null)
			{
				ZDOMan.instance.RequestZDO(connectionZDOID);
				Terminal context4 = args.Context;
				if (context4 != null)
				{
					context4.AddString($"Easy Relocate: linked portal {connectionZDOID} is not loaded yet; run the command again in a second.");
				}
				return;
			}
			string text = zDO.GetString(ZDOVars.s_tag, "");
			Vector3 position = zDO.GetPosition();
			bool flag = (Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ZNetScene.instance.FindInstance(zDO) != (Object)null;
			string text2 = $"linked portal {connectionZDOID} tag=\"{text}\" at {position:F0} ({Vector3.Distance(position, val4.GetPosition()):F0}m away)";
			if (flag)
			{
				Terminal context5 = args.Context;
				if (context5 != null)
				{
					context5.AddString("Easy Relocate: " + text2 + " is a real, loaded portal; not deleting it.");
				}
				return;
			}
			if (args.Length < 2 || args[1] != "confirm")
			{
				Terminal context6 = args.Context;
				if (context6 != null)
				{
					context6.AddString("Easy Relocate: " + text2 + ". If no portal stands there, run 'easyrelocate_remove_portal_target confirm' to delete it.");
				}
				return;
			}
			ManualLogSource log = RelocatePlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)string.Format("{0}: deleting {1}, linked from {2}", "easyrelocate_remove_portal_target", text2, val4.m_uid));
			}
			zDO.SetOwner(ZDOMan.GetSessionID());
			ZDOMan.instance.DestroyZDO(zDO);
			PortalIndex.Repair();
			Terminal context7 = args.Context;
			if (context7 != null)
			{
				context7.AddString("Easy Relocate: deleted " + text2 + ". The portal you are looking at will unlink within a few seconds.");
			}
		}

		private static void RemoveHovered(ConsoleEventArgs args)
		{
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.LocalPlayerIsAdminOrHost())
			{
				Terminal context = args.Context;
				if (context != null)
				{
					context.AddString("Easy Relocate: admin or host only.");
				}
				return;
			}
			GameObject val = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Humanoid)Player.m_localPlayer).GetHoverObject() : null);
			ZNetView val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInParent<ZNetView>() : null);
			if ((Object)(object)val2 == (Object)null)
			{
				Terminal context2 = args.Context;
				if (context2 != null)
				{
					context2.AddString("Easy Relocate: nothing hovered. Look at the piece and run the command again.");
				}
				return;
			}
			GameObject gameObject = ((Component)val2).gameObject;
			string text = StripClone(((Object)gameObject).name);
			ZDO zDO = val2.GetZDO();
			if (zDO == null || !val2.IsValid())
			{
				ManualLogSource log = RelocatePlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("easyrelocate_remove_hovered: " + text + " has no network data; destroying local object only"));
				}
				Object.Destroy((Object)(object)gameObject);
				Terminal context3 = args.Context;
				if (context3 != null)
				{
					context3.AddString("Easy Relocate: removed orphaned local " + text + ".");
				}
				return;
			}
			string text2 = zDO.GetString(ZDOVars.s_tag, "");
			ManualLogSource log2 = RelocatePlugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)(string.Format("{0}: object={1} zdo={2} prefabHash={3} ", "easyrelocate_remove_hovered", text, zDO.m_uid, zDO.GetPrefab()) + $"owner={zDO.GetOwner()} tag=\"{text2}\" zdoPos={zDO.GetPosition()} objPos={gameObject.transform.position}"));
			}
			if (zDO.GetPrefab() != StringExtensionMethods.GetStableHashCode(text))
			{
				ZNetScene instance = ZNetScene.instance;
				if ((Object)(object)instance != (Object)null && instance.m_instances.TryGetValue(zDO, out var value) && (Object)(object)value == (Object)(object)val2)
				{
					instance.m_instances.Remove(zDO);
				}
				val2.ResetZDO();
				Object.Destroy((Object)(object)gameObject);
				Terminal context4 = args.Context;
				if (context4 != null)
				{
					context4.AddString("Easy Relocate: " + text + " was bound to another object's data; removed the local copy only.");
				}
			}
			else
			{
				ZDOID uid = zDO.m_uid;
				val2.ClaimOwnership();
				ZNetScene.instance.Destroy(gameObject);
				PortalIndex.Repair();
				Terminal context5 = args.Context;
				if (context5 != null)
				{
					context5.AddString($"Easy Relocate: deleted {text} ({uid}).");
				}
			}
		}

		private static string StripClone(string name)
		{
			if (!name.EndsWith("(Clone)"))
			{
				return name;
			}
			return name.Substring(0, name.Length - "(Clone)".Length).Trim();
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	internal static class Terminal_InitTerminal_RelocateCommandsPatch
	{
		private static void Postfix()
		{
			RelocateCommands.Register();
		}
	}
	internal enum RelocateState
	{
		Idle,
		Moving
	}
	internal class RelocateController : MonoBehaviour
	{
		private RelocateState _state;

		private RelocateVisuals _visuals;

		private readonly VanillaPlacementSession _vanillaPlacement = new VanillaPlacementSession();

		private Piece _sourcePiece;

		private ZNetView _sourceView;

		private Vector3 _originPosition;

		private Quaternion _originRotation;

		private Vector3 _ghostPosition;

		private Quaternion _ghostRotation;

		private bool _placementValid;

		private bool _loggedPlacementError;

		private Player _trackedPlayer;

		private static PieceTable _dummyBuildPieces;

		private PieceTable _savedBuildPieces;

		private bool _assignedDummyBuildPieces;

		internal static float SuppressAttackUntil;

		internal static bool IsMoving { get; private set; }

		internal static bool IsActive { get; private set; }

		internal static GameObject RelocatePrefab { get; private set; }

		internal static bool ShouldSuppressCombatInput
		{
			get
			{
				if (!IsActive)
				{
					return Time.time < SuppressAttackUntil;
				}
				return true;
			}
		}

		internal static bool ShouldSuppressAttack => ShouldSuppressCombatInput;

		private void Awake()
		{
			_visuals = ((Component)this).gameObject.AddComponent<RelocateVisuals>();
			((Component)this).gameObject.AddComponent<RelocateHoverHint>();
		}

		private void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				if ((Object)(object)_trackedPlayer != (Object)null || _state != RelocateState.Idle || IsMoving || IsActive)
				{
					ForceReset();
				}
				_trackedPlayer = null;
				return;
			}
			if ((Object)(object)localPlayer != (Object)(object)_trackedPlayer)
			{
				ForceReset();
				_trackedPlayer = localPlayer;
			}
			if (RelocatePlugin.Enabled.Value && !RelocateUtils.IsTextFieldFocused())
			{
				if (_state == RelocateState.Idle)
				{
					TryBeginRelocate(localPlayer);
				}
				else
				{
					UpdateMoving(localPlayer);
				}
			}
		}

		private void ForceReset()
		{
			_visuals?.Hide();
			RestoreSourceToOrigin();
			Piece sourcePiece = _sourcePiece;
			SourcePieceSuppression.Restore();
			RelocateApplier.RefreshSupport(sourcePiece);
			SuppressAttackUntil = 0f;
			TearDownPlacementSession(_trackedPlayer);
		}

		private void TryBeginRelocate(Player player)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = RelocatePlugin.GrabKey.Value;
			if (!((KeyboardShortcut)(ref value)).IsDown())
			{
				return;
			}
			if (RelocateUtils.IsTextFieldFocused())
			{
				ManualLogSource log = RelocatePlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"Relocate grab ignored: a text field is focused");
				}
				return;
			}
			if (!((Character)player).TakeInput())
			{
				ManualLogSource log2 = RelocatePlugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)"Relocate grab ignored: player is not taking input (menu/inventory/map open?)");
				}
				return;
			}
			if (!RelocateUtils.TryGetHoveredPiece(player, out var piece, out var nview))
			{
				GameObject hoverObject = ((Humanoid)player).GetHoverObject();
				ManualLogSource log3 = RelocatePlugin.Log;
				if (log3 != null)
				{
					log3.LogInfo((object)("Relocate grab ignored: no relocatable hovered piece (hover=" + (((Object)(object)hoverObject != (Object)null) ? ((Object)hoverObject).name : "null") + ")"));
				}
				return;
			}
			if (!RelocateUtils.CanRelocate(player, piece, out var blockedReason))
			{
				ManualLogSource log4 = RelocatePlugin.Log;
				if (log4 != null)
				{
					log4.LogInfo((object)("Relocate grab ignored: " + ((Object)piece).name + " blocked (" + (blockedReason ?? "not relocatable") + ")"));
				}
				return;
			}
			try
			{
				BeginRelocate(player, piece, nview);
				RelocateNetwork.EnsureRegistered(nview);
			}
			catch (Exception arg)
			{
				ManualLogSource log5 = RelocatePlugin.Log;
				if (log5 != null)
				{
					log5.LogError((object)$"Relocate grab threw: {arg}");
				}
				throw;
			}
		}

		private void BeginRelocate(Player player, Piece piece, ZNetView nview)
		{
			//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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			_sourcePiece = piece;
			_sourceView = nview;
			_originPosition = ((Component)piece).transform.position;
			_originRotation = ((Component)piece).transform.rotation;
			GameObject val = ResolvePrefab(nview);
			if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<Piece>() == (Object)null)
			{
				ZDO zDO = nview.GetZDO();
				ManualLogSource log = RelocatePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)($"Relocate failed: object={((Object)piece).name} zdo={zDO?.m_uid} prefabHash={((zDO != null) ? new int?(zDO.GetPrefab()) : ((int?)null))} " + string.Format("resolvedPrefab={0} owner={1} ", ((Object)(object)val != (Object)null) ? ((Object)val).name : "null", (zDO != null) ? new long?(zDO.GetOwner()) : ((long?)null)) + $"zdoPos={((zDO != null) ? new Vector3?(zDO.GetPosition()) : ((Vector3?)null))} objPos={((Component)piece).transform.position}. " + "If this is a stuck copy, an admin can delete it with 'easyrelocate_remove_hovered'."));
				}
				MessageHud instance = MessageHud.instance;
				if (instance != null)
				{
					instance.ShowMessage((MessageType)2, "Relocate failed", 0, (Sprite)null, false, true);
				}
				return;
			}
			ManualLogSource log2 = RelocatePlugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)("Relocate begin: " + ((Object)val).name));
			}
			FreePlacementRotationCompat.TryApply(RelocatePlugin.HarmonyInstance);
			RelocatePrefab = val;
			AssignDummyBuildPieces(player);
			VanillaPlacementSessionPatches.Apply(RelocatePlugin.HarmonyInstance);
			IsMoving = true;
			IsActive = true;
			try
			{
				SourcePieceSuppression.Suppress(piece);
				if (!_vanillaPlacement.Begin(player, val, _originRotation))
				{
					ManualLogSource log3 = RelocatePlugin.Log;
					if (log3 != null)
					{
						log3.LogWarning((object)("Relocate failed: could not create ghost for " + ((Object)val).name));
					}
					SourcePieceSuppression.Restore();
					TearDownPlacementSession(player);
					MessageHud instance2 = MessageHud.instance;
					if (instance2 != null)
					{
						instance2.ShowMessage((MessageType)2, "Relocate failed", 0, (Sprite)null, false, true);
					}
					return;
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log4 = RelocatePlugin.Log;
				if (log4 != null)
				{
					log4.LogWarning((object)$"Relocate failed for {((Object)val).name}: {arg}");
				}
				SourcePieceSuppression.Restore();
				TearDownPlacementSession(player);
				MessageHud instance3 = MessageHud.instance;
				if (instance3 != null)
				{
					instance3.ShowMessage((MessageType)2, "Relocate failed", 0, (Sprite)null, false, true);
				}
				return;
			}
			_ghostPosition = _originPosition;
			_ghostRotation = _originRotation;
			_placementValid = true;
			_state = RelocateState.Moving;
			Hud.HidePieceSelection();
			_visuals.Show(_originPosition, _ghostPosition);
			KeyboardShortcut value = RelocatePlugin.GrabKey.Value;
			string text = ((object)((KeyboardShortcut)(ref value)).MainKey/*cast due to .constrained prefix*/).ToString().ToUpperInvariant();
			MessageHud instance4 = MessageHud.instance;
			if (instance4 != null)
			{
				instance4.ShowMessage((MessageType)2, "Relocate: aim and left-click to place, right-click or " + text + " to cancel", 0, (Sprite)null, false, true);
			}
		}

		private void UpdateMoving(Player player)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			SuppressAttackUntil = Time.time + 0.75f;
			HandleRotationInput(player);
			UpdateGhostFromVanilla(player);
			UpdateVisuals();
			if (Input.GetMouseButtonDown(0))
			{
				if (_placementValid)
				{
					SuppressAttackUntil = Time.time + 0.75f;
					ApplyRelocate(player);
					return;
				}
				ManualLogSource log = RelocatePlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"Relocate place blocked: placement status {player.GetPlacementStatus()}");
				}
			}
			if (!Input.GetMouseButtonDown(1))
			{
				KeyboardShortcut value = RelocatePlugin.GrabKey.Value;
				if (!((KeyboardShortcut)(ref value)).IsDown())
				{
					return;
				}
			}
			SuppressAttackUntil = Time.time + 0.75f;
			CancelRelocate();
		}

		private void HandleRotationInput(Player player)
		{
			float axis = Input.GetAxis("Mouse ScrollWheel");
			if (!(Mathf.Abs(axis) < 0.001f))
			{
				if (axis > 0f)
				{
					player.m_placeRotation++;
				}
				else
				{
					player.m_placeRotation--;
				}
			}
		}

		private void UpdateGhostFromVanilla(Player player)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			if (!IsSourceStillValid())
			{
				AbortRelocate();
				return;
			}
			GameObject placementGhost = player.m_placementGhost;
			if ((Object)(object)placementGhost == (Object)null)
			{
				ManualLogSource log = RelocatePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"Relocate cancelled: placement ghost was removed by another mod or the game");
				}
				CancelRelocate();
				return;
			}
			try
			{
				player.UpdatePlacementGhost(false);
			}
			catch (Exception arg)
			{
				if (!_loggedPlacementError)
				{
					_loggedPlacementError = true;
					ManualLogSource log2 = RelocatePlugin.Log;
					if (log2 != null)
					{
						log2.LogWarning((object)$"UpdatePlacementGhost threw during relocate: {arg}");
					}
				}
				_placementValid = false;
				return;
			}
			_ghostPosition = placementGhost.transform.position;
			_ghostRotation = placementGhost.transform.rotation;
			_placementValid = (int)player.GetPlacementStatus() == 0;
		}

		private void AssignDummyBuildPieces(Player player)
		{
			if (!((Object)(object)player == (Object)null) && !_assignedDummyBuildPieces)
			{
				PieceTable orCreateDummyBuildPieces = GetOrCreateDummyBuildPieces();
				if ((Object)(object)player.m_buildPieces == (Object)(object)orCreateDummyBuildPieces)
				{
					_savedBuildPieces = null;
					_assignedDummyBuildPieces = true;
				}
				else
				{
					_savedBuildPieces = player.m_buildPieces;
					player.m_buildPieces = orCreateDummyBuildPieces;
					_assignedDummyBuildPieces = true;
				}
			}
		}

		private void RestoreBuildPieces(Player player)
		{
			if (_assignedDummyBuildPieces)
			{
				if ((Object)(object)player != (Object)null && (Object)(object)player.m_buildPieces == (Object)(object)GetOrCreateDummyBuildPieces())
				{
					player.m_buildPieces = _savedBuildPieces;
				}
				_savedBuildPieces = null;
				_assignedDummyBuildPieces = false;
			}
		}

		private static PieceTable GetOrCreateDummyBuildPieces()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_dummyBuildPieces != (Object)null)
			{
				return _dummyBuildPieces;
			}
			GameObject val = new GameObject("EasyRelocate_DummyPieceTable");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			_dummyBuildPieces = val.AddComponent<PieceTable>();
			return _dummyBuildPieces;
		}

		private static GameObject ResolvePrefab(ZNetView nview)
		{
			if (((nview != null) ? nview.GetZDO() : null) == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return null;
			}
			return ZNetScene.instance.GetPrefab(nview.GetZDO().GetPrefab());
		}

		private void UpdateVisuals()
		{
			//IL_001e: 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 ((Object)(object)_visuals != (Object)null && _state == RelocateState.Moving)
			{
				_visuals.Show(_originPosition, _ghostPosition);
			}
		}

		private void ApplyRelocate(Player player)
		{
			//IL_001c: 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)
			if (!IsSourceStillValid())
			{
				AbortRelocate();
				return;
			}
			if (!RelocateApplier.ApplyOwnerRelocate(_sourceView, _sourcePiece, _ghostPosition, _ghostRotation))
			{
				MessageHud instance = MessageHud.instance;
				if (instance != null)
				{
					instance.ShowMessage((MessageType)2, "Relocate failed", 0, (Sprite)null, false, true);
				}
				EndRelocate(player);
				return;
			}
			SourcePieceSuppression.Restore();
			RelocateApplier.RefreshSupport(_sourcePiece);
			MessageHud instance2 = MessageHud.instance;
			if (instance2 != null)
			{
				instance2.ShowMessage((MessageType)2, "Relocated", 0, (Sprite)null, false, true);
			}
			EndRelocate(player, restoreSuppression: false);
		}

		private void CancelRelocate()
		{
			MessageHud instance = MessageHud.instance;
			if (instance != null)
			{
				instance.ShowMessage((MessageType)2, "Relocate cancelled", 0, (Sprite)null, false, true);
			}
			EndRelocate(Player.m_localPlayer);
		}

		private void AbortRelocate()
		{
			EndRelocate(Player.m_localPlayer);
		}

		private bool IsSourceStillValid()
		{
			if ((Object)(object)_sourcePiece != (Object)null && (Object)(object)_sourceView != (Object)null)
			{
				return _sourceView.IsValid();
			}
			return false;
		}

		private void EndRelocate(Player player, bool restoreSuppression = true)
		{
			if (restoreSuppression)
			{
				RestoreSourceToOrigin();
				SourcePieceSuppression.Restore();
				RelocateApplier.RefreshSupport(_sourcePiece);
			}
			_visuals?.Hide();
			TearDownPlacementSession(player);
			if ((Object)(object)player != (Object)null)
			{
				Hud.HidePieceSelection();
			}
		}

		private void TearDownPlacementSession(Player player)
		{
			VanillaPlacementSessionPatches.Remove(RelocatePlugin.HarmonyInstance);
			Player player2 = player ?? _trackedPlayer;
			_vanillaPlacement.EndGhost(player2);
			IsMoving = false;
			IsActive = false;
			RelocatePrefab = null;
			RestoreBuildPieces(player2);
			_vanillaPlacement.RebuildHammerGhostIfNeeded(player2);
			ResetState();
		}

		internal static bool IsDummyBuildPieces(PieceTable table)
		{
			if ((Object)(object)table != (Object)null)
			{
				return (Object)(object)table == (Object)(object)_dummyBuildPieces;
			}
			return false;
		}

		private void RestoreSourceToOrigin()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_sourceView == (Object)null) && _sourceView.IsValid())
			{
				RelocateApplier.ApplyOwnerRelocate(_sourceView, _sourcePiece, _originPosition, _originRotation);
			}
		}

		private void ResetState()
		{
			_state = RelocateState.Idle;
			IsMoving = false;
			IsActive = false;
			_sourcePiece = null;
			_sourceView = null;
			RelocatePrefab = null;
			_placementValid = false;
		}

		private void OnDestroy()
		{
			ForceReset();
		}
	}
	internal class RelocateHoverHint : MonoBehaviour
	{
		private const string RelocateMarker = "Relocate";

		private void LateUpdate()
		{
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			if (!RelocatePlugin.Enabled.Value || !RelocatePlugin.ShowHoverHint.Value || RelocateUtils.IsTextFieldFocused() || (Object)(object)Hud.instance == (Object)null || (Object)(object)Hud.instance.m_hoverName == (Object)null)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || RelocateController.IsMoving || !RelocateUtils.TryGetHoveredPiece(localPlayer, out var piece, out var _) || !RelocateUtils.CanRelocate(localPlayer, piece, out var _))
			{
				return;
			}
			string text = Localization.instance.Localize(RelocateUtils.GetRelocateHoverLine());
			string text2 = ((TMP_Text)Hud.instance.m_hoverName).text ?? string.Empty;
			if (!text2.Contains("Relocate"))
			{
				if (string.IsNullOrEmpty(text2))
				{
					string text3 = ((!string.IsNullOrEmpty(piece.m_name)) ? Localization.instance.Localize(piece.m_name) : ((Object)piece).name);
					((TMP_Text)Hud.instance.m_hoverName).text = text3 + "\n" + text;
				}
				else
				{
					((TMP_Text)Hud.instance.m_hoverName).text = text2 + "\n" + text;
				}
				((Graphic)Hud.instance.m_crosshair).color = Color.yellow;
			}
		}
	}
	internal static class RelocateNetwork
	{
		internal const string RpcName = "PressURelocate";

		internal const string MovedRpcName = "EasyRelocate_Moved";

		private const float ForceSendTimeout = 10f;

		private static readonly HashSet<int> RegisteredViews = new HashSet<int>();

		private static ZRoutedRpc _registeredRouter;

		internal static void EnsureRegistered(ZNetView nview)
		{
			if ((Object)(object)nview == (Object)null || !nview.IsValid())
			{
				return;
			}
			int instanceID = ((Object)nview).GetInstanceID();
			if (!RegisteredViews.Add(instanceID))
			{
				return;
			}
			nview.Register<Vector3, Quaternion>("PressURelocate", (Action<long, Vector3, Quaternion>)delegate(long sender, Vector3 position, Quaternion rotation)
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				if (nview.IsValid())
				{
					RelocateApplier.ApplyRemoteRelocate(nview.GetZDO(), position, rotation);
				}
			});
		}

		internal static void RegisterRouted()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance !=