Streaming Deferred Prefabs & Scene GameObjects
Saveable Component (Remember Component) Load Scheduling and Change Detection
Streaming data allows a scene to load within seconds where it would normally take several minutes. The video below demonstrates the faster loading of a scene with over 2,800 GameObjects, each with a RememberGameObject and RememberTransform component attached. These track positions, rotations, active states, destroyed states, and more. With this streaming optimization, the scene now loads in about 10 seconds, compared to the previous 3–4 minutes.
Since Version 1.6.21 Crystal Save SaveableComponents expose three complementary optimisation tools:

Skip Saving When Unchanged lets components avoid re-serialising data when a change detector concludes the payload matches the last stored snapshot (for example,
RememberTransformandRememberCustomComponentstrack a cached baseline and bail out when they haven’t drifted beyond their tolerances).

Load Priority is a 0–100 slider in the inspector that orders components during the initial restoration pass (higher values are processed first).
Defer Until Requested stages component payloads in a deferred queue that you can flush later by scene, GameObject, component ID or explicit unique IDs.
Whenever a component serialises bytes, the save pipeline records its load priority, deferral flag and (when applicable) remembered home scene inside ComponentDataMetadata, so downstream loads and streaming helpers can respect those decisions.
Recommended global settings
These features deliver the biggest gains when the SaveSystem relies on fast lookups instead of whole-scene scans. Enable the lookup caches and disable the legacy startup scan in Save Settings so component and GameObject IDs resolve through the in-memory dictionaries that Load Priority and deferral expect.

Enable Lookup Cache.
Enable Component Lookup Cache.
Disable Scan For Existing Game Objects (let components register themselves on activation).
Configuring SaveableComponents
Skip Saving When Unchanged
Select a SaveableComponent (Remember X Component) that supports change detection (all built-in “Remember …” helpers that expose a Save Optimization group, such as transforms, custom components, lights, etc.).
Tick Skip Saving When Unchanged. The component will capture a baseline snapshot in
Awake, compare the nextSerializeComponentData()payload against that cache, and only persist changes when something actually moved or mutated.
Watch precision-sensitive data. Modules such as
RememberTransformuse tight but non-zero tolerances (0.0001f) when deciding whether values changed. If you rely on sub-millimetre or high-frequency jitter, leave the optimisation disabled for that component.
Load Priority
In the component inspector expand Load Scheduling and drag the Load Priority slider. Values closer to 100 ensure the component deserialises in the first batch during
ComponentManager.ApplyComponentData, while lower numbers sink toward the back of the queue.
You can also assign the property at runtime via
myComponent.LoadPriority = 80;thanks to the public accessor onSaveableComponent.
Use high priorities for gameplay-critical systems (player stats, quest state) and reserve the low end for cosmetic helpers or streaming content.
Defer Until Requested
Toggle Defer Until Requested in the inspector or set
myComponent.DeferLowPriorityUntilRequested = true;from code.
During a load, ComponentManager writes the component’s metadata, partitions the dataset into immediate and deferred entries, and enqueues the latter grouped by home scene (or global scope when none is defined). You also receive an OnDeferredComponentsQueued callback with the affected scene keys.
Deferred payloads stay dormant until you explicitly ask for them through the public
ProcessDeferred…methods (by scene, by GameObject, by component ID, etc.).
Processing deferred component data
ComponentManager exposes a flexible API for flushing the queue once the relevant content is visible:
// Example: when an additive scene finishes loading
ComponentManager.Instance.ProcessDeferredComponentsForScene("DungeonInterior");
// Example: when a streamed prefab cluster moves within range
ComponentManager.Instance.ProcessDeferredComponentsByUniqueIDs(idsToReveal);You can inspect pending work through HasDeferredComponents, GetDeferredSceneKeys, or PeekDeferredComponentsForScene, then respond to OnDeferredComponentsQueued to integrate with your own streaming logic.
If you prefer an automated solution, drop a DeferredPrefabRadiusStreamer in your scene. It listens to both prefab and component deferral queues and processes entries once the player comes within range, coordinating with the same APIs shown above.
Compatibility with other SaveManager features
Targeted restores (
RestoreSingleGameObject…) – These helpers gather component payloads directly fromSaveData.ComponentsDataand callComponentManager.ApplyComponentDataToObject(..., forceDuplicateLoads: true). They bypass metadata entirely, so Load Priority and Defer Until Requested settings do not delay the targeted restore, and skip-saving simply means “no data → nothing to overwrite,” which is expected when no changes were captured.Destroyed-object workflows (
DestroyWithSnapshot,RestoreDestroyedGameObject,RestoreDestroyedPrefabByAssetID) – When an object is snapshotted before destruction,SaveManagercollects all current component bytes and stores them underDestroyedObjectData. Restoration later fetches those bytes via the variant-aware lookup, without consulting deferred metadata. Skip-saving therefore only omits entries when nothing changed, and load scheduling flags have no effect on this path. Prefab instantiation still invites deferred components to apply themselves once the spawned GameObject registers, so defers continue to work for newly created instances.Snapshot-driven scene handoff (
LoadSceneAfterSnapshotAndPopulatePendingPrefabsAsync) – The helper collects a transient save, instantiates prefabs, and runs the sameApplyComponentDatapass used during a normal load. Immediate entries obey the Load Priority sort order; deferred entries remain queued, so remember to callComponentManager.ProcessDeferredComponents...(or rely on the radius streamer) once the new scene should come alive.
When (not) to enable each optimisation
✅ Skip Saving When Unchanged – Great for large structures that rarely change (terrain, complex custom components). Avoid when you need per-frame precision beyond the built-in tolerances or when downstream systems expect “last written timestamp” semantics regardless of actual data differences.
✅ Load Priority – Use to guarantee critical state (player data, quest state, inventory) becomes available before dependent scripts run. Remember it only affects the main load pipeline—targeted restores ignore the priority sort.
✅ Defer Until Requested – Ideal for world streaming, large additive scenes, or cosmetic content that can appear on demand. Pair it with radius-based processing or custom triggers. Avoid deferral for components that gate scene initialization, cut-scenes, or logic that must exist the moment a scene finishes loading.
Troubleshooting & best practices
Use
ComponentManager.GetDeferredSceneKeys()andPeekDeferredComponentsForScene()to audit staged work during debugging sessions.If legacy saves are missing metadata, the loader falls back to priority
50and “apply immediately,” so schedule a fresh save after enabling these features to populate the new metadata blocks.Hook
OnDeferredComponentsQueuedto surface UI notifications or to kick off your streaming logic as soon as new work arrives.
Streaming instantiated SaveablePrefabs (Remember Prefab)
Crystal Save can stagger the restoration of saved prefabs so that they are only instantiated when a player gets close enough, reducing up-front load spikes. This feature is especially useful for scenes with a high number of Remember Prefab instantiations, since a normal load slot call would attempt to load all prefabs at once, potentially causing long load times if Crystal Save has to deserialize thousands of objects.
In this context, the DeferredPrefabRadiusStreamer component drives this streaming workflow by listening for newly deferred prefabs, caching them per scene, and requesting instantiation once they enter a configurable radius around a chosen transform.
Video of included Demo Scene (StreamingDeferredPrefabs):
Feature overview
Deferred streaming builds on Crystal Save’s prefab deferral pipeline. When prefab data is collected, entries flagged with Defer Until Requested are split into a deferred batch;

