UGTK cat mascotUGTKengine within an engine Request access

UGTK / Toolkit / Utility Systems / Level Streaming System Completed

Utility Systems — UGTK

Level Streaming System

Summary

The Level Streaming System loads and unloads scenes additively from one component: a serialized list of levels, async load/unload with events on every stage, and an optional object-optimization pass that disables renderers (or whole GameObjects) that are too far from the camera or off screen.

It is the piece you need for an open level split into chunks, or for a hub that streams in the room the player is entering.


Content


Modules Dependencies

None. One runtime component plus a debug helper; it only uses UnityEngine.SceneManagement.


Setup

There is no prefab: add Mn_LevelStreamingSystem to a GameObject that lives for the whole session.

  1. Fill the Levels list — each entry takes a scene name, or a SceneAsset you can drag in from the editor (the name is derived from it).
  2. Add every streamed scene to Build Settings. A scene that is not in the build list cannot be loaded at runtime, and the failure is a console error, not an exception.
  3. Bind LoadLevel / UnloadLevel to buttons, triggers or your own code.

How To Use

Behavior - Allow Parallel Operations (off by default): with it off, a load/unload request while another is running is ignored — which is what you want, because two async scene operations on the same scene race each other. Turn it on only if you stream several independent chunks at once. - Set Loaded Level As Active: makes the newly loaded scene the active one, so new objects, lightmaps and the skybox come from it. - Debug Log (on by default): logs every stage. Turn it off in a release build.

EventsOnLevelLoadStarted(string), and the matching finished/unload events: use them to show a loading overlay, to enable the chunk's gameplay once it is really there, and to know when it is safe to unload.

Good to know:


Object Optimization

Independent of streaming, the component can cull a list of objects to keep a heavy chunk cheap while it is loaded but not in front of the player:

RenderersOnly is the safe default: deactivating a whole GameObject also stops its coroutines and makes it invisible to Find, which breaks anything holding a reference to it.


Testing Scene

Open Debug/LevelStreamingSystemScene.unity. It holds LevelStreamingSystem with Mn_LevelStreamingSystem and Mn_LevelStreamingSystemTest, and two levels are already registered: LevelStreaming_Forest and LevelStreaming_Cave, two tiny scenes in Debug/Levels/ each holding one shape, so you can tell at a glance which is loaded.

Press Play, then use the Editor Test Tools at the bottom of the inspector:

  1. Load on level 0 — LevelStreaming_Forest appears in the Hierarchy as a second open scene, and the row is marked loaded. The main scene never went away: this is an additive load.
  2. Load on level 1 too, and both are open at once.
  3. Unload removes each of them again.

The check above the buttons is the part worth having. Outside Play Mode the block reports, per level, whether that scene is in the Build Settings and enabled — and refuses with an error if it is not. An additive load of a scene missing from the build list fails at runtime with a message that says nothing useful about which entry is wrong, and on a device it fails in the build only. Seeing it in red in the inspector, before pressing anything, is the whole point.

The two demo levels are in the Build Settings for exactly this reason. Add your own the same way, or the inspector will tell you off.


Technical Info

Path Content
Scripts/Runtime/Mn_LevelStreamingSystem.cs The component: level list, async load/unload, events, and the object-optimization pass. Declares S_LevelEntry, S_OptimizationTarget and E_OptimizationAction
Debug/Mn_LevelStreamingSystemTest.cs Debug helper that triggers load/unload from the test scene
Debug/LevelStreamingSystemScene.unity Test scene

© 2026 Marcello De Bonis. All rights reserved