示例#1
0
        public override void SharedUpdate(double deltaTime)
        {
            // don't invoke the base SharedUpdate implementation as we don't advance the timer here
            if (!ReferenceEquals(this.ItemFishingRod, this.CharacterPublicState.SelectedItem))
            {
                // player changed the selected item
                this.SetCompleted(isCancelled: true);
                this.AbortAction();
                return;
            }

            if (FishingSystem.SharedIsTooFar(this.Character, this.FishingTargetPosition))
            {
                if (Api.IsClient)
                {
                    CannotInteractMessageDisplay.ClientOnCannotInteract(this.Character,
                                                                        CoreStrings.Notification_TooFar,
                                                                        isOutOfRange: true);
                }

                this.Cancel();
                return;
            }

            if (this.SharedFishingSession != null &&
                this.SharedFishingSession.IsDestroyed)
            {
                this.Complete();
            }
        }
示例#2
0
        protected override void SharedValidateRequest(WorldActionRequest request)
        {
            var worldObject = request.WorldObject;

            if (!(worldObject?.ProtoWorldObject is IProtoObjectGatherable))
            {
                throw new Exception("The world object must be gatherable");
            }

            if (!worldObject.ProtoWorldObject.SharedCanInteract(request.Character, worldObject, true))
            {
                throw new Exception("Cannot interact with " + worldObject);
            }

            if (!(worldObject.ProtoGameObject is IProtoObjectGatherable protoGatherable))
            {
                throw new Exception("Not a gatherable resource: " + worldObject);
            }

            if (!protoGatherable.SharedIsCanGather((IStaticWorldObject)worldObject))
            {
                Logger.Warning("Cannot gather now: " + worldObject, request.Character);
                if (Api.IsClient)
                {
                    CannotInteractMessageDisplay.ShowOn(worldObject, NotificationNothingToHarvestYet);
                    worldObject.ProtoWorldObject.SharedGetObjectSoundPreset()
                    .PlaySound(ObjectSound.InteractFail);
                }

                throw new Exception("Cannot gather now: " + worldObject);
            }
        }
        public static bool SharedIsTargetAlreadyScheduledForAnyActiveDrone(
            ICharacter character,
            Vector2Ushort worldPosition,
            bool logError)
        {
            foreach (var objectDrone in character.SharedGetCurrentlyControlledDrones())
            {
                var droneTargetPosition = objectDrone.GetPublicState <DronePublicState>()
                                          .TargetObjectPosition;
                if (droneTargetPosition != worldPosition)
                {
                    continue;
                }

                // the drone is already sent there
                if (logError)
                {
                    if (IsServer)
                    {
                        Logger.Info("Drone already sent there: " + worldPosition, character);
                    }
                    else
                    {
                        CannotInteractMessageDisplay.ClientOnCannotInteract(ClientCurrentCharacterHelper.Character,
                                                                            Notification_DroneAlreadySent,
                                                                            isOutOfRange: false);
                    }
                }

                return(true);
            }

            return(false);
        }