PrefabManager queues those entries, groups them by scene (with __GLOBAL__ as a catch-all key), and raises OnDeferredPrefabsQueued so listeners can react.
The queued data retains load priorities and home-scene metadata, making it possible to revive only the objects that matter near the player.
How to use?
Select your prefab root and ensure it has the
SaveablePrefabcomponent (Remember Prefab).Open the inspector’s Advanced Settings foldout. In the
Remember Prefabcustom inspector, expand Advanced Settings to reveal the less-common options that control persistence behavior, load scheduling, and performance.Scroll to Load Scheduling and enable Defer Until Requested. This checkbox sits alongside the load-priority slider; switching it on tells Crystal Save to bypass the initial restoration pass and leave the prefab in the deferred queue until a manual trigger or
DeferredPrefabRadiusStreamerrequests it.Save or apply your prefab changes. Once the setting is enabled, the prefab’s saved state will remain deferred after loading, and the radius streamer (or any other trigger-driven call) can pull it in exactly when your gameplay requires.
With this flag active, you can rely on your trigger-based workflow—or the out-of-the-box radius streamer—to bring deferred prefabs online right when the player approaches, keeping initial load bursts under control.
How DeferredPrefabRadiusStreamer works
DeferredPrefabRadiusStreamer works
Lifecycle hooks
The streamer registers for SceneManager.activeSceneChanged and SaveManager.Initialized when it is enabled, ensuring that it reconnects to the active PrefabManager, warms the local cache, and immediately schedules a distance evaluation whenever the save system is ready or the active scene changes.
It safely detaches from events and clears its cache on disable so there are no dangling subscriptions.
Cache hydration and maintenance
Newly deferred batches trigger HandleDeferredPrefabsQueued, which notes the affected scenes and rebuilds per-scene caches by calling PrefabManager.PeekDeferredPrefabsForScene. Each cache is keyed by the prefab’s instance ID, with an empty-string scene key representing global deferrals. Whenever instantiation happens or a scene becomes active, the component refreshes its snapshot so stale entries are pruned.
Distance-based evaluation
On a configurable interval, the streamer builds a lookup that merges global and scene-specific caches, removes any prefabs already instantiated, and compares each pending prefab’s world-space position against the squared activation radius centered on the configured player transform.
Prefabs whose parents are not yet spawned are recursively resolved: if a parent exists in the scene or is already live, the component composes the proper world transform before measuring distance. It can also seed the spawn list with ancestor prefabs to keep parent-child hierarchies intact.
Requesting instantiation
When one or more prefabs fall within range, the streamer calls PrefabManager.ProcessDeferredPrefabsByInstanceIDs, handing over the exact IDs to instantiate. The manager dequeues matching entries across scenes, sorts them by load priority, and launches the restore coroutine that rebuilds those objects.
Configuration and prerequisites
Player transform: Assign the transform that should act as the distance origin. If it is missing, streaming never runs.
Prefab manager override: Optionally supply a specific
PrefabManager; otherwise the component resolvesSaveManager.Instance.GetPrefabManagerat runtime.Activation radius: Controls how far from the player prefabs must be before they are requested. The check uses squared magnitude for efficiency.
Refresh interval: Sets how often distance evaluations run; zero forces a check every frame.
Compile-time symbols: Both MEMORYPACK and ARAWN_REMEMBERME must be defined for the streamer (and its supporting data types) to compile.
Why you want to use it
Smoother load times: Objects marked for deferral stay in
PrefabManager’s queue and are revived only when a player can actually interact with them, reducing the initial instantiation burst after loading a save.Scene-aware streaming: Caches are segmented by scene and global context, so additive scene setups can stream content independently while still honoring cross-scene prefabs.
Hierarchy integrity: Recursive transform resolution and parent clustering mean children spawn next to their parents even if those parents are still deferred when the distance check runs.
Why you might skip it
Always-on worlds: If gameplay or AI systems rely on distant prefabs being active regardless of player proximity, the streamer will keep them deferred until the player enters the radius, delaying their availability.
Update budget concerns: The component runs periodic evaluations (potentially every frame), so extremely tight CPU budgets or very large deferred sets might prefer a bespoke trigger instead of radius polling.
Trigger-driven deferred streaming
Every prefab flagged with DeferLowPriorityUntilRequested remains in the deferred queue until you explicitly ask the PrefabManager to revive it, making the feature a good fit for bespoke triggers such as quest milestones, level-streaming volumes, or scripted cutscenes.
Core API surface
PrefabManager exposes several public entry points so you can flush deferred content on demand:
ProcessDeferredPrefabs()restores everything that is still deferred across all scenes in priority order.ProcessDeferredPrefabsForScene(sceneName)limits the restore to a single scene key (empty string targets the global queue).ProcessDeferredPrefabsForAsset(prefabAssetID)andProcessDeferredPrefabByUniqueID(instanceID)let you target a single prefab asset type or runtime instance, respectively.ProcessDeferredPrefabsByInstanceIDs(instanceIDs)gives you fine-grained control to spawn an arbitrary subset—useful when a trigger volume decides which specific objects should appear.
All of these helpers return the instantiation coroutine, so your systems can await completion or chain additional work afterwards.
Building smart triggers
To decide when and what to request, you can inspect the queue at runtime:
GetDeferredSceneKeys()lists every scene that still has deferred entries, whilePeekDeferredPrefabsForScene(sceneName)returns a non-destructive snapshot you can filter (e.g., by metadata stored inSaveablePrefabData).Subscribe to
OnDeferredPrefabsQueuedto be notified whenever new entries arrive, cache the IDs you care about, and trigger the relevantProcessDeferred…call once your gameplay condition is met.
Because the API mirrors what DeferredPrefabRadiusStreamer does internally, you can port its logic into bespoke systems—for example, gather the deferred IDs that belong to a dungeon wing when the player pulls a lever, then call ProcessDeferredPrefabsByInstanceIDs so the wing animates into place without ever polling distances.
Designer-friendly integrations
If your team prefers visual scripting, Crystal Save ships ready-made nodes/actions that wrap these APIs:
Game Creator instructions cover the global, scene, asset, and unique-ID variants, with optional one-frame delays to let destruction events settle before instantiating.

Equivalent Playmaker actions offer the same set of controls, enabling trigger volumes, FSM transitions, or quest states to issue the restore calls without writing custom C#.
When to pick this approach
Choose manual trigger-driven streaming whenever spawn timing is dictated by narrative beats, puzzle states, or complex spatial logic. You retain the memory/performance advantages of deferred prefabs, but avoid the periodic polling cost of the radius streamer and ensure distant systems can light up the moment your gameplay condition fires.
Benefits recap
Reduced memory churn: Deferral keeps non-essential prefabs out of memory until needed, and the streamer prunes cached entries once they are instantiated to avoid duplicate work.
Consistent player experience: By tying activation to a radius around a meaningful transform (typically the player), you maintain the illusion of a populated world without paying the cost for unseen areas.
Extensible events: Because the streamer listens to
OnDeferredPrefabsQueued, other systems can piggyback on the same event stream to drive UI or analytics about pending world content.
Use DeferredPrefabRadiusStreamer whenever you want Crystal Save’s deferred prefabs to feel invisible to players—appearing just in time as they explore—while keeping configuration simple through radius and interval tuning.
Flowchart
Last updated