Hide/Show prop acting unprodictable and MoveTo mysteriously fails sometimes

I’m working on a map inspired by Raft and I want to have drifting debris which can be picked up or harvested by damaging them. I’m using an invisible prop with a button and prop manipulator device attached to it, as well as an array of props which gets hidden/shown depending on which loot table index is selected during runtime.
However I encounter a few problems:
After hiding the prop for the first time the next prop doesn’t turn visible. Show/Hide transacts but aren’t failable, so I can’t tell if they fail/get rolled back.
MoveTo often fails, even though I have tested by setting the area in which the prop moves to a small zone with no other props which it might collide with. I also removed collision from the props, but I don’t know if that even works because it seems like I can still trigger damage events by shooting them (or maybe it’s the invisible parent-prop that receives the calls, but that one is also set to have no collision).
The button device (set to not visible during game) is sometimes visible at some point after I have damaged/harvested the prop.

I have done some debugging and noted that if I disable MoveProp() and HideProp() then eventually it will show both/all items once their indexes gets rolled on the table. But hiding a prop seems to disable any of the props to the shown again.

Does anyone have any idea what could be going wrong here with the Hide/Show bug and/or the TeleportTo/MoveTo bug?


using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Random }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Fortnite.com/Characters }
using { raft_constants }

# This device handles drifting debris
debris_device := class(creative_device):
    # A reference to the player manager
    @editable
    PlayerMan : player_manager_device = player_manager_device{}

    # Interactables
    # In order for loot/debris to be collectable in several ways we need to have several devices
    @editable
    PropMan : prop_manipulator_device = prop_manipulator_device{} # This allows us to listen to "damaged" events as loot trigger

    @editable 
    Button : button_device = button_device{} # This allows a player to pick up an object by interacting with it
        
    @editable
    PropToMove : creative_prop = creative_prop{} # This is a dummy prop which only exists so that we can move the entire device rather than having moving each individual prop

    # A loot table should first be defined by all possible items that might drop
    # Since the code will break if we change this list during runtime we need to list them all
    # However we can give a weight of 0 to all objects that we don't wish to spawn and then handle that in the logic
    @editable
    Props : []creative_prop = array{}
    @editable
    Loot : []raft_constants.LootObject = array{} 

    # Movement points
    var StartPos : vector3 = vector3{X:=0.0, Y:=0.0, Z:= 0.0}
    var EndPos : vector3 = vector3{X:=0.0, Y:=0.0, Z:= 0.0}

    # Current loot index
    var LootIndex : int = -1

    # TRIGGERS

    # Lets the player loot the current debris directly
    # This triggers a respawn
    OnButtonPressed(Agent:agent):void=
        GiveLoot(Agent)
        spawn{Stop()}

    # Lets the player loot the current debris directly
    # This triggers a respawn
    OnDamaged(Agent:agent):void=
        Print("Damaged!")
        GiveLoot(Agent)
        spawn{Stop()}

    
    # LOGIC
    
    # Determines which direction the debris should travel
    SelectTravelVector() : void=
        Print("Setting travel vectors")
        # reset start and end pos
        set StartPos = vector3{X:=0.0, Y:=0.0, Z:= 0.0}
        set EndPos = vector3{X:=0.0, Y:=0.0, Z:= 0.0}
        
        # loop comparison between start and end, continue if shorter than 100
        loop:
            var Count : int = 0
            if (Res := Distance(StartPos, EndPos) > 100.0):
                break
            var _X : float = 0.0
            var _Y : float = 0.0
            var _Z : float = 0.0

            # Should start be south or east?
            if(GetRandomInt(0,100) > 50):   # Start from east
                set _X = raft_constants.SESpawn.X
                set _Y = GetRandomFloat(raft_constants.SESpawn.Y,NESpawn.Y)
                set _Z = raft_constants.SESpawn.Z
                set StartPos = vector3{X:=_X,Y:= _Y,Z:= _Z}
            else:                           # Start from south
                set _X = GetRandomFloat(raft_constants.SWSpawn.X,SESpawn.X)
                set _Y = raft_constants.SWSpawn.Y
                set _Z = raft_constants.SWSpawn.Z
                set StartPos = vector3{X:=_X,Y:= _Y,Z:= _Z}

            # Should end be west or north?
            if(GetRandomInt(0,100) > 50):   # End in West
                set _X = raft_constants.SWSpawn.X
                set _Y = GetRandomFloat(raft_constants.SWSpawn.Y,NWSpawn.Y)
                set _Z = raft_constants.SWSpawn.Z
                set EndPos = vector3{X:=_X,Y:= _Y,Z:= _Z}
            else:                           # End in North
                set _X = GetRandomFloat(raft_constants.NWSpawn.X,NESpawn.X)
                set _Y = raft_constants.NWSpawn.Y
                set _Z = raft_constants.NWSpawn.Z
                set EndPos = vector3{X:=_X,Y:= _Y,Z:= _Z}

            if (Count > 100):
                break
            set Count += 1
        return

    # Gives random loot to a player
    GiveLoot(Agent : agent) : void=
        if (Player := player[Agent]): # The recipient is a player
            if (LootItem := GetActiveLoot[]):
                PlayerMan.GivePlayerLoot(Player, LootItem.LootAmount, LootItem.LootType)

    # Failable function that tries to get a loot object
    GetActiveLoot<public>()<decides><transacts>:raft_constants.LootObject =
        return Loot[LootIndex]

    # Public function, a collider can also call this
    Stop<public>()<suspends>:void=
        Print("Stopping")
        HideActiveProp()
        Sleep(GetRandomFloat(5.0, 10.0))
        Print("Respawning")
        Respawn()

    # Respawns the debris
    Respawn():void =
        SelectTravelVector()
        SetRandomLoot()
        ShowActiveProp()
        spawn{MoveProp()}

    # Select random loot from the loot table and update the device variables
    SetRandomLoot():void =
        Print("Randomizing loot index")
        ValidLoot := for(Index -> Item : Loot, Item.LootAmount > 0):
            (Index, Item.LootWeight)
        var TotalWeight : int = 0
        var CurrentWeight : int = 0
        set LootIndex = -1
        for (Item : ValidLoot):
            set TotalWeight += Item(1)
        SelectedWeight := GetRandomInt(0, TotalWeight)
        for (Item : ValidLoot):
            set CurrentWeight += Item(1)
            if (LootIndex < 0):
                if (SelectedWeight <= CurrentWeight):
                    set LootIndex = Item(0)            
        return
    
    # Hide the active prop
    HideActiveProp():void=
        Print("Attempting to hide the prop")
        if (ActiveProp := Props[LootIndex]):
            ActiveProp.Hide()
        PropMan.HideProps()
    # Show active prop
    ShowActiveProp():void=
        Print("Attempting to show the prop")
        if (ActiveProp := Props[LootIndex]):
            ActiveProp.Show()
    
    # Estimate travel time        
    EstimateTime():float=
        Res := Distance(StartPos, EndPos)
        Base := Res / 256.0
        return Base * GetRandomFloat(0.75, 1.25) # Randomize the movement speed

    # Moves the parent prop
    MoveProp()<suspends>:void=
        Print("Start movement")
        Rot := PropToMove.GetTransform().Rotation
        if (res := PropToMove.TeleportTo[StartPos, Rot]):
            Time := EstimateTime()
            Res := PropToMove.MoveTo(EndPos, Rot, Time)
            if(Res = move_to_result.WillNotReachDestination):
                Print("MoveTo failed")
                HideActiveProp()
                Respawn()
            else:
                Print("Moveto not failed?")
            Print("Moveto started")
        else:
            Print("Catastrophic failure")

    # Runs when the device is started in a running game
    OnBegin<override>()<suspends>:void=
        Button.InteractedWithEvent.Subscribe(OnButtonPressed)
        PropMan.DamagedEvent.Subscribe(OnDamaged)
        for(Prop : Props):
            Prop.Hide()
        Respawn()