Scene graph entities do not rerender for player when player leaves render distance from v41.00

Summary

We are building a game that allows you to build out an arcade business. Within the building you can place furniture and arcade cabinets with scene graph entities that have meshes, keyframe and interactive components on them along with a custom verse component that allows them to be moved around.

The furniture and arcades have an interactive component on them, if the furniture is a chair then you can “sit” on it and if it’s an arcade then we send the player to the minigame via a teleporter.

It’s at this point when the player teleports away from their arcade and plays a game and then comes back and all of the furniture they placed is invisible and non interactive but collision remains.

If another player is in the game, those items stay visible and interactive, only for the second player, the first player that comes back can’t see nor interact. If the second player goes away and comes back, then they are gone for the second player too.

The weirdest part though is if player two goes away and player one places furniture while they are away, then when player two comes back the furniture is visible and interactive. If player two goes away and comes back again, then the furniture is gone.

Please select what you are reporting on:

Unreal Editor for Fortnite

What Type of Bug are you experiencing?

Scene Graph

Steps to Reproduce

I have not been able to reproduce this in a blank project, which leads me to believe this happens in our map due to the amount of stuff in it as the culled scene graph items get garbage collected maybe PER PLAYER, but only after culling is triggered and something takes it’s place.. not sure.

The simplest way to explain how our map works is that a player selects an item from their inventory, which then spawns in an entity into a parent entity. This entity holds the interactive, keyframe, mesh and custom verse component. The player places it down via input trigger device, which simply sets the global transform of the entity.

For going to a minigame, we teleport the player away with a teleporter device and they can go as far away as about 6 grid planes.

Again, I was not able to reproduce this in a blank map with those specs in place and exact knowledge of my own code.

Expected Result

Scene graph objects should come back as normal and have interaction available

Observed Result

Scene graph objects do not show, nor are they interactive anymore, only collision remains

Platform(s)

PC

I think it’s important to especially note that this did not happen before version 41.00, we had no issues with this before the update, this is a brand new problem for us without any code changes on our part.

Here is footage of the bug in action. https://drive.google.com/file/d/1Uh3Z0DehCCTE6f0zXZuU7Q0E_IzUT9aF/view?usp=sharing

Additionally here is a private code for the map. The map is unpublished atm. 6265-7586-8856
To reproduce simply load in, use the signal remote to open inventory, place items in your arcade, then play one of the arcade machines in your inventory after placing it down. Once you return, all the items in your arcade will be invisible, but still have collision. The game still thinks they are there, but they can no longer be interacted with or seen.

More to add. I’ve run a test deleting a ton of the memory in our map. I lowered the memory in the map to 50/100mb, but the issue is still happening. Additionally, we have world streaming turned off.

I have steps to replicate this now:

  1. Create a mesh inside the project to programmatically add to the main entity, this is what is going to disappear when you get too far away and then never come back
  2. Create a prefab to put your component code on so that this whole thing will run, here is the code
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Fortnite.com/Devices }
using { /Fortnite.com/Game }

BasicButtonSubClass:=class(basic_interactable_component):
    var Msg:message
    
    InteractableDuration<override> : ?interactable_duration = option{interactable_duration{InteractDuration:=5.0}}

    InteractMessage<override>(Agent:agent)<reads><decides>:message=
        Msg

StringToMessage<localizes>(value:string)<computes> : message = "{value}"

