ue-world-level-streaming
Use this skill when working with World Partition, level streaming, level travel, OpenLevel, ServerTravel, data layer, world subsystem, level instance, sub-level, seamless travel, open world, or HLOD. See references/streaming-patterns.md for configuration patterns by game type.
By quodsoler · 810 installs
npx skills add quodsoler/unreal-engine-skills --skill ue-world-level-streaming
Source repository · Upstream listing
UE World & Level Streaming
Target engine: UE 5.8 . APIs below are verified against the 5.8 headers; older forms are listed under "Deprecated — do not use".
This skill covers how a UWorld is composed and swapped at runtime: World Partition grids, data layers, HLOD, level instances, classic sub level streaming, streaming volumes, and map travel. Everything here lives in the Engine module ( Engine/Source/Runtime/Engine ), so Core , CoreUObject and Engine in PublicDependencyModuleNames is all that is needed. The one exception is the Level Streaming Persistence plugin, which adds the LevelStreamingPersistence module.
For end to end configurations per game type (open world, hub and spoke, procedural, chapter based, volume driven, dedicated server), see [streaming patterns](references/streaming patterns.md).
Context
Read .agents/ue project context.md if it exists (module names, conventions, enabled plugins, GAS/networking setup). Do not stop if it is missing.
Identify the area from the request and the codebase. Ask only when two plausible readings would produce different code.
Request is about… Go to
Picking between World Partition and sub levels [Choosing a Streaming Model]( choosing a streaming model)
Grid streaming, streaming sources, blocking loads, CVars [World Partition Runtime]( world partition runtime)
Turning content on and off inside a partitioned world [Data Layers]( data layers)
Reusable level chunks placed in the editor, packed actors [Level Instances]( level instances)
LoadStreamLevel , ULevelStreaming , volumes, runtime instancing [Sub Level Streaming]( sub level streaming)
OpenLevel , ServerTravel , ClientTravel , seamless travel [Level Travel]( level travel)
Distant proxies for streamed out cells [HLOD]( hlod)
Keeping actor changes across a streaming cycle [Level Streaming Persistence]( level streaming persistence)
Per world managers, state that must survive travel [World Subsystems and Cross Level State]( world subsystems and cross level state)
Choosing a Streaming Model
Situation Use Why
One large continuous map World Partition grid Automatic spatial cells, no manual sub level bookkeeping
Optional content inside a partitioned map Data layers EDataLayerRuntimeState toggles without travel
The same level asset placed many times in the editor ALevelInstance / APackedLevelActor Edited as a unit, packed into instanced meshes
The same level package spawned many times at runtime ULevelStreamingDynamic::LoadLevelInstance Creates a uniquely named package per instance
Discrete hand authored zones in a non partitioned map ULevelStreaming sub levels Explicit load and visibility control per zone
Proximity driven interiors in a non partitioned map ALevelStreamingVolume Camera position driven, no gameplay code
A different map entirely OpenLevel / ServerTravel Tears down and rebuilds the world
World Partition and sub level streaming are mutually exclusive on the same persistent level. UWorld::IsPartitionedWorld() ( Engine/World.h:2968 ) reports which one is in play; AWorldSettings::GetWorldPartition() ( GameFramework/WorldSettings.h:837 ) returns the partition object (the WorldPartition member is protected).
World Partition Runtime
UWorldPartition ( WorldPartition/WorldPartition.h ) owns the runtime hash that turns actors into cells. UWorldPartitionSubsystem is the per world entry point and is a UTickableWorldSubsystem .
UWorldPartitionRuntimeCell is the unit the hash produces. Query readiness at an arbitrary point with a query source instead of polling actors:
EWorldPartitionRuntimeCellState is Unloaded , Loaded , Activated ( WorldPartitionRuntimeCell.h:202 ).
Streaming sources
Any object can drive streaming by implementing IWorldPartitionStreamingSourceProvider (a plain interface struct in WorldPartitionStreamingSource.h ) and registering it with the subsystem. For the common "this actor pulls cells in" case, add a UWorldPartitionStreamingSourceComponent instead — it already implements the provider and registers itself.
The two virtuals to override are virtual bool GetStreamingSources(TArray<FWorldPartitionStreamingSource & StreamingSources) const and virtual const UObject GetStreamingSourceOwner() const . Register in BeginPlay with UWorldPartitionSubsystem::RegisterStreamingSourceProvider(this) and release in EndPlay with UnregisterStreamingSourceProvider(this) . A complete actor implementation is in [streaming patterns](references/streaming patterns.md custom streaming source provider).
EStreamingSourceTargetState : Loaded (in memory, not added to the world) or Activated .
EStreamingSourcePriority : Highest , High , Normal , Low , Lowest , Default (equals Normal ).
TargetGrids plus EStreamingSourceTargetBehavior ( Include / Exclude ) restrict a source to named runtime grids.
bBlockOnSlowLoading opts the source into the engine's blocking path when streaming falls behind. Leave it false for cosmetic sources.
UWorldPartitionSubsystem::GetStreamingSources(const UWorldPartition , TArray<FWorldPartitionStreamingSource &) reads back everything currently registered.
Runtime CVars
CVar Effect
wp.Runtime.EnableServerStreaming Server side cell streaming on dedicated and listen servers
wp.Runtime.EnableServerStreamingOut Lets the server stream cells back out
wp.Runtime.BlockOnSlowStreaming Blocks the game thread when a blocking source falls behind
wp.Runtime.MaxLoadingStreamingCells Caps concurrent cell loads
wp.Runtime.OverrideRuntimeLoadingRange Overrides a grid's loading range for testing
wp.Runtime.ToggleDrawRuntimeHash2D Draws the cell grid on screen
wp.Runtime.DumpStreamingSources Logs every registered streaming source
wp.Runtime.HLOD Enables and disables HLOD proxies at runtime
Data Layers
Actors reference data layers through AActor::DataLayerAssets ( TArray<TSoftObjectPtr<UDataLayerAsset , GameFramework/Actor.h:1123 ). UDataLayerAsset is the authored asset, UDataLayerInstance is its per world instance, and UDataLayerManager is the runtime accessor, reachable from any object inside a partitioned world.
EDataLayerRuntimeState ( DataLayerInstance.h:23 ): Unloaded , Loaded (in memory but not visible — use it to pre warm), Activated (loaded and visible).
Other manager entry points: SetDataLayerInstanceRuntimeState(const UDataLayerInstance , EDataLayerRuntimeState, bool bInIsRecursive) , GetDataLayerInstanceEffectiveRuntimeState , GetDataLayerInstances() , GetDataLayerInstanceFromName(const FName&) , and the BlueprintAssignable delegate OnDataLayerInstanceRuntimeStateChanged . To sweep every instance:
Authority: a runtime data layer with no load filter only responds to state changes made on the server, and the resulting state replicates. Client only layers must be changed on the client, server only layers on the server. The old world subsystem accessor still exists as a deprecated shim — see [Deprecated — do not use]( deprecated do not use); route everything through UDataLayerManager .
Level Instances
ALevelInstance ( LevelInstance/LevelInstanceActor.h ) places a .umap as a reusable chunk and implements ILevelInstanceInterface . ULevelInstanceSubsystem is the UWorldSubsystem that tracks them.
ILevelInstanceInterface runtime members: LoadLevelInstance() , UnloadLevelInstance() , IsLoaded() , GetLoadedLevel() , GetLevelStreaming() , GetWorldAsset() , GetLevelInstanceID() , IsInitiallyVisible() .
ULevelInstanceSubsystem runtime members: GetLevelInstance(const FLevelInstanceID&) , GetOwningLevelInstance(const ULevel ) , RequestLoadLevelInstance(ILevelInstanceInterface , bool bUpdate) , RequestUnloadLevelInstance(ILevelInstanceInterface ) , IsLoaded , IsLoading , ForEachActorInLevelInstance , GetLevelInstanceLevel . The editing entry points are WITH EDITOR only.
ELevelInstanceRuntimeBehavior ( LevelInstanceTypes.h:56 ) picks how the instance reaches the runtime: Partitioned (actors move into the main partition grid; shown as "Embedded") or LevelStreaming (its own streaming level; shown as "Standalone").
APackedLevelActor ( PackedLevelActor/PackedLevelActor.h ) derives from ALevelInstance and bakes its static meshes into instanced mesh components. It reports ELevelInstanceRuntimeBehavior::None and loads no level at runtime.
Sub Level Streaming
ULevelStreaming state
ELevelStreamingState ( Engine/LevelStreaming.h:110 ) is Removed , Unloaded , FailedToLoad , Loading , LoadedNotVisible , MakingVisible , LoadedVisible , MakingInvisible . Read it with GetLevelStreamingState() . The requested side is ELevelStreamingTargetState ( Unloaded , UnloadedAndRemoved , LoadedNotVisible , LoadedVisible ).
Four BlueprintAssignable delegates, all with no parameters: OnLevelLoaded , OnLevelUnloaded , OnLevelShown , OnLevelHidden . Bind with AddDynamic to a no argument UFUNCTION() .
Use SetIsRequestingUnloadAndRemoval(true) to drop the streaming level object entirely. Never mutate UWorld::StreamingLevels directly — use AddStreamingLevel , AddStreamingLevels , RemoveStreamingLevel , RemoveStreamingLevels and UpdateStreamingLevelShouldBeConsidered ( Engine/World.h:1073 1109 ), which maintain StreamingLevelsToConsider .
Latent load and unload
UGameplayStatics::LoadStreamLevel(const UObject WorldContextObject, FName LevelName, bool bMakeVisibleAfterLoad, bool bShouldBlockOnLoad, FLatentActionInfo LatentInfo) and UnloadStreamLevel(const UObject WorldContextObject, FName LevelName, FLatentActionInfo LatentInfo, bool bShouldBlockOnUnload) resume through FLatentActionInfo::ExecutionFunction , which is resolved by name through the reflection system . The callback therefore has to be a UFUNCTION() declared inside a class body in a header.
LoadStreamLevelBySoftObjectPtr and UnloadStreamLevelBySoftObjectPtr take a TSoftObjectPtr<UWorld in place of the FName and are the packaging safe form. UGameplayStatics::FlushLevelStreaming(const UObject ) blocks until pending work completes; UWorld::FlushLevelStreaming(EFlushLevelStreamingType) gives finer control ( None , Full , Visibility ).
Runtime level instancing
ULevelStreamingDynamic loads one package repeatedly at different transforms. Prefer the params struct overload, because the by name overload cannot express a full FTransform .
Tear an instance down with SetShouldBeVisible(false) , SetShouldBeLoaded(false) , then SetIsRequestingUnloadAndRemoval(true) . A generator that tracks its instances and binds OnLevelShown is in [streaming patterns](references/streaming patterns.md pattern 3 procedural and instanced level streaming).
FLoadLevelInstanceParams members: World , LongPackageName , LevelTransform , OptionalLevelNameOverride ( const FString ), OptionalLevelStreamingClass , bLoadAsTempPackage , bInitiallyVisible , bAllowReuseExitingLevelStreaming , EditorPathOwner , LevelStreamingCreatedCallback .
The Blueprint exposed overloads are LoadLevelInstance(UObject WorldContextObject, FString LevelName, FVector Location, FRotator Rotation, bool& bOutSuccess, const FString& OptionalLevelNameOverride, TSubclassOf<ULevelStreamingDynamic OptionalLevelStreamingClass, bool bLoadAsTempPackage) and LoadLevelInstanceBySoftObjectPtr , which takes a TSoftObjectPtr<UWorld in place of LevelName and the same tail parameters; a C++ only BySoftObjectPtr overload takes an FTransform ( Engine/LevelStreamingDynamic.h:94 ).
Streaming volumes
ALevelStreamingVolume drives sub levels from camer