示例#4
0
        protected override async void ClientInteractStart(ClientObjectData data)
        {
            var bedObject = data.GameObject;
            var (isSuccess, name) = await this.CallServer(_ => _.ServerRemote_GetBedOwnerName(bedObject));
            if (!isSuccess)
            {
                ClientOnCannotInteract(bedObject, CoreStrings.Notification_TooFar, isOutOfRange: true);
                return;
            }

            var isFree = string.IsNullOrEmpty(name);
            if (isFree)
            {
                DialogWindow.ShowDialog(
                    DialogClaimBed_Title,
                    DialogClaimBed_Message,
                    okText: CoreStrings.Yes,
                    okAction: () => this.ClientMakeCurrentBed(bedObject),
                    hideCancelButton: false);
                return;
            }

            var message = name == Client.Characters.CurrentPlayerCharacter.Name
                              ? MessageBedBelongsToCurrentPlayer
                              : string.Format(MessageFormatBedBelongsToAnotherPlayer, name);

            CannotInteractMessageDisplay.ShowOn(bedObject, message);
            this.SoundPresetObject.PlaySound(ObjectSound.InteractSuccess);
        }
        public static bool ClientTryStartDrone(
            IItem itemDrone,
            Vector2Ushort worldPosition,
            bool showErrorNotification)
        {
            var character = ClientCurrentCharacterHelper.Character;

            if (SharedIsMaxDronesToControlNumberExceeded(character,
                                                         showErrorNotification) ||
                SharedIsTargetAlreadyScheduledForAnyActiveDrone(character,
                                                                worldPosition,
                                                                showErrorNotification))
            {
                return(false);
            }

            var targetObject = SharedGetCompatibleTarget(character,
                                                         worldPosition,
                                                         out var hasIncompatibleTarget,
                                                         out var isPveActionForbidden);

            if (targetObject is null)
            {
                // nothing to mine there
                if (showErrorNotification)
                {
                    if (isPveActionForbidden)
                    {
                        PveSystem.ClientShowNotificationActionForbidden();
                    }

                    CannotInteractMessageDisplay.ClientOnCannotInteract(
                        character,
                        hasIncompatibleTarget
                            ? Notification_CannotMineThat
                            : Notification_NothingToMineThere,
                        isOutOfRange: false);
                }

                return(false);
            }

            if (!SharedIsValidStartLocation(character, worldPosition, out var hasObstacles))
            {
                if (showErrorNotification)
                {
                    CannotInteractMessageDisplay.ClientOnCannotInteract(
                        character,
                        hasObstacles
                            ? CoreStrings.Notification_ObstaclesOnTheWay
                            : CoreStrings.Notification_TooFar,
                        isOutOfRange: true);
                }

                return(false);
            }

            ClientDroneStartQueue.Add(itemDrone, worldPosition);
            return(true);
        }
示例#6
0
        protected BaseUserControlWithWindow ClientOpenUI(ClientObjectData data)
        {
            var worldObject = data.GameObject;
            var publicState = data.SyncPublicState;

            if (worldObject.ClientHasPrivateState &&
                !Client.Input.IsKeyHeld(InputKey.Alt))
            {
                // open admin window
                return(WindowTradingStationAdmin.Open(
                           new ViewModelWindowTradingStationAdmin(worldObject,
                                                                  data.SyncPrivateState,
                                                                  publicState)));
            }

            // open user window (if has any lots)
            if (publicState.Lots.Any(l => l.State != TradingStationLotState.Disabled))
            {
                return(WindowTradingStationUser.Open(
                           new ViewModelWindowTradingStationUser(worldObject,
                                                                 publicState)));
            }

            CannotInteractMessageDisplay.ShowOn(worldObject,
                                                publicState.Mode == TradingStationMode.StationSelling
                                                    ? NotificationNothingForSale
                                                    : NotificationNoTradingLots);
            return(null);
        }
示例#7
0
 public static void ClientOnCannotInteract(
     IWorldObject worldObject,
     string message,
     bool isOutOfRange = false)
 {
     CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject,
                                                         message,
                                                         isOutOfRange);
 }
示例#8
0
        public static void ClientOnCannotInteractNotOwner(IWorldObject worldObject, bool isFactionAccess)
        {
            var message = isFactionAccess
                              ? WorldObjectAccessModeSystem.NotificationDontHaveAccess
                              : DialogCannotSetOwners_MessageNotOwner;

            CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject,
                                                                message,
                                                                isOutOfRange: false);
        }
        private void RefreshAttachedComponent()
        {
            this.componentAttachedUIElement?.Destroy();
            this.componentAttachedUIElement = null;

            var actionState = this.privateState.CurrentActionState;

            if (actionState is null ||
                !actionState.IsDisplayingProgress)
            {
                return;
            }

            var targetWorldObject = actionState.TargetWorldObject;

            if (targetWorldObject is null)
            {
                // display over the character
                targetWorldObject = (IWorldObject)this.privateState.GameObject;
            }

            Vector2D offset = (0, 1.13);

            if (targetWorldObject == ClientCurrentCharacterHelper.Character &&
                GeneralOptionDisplayHealthbarAboveCurrentCharacter.IsDisplay)
            {
                // adjust the offset so the circle will not overlap with the current character's name and healthbar
                offset += (0, 0.2);
            }

            switch (targetWorldObject.ProtoWorldObject)
            {
            case IProtoStaticWorldObject protoStaticWorldObject:
                offset += protoStaticWorldObject.SharedGetObjectCenterWorldOffset(targetWorldObject);
                break;

            case IProtoCharacter protoCharacter:
                offset += protoCharacter.SharedGetObjectCenterWorldOffset(targetWorldObject);
                break;
            }

            this.componentAttachedUIElement = Client.UI.AttachControl(
                targetWorldObject,
                new ActionProgressControl()
            {
                ActionState = actionState
            },
                positionOffset: offset,
                isFocusable: false);

            CannotInteractMessageDisplay.Hide();
            InteractionTooltip.Hide();
        }
        public virtual void ClientOnCannotInteract(
            TWorldObject worldObject,
            string message,
            bool isOutOfRange = false)
        {
            CannotInteractMessageDisplay.ShowOn(worldObject, message);

            var soundKey = isOutOfRange ? ObjectSound.InteractOutOfRange : ObjectSound.InteractFail;

            worldObject.ProtoWorldObject.SharedGetObjectSoundPreset()
            .PlaySound(soundKey);
        }
