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 node in 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 entry in 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 entry and 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
Source
docs/v5-0/guides/save-and-load.md
Plugin docs root:gdscript/plugins/grid_placement_dev/docs