Decompiled source of MoveBuildPieces v1.1.1

MoveBuildPieces.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Obelisk.MoveBuildPieces;

[BepInPlugin("obelisk.valheim.movebuildpieces", "MoveBuildPieces", "1.1.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class MoveBuildPiecesPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "obelisk.valheim.movebuildpieces";

	public const string PluginName = "MoveBuildPieces";

	public const string PluginVersion = "1.1.1";

	private static ConfigEntry<bool> _enabled;

	private static ConfigEntry<MoveActivationMode> _moveMode;

	private static ConfigEntry<KeyboardShortcut> _buildModeMoveHotkey;

	private static ConfigEntry<KeyboardShortcut> _worldModeMoveHotkey;

	private static ConfigEntry<KeyboardShortcut> _mixedModeMoveHotkey;

	private static ConfigEntry<bool> _requireKnownPiece;

	private static ConfigEntry<bool> _blockTerrainModifiers;

	private static ConfigEntry<bool> _blockDynamicObjects;

	private static ConfigEntry<float> _moveLockTimeoutSeconds;

	private Harmony _harmony;

	internal static bool IsEnabled => _enabled.Value;

	internal static MoveActivationMode ActiveMode => _moveMode.Value;

	internal static KeyboardShortcut BuildModeMoveHotkey => _buildModeMoveHotkey.Value;

	internal static KeyboardShortcut WorldModeMoveHotkey => _worldModeMoveHotkey.Value;

	internal static KeyboardShortcut MixedModeMoveHotkey => _mixedModeMoveHotkey.Value;

	internal static bool RequireKnownPiece => MoveController.ResolveRequireKnownPiece(_requireKnownPiece.Value);

	internal static bool BlockTerrainModifiers => MoveController.ResolveBlockTerrainModifiers(_blockTerrainModifiers.Value);

	internal static bool BlockDynamicObjects => MoveController.ResolveBlockDynamicObjects(_blockDynamicObjects.Value);

	internal static float MoveLockTimeoutSeconds
	{
		get
		{
			float value = _moveLockTimeoutSeconds.Value;
			return MoveController.ResolveMoveLockTimeout((float.IsNaN(value) || float.IsInfinity(value)) ? 45f : Mathf.Clamp(value, 5f, 300f));
		}
	}

	private void Awake()
	{
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: 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_015a: Expected O, but got Unknown
		_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable moving already built player-built pieces.");
		_moveMode = ((BaseUnityPlugin)this).Config.Bind<MoveActivationMode>("General", "Move mode", MoveActivationMode.Mixed, "Choose whether moving works in build mode, world mode, or both through Mixed mode.");
		_buildModeMoveHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "Build mode move hotkey", new KeyboardShortcut((KeyCode)117, Array.Empty<KeyCode>()), "Press while hovering a buildable player-built piece in build mode to start or cancel moving it.");
		_worldModeMoveHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "World mode move hotkey", new KeyboardShortcut((KeyCode)117, Array.Empty<KeyCode>()), "Press while hovering a buildable player-built piece outside build mode to start or cancel moving it.");
		_mixedModeMoveHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "Mixed mode move hotkey", new KeyboardShortcut((KeyCode)117, Array.Empty<KeyCode>()), "Press in or outside build mode to start or cancel moving a piece while Move mode is Mixed.");
		_requireKnownPiece = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "Require known piece", false, "Only allow moving pieces the player has learned. Disable to move player-built pieces before learning their recipes.");
		_blockTerrainModifiers = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "Block terrain modifiers", true, "Do not move pieces that contain TerrainModifier or TerrainOp components.");
		_blockDynamicObjects = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "Block dynamic objects", true, "Do not move ships, carts, characters, or pieces with non-kinematic rigidbodies.");
		_moveLockTimeoutSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "Move lock timeout seconds", 45f, "How long a move lock can survive without being released, used as a multiplayer disconnect safety net.");
		MoveController.Initialize();
		_harmony = new Harmony("obelisk.valheim.movebuildpieces");
		_harmony.PatchAll();
		AAABuildMenuCompatibility.Apply(_harmony);
	}

	private void OnDestroy()
	{
		MoveController.Reset();
		Harmony harmony = _harmony;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
	}
}
internal enum MoveActivationMode
{
	BuildMenu,
	World,
	Mixed
}
[HarmonyPatch(typeof(Player), "Update")]
internal static class PlayerUpdatePatch
{
	private static void Postfix(Player __instance)
	{
		MoveController.Update(__instance);
	}
}
[HarmonyPatch(typeof(Player), "UpdatePlacement")]
internal static class PlayerUpdatePlacementPatch
{
	private static bool Prefix(Player __instance)
	{
		return !MoveController.ShouldSkipVanillaUpdatePlacement(__instance);
	}
}
[HarmonyPatch(typeof(Player), "LateUpdate")]
internal static class PlayerLateUpdatePatch
{
	private static void Postfix(Player __instance)
	{
		MoveController.UpdateVisuals(__instance);
	}
}
[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
internal static class PlayerUpdatePlacementGhostPatch
{
	private static bool Prefix(Player __instance)
	{
		return MoveController.ShouldRunPlacementGhostUpdate(__instance);
	}

	private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
	{
		MethodInfo overlapSphereWithMask = AccessTools.Method(typeof(Physics), "OverlapSphere", new Type[3]
		{
			typeof(Vector3),
			typeof(float),
			typeof(int)
		}, (Type[])null);
		MethodInfo filteredOverlapSphereWithMask = AccessTools.Method(typeof(PlacementPhysicsBridge), "OverlapSphere", new Type[3]
		{
			typeof(Vector3),
			typeof(float),
			typeof(int)
		}, (Type[])null);
		MethodInfo overlapSphere = AccessTools.Method(typeof(Physics), "OverlapSphere", new Type[2]
		{
			typeof(Vector3),
			typeof(float)
		}, (Type[])null);
		MethodInfo filteredOverlapSphere = AccessTools.Method(typeof(PlacementPhysicsBridge), "OverlapSphere", new Type[2]
		{
			typeof(Vector3),
			typeof(float)
		}, (Type[])null);
		foreach (CodeInstruction instruction in instructions)
		{
			if (instruction.opcode == OpCodes.Call && object.Equals(instruction.operand, overlapSphereWithMask))
			{
				instruction.operand = filteredOverlapSphereWithMask;
			}
			else if (instruction.opcode == OpCodes.Call && object.Equals(instruction.operand, overlapSphere))
			{
				instruction.operand = filteredOverlapSphere;
			}
			yield return instruction;
		}
	}
}
[HarmonyPatch(typeof(Player), "TestGhostClipping")]
internal static class PlayerTestGhostClippingPatch
{
	private static bool Prefix(Player __instance, GameObject ghost, float maxPenetration, ref bool __result)
	{
		return !MoveController.TryTestGhostClippingIgnoringMovedPiece(__instance, ghost, maxPenetration, out __result);
	}
}
[HarmonyPatch(typeof(Player), "IsOverlappingOtherPiece")]
internal static class PlayerPieceOverlapPatch
{
	private static bool Prefix(Player __instance, Vector3 p, Quaternion rotation, string pieceName, List<Piece> pieces, bool allowRotatedOverlap, ref bool __result)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		return !MoveController.TryEvaluatePieceOverlapIgnoringMovedPiece(__instance, p, rotation, pieceName, pieces, allowRotatedOverlap, out __result);
	}
}
[HarmonyPatch(typeof(StationExtension), "OtherExtensionInRange")]
internal static class StationExtensionRangePatch
{
	private static bool Prefix(StationExtension __instance, float radius, ref bool __result)
	{
		return !MoveController.TryEvaluateExtensionRangeIgnoringMovedPiece(__instance, radius, out __result);
	}
}
[HarmonyPatch(typeof(Player), "SetControls")]
internal static class PlayerSetControlsPatch
{
	private static void Prefix(Player __instance, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold)
	{
		MoveController.SuppressAttackControls(__instance, ref attack, ref attackHold, ref secondaryAttack, ref secondaryAttackHold);
	}
}
[HarmonyPatch(typeof(Player), "TeleportTo")]
internal static class PlayerTeleportToPatch
{
	private static void Prefix(Player __instance)
	{
		MoveController.CancelForTeleport(__instance);
	}
}
[HarmonyPatch(typeof(Player), "OnDeath")]
internal static class PlayerOnDeathPatch
{
	private static void Prefix(Player __instance)
	{
		MoveController.CancelForDeath(__instance);
	}
}
[HarmonyPatch(typeof(Player), "OnDestroy")]
internal static class PlayerOnDestroyPatch
{
	private static void Prefix(Player __instance)
	{
		MoveController.CancelForPlayerDestroyed(__instance);
	}
}
[HarmonyPatch(typeof(Door), "Interact")]
internal static class DoorInteractPatch
{
	private static void Postfix(Humanoid character, bool hold, bool __result)
	{
		if (__result && !hold)
		{
			Player val = (Player)(object)((character is Player) ? character : null);
			if (val != null)
			{
				MoveController.NotifyDoorInteracted(val);
			}
		}
	}
}
[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
{
	typeof(Piece),
	typeof(RequirementMode)
})]
internal static class PlayerHaveRequirementsPatch
{
	private static bool Prefix(Player __instance, Piece piece, RequirementMode mode, ref bool __result)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		if (MoveController.ShouldBypassRequirements(__instance, piece, mode))
		{
			__result = true;
			return false;
		}
		return true;
	}
}
[HarmonyPatch(typeof(PieceTable), "UpdateAvailable", new Type[]
{
	typeof(HashSet<string>),
	typeof(Player),
	typeof(bool),
	typeof(bool)
})]
internal static class PieceTableUpdateAvailablePatch
{
	private static bool Prefix(PieceTable __instance)
	{
		return !MoveController.IsTemporaryPieceTable(__instance);
	}
}
[HarmonyPatch(typeof(Player), "TryPlacePiece")]
internal static class PlayerTryPlacePiecePatch
{
	private static bool Prefix(Player __instance, Piece piece, ref bool __result)
	{
		if (!MoveController.ShouldHandlePlacement(__instance))
		{
			return true;
		}
		__result = false;
		MoveController.TryFinishMove(__instance);
		return false;
	}
}
[HarmonyPatch(typeof(Player), "RemovePiece")]
internal static class PlayerRemovePiecePatch
{
	private static bool Prefix(Player __instance, ref bool __result)
	{
		if (!MoveController.ShouldBlockBuildAction(__instance))
		{
			return true;
		}
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(Player), "CopyPiece")]
internal static class PlayerCopyPiecePatch
{
	private static bool Prefix(Player __instance, ref bool __result)
	{
		if (!MoveController.ShouldBlockBuildAction(__instance))
		{
			return true;
		}
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(ZRoutedRpc), "RPC_RoutedRPC")]
internal static class RoutedRpcSenderValidationPatch
{
	private static bool Prefix(ZRoutedRpc __instance, ZRpc rpc, ZPackage pkg)
	{
		return MoveController.ValidateRoutedRpcSender(__instance, rpc, pkg);
	}
}
[HarmonyPatch(typeof(ZNet), "Awake")]
internal static class ZNetAwakePatch
{
	private static void Postfix(ZNet __instance)
	{
		MoveController.OnNetworkStarted(__instance);
	}
}
[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
internal static class ZNetNewConnectionPatch
{
	private static void Postfix(ZNetPeer peer)
	{
		MoveController.RegisterNetworkPeer(peer);
	}
}
[HarmonyPatch(typeof(ZNet), "OnDestroy")]
internal static class ZNetDestroyPatch
{
	private static void Prefix(ZNet __instance)
	{
		MoveController.OnNetworkStopped(__instance);
	}
}
[HarmonyPatch(typeof(ZNet), "Disconnect")]
internal static class ZNetDisconnectPatch
{
	private static void Prefix(ZNetPeer peer)
	{
		MoveController.UnregisterNetworkPeer(peer);
	}
}
[HarmonyPatch(typeof(ZNetScene), "Shutdown")]
internal static class ZNetSceneShutdownPatch
{
	private static void Prefix()
	{
		MoveController.PrepareForNetworkShutdown();
	}
}
internal sealed class MovePieceTableMarker : MonoBehaviour
{
}
internal static class AAABuildMenuCompatibility
{
	internal const string PluginGuid = "Azumatt.AAABuildMenu";

	private const string EnhancedBuildMenuTypeName = "AAABuildMenu.EnhancedBuildMenu";

	private static PropertyInfo _needsRefreshProperty;

	internal static void Apply(Harmony harmony)
	{
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Expected O, but got Unknown
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Expected O, but got Unknown
		_needsRefreshProperty = null;
		if (harmony == null || !Chainloader.PluginInfos.ContainsKey("Azumatt.AAABuildMenu"))
		{
			return;
		}
		Type type = AccessTools.TypeByName("AAABuildMenu.EnhancedBuildMenu");
		if (type == null)
		{
			Debug.LogWarning((object)"[MoveBuildPieces] AAABuildMenu is installed, but its enhanced menu type was not found; compatibility mode was not enabled.");
			return;
		}
		MethodInfo methodInfo = AccessTools.Method(type, "ApplyFilter", new Type[3]
		{
			typeof(Player),
			typeof(PieceTable),
			typeof(bool)
		}, (Type[])null);
		MethodInfo methodInfo2 = AccessTools.Method(type, "CaptureMasterAndApply", new Type[2]
		{
			typeof(Player),
			typeof(PieceTable)
		}, (Type[])null);
		MethodInfo methodInfo3 = AccessTools.Method(typeof(AAABuildMenuCompatibility), "AllowPieceTableMutation", (Type[])null, (Type[])null);
		if (methodInfo == null || methodInfo3 == null)
		{
			Debug.LogWarning((object)"[MoveBuildPieces] AAABuildMenu is installed, but its filter API was not found; compatibility mode was not enabled.");
			return;
		}
		try
		{
			_needsRefreshProperty = AccessTools.Property(type, "NeedsRefresh");
			HarmonyMethod val = new HarmonyMethod(methodInfo3);
			harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			if (methodInfo2 != null)
			{
				harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(methodInfo3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			Debug.Log((object)"[MoveBuildPieces] AAABuildMenu compatibility enabled.");
		}
		catch (Exception ex)
		{
			Debug.LogWarning((object)("[MoveBuildPieces] AAABuildMenu compatibility failed: " + ex.GetBaseException().Message));
		}
	}

	private static bool AllowPieceTableMutation(object[] __args)
	{
		PieceTable table = null;
		if (__args != null)
		{
			foreach (object obj in __args)
			{
				PieceTable val = (PieceTable)((obj is PieceTable) ? obj : null);
				if (val != null)
				{
					table = val;
					break;
				}
			}
		}
		if (!MoveController.IsTemporaryPieceTable(table))
		{
			return true;
		}
		try
		{
			PropertyInfo needsRefreshProperty = _needsRefreshProperty;
			if ((object)needsRefreshProperty != null && needsRefreshProperty.CanWrite)
			{
				_needsRefreshProperty.SetValue(null, false, null);
			}
		}
		catch
		{
		}
		return false;
	}
}
public static class PlacementPhysicsBridge
{
	public static Collider[] OverlapSphere(Vector3 position, float radius)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		return MoveController.FilterPlacementOverlap(Physics.OverlapSphere(position, radius));
	}

	public static Collider[] OverlapSphere(Vector3 position, float radius, int layerMask)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		return MoveController.FilterPlacementOverlap(Physics.OverlapSphere(position, radius, layerMask));
	}
}
internal static class MoveController
{
	private enum MoveContext
	{
		Build,
		World
	}

	private sealed class MoveState
	{
		public Player Player;

		public Piece Piece;

		public ZNetView NetView;

		public string PrefabName;

		public MoveContext Context;

		public MoveActivationMode ActivationMode;

		public GameObject RelocateTableObject;

		public PieceTable OriginalBuildPieces;

		public PieceTable ActivePieceTable;

		public Vector3 OriginalPosition;

		public List<EffectArea> OriginalBuildAreas;

		public long LockPlayerId;

		public long LockPeerId;

		public long LockToken;

		public long LockOwnerPeerId;

		public long LockRequestOwnerPeerId;

		public float LastLockRefreshTime;

		public bool WaitingForMoveResult;

		public long MoveRequestOwnerPeerId;

		public float MoveRequestStartedAt;

		public float FirstMoveRequestStartedAt;

		public int MoveRequestAttempts;

		public float LastServerVerifyRequestAt;

		public float MoveFailureReceivedAt;

		public string MoveFailureMessage;

		public Vector3 PendingTargetPosition;

		public Quaternion PendingTargetRotation;

		public bool UpdateBedSpawnPoint;

		public Vector3 BedSpawnLocalPoint;

		public Vector3 BedOriginalProfileSpawnPoint;

		public GameObject HighlightedGhost;

		public bool GhostHighlighted;

		public bool OriginGeometryCached;

		public Vector3 OriginGroundPoint;

		public Vector3 OriginLinkPoint;

		public float OriginRingRadius;

		public bool VisualGeometryCached;

		public Vector3 LastGhostPosition;

		public Quaternion LastGhostRotation;

		public bool LastGhostVisible;
	}

	private sealed class PendingMoveRequest
	{
		public Player Player;

		public Piece Piece;

		public ZNetView NetView;

		public MoveContext Context;

		public MoveActivationMode ActivationMode;

		public long PlayerId;

		public long LockToken;

		public long ExpectedOwnerPeerId;

		public float StartedAt;

		public float LastRequestAt;
	}

	private sealed class CancelledLockRequest
	{
		public ZDOID ZdoId;

		public long PlayerId;

		public long LockToken;

		public long ExpectedOwnerPeerId;

		public float CancelledAt;
	}

	private sealed class OwnerMoveSnapshot
	{
		public Vector3 TransformPosition;

		public Quaternion TransformRotation;

		public Vector3 ZdoPosition;

		public Quaternion ZdoRotation;

		public long LastMoveToken;

		public long LastMovePeer;

		public long LastMovePlayer;

		public long LockOwner;

		public long LockPeer;

		public long LockToken;

		public long LockUntil;

		public string LockName;

		public List<RigidbodySnapshot> RigidbodyStates;

		public List<FieldValueSnapshot> ComponentFields;
	}

	private sealed class RigidbodySnapshot
	{
		public Rigidbody Body;

		public Vector3 Position;

		public Quaternion Rotation;

		public Vector3 LinearVelocity;

		public Vector3 AngularVelocity;
	}

	private sealed class FieldValueSnapshot
	{
		public object Target;

		public FieldInfo Field;

		public object Value;
	}

	private sealed class RaycastHitDistanceComparer : IComparer<RaycastHit>
	{
		public static readonly RaycastHitDistanceComparer Instance = new RaycastHitDistanceComparer();

		public int Compare(RaycastHit x, RaycastHit y)
		{
			return ((RaycastHit)(ref x)).distance.CompareTo(((RaycastHit)(ref y)).distance);
		}
	}

	private static readonly FieldInfo PlacementGhostField = AccessTools.Field(typeof(Player), "m_placementGhost");

	private static readonly FieldInfo BuildPiecesField = AccessTools.Field(typeof(Player), "m_buildPieces");

	private static readonly FieldInfo PlacementStatusField = AccessTools.Field(typeof(Player), "m_placementStatus");

	private static readonly FieldInfo EyeField = AccessTools.Field(typeof(Character), "m_eye");

	private static readonly FieldInfo MaxPlaceDistanceField = AccessTools.Field(typeof(Player), "m_maxPlaceDistance");

	private static readonly FieldInfo MaxInteractDistanceField = AccessTools.Field(typeof(Player), "m_maxInteractDistance");

	private static readonly FieldInfo RemoveRayMaskField = AccessTools.Field(typeof(Player), "m_removeRayMask");

	private static readonly FieldInfo PlaceRayMaskField = AccessTools.Field(typeof(Player), "m_placeRayMask");

	private static readonly FieldInfo InteractMaskField = AccessTools.Field(typeof(Player), "m_interactMask");

	private static readonly FieldInfo PlaceRotationField = AccessTools.Field(typeof(Player), "m_placeRotation");

	private static readonly FieldInfo ScrollCurrentAmountField = AccessTools.Field(typeof(Player), "m_scrollCurrAmount");

	private static readonly FieldInfo RotatePieceTimerField = AccessTools.Field(typeof(Player), "m_rotatePieceTimer");

	private static readonly FieldInfo PieceTableAvailablePiecesField = AccessTools.Field(typeof(PieceTable), "m_availablePieces");

	private static readonly FieldInfo PieceTableSelectedCategoryField = AccessTools.Field(typeof(PieceTable), "m_selectedCategory");

	private static readonly FieldInfo AttackField = AccessTools.Field(typeof(Character), "m_attack");

	private static readonly FieldInfo AttackHoldField = AccessTools.Field(typeof(Character), "m_attackHold");

	private static readonly FieldInfo SecondaryAttackField = AccessTools.Field(typeof(Character), "m_secondaryAttack");

	private static readonly FieldInfo SecondaryAttackHoldField = AccessTools.Field(typeof(Character), "m_secondaryAttackHold");

	private static readonly FieldInfo QueuedAttackTimerField = AccessTools.Field(typeof(Player), "m_queuedAttackTimer");

	private static readonly FieldInfo QueuedSecondAttackTimerField = AccessTools.Field(typeof(Player), "m_queuedSecondAttackTimer");

	private static readonly FieldInfo AttackDrawTimeField = AccessTools.Field(typeof(Humanoid), "m_attackDrawTime");

	private static readonly FieldInfo WearNTearCollidersField = AccessTools.Field(typeof(WearNTear), "m_colliders");

	private static readonly FieldInfo WearNTearBoundsField = AccessTools.Field(typeof(WearNTear), "m_bounds");

	private static readonly FieldInfo WearNTearClearCachedSupportField = AccessTools.Field(typeof(WearNTear), "m_clearCachedSupport");

	private static readonly FieldInfo WearNTearRoofField = AccessTools.Field(typeof(WearNTear), "m_roof");

	private static readonly FieldInfo WearNTearAshRoofField = AccessTools.Field(typeof(WearNTear), "m_ashroof");

	private static readonly FieldInfo WearNTearBiomeField = AccessTools.Field(typeof(WearNTear), "m_biome");

	private static readonly FieldInfo WearNTearHeightmapField = AccessTools.Field(typeof(WearNTear), "m_heightmap");

	private static readonly FieldInfo WearNTearConnectedHeightmapField = AccessTools.Field(typeof(WearNTear), "m_connectedHeightMap");

	private static readonly FieldInfo WearNTearGroundDistanceField = AccessTools.Field(typeof(WearNTear), "m_groundDist");

	private static readonly FieldInfo WearNTearInAshlandsField = AccessTools.Field(typeof(WearNTear), "m_inAshlands");

	private static readonly FieldInfo WearNTearLavaValueField = AccessTools.Field(typeof(WearNTear), "m_lavaValue");

	private static readonly FieldInfo WearNTearLavaTimerField = AccessTools.Field(typeof(WearNTear), "m_lavaTimer");

	private static readonly FieldInfo WearNTearAshTimerField = AccessTools.Field(typeof(WearNTear), "m_ashTimer");

	private static readonly FieldInfo WearNTearRainTimerField = AccessTools.Field(typeof(WearNTear), "m_rainTimer");

	private static readonly FieldInfo WearNTearUpdateCoverTimerField = AccessTools.Field(typeof(WearNTear), "m_updateCoverTimer");

	private static readonly FieldInfo WearNTearHaveRoofField = AccessTools.Field(typeof(WearNTear), "m_haveRoof");

	private static readonly FieldInfo WearNTearHaveAshRoofField = AccessTools.Field(typeof(WearNTear), "m_haveAshRoof");

	private static readonly FieldInfo WearNTearShieldChangeIdField = AccessTools.Field(typeof(WearNTear), "m_shieldChangeID");

	private static readonly FieldInfo WearNTearPreviousWaterVolumeField = AccessTools.Field(typeof(WearNTear), "m_previousWaterVolume");

	private static readonly FieldInfo SapCollectorRootField = AccessTools.Field(typeof(SapCollector), "m_root");

	private static readonly FieldInfo SapCollectorConnectedObjectField = AccessTools.Field(typeof(SapCollector), "m_connectedObject");

	private static readonly FieldInfo ShieldGeneratorRadiusSentField = AccessTools.Field(typeof(ShieldGenerator), "m_radiusSent");

	private static readonly FieldInfo FireplaceBiomeField = AccessTools.Field(typeof(Fireplace), "m_biome");

	private static readonly FieldInfo CinderSpawnerBiomeField = AccessTools.Field(typeof(CinderSpawner), "m_biome");

	private static readonly FieldInfo StaticRotationValueField = AccessTools.Field(typeof(StaticRotation), "m_rotation");

	private static readonly PropertyInfo RigidbodyLinearVelocityProperty = AccessTools.Property(typeof(Rigidbody), "linearVelocity") ?? AccessTools.Property(typeof(Rigidbody), "velocity");

	private static readonly EventInfo HeightmapSupportCacheEvent = typeof(Heightmap).GetEvent("m_clearConnectedWearNTearCache", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo PrivateAreasField = AccessTools.Field(typeof(PrivateArea), "m_allAreas");

	private static readonly FieldInfo PrivateAreaConnectionUpdateTimeField = AccessTools.Field(typeof(PrivateArea), "m_connectionUpdateTime");

	private static readonly FieldInfo StationExtensionsField = AccessTools.Field(typeof(StationExtension), "m_allExtensions");

	private static readonly FieldInfo CraftingStationsField = AccessTools.Field(typeof(CraftingStation), "m_allStations");

	private static readonly FieldInfo CraftingStationExtensionTimerField = AccessTools.Field(typeof(CraftingStation), "m_updateExtensionTimer");

	private static readonly FieldInfo EffectAreaColliderField = AccessTools.Field(typeof(EffectArea), "m_collider");

	private static readonly FieldInfo EffectAreaNoMonsterAreaField = AccessTools.Field(typeof(EffectArea), "noMonsterArea");

	private static readonly FieldInfo EffectAreaNoMonsterCloseAreaField = AccessTools.Field(typeof(EffectArea), "noMonsterCloseToArea");

	private static readonly FieldInfo EffectAreaBurnCloseAreaField = AccessTools.Field(typeof(EffectArea), "burnCloseToArea");

	private static readonly FieldInfo EffectAreaNoMonsterAreasField = AccessTools.Field(typeof(EffectArea), "s_noMonsterAreas");

	private static readonly FieldInfo EffectAreaNoMonsterCloseAreasField = AccessTools.Field(typeof(EffectArea), "s_noMonsterCloseToAreas");

	private static readonly FieldInfo EffectAreaBurningAreasField = AccessTools.Field(typeof(EffectArea), "s_BurningAreas");

	private static readonly FieldInfo RoutedRpcFunctionsField = AccessTools.Field(typeof(ZRoutedRpc), "m_functions");

	private static readonly MethodInfo SetupPlacementGhostMethod = AccessTools.Method(typeof(Player), "SetupPlacementGhost", (Type[])null, (Type[])null);

	private static readonly MethodInfo UpdatePlacementGhostMethod = AccessTools.Method(typeof(Player), "UpdatePlacementGhost", (Type[])null, (Type[])null);

	private static readonly MethodInfo UpdateAvailablePiecesListMethod = AccessTools.Method(typeof(Player), "UpdateAvailablePiecesList", (Type[])null, (Type[])null);

	private static readonly MethodInfo ClearLocalSupportCacheMethod = AccessTools.Method(typeof(WearNTear), "ClearCachedSupport", (Type[])null, (Type[])null);

	private static readonly MethodInfo UpdateSupportMethod = AccessTools.Method(typeof(WearNTear), "UpdateSupport", (Type[])null, (Type[])null);

	private static readonly MethodInfo HaveSupportMethod = AccessTools.Method(typeof(WearNTear), "HaveSupport", (Type[])null, (Type[])null);

	private static readonly MethodInfo PrivateAreaIsEnabledMethod = AccessTools.Method(typeof(PrivateArea), "IsEnabled", (Type[])null, (Type[])null);

	private static readonly MethodInfo PrivateAreaIsPermittedMethod = AccessTools.Method(typeof(PrivateArea), "IsPermitted", (Type[])null, (Type[])null);

	private static readonly FieldInfo[] WearNTearRelocationFields = new FieldInfo[19]
	{
		WearNTearCollidersField, WearNTearBoundsField, WearNTearClearCachedSupportField, WearNTearRoofField, WearNTearAshRoofField, WearNTearBiomeField, WearNTearHeightmapField, WearNTearConnectedHeightmapField, WearNTearGroundDistanceField, WearNTearInAshlandsField,
		WearNTearLavaValueField, WearNTearLavaTimerField, WearNTearAshTimerField, WearNTearRainTimerField, WearNTearUpdateCoverTimerField, WearNTearHaveRoofField, WearNTearHaveAshRoofField, WearNTearShieldChangeIdField, WearNTearPreviousWaterVolumeField
	};

	private static readonly Color GhostColor = new Color(0.22f, 0.66f, 1f, 0.75f);

	private static readonly Color GhostEmissionColor = new Color(0.05f, 0.42f, 0.9f, 0.9f);

	private static readonly Color LinkColor = new Color(1f, 0.9f, 0.2f, 0.92f);

	private static readonly Color RingColor = new Color(1f, 0.95f, 0.35f, 0.9f);

	private const int RingSegments = 28;

	private const float LinkWidth = 0.075f;

	private const float DashLength = 0.35f;

	private const float MinRingRadius = 0.6f;

	private const float MaxRingRadius = 8f;

	private const float RingPadding = 0.25f;

	private const float TopLinkPadding = 0.15f;

	private const float DefaultLinkHeight = 1.25f;

	private const float MinUsefulBoundsSize = 0.05f;

	private static readonly HashSet<WearNTear> SupportPieces = new HashSet<WearNTear>();

	private static readonly Dictionary<long, CancelledLockRequest> CancelledLockRequests = new Dictionary<long, CancelledLockRequest>();

	private static readonly List<long> ExpiredRequestTokens = new List<long>();

	private static readonly RaycastHit[] FloorHits = (RaycastHit[])(object)new RaycastHit[16];

	private static readonly RaycastHit[] DoorInteractHits = (RaycastHit[])(object)new RaycastHit[32];

	private static readonly List<Collider> BoundsColliderBuffer = new List<Collider>();

	private static readonly List<Renderer> BoundsRendererBuffer = new List<Renderer>();

	private static readonly List<MeshFilter> BoundsMeshFilterBuffer = new List<MeshFilter>();

	private static readonly List<Transform> BoundsSnapPointBuffer = new List<Transform>();

	private static Collider[] _supportColliderBuffer = (Collider[])(object)new Collider[128];

	private const string TemporaryPieceTableName = "MoveBuildPieces_TemporaryPieceTable";

	private const string MoveRpcName = "MoveBuildPiecesV4_Move";

	private const string MoveResultRpcName = "MoveBuildPiecesV4_MoveResult";

	private const string ApplyVisualRpcName = "MoveBuildPiecesV4_ApplyVisual";

	private const string LockRequestRpcName = "MoveBuildPiecesV4_LockRequest";

	private const string LockResponseRpcName = "MoveBuildPiecesV4_LockResponse";

	private const string LockReleaseRpcName = "MoveBuildPiecesV4_LockRelease";

	private const string ServerProbeRpcName = "MoveBuildPiecesV4_ServerProbe";

	private const string ServerProbeResultRpcName = "MoveBuildPiecesV4_ServerProbeResult";

	private const string ServerVerifyMoveRpcName = "MoveBuildPiecesV4_ServerVerifyMove";

	private const string ServerVerifyMoveResultRpcName = "MoveBuildPiecesV4_ServerVerifyMoveResult";

	private const int MoveProtocolVersion = 4;

	private static readonly int LockOwnerHash = StringExtensionMethods.GetStableHashCode("MoveBuildPieces.LockOwner");

	private static readonly int LockPeerHash = StringExtensionMethods.GetStableHashCode("MoveBuildPieces.LockPeer");

	private static readonly int LockTokenHash = StringExtensionMethods.GetStableHashCode("MoveBuildPieces.LockToken");

	private static readonly int LockUntilHash = StringExtensionMethods.GetStableHashCode("MoveBuildPieces.LockUntil");

	private static readonly int LockNameHash = StringExtensionMethods.GetStableHashCode("MoveBuildPieces.LockName");

	private static readonly int LastMoveTokenHash = StringExtensionMethods.GetStableHashCode("MoveBuildPieces.LastMoveToken");

	private static readonly int LastMovePeerHash = StringExtensionMethods.GetStableHashCode("MoveBuildPieces.LastMovePeer");

	private static readonly int LastMovePlayerHash = StringExtensionMethods.GetStableHashCode("MoveBuildPieces.LastMovePlayer");

	private const float PendingRequestTimeoutSeconds = 5f;

	private const float MoveResultTimeoutSeconds = 8f;

	private const float LockRefreshIntervalSeconds = 2f;

	private const float ServerVerificationIntervalSeconds = 0.5f;

	private const float ServerCapabilityLeaseSeconds = 12f;

	private const float MoveFailureGraceSeconds = 2.5f;

	private const int MaxMoveRequestAttempts = 3;

	private const int MaxSupportColliderBufferSize = 2048;

	private static MoveState _state;

	private static PendingMoveRequest _pendingRequest;

	private static GameObject _lineObject;

	private static LineRenderer _dashLine;

	private static LineRenderer _originRing;

	private static LineRenderer _ghostRing;

	private static Texture2D _dashTexture;

	private static int _floorMask;

	private static int _supportLayerMask;

	private static int _lastDoorInteractFrame = -1;

	private static Player _suppressAttackPlayer;

	private static float _suppressAttackUntilTime;

	private static float _nextCancelledRequestCleanupAt;

	private static long _requestTokenCounter;

	private static readonly List<ZRpc> RegisteredPeerRpcs = new List<ZRpc>();

	private static readonly Dictionary<ZRpc, double> PeerLastVerifyTimes = new Dictionary<ZRpc, double>();

	private static ZRoutedRpc _registeredRoutedRpc;

	private static bool _routedHandlersActive;

	private static ZRpc _serverRpc;

	private static long _serverProbeNonce;

	private static float _lastServerProbeAt;

	private static float _lastServerPolicyAckAt;

	private static bool _serverCapabilityConfirmed;

	private static bool _serverPolicyEnabled;

	private static bool _serverPolicyRequireKnownPiece;

	private static bool _serverPolicyBlockTerrainModifiers;

	private static bool _serverPolicyBlockDynamicObjects;

	private static float _serverPolicyMoveLockTimeoutSeconds = 45f;

	private static bool _runningFinalPlacementValidation;

	private static Player _placementValidationPlayer;

	private static Player _skipPlacementGhostPlayer;

	private static int _skipPlacementGhostFrame = -1;

	internal static bool NetworkMovesEnabled
	{
		get
		{
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				if (!ZNet.instance.IsServer())
				{
					if (IsServerCapabilityCurrent())
					{
						return _serverPolicyEnabled;
					}
					return false;
				}
				return MoveBuildPiecesPlugin.IsEnabled;
			}
			return false;
		}
	}

	public static void Initialize()
	{
		Reset();
		if ((Object)(object)ZNet.instance != (Object)null)
		{
			OnNetworkStarted(ZNet.instance);
		}
	}

	public static void Reset()
	{
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		ClearNetworkSession();
		if (_state != null)
		{
			Cancel(_state.Player, showMessage: false);
		}
		if (_pendingRequest != null)
		{
			ReleaseMoveLock(_pendingRequest.NetView, _pendingRequest.PlayerId, _pendingRequest.LockToken, _pendingRequest.ExpectedOwnerPeerId);
			_pendingRequest = null;
		}
		foreach (CancelledLockRequest value in CancelledLockRequests.Values)
		{
			ReleaseMoveLock(ResolvePieceNetView(value.ZdoId), value.PlayerId, value.LockToken, value.ExpectedOwnerPeerId);
		}
		CancelledLockRequests.Clear();
		ExpiredRequestTokens.Clear();
		_suppressAttackPlayer = null;
		_suppressAttackUntilTime = 0f;
		_nextCancelledRequestCleanupAt = 0f;
		_lastDoorInteractFrame = -1;
		_floorMask = 0;
		_supportLayerMask = 0;
		_runningFinalPlacementValidation = false;
		_placementValidationPlayer = null;
		_skipPlacementGhostPlayer = null;
		_skipPlacementGhostFrame = -1;
		DestroyLine();
	}

	public static void OnNetworkStarted(ZNet network)
	{
		ClearNetworkSession();
		if (!((Object)(object)network == (Object)null))
		{
			RegisterGlobalRoutedRpcs();
			_serverCapabilityConfirmed = network.IsServer();
			_serverProbeNonce = CreateRequestToken();
			List<ZNetPeer> peers = network.GetPeers();
			for (int i = 0; i < peers.Count; i++)
			{
				RegisterNetworkPeer(peers[i]);
			}
		}
	}

	public static void OnNetworkStopped(ZNet network)
	{
		if ((Object)(object)network == (Object)null || (Object)(object)network == (Object)(object)ZNet.instance)
		{
			ClearNetworkSession();
		}
	}

	public static void PrepareForNetworkShutdown()
	{
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		if (_state != null)
		{
			Cancel(_state.Player, showMessage: false);
		}
		if (_pendingRequest != null)
		{
			CancelPendingRequest(_pendingRequest.Player, showMessage: false, null);
		}
		foreach (CancelledLockRequest value in CancelledLockRequests.Values)
		{
			try
			{
				ReleaseMoveLock(ResolvePieceNetView(value.ZdoId), value.PlayerId, value.LockToken, value.ExpectedOwnerPeerId);
			}
			catch
			{
			}
		}
	}

	public static void RegisterNetworkPeer(ZNetPeer peer)
	{
		ZRpc val = peer?.m_rpc;
		if (val == null)
		{
			return;
		}
		for (int i = 0; i < RegisteredPeerRpcs.Count; i++)
		{
			if (RegisteredPeerRpcs[i] == val)
			{
				return;
			}
		}
		val.Register<int, long>("MoveBuildPiecesV4_ServerProbe", (Action<ZRpc, int, long>)HandleServerProbe);
		val.Register<ZPackage>("MoveBuildPiecesV4_ServerProbeResult", (Action<ZRpc, ZPackage>)HandleServerProbeResult);
		val.Register<ZPackage>("MoveBuildPiecesV4_ServerVerifyMove", (Action<ZRpc, ZPackage>)HandleServerVerifyMove);
		val.Register<ZPackage>("MoveBuildPiecesV4_ServerVerifyMoveResult", (Action<ZRpc, ZPackage>)HandleServerVerifyMoveResult);
		RegisteredPeerRpcs.Add(val);
		if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer())
		{
			_serverRpc = val;
			_serverCapabilityConfirmed = false;
			_lastServerProbeAt = 0f;
			_lastServerPolicyAckAt = 0f;
		}
	}

	public static void UnregisterNetworkPeer(ZNetPeer peer)
	{
		ZRpc val = peer?.m_rpc;
		if (val == null)
		{
			return;
		}
		val.Unregister("MoveBuildPiecesV4_ServerProbe");
		val.Unregister("MoveBuildPiecesV4_ServerProbeResult");
		val.Unregister("MoveBuildPiecesV4_ServerVerifyMove");
		val.Unregister("MoveBuildPiecesV4_ServerVerifyMoveResult");
		for (int num = RegisteredPeerRpcs.Count - 1; num >= 0; num--)
		{
			if (RegisteredPeerRpcs[num] == val)
			{
				RegisteredPeerRpcs.RemoveAt(num);
			}
		}
		PeerLastVerifyTimes.Remove(val);
		if (_serverRpc == val)
		{
			_serverRpc = null;
			InvalidateServerCapability(null);
		}
	}

	private static void ClearNetworkSession()
	{
		UnregisterGlobalRoutedRpcs();
		for (int i = 0; i < RegisteredPeerRpcs.Count; i++)
		{
			ZRpc val = RegisteredPeerRpcs[i];
			if (val != null)
			{
				val.Unregister("MoveBuildPiecesV4_ServerProbe");
				val.Unregister("MoveBuildPiecesV4_ServerProbeResult");
				val.Unregister("MoveBuildPiecesV4_ServerVerifyMove");
				val.Unregister("MoveBuildPiecesV4_ServerVerifyMoveResult");
			}
		}
		RegisteredPeerRpcs.Clear();
		PeerLastVerifyTimes.Clear();
		_serverRpc = null;
		_serverProbeNonce = 0L;
		_lastServerProbeAt = 0f;
		_lastServerPolicyAckAt = 0f;
		_serverCapabilityConfirmed = false;
		_serverPolicyEnabled = false;
		_serverPolicyRequireKnownPiece = false;
		_serverPolicyBlockTerrainModifiers = true;
		_serverPolicyBlockDynamicObjects = true;
		_serverPolicyMoveLockTimeoutSeconds = 45f;
	}

	private static void UpdateServerCapability()
	{
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer() && _serverCapabilityConfirmed && (_lastServerPolicyAckAt <= 0f || realtimeSinceStartup - _lastServerPolicyAckAt > 12f))
		{
			InvalidateServerCapability("MoveBuildPieces server protocol stopped responding");
		}
		float num = (_serverCapabilityConfirmed ? 5f : 1f);
		if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer() && _serverRpc != null && _serverRpc.IsConnected() && !(realtimeSinceStartup - _lastServerProbeAt < num))
		{
			_lastServerProbeAt = realtimeSinceStartup;
			_serverRpc.Invoke("MoveBuildPiecesV4_ServerProbe", new object[2] { 4, _serverProbeNonce });
		}
	}

	private static void InvalidateServerCapability(string message)
	{
		bool num = _state != null || _pendingRequest != null;
		_serverCapabilityConfirmed = false;
		_serverPolicyEnabled = false;
		_lastServerPolicyAckAt = 0f;
		_lastServerProbeAt = 0f;
		_serverProbeNonce = CreateRequestToken();
		if (_state != null)
		{
			Cancel(_state.Player, showMessage: false);
		}
		if (_pendingRequest != null)
		{
			CancelPendingRequest(_pendingRequest.Player, showMessage: false, null);
		}
		if (num && !string.IsNullOrEmpty(message))
		{
			Message(Player.m_localPlayer, message);
		}
	}

	private static void HandleServerProbe(ZRpc rpc, int protocolVersion, long nonce)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Expected O, but got Unknown
		if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && protocolVersion == 4 && nonce != 0L && TryGetReadyPeer(rpc, out var _))
		{
			ZPackage val = new ZPackage();
			val.Write(4);
			val.Write(nonce);
			val.Write(MoveBuildPiecesPlugin.IsEnabled);
			val.Write(MoveBuildPiecesPlugin.RequireKnownPiece);
			val.Write(MoveBuildPiecesPlugin.BlockTerrainModifiers);
			val.Write(MoveBuildPiecesPlugin.BlockDynamicObjects);
			val.Write(MoveBuildPiecesPlugin.MoveLockTimeoutSeconds);
			rpc.Invoke("MoveBuildPiecesV4_ServerProbeResult", new object[1] { val });
		}
	}

	private static void HandleServerProbeResult(ZRpc rpc, ZPackage package)
	{
		if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer() || rpc != _serverRpc || package == null)
		{
			return;
		}
		try
		{
			int num = package.ReadInt();
			long num2 = package.ReadLong();
			bool flag = package.ReadBool();
			bool serverPolicyRequireKnownPiece = package.ReadBool();
			bool serverPolicyBlockTerrainModifiers = package.ReadBool();
			bool serverPolicyBlockDynamicObjects = package.ReadBool();
			float num3 = package.ReadSingle();
			if (num != 4 || num2 != _serverProbeNonce || float.IsNaN(num3) || float.IsInfinity(num3))
			{
				return;
			}
			bool flag2 = _state != null || _pendingRequest != null;
			_serverPolicyEnabled = flag;
			_serverPolicyRequireKnownPiece = serverPolicyRequireKnownPiece;
			_serverPolicyBlockTerrainModifiers = serverPolicyBlockTerrainModifiers;
			_serverPolicyBlockDynamicObjects = serverPolicyBlockDynamicObjects;
			_serverPolicyMoveLockTimeoutSeconds = Mathf.Clamp(num3, 5f, 300f);
			_serverCapabilityConfirmed = true;
			_lastServerPolicyAckAt = Time.realtimeSinceStartup;
			if (!flag && flag2)
			{
				if (_state != null)
				{
					Cancel(_state.Player, showMessage: false);
				}
				if (_pendingRequest != null)
				{
					CancelPendingRequest(_pendingRequest.Player, showMessage: false, null);
				}
				Message(Player.m_localPlayer, "MoveBuildPieces is disabled by the server policy");
			}
		}
		catch
		{
		}
	}

	private static void HandleServerVerifyMove(ZRpc rpc, ZPackage package)
	{
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Expected O, but got Unknown
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: 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_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: 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)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || package == null || !TryGetReadyPeer(rpc, out var peer))
		{
			return;
		}
		double networkTimeSeconds = GetNetworkTimeSeconds();
		if (PeerLastVerifyTimes.TryGetValue(rpc, out var value) && networkTimeSeconds - value < 0.1)
		{
			return;
		}
		PeerLastVerifyTimes[rpc] = networkTimeSeconds;
		ZDOID val = ZDOID.None;
		long num = 0L;
		Vector3 val2 = Vector3.zero;
		Quaternion val3 = Quaternion.identity;
		bool flag = false;
		try
		{
			val = package.ReadZDOID();
			long num2 = package.ReadLong();
			num = package.ReadLong();
			val2 = package.ReadVector3();
			val3 = package.ReadQuaternion();
			object obj;
			if (((ZDOID)(ref peer.m_characterID)).IsNone())
			{
				obj = null;
			}
			else
			{
				ZDOMan instance = ZDOMan.instance;
				obj = ((instance != null) ? instance.GetZDO(peer.m_characterID) : null);
			}
			ZDO val4 = (ZDO)obj;
			ZDOMan instance2 = ZDOMan.instance;
			ZDO zdo = ((instance2 != null) ? instance2.GetZDO(val) : null);
			flag = MoveBuildPiecesPlugin.IsEnabled && val4 != null && val4.GetOwner() == peer.m_uid && val4.GetLong(ZDOVars.s_playerID, 0L) == num2 && IsCommittedMove(zdo, peer.m_uid, num2, num, val2, val3);
		}
		catch
		{
			flag = false;
		}
		ZPackage val5 = new ZPackage();
		val5.Write(val);
		val5.Write(num);
		val5.Write(val2);
		val5.Write(val3);
		val5.Write(flag);
		rpc.Invoke("MoveBuildPiecesV4_ServerVerifyMoveResult", new object[1] { val5 });
	}

	private static void HandleServerVerifyMoveResult(ZRpc rpc, ZPackage package)
	{
		//IL_0027: 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_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: 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_00df: 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_0122: 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_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer() || rpc != _serverRpc || package == null)
		{
			return;
		}
		try
		{
			ZDOID val = package.ReadZDOID();
			long num = package.ReadLong();
			Vector3 val2 = package.ReadVector3();
			Quaternion val3 = package.ReadQuaternion();
			if (package.ReadBool() && _serverCapabilityConfirmed && NetworkMovesEnabled && _state != null && _state.WaitingForMoveResult && _state.LockToken == num && !((Object)(object)_state.NetView == (Object)null) && _state.NetView.IsValid() && !(_state.NetView.GetZDO().m_uid != val) && !(Vector3.Distance(_state.PendingTargetPosition, val2) > 0.001f) && !(Quaternion.Angle(_state.PendingTargetRotation, val3) > 0.01f))
			{
				MoveState state = _state;
				ReleaseMoveLock(state.NetView, state.LockPlayerId, state.LockToken, state.LockOwnerPeerId);
				ApplyVisualMoveLocally(state.NetView, val2, val3);
				FinishSuccessfulMove(state.Player, state.Piece, val2, val3);
			}
		}
		catch
		{
		}
	}

	private static bool TryGetReadyPeer(ZRpc rpc, out ZNetPeer peer)
	{
		peer = null;
		if (rpc == null || (Object)(object)ZNet.instance == (Object)null)
		{
			return false;
		}
		List<ZNetPeer> peers = ZNet.instance.GetPeers();
		for (int i = 0; i < peers.Count; i++)
		{
			ZNetPeer val = peers[i];
			if (val != null && val.m_rpc == rpc && val.IsReady() && val.m_uid != 0L && !((ZDOID)(ref val.m_characterID)).IsNone())
			{
				peer = val;
				return true;
			}
		}
		return false;
	}

	private static void RegisterGlobalRoutedRpcs()
	{
		ZRoutedRpc instance = ZRoutedRpc.instance;
		if (instance != null && (_registeredRoutedRpc != instance || !_routedHandlersActive))
		{
			UnregisterGlobalRoutedRpcs();
			instance.Register<ZDOID, long, long, Vector3, Quaternion>("MoveBuildPiecesV4_Move", (Method<ZDOID, long, long, Vector3, Quaternion>)HandleRoutedMoveRpc);
			instance.Register<ZDOID, bool, string, long>("MoveBuildPiecesV4_MoveResult", (Method<ZDOID, bool, string, long>)HandleRoutedMoveResultRpc);
			instance.Register<ZDOID, long, Vector3, Quaternion>("MoveBuildPiecesV4_ApplyVisual", (Method<ZDOID, long, Vector3, Quaternion>)HandleRoutedVisualMoveRpc);
			instance.Register<ZDOID, long, long, bool>("MoveBuildPiecesV4_LockRequest", (Method<ZDOID, long, long, bool>)HandleRoutedLockRequestRpc);
			instance.Register<ZDOID, bool, string, long>("MoveBuildPiecesV4_LockResponse", (Method<ZDOID, bool, string, long>)HandleRoutedLockResponseRpc);
			instance.Register<ZDOID, long, long>("MoveBuildPiecesV4_LockRelease", (Action<long, ZDOID, long, long>)HandleRoutedLockReleaseRpc);
			_registeredRoutedRpc = instance;
			_routedHandlersActive = true;
		}
	}

	private static void UnregisterGlobalRoutedRpcs()
	{
		if (_registeredRoutedRpc != null && RoutedRpcFunctionsField?.GetValue(_registeredRoutedRpc) is IDictionary dictionary)
		{
			dictionary.Remove(StringExtensionMethods.GetStableHashCode("MoveBuildPiecesV4_Move"));
			dictionary.Remove(StringExtensionMethods.GetStableHashCode("MoveBuildPiecesV4_MoveResult"));
			dictionary.Remove(StringExtensionMethods.GetStableHashCode("MoveBuildPiecesV4_ApplyVisual"));
			dictionary.Remove(StringExtensionMethods.GetStableHashCode("MoveBuildPiecesV4_LockRequest"));
			dictionary.Remove(StringExtensionMethods.GetStableHashCode("MoveBuildPiecesV4_LockResponse"));
			dictionary.Remove(StringExtensionMethods.GetStableHashCode("MoveBuildPiecesV4_LockRelease"));
		}
		_routedHandlersActive = false;
		_registeredRoutedRpc = null;
	}

	private static bool TryResolvePieceNetView(ZDOID zdoId, out ZNetView netView)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		netView = (_routedHandlersActive ? ResolvePieceNetView(zdoId) : null);
		return (Object)(object)netView != (Object)null;
	}

	private static ZNetView ResolvePieceNetView(ZDOID zdoId)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		if (((ZDOID)(ref zdoId)).IsNone() || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null)
		{
			return null;
		}
		ZDO zDO = ZDOMan.instance.GetZDO(zdoId);
		ZNetView val = ((zDO != null) ? ZNetScene.instance.FindInstance(zDO) : null);
		if (!((Object)(object)val != (Object)null) || !val.IsValid() || val.GetZDO() != zDO || !((Object)(object)((Component)val).GetComponent<Piece>() != (Object)null))
		{
			return null;
		}
		return val;
	}

	private static void HandleRoutedMoveRpc(long sender, ZDOID zdoId, long playerId, long lockToken, Vector3 position, Quaternion rotation)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		if (TryResolvePieceNetView(zdoId, out var netView))
		{
			ApplyMoveRpc(netView, sender, playerId, lockToken, position, rotation);
		}
	}

	private static void HandleRoutedMoveResultRpc(long sender, ZDOID zdoId, bool success, string message, long lockToken)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		if (TryResolvePieceNetView(zdoId, out var netView))
		{
			ApplyMoveResultRpc(netView, sender, success, message, lockToken);
		}
	}

	private static void HandleRoutedVisualMoveRpc(long sender, ZDOID zdoId, long lockToken, Vector3 position, Quaternion rotation)
	{
		//IL_0000: 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_000e: Unknown result type (might be due to invalid IL or missing references)
		if (TryResolvePieceNetView(zdoId, out var netView))
		{
			ApplyVisualMoveRpc(netView, sender, lockToken, position, rotation);
		}
	}

	private static void HandleRoutedLockRequestRpc(long sender, ZDOID zdoId, long playerId, long lockToken, bool refreshOnly)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		if (TryResolvePieceNetView(zdoId, out var netView))
		{
			ApplyLockRequestRpc(netView, sender, playerId, lockToken, refreshOnly);
		}
	}

	private static void HandleRoutedLockResponseRpc(long sender, ZDOID zdoId, bool granted, string message, long lockToken)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		if (TryResolvePieceNetView(zdoId, out var netView))
		{
			ApplyLockResponseRpc(netView, sender, granted, message, lockToken);
		}
	}

	private static void HandleRoutedLockReleaseRpc(long sender, ZDOID zdoId, long playerId, long lockToken)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		if (TryResolvePieceNetView(zdoId, out var netView))
		{
			ApplyLockReleaseRpc(netView, sender, playerId, lockToken);
		}
	}

	private static bool InvokePieceRpc(ZNetView netView, long targetPeerId, string methodName, params object[] arguments)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)netView == (Object)null || !netView.IsValid() || string.IsNullOrEmpty(methodName) || ZRoutedRpc.instance == null)
		{
			return false;
		}
		object[] array = new object[arguments.Length + 1];
		array[0] = netView.GetZDO().m_uid;
		Array.Copy(arguments, 0, array, 1, arguments.Length);
		ZRoutedRpc.instance.InvokeRoutedRPC(targetPeerId, methodName, array);
		return true;
	}

	public static bool ValidateRoutedRpcSender(ZRoutedRpc routedRpc, ZRpc rpc, ZPackage package)
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		if (routedRpc == null || rpc == null || package == null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
		{
			return true;
		}
		int pos = package.GetPos();
		try
		{
			package.ReadLong();
			long num = package.ReadLong();
			package.ReadLong();
			package.ReadZDOID();
			if (!IsMoveProtocolMethod(package.ReadInt()))
			{
				return true;
			}
			List<ZNetPeer> peers = ZNet.instance.GetPeers();
			for (int i = 0; i < peers.Count; i++)
			{
				ZNetPeer val = peers[i];
				if (val != null && val.m_rpc == rpc)
				{
					return num != 0L && num == val.m_uid;
				}
			}
			return false;
		}
		catch
		{
			return false;
		}
		finally
		{
			package.SetPos(pos);
		}
	}

	private static bool IsMoveProtocolMethod(int methodHash)
	{
		if (methodHash != StringExtensionMethods.GetStableHashCode("MoveBuildPiecesV4_Move") && methodHash != StringExtensionMethods.GetStableHashCode("MoveBuildPiecesV4_MoveResult") && methodHash != StringExtensionMethods.GetStableHashCode("MoveBuildPiecesV4_ApplyVisual") && methodHash != StringExtensionMethods.GetStableHashCode("MoveBuildPiecesV4_LockRequest") && methodHash != StringExtensionMethods.GetStableHashCode("MoveBuildPiecesV4_LockResponse"))
		{
			return methodHash == StringExtensionMethods.GetStableHashCode("MoveBuildPiecesV4_LockRelease");
		}
		return true;
	}

	public static void Update(Player player)
	{
		if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
		{
			return;
		}
		CleanupCancelledLockRequests();
		UpdateServerCapability();
		if (!MoveBuildPiecesPlugin.IsEnabled)
		{
			if (_state != null)
			{
				Cancel(player, showMessage: false);
			}
			if (_pendingRequest != null)
			{
				CancelPendingRequest(player, showMessage: false, null);
			}
			return;
		}
		if (_pendingRequest != null && (Object)(object)_pendingRequest.Player == (Object)(object)player && (((Character)player).IsDead() || ((Character)player).IsTeleporting()))
		{
			CancelPendingRequest(player, showMessage: false, null);
		}
		else if (_pendingRequest != null && (Object)(object)_pendingRequest.Player == (Object)(object)player && Time.realtimeSinceStartup - _pendingRequest.StartedAt > 5f)
		{
			CancelPendingRequest(player, showMessage: false, "Move lock request timed out or the object owner has an incompatible mod version");
		}
		if (_pendingRequest != null && (!CanBeginPendingMove(_pendingRequest) || IsUiBlockingInput()))
		{
			CancelPendingRequest(player, showMessage: false, null);
		}
		if (_pendingRequest != null)
		{
			RetryPendingLockAfterOwnerChange(_pendingRequest);
		}
		if (ShouldCancelForUiOrState(player))
		{
			Cancel(player, showMessage: false);
		}
		else
		{
			if (IsUiBlockingInput())
			{
				return;
			}
			if ((_state == null || !TryInteractDoorInMoveMode(player)) && ShouldHandleMoveHotkey(player, out var context, out var activationMode))
			{
				ToggleMove(player, context, activationMode);
			}
			if (_state == null)
			{
				return;
			}
			RefreshMoveLock(_state);
			if (_state == null)
			{
				return;
			}
			if (_state.WaitingForMoveResult)
			{
				RequestServerMoveVerification(_state);
			}
			if ((!_state.WaitingForMoveResult || !TryResolveCommittedMove(_state)) && (!_state.WaitingForMoveResult || !TryRetryMoveAfterOwnerChange(_state)))
			{
				if (_state.WaitingForMoveResult && _state.MoveFailureReceivedAt > 0f && Time.realtimeSinceStartup - _state.MoveFailureReceivedAt >= 2.5f)
				{
					Message(player, string.IsNullOrEmpty(_state.MoveFailureMessage) ? "$msg_invalidplacement" : _state.MoveFailureMessage);
					_state.WaitingForMoveResult = false;
					_state.MoveFailureReceivedAt = 0f;
					_state.MoveFailureMessage = null;
					_state.MoveRequestOwnerPeerId = 0L;
					_state.MoveRequestStartedAt = 0f;
					_state.FirstMoveRequestStartedAt = 0f;
					_state.MoveRequestAttempts = 0;
					_state.LastLockRefreshTime = 0f;
				}
				else if (_state.WaitingForMoveResult && Time.realtimeSinceStartup - _state.FirstMoveRequestStartedAt > 8f)
				{
					Message(player, "Move confirmation timed out; verify the object's position");
					Cancel(player, showMessage: false);
				}
				else if (!_state.WaitingForMoveResult)
				{
					UpdateActiveMovePlacement(player);
				}
			}
		}
	}

	public static void UpdateVisuals(Player player)
	{
		if (MoveBuildPiecesPlugin.IsEnabled && !((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && _state != null)
		{
			UpdateLineAndGhost(player);
		}
	}

	public static void SuppressAttackControls(Player player, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold)
	{
		if (ShouldSuppressAttackControls(player, attack, attackHold, secondaryAttack, secondaryAttackHold))
		{
			attack = false;
			attackHold = false;
			secondaryAttack = false;
			secondaryAttackHold = false;
			ClearQueuedAttackInput(player);
		}
	}

	private static bool ShouldSuppressAttackControls(Player player, bool attack, bool attackHold, bool secondaryAttack, bool secondaryAttackHold)
	{
		if (!MoveBuildPiecesPlugin.IsEnabled || (Object)(object)player == (Object)null)
		{
			return false;
		}
		if (_state != null && (Object)(object)player == (Object)(object)_state.Player)
		{
			return true;
		}
		if ((Object)(object)_suppressAttackPlayer == (Object)(object)player)
		{
			if ((attack || attackHold || secondaryAttack || secondaryAttackHold) && Time.realtimeSinceStartup <= _suppressAttackUntilTime)
			{
				return true;
			}
			_suppressAttackPlayer = null;
			_suppressAttackUntilTime = 0f;
		}
		return false;
	}

	public static bool ShouldHandlePlacement(Player player)
	{
		if (_state != null && (Object)(object)player != (Object)null)
		{
			return (Object)(object)player == (Object)(object)_state.Player;
		}
		return false;
	}

	public static bool ShouldBlockBuildAction(Player player)
	{
		if (_state != null && (Object)(object)player != (Object)null)
		{
			return (Object)(object)player == (Object)(object)_state.Player;
		}
		return false;
	}

	public static bool ShouldBypassRequirements(Player player, Piece piece, RequirementMode mode)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Invalid comparison between Unknown and I4
		if ((Object)(object)player == (Object)null || (Object)(object)piece == (Object)null)
		{
			return false;
		}
		if ((int)mode != 0 && (int)mode != 2)
		{
			return false;
		}
		string prefabName = Utils.GetPrefabName(((Component)piece).gameObject);
		if (_state != null && (Object)(object)player == (Object)(object)_state.Player)
		{
			return prefabName == _state.PrefabName;
		}
		return false;
	}

	public static bool ShouldSkipVanillaUpdatePlacement(Player player)
	{
		if (_state != null && (Object)(object)player != (Object)null)
		{
			return (Object)(object)player == (Object)(object)_state.Player;
		}
		return false;
	}

	public static void NotifyDoorInteracted(Player player)
	{
		if (_state != null && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)_state.Player)
		{
			_lastDoorInteractFrame = Time.frameCount;
		}
	}

	public static void CancelForTeleport(Player player)
	{
		if (_state != null && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)_state.Player)
		{
			Cancel(player, showMessage: true);
		}
		if (_pendingRequest != null && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)_pendingRequest.Player)
		{
			CancelPendingRequest(player, showMessage: false, null);
		}
	}

	public static void CancelForDeath(Player player)
	{
		if (_state != null && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)_state.Player)
		{
			Cancel(player, showMessage: true);
		}
		if (_pendingRequest != null && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)_pendingRequest.Player)
		{
			CancelPendingRequest(player, showMessage: false, null);
		}
	}

	public static void CancelForPlayerDestroyed(Player player)
	{
		if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer))
		{
			if (_state != null && (Object)(object)player == (Object)(object)_state.Player)
			{
				Cancel(player, showMessage: false);
			}
			if (_pendingRequest != null && (Object)(object)player == (Object)(object)_pendingRequest.Player)
			{
				CancelPendingRequest(player, showMessage: false, null);
			}
		}
	}

	public static void TryFinishMove(Player player)
	{
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: 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_00a2: 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_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: 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_0143: Unknown result type (might be due to invalid IL or missing references)
		if (_state == null || (Object)(object)player != (Object)(object)_state.Player || _state.WaitingForMoveResult)
		{
			return;
		}
		if (!IsMoveSelectionIntact(_state, player))
		{
			Message(player, "Move cancelled because the selected build piece changed");
			Cancel(player, showMessage: false);
			return;
		}
		if (!RunFinalPlacementValidation(player))
		{
			Message(player, "$msg_invalidplacement");
			return;
		}
		GameObject placementGhost = GetPlacementGhost(player);
		if ((Object)(object)placementGhost == (Object)null)
		{
			Message(player, "$msg_invalidplacement");
			Cancel(player, showMessage: false);
			return;
		}
		PlacementStatus placementStatus = GetPlacementStatus(player);
		if ((int)placementStatus != 0)
		{
			Message(player, GetPlacementFailureMessage(placementStatus));
			return;
		}
		Vector3 position = placementGhost.transform.position;
		Quaternion rotation = placementGhost.transform.rotation;
		if (!IsInsideOriginalBuildArea(_state, position))
		{
			Message(player, "$msg_nobuildzone");
		}
		else if (ValidateMoveTarget(player, _state.Piece))
		{
			Piece piece = _state.Piece;
			_state.PendingTargetPosition = position;
			_state.PendingTargetRotation = rotation;
			if (!RequestMovePiece(_state, position, rotation, out var completedImmediately))
			{
				Message(player, "$msg_invalidplacement");
			}
			else if (!completedImmediately)
			{
				Message(player, "Moving " + Localization.instance.Localize(piece.m_name));
			}
			else
			{
				FinishSuccessfulMove(player, piece, position, rotation);
			}
		}
	}

	private static bool RunFinalPlacementValidation(Player player)
	{
		if ((Object)(object)player == (Object)null || UpdatePlacementGhostMethod == null)
		{
			return false;
		}
		_runningFinalPlacementValidation = true;
		_placementValidationPlayer = player;
		try
		{
			UpdatePlacementGhostMethod.Invoke(player, new object[1] { true });
			return true;
		}
		catch (Exception ex)
		{
			Debug.LogWarning((object)("[MoveBuildPieces] Final placement validation failed: " + ex.GetBaseException().Message));
			return false;
		}
		finally
		{
			_runningFinalPlacementValidation = false;
			_placementValidationPlayer = null;
			_skipPlacementGhostPlayer = player;
			_skipPlacementGhostFrame = Time.frameCount;
		}
	}

	public static bool ShouldRunPlacementGhostUpdate(Player player)
	{
		if (_runningFinalPlacementValidation && (Object)(object)player == (Object)(object)_placementValidationPlayer)
		{
			return true;
		}
		if ((Object)(object)player == (Object)(object)_skipPlacementGhostPlayer && Time.frameCount == _skipPlacementGhostFrame)
		{
			return false;
		}
		if (Time.frameCount != _skipPlacementGhostFrame)
		{
			_skipPlacementGhostPlayer = null;
			_skipPlacementGhostFrame = -1;
		}
		return true;
	}

	public static Collider[] FilterPlacementOverlap(Collider[] overlaps)
	{
		Piece val = _state?.Piece;
		if ((Object)(object)val == (Object)null || overlaps == null || overlaps.Length == 0)
		{
			return overlaps;
		}
		int num = 0;
		foreach (Collider val2 in overlaps)
		{
			if ((Object)(object)val2 != (Object)null && (Object)(object)((Component)val2).GetComponentInParent<Piece>() == (Object)(object)val)
			{
				num++;
			}
		}
		if (num == 0)
		{
			return overlaps;
		}
		Collider[] array = (Collider[])(object)new Collider[overlaps.Length - num];
		int num2 = 0;
		foreach (Collider val3 in overlaps)
		{
			if ((Object)(object)val3 == (Object)null || (Object)(object)((Component)val3).GetComponentInParent<Piece>() != (Object)(object)val)
			{
				array[num2++] = val3;
			}
		}
		return array;
	}

	public static bool TryTestGhostClippingIgnoringMovedPiece(Player player, GameObject ghost, float maxPenetration, out bool result)
	{
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		result = false;
		Piece val = (((Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)_state?.Player) ? _state.Piece : null);
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		if ((Object)(object)ghost == (Object)null || !(PlaceRayMaskField?.GetValue(player) is int num))
		{
			result = true;
			return true;
		}
		Collider[] componentsInChildren = ghost.GetComponentsInChildren<Collider>();
		Collider[] array = Physics.OverlapSphere(ghost.transform.position, 10f, num);
		Vector3 val4 = default(Vector3);
		float num2 = default(float);
		foreach (Collider val2 in componentsInChildren)
		{
			if ((Object)(object)val2 == (Object)null)
			{
				continue;
			}
			foreach (Collider val3 in array)
			{
				if (!((Object)(object)val3 == (Object)null) && !((Object)(object)((Component)val3).GetComponentInParent<Piece>() == (Object)(object)val) && Physics.ComputePenetration(val2, ((Component)val2).transform.position, ((Component)val2).transform.rotation, val3, ((Component)val3).transform.position, ((Component)val3).transform.rotation, ref val4, ref num2) && num2 > maxPenetration)
				{
					result = true;
					return true;
				}
			}
		}
		return true;
	}

	public static bool TryEvaluatePieceOverlapIgnoringMovedPiece(Player player, Vector3 position, Quaternion rotation, string pieceName, List<Piece> pieces, bool allowRotatedOverlap, out bool result)
	{
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		result = false;
		Piece val = (((Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)_state?.Player) ? _state.Piece : null);
		if ((Object)(object)val == (Object)null || pieces == null)
		{
			return false;
		}
		for (int i = 0; i < pieces.Count; i++)
		{
			Piece val2 = pieces[i];
			if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)val) && Vector3.Distance(position, ((Component)val2).transform.position) < 0.05f && (!allowRotatedOverlap || Quaternion.Angle(((Component)val2).transform.rotation, rotation) <= 10f) && Utils.CustomStartsWith(((Object)((Component)val2).gameObject).name, pieceName))
			{
				result = true;
				break;
			}
		}
		return true;
	}

	public static bool TryEvaluateExtensionRangeIgnoringMovedPiece(StationExtension extension, float radius, out bool result)
	{
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		result = false;
		Piece val = _state?.Piece;
		if ((Object)(object)val == (Object)null || (Object)(object)extension == (Object)null || !(StationExtensionsField?.GetValue(null) is List<StationExtension> list))
		{
			return false;
		}
		for (int i = 0; i < list.Count; i++)
		{
			StationExtension val2 = list[i];
			if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)extension) && !((Object)(object)((Component)val2).GetComponentInParent<Piece>() == (Object)(object)val) && Vector3.Distance(((Component)val2).transform.position, ((Component)extension).transform.position) < radius)
			{
				result = true;
				break;
			}
		}
		return true;
	}

	private static void FinishSuccessfulMove(Player player, Piece movedPiece, Vector3 targetPosition, Quaternion targetRotation)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: 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)
		if ((Object)(object)movedPiece == (Object)null)
		{
			Message(player, "$msg_invalidplacement");
			Cancel(player, showMessage: false);
			return;
		}
		MoveState state = _state;
		try
		{
			UpdateMovedBedSpawnPoint(state, targetPosition, targetRotation);
			SuppressAttackUntilRelease(player);
			Message(player, "Moved " + Localization.instance.Localize(movedPiece.m_name));
			movedPiece.m_placeEffect.Create(targetPosition, targetRotation, ((Component)movedPiece).transform, 1f, -1);
		}
		catch (Exception ex)
		{
			Debug.LogWarning((object)("[MoveBuildPieces] Move completion effect failed: " + ex.GetBaseException().Message));
		}
		finally
		{
			Cancel(player, showMessage: false, releaseLock: false);
		}
	}

	private static void UpdateMovedBedSpawnPoint(MoveState state, Vector3 targetPosition, Quaternion targetRotation)
	{
		//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_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		if (state != null && state.UpdateBedSpawnPoint && !((Object)(object)Game.instance == (Object)null))
		{
			PlayerProfile playerProfile = Game.instance.GetPlayerProfile();
			if (playerProfile != null && playerProfile.HaveCustomSpawnPoint() && !(Vector3.Distance(playerProfile.GetCustomSpawnPoint(), state.BedOriginalProfileSpawnPoint) > 0.1f))
			{
				Vector3 val = (((Object)(object)state.Piece != (Object)null) ? ((Component)state.Piece).transform.lossyScale : Vector3.one);
				Vector3 customSpawnPoint = targetPosition + targetRotation * Vector3.Scale(state.BedSpawnLocalPoint, val);
				playerProfile.SetCustomSpawnPoint(customSpawnPoint);
			}
		}
	}

	private static void SuppressAttackUntilRelease(Player player)
	{
		if (!((Object)(object)player == (Object)null))
		{
			_suppressAttackPlayer = player;
			_suppressAttackUntilTime = Time.realtimeSinceStartup + 5f;
			ClearQueuedAttackInput(player);
		}
	}

	private static void ClearQueuedAttackInput(Player player)
	{
		if (!((Object)(object)player == (Object)null))
		{
			AttackField?.SetValue(player, false);
			AttackHoldField?.SetValue(player, false);
			SecondaryAttackField?.SetValue(player, false);
			SecondaryAttackHoldField?.SetValue(player, false);
			QueuedAttackTimerField?.SetValue(player, 0f);
			QueuedSecondAttackTimerField?.SetValue(player, 0f);
			AttackDrawTimeField?.SetValue(player, 0f);
		}
	}

	private static bool ShouldHandleMoveHotkey(Player player, out MoveContext context, out MoveActivationMode activationMode)
	{
		//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_00a0: 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_0082: 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_00dd: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		context = MoveContext.Build;
		activationMode = MoveBuildPiecesPlugin.ActiveMode;
		KeyboardShortcut val;
		if (_state != null && (Object)(object)player == (Object)(object)_state.Player)
		{
			context = _state.Context;
			activationMode = _state.ActivationMode;
			val = GetMoveHotkey(activationMode, context);
			return ((KeyboardShortcut)(ref val)).IsDown();
		}
		if (_pendingRequest != null && (Object)(object)player == (Object)(object)_pendingRequest.Player)
		{
			context = _pendingRequest.Context;
			activationMode = _pendingRequest.ActivationMode;
			val = GetMoveHotkey(activationMode, context);
			return ((KeyboardShortcut)(ref val)).IsDown();
		}
		bool flag = ((Character)player).InPlaceMode();
		if (activationMode == MoveActivationMode.BuildMenu && flag)
		{
			val = MoveBuildPiecesPlugin.BuildModeMoveHotkey;
			if (((KeyboardShortcut)(ref val)).IsDown())
			{
				context = MoveContext.Build;
				return true;
			}
		}
		if (activationMode == MoveActivationMode.World && !flag && !HasEquippedBuildTool(player))
		{
			val = MoveBuildPiecesPlugin.WorldModeMoveHotkey;
			if (((KeyboardShortcut)(ref val)).IsDown())
			{
				context = MoveContext.World;
				return true;
			}
		}
		if (activationMode == MoveActivationMode.Mixed)
		{
			val = MoveBuildPiecesPlugin.MixedModeMoveHotkey;
			if (((KeyboardShortcut)(ref val)).IsDown())
			{
				if (flag)
				{
					context = MoveContext.Build;
					return true;
				}
				if (!HasEquippedBuildTool(player))
				{
					context = MoveContext.World;
					return true;
				}
			}
		}
		return false;
	}

	private static KeyboardShortcut GetMoveHotkey(MoveActivationMode activationMode, MoveContext context)
	{
		//IL_0004: 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_000e: Unknown result type (might be due to invalid IL or missing references)
		if (activationMode == MoveActivationMode.Mixed)
		{
			return MoveBuildPiecesPlugin.MixedModeMoveHotkey;
		}
		if (context != MoveContext.World)
		{
			return MoveBuildPiecesPlugin.BuildModeMoveHotkey;
		}
		return MoveBuildPiecesPlugin.WorldModeMoveHotkey;
	}

	private static void ToggleMove(Player player, MoveContext context, MoveActivationMode activationMode)
	{
		if (_state != null)
		{
			Cancel(player, showMessage: true);
		}
		else if (_pendingRequest != null)
		{
			CancelPendingRequest(player, showMessage: true, null);
		}
		else
		{
			StartMove(player, context, activationMode);
		}
	}

	private static bool TryInteractDoorInMoveMode(Player player)
	{
		if ((Object)(object)player == (Object)null || _lastDoorInteractFrame == Time.frameCount || Hud.InRadial() || (!ZInput.GetButtonDown("Use") && !ZInput.GetButtonDown("JoyUse")))
		{
			return false;
		}
		Door val = FindDoorForMoveModeInteraction(player);
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		bool flag = ZInput.GetButton("AltPlace") || ZInput.GetButton("JoyAltPlace") || ZInput.GetButton("JoyAltKeys");
		if (!val.Interact((Humanoid)(object)player, false, flag))
		{
			return false;
		}
		_lastDoorInteractFrame = Time.frameCount;
		return true;
	}

	private static Door FindDoorForMoveModeInteraction(Player player)
	{
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)player == (Object)null || (Object)(object)GameCamera.instance == (Object)null)
		{
			return null;
		}
		int num = ((InteractMaskField?.GetValue(player) is int num2) ? num2 : LayerMask.GetMask(new string[5] { "piece", "piece_nonsolid", "Default", "static_solid", "Default_small" }));
		object? obj = EyeField?.GetValue(player);
		Transform val = (Transform)((obj is Transform) ? obj : null);
		float num3 = ((MaxInteractDistanceField?.GetValue(player) is float num4) ? num4 : 5f);
		Transform transform = ((Component)GameCamera.instance).transform;
		GameObject placementGhost = GetPlacementGhost(player);
		int num5 = Physics.RaycastNonAlloc(transform.position, transform.forward, DoorInteractHits, 50f, num);
		Array.Sort(DoorInteractHits, 0, num5, RaycastHitDistanceComparer.Instance);
		for (int i = 0; i < num5; i++)
		{
			RaycastHit val2 = DoorInteractHits[i];
			Collider collider = ((RaycastHit)(ref val2)).collider;
			if (!((Object)(object)collider == (Object)null) && !IsPlayerCollider(player, collider) && (!((Object)(object)placementGhost != (Object)null) || !((Component)collider).transform.IsChildOf(placementGhost.transform)))
			{
				if (Vector3.Distance(((Object)(object)val != (Object)null) ? val.position : ((Component)player).transform.position, ((RaycastHit)(ref val2)).point) >= num3)
				{
					return null;
				}
				Door componentInParent = ((Component)collider).GetComponentInParent<Door>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					return componentInParent;
				}
				return null;
			}
		}
		return null;
	}

	private static bool IsPlayerCollider(Player player, Collider collider)
	{
		if ((Object)(object)player == (Object)null || (Object)(object)collider == (Object)null)
		{
			return false;
		}
		if ((Object)(object)collider.attachedRigidbody != (Object)null)
		{
			return (Object)(object)((Component)collider.attachedRigidbody).gameObject == (Object)(object)((Component)player).gameObject;
		}
		return false;
	}

	private static bool TryAcquireOrRequestMoveLock(Player player, Piece piece, MoveContext context, MoveActivationMode activationMode, ZNetView netView, long lockToken)
	{
		long num = (((Object)(object)player != (Object)null) ? player.GetPlayerID() : 0);
		long num2 = (((Object)(object)player != (Object)null) ? ((Character)player).GetOwner() : 0);
		if ((Object)(object)player == (Object)null || (Object)(object)piece == (Object)null || (Object)(object)netView == (Object)null || !netView.IsValid() || num == 0L || num2 == 0L || lockToken == 0L)
		{
			Message(player, "$msg_invalidplacement");
			return false;
		}
		if (!HasVerifiedServerProtocol())
		{
			Message(player, "Matching MoveBuildPieces 1.1.1 is required on the server");
			return false;
		}
		if (!NetworkMovesEnabled)
		{
			Message(player, "MoveBuildPieces is disabled by the server policy");
			return false;
		}
		if (netView.IsOwner())
		{
			if (!TryAcquireMoveLock(netView, num2, player, lockToken, refreshOnly: false, out var message))
			{
				Message(player, message);
				return false;
			}
			return true;
		}
		_pendingRequest = new PendingMoveRequest
		{
			Player = player,
			Piece = piece,
			NetView = netView,
			Context = context,
			ActivationMode = activationMode,
			PlayerId = num,
			LockToken = lockToken,
			ExpectedOwnerPeerId = netView.GetZDO().GetOwner(),
			StartedAt = Time.realtimeSinceStartup,
			LastRequestAt = Time.realtimeSinceStartup
		};
		if (_pendingRequest.ExpectedOwnerPeerId == 0L)
		{
			_pendingRequest = null;
			Message(player, "The object has no network owner yet");
			return false;
		}
		InvokePieceRpc(netView, _pendingRequest.ExpectedOwnerPeerId, "MoveBuildPiecesV4_LockRequest", num, lockToken, false);
		Message(player, "Requesting move lock");
		return false;
	}

	private static void RetryPendingLockAfterOwnerChange(PendingMoveRequest request)
	{
		if (!((Object)(object)request?.NetView == (Object)null) && request.NetView.IsValid() && !(Time.realtimeSinceStartup - request.LastRequestAt < 1.25f))
		{
			ZDO zDO = request.NetView.GetZDO();
			long num = ((zDO != null) ? zDO.GetOwner() : 0);
			if (num != 0L && num != request.ExpectedOwnerPeerId)
			{
				long expectedOwnerPeerId = request.ExpectedOwnerPeerId;
				ReleaseMoveLock(request.NetView, request.PlayerId, request.LockToken, expectedOwnerPeerId);
				request.ExpectedOwnerPeerId = num;
				request.LastRequestAt = Time.realtimeSinceStartup;
				InvokePieceRpc(request.NetView, num, "MoveBuildPiecesV4_LockRequest", request.PlayerId, request.LockToken, false);
			}
		}
	}

	private static bool TryAcquireMoveLock(ZNetView netView, long senderPeerId, Player player, long lockToken, bool refreshOnly, out string message)
	{
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		message = "";
		ZDO val = (((Object)(object)netView != (Object)null && netView.IsValid()) ? netView.GetZDO() : null);
		long num = (((Object)(object)player != (Object)null) ? player.GetPlayerID() : 0);
		if (!NetworkMovesEnabled || !HasVerifiedServerProtocol() || val == null || !netView.IsOwner() || senderPeerId == 0L || num == 0L || lockToken == 0L || ((Character)player).GetOwner() != senderPeerId)
		{
			message = "$msg_invalidplacement";
			return false;
		}
		long num2 = val.GetLong(LockOwnerHash, 0L);
		long num3 = val.GetLong(LockPeerHash, 0L);
		long num4 = val.GetLong(LockTokenHash, 0L);
		double num5 = (double)val.GetLong(LockUntilHash, 0L) / 1000.0;
		double networkTimeSeconds = GetNetworkTimeSeconds();
		bool flag = num2 == num && num3 == senderPeerId && num4 == lockToken && num5 > networkTimeSeconds;
		if (refreshOnly && !flag)
		{
			message = "Move lock was lost";
			return false;
		}
		if (num2 != 0L && num5 > networkTimeSeconds && (num2 != num || num3 != senderPeerId || num4 != lockToken))
		{
			string text = val.GetString(LockNameHash, "another player");
			message = "Already being moved by " + text;
			return false;
		}
		if (!flag && !CanGrantMoveLock(player, ((Component)netView).GetComponent<Piece>(), out message))
		{
			return false;
		}
		float moveLockTimeoutSeconds = MoveBuildPiecesPlugin.MoveLockTimeoutSeconds;
		double num6 = num5 - networkTimeSeconds;
		if (flag && num6 > (double)moveLockTimeoutSeconds - 0.5 && num6 <= (double)moveLockTimeoutSeconds + 0.5)
		{
			return true;
		}
		val.Set(LockOwnerHash, num);
		val.Set(LockPeerHash, senderPeerId);
		val.Set(LockTokenHash, lockToken);
		val.Set(LockUntilHash, SecondsToMillis(networkTimeSeconds + (double)moveLockTimeoutSeconds));
		string playerName = player.GetPlayerName();
		val.Set(LockNameHash, string.IsNullOrWhiteSpace(playerName) ? "another player" : playerName);
		ZDOMan instance = ZDOMan.instance;
		if (instance != null)
		{
			instance.ForceSendZDO(val.m_uid);
		}
		return true;
	}

	private static void RefreshMoveLock(MoveState state)
	{
		if ((Object)(object)state?.NetView == (Object)null || !state.NetView.IsValid() || state.NetView.GetZDO() == null || Time.realtimeSinceStartup - state.LastLockRefreshTime < 2f)
		{
			return;
		}
		state.LastLockRefreshTime = Time.realtimeSinceStartup;
		if (state.NetView.IsOwner())
		{
			if (!TryAcquireMoveLock(state.NetView, state.LockPeerId, state.Player, state.LockToken, refreshOnly: true, out var _))
			{
				Message(state.Player, "Move lock was lost");
				Cancel(state.Player, showMessage: false);
			}
		}
		else if (state.NetView.HasOwner())
		{
			long owner = state.NetView.GetZDO().GetOwner();
			if (owner == 0L)
			{
				Message(state.Player, "Move lock was lost");
				Cancel(state.Player, showMessage: false);
				return;
			}
			state.LockRequestOwnerPeerId = owner;
			state.LockOwnerPeerId = owner;
			InvokePieceRpc(state.NetView, owner, "MoveBuildPiecesV4_LockRequest", state.LockPlayerId, state.LockToken, true);
		}
	}

	private static void ReleaseMoveLock(ZNetView netView, long playerId, long lockToken, long expectedOwnerPeerId = 0L)
	{
		if ((Object)(object)netView == (Object)null || !netView.IsValid() || playerId == 0L || lockToken == 0L)
		{
			return;
		}
		if (netView.IsOwner())
		{
			ClearMoveLock(netView, ZDOMan.GetSessionID(), playerId, lockToken);
			return;
		}
		long num = (netView.HasOwner() ? netView.GetZDO().GetOwner() : 0);
		if (expectedOwnerPeerId != 0L)
		{
			InvokePieceRpc(netView, expectedOwnerPeerId, "MoveBuildPiecesV4_LockRelease", playerId, lockToken);
		}
		if (num != 0L && num != expectedOwnerPeerId)
		{
			InvokePieceRpc(netView, num, "MoveBuildPiecesV4_LockRelease", playerId, lockToken);
		}
	}

	private static bool ClearMoveLock(ZNetView netView, long senderPeerId, long playerId, long lockToken)
	{
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		ZDO val = (((Object)(object)netView != (Object)null && netView.IsValid()) ? netView.GetZDO() : null);
		if (val == null || !netView.IsOwner() || senderPeerId == 0L || playerId == 0L || lockToken == 0L || val.GetLong(LockOwnerHash, 0L) != playerId || val.GetLong(LockPeerHash, 0L) != senderPeerId || val.GetLong(LockTokenHash, 0L) != lockToken)
		{
			return false;
		}
		val.Set(LockOwnerHash, 0L);
		val.Set(LockPeerHash, 0L);
		val.Set(LockTokenHash, 0L);
		val.Set(LockUntilHash, 0L);
		val.Set(LockNameHash, "");
		ZDOMan instance = ZDOMan.instance;
		if (instance != null)
		{
			instance.ForceSendZDO(val.m_uid);
		}
		return true;
	}

	private static void ApplyLockRequestRpc(ZNetView netView, long sender, long playerId, long lockToken, bool refreshOnly)
	{
		if (!((Object)(object)netView == (Object)null) && netView.IsValid() && netView.IsOwner())
		{
			Player player;
			bool num = TryGetAuthenticatedPlayer(sender, playerId, out player);
			string message = "";
			bool flag = num && TryAcquireMoveLock(netView, sender, player, lockToken, refreshOnly, out message);
			if (!num)
			{
				message = "$msg_privatezone";
			}
			if (sender != 0L)
			{
				InvokePieceRpc(netView, sender, "MoveBuildPiecesV4_LockResponse", flag, message, lockToken);
			}
		}
	}

	private static void ApplyLockResponseRpc(ZNetView netView, long sender, bool granted, string message, long lockToken)
	{
		//IL_00a9: 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)
		CancelledLockRequest value;
		if (_state != null && (Object)(object)_state.NetView == (Object)(object)netView && _state.LockToken == lockToken && _state.LockRequestOwnerPeerId == sender)
		{
			_state.LockRequestOwnerPeerId = 0L;
			if (granted)
			{
				_state.LockOwnerPeerId = sender;
			}
			if (!granted)
			{
				Message(_state.Player, string.IsNullOrEmpty(message) ? "Move lock was lost" : message);
				Cancel(_state.Player, showMessage: false);
			}
		}
		else if (CancelledLockRequests.TryGetValue(lockToken, out value))
		{
			if ((Object)(object)netView != (Object)null && netView.IsValid() && netView.GetZDO().m_uid == value.ZdoId && value.ExpectedOwnerPeerId == sender)
			{
				CancelledLockRequests.Remove(lockToken);
				if (granted)
				{
					ReleaseMoveLock(netView, value.PlayerId, value.LockToken, value.ExpectedOwnerPeerId);
				}
			}
		}
		else if (_pendingRequest != null && !((Object)(object)netView == (Object)null) && !((Object)(object)_pendingRequest.NetView != (Object)(object)netView) && _pendingRequest.LockToken == lockToken && _pendingRequest.ExpectedOwnerPeerId == sender)
		{
			PendingMoveRequest pendingRequest = _pendingRequest;
			_pendingRequest = null;
			if (!granted)
			{
				Message(pendingRequest.Player, string.IsNullOrEmpty(message) ? "$msg_inuse" : message);
			}
			else if (!CanBeginPendingMove(pendingRequest) || !ValidateMoveTarget(pendingRequest.Player, pendingRequest.Piece))
			{
				ReleaseMoveLock(pendingRequest.NetView, pendingRequest.PlayerId, pendingRequest.LockToken, pendingRequest.ExpectedOwnerPeerId);
			}
			else
			{
				BeginMoveWithLockedPiece(pendingRequest.Player, pendingRequest.Piece, pendingRequest.Context, pendingRequest.ActivationMode, pendingRequest.NetView, pendingRequest.LockToken, sender);
			}
		}
	}

	private static void ApplyLockReleaseRpc(ZNetView netView, long sender, long playerId, long lockToken)
	{
		if (!((Object)(object)netView == (Object)null) && netView.IsValid() && netView.IsOwner())
		{
			ClearMoveLock(netView, sender, playerId, lockToken);
		}
	}

	private static bool TryGetAuthenticatedPlayer(long senderPeerId, long playerId, out Player player)
	{
		player = null;
		if (senderPeerId == 0L || playerId == 0L)
		{
			return false;
		}
		List<Player> allPlayers = Player.GetAllPlayers();
		for (int i = 0; i < allPlayers.Count; i++)
		{
			Player val = allPlayers[i];
			if ((Object)(object)val != (Object)null && val.GetPlayerID() == playerId && ((Character)val).GetOwner() == senderPeerId && !((Character)val).IsDead() && !((Character)val).IsTeleporting())
			{
				player = val;
				return true;
			}
		}
		return false;
	}

	private static bool CanBeginPendingMove(PendingMoveRequest request)
	{
		if (!HasVerifiedServerProtocol() || !NetworkMovesEnabled || (Object)(object)request?.Player == (Object)null || ((Character)request.Player).IsDead() || ((Character)request.Player).IsTeleporting() || (Object)(object)request.Piece == (Object)null || (Object)(object)request.NetView == (Object)null || !request.NetView.IsValid() || IsUiBlockingInput())
		{
			return false;
		}
		bool flag = ((Character)request.Player).InPlaceMode();
		if (request.Context != MoveContext.Build)
		{
			if (!flag)
			{
				return !HasEquippedBuildTool(request.Player);
			}
			return false;
		}
		return flag;
	}

	private static void CancelPendingRequest(Player player, bool showMessage, string message)
	{
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		PendingMoveRequest pendingRequest = _pendingRequest;
		if (pendingRequest != null && (!((Object)(object)player != (Object)null) || !((Object)(object)pendingRequest.Player != (Object)(object)player)))
		{
			_pendingRequest = null;
			ZDO val = (((Object)(object)pendingRequest.NetView != (Object)null && pendingRequest.NetView.IsValid()) ? pendingRequest.NetView.GetZDO() : null);
			if (val != null)
			{
				CancelledLockRequests[pendingRequest.LockToken] = new CancelledLockRequest
				{
					ZdoId = val.m_uid,
					PlayerId = pendingRequest.PlayerId,
					LockToken = pendingRequest.LockToken,
					ExpectedOwnerPeerId = pendingRequest.ExpectedOwnerPeerId,
					CancelledAt = Time.realtimeSinceStartup
				};
			}
			try
			{
				ReleaseMoveLock(pendingRequest.NetView, pendingRequest.PlayerId, pendingRequest.LockToken, pendingRequest.ExpectedOwnerPeerId);
			}
			catch
			{
			}
			if (showMessage)
			{
				Message(pendingRequest.Player, "Move cancelled");
			}
			else if (!string.IsNullOrEmpty(message))
			{
				Message(pendingRequest.Player, message);
			}
		}
	}

	private static void CleanupCancelledLockRequests()
	{
		if (CancelledLockRequests.Count == 0)
		{
			_nextCancelledRequestCleanupAt = 0f;
			return;
		}
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		if (realtimeSinceStartup < _nextCancelledRequestCleanupAt)
		{
			return;
		}
		_nextCancelledRequestCleanupAt = realtimeSinceStartup + 5f;
		ExpiredRequestTokens.Clear();
		foreach (KeyValuePair<long, CancelledLockRequest> cancelledLockRequest in CancelledLockRequests)
		{
			if (realtimeSinceStartup - cancelledLockRequest.Value.CancelledAt > 310f)
			{
				ExpiredRequestTokens.Add(cancelledLockRequest.Key);
			}
		}
		for (int i = 0; i < ExpiredRequestTokens.Count; i++)
		{
			CancelledLockRequests.Remove(ExpiredRequestTokens[i]);
		}
		ExpiredRequestTokens.Clear();
	}

	private static long CreateRequestToken()
	{
		long num = DateTime.UtcNow.Ticks ^ ZDOMan.GetSessionID() ^ ++_requestTokenCounter;
		if (num != 0L)
		{
			return num;
		}
		return ++_requestTokenCounter;
	}

	private static double GetNetworkTimeSeconds()
	{
		if (!((Object)(object)ZNet.instance != (Object)null))
		{
			return Time.realtimeSinceStartupAsDouble;
		}
		return ZNet.instance.GetTimeSeconds();
	}

	private static long SecondsToMillis(double seconds)
	{
		return (long)(seconds * 1000.0);
	}

	private static void UpdateActiveMovePlacement(Player player)
	{
		if (_state == null || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)_state.Player)
		{
			return;
		}
		if ((Object)(object)GetBuildPieces(player) != (Object)(object)GetRelocatePieceTable(_state))
		{
			Cancel(player, showMessage: true);
			return;
		}
		RotateMoveGhost(player);
		if ((ZInput.GetButtonDown("Attack") || ZInput.GetButtonDown("JoyPlace")) && !Hud.InRadial())
		{
			TryFinishMove(player);
		}
	}

	private static void RotateMoveGhost(Player player)
	{
		//IL_00fd: 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_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Invalid comparison between Unknown and I4
		GameObject placementGhost = GetPlacementGhost(player);
		Piece val = (((Object)(object)placementGhost != (Object)null) ? placementGhost.GetComponent<Piece>() : null);
		if ((Object)(object)player == (Object)null || PlaceRotationField == null || ScrollCurrentAmountField == null || RotatePieceTimerField == null || (Object)(object)val == (Object)null || !val.m_canRotate || !placementGhost.activeInHierarchy)
		{
			return;
		}
		int num = ((PlaceRotationField.GetValue(player) is int num2) ? num2 : 0);
		float num3 = ((ScrollCurrentAmountField.GetValue(player) is float num4) ? num4 : 0f);
		num3 += ZInput.GetMouseScrollWheel();
		if (num3 > player.m_scrollAmountThreshold)
		{
			num3 = 0f;
			num++;
		}
		else if (num3 < 0f - player.m_scrollAmountThreshold)
		{
			num3 = 0f;
			num--;
		}
		float num5 = 0f;
		bool flag = false;
		if (ZInput.IsGamepadActive())
		{
			InputLayout inputLayout = ZInput.InputLayout;
			if ((int)inputLayout != 0)
			{
				if (inputLayout - 1 <= 1)
				{
					bool button = ZInput.GetButton("JoyRotate");
					bool button2 = ZInput.GetButton("JoyRotateRight");
					flag = button || button2;
					num5 = (button ? 0.5f : (button2 ? (-0.5f) : 0f));
				}
			}
			else
			{
				num5 = ZInput.GetJoyRightStickX(true);
				flag = ZInput.GetButton("JoyRotate") && Mathf.Abs(num5) > 0.5f;
			}
		}
		float num6 = ((RotatePieceTimerField.GetValue(player) is float num7) ? num7 : 0f);
		if (flag)
		{
			if (num6 == 0f || num6 > 0.25f)
			{
				num += ((num5 < 0f) ? 1 : (-1));
				if (num6 > 0.25f)
				{
					num6 = 0.17f;
				}
			}
			num6 += Time.deltaTime;
		}
		else
		{
			num6 = 0f;
		}
		PlaceRotationField.SetValue(player, num);
		ScrollCurrentAmountField.SetValue(player, num3);
		RotatePieceTimerField.SetValue(player, num6);
	}

	private static void StartMove(Player player, MoveContext context, MoveActivationMode activationMode)
	{
		bool flag = ((Character)player).InPlaceMode();
		if ((context == MoveContext.Build && !flag) || (context == MoveContext.World && (flag || HasEquippedBuildTool(player))))
		{
			return;
		}
		Piece val = ((context == MoveContext.World) ? FindWorldHoveringPiece(player) : player.GetHoveringPiece());
		if ((Object)(object)val == (Object)null)
		{
			Message(player, "Hover a build piece to move it");
		}
		else if (ValidateMoveTarget(player, val))
		{
			ZNetView component = ((Component)val).GetComponent<ZNetView>();
			long lockToken = CreateRequestToken();
			if (TryAcquireOrRequestMoveLock(player, val, context, activationMode, component, lockToken))
			{
				BeginMoveWithLockedPiece(player, val, context, activationMode, component, lockToken, component.GetZDO().GetOwner());
			}
		}
	}

	private static void BeginMoveWithLockedPiece(Player player, Piece piece, MoveContext context, MoveActivationMode activationMode, ZNetView netView, long lockToken, long lockOwnerPeerId)
	{
		//IL_002e: 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)