Save Procedural GameObjects
This guide explains how to save and restore procedurally generated GameObjects using Crystal Save Version 1.6.52 or higher. There are two distinct approaches, each suited to different use cases.
Overview: Two Scenarios
Scenario 1
Prefab Variations
✅ Efficient
You can use a prefab as a base and add/modify components at runtime
Scenario 2
Truly Procedural
⚠️ Resource-Intensive
GameObjects are created entirely from code with no prefab base
Recommendation: Always prefer Scenario 1 when possible. Most "procedural" content can be modeled as variations on a base prefab.
Scenario 1: Prefab Variations (Recommended)
Concept
Start with a prefab asset (even a minimal "blank" one) and modify it at runtime by:
Adding new components
Changing materials, meshes, or textures
Modifying child object state
Adding or removing child objects
Crystal Save uses prefab diffing to efficiently store only the differences from the original prefab.
Setup
Option A: Configure in Editor
Select your prefab asset
In the
SaveablePrefabinspector, enable:☑️ Track Added Components – Captures components added at runtime
☑️ Track Component Blobs – Saves custom data from ISaveable components
(Optional) Other tracking flags based on your needs
Option B: Configure at Runtime via Code
Or configure an existing instance:
How It Works
On Save: Crystal Save compares the instance to the original prefab asset
Diffing: Only components/properties that differ from the prefab are serialized
On Load: The prefab is instantiated via Unity's optimized system, then the diff is applied
Advantages
✅ Fast instantiation – Uses Unity's native prefab system
✅ Small save files – Only differences are stored
✅ Supports pooling – Works with
SaveablePrefabPoolCache✅ Memory efficient – Prefabs share assets in memory
Example: Procedural Items
Scenario 2: Truly Procedural GameObjects
⚠️ WARNING: Resource-Intensive Approach
This approach saves GameObjects that have no prefab base – objects created entirely via new GameObject() and populated with components through code.
Why Is This Inefficient?
Unity's architecture is fundamentally optimized for prefabs. When you save a "truly procedural" GameObject, Crystal Save must work against Unity's design in several ways:
1. Serialization Overhead
Prefab (Scenario 1): Only the diff from the base prefab is serialized (typically small)
Procedural (Scenario 2): The entire component graph must be serialized, including:
Every component type name (as strings)
Every serializable field on every component
All object references (which may break across sessions)
2. Restoration Cost
On load, the restoration process differs dramatically:
Create GameObject
Instantiate(prefab) – native C++ binary deserialization
new GameObject() – slow managed allocation
Add Components
Not needed – already on prefab
AddComponent() for each – reflection-heavy
Set Field Values
Apply diff only
Deserialize and apply ALL fields
AddComponent() is slow because Unity must:
Allocate the component in managed memory
Perform reflection to find the component type
Initialize default values
Wire up to the GameObject's component list
Call Awake/OnEnable lifecycle methods
For a prefab, all of this is pre-computed in the prefab's binary data and restored through Unity's optimized native code path.
3. Memory Fragmentation
Prefab instances share underlying mesh, material, and texture assets. Procedural objects created from scratch may create duplicate references or orphaned assets.
4. Reference Integrity
Object references (e.g., a component referencing another GameObject) may not survive serialization correctly for procedural objects, since there's no stable prefab structure to anchor them.
When to Use Scenario 2
Despite the costs, Scenario 2 is appropriate when:
✅ The object structure is completely unpredictable at design time
✅ You have a very small number of procedural objects (<10 in the entire game)
✅ Save/load performance is not critical (e.g., only saving on game quit)
✅ You cannot create even a generic "blank" prefab as a base
Setup for Scenario 2
Or use the convenience method:
Why You Still Need an Empty Prefab
Even for "truly procedural" objects, Crystal Save needs a prefab asset registered in the PrefabRegistry to serve as the restoration base. This prefab can be completely empty (just a GameObject with SaveablePrefab), but it:
Provides a stable
PrefabAssetIDfor the registryGives Unity something to instantiate before applying the procedural component list
Ensures the object can be found and restored after scene reloads
Comparison Summary
Base Object
Prefab asset
Empty prefab or none
Instantiation Speed
Fast (native)
Slow (managed + reflection)
Save Data Size
Small (diff only)
Large (full component graph)
Supports Pooling
Yes
No
Reference Integrity
High
Limited
Recommended Count
Unlimited
<10 objects
Use Case
Items, enemies, props
Unique one-off objects
API Reference
ProceduralSaveUtility
SaveablePrefab Tracking Properties
All tracking flags now have public setters for runtime configuration:
Best Practices
Start with Scenario 1 – Even if your content feels "procedural," try to identify common bases that can be prefabs
Create Generic Prefabs – A "blank" prefab with just
SaveablePrefabcan serve as a base for many procedural variationsUse ISaveable for Custom Data – Implement
ISaveableon components that need to save complex state, then enableTrackComponentBlobsLimit Scenario 2 Usage – Reserve truly procedural objects for unique, irreplaceable game objects
Test Save/Load Performance – If using Scenario 2, profile your save/load times with realistic object counts
Consider Hybrid Approaches – Sometimes you can save procedural data as pure data (not GameObjects) and reconstruct objects on load
Troubleshooting
Components Not Being Saved
Ensure
TrackAddedComponentsis enabledFor custom data, ensure
TrackComponentBlobsis enabled and components implementISaveableVerify the instance was created via
SaveablePrefabFactoryor properly configured
Missing Components After Load
Check that component types are registered with Unity's serialization system
Ensure no
[NonSerialized]attributes on critical fieldsVerify the
PrefabAssetIDis registered inPrefabRegistry
Slow Load Times with Procedural Objects
This is expected behavior for Scenario 2
Consider switching to Scenario 1 with a generic base prefab
Reduce the number of procedural objects
Defer low-priority object loading using
DeferLowPriorityUntilRequested
Game Creator 2 Integration
Crystal Save provides visual scripting Instructions and Conditions for Game Creator 2 users who visual workflows over C# code.
Instructions
All procedural instructions are located in: Crystal Save → Procedural
1. Configure Prefab Variations (Scenario 1 - Recommended)
Location: Crystal Save/Procedural/Configure Prefab Variations
Configures an existing SaveablePrefab instance to track runtime modifications. Use this after spawning a prefab via other means (e.g., GC2's built-in Instantiate or Crystal Save's "Instantiate Saveable Prefab").
Target
GameObject with SaveablePrefab to configure
Required
Track Added Components
Track components added via AddComponent at runtime
true
Track Component Blobs
Track custom ISaveable data from attached components
true
Track Material Overrides
Track per-slot Material changes on Renderers
false
Track Child State Overrides
Track child object active/tag/layer changes
true
Track Child Transform Overrides
Track child position/rotation/scale changes
false
Store Success
(Optional) Variable to store whether configuration succeeded
None
Example Workflow:
Instantiate Saveable Prefab → store in
myItemConfigure Prefab Variations → Target:
myItem(Use GC2's Add Component or custom logic to modify the instance)
Save Game
2. Instantiate With Variation Tracking (Scenario 1 - Recommended)
Location: Crystal Save/Procedural/Instantiate With Variation Tracking
Spawns a prefab and configures it for runtime modifications in a single instruction. This is the most convenient way to spawn procedural content.
Prefab
Prefab asset to instantiate
Required
Position
World position for the new instance
(0,0,0)
Rotation
World rotation for the new instance
Identity
Parent
(Optional) Parent transform
None
Track Added Components
Track components added at runtime
true
Track Component Blobs
Track custom ISaveable data
true
Store Instance
Variable to store the spawned GameObject
None
Store Prefab Component
Variable to store the SaveablePrefab component
None
Example Workflow:
Instantiate With Variation Tracking → Prefab:
GenericItem, Store Instance:spawnedItem(Add components or modify
spawnedItemas needed)Components added will automatically be saved and restored
3. Configure Procedural GameObject (Scenario 2 - ⚠️ Resource-Intensive)
Location: Crystal Save/Procedural/Configure Procedural GameObject
Configures a GameObject that was created entirely from code (via new GameObject()) for saving. Only use this when you cannot use a prefab base.
Target
The procedural GameObject to configure
Required
Empty Prefab Asset
A minimal "blank" prefab to use as restoration base
Recommended
Store Prefab Component
Variable to store the added SaveablePrefab
None
Store Success
Variable to store whether configuration succeeded
None
Important: The "Empty Prefab Asset" should be a blank GameObject with just a SaveablePrefab component. This is needed for the save system to know how to restore the object.
Example Workflow:
(Create a GameObject via GC2's "Create Game Object" or custom code)
Configure Procedural GameObject → Target:
myObject, Empty Prefab Asset:BlankSaveablePrefab(Add components to
myObject)Save Game
4. Create Procedural GameObject (Scenario 2 - ⚠️ Resource-Intensive)
Location: Crystal Save/Procedural/Create Procedural GameObject
Creates a new empty GameObject and configures it for procedural saving in one instruction. The object starts with NO components – add them after creation.
Name
Name for the new GameObject
"ProceduralObject"
Position
World position
(0,0,0)
Rotation
World rotation
Identity
Empty Prefab Asset
A minimal "blank" prefab for restoration
Recommended
Store Instance
Variable to store the created GameObject
None
Example Workflow:
Create Procedural GameObject → Name:
"DynamicPlatform", Store Instance:platform(Add MeshFilter, MeshRenderer, Collider, etc. to
platform)Save Game
Conditions
Is Configured For Procedural Saving
Location: Crystal Save/Procedural/Is Configured For Procedural Saving
Returns true if the target SaveablePrefab has the minimum required settings enabled for procedural saving (TrackAddedComponents AND TrackComponentBlobs).
Target
GameObject with SaveablePrefab to check
Use Cases:
Validate that an object is properly configured before adding components
Debug workflows to ensure configuration was applied
Conditional logic based on save capability
Example:
Visual Scripting Workflow Examples
Example 1: Spawning Randomized Items
Goal: Spawn items with random components that persist across save/load.
Example 2: Player-Built Structures
Goal: Let players place objects that gain components over time.
Example 3: Truly Procedural (Use Sparingly)
Goal: Create a completely dynamic object at runtime.
Tips for Game Creator 2 Users
Use "Instantiate With Variation Tracking" for most cases – It's a single instruction that handles everything.
Create a "BlankSaveablePrefab" asset – A simple empty prefab with just
SaveablePrefabthat you can reference for Scenario 2 workflows.The ⚠️ warning icon is intentional – Instructions for Scenario 2 show a yellow warning color to remind you they're resource-intensive.
Combine with existing Crystal Save instructions – These procedural instructions work alongside "Instantiate Saveable Prefab", "Register Saveable", etc.
Test save/load frequently – Procedural content can be tricky. Verify your workflows actually persist correctly.
Last updated