Save and Load (5.0.3)

-This guide covers how to persist placed objects across game sessions in GridBuilding 5.0.3. While the maintenance version uses component-based persistence, it establishes patterns that carry forward into future versions.## Core ConceptsPersistence in 5.0.3 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 ContractA valid save entry in 5.0.3 looks like this:pythonfunc make_save_entry() -> Dictionary: return { "instance_name": "Chair_001", "transform": Transform2D.IDENTITY, "placeable_id": "res://placeables/chair.tres", "custom_data": { "durability": 50, "owner_id": "player_1" } }## PlaceableInstance ComponentThe PlaceableInstance script (res://addons/grid_building/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 WorldTo save your level, iterate through the PlaceableInstance group. This group is automatically managed by the system.pythonfunc 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 WorldLoading is a two-step process: Clear the existing world, then rebuild from data.pythonfunc 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_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.3 does not have a built-in schema migration system. If you change your data structure, you must handle version checking in your own code.## Related Guides- Placement Workflow- Architecture Overview (5.0.3)