Files
godot-shader-experiments/addons/gecs/docs/SERIALIZATION.md
2026-01-15 15:27:48 +01:00

5.1 KiB

GECS Serialization

The GECS framework provides a robust serialization system using Godot's native resource format, enabling persistent game states, save systems, and level data management.

Quick Start

Basic Save/Load

# Save entities with persistent components
var query = ECS.world.query.with_all([C_Persistent])
var data = ECS.serialize(query)
ECS.save(data, "user://savegame.tres")

# Load entities back
var entities = ECS.deserialize("user://savegame.tres")
for entity in entities:
    ECS.world.add_entity(entity)

Binary Format

# Save as binary for production (smaller files)
ECS.save(data, "user://savegame.tres", true)  # Creates .res file

# Load auto-detects format (tries .res first, then .tres)
var entities = ECS.deserialize("user://savegame.tres")

API Reference

ECS.serialize(query: QueryBuilder) -> GecsData

Converts entities matching a query into serializable data.

Example:

# Serialize specific entities
var player_query = ECS.world.query.with_all([C_Player, C_Health])
var save_data = ECS.serialize(player_query)

ECS.save(data: GecsData, filepath: String, binary: bool = false) -> bool

Saves data to disk. Returns true on success.

Parameters:

  • data: Serialized entity data
  • filepath: Save location (use .tres extension)
  • binary: If true, saves as .res (smaller, faster loading)

ECS.deserialize(filepath: String) -> Array[Entity]

Loads entities from file. Returns empty array if file doesn't exist.

Auto-detection: Tries binary .res first, falls back to text .tres.

Component Serialization

Only @export variables are serialized:

class_name C_PlayerData
extends Component

@export var health: float = 100.0        # ✅ Saved
@export var inventory: Array[String]     # ✅ Saved
@export var position: Vector2            # ✅ Saved

var _cache: Dictionary = {}              # ❌ Not saved

Supported types: All Godot built-ins (int, float, String, Vector2/3, Color, Array, Dictionary, etc.)

Use Cases

Save Game System

func save_game(slot: String):
    var query = ECS.world.query.with_all([C_Persistent])
    var data = ECS.serialize(query)

    if ECS.save(data, "user://saves/slot_%s.tres" % slot, true):
        print("Game saved!")

func load_game(slot: String):
    ECS.world.purge()  # Clear current state

    var entities = ECS.deserialize("user://saves/slot_%s.tres" % slot)
    for entity in entities:
        ECS.world.add_entity(entity)

Level Export/Import

func export_level():
    var query = ECS.world.query.with_all([C_LevelObject])
    var data = ECS.serialize(query)
    ECS.save(data, "res://levels/level_01.tres")

func load_level(path: String):
    var entities = ECS.deserialize(path)
    ECS.world.add_entities(entities)

Selective Serialization

# Save only player data
var player_query = ECS.world.query.with_all([C_Player])

# Save entities in specific area
var area_query = ECS.world.query.with_group("area_1")

# Save entities with specific components
var combat_query = ECS.world.query.with_all([C_Health, C_Weapon])

Data Structure

The system uses two main resource classes:

GecsData

class_name GecsData
extends Resource

@export var version: String = "0.1"
@export var entities: Array[GecsEntityData] = []

GecsEntityData

class_name GecsEntityData
extends Resource

@export var entity_name: String = ""
@export var scene_path: String = ""      # For prefab entities
@export var components: Array[Component] = []

Error Handling

# Serialize never fails (returns empty data if no matches)
var data = ECS.serialize(query)

# Check save success
if not ECS.save(data, filepath):
    print("Save failed - check permissions")

# Handle missing files
var entities = ECS.deserialize(filepath)
if entities.is_empty():
    print("No data loaded")

Performance

  • Memory: Creates component copies during serialization
  • Speed: Binary format ~60% smaller, faster loading than text
  • Scale: Tested with 100+ entities, sub-second performance

Binary vs Text Format

Text (.tres):

  • Human readable
  • Editor inspectable
  • Version control friendly
  • Development debugging

Binary (.res):

  • Smaller file size
  • Faster loading
  • Production builds
  • Auto-detection on load

File Structure Example

[gd_resource type="GecsData" format=3]

[sub_resource type="C_Health" id="1"]
current = 85.0
maximum = 100.0

[sub_resource type="GecsEntityData" id="2"]
entity_name = "Player"
components = [SubResource("1")]

[resource]
version = "0.1"
entities = [SubResource("2")]

Best Practices

  1. Use meaningful filenames: player_save.tres, level_boss.tres
  2. Organize by purpose: user://saves/, res://levels/
  3. Handle missing components gracefully
  4. Use binary format for production
  5. Version your save data for compatibility
  6. Test with empty query results

Limitations

  • No entity relationships (planned feature)
  • Prefab entities need scene files present
  • External resource references need manual handling