using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; 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.0.1")] public sealed class MoveBuildPiecesPlugin : BaseUnityPlugin { public const string PluginGuid = "obelisk.valheim.movebuildpieces"; public const string PluginName = "MoveBuildPieces"; public const string PluginVersion = "1.0.1"; private static ConfigEntry _enabled; private static ConfigEntry _moveHotkey; private static ConfigEntry _blockTerrainModifiers; private static ConfigEntry _blockDynamicObjects; private Harmony _harmony; internal static bool IsEnabled => _enabled.Value; internal static KeyboardShortcut MoveHotkey => _moveHotkey.Value; internal static bool BlockTerrainModifiers => _blockTerrainModifiers.Value; internal static bool BlockDynamicObjects => _blockDynamicObjects.Value; private void Awake() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown _enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Enable moving already built pieces while in build mode."); _moveHotkey = ((BaseUnityPlugin)this).Config.Bind("General", "Move hotkey", new KeyboardShortcut((KeyCode)101, Array.Empty()), "Press while hovering a buildable player-built piece in build mode to start or cancel moving it."); _blockTerrainModifiers = ((BaseUnityPlugin)this).Config.Bind("Safety", "Block terrain modifiers", true, "Do not move pieces that contain TerrainModifier or TerrainOp components."); _blockDynamicObjects = ((BaseUnityPlugin)this).Config.Bind("Safety", "Block dynamic objects", true, "Do not move ships, carts, characters, or pieces with non-kinematic rigidbodies."); MoveController.Initialize(); _harmony = new Harmony("obelisk.valheim.movebuildpieces"); _harmony.PatchAll(); } private void OnDestroy() { MoveController.Reset(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } [HarmonyPatch(typeof(Player), "Update")] internal static class PlayerUpdatePatch { private static void Postfix(Player __instance) { MoveController.Update(__instance); } } [HarmonyPatch(typeof(Player), "LateUpdate")] internal static class PlayerLateUpdatePatch { private static void Postfix(Player __instance) { MoveController.UpdateVisuals(__instance); } } [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(Player), "TryPlacePiece")] internal static class PlayerTryPlacePiecePatch { private static bool Prefix(Player __instance, Piece piece, ref bool __result) { if (!MoveController.IsMovingWith(__instance, piece)) { return true; } __result = false; MoveController.TryFinishMove(__instance); return false; } } internal static class MoveController { private sealed class MoveState { public Player Player; public Piece Piece; public ZNetView NetView; public string PrefabName; public Vector3 OriginalPosition; public Quaternion OriginalRotation; public List OriginalBaseAreas; public GameObject HighlightedGhost; public bool GhostHighlighted; } private sealed class MoveSelectionOverride { public Player Player; public string PrefabName; } private static class SupportCollidersBuffer { public static readonly Collider[] Items = (Collider[])(object)new Collider[128]; } private static readonly FieldInfo PlacementGhostField = AccessTools.Field(typeof(Player), "m_placementGhost"); private static readonly FieldInfo PlacementStatusField = AccessTools.Field(typeof(Player), "m_placementStatus"); private static readonly MethodInfo SetupPlacementGhostMethod = AccessTools.Method(typeof(Player), "SetupPlacementGhost", (Type[])null, (Type[])null); private static readonly MethodInfo UpdateAvailablePiecesListMethod = AccessTools.Method(typeof(Player), "UpdateAvailablePiecesList", (Type[])null, (Type[])null); private static readonly MethodInfo ClearCachedSupportMethod = AccessTools.Method(typeof(WearNTear), "RPC_ClearCachedSupport", (Type[])null, (Type[])null); 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 List SupportColliders = new List(); private static readonly HashSet SupportPieces = new HashSet(); private static readonly RaycastHit[] FloorHits = (RaycastHit[])(object)new RaycastHit[16]; private static MoveState _state; private static MoveSelectionOverride _selectionOverride; private static GameObject _lineObject; private static LineRenderer _dashLine; private static LineRenderer _originRing; private static LineRenderer _ghostRing; private static Texture2D _dashTexture; private static int _floorMask; public static void Initialize() { Reset(); } public static void Reset() { _state = null; DestroyLine(); } public static void Update(Player player) { //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) if (!MoveBuildPiecesPlugin.IsEnabled || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return; } if (ShouldCancelForUiOrState(player)) { Cancel(player, showMessage: false); return; } if (!IsUiBlockingInput()) { KeyboardShortcut moveHotkey = MoveBuildPiecesPlugin.MoveHotkey; if (((KeyboardShortcut)(ref moveHotkey)).IsDown()) { if (_state != null) { Cancel(player, showMessage: true); } else { StartMove(player); } } } if (_state != null) { UpdateMoveGhostValidity(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 bool IsMovingWith(Player player, Piece selectedPiece) { if (_state == null || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)_state.Player || (Object)(object)selectedPiece == (Object)null) { return false; } return Utils.GetPrefabName(((Component)selectedPiece).gameObject) == _state.PrefabName; } 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 //IL_0056: 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) 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 && prefabName == _state.PrefabName) { return CanBypassResourceRequirements(player, piece, mode); } if (_selectionOverride != null && (Object)(object)player == (Object)(object)_selectionOverride.Player && prefabName == _selectionOverride.PrefabName) { return CanBypassResourceRequirements(player, piece, mode); } return false; } public static void TryFinishMove(Player player) { //IL_003e: 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_0063: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) if (_state == null || (Object)(object)player != (Object)(object)_state.Player) { return; } GameObject placementGhost = GetPlacementGhost(player); if ((Object)(object)placementGhost == (Object)null) { Message(player, "$msg_invalidplacement"); Cancel(player, showMessage: false); return; } if ((int)GetPlacementStatus(player) != 0) { Message(player, "$msg_invalidplacement"); return; } Vector3 position = placementGhost.transform.position; Quaternion rotation = placementGhost.transform.rotation; if (ValidateMoveDestination(player, position, showMessage: true) && ValidateMoveTarget(player, _state.Piece)) { MovePiece(_state, position, rotation); Message(player, "Moved " + Localization.instance.Localize(_state.Piece.m_name)); _state.Piece.m_placeEffect.Create(position, rotation, ((Component)_state.Piece).transform, 1f, -1); Cancel(player, showMessage: false); } } private static void StartMove(Player player) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_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_00e7: Unknown result type (might be due to invalid IL or missing references) if (!((Character)player).InPlaceMode()) { return; } Piece hoveringPiece = player.GetHoveringPiece(); if ((Object)(object)hoveringPiece == (Object)null) { Message(player, "Hover a build piece to move it"); } else { if (!ValidateMoveTarget(player, hoveringPiece)) { return; } if (!SelectMovePiece(player, hoveringPiece)) { Message(player, "$msg_missingrequirement"); return; } SetupPlacementGhostMethod?.Invoke(player, Array.Empty()); if ((Object)(object)GetPlacementGhost(player) == (Object)null) { Message(player, "$msg_invalidplacement"); return; } List baseAreasAt = GetBaseAreasAt(((Component)hoveringPiece).transform.position); if (baseAreasAt.Count == 0) { Message(player, "Only pieces inside a base territory can be moved"); return; } _state = new MoveState { Player = player, Piece = hoveringPiece, NetView = ((Component)hoveringPiece).GetComponent(), PrefabName = Utils.GetPrefabName(((Component)hoveringPiece).gameObject), OriginalPosition = ((Component)hoveringPiece).transform.position, OriginalRotation = ((Component)hoveringPiece).transform.rotation, OriginalBaseAreas = baseAreasAt }; Message(player, "Move mode: place the ghost to move " + Localization.instance.Localize(hoveringPiece.m_name)); UpdateMoveGhostValidity(player); } } private static bool SelectMovePiece(Player player, Piece piece) { _selectionOverride = new MoveSelectionOverride { Player = player, PrefabName = Utils.GetPrefabName(((Component)piece).gameObject) }; try { UpdateAvailablePiecesListMethod?.Invoke(player, Array.Empty()); return player.SetSelectedPiece(piece); } finally { _selectionOverride = null; } } private static bool ValidateMoveTarget(Player player, Piece piece) { //IL_0037: 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_007c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)piece == (Object)null || (Object)(object)player == (Object)null) { return false; } if (!piece.m_canBeRemoved || !piece.IsPlacedByPlayer()) { Message(player, "Only player-built removable pieces can be moved"); return false; } if (Location.IsInsideNoBuildLocation(((Component)piece).transform.position)) { Message(player, "$msg_nobuildzone"); return false; } if (!PrivateArea.CheckAccess(((Component)piece).transform.position, 0f, true, false)) { Message(player, "$msg_privatezone"); return false; } if (!IsInsideBaseTerritory(((Component)piece).transform.position)) { Message(player, "Only pieces inside a base territory can be moved"); return false; } ZNetView component = ((Component)piece).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid()) { Message(player, "$msg_invalidplacement"); return false; } if (!piece.CanBeRemoved()) { Message(player, "$msg_cantremovenow"); return false; } if (MoveBuildPiecesPlugin.BlockTerrainModifiers && HasTerrainMutation(piece)) { Message(player, "Pieces that modify terrain are blocked"); return false; } if (MoveBuildPiecesPlugin.BlockDynamicObjects && HasBlockedDynamicComponent(piece)) { Message(player, "Dynamic pieces are blocked"); return false; } if (IsContainerInUse(piece)) { Message(player, "$msg_inuse"); return false; } return true; } private static bool HasTerrainMutation(Piece piece) { if (!((Object)(object)((Component)piece).GetComponentInChildren(true) != (Object)null)) { return (Object)(object)((Component)piece).GetComponentInChildren(true) != (Object)null; } return true; } private static bool HasBlockedDynamicComponent(Piece piece) { if ((Object)(object)((Component)piece).GetComponentInChildren(true) != (Object)null || (Object)(object)((Component)piece).GetComponentInChildren(true) != (Object)null || (Object)(object)((Component)piece).GetComponentInChildren(true) != (Object)null) { return true; } Rigidbody[] componentsInChildren = ((Component)piece).GetComponentsInChildren(true); foreach (Rigidbody val in componentsInChildren) { if ((Object)(object)val != (Object)null && !val.isKinematic) { return true; } } return false; } private static bool IsContainerInUse(Piece piece) { Container[] componentsInChildren = ((Component)piece).GetComponentsInChildren(true); foreach (Container val in componentsInChildren) { if ((Object)(object)val != (Object)null && val.IsInUse()) { return true; } } return false; } private static bool IsInsideBaseTerritory(Vector3 point) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return (Object)(object)EffectArea.IsPointInsideArea(point, (Type)4, 0.05f) != (Object)null; } private static bool ValidateMoveDestination(Player player, Vector3 targetPosition, bool showMessage) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_00b7: Unknown result type (might be due to invalid IL or missing references) if (Location.IsInsideNoBuildLocation(targetPosition)) { if (showMessage) { Message(player, "$msg_nobuildzone"); } return false; } if (!PrivateArea.CheckAccess(targetPosition, 0f, true, false)) { if (showMessage) { Message(player, "$msg_privatezone"); } return false; } if (!IsInsideMoveTerritory(targetPosition)) { if (showMessage) { Message(player, "Target is outside the original base territory"); } return false; } if ((Object)(object)_state?.Piece != (Object)null && !HasRequiredBuildStationInRange(_state.Piece, ((Component)player).transform.position)) { if (showMessage) { Message(player, "$msg_missingstation"); } return false; } if ((Object)(object)_state?.Piece != (Object)null && !HasRequiredBuildStationInRange(_state.Piece, targetPosition)) { if (showMessage) { Message(player, "$msg_missingstation"); } return false; } return true; } private static bool CanBypassResourceRequirements(Player player, Piece piece, RequirementMode mode) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!player.HaveRequirements(piece, (RequirementMode)1)) { return false; } if ((int)mode == 0) { return HasRequiredBuildStationInRange(piece, ((Component)player).transform.position); } return true; } private static bool HasRequiredBuildStationInRange(Piece piece, Vector3 point) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)piece == (Object)null || (Object)(object)piece.m_craftingStation == (Object)null) { return true; } if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)22)) { return true; } return (Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, point) != (Object)null; } private static bool IsInsideMoveTerritory(Vector3 point) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (_state?.OriginalBaseAreas == null || _state.OriginalBaseAreas.Count == 0) { return false; } foreach (EffectArea originalBaseArea in _state.OriginalBaseAreas) { if (IsPointInsideArea(originalBaseArea, point)) { return true; } } return false; } private static List GetBaseAreasAt(Vector3 point) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) List list = new List(); foreach (EffectArea allArea in EffectArea.GetAllAreas()) { if (IsPointInsideArea(allArea, point)) { list.Add(allArea); } } return list; } private static bool IsPointInsideArea(EffectArea area, Vector3 point) { //IL_000a: 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) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)area == (Object)null || (area.m_type & 4) == 0) { return false; } Collider component = ((Component)area).GetComponent(); if (!((Object)(object)component == (Object)null)) { Bounds bounds = component.bounds; if (((Bounds)(ref bounds)).Contains(point)) { return Vector3.Distance(component.ClosestPoint(point), point) <= 0.1f; } } return false; } private static void MovePiece(MoveState state, Vector3 targetPosition, Quaternion targetRotation) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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_0083: Unknown result type (might be due to invalid IL or missing references) ZNetView netView = state.NetView; if (!netView.IsOwner()) { netView.ClaimOwnership(); } ClearSupportCachesNear(state.OriginalPosition); ClearSupportCachesNear(targetPosition); ZDO zDO = netView.GetZDO(); zDO.SetPosition(targetPosition); zDO.SetRotation(targetRotation); ((Component)state.Piece).transform.SetPositionAndRotation(targetPosition, targetRotation); Rigidbody[] componentsInChildren = ((Component)state.Piece).GetComponentsInChildren(true); foreach (Rigidbody val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { val.position = targetPosition; val.rotation = targetRotation; val.linearVelocity = Vector3.zero; val.angularVelocity = Vector3.zero; } } Physics.SyncTransforms(); ClearSupportCachesNear(targetPosition); } private static void ClearSupportCachesNear(Vector3 position) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (ClearCachedSupportMethod == null) { return; } SupportColliders.Clear(); SupportPieces.Clear(); int num = Physics.OverlapSphereNonAlloc(position, 8f, SupportCollidersBuffer.Items, LayerMask.GetMask(new string[2] { "piece", "piece_nonsolid" })); for (int i = 0; i < num; i++) { Collider val = SupportCollidersBuffer.Items[i]; WearNTear val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInParent() : null); if ((Object)(object)val2 != (Object)null && SupportPieces.Add(val2)) { ClearCachedSupportMethod.Invoke(val2, new object[1] { ZDOMan.GetSessionID() }); ZNetView component = ((Component)val2).GetComponent(); if ((Object)(object)component != (Object)null && component.IsValid()) { component.InvokeRPC(ZNetView.Everybody, "RPC_ClearCachedSupport", Array.Empty()); } } } } private static void UpdateMoveGhostValidity(Player player) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Invalid comparison between Unknown and I4 GameObject placementGhost = GetPlacementGhost(player); if (_state == null || (Object)(object)placementGhost == (Object)null || (Object)(object)_state.Piece == (Object)null) { Cancel(player, showMessage: false); return; } bool flag = ValidateMoveDestination(player, placementGhost.transform.position, showMessage: false); Piece component = placementGhost.GetComponent(); if (!((Object)(object)component != (Object)null)) { return; } if (flag && (int)GetPlacementStatus(player) == 0) { component.SetInvalidPlacementHeightlight(false); if ((Object)(object)_state.HighlightedGhost != (Object)(object)placementGhost || !_state.GhostHighlighted) { ApplyMoveGhostHighlight(placementGhost); _state.HighlightedGhost = placementGhost; _state.GhostHighlighted = true; } } else { component.SetInvalidPlacementHeightlight(true); _state.GhostHighlighted = false; } } private static void UpdateLineAndGhost(Player player) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_005b: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: 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_00a3: 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) GameObject placementGhost = GetPlacementGhost(player); if (_state == null || (Object)(object)placementGhost == (Object)null || (Object)(object)_state.Piece == (Object)null) { Cancel(player, showMessage: false); return; } EnsureLine(); Vector3 position = ((Component)_state.Piece).transform.position; Vector3 position2 = placementGhost.transform.position; Vector3 val = ProjectToGround(position); Vector3 val2 = ProjectToGround(position2); Vector3 topLinkPoint = GetTopLinkPoint(((Component)_state.Piece).gameObject, val); Vector3 topLinkPoint2 = GetTopLinkPoint(placementGhost, val2); float ringRadius = GetRingRadius(((Component)_state.Piece).gameObject); float ringRadius2 = GetRingRadius(placementGhost); UpdateLinkObject(val, val2, topLinkPoint, topLinkPoint2, ringRadius, ringRadius2, placementGhost.activeInHierarchy); UpdateMoveGhostValidity(player); } private static void UpdateLinkObject(Vector3 groundStart, Vector3 groundEnd, Vector3 linkStart, Vector3 linkEnd, float originRingRadius, float ghostRingRadius, bool visible) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00bc: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_lineObject == (Object)null) && !((Object)(object)_dashLine == (Object)null) && !((Object)(object)_originRing == (Object)null) && !((Object)(object)_ghostRing == (Object)null)) { if (!IsFinite(linkStart) || !IsFinite(linkEnd) || Vector3.Distance(linkStart, linkEnd) <= 0.05f) { linkStart = groundStart + Vector3.up * 1.25f; linkEnd = groundEnd + Vector3.up * 1.25f; } float num = Vector3.Distance(linkStart, linkEnd); bool num2 = visible && num > 0.05f; SetLineVisible(num2); if (num2) { DrawRing(_originRing, groundStart, originRingRadius); DrawRing(_ghostRing, groundEnd, ghostRingRadius); DrawDash(linkStart, linkEnd, num); } } } private static void ApplyMoveGhostHighlight(GameObject ghost) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = ghost.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } Material[] materials = val.materials; foreach (Material val2 in materials) { if (!((Object)(object)val2 == (Object)null)) { SetMaterialColor(val2, "_Color", GhostColor); SetMaterialColor(val2, "_BaseColor", GhostColor); SetMaterialColor(val2, "_TintColor", GhostColor); SetMaterialColor(val2, "_EmissionColor", GhostEmissionColor); val2.EnableKeyword("_EMISSION"); } } } } private static void SetMaterialColor(Material material, string property, Color color) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (material.HasProperty(property)) { material.SetColor(property, color); } } private static Vector3 ProjectToGround(Vector3 worldPosition) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (TryFindFloorY(worldPosition, 4f, out var floorY)) { return new Vector3(worldPosition.x, floorY + 0.03f, worldPosition.z); } return worldPosition; } private static Vector3 GetTopLinkPoint(GameObject gameObject, Vector3 fallbackGroundPoint) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_007b: 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_00a0: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) if (TryGetObjectBounds(gameObject, out var bounds)) { Vector3 center = ((Bounds)(ref bounds)).center; float num = Mathf.Max(((Bounds)(ref bounds)).max.y + 0.15f, fallbackGroundPoint.y + 0.35f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(center.x, num, center.z); if (IsFinite(val)) { return val; } } Piece component = gameObject.GetComponent(); if ((Object)(object)component != (Object)null && TryGetSnapPointBounds(component, out bounds)) { Vector3 center2 = ((Bounds)(ref bounds)).center; float num2 = Mathf.Max(((Bounds)(ref bounds)).max.y + 0.15f, fallbackGroundPoint.y + 0.35f); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(center2.x, num2, center2.z); if (IsFinite(val2)) { return val2; } } return fallbackGroundPoint + Vector3.up * 1.25f; } private static bool TryGetObjectBounds(GameObject gameObject, out Bounds bounds) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) bool hasBounds = TryCollectColliderBounds(gameObject, out bounds); if (!IsUsefulBounds(bounds, hasBounds)) { hasBounds = TryCollectRendererBounds(gameObject, out bounds); } if (!IsUsefulBounds(bounds, hasBounds)) { hasBounds = TryCollectMeshBounds(gameObject, out bounds); } return IsUsefulBounds(bounds, hasBounds); } private static float GetRingRadius(GameObject gameObject) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (TryGetObjectBounds(gameObject, out var bounds)) { float num = Mathf.Sqrt(((Bounds)(ref bounds)).extents.x * ((Bounds)(ref bounds)).extents.x + ((Bounds)(ref bounds)).extents.z * ((Bounds)(ref bounds)).extents.z); if (IsFinite(num) && num > 0f) { return Mathf.Clamp(num + 0.25f, 0.6f, 8f); } } return 0.6f; } private static bool TryCollectColliderBounds(GameObject gameObject, out Bounds bounds) { //IL_0003: 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) bool hasBounds = false; bounds = default(Bounds); Collider[] componentsInChildren = gameObject.GetComponentsInChildren(true); foreach (Collider val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && val.enabled && !val.isTrigger) { AddBounds(ref bounds, ref hasBounds, val.bounds); } } return hasBounds; } private static bool TryCollectRendererBounds(GameObject gameObject, out Bounds bounds) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) bool hasBounds = false; bounds = default(Bounds); Renderer[] componentsInChildren = gameObject.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && val.enabled && !(((object)val).GetType().Name == "ParticleSystemRenderer")) { AddBounds(ref bounds, ref hasBounds, val.bounds); } } return hasBounds; } private static bool TryCollectMeshBounds(GameObject gameObject, out Bounds bounds) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_0079: Unknown result type (might be due to invalid IL or missing references) bool hasBounds = false; bounds = default(Bounds); MeshFilter[] componentsInChildren = gameObject.GetComponentsInChildren(true); foreach (MeshFilter val in componentsInChildren) { Mesh val2 = (((Object)(object)val != (Object)null) ? val.sharedMesh : null); if (!((Object)(object)val2 == (Object)null)) { Bounds bounds2 = val2.bounds; Vector3 val3 = ((Component)val).transform.TransformPoint(((Bounds)(ref bounds2)).center); Vector3 val4 = Vector3.Scale(((Bounds)(ref bounds2)).size, Abs(((Component)val).transform.lossyScale)); AddBounds(ref bounds, ref hasBounds, new Bounds(val3, val4)); } } return hasBounds; } private static bool TryGetSnapPointBounds(Piece piece, out Bounds bounds) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) List list = new List(); piece.GetSnapPoints(list); bool hasBounds = false; bounds = default(Bounds); Bounds candidate = default(Bounds); foreach (Transform item in list) { if (!((Object)(object)item == (Object)null)) { ((Bounds)(ref candidate))..ctor(item.position, Vector3.one * 0.05f); AddBounds(ref bounds, ref hasBounds, candidate); } } return hasBounds; } private static void AddBounds(ref Bounds bounds, ref bool hasBounds, Bounds candidate) { //IL_0002: 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) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (IsFinite(((Bounds)(ref candidate)).center) && IsFinite(((Bounds)(ref candidate)).size)) { if (!hasBounds) { bounds = candidate; hasBounds = true; } else { ((Bounds)(ref bounds)).Encapsulate(candidate); } } } private static bool IsUsefulBounds(Bounds bounds, bool hasBounds) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (hasBounds && IsFinite(((Bounds)(ref bounds)).center) && IsFinite(((Bounds)(ref bounds)).size)) { Vector3 size = ((Bounds)(ref bounds)).size; return ((Vector3)(ref size)).sqrMagnitude >= 0.0025000002f; } return false; } private static Vector3 Abs(Vector3 vector) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) return new Vector3(Mathf.Abs(vector.x), Mathf.Abs(vector.y), Mathf.Abs(vector.z)); } private static bool IsFinite(Vector3 vector) { //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_001a: Unknown result type (might be due to invalid IL or missing references) if (IsFinite(vector.x) && IsFinite(vector.y)) { return IsFinite(vector.z); } return false; } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static bool TryFindFloorY(Vector3 worldPosition, float searchHeight, out float floorY) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) floorY = worldPosition.y; if (_floorMask == 0) { _floorMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "terrain", "water" }); } int num = Physics.RaycastNonAlloc(worldPosition + Vector3.up * 0.25f, Vector3.down, FloorHits, searchHeight, _floorMask, (QueryTriggerInteraction)1); bool flag = false; float num2 = float.NegativeInfinity; for (int i = 0; i < num; i++) { RaycastHit val = FloorHits[i]; if (!(((RaycastHit)(ref val)).normal.y < 0.7f) && !(((RaycastHit)(ref val)).point.y > worldPosition.y + 0.2f) && !(((RaycastHit)(ref val)).point.y <= num2)) { num2 = ((RaycastHit)(ref val)).point.y; flag = true; } } if (flag) { floorY = num2; } return flag; } private static void DrawRing(LineRenderer ring, Vector3 center, float radius) { //IL_002b: 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_0037: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_005f: Unknown result type (might be due to invalid IL or missing references) if (ring.positionCount != 28) { ring.positionCount = 28; } for (int i = 0; i < 28; i++) { float num = (float)i / 28f * (float)Math.PI * 2f; Vector3 val = center + (Vector3.right * Mathf.Cos(num) + Vector3.forward * Mathf.Sin(num)) * radius; ring.SetPosition(i, val); } } private static void DrawDash(Vector3 from, Vector3 to, float length) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) _dashLine.positionCount = 2; _dashLine.SetPosition(0, from); _dashLine.SetPosition(1, to); Material material = ((Renderer)_dashLine).material; if (!((Object)(object)material == (Object)null)) { EnsureDashTexture(); material.mainTexture = (Texture)(object)_dashTexture; material.mainTextureScale = new Vector2(Mathf.Max(0.01f, length / 0.35f), 1f); material.mainTextureOffset = new Vector2((0f - Time.time) * 1.6f, 0f); } } private static void EnsureDashTexture() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_dashTexture != (Object)null)) { _dashTexture = new Texture2D(10, 1, (TextureFormat)4, false) { wrapMode = (TextureWrapMode)0, filterMode = (FilterMode)1 }; Color[] array = (Color[])(object)new Color[10]; for (int i = 0; i < 10; i++) { array[i] = (Color)((i < 6) ? Color.white : new Color(1f, 1f, 1f, 0f)); } _dashTexture.SetPixels(array); _dashTexture.Apply(); } } private static bool ShouldCancelForUiOrState(Player player) { if (_state == null) { return false; } if (!MoveBuildPiecesPlugin.IsEnabled || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)_state.Player || !((Character)player).InPlaceMode() || ((Character)player).IsDead()) { return true; } if ((Object)(object)_state.NetView == (Object)null || !_state.NetView.IsValid() || (Object)(object)_state.Piece == (Object)null) { return true; } if (IsUiBlockingInput() || Hud.IsPieceSelectionVisible()) { return true; } return ZInput.GetKeyDown((KeyCode)27, true); } private static bool IsUiBlockingInput() { if (!Menu.IsVisible() && !InventoryGui.IsVisible() && !Console.IsVisible() && !TextInput.IsVisible() && !Minimap.IsOpen()) { if ((Object)(object)Chat.instance != (Object)null) { return Chat.instance.HasFocus(); } return false; } return true; } private static void Cancel(Player player, bool showMessage) { if (_state != null && showMessage) { Message(player, "Move cancelled"); } _state = null; DestroyLine(); } private static GameObject GetPlacementGhost(Player player) { object? obj = PlacementGhostField?.GetValue(player); return (GameObject)((obj is GameObject) ? obj : null); } private static PlacementStatus GetPlacementStatus(Player player) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) object obj = PlacementStatusField?.GetValue(player); if (obj is PlacementStatus) { return (PlacementStatus)obj; } return (PlacementStatus)1; } private static void EnsureLine() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if (!((Object)(object)_lineObject != (Object)null)) { _lineObject = new GameObject("MoveBuildPieces_LinkVisuals"); Object.DontDestroyOnLoad((Object)(object)_lineObject); _dashLine = CreateLineRenderer("MoveBuildPieces_Dash", loop: false, tiled: true); _originRing = CreateLineRenderer("MoveBuildPieces_OriginRing", loop: true, tiled: false); _ghostRing = CreateLineRenderer("MoveBuildPieces_GhostRing", loop: true, tiled: false); SetLineVisible(visible: false); } } private static LineRenderer CreateLineRenderer(string name, bool loop, bool tiled) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_00d3: 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_00f4: Expected O, but got Unknown GameObject val = new GameObject(name); val.transform.SetParent(_lineObject.transform, false); LineRenderer val2 = val.AddComponent(); val2.useWorldSpace = true; val2.loop = loop; val2.numCapVertices = 4; val2.numCornerVertices = 2; val2.textureMode = (LineTextureMode)(tiled ? 1 : 0); val2.alignment = (LineAlignment)0; val2.positionCount = 0; val2.widthMultiplier = 0.075f; val2.startColor = (loop ? RingColor : LinkColor); val2.endColor = (loop ? RingColor : LinkColor); ((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)val2).receiveShadows = false; Shader val3 = Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Color") ?? Shader.Find("Standard"); if ((Object)(object)val3 != (Object)null) { ((Renderer)val2).material = new Material(val3) { name = name + "_Material", renderQueue = 3100 }; } ((Renderer)val2).enabled = false; return val2; } private static void SetLineVisible(bool visible) { if ((Object)(object)_dashLine != (Object)null) { ((Renderer)_dashLine).enabled = visible; } if ((Object)(object)_originRing != (Object)null) { ((Renderer)_originRing).enabled = visible; } if ((Object)(object)_ghostRing != (Object)null) { ((Renderer)_ghostRing).enabled = visible; } } private static void DestroyLine() { if ((Object)(object)_lineObject != (Object)null) { Object.Destroy((Object)(object)_lineObject); } _lineObject = null; _dashLine = null; _originRing = null; _ghostRing = null; } private static void Message(Player player, string text) { if ((Object)(object)player != (Object)null) { ((Character)player).Message((MessageType)2, text, 0, (Sprite)null); } } }