private static bool SharedCheckTileRequirementsForRelocation( ICharacter character, IStaticWorldObject objectStructure, Vector2Ushort toPosition, out string errorMessage, bool logErrors) { if (!(objectStructure.ProtoGameObject is IProtoObjectStructure protoStructure)) { errorMessage = null; return(false); } var world = Api.IsServer ? (IWorldService)Server.World : (IWorldService)Client.World; var tileRequirements = protoStructure.TileRequirements; var occupiedTilePositions = new HashSet <Vector2Ushort>(objectStructure.OccupiedTilePositions); foreach (var tileOffset in protoStructure.Layout.TileOffsets) { var tilePosition = new Vector2Ushort((ushort)(toPosition.X + tileOffset.X), (ushort)(toPosition.Y + tileOffset.Y)); if (occupiedTilePositions.Contains(tilePosition)) { // no need to check that tile as the object player want to move is already there continue; } var tile = world.GetTile(tilePosition, logOutOfBounds: false); if (tile.IsOutOfBounds) { errorMessage = "Out of bounds"; } else { var context = new ConstructionTileRequirements.Context(tile, character, protoStructure, tileOffset, startTilePosition: toPosition, objectToRelocate: objectStructure); if (tileRequirements.Check(context, out errorMessage)) { // valid tile continue; } } // check failed if (!logErrors) { return(false); } if (Api.IsServer) { Api.Logger.Warning( $"Cannot move {protoStructure} at {toPosition} - check failed:" + Environment.NewLine + errorMessage); } ConstructionSystem.SharedShowCannotPlaceNotification( character, errorMessage, protoStructure); return(false); } errorMessage = null; return(true); }
public static void ClientStartRelocation(IStaticWorldObject objectStructure) { var protoStructure = objectStructure.ProtoStaticWorldObject; var character = Client.Characters.CurrentPlayerCharacter; if (IsInObjectPlacementMode || ConstructionPlacementSystem.IsInObjectPlacementMode) { // already relocating/placing something return; } if (!SharedIsRelocatable(objectStructure)) { return; } if (!CreativeModeSystem.SharedIsInCreativeMode(character) && !LandClaimSystem.SharedIsOwnedLand(objectStructure.TilePosition, character, out _)) { // the building location or destination is in an area that is not owned by the player ConstructionSystem.SharedShowCannotPlaceNotification( character, LandClaimSystem.ErrorNotLandOwner_Message, protoStructure); return; } var isPvEorWithinInteractionArea = PveSystem.SharedIsPve(false) || protoStructure.SharedIsInsideCharacterInteractionArea( Api.Client.Characters.CurrentPlayerCharacter, objectStructure, writeToLog: false); if (!isPvEorWithinInteractionArea) { CannotInteractMessageDisplay.ClientOnCannotInteract( character, CoreStrings.Notification_TooFar, isOutOfRange: true); return; } if (LandClaimSystem.SharedIsUnderRaidBlock(character, objectStructure)) { // the building is in an area under the raid ConstructionSystem.SharedShowCannotBuildNotification( character, LandClaimSystem.ErrorRaidBlockActionRestricted_Message, protoStructure); return; } if (LandClaimShieldProtectionSystem.SharedIsUnderShieldProtection(objectStructure)) { // the building is in an area under shield protection LandClaimShieldProtectionSystem.SharedSendNotificationActionForbiddenUnderShieldProtection( character); return; } ClientDisableConstructionRelocation(); var sceneObject = Client.Scene.CreateSceneObject("StructureRelocationHelper"); componentObjectPlacementHelper = sceneObject.AddComponent <ClientComponentObjectPlacementHelper>(); componentRelocationHelper = sceneObject.AddComponent <ClientComponentObjectRelocationHelper>(); componentObjectPlacementHelper .Setup(protoStructure, isCancelable: true, isRepeatCallbackIfHeld: false, isDrawConstructionGrid: true, isBlockingInput: true, validateCanPlaceCallback: ClientValidateCanRelocate, placeSelectedCallback: ClientConstructionPlaceSelectedCallback, delayRemainsSeconds: 0.1); componentObjectPlacementHelper.HideBlueprintOnOverlapWithTheSameObject = false; componentRelocationHelper.Setup(objectStructure); void ClientValidateCanRelocate( Vector2Ushort tilePosition, bool logErrors, out bool canPlace, out bool isTooFar) { if (tilePosition == objectStructure.TilePosition) { canPlace = true; isTooFar = false; return; } if (!SharedCheckTileRequirementsForRelocation(character, objectStructure, tilePosition, logErrors: logErrors)) { // time requirements are not valid canPlace = false; isTooFar = false; return; } if (!SharedValidateCanCharacterRelocateStructure(character, objectStructure, tilePosition, logErrors: logErrors)) { canPlace = true; isTooFar = true; return; } if (SharedHasObstacle( character, objectStructure, tilePosition.ToVector2D() + protoStructure.Layout.Center)) { if (logErrors) { CannotInteractMessageDisplay.ClientOnCannotInteract( character, CoreStrings.Notification_ObstaclesOnTheWay, isOutOfRange: true); } canPlace = true; isTooFar = true; return; } canPlace = true; isTooFar = false; } void ClientConstructionPlaceSelectedCallback(Vector2Ushort tilePosition) { if (SharedHasObstacle( character, objectStructure, tilePosition.ToVector2D() + protoStructure.Layout.Center)) { CannotInteractMessageDisplay.ClientOnCannotInteract( character, CoreStrings.Notification_ObstaclesOnTheWay, isOutOfRange: true); return; } ClientTimersSystem.AddAction(0.1, ClientDisableConstructionRelocation); if (tilePosition != objectStructure.TilePosition) { Instance.CallServer(_ => _.ServerRemote_RelocateStructure(objectStructure, tilePosition)); } } }
public static bool SharedValidateCanCharacterRelocateStructure( ICharacter character, IStaticWorldObject objectStructure, Vector2Ushort toPosition, out string errorMessage, bool logErrors) { if (!SharedIsRelocatable(objectStructure)) { errorMessage = null; return(false); } if (!SharedCheckTileRequirementsForRelocation(character, objectStructure, toPosition, out errorMessage, logErrors)) { return(false); } if (!(objectStructure.ProtoGameObject is IProtoObjectStructure protoStructure)) { return(false); } var maxRelocationDistance = PveSystem.SharedIsPve(true) ? MaxRelocationDistancePvE : MaxRelocationDistancePvP; if (objectStructure.TilePosition.TileSqrDistanceTo(toPosition) > maxRelocationDistance * maxRelocationDistance) { if (logErrors) { ConstructionSystem.SharedShowCannotPlaceNotification( character, CoreStrings.Notification_TooFar, protoStructure); } errorMessage = CoreStrings.Notification_TooFar; return(false); } var itemInHands = character.SharedGetPlayerSelectedHotbarItem(); if (!(itemInHands.ProtoGameObject is IProtoItemToolToolbox)) { return(false); } if (CreativeModeSystem.SharedIsInCreativeMode(character)) { errorMessage = null; return(true); } if (!LandClaimSystem.SharedIsOwnedLand(objectStructure.TilePosition, character, requireFactionPermission: true, out var hasNoFactionPermission, ownedArea: out _) || !IsOwnedLand(toPosition, out hasNoFactionPermission)) { errorMessage = string.Format(CoreStrings.Faction_Permission_Required_Format, CoreStrings.Faction_Permission_LandClaimManagement_Title); // the building location or destination is in an area that is not owned by the player if (logErrors) { SharedShowCannotRelocateNotification( character, protoStructure, hasNoFactionPermission); } return(false); } if (LandClaimSystem.SharedIsUnderRaidBlock(character, objectStructure)) { // the building is in an area under the raid errorMessage = LandClaimSystem.ErrorRaidBlockActionRestricted_Message; if (logErrors) { ConstructionSystem.SharedShowCannotPlaceNotification( character, LandClaimSystem.ErrorRaidBlockActionRestricted_Message, protoStructure); } return(false); } if (LandClaimShieldProtectionSystem.SharedIsUnderShieldProtection(objectStructure)) { // the building is in an area under shield protection errorMessage = CoreStrings.ShieldProtection_ActionRestrictedBaseUnderShieldProtection; if (logErrors) { LandClaimShieldProtectionSystem.SharedSendNotificationActionForbiddenUnderShieldProtection( character); } return(false); } errorMessage = null; return(true); bool IsOwnedLand( Vector2Ushort startTilePosition, out bool hasNoFactionPermission) { var worldObjectLayoutTileOffsets = objectStructure.ProtoStaticWorldObject.Layout.TileOffsets; foreach (var tileOffset in worldObjectLayoutTileOffsets) { if (!LandClaimSystem.SharedIsOwnedLand(startTilePosition.AddAndClamp(tileOffset), character, requireFactionPermission: true, out hasNoFactionPermission, out _)) { return(false); } } hasNoFactionPermission = false; return(true); } }
public static bool SharedValidateCanCharacterRelocateStructure( ICharacter character, IStaticWorldObject objectStructure, Vector2Ushort toPosition, bool logErrors) { if (!SharedIsRelocatable(objectStructure)) { return(false); } if (!SharedCheckTileRequirementsForRelocation(character, objectStructure, toPosition, logErrors)) { return(false); } if (!(objectStructure.ProtoGameObject is IProtoObjectStructure protoStructure)) { return(false); } if (objectStructure.TilePosition.TileSqrDistanceTo(toPosition) > MaxRelocationDistance * MaxRelocationDistance) { if (logErrors) { ConstructionSystem.SharedShowCannotPlaceNotification( character, CoreStrings.Notification_TooFar, protoStructure); } return(false); } var itemInHands = character.SharedGetPlayerSelectedHotbarItem(); if (!(itemInHands.ProtoGameObject is IProtoItemToolToolbox)) { return(false); } if (CreativeModeSystem.SharedIsInCreativeMode(character)) { return(true); } if (!LandClaimSystem.SharedIsOwnedLand(objectStructure.TilePosition, character, out _) || !IsOwnedLand(toPosition)) { // the building location or destination is in an area that is not owned by the player if (logErrors) { ConstructionSystem.SharedShowCannotPlaceNotification( character, LandClaimSystem.ErrorNotLandOwner_Message, protoStructure); } return(false); } if (LandClaimSystem.SharedIsUnderRaidBlock(character, objectStructure)) { // the building is in an area under the raid if (logErrors) { ConstructionSystem.SharedShowCannotPlaceNotification( character, LandClaimSystem.ErrorRaidBlockActionRestricted_Message, protoStructure); } return(false); } if (LandClaimShieldProtectionSystem.SharedIsUnderShieldProtection(objectStructure)) { // the building is in an area under shield protection if (logErrors) { LandClaimShieldProtectionSystem.SharedSendNotificationActionForbiddenUnderShieldProtection( character); } return(false); } return(true); bool IsOwnedLand(Vector2Ushort startTilePosition) { var worldObjectLayoutTileOffsets = objectStructure.ProtoStaticWorldObject.Layout.TileOffsets; foreach (var tileOffset in worldObjectLayoutTileOffsets) { if (!LandClaimSystem.SharedIsOwnedLand(startTilePosition.AddAndClamp(tileOffset), character, out _)) { return(false); } } return(true); } }