Historical 5.x guide. This page describes a legacy API and is not current integration guidance. For new projects, start with Getting Started.
This guide covers how to persist placed objects across game sessions in GridBuilding 5.0.8. While the maintenance version uses component-based persistence, it establishes patterns that carry forward into future versions.
Core Concepts
Persistence in 5.0.8 relies on three key elements:
- PlaceableInstance: A runtime component attached to every valid placement. It holds the "DNA" of the object (template ID, original resource path).
- Serialization: The process of converting the node hierarchy into a flat Dictionary.
- Deserialization: Reconstructing the node tree from data, ensuring all dependencies (scripts, resources) are relinked.
The Serialization Contract
A valid save entry in 5.0.8 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_idresource path no longer exists (e.g., you deleted the file),instance_from_savewill fail gracefully. Ensure your loading logic handles null returns. - Version Migrations: 5.0.8 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
Using this in a game?
Grid Placement v6.3.0 — full source, playable demos, commercial license
The guide above is the same setup the shipped demos use. Try the build in your browser before you buy it.