Fyrox Savegame

セーブスロット、バージョニング、暗号化 — Fyrox Rustゲームエンジン向けのゲーム指向セーブ/ロードシステム。単なるserdeラッパーではありません。

Fyrox 1.0+ Rust 1.87+ MIT (Free) LZ4 / Zstd AES-256-GCM (Pro) アトミック書き込み
itch.ioでProを入手 GitHub (Free版)

主要機能

💾

名前付きスロット + クイックセーブ

名前付きスロット("slot_1"、"manual_save")にセーブ、またはquick_save()/quick_load()でワンボタンセーブ/ロード。

📋

リッチメタデータ

タイムスタンプ、総プレイ時間、説明文、サムネイル(PNGバイト)、カスタムキー・バリューペア。フルファイルをロードせずにセーブ情報を表示可能。

🔄

バージョンマイグレーション

MigrationRegistryがアップグレード関数を順番に実行(v1 → v2 → v3)。大規模アップデート後でも古いセーブを常にロード可能。

📦

LZ4圧縮

高速LZ4圧縮により、最小限のCPUオーバーヘッドでセーブファイルサイズを削減。Pro版ではより高い圧縮率のZstdを追加。

🔒

CRC32チェックサム

すべてのセーブファイルにCRC32チェックサムを付与。デシリアライズ前にロード時の破損を検出。Pro版ではより強力なSHA-256を追加。

⚛️

アトミック書き込み

一時ファイルに書き込んでからターゲットにリネーム。セーブ中にゲームがクラッシュしても、以前のファイルはそのまま。

🔐

AES-256-GCM(Pro)

セーブファイルを暗号化して改ざんやチートを防止。認証付き暗号化により機密性と整合性の両方を保証。

非同期セーブ(Pro)

tokioによるノンブロッキングセーブ。セーブデータの圧縮・暗号化・書き込み中もゲームは動き続けます。

セーブファイルフォーマット

マジック FXSG(4バイト)
ヘッダー バージョン + フラグ
メタデータ bincodeエンコード
ペイロード bincode → LZ4
チェックサム CRC32(4バイト)

Pro版:ペイロードはLZ4の代わりにZstdを使用可能。ペイロード+チェックサムブロック全体をAES-256-GCM暗号化でラップ可能。

依存関係

Free

serdeシリアライゼーションフレームワーク
bincodeバイナリエンコーディング
thiserrorエラー型
crc32fastCRC32チェックサム
lz4_flexLZ4圧縮

Pro(追加分)

sha2SHA-256整合性
aes-gcmAES-256-GCM暗号化
zstdZstd圧縮
tokio非同期ランタイム

Free版 vs Pro版

Free MIT

  • 名前付きスロット + クイックセーブ/ロード
  • メタデータ(タイムスタンプ、プレイ時間、説明文、サムネイル、カスタムKV)
  • バージョンアップグレード用MigrationRegistry
  • LZ4圧縮
  • CRC32チェックサム
  • アトミック書き込み(一時ファイル + リネーム)
  • フォーマット:マジックFXSG + bincode + LZ4 + CRC32
  • 完全なserde統合

Pro 有料

  • Free版のすべての機能
  • SHA-256整合性検証
  • AES-256-GCM暗号化(チート対策)
  • Zstd圧縮(より高い圧縮率)
  • tokioによる非同期セーブ(ノンブロッキング)
  • オートセーブローテーション(タイマー + ローテーションスロット)
  • pro_encode()/pro_decode()用ProSaveConfig
  • 優先サポート

クイックスタート例

use fyrox_savegame::*;

#[derive(serde::Serialize, serde::Deserialize)]
struct GameState {
    player_hp: i32,
    level: u32,
    position: [f32; 3],
    inventory: Vec<String>,
}