示例#11
0
        public static bool SharedCheckCanInteract(
            ICharacter character,
            IWorldObject worldObject,
            bool writeToLog)
        {
            if (worldObject == null ||
                worldObject.IsDestroyed)
            {
                return(false);
            }

            // Can deconstruct only if the character can contact directly
            // with the object click area (if object has the click area)
            // or with the object collider (if object don't has the click area).
            var isObjectHasClickArea = worldObject.PhysicsBody
                                       .Shapes
                                       .Any(s => s.CollisionGroup == CollisionGroups.ClickArea);

            var result = worldObject.ProtoWorldObject.SharedIsInsideCharacterInteractionArea(
                character,
                worldObject,
                writeToLog: false,
                requiredCollisionGroup: isObjectHasClickArea
                                            ? CollisionGroups.ClickArea
                                            : CollisionGroups
                .DefaultWithCollisionToInteractionArea);

            if (result)
            {
                return(true);
            }

            if (writeToLog)
            {
                Logger.Warning(
                    $"Cannot deconstruct - {character} cannot interact with the {worldObject} - there is no direct (physics) line of sight between them (the object click area or static/dynamic colliders must be inside the character interaction area)");

                if (IsClient)
                {
                    CannotInteractMessageDisplay.ShowOn(worldObject, CoreStrings.Notification_TooFar);
                    worldObject.ProtoWorldObject.SharedGetObjectSoundPreset()
                    .PlaySound(ObjectSound.InteractOutOfRange);
                }
            }

            return(false);
        }
示例#12
0
        private void RefreshAttachedComponent()
        {
            this.componentAttachedUIElement?.Destroy();
            this.componentAttachedUIElement = null;

            var actionState = this.privateState.CurrentActionState;

            if (actionState is null ||
                !actionState.IsDisplayingProgress)
            {
                return;
            }

            var targetWorldObject = actionState.TargetWorldObject;

            if (targetWorldObject is null)
            {
                // display over the character
                targetWorldObject = (IWorldObject)this.privateState.GameObject;
            }

            Vector2D offset = (0, 1.01);

            switch (targetWorldObject.ProtoWorldObject)
            {
            case IProtoStaticWorldObject protoStaticWorldObject:
                offset += protoStaticWorldObject.SharedGetObjectCenterWorldOffset(targetWorldObject);
                break;

            case IProtoCharacter protoCharacter:
                offset += protoCharacter.SharedGetObjectCenterWorldOffset(targetWorldObject);
                break;
            }

            this.componentAttachedUIElement = Client.UI.AttachControl(
                targetWorldObject,
                new ActionProgressControl()
            {
                ActionState = actionState
            },
                positionOffset: offset,
                isFocusable: false);

            CannotInteractMessageDisplay.Hide();
            InteractionTooltip.Hide();
        }
示例#13
0
        protected override GatheringActionState SharedTryCreateState(WorldActionRequest request)
        {
            var worldObject = request.WorldObject;
            var character   = request.Character;

            var staticWorldObject = (IStaticWorldObject)worldObject;

            if (!(worldObject.ProtoGameObject is IProtoObjectGatherable protoGatherable))
            {
                throw new Exception("Not a gatherable resource: " + worldObject);
            }

            if (!protoGatherable.SharedIsCanGather(staticWorldObject))
            {
                Logger.Warning("Cannot gather now: " + worldObject, character);
                if (Api.IsClient)
                {
                    CannotInteractMessageDisplay.ShowOn(worldObject, NotificationNothingToHarvestYet);
                    worldObject.ProtoWorldObject.SharedGetObjectSoundPreset()
                    .PlaySound(ObjectSound.InteractFail);
                }

                return(null);
            }

            var durationSeconds = protoGatherable.DurationGatheringSeconds;

            var multiplier = protoGatherable.GetGatheringSpeedMultiplier(staticWorldObject, character);

            durationSeconds /= multiplier;

            if (CreativeModeSystem.SharedIsInCreativeMode(character))
            {
                durationSeconds = 0.1;
            }

            return(new GatheringActionState(
                       character,
                       staticWorldObject,
                       durationSeconds));
        }
