Skip to content
ct

Grid Placement v5.0.9

Save and Load

Persist Grid Placement v5 state in consuming projects.

Status
Current
Version
v5.0.9
Updated
Active v5.0.9 guide line from Grid Placement repo

This guide covers how to persist placed objects across game sessions in GridBuilding 5.0.9. While the maintenance version uses component-based persistence, it establishes patterns that carry forward into future versions.

Core Concepts

Persistence in 5.0.9 relies on three key elements:

  1. PlaceableInstance: A runtime component attached to every valid placement. It holds the "DNA" of the object (template ID, original resource path).
  2. Serialization: The process of converting the node hierarchy into a flat Dictionary.
  3. Deserialization: Reconstructing the node tree from data, ensuring all dependencies (scripts, resources) are relinked.

The Serialization Contract

A valid save entry in 5.0.9 looks like this:

{
    "instance_name":"Chair_001",
    "transform":Transform2D(...),
    "placeable_id":"**res://placeables/chair.tres**",
    "custom_data": {
        "durability":50,
        "owner_id":"player_1"
    }
}

PlaceableInstance Component

The PlaceableInstance script (res://addons/grid_placement/placeable_instance.gd) exposes two critical methods:

  • save(with_custom_data: bool) -> Dictionary: serializes the node.
  • instance_from_save(data: Dictionary, parent: Node) -> Node: static factory method to rebuild the node.

Implementation Guide

Step 1: Saving the World

To save your level, iterate through the PlaceableInstance group. This group is automatically managed by the system.

func save_level()-> void:
    var save_data:Array[Dictionary]= []

    # Iterate all placed objects
    for nodein get_tree().get_nodes_in_group("PlaceableInstance"):

        # 1. Validate it's a valid placement (not a preview)
        if node.get_parent().has_meta("gb_preview"):
            continue

        # 2. Serialize
        # Assumes the node structure: PlaceableRoot -> PlaceableInstance
        var data= node.save(true)

        # 3. Add custom game logic data (optional)
        if node.get_parent().has_method("get_custom_save_data"):
            data["custom_data"]= node.get_parent().get_custom_save_data()

        save_data.append(data)

    # Write to file
    _write_to_disk(save_data)

Step 2: Loading the World

Loading is a two-step process: Clear the existing world, then rebuild from data.

func load_level(data:Array[Dictionary])-> void:
    # 1. Clear existing
    get_tree().call_group("PlaceableInstance","queue_free")
    await get_tree().process_frame

    # 2. Rebuild
    for entryin data:
        # Static factory method handles resource loading
        var new_node= PlaceableInstance.instance_from_save(entry, world_root)

        # Restore custom data if needed
        if "custom_data" in entryand new_node.has_method("restore_custom_data"):
            new_node.restore_custom_data(entry["custom_data"])

Handling Edge Cases

  • Missing Resources: If a placeable_id resource path no longer exists (e.g., you deleted the file), instance_from_save will fail gracefully. Ensure your loading logic handles null returns.
  • Version Migrations: 5.0.9 does not have a built-in schema migration system. If you change your data structure, you must handle version checking in your own code.

Validated By

The save/load architecture and serialization patterns are verified by the following test suites:

  • Serialization Protocol: res://addons/grid_placement/test/building/placement/placement_report_unit_test.gd — Validates the serialization of placement metadata and report integrity.
  • Component Implementation: res://addons/grid_placement/placeable_instance.gd — Core component that manages instance lifecycle and serialization hooks.
  • Metadata Integrity: res://addons/grid_placement/test/utilities/data/composition_container_subresources_test.gd — Ensures that configuration data used during reconstruction is properly persisted.

Related Guides