# A Verse-authored component that can be added to entities
GameManagerComponent<public> := class<final_super>(component):

    @editable
    var TestButton<public>:button_device = button_device{}

    var PurchaseableItems:PurchaseablesData = PurchaseablesData{}

    OnBeginSimulation<override>():void =
        
        (super:)OnBeginSimulation()
        
        if:
            FortRoundManager := Entity.GetFortRoundManager[]
        then:
            FortRoundManager.SubscribeRoundStarted(OnRoundStarted)

    OnRoundStarted():void=
        TestButton.InteractedWithEvent.Subscribe(OnButton)
        PurchaseableItems.CreateDataArray(Entity)

    OnButton(Agent:agent):void=
        #make an entity for the mesh to go in
        BasicEntity:=entity{}

        if(Item:=PurchaseableItems.Items[0]):
            if(TheMesh:=Item.Mesh[0]?):
                Button:basic_interactable_component = BasicButtonSubClass{Entity:=BasicEntity, Msg:=StringToMessage("Play")}
                Button.SucceededEvent.Subscribe(OnTheButton)
                BasicEntity.AddComponents(array{Button})
                BasicEntity.AddComponents(array{TheMesh})

        Entity.AddEntities(array{BasicEntity})
        

    OnTheButton(Agent:agent):void=
        block:

    OnSimulate<override>()<suspends>:void =
        block:
        


  1. Then add that component to your prefab and put the prefab in the scene
  2. place and hook up a button in the scene (this is literally just used to spawn the programmatic entity in
  3. Add two more bits of code (classes) that are mimicking our structure (I don’t think this is needed but might as well do it anyways)
PurchaseableItem := class():

    var ID:int = 0
    var Mesh:[int]?mesh_component = map{}

PurchaseablesData := class():

    var Items:[]PurchaseableItem = array{}

    CreateDataArray(MainPropEntity:entity):void=
        
        A1:=PurchaseableItem{}
        set A1.ID = 0
        set A1.Mesh = map{0=>option{Props.SomeBasicMesh{Entity:=MainPropEntity}}}

        set Items += array{A1}

Compile and run this and then run away from the spawned entity until it disappears. If you go back right away sometimes it comes back, if you want anything about 10 seconds then it never comes back. If you have collision on your mesh then that is still there, interactivity is also gone.

I should add that this only happens for the player that gets too far away, for everybody else the mesh and interactivity is still there until they go away.

I just tested and it doesn’t matter if our framework for getting meshes is used, you can simple do this and it’s the same result. Programmatically adding entities to a scene breaks reliably:

OnButton(Agent:agent):void=
        #make an entity for the mesh to go in
        BasicEntity:=entity{}

        SomeMesh:=Props.SomeBasicMesh{Entity:=Entity}
        Button:basic_interactable_component = BasicButtonSubClass{Entity:=BasicEntity, Msg:=StringToMessage("Play")}
        Button.SucceededEvent.Subscribe(OnTheButton)
        BasicEntity.AddComponents(array{Button})
        BasicEntity.AddComponents(array{SomeMesh})

        Entity.AddEntities(array{BasicEntity})

One more thing, if you make a prefab in the content browser and use that instead of the empty entity as in the code here, the same result happens. If you put the mesh in that prefab and DON’T put the mesh in with code then it works as expected and all is normal. It seems the problem is using empty prefabs or entities as containers for components to be added to. Should be “easy” to track down from all this I hope.

Two possible related issues you can check:
One i recently reported which is targeted to be fixed soon, related to where your root is: [CRITICAL] Scene Graph child meshes disappear when placed far from root entity

Two: Related to spawning but solved them by using a creative device to spawn entities and not doing addentity through sg entities/components.

world_creative_device_reference<public> := interface:
    AddEntitiesCustom<public>(ParentEnt:entity, Entities:[]entity):void
    AddEntitiesCustomSimEntity<public>(Entities:[]entity):void

MYDEVICE<public> := class(creative_device, world_creative_device_reference):
AddEntitiesCustom<override>(ParentEnt:entity, Entities:[]entity):void=
        ParentEnt.AddEntities(Entities)
If that doesn’t work try adding to sim entity:
 AddEntitiesCustomSimEntity<override>(Entities:[]entity):void=
        if(Entity:=GetSimulationEntity[]):
            Entity.AddEntities(Entities)

whoa… that’s a thing? I’ll try that in my test project for sure but I wouldn’t want to put that in our current project as this really should just get fixed. Wasn’t happening before the update.

@GraemeBB Are you setting up the Arcade machines as child entities for another root entity when players spawn them from their inventory to place in their Arcades?

In our case I have the parent entity the arcade manager which is an entity in the game. I add the mesh, button and custom verse device to an entity and add that entity to the manager.

That said, this bug can be replicated in 5 mins with the post above, it’s completely irrelevant of what entity is used it seems. Just creating an empty entity, adding mesh to it, add that to the root entity or any entity in the game and going away and coming back causes it to bug. This wasn’t the case before 41.00.

Thank you, I’ll pass that along.

1 Like

With more testing we have discovered that a prefab with a mesh in it will derender as well but takes just a bit longer for it to happen.

To summarize this game breaking scene graph functionality, if you spawn in a programmatically created entity and mesh or even just a prefab with mesh to a scene and get far away from it enough for it to derender, if you wait long enough (about 10 seconds for an empty entity plus mesh, maybe about 3 mins for a prefab with mesh) then this entity will derender the mesh but keep collision. If there was an interactive component in it, that will break and not respond either.

I can’t stress enough how frustrating this is to be using a technology that Epic has asked us to use in our games now and then break it with an update. There was no issue before 41.00 and now it’s fully game breaking with no workaround at all this time.

What about manually despawning them when the player gets far enough and respawning them when they get back close enough? Combined with Set Presentable, a per-player system can be set up.

Thanks for the response! You can’t despawn an entity for only one player as far as I’m aware of. We can’t have entities blinking in and out for other players.

I mean, you can spawn one for each player and directly set it to be presentable to that player. This should make the spawned instance per player. You can then despawn it and respawn it with no issues if I am not mistaken.

That’s an interesting idea… We have up to 150 items that I’d have to manage that way though, I think despawning/spawning them might be a suck on game resources/memory. It’s kind of well known if you do a lot of that for entities or BPs then it crashes the game sooner or later as GC is so buggy in fortnite maps.

1 Like

A little bit more info that maybe will help (as we REALLY need this fixed or we can release and I don’t know how anybody else would either…), here is some new code for the button:

OnButton(Agent:agent):void=
        #make an entity for the mesh to go in
        BasicEntity:=Prefabs.BasicPrefab_Ent{}
        AnotherBasicEntity:=Prefabs.BasicPrefab_Ent{}
        AndAnotherBasicEntity:=Prefabs.BasicPrefab_Ent{}
        AndOneMoreBasicEntity:=Prefabs.BasicPrefab_Ent{}

        #SomeMesh:=Props.SomeBasicMesh{Entity:=BasicEntity}
        Button:basic_interactable_component = BasicButtonSubClass{Entity:=BasicEntity, Msg:=StringToMessage("Play")}
        Button.SucceededEvent.Subscribe(OnTheButton)
        BasicEntity.AddComponents(array{Button})
        #BasicEntity.AddComponents(array{SomeMesh})
        var T:luf_transform = luf_transform{}
        set T.Translation = luf_vector3{Up:=0.0, Left:=200.0, Forward:=0.0}
        AnotherBasicEntity.SetLocalTransform(T)
        Entity.AddEntities(array{BasicEntity})
        Entity.AddEntities(array{AnotherBasicEntity})
        set T.Translation = luf_vector3{Up:=0.0, Left:=400.0, Forward:=0.0}
        AndAnotherBasicEntity.SetLocalTransform(T)
        Entity.AddEntities(array{AndAnotherBasicEntity})
        set T.Translation = luf_vector3{Up:=0.0, Left:=600.0, Forward:=0.0}
        AndOneMoreBasicEntity.SetLocalTransform(T)
        Entity.AddEntities(array{AndOneMoreBasicEntity})

If you put this in, build and launch and then go far enough away for things to derender (as noted way above, some mesh should be in that prefab), then stay away for longer than 10 seconds or so, the FIRST prefab in the array will derender. This is VERY reproducable. Oddly, if you go away and come back again, there is a 50/50 chance that it rerenders… Sometimes it does and sometimes it doesn’t, it definitely derenders again though too.

I sure hope this helps…