// セーブ
let state = GameState { player_hp: 85, level: 7, position: [10.0, 0.0, -5.0], inventory: vec!["sword".into()] };
let meta = Metadata::new()
    .description("森のダンジョンに入った")
    .playtime(Duration::from_secs(3600))
    .custom("chapter", "3");

SaveManager::save("slot_1", &state, &meta)?;

// ロード
let (state, meta): (GameState, Metadata) = SaveManager::load("slot_1")?;
println!("HP: {}, プレイ時間: {:?}", state.player_hp, meta.playtime());

// クイックセーブ/ロード
SaveManager::quick_save(&state, &meta)?;
let (state, meta): (GameState, Metadata) = SaveManager::quick_load()?;

// バージョンマイグレーション
let mut registry = MigrationRegistry::new();
registry.register(1, 2, |data: Value| {
    // 新しい"stamina"フィールドをデフォルト値で追加
    data["stamina"] = Value::from(100);
    Ok(data)
});
registry.register(2, 3, |data: Value| {
    // "hp"を"player_hp"にリネーム
    data["player_hp"] = data["hp"].clone();
    Ok(data)
});

Pro:暗号化非同期セーブ

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,
};

// ノンブロッキングセーブ(即座に返る)
let handle = pro_encode_async("autosave_1", &state, &meta, &config).await?;

// オートセーブローテーション:直近3件のセーブを保持、5分ごとにローテーション
let auto_saver = AutoSave::new()
    .interval(Duration::from_secs(300))
    .slots(3)  // autosave_0, autosave_1, autosave_2
    .config(config);
auto_saver.start(); // tokioでバックグラウンド実行

よくある質問

なぜserdeを直接使わないのですか?

素のserdeはシリアライゼーションを提供しますが、ゲームセーブ機能は含まれていません。Fyrox Savegameは名前付きセーブスロット、メタデータ(タイムスタンプ、プレイ時間、サムネイル)、アップデート後も古いセーブが読み込めるバージョンマイグレーション、LZ4圧縮、CRC32整合性チェック、破損を防ぐアトミック書き込みを追加します。単なるシリアライゼーションラッパーではなく、完全なセーブシステムです。

クラッシュに対して安全ですか?

はい。セーブはアトミック書き込みを使用します:データはまず一時ファイルに書き込まれ、その後ターゲットにリネームされます。書き込み中にゲームがクラッシュしても、以前のセーブはそのまま残ります。CRC32チェックサムがロード時にファイルの破損を検出します。

バージョンマイグレーションはどのように動作しますか?

MigrationRegistryにバージョン番号をキーとしたマイグレーション関数を登録します。古いバージョンのセーブをロードする際、システムは各マイグレーションを順番に実行(v1からv2、v2からv3など)してデータをアップグレードします。後方互換性を壊す必要はありません。

セーブファイルのフォーマットは?

マジックバイト(FXSG)+ バージョンヘッダー + メタデータ(bincode)+ ペイロード(ゲームステートをbincodeでシリアライズ、LZ4で圧縮、CRC32付加)。Pro版ではZstd圧縮に切り替え可能で、ペイロードをAES-256-GCM暗号化でラップできます。

なぜチート対策にAES-256-GCMを使うのですか?

AES-256-GCMは認証付き暗号化を提供します。鍵なしではプレイヤーがセーブデータを読んだり変更したりすることはできません。GCM認証タグにより、ロード時にあらゆる改ざんが検出されます。セーブエディタやチートツールによるゲームステートの改変を防止します。

非同期セーブはゲームをブロックしますか?

いいえ。Pro版の非同期セーブ(tokio経由)はバックグラウンドスレッドでデータのシリアライズ、圧縮、暗号化を行います。ゲームループは動き続けます。ステータス確認や結果の待機用の完了ハンドルが提供されます。

プレイヤーの進行状況を二度と失わない

圧縮、整合性チェック、暗号化、マイグレーションを備えたクラッシュセーフなセーブ — ゲームのために作られました。

itch.ioでProを入手 GitHub (Free版)