creative_prop MoveTo disposed error when called from other Verse

I’m building a simple elevator system, and I have two door props that I’m pulling into a Verse script as creative_props, then animating their position using MoveTo.

The weird thing is… this works when I call it from OnBegin on the door itself. But when I later call it from a button activation (through a looping function on another Verse), I get an error that the object has been disposed (even though I’m still looking at it in-game). I have no idea what to try next.

Perhaps there is some other way to access a function like this from another place? Directly calling them from event functions wasn’t possible, so I went this route instead.

The verse script are as follows:

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

elevator_door := class<concrete>(creative_device):

    @editable
    var DoorLeft<public> : creative_prop = creative_prop{}
    @editable
    var DoorRight<public> : creative_prop = creative_prop{}

    var leftClosedPosition : vector3 = vector3{}
    var rightClosedPosition : vector3 = vector3{}
    var TransformLeft : transform = transform{}
    var TransformRight : transform = transform{}

    @editable
    var distance<public> : float = 128.0

    @editable
    var floor<public> : int = 0

    var isOpen : logic = false

    # Runs when the device is started in a running game
    OnBegin<override>()<suspends>:void=
        Print("Elevator door start")
        set TransformLeft = DoorLeft.GetTransform()
        set TransformRight = DoorRight.GetTransform()
        set leftClosedPosition = DoorLeft.GetTransform().Translation
        set rightClosedPosition = DoorRight.GetTransform().Translation
        Print("{ DoorLeft.GetTransform().Translation}")
        Print("{ DoorRight.GetTransform().Translation}")

        block:
            Open()
            Sleep(1.0)
            Close()
    
    Open<public>()<suspends>:void=
        Print("Door opening")
        TargetLeft : vector3 = vector3 {X:= leftClosedPosition.X, Y:= leftClosedPosition.Y - 128.0, Z:= leftClosedPosition.Z}
        TargetRight : vector3 = vector3 {X:= leftClosedPosition.X, Y:= rightClosedPosition.Y + 128.0, Z:= leftClosedPosition.Z}

        lRot := DoorLeft.GetTransform().Rotation
        rRot := DoorRight.GetTransform().Rotation

        block:
            Result := sync:
                DoorLeft.MoveTo(TargetLeft, lRot, 1.0)
                DoorRight.MoveTo(TargetRight, rRot, 1.0)
        
        set isOpen = true

    Close<public>()<suspends>:void=
        Print("Door closing")
        TargetLeft : vector3 = leftClosedPosition
        TargetRight : vector3 = rightClosedPosition

        Print("Moving")
        block:
            Result := sync:
                DoorLeft.MoveTo(TargetLeft, TransformLeft.Rotation, 1.0)
                DoorRight.MoveTo(TargetRight, TransformRight.Rotation, 1.0)
        
        set isOpen = false

And the elevator button (name needs a refactor)

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

elevator_button := class<concrete>(creative_device):

    @editable
    MyButton<public> : button_device = button_device{}

    @editable
    MyOuterButton<public> : button_device = button_device{}

    @editable
    var baseFloor<public> : int = 0

    var basePosition : vector3 = vector3{}
    var currentFloor : int = 0
    var targetFloor : int = 0
    var activated : logic = false
    var called : logic = false

    @editable
    MyCabin<public> : creative_prop = creative_prop{}

    @editable
    MyDoors<public> : []elevator_door = array{elevator_door{}}

    # Runs when the device is started in a running game
    OnBegin<override>()<suspends>:void=
        Print("Elevator start")
        MyButton.InteractedWithEvent.Subscribe(OnActivated)
        MyOuterButton.InteractedWithEvent.Subscribe(OnOuterActivated)
        set basePosition = MyCabin.GetTransform().Translation

        MovementFunction()

    OnActivated(Agent : agent ) : void=
        Print("USED BUTTON")
        # Check state (not moving or called down)
        if ( activated = false):
            # move to next floor
            set targetFloor = currentFloor+1
            set activated = true

    OnOuterActivated(Agent : agent ) : void=
        Print("USED BOTTOM BUTTON")
        set called = true

    MovementFunction()<suspends> : void=
        loop:
            if (called = true):
                if ( currentFloor = baseFloor ):
                    block:
                        OpenDoors()
                else:
                    set targetFloor = baseFloor
                    block: 
                        CloseDoors()
                        MoveTo()
                        OpenDoors()
                        set called = false
            else:
                if (activated = true):
                    block:
                        CloseDoors()
                        MoveTo()
                        OpenDoors()
                        set activated = false

            Sleep(0.1)
    
    MoveTo()<suspends> : void=
        Print("Moving to floor {targetFloor}")
        Transform := MyCabin.GetTransform()
        Target : vector3 = basePosition + vector3 {X:= 0.0, Y:= 0.0, Z:= 256.0 * 4 * (targetFloor - baseFloor)}

        Print("Moving")
        MyCabin.MoveTo(Target, Transform.Rotation, 5.0)

        Print("Done Moving")
        set currentFloor = targetFloor

    CloseDoors()<suspends> : void=
        Print("Closing Doors")
        # close doors at current floor
        if ( Door := MyDoors[currentFloor]):
            if ( Door.isOpen = true ):
                Door.Close()

    OpenDoors()<suspends> : void=
        Print("Opening Doors")
        #open doors at current floor 
        if ( Door := MyDoors[currentFloor]):
            if ( Door.isOpen = false ):
                Door.Open()

