DeactivateObjectivePulse has no effect on Map Indicator Pulse since 38.00

Summary

On one of my larger Verse scripts, I noticed that the Map Indicator Devices would not stop pulsing when deactivated per player agent.

To debug this, I created a minimal test script to determine whether this issue was specific to my implementation (e.g., a race condition) or a global bug.

Unfortunately, it appears to be global. I was able to reproduce the issue in a clean test environment.

Expected behavior:
-When the switch is toggled ON, the pulse should start.
-When the switch is toggled OFF, the pulse should stop.

Actual behavior:
-After toggling the switch OFF, the pulse continues indefinitely and does not deactivate as expected.

Below is the Verse script I used to isolate and reproduce the issue:

using { /Verse.org/Simulation }
using { /Fortnite.com/Devices }
using { /Fortnite.com/Playspaces }
using { /Verse.org/Concurrency }

pulse_tester := class(creative_device):

    @editable
    TestSwitch: switch_device = switch_device{}

    @editable
    TestIndicator: map_indicator_device = map_indicator_device{}

    # This function runs when the device starts
    OnBegin<override>()<suspends>:void=
        
        # Subscribe to the switch events
        TestSwitch.TurnedOnEvent.Subscribe(HandleTurnedOn)
        TestSwitch.TurnedOffEvent.Subscribe(HandleTurnedOff)

        # Make sure the map indicator is enabled when the game starts
        TestIndicator.Enable()
        
        # Check if the switch is set to "Per Player"
        if (TestSwitch.IsStatePerAgent[] = false):
            Print("WARNING: For this test, TestSwitch should have 'Store State Per Player' set to 'Yes'.")

        # Clean up any existing pulses for all players at the start
        AllPlayers := GetPlayspace().GetPlayers()
        for (Player : AllPlayers):
            TestIndicator.DeactivateObjectivePulse(Player)

    # This function runs when an agent turns the switch ON
    HandleTurnedOn(Agent: agent):void=
        Print("Pulse Tester: Switch Turned ON for player. Calling ActivateObjectivePulse...")
        TestIndicator.ActivateObjectivePulse(Agent)
        Print("Pulse Tester: ActivateObjectivePulse(Agent) has been called.")

    # This function runs when an agent turns the switch OFF
    HandleTurnedOff(Agent: agent):void=
        Print("Pulse Tester: Switch Turned OFF for player. Calling DeactivateObjectivePulse...")
        TestIndicator.DeactivateObjectivePulse(Agent)
        Print("Pulse Tester: DeactivateObjectivePulse(Agent) has been called.")

Please select what you are reporting on:

Unreal Editor for Fortnite

What Type of Bug are you experiencing?

Verse

Steps to Reproduce

use DeactivateObjectivePulse(Agent) on Map Indicator Device in verse

Expected Result

When the switch is toggled ON, the pulse should start.
When the switch is toggled OFF, the pulse should stop.

Observed Result

After toggling the switch OFF, the pulse continues indefinitely and does not deactivate as expected.

Platform(s)

PC, Mobile (iphone 13)

Ran into this problem as well. Disabling the device also doesn’t remove the pulse effect, it seems to be stuck permanently once assigned. This is a critical bug as it is extremely helpful in onboarding new players/tutorials.

1 Like

Also encountering this issue; critical for us one one island as we use ObjectivePulse for a custom quest system (so there are 5+ pulses active at all times now).

2 Likes

Encounter the same issue, really hope this can be fixed, is very important to our game

Also another bug, when you activate it the trail shows for all players https://youtu.be/qQZnyg35ZHo

Having the same issue, the pulse stays active even when a player completed a tracker in my map. Really hope this can be fixed as soon as possible

(post deleted by author)

I can confirm this issue too in my maps where I am using Objective Pulse from a Map Indicator device. I am deactivating it by Direct Event Binding with a function “Deactivate Objective Pulse” by different actions, so it is not only related to Verse. It is happening in a map that was updated just a few hours ago and also in a map that was last updated a few weeks ago.

Here’s a custom workaround that lets you take any creative prop and have it rotate toward a Map Indicator Device. This setup is designed to work alongside my custom Quest Manager, but you can easily adjust it to fit your own project.


    # Quest Arrow Manager 1.00.00
    # A replacement for the Map Indicator Pulse. Works in tandem with my Quest Manager, but with minor adjustments it can be adapted for your own needs.
    # If this code is helpful to you, please favorite me as a creator: https://www.fortnite.com/@graphicsurfer?lang=en-US
    # It costs nothing and means a lot. Thank you -GraphicSurfer.

    using { /Fortnite.com/Devices }
    using { /Fortnite.com/Characters }
    using { /Fortnite.com/Playspaces }
    using { /Verse.org/Simulation }
    using { /UnrealEngine.com/Temporary/SpatialMath }
    using { /Verse.org/Verse } 

    quest_arrow_manager_device := class(creative_device):

        # --- Arrow Prop Arrays ---
        @editable
        MainQuestArrows: []creative_prop = array{}
        @editable
        SideQuestArrows: []creative_prop = array{}
        @editable
        OptionalQuestArrows: []creative_prop = array{}

        # --- Shared Settings ---
        @editable
        ArrowOffset: vector3 = vector3{X := 0.0, Y := 0.0, Z := 150.0}
        @editable
        UpdateRate: float = 0.064
        @editable
        Smoothness: float = 20.0

        # --- State Variables ---
        var MainPropScales: []vector3 = array{}
        var SidePropScales: []vector3 = array{}
        var OptionalPropScales: []vector3 = array{}

        var MainQuestTargetMap: [player]?map_indicator_device = map{}
        var SideQuestTargetMap: [player]?map_indicator_device = map{}
        var OptionalQuestTargetMap: [player]?map_indicator_device = map{}

        var PlayerArrowIndexMap: [player]?int = map{}
        var AvailableArrowIndices: []int = array{}

        HiddenLocation: vector3 = vector3{X := 0.0, Y := 0.0, Z := -1000.0}

        OnBegin<override>()<suspends>:void=
            for (Arrow : MainQuestArrows):
                set MainPropScales = MainPropScales + array{Arrow.GetTransform().Scale}
            for (Arrow : SideQuestArrows):
                set SidePropScales = SidePropScales + array{Arrow.GetTransform().Scale}
            for (Arrow : OptionalQuestArrows):
                set OptionalPropScales = OptionalPropScales + array{Arrow.GetTransform().Scale}

            for (Index -> Arrow : MainQuestArrows):
                set AvailableArrowIndices += array{Index}

            Playspace := GetPlayspace()

            for (Player : Playspace.GetPlayers()):
                spawn{ OnPlayerAdded(Player) }
            
            Playspace.PlayerAddedEvent().Subscribe(OnPlayerAddedWrapper)
            Playspace.PlayerRemovedEvent().Subscribe(OnPlayerRemoved)

            loop:
                InterpFactor := Clamp(Smoothness * UpdateRate, 0.0, 1.0)
                AllPlayers := Playspace.GetPlayers()

                for (Player : AllPlayers):
                    if (StablePlayerIndex := PlayerArrowIndexMap[Player]?):
                        if (PlayerCharacter := Player.GetFortCharacter[]):
                            PlayerLocation := PlayerCharacter.GetTransform().Translation

                            # --- Main Quest ---
                            if (MainArrow := MainQuestArrows[StablePlayerIndex]):
                                if (MainScale := MainPropScales[StablePlayerIndex]):
                                    if (CurrentTarget := MainQuestTargetMap[Player]?):
                                        UpdateArrowMovement(MainArrow, CurrentTarget, PlayerLocation, MainScale, InterpFactor)
                                    else:
                                        HideArrow(MainArrow, MainScale)
                            
                            # --- Side Quest ---
                            if (SideArrow := SideQuestArrows[StablePlayerIndex]):
                                if (SideScale := SidePropScales[StablePlayerIndex]):
                                    if (CurrentTarget := SideQuestTargetMap[Player]?):
                                        UpdateArrowMovement(SideArrow, CurrentTarget, PlayerLocation, SideScale, InterpFactor)
                                    else:
                                        HideArrow(SideArrow, SideScale)
                            
                            # --- Optional Quest ---
                            if (OptionalArrow := OptionalQuestArrows[StablePlayerIndex]):
                                if (OptionalScale := OptionalPropScales[StablePlayerIndex]):
                                    if (CurrentTarget := OptionalQuestTargetMap[Player]?):
                                        UpdateArrowMovement(OptionalArrow, CurrentTarget, PlayerLocation, OptionalScale, InterpFactor)
                                    else:
                                        HideArrow(OptionalArrow, OptionalScale)
                
                Sleep(UpdateRate)

        OnPlayerAddedWrapper(Player: player):void=
            spawn{ OnPlayerAdded(Player) }

        OnPlayerAdded(Player: player)<suspends>:void=
            if (PlayerArrowIndexMap[Player]?):
                return

            if (AvailableArrowIndices.Length = 0):
                Print("QuestArrowManager: CRITICAL - No available arrow indices for new player!")
                return

            var CurrentIndex: int = 0
            if (IndexValue := AvailableArrowIndices[0]):
                set CurrentIndex = IndexValue
                var NewAvailableIndices: []int = array{}
                for (I := 1..AvailableArrowIndices.Length - 1):
                    if (Index := AvailableArrowIndices[I]):
                        set NewAvailableIndices += array{Index}
                set AvailableArrowIndices = NewAvailableIndices
            else:
                Print("QuestArrowManager: Failed to get CurrentIndex from AvailableArrowIndices")
                return

            if (set PlayerArrowIndexMap[Player] = option{CurrentIndex}):

                if (set MainQuestTargetMap[Player] = false):

                else:
                    Print("QuestArrowManager: Failed to clear MainQuestTargetMap in OnPlayerAdded")

                if (set SideQuestTargetMap[Player] = false):

                else:
                    Print("QuestArrowManager: Failed to clear SideQuestTargetMap in OnPlayerAdded")
                    
                if (set OptionalQuestTargetMap[Player] = false):

                else:
                    Print("QuestArrowManager: Failed to clear OptionalQuestTargetMap in OnPlayerAdded")

                Print("QuestArrowManager: Assigned arrow index {CurrentIndex} to new player.")
            else:
                Print("QuestArrowManager: CRITICAL - Failed to set PlayerArrowIndexMap.")

        OnPlayerRemoved(Player: player):void=
            if (Index := PlayerArrowIndexMap[Player]?):
                Print("QuestArrowManager: Player left. Cleaning up index {Index}.")
                

                if (set MainQuestTargetMap[Player] = false):

                else:
                    Print("QuestArrowManager: Failed to clear MainQuestTargetMap in OnPlayerRemoved")
                    
                if (set SideQuestTargetMap[Player] = false):

                else:
                    Print("QuestArrowManager: Failed to clear SideQuestTargetMap in OnPlayerRemoved")
                    
                if (set OptionalQuestTargetMap[Player] = false):

                else:
                    Print("QuestArrowManager: Failed to clear OptionalQuestTargetMap in OnPlayerRemoved")

                
                if (set PlayerArrowIndexMap[Player] = false):
                    Print("QuestArrowManager: Player removed from index map.")
                    set AvailableArrowIndices += array{Index}
                else:
                    Print("QuestArrowManager: FAILED to remove player from index map.")

        UpdateArrowMovement(ArrowProp: creative_prop, TargetDevice: map_indicator_device, PlayerLocation: vector3, PropScale: vector3, InterpFactor: float)<suspends>:void=
            TargetLocation := TargetDevice.GetTransform().Translation
            TargetArrowLocation := PlayerLocation + ArrowOffset

            Direction := vector3{
                X := TargetLocation.X - PlayerLocation.X,
                Y := TargetLocation.Y - PlayerLocation.Y,
                Z := 0.0
            }

            if (NormalizedDirection := Direction.MakeUnitVector[]):
                XForward := vector3{X := 1.0, Y := 0.0, Z := 0.0}
                TargetArrowRotation := MakeShortestRotationBetween(XForward, NormalizedDirection)

                CurrentTransform := ArrowProp.GetTransform()
                CurrentLocation := CurrentTransform.Translation
                CurrentRotation := CurrentTransform.Rotation
                
                NewLocation := Lerp(CurrentLocation, TargetArrowLocation, InterpFactor)
                
                if (NewRotation := Slerp[CurrentRotation, TargetArrowRotation, InterpFactor]):
                    NewTransform := transform{
                        Translation := NewLocation,
                        Rotation := NewRotation,
                        Scale := PropScale
                    }

                    if (ArrowProp.TeleportTo[NewTransform]):

                    else:
                        Print("QuestArrowManager: TeleportTo failed.")

        HideArrow(ArrowToHide: creative_prop, PropScale: vector3)<transacts>:void=
            HiddenTransform := transform{
                Translation := HiddenLocation,
                Rotation := IdentityRotation(),
                Scale := PropScale
            }
            
            if (ArrowToHide.TeleportTo[HiddenTransform]):

            else:
                Print("QuestArrowManager: HideArrow TeleportTo failed.")

        ActivateMainQuestArrow<public>(Player: player, Target: map_indicator_device)<transacts>:void=
            if (set MainQuestTargetMap[Player] = option{Target}):

            else:
                Print("QuestArrowManager: Failed to set MainQuestTargetMap.")

        DeactivateMainQuestArrow<public>(Player: player)<transacts>:void=
            if (set MainQuestTargetMap[Player] = false):

            else:
                Print("QuestArrowManager: Failed to clear MainQuestTargetMap.")

        ActivateSideQuestArrow<public>(Player: player, Target: map_indicator_device)<transacts>:void=
            if (set SideQuestTargetMap[Player] = option{Target}):

            else:
                Print("QuestArrowManager: Failed to set SideQuestTargetMap.")

        DeactivateSideQuestArrow<public>(Player: player)<transacts>:void=
            if (set SideQuestTargetMap[Player] = false):

            else:
                Print("QuestArrowManager: Failed to clear SideQuestTargetMap.")

        ActivateOptionalQuestArrow<public>(Player: player, Target: map_indicator_device)<transacts>:void=
            if (set OptionalQuestTargetMap[Player] = option{Target}):

            else:
                Print("QuestArrowManager: Failed to set OptionalQuestTargetMap.")

        DeactivateOptionalQuestArrow<public>(Player: player)<transacts>:void=
            if (set OptionalQuestTargetMap[Player] = false):

            else:
                Print("QuestArrowManager: Failed to clear OptionalQuestTargetMap.")

Use this…

I have always used this ever since issues started happening 1yr+ ago

https://dev.epicgames.com/community/snippets/90ma/fortnite-compass-device

Credit to the creator.

Its easy to setup and has the images ect super useful :slight_smile:

All you do is pass the location in/player ect and bam works like a charm

2 Likes

For tracking: Fortnite Ecosystem 38.00 Known Issues Thread - #12 by Flak

FORT-1006729’s status has changed to ‘Ready for QA’. A member of the QA department is investigating the issue.