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
Description
Performance
Use When

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.


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

  1. Select your prefab asset

  2. In the SaveablePrefab inspector, 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

  1. On Save: Crystal Save compares the instance to the original prefab asset

  2. Diffing: Only components/properties that differ from the prefab are serialized

  3. 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:

Step
Prefab (Scenario 1)
Procedural (Scenario 2)

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:

  1. Allocate the component in managed memory

  2. Perform reflection to find the component type

  3. Initialize default values

  4. Wire up to the GameObject's component list

  5. 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:

  1. Provides a stable PrefabAssetID for the registry

  2. Gives Unity something to instantiate before applying the procedural component list

  3. Ensures the object can be found and restored after scene reloads


Comparison Summary

Aspect
Scenario 1 (Prefab Variations)
Scenario 2 (Truly Procedural)

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

  1. Start with Scenario 1 – Even if your content feels "procedural," try to identify common bases that can be prefabs

  2. Create Generic Prefabs – A "blank" prefab with just SaveablePrefab can serve as a base for many procedural variations

  3. Use ISaveable for Custom Data – Implement ISaveable on components that need to save complex state, then enable TrackComponentBlobs

  4. Limit Scenario 2 Usage – Reserve truly procedural objects for unique, irreplaceable game objects

  5. Test Save/Load Performance – If using Scenario 2, profile your save/load times with realistic object counts

  6. 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 TrackAddedComponents is enabled

  • For custom data, ensure TrackComponentBlobs is enabled and components implement ISaveable

  • Verify the instance was created via SaveablePrefabFactory or properly configured

Missing Components After Load

  • Check that component types are registered with Unity's serialization system

  • Ensure no [NonSerialized] attributes on critical fields

  • Verify the PrefabAssetID is registered in PrefabRegistry

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").

Parameter
Description
Default

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:

  1. Instantiate Saveable Prefab → store in myItem

  2. Configure Prefab Variations → Target: myItem

  3. (Use GC2's Add Component or custom logic to modify the instance)

  4. 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.

Parameter
Description
Default

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:

  1. Instantiate With Variation Tracking → Prefab: GenericItem, Store Instance: spawnedItem

  2. (Add components or modify spawnedItem as needed)

  3. 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.

Parameter
Description
Default

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:

  1. (Create a GameObject via GC2's "Create Game Object" or custom code)

  2. Configure Procedural GameObject → Target: myObject, Empty Prefab Asset: BlankSaveablePrefab

  3. (Add components to myObject)

  4. 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.

Parameter
Description
Default

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:

  1. Create Procedural GameObject → Name: "DynamicPlatform", Store Instance: platform

  2. (Add MeshFilter, MeshRenderer, Collider, etc. to platform)

  3. 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).

Parameter
Description

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

  1. Use "Instantiate With Variation Tracking" for most cases – It's a single instruction that handles everything.

  2. Create a "BlankSaveablePrefab" asset – A simple empty prefab with just SaveablePrefab that you can reference for Scenario 2 workflows.

  3. The ⚠️ warning icon is intentional – Instructions for Scenario 2 show a yellow warning color to remind you they're resource-intensive.

  4. Combine with existing Crystal Save instructions – These procedural instructions work alongside "Instantiate Saveable Prefab", "Register Saveable", etc.

  5. Test save/load frequently – Procedural content can be tricky. Verify your workflows actually persist correctly.

Last updated