idk if this would be the correct solution but for me i think i was getting the same error as you described. so i just passed the creative props in the function.

updated the functions

MoveTo(MyCabinTemp: creative_prop, MyDoorsTemp: []elevator_door)<suspends> : void=

CloseDoors(MyCabinTemp: creative_prop, MyDoorsTemp: []elevator_door)<suspends> : void=

OpenDoors(MyCabinTemp: creative_prop, MyDoorsTemp: []elevator_door)<suspends> : void=

then created a tuple

    MovementFunction()<suspends> : void=
        CabinDoors := {MyCabin, MyDoors}

full code after updates

MovementFunction()<suspends> : void=
    #tuple
    CabinDoors := {MyCabin, MyDoors}
    loop:
        if (called = true):
            if ( currentFloor = baseFloor ):
                block:
                    OpenDoors(CabinDoors)
            else:
                set targetFloor = baseFloor
                block: 
                    CloseDoors(CabinDoors)
                    MoveTo(CabinDoors)
                    OpenDoors(CabinDoors)
                    set called = false
        else:
            if (activated = true):
                block:
                    CloseDoors(CabinDoors)
                    MoveTo(CabinDoors)
                    OpenDoors(CabinDoors)
                    set activated = false

        Sleep(0.1)

MoveTo(MyCabinTemp: creative_prop, MyDoorsTemp: []elevator_door)<suspends> : void=
    Print("Moving to floor {targetFloor}")
    Transform := MyCabin.GetTransform()
    Target : vector3 = basePosition + vector3 {X:= 0.0, Y:= 0.0, Z:= 256.0 * 4 * (targetFloor - baseFloor)}

    Print("Moving")
    MyCabin.MoveTo(Target, Transform.Rotation, 5.0)

    Print("Done Moving")
    set currentFloor = targetFloor

CloseDoors(MyCabinTemp: creative_prop, MyDoorsTemp: []elevator_door)<suspends> : void=
    Print("Closing Doors")
    # close doors at current floor
    if ( Door := MyDoors[currentFloor]):
        if ( Door.isOpen = true ):
            Door.Close()

OpenDoors(MyCabinTemp: creative_prop, MyDoorsTemp: []elevator_door)<suspends> : void=
    Print("Opening Doors")
    #open doors at current floor 
    if ( Door := MyDoors[currentFloor]):
        if ( Door.isOpen = false ):
            Door.Open()

im not sure why or if the solution works for you but thats what i did

This didn’t change anything for me, but I think that’s because the actual failure happens inside of Door.Close()…

Specifically, the MoveTo line causes an error because the DoorLeft and DoorRight creative_props have been disposed. I’ve tried running a similar loop inside the Begin of the Door with some logic vars, but those don’t get caught at all if I set them from the other Verse.

Definitely something fishy going on here. Smells like concurrency woes to me.

EDIT: To add to the weirdness… I climbed into the elevator without the doors opening, and tried the inside button (which moves the elevator up floors), and that works… and the other doors (all 3 sets) also work fine. It’s only this first set of doors, that somehow doesn’t work. (I’ve tried removing them, copying it over from another, no change)

1 Like

The solution is ridiculous, but it seems the array is to blame here. If I put “MyDoors[currentFloor+1]”, and just move everything one down the array (leaving the 0th index as a duplicate of the first door), it works perfectly.

It’s even the same elevator_door instance, it’s just in another spot in the array.

I guess this is a bug?

I believe this is either a bug in Verse or something that isn’t documented.

Sometimes, for whatever reason, you can’t refer to a class field as-is - you need to pass it in via an instance. This usually happens when you use concurrency but it also happens without in the case of props.

You should be able to solve it by passing Self as a parameter to Close, and then calling Self.DoorLeft.MoveTo rather than just DoorLeft.MoveTo. This should work.

Alternatively you can pass DoorLeft itself as a Param but it’s easier to just throw Self around when you’ve got a lot going on.

Like I said I think this is either a bug in Verse, or maybe an issue with our ignorance on effect specifiers. I know, for example, that you should always use a Setter method when updating a var - and that Setter method needs <transacts> effect, otherwise the variable update may not be visible in other scopes (e.g. event subscriptions, concurrent tasks, etc.). But still even with this, I need to thow “Self” around to avoid IsDisposed error for vars for some reason… but I digress, that’s a thing with vars - not @editable constants. But kinda related to the theory that this is a “bug” in Verse. Or us not using it correctly :slight_smile:

EDIT: Fixed missing <transacts> effect above, would have been confusing. Also I remembered that at first I was making my @editable props var - do NOT do this, it may cause issues and there’s no point making an @editable var anyway.

Since you are using MoveTo() you also might want to check this post out: