Save Slots, Versioning & Encryption — a game-oriented save/load system for the Fyrox Rust game engine. Not just a serde wrapper.
Save to named slots ("slot_1", "manual_save") or use quick_save()/quick_load() for one-button save/load.
Timestamp, total playtime, description, thumbnail (PNG bytes), and custom key-value pairs. Display save info without loading the full file.
MigrationRegistry runs upgrade functions in order (v1 → v2 → v3). Old saves always load, even after major updates.
Fast LZ4 compression reduces save file size with minimal CPU overhead. Pro adds Zstd for higher compression ratios.
Every save file includes a CRC32 checksum. Detect corruption on load before deserializing. Pro adds SHA-256 for stronger integrity.
Write to a temp file, then rename over the target. If the game crashes mid-save, the previous file stays intact.
Encrypt save files to prevent tampering and cheating. Authenticated encryption ensures both confidentiality and integrity.
Non-blocking saves via tokio. The game keeps running while save data is compressed, encrypted, and written to disk.
Pro: Payload can use Zstd instead of LZ4, and the entire payload+checksum block can be wrapped in AES-256-GCM encryption.
serde | Serialization framework |
bincode | Binary encoding |
thiserror | Error types |
crc32fast | CRC32 checksums |
lz4_flex | LZ4 compression |
sha2 | SHA-256 integrity |
aes-gcm | AES-256-GCM encryption |
zstd | Zstd compression |
tokio | Async runtime |
use fyrox_savegame::*;
#[derive(serde::Serialize, serde::Deserialize)]
struct GameState {
player_hp: i32,
level: u32,
position: [f32; 3],
inventory: Vec<String>,
}
// Save
let state = GameState { player_hp: 85, level: 7, position: [10.0, 0.0, -5.0], inventory: vec!["sword".into()] };
let meta = Metadata::new()
.description("Entered the forest dungeon")
.playtime(Duration::from_secs(3600))
.custom("chapter", "3");
SaveManager::save("slot_1", &state, &meta)?;
// Load
let (state, meta): (GameState, Metadata) = SaveManager::load("slot_1")?;
println!("HP: {}, Playtime: {:?}", state.player_hp, meta.playtime());
// Quick save/load
SaveManager::quick_save(&state, &meta)?;
let (state, meta): (GameState, Metadata) = SaveManager::quick_load()?;
// Version migration
let mut registry = MigrationRegistry::new();
registry.register(1, 2, |data: Value| {
// Add new "stamina" field with default
data["stamina"] = Value::from(100);
Ok(data)
});
registry.register(2, 3, |data: Value| {
// Rename "hp" to "player_hp"
data["player_hp"] = data["hp"].clone();
Ok(data)
});
use fyrox_savegame_pro::*;
let config = ProSaveConfig {
compression: Compression::Zstd { level: 3 },
encryption: Some(EncryptionConfig {
algorithm: EncryptionAlgorithm::Aes256Gcm,
key: load_key_from_secure_storage()?,
}),
integrity: Integrity::Sha256,
};
// Non-blocking save (returns immediately)
let handle = pro_encode_async("autosave_1", &state, &meta, &config).await?;
// Auto-save rotation: keeps last 3 saves, rotates every 5 minutes
let auto_saver = AutoSave::new()
.interval(Duration::from_secs(300))
.slots(3) // autosave_0, autosave_1, autosave_2
.config(config);
auto_saver.start(); // runs in background via tokio
Plain serde gives you serialization, but not game save features. Fyrox Savegame adds named save slots, metadata (timestamps, playtime, thumbnails), version migration so old saves load after updates, LZ4 compression, CRC32 integrity checks, and atomic writes to prevent corruption. It is a complete save system, not just a serialization wrapper.
Yes. Saves use atomic writes: data is written to a temporary file first, then renamed over the target. If the game crashes mid-write, the previous save remains intact. CRC32 checksums detect any file corruption on load.
Register migration functions in the MigrationRegistry, keyed by version numbers. When loading a save from an older version, the system runs each migration in order (v1 to v2, v2 to v3, etc.) to upgrade the data. You never break backward compatibility.
Magic bytes (FXSG) + version header + metadata (bincode) + payload (game state serialized with bincode, compressed with LZ4, CRC32 appended). Pro can substitute Zstd compression and wrap the payload in AES-256-GCM encryption.
AES-256-GCM provides authenticated encryption: players cannot read or modify save data without the key. The GCM authentication tag ensures any tampering is detected on load. This prevents save editors and cheat tools from modifying game state.
No. Pro's async saving (via tokio) serializes, compresses, and encrypts the data on a background thread. The game loop continues running. You receive a completion handle to check status or await the result.
Crash-safe saves with compression, integrity, encryption, and migration — built for games.
Get Pro on itch.io GitHub (Free)