示例#14
0
        protected override void SharedValidateRequest(WorldActionRequest request)
        {
            var worldObject = (IStaticWorldObject)request.WorldObject;

            if (!(worldObject?.ProtoWorldObject is IProtoObjectGatherable protoGatherable))
            {
                throw new Exception("The world object must be gatherable");
            }

            if (!worldObject.ProtoWorldObject.SharedCanInteract(request.Character, worldObject, true))
            {
                throw new Exception("Cannot interact with " + worldObject);
            }

            if (!WorldObjectClaimSystem.SharedIsAllowInteraction(request.Character,
                                                                 worldObject,
                                                                 showClientNotification: true))
            {
                throw new Exception("Locked for another player: " + worldObject);
            }

            if (protoGatherable.SharedIsCanGather(worldObject))
            {
                return;
            }

            Logger.Warning("Cannot gather now: " + worldObject, request.Character);
            if (Api.IsClient)
            {
                CannotInteractMessageDisplay.ShowOn(worldObject, NotificationNothingToHarvestYet);
                worldObject.ProtoWorldObject.SharedGetObjectSoundPreset()
                .PlaySound(ObjectSound.InteractFail);
            }

            throw new Exception("Cannot gather now: " + worldObject);
        }
        protected override bool ClientItemUseFinish(ClientItemData data)
        {
            var character             = ClientCurrentCharacterHelper.Character;
            var characterTilePosition = character.TilePosition;
            var mouseTilePosition     = Client.Input.MousePointedTilePosition;
            var dronesNumberToLaunch  = Api.Client.Input.IsKeyHeld(InputKey.Shift, evenIfHandled: true)
                                           ? this.MaxDronesToControl
                                           : 1;

            using var tempExceptDrones  = Api.Shared.GetTempList <IItem>();
            using var tempExceptTargets = Api.Shared.GetTempList <Vector2Ushort>();

            for (var index = 0; index < dronesNumberToLaunch; index++)
            {
                var showErrorNotification = index == 0;
                var itemDrone             = CharacterDroneControlSystem.ClientSelectNextDrone(tempExceptDrones.AsList());
                if (itemDrone is null)
                {
                    if (CharacterDroneControlSystem.SharedIsMaxDronesToControlNumberExceeded(
                            character,
                            clientShowErrorNotification: showErrorNotification))
                    {
                        break;
                    }

                    if (showErrorNotification)
                    {
                        CannotInteractMessageDisplay.ClientOnCannotInteract(
                            character,
                            CharacterDroneControlSystem.Notification_ErrorNoDrones_Title,
                            isOutOfRange: false);
                    }

                    break;
                }

                tempExceptDrones.Add(itemDrone);
                Vector2Ushort targetPosition;

                if (index == 0)
                {
                    targetPosition = mouseTilePosition;
                    var targetObject = CharacterDroneControlSystem
                                       .SharedGetCompatibleTarget(character,
                                                                  mouseTilePosition,
                                                                  out var hasIncompatibleTarget,
                                                                  out var isPveActionForbidden);
                    if (targetObject is null)
                    {
                        if (showErrorNotification)
                        {
                            if (isPveActionForbidden)
                            {
                                PveSystem.ClientShowNotificationActionForbidden();
                            }

                            CannotInteractMessageDisplay.ClientOnCannotInteract(
                                character,
                                hasIncompatibleTarget
                                    ? CharacterDroneControlSystem.Notification_CannotMineThat
                                    : CharacterDroneControlSystem.Notification_NothingToMineThere,
                                isOutOfRange: false);
                        }

                        return(false);
                    }

                    if (!WorldObjectClaimSystem.SharedIsAllowInteraction(character,
                                                                         targetObject,
                                                                         showClientNotification: showErrorNotification))
                    {
                        return(false);
                    }

                    if (CharacterDroneControlSystem.SharedIsTargetAlreadyScheduledForAnyActiveDrone(
                            character,
                            mouseTilePosition,
                            logError: false))
                    {
                        // already scheduled a drone mining there...try find another target of the same type
                        targetPosition = TryGetNextTargetPosition();
                        if (targetPosition == default)
                        {
                            // no further targets
                            CannotInteractMessageDisplay.ClientOnCannotInteract(
                                character,
                                CharacterDroneControlSystem.Notification_DroneAlreadySent,
                                isOutOfRange: false);
                            return(false);
                        }
                    }
                }
                else
                {
                    targetPosition = TryGetNextTargetPosition();
                    if (targetPosition == default)
                    {
                        // no further targets
                        break;
                    }
                }

                if (!CharacterDroneControlSystem.ClientTryStartDrone(itemDrone,
                                                                     targetPosition,
                                                                     showErrorNotification: showErrorNotification))
                {
                    break;
                }

                tempExceptTargets.Add(targetPosition);
            }

            // always return false as we don't want to play any device sounds
            return(false);

            Vector2Ushort TryGetNextTargetPosition()
            {
                var targetObjectProto = CharacterDroneControlSystem
                                        .SharedGetCompatibleTarget(character,
                                                                   mouseTilePosition,
                                                                   out _,
                                                                   out _)?
                                        .ProtoWorldObject;

                if (targetObjectProto is null)
                {
                    return(default);
示例#16
0
        public static bool SharedCheckCanInteract(
            ICharacter character,
            IWorldObject worldObject,
            bool writeToLog)
        {
            if (worldObject == null ||
                worldObject.IsDestroyed)
            {
                return(false);
            }

            // Can build/repair only if the character can contact directly
            // with the object click area (if object has the click area)
            // or with the object collider (if object don't has the click area).
            var isObjectHasClickArea =
                worldObject.PhysicsBody.Shapes.Any(s => s.CollisionGroup == CollisionGroups.ClickArea);

            var result = worldObject.ProtoWorldObject.SharedIsInsideCharacterInteractionArea(
                character,
                worldObject,
                writeToLog: false,
                requiredCollisionGroup: isObjectHasClickArea
                                            ? CollisionGroups.ClickArea
                                            : CollisionGroups
                .DefaultWithCollisionToInteractionArea);

            if (!result)
            {
                if (writeToLog)
                {
                    Logger.Warning(
                        $"Cannot build/repair - {character} cannot interact with the {worldObject} - there is no direct (physics) line of sight between them (the object click area or static/dynamic colliders must be inside the character interaction area)");

                    if (IsClient)
                    {
                        CannotInteractMessageDisplay.ShowOn(worldObject, CoreStrings.Notification_TooFar);
                        worldObject.ProtoWorldObject.SharedGetObjectSoundPreset()
                        .PlaySound(ObjectSound.InteractOutOfRange);
                    }
                }

                return(false);
            }

            if (worldObject is IStaticWorldObject staticWorldObject)
            {
                // ensure the building is not in an area under the raid
                var world = IsClient
                                ? (IWorldService)Client.World
                                : Server.World;

                var protoStaticWorldObject = staticWorldObject.ProtoStaticWorldObject;
                var validatorNoRaid        = LandClaimSystem.ValidatorNoRaid;
                foreach (var tileOffset in protoStaticWorldObject.Layout.TileOffsets)
                {
                    var occupiedTile = world.GetTile(
                        worldObject.TilePosition.X + tileOffset.X,
                        worldObject.TilePosition.Y + tileOffset.Y,
                        logOutOfBounds: false);

                    if (!occupiedTile.IsValidTile)
                    {
                        continue;
                    }

                    if (validatorNoRaid.Function(
                            new ConstructionTileRequirements.Context(
                                occupiedTile,
                                character,
                                protoStaticWorldObject,
                                tileOffset)))
                    {
                        continue;
                    }

                    // raid is under way - cannot build/repair
                    SharedShowCannotBuildNotification(
                        character,
                        validatorNoRaid.ErrorMessage,
                        protoStaticWorldObject);
                    return(false);
                }
            }

            return(true);
        }
示例#17
0
        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,
                                                   requireFactionPermission: true,
                                                   out var hasNoFactionPermission,
                                                   out _))
            {
                // the building location or destination is in an area that is not owned by the player
                SharedShowCannotRelocateNotification(
                    character,
                    protoStructure,
                    hasNoFactionPermission);
                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 string errorMessage,
                out bool canPlace,
                out bool isTooFar)
            {
                if (tilePosition == objectStructure.TilePosition)
                {
                    canPlace     = true;
                    isTooFar     = false;
                    errorMessage = null;
                    return;
                }

                if (!SharedCheckTileRequirementsForRelocation(character,
                                                              objectStructure,
                                                              tilePosition,
                                                              out errorMessage,
                                                              logErrors: logErrors))
                {
                    // time requirements are not valid
                    canPlace = false;
                    isTooFar = false;
                    return;
                }

                if (!SharedValidateCanCharacterRelocateStructure(character,
                                                                 objectStructure,
                                                                 tilePosition,
                                                                 out errorMessage,
                                                                 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);
                    }

                    errorMessage = CoreStrings.Notification_ObstaclesOnTheWay;
                    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));
                }
            }
        }
