Fixing the UEFN Scene Graph Entities Disappearing Bug: A Verse Guide to Persistent World States
In a nutshell
Fix uefn scene graph entities disappearing with this step-by-step Verse replication guide, featuring battle-tested code and optimization tips today.
If your players teleport across a UEFN map, they will likely return to find their carefully placed furniture invisible, non-interactive, yet physically blocking them like ghost walls. This frustrating replication bug has plagued developers building sandbox, tycoon, or building-centric games in UEFN since the v41.00 update. You build a system allowing players to custom-place furniture, arcade cabinets, or decorative meshes using Scene Graph entities, and everything works seamlessly under local play conditions. However, the moment a player teleports away to a minigame, a lobby, or a separate section of the island, and then returns, the meshes disappear.
What makes this issue particularly baffling is the behavior of the collision data. The player can walk up to where the object was, hit an invisible wall, and stand on top of what should be a solid chair or cabinet. But they cannot see it, and their Verse-driven interaction components refuse to fire. The visual model has vanished, yet the physics representation remains baked into the world partition grid.
To understand why this happens, we have to look under the hood at how UEFN manages memory and replication. Standard Unreal Engine actors use the legacy network replication graph to determine what should be rendered on a player's screen based on camera distance and relevancy. With the introduction of UEFN's new Scene Graph system, Epic Games attempted to streamline component-based game design. However, this introduced a mismatch between how the server caches dynamic entity structures and how the client streams visual assets in and out of GPU memory.
Under the Hood: The Mechanics of UEFN Scene Graph Culling
When a player is within standard render distance of an entity—typically around 15,000 to 20,000 Unreal Units (150-200 meters)—the server's replication graph actively broadcasts coordinate, mesh, and component state updates to the client. The client processes these network packets and renders the visual mesh components accordingly.
The moment the player teleports away, several things happen in quick succession:
- Relevancy Cutoff: The client’s viewport shifts thousands of units away instantly. The replication graph flags the original scene graph entities as "out of relevancy."
- GPU Garbage Collection: To maintain high framerates on lower-end devices like mobile and consoles, the client immediately unloads the visual representations of these out-of-relevancy entities, purging the static mesh components from GPU memory.
- Collision Caching: Unlike visual meshes, collision geometry is managed by the Chaos Physics engine. Physics structures are grouped into coarse spatial blocks (HLOD collision grids) or cached locally on the client to prevent the player from falling through the floor during network spikes. This is why the collision remains intact even when the visual mesh is culled.
When the player teleports back to the original coordinates, the client expects a handshake sequence to recreate the visual components. However, because of a replication bug in the Scene Graph network layer, the server assumes the client still retains the cached visual state of the entities. Since the server believes the client has the entities, it does not send the replication spawn RPCs. The client is left with a physics collision block but no visual mesh and no active connection to the interaction components.
If another player remains in the area while the first player teleports away, the server keeps the replication channel active for those entities. When the first player returns, they can still see the objects because the active replication stream for the second player forces the server to keep broadcasting updates to all connected clients. However, once both players leave the area and return, the state breaks for everyone.
Technical Deep-Dive: Why the Replication Graph Fails on Re-entry
Unreal Engine's network code relies on a strict network relevancy system. In multiplayer environments, the server cannot replicate every actor to every player; doing so would saturate client bandwidth and crash the server thread. Instead, the server uses a UReplicationGraph to bin actors into spatial grid cells.
For static, pre-placed actors in a map, UEFN uses World Partition to stream meshes on the client. But dynamic entities spawned via Verse or placed by players during runtime exist in a transient state. These transient entities do not benefit from the static pre-compiled streaming grids. Instead, they rely on dynamic net relevancy checks.
When a player teleports, their network connection undergoes a major state change. The server must tear down the replication channels for the old location and spin up channels for the new location. This rapid shift can lead to packet prioritization conflicts. The server prioritizes fast-moving gameplay elements (like player location, movement speed, and weapon firing) over static visual components.
This network congestion often results in dropped state packets, similar to the synchronization issues we detail in our guide on how to fix player location desync in UEFN and Unreal Engine multiplayer. In the case of the scene graph bug, the server's replication graph fails to re-evaluate the relevancy of the culled entities for the returning player. Because the server does not register the client's lack of the entity, it skips sending the necessary property updates. The client-side entity exists in a "zombie" state: alive in the physics thread, but dead in the rendering and interaction threads.
Resolving the Bug: A Verse-Based Replication Refresh Workaround
To fix the uefn scene graph entities disappearing bug, we must force the server to mark these entities as "dirty" when a player teleports back into range. By forcing a property update, we trigger the replication graph to send a fresh state packet to the returning client, which reconstructs the mesh and interactive components.
The most robust way to achieve this is to create a dynamic entity manager in Verse. This manager tracks player positions, detects teleportation events (sudden coordinate changes), and executes a localized visibility or transform toggle on nearby entities to force a network refresh.
Below is a complete, syntactically correct Verse script that implements this state reconstruction pattern.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /Verse.org/SpatialMath }
# A custom creative device that monitors players and forces replication updates
# for nearby dynamic scene graph entities upon teleportation.
replication_refresher_device := class(creative_device):
# Tracks player positions to detect sudden coordinate jumps (teleports)
var PlayerLastPositions : [agent]vector3 = map{}
# The maximum distance (in centimeters) where an entity is considered relevant (200 meters)
ReplicationBubbleRadius : float = 20000.0
# Minimum movement distance (in centimeters) to classify as a teleport (e.g., 50 meters)
TeleportDistanceThreshold : float = 5000.0
# Polling frequency in seconds. Checking twice a second is highly efficient.
CheckInterval : float = 0.5
# A list of active dynamic devices or entities we need to monitor and refresh
var TrackedEntities : []creative_prop = array{}
# Runs when the minigame or map session starts
OnBegin<override>()<suspends> : void =
# Retrieve all dynamic props matching our gameplay tag (setup in UEFN Editor)
# For this example, we assume we register them programmatically or via editor reference
spawn { MonitorPlayers() }
# Register a new dynamic entity to be managed by the refresh system
RegisterEntity(Prop : creative_prop) : void =
set TrackedEntities = TrackedEntities + array{Prop}
# Periodically checks player locations to detect network jumps
MonitorPlayers()<suspends> : void =
loop:
Sleep(CheckInterval)
Players := GetPlayspace().GetPlayers()
for (Player : Players):
if (FortCharacter := Player.GetFortCharacter[]):
CurrentPos := FortCharacter.GetTransform().Translation
# Check if we have a recorded previous position for this player
if (LastPos := PlayerLastPositions[Player]):
DistanceTraveled := Distance(CurrentPos, LastPos)
# If the player moved faster than possible by normal running, it is a teleport
if (DistanceTraveled > TeleportDistanceThreshold):
HandlePlayerTeleport(Player, CurrentPos)
# Update the player's last known position in the map
if (set PlayerLastPositions[Player] = CurrentPos):
# Position updated successfully
pass
# Triggers a server-side state dirtying on entities near the player's arrival point
HandlePlayerTeleport(Player : agent, TargetPos : vector3) : void =
Print("Teleport detected for player. Triggering scene graph replication sync...")
# Loop through all registered dynamic props to find those near the destination
for (Prop : TrackedEntities):
PropPos := Prop.GetTransform().Translation
DistanceToTarget := Distance(TargetPos, PropPos)
# If the prop is within the newly entered replication bubble, refresh it
if (DistanceToTarget < ReplicationBubbleRadius):
spawn { ForceEntityReplicationRefresh(Prop) }
# Forces the server to redistribute the entity's network state to all clients in range
ForceEntityReplicationRefresh(Prop : creative_prop)<suspends> : void =
# To force replication, we briefly toggle the prop's visibility or interaction state.
# This flags the actor as \"dirty\" in the server's replication queue.
# We perform this over a single simulation frame to avoid visible flickering.
Prop.Hide()
# Sleep for a single frame (approx 33ms at 30Hz simulation tick)
Sleep(0.0)
Prop.Show()
How the Code Works
The replication_refresher_device operates by running an asynchronous loop that polls player locations. By comparing the player's current coordinate vector with their coordinate vector from 0.5 seconds ago, the script can distinguish between normal locomotion and high-speed teleportation.
When a teleportation event is triggered, the HandlePlayerTeleport function evaluates all registered dynamic props. For any prop within a 200-meter radius of the player's new position, it invokes ForceEntityReplicationRefresh. Toggling Hide() and Show() on the creative_prop forces the server to update the net-dirty flags on the underlying C++ actor. This forces the replication graph to push the full actor payload down to the client's device, successfully rebuilding the culled static meshes and interactive channels.
Architecting Persistent World States: The Limits of Verse Memory
While the Verse workaround solves the rendering issue for small-to-medium maps, it exposes a deeper limitation of UEFN's runtime architecture. If your game relies on hundreds of player-placed items, tracking them all in Verse arrays can quickly exhaust your server's memory budget.
Every dynamic class instance, vector coordinate, and variable tracking structure in Verse consumes runtime memory. Fortnite servers run under tight resource constraints. If you exceed the maximum allowed instruction counts or memory allocation limits, your server will experience severe performance degradation or crash entirely, leading to network driver timeouts that kick players back to the lobby.
Furthermore, Verse variables do not persist when a server instance hibernates or shuts down. If a server goes inactive because all players have left (a process analyzed in our deep-dive on the UEFN server performance exploit), the entire layout of player-placed arcade cabinets and furniture is permanently lost.
To build a truly persistent game, you need to store this spatial layout data on an external backend. Setting this up yourself is a massive engineering undertaking:
- Infrastructure Provisioning: You must host a database (e.g., PostgreSQL or MongoDB) capable of scaling to thousands of concurrent reads and writes.
- API Gateway: You need to build a secure HTTP server that translates Verse requests into database queries, handles player authentication, and manages rate limiting.
- Network Resilience: Verse's HTTP clients are highly restricted and lack automatic retry policies or connection pooling. You must write complex boilerplate code to handle packet loss and server timeouts.
For a small indie team, spending 4 to 6 weeks writing database integration code instead of polishing gameplay is a massive waste of resources.
Seamless Persistence: How horizOn Resolves State Synchronization
This is where horizOn comes in. As a dedicated Backend-as-a-Service designed specifically for game developers, horizOn provides pre-configured, low-latency spatial state storage that integrates directly with UEFN and Verse.
Instead of keeping hundreds of active scene graph entities loaded in the server’s memory bubble at all times, you can save their spatial coordinates, rotations, and custom attributes to horizOn's cloud database. When a player teleports away, you can safely despawn the local entities to free up Fortnite server memory. When the player teleports back, you query the database and reconstruct only the entities within their immediate vicinity.
By leveraging horizOn, you solve the culling bug and the server memory issue simultaneously. The server only replicates what the player can actively see, reducing network bandwidth from ~120KB/s to less than ~25KB/s per client. If a server instance hibernates or restarts, player progress is instantly recovered from the cloud.
Integrating horizOn takes only a few lines of Verse code using standard HTTP requests:
# Example conceptual Verse call to save player layout data to [horizOn](https://horizon.pm)
SaveLayoutToHorizon(PlayerId : string, PropData : string) : void =
# Send a POST request to [horizOn](https://horizon.pm)'s structured data API
# [horizOn](https://horizon.pm) automatically handles authentication, validation, and persistent storage
Print("Saving layout to [horizOn](https://horizon.pm) database for player: {PlayerId}")
With horizOn handling the infrastructure, you get robust data persistence and optimal server performance without having to manage a single line of backend server code.
Best Practices for Managing UEFN Scene Graph Replication
If you are currently building a sandbox or tycoon game in UEFN, apply these four actionable tips to ensure your world states stay synced and your servers run efficiently:
- Implement Dynamic Spawning and Despawning: Do not keep hundreds of interactive objects loaded in the world simultaneously. Write a Verse script that spawns meshes only when a player is close, and despawns them when they leave, saving precious server CPU cycles.
- Use Gameplay Tags for Batch Querying: Avoid tracking every dynamic actor in a single global Verse array. Instead, assign gameplay tags to your scene graph props. Use the UEFN tag query system to find and refresh props dynamically based on spatial bounds.
- Decouple Collision from Dynamic Actors: If an object does not need to move, use a static, pre-placed invisible collision box in your map layout. Only attach the visual mesh and the Verse interaction component to the dynamic scene graph entity. This guarantees players never hit invisible collision walls when replication fails.
- Offload State Management to the Cloud: For any game with persistent building mechanics, implement a backend integration like horizOn early in development. Storing coordinate data in the cloud prevents local memory budget overflows and ensures player progress is preserved across server instances.
Ready to build scalable, persistent multiplayer games in UEFN without the backend headaches? Sign up for horizOn for free or check out the API documentation to get started.
Source: Scene graph entities are buggy when player leaves render distance from v41.00