Data Persistence System

Event-driven save system with crash recovery that adapts to code changes automatically

The Challenge

Save files break between updates

Even minor code refactoring corrupts player progress, forcing complete restarts with each game update

Complex state tracking nightmares

Manually serializing nested objects and relationships becomes an unmaintainable web of dependencies

Technical Implementation

Inspired by Jan Thomä's guide on save compatibility in Godot.

Why most games break saves

Without this system

// Version 1.0
player_health = 100
// Version 1.1 - renamed variable
player_health → health
All saves corrupted
// Version 1.2 - added feature
+ player_stamina
Old saves crash on load

With this system

Flexible property mapping
Old names map to new ones automatically
Graceful defaults
Missing properties get sensible values
Self-healing saves
Objects rebuild from partial data

How it works

Every game object broadcasts its state through signals. No central tracking system that becomes a bottleneck or single point of failure.

State lives in memory until explicitly saved. This means instant autosaves, zero corruption from crashes, and perfect recovery even from power loss.

The real magic: property versioning. When you refactor code, the save system adapts. Players keep their progress through every update.

Protection Layers

1

Write-ahead logging

Changes written to temp files first. Original saves untouched until validated.

2

Memory-first architecture

State cached in memory. Crashes can't corrupt disk data.

3

Self-healing saves

Objects rebuild from partial data. Game continues with defaults if needed.

The Results

Before

Reliability Data loss on crashes and transitions
Updates Save files break with code changes
Complexity Manual tracking of every object

After

Reliability Complete crash recovery
Updates Save files survive all updates
Complexity Automatic distributed persistence

C# • Godot Resource System • Event Architecture