示例#18
0
        public static bool CheckCanInteractForConstruction(
            ICharacter character,
            IStaticWorldObject worldObject,
            bool writeToLog,
            bool checkRaidblock)
        {
            var characterPosition      = character.Position;
            var canInteract            = false;
            var staticWorldObjectProto = ProtoObjectConstructionSite.SharedGetConstructionProto(worldObject)
                                         ?? worldObject.ProtoStaticWorldObject;

            var startTilePosition = worldObject.TilePosition;

            foreach (var tileOffset in staticWorldObjectProto.Layout.TileOffsets)
            {
                var tilePosition = startTilePosition + tileOffset;

                if (characterPosition.DistanceSquaredTo(
                        new Vector2D(tilePosition.X + 0.5, tilePosition.Y + 0.5))
                    <= MaxDistanceForBuildRepairAction * MaxDistanceForBuildRepairAction)
                {
                    canInteract = true;
                    break;
                }
            }

            if (!canInteract)
            {
                canInteract = CreativeModeSystem.SharedIsInCreativeMode(character);
            }

            if (!canInteract)
            {
                if (writeToLog)
                {
                    Logger.Warning(
                        $"Character cannot interact with {worldObject} for (de)construction - too far.",
                        character);

                    if (IsClient)
                    {
                        CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject,
                                                                            CoreStrings.Notification_TooFar,
                                                                            isOutOfRange: true);
                    }
                }

                return(false);
            }

            if (checkRaidblock &&
                LandClaimSystem.SharedIsUnderRaidBlock(character, worldObject))
            {
                // the building is in an area under the raid
                if (writeToLog)
                {
                    LandClaimSystem.SharedSendNotificationActionForbiddenUnderRaidblock(character);
                }

                return(false);
            }

            return(true);
        }
示例#19
0
        protected override void SharedValidateRequest(FishingActionRequest request)
        {
            var character             = request.Character;
            var fishingTargetPosition = request.FishingTargetPosition;
            var itemRod = request.Item;

            if (itemRod is null ||
                itemRod != character.SharedGetPlayerSelectedHotbarItem() ||
                !(itemRod.ProtoItem is IProtoItemToolFishing))
            {
                throw new Exception("The fishing rod is not selected");
            }

            var fishingRodPublicState = itemRod.GetPublicState <ItemFishingRodPublicState>();

            if (fishingRodPublicState.CurrentProtoBait is null ||
                SharedFindBaitItem(character, fishingRodPublicState.CurrentProtoBait) is null)
            {
                // no bait available
                throw new Exception("There is no bait available of the required type");
            }

            var world = IsServer
                            ? (IWorldService)Server.World
                            : (IWorldService)Client.World;
            var tile = world.GetTile(fishingTargetPosition.ToVector2Ushort());

            if (!(tile.ProtoTile is IProtoTileWater protoTileWater) ||
                !protoTileWater.IsFishingAllowed)
            {
                if (IsClient)
                {
                    CannotInteractMessageDisplay.ClientOnCannotInteract(character,
                                                                        Notification_CannotFishHere,
                                                                        isOutOfRange: false);
                }

                throw new Exception("Cannot fish here");
            }

            // check obstacle objects (such as bridges)
            using var testResults = world.GetPhysicsSpace()
                                    .TestPoint(fishingTargetPosition,
                                               CollisionGroups.Default,
                                               sendDebugEvent: false);

            foreach (var testResult in testResults.AsList())
            {
                if (testResult.PhysicsBody.AssociatedWorldObject is null)
                {
                    continue;
                }

                // an obstacle found
                if (IsClient)
                {
                    CannotInteractMessageDisplay.ClientOnCannotInteract(character,
                                                                        Notification_CannotFishHere,
                                                                        isOutOfRange: false);
                }

                throw new Exception("Cannot fish here");
            }

            if (SharedIsTooFar(character, fishingTargetPosition))
            {
                if (IsClient)
                {
                    CannotInteractMessageDisplay.ClientOnCannotInteract(character,
                                                                        CoreStrings.Notification_TooFar,
                                                                        isOutOfRange: true);
                }

                throw new Exception("Too far");
            }
        }
示例#20
0
        public static bool SharedCheckCanInteract(
            ICharacter character,
            IDynamicWorldObject vehicle,
            bool writeToLog)
        {
            if (vehicle is null ||
                vehicle.IsDestroyed)
            {
                return(false);
            }

            // it's possible to repair any vehicle within a certain distance to the character
            var canInteract = character.Position.DistanceSquaredTo(vehicle.Position)
                              <= MaxDistanceForRepairAction * MaxDistanceForRepairAction;

            if (!canInteract)
            {
                if (writeToLog)
                {
                    Logger.Warning(
                        $"Character cannot interact with {vehicle} for repair - too far",
                        character);

                    if (IsClient)
                    {
                        CannotInteractMessageDisplay.ClientOnCannotInteract(vehicle,
                                                                            CoreStrings.Notification_TooFar,
                                                                            isOutOfRange: true);
                    }
                }

                return(false);
            }

            var physicsSpace    = character.PhysicsBody.PhysicsSpace;
            var characterCenter = character.Position + character.PhysicsBody.CenterOffset;

            if (ObstacleTestHelper.SharedHasObstaclesInTheWay(characterCenter,
                                                              physicsSpace,
                                                              vehicle,
                                                              sendDebugEvents: writeToLog))
            {
                if (writeToLog)
                {
                    Logger.Warning(
                        $"Character cannot interact with {vehicle} for repair - obstacles in the way",
                        character);

                    if (IsClient)
                    {
                        CannotInteractMessageDisplay.ClientOnCannotInteract(vehicle,
                                                                            CoreStrings.Notification_ObstaclesOnTheWay,
                                                                            isOutOfRange: true);
                    }
                }

                return(false);
            }

            using var tempCharactersNearby = Api.Shared.GetTempList <ICharacter>();
            if (IsClient)
            {
                Client.Characters.GetKnownPlayerCharacters(tempCharactersNearby);
            }
            else
            {
                Server.World.GetScopedByPlayers(vehicle, tempCharactersNearby);
            }

            foreach (var otherPlayerCharacter in tempCharactersNearby.AsList())
            {
                if (ReferenceEquals(character, otherPlayerCharacter))
                {
                    continue;
                }

                if (PlayerCharacter.GetPublicState(otherPlayerCharacter).CurrentPublicActionState
                    is VehicleRepairActionState.PublicState repairActionState &&
                    ReferenceEquals(repairActionState.TargetWorldObject, vehicle))
                {
                    // already repairing by another player
                    if (!writeToLog)
                    {
                        return(false);
                    }

                    Logger.Important($"Cannot start repairing {vehicle} - already repairing by another player",
                                     character);
                    if (IsClient)
                    {
                        NotificationSystem.ClientShowNotification(
                            CoreStrings.Notification_ErrorCannotInteract,
                            CoreStrings.Notification_ErrorObjectUsedByAnotherPlayer,
                            NotificationColor.Bad,
                            icon: ((IProtoVehicle)vehicle.ProtoGameObject).Icon);
                    }

                    return(false);
                }
            }

            return(true);
        }
 public static void ClientOnCannotInteractNotOwner(IWorldObject worldObject)
 {
     CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject,
                                                         DialogCannotSetOwners_MessageNotOwner,
                                                         isOutOfRange: false);
 }
示例#22
0
 private void ClientRemote_OnCannotInteractNoAccess(IStaticWorldObject worldObject)
 {
     CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject,
                                                         NotificationDontHaveAccess,
                                                         isOutOfRange: false);
 }