メインコンテンツまでスキップ

セーブシステム

MCE は、名前付きセーブ、アトミックな書き込み、オートセーブのローテーション、バージョン管理、拡張性を備えた JSON ベースのセーブシステムを使います。セーブシステムは、プレイヤーのゲーム状態全体 -- ロースター、インベントリ、位置、バッジ、クエストの進行、ゲーム変数 -- を保存します。

セーブ関連のオプション

その画面のスイッチのうち 3 つは、このシステムに属します。Partida guardada はシリアライズ形式を選び、 Autoguard. historia はストーリーの節目で自動的に書き込むかを決め、 Subir a la nube はマシンの外へ出す前に確認を求めるものです。

アーキテクチャ​

セーブシステムは複数のコンポーネントで構成されています。

コンポーネント目的
SavegameManagerセーブ/ロード操作を統括する(SavegameInstaller でバインドされる ScriptableObject)
SavableObjectデータを永続化するあらゆるオブジェクトの基底クラス(ScriptableObject):SaveToText、LoadFromText、ResetSave
MCESavesSerializerすべての保存テキストに使われる JSON シリアライザー
GameVariables名前付き変数のストア:bool、整数、浮動小数点数、文字列
GameVariableHolderGameVariables ストアを所有する SavableObject(GlobalGameData とすべての SceneInfoAsset がホルダー)
GameVariableReferenceCommandGraph ノードが使う、1 つの変数への Inspector 参照
Migrations/ISaveMigration、SaveMigrationPipeline、SaveFormatVersions:セーブのバージョン管理

保存されるもの​

SavegameManager.SavegameObjects は、すべてのセーブに入る保存可能オブジェクトのリストです。エンジン自身のものは次のとおりです。

オブジェクト保持するもの
GlobalGameData(SavableGlobalGameData として保存)プレイヤーの位置、お金、獲得したバッジ、ゲーム変数、フォーマットのバージョン刻印、シークレットベースとプレイヤージム
Roster完全な状態を持つ手持ちのモンスター(種、レベル、個体値、努力値、性格、技、PP、HP、状態異常、なつき度…)
MonsterStorageボックスのモンスター
Bagアイテムと個数
Dex種ごとの見た/捕まえたの記録
QuestManager進行中のクエスト、達成した目標、受け取った報酬
CharacterDataプレイヤーキャラクター
TimeManager時間帯
Nursery育て屋
SceneInfoAsset各マップ固有のゲーム変数

セーブファイル​

セーブは単一のファイルではなくフォルダーです。セーブは、Unity の Application.persistentDataPath 配下の Saves/ に置かれます。

プラットフォームpersistentDataPath
Windows%USERPROFILE%/AppData/LocalLow/<CompanyName>/<ProductName>/
macOS~/Library/Application Support/<CompanyName>/<ProductName>/
Linux~/.config/unity3d/<CompanyName>/<ProductName>/
Android内部ストレージ(アプリ専用)
iOSアプリのサンドボックス
<persistentDataPath>/Saves/
2026-10-10-18-30-02/ a manual save, named with the current date
GlobalGameData.sav one .sav per savable object
Roster.sav
...
Manifest.txt the list of files a COMPLETE save must contain
Autosave/
OlderAutosave/

セーブはクラッシュに強いように書き込まれます。

  • すべてのファイルはアトミックに書き込まれます(一時ファイルに書いてから置き換え)。
  • セーブ全体はまず <name>.staging フォルダーに書き込まれ、すべてのファイルとマニフェストが書き込まれた後にだけ所定の場所に入れ替えられます。中断されたセーブが、古い状態と新しい状態の中途半端な混在を残すことはありません。
  • ロード時、マニフェストに載っているファイルが欠けていれば、セーブが中断されたことを意味するため、部分的なセーブを読み込む代わりに拒否されます。

セーブとロード​

プレイヤーはポーズメニューからセーブし(Exit エントリがセーブを提案し、メニューのセーブキーは確認のうえ、現在の日付で名前を付けたセーブを書き込みます)、メインメニューからロードします(Continue は最新のセーブを読み込み、Load はすべてを一覧表示します)。ゲームがオンライン(MCE Online)で動作しているときは、進行はサーバーが保持し、ローカルのセーブは書き込まれません。

コードからは、SavegameManager(Source・Studio エディション)を通じて行います。

// A new save named with the current date
yield return savegameManager.SaveGameWithCurrentDate(playerCharacter);

// Rotate the autosave
yield return savegameManager.Autosave(playerCharacter);

// Load by name, or the most recent one
yield return savegameManager.LoadGame(saveName);
yield return savegameManager.LoadLastSavegame();

SavegameManager.GetAllSavegames(out list) と AreThereSavegames() は、ディスク上に何があるかを教えてくれます。テスト用のセーブステート(SaveStates)は、プレイヤーのセーブの隣に専用のプレフィックスで置かれ、プレイヤーが見られるすべてのリストから隠されます。

SDK のセーブファサード

engine.SaveSystem(ISaveSystem)は、Save(slot)、Load(slot)、HasSaveData(slot)、DeleteSave(slot)、OnSaved、OnLoaded を公開していますが、現在のエンジンでは SavegameManager に接続されていません。そのセーブとロードの要求を処理するものはなく、HasSaveData は、エンジンが書き込まない slot{N}.sav ファイルを persistentDataPath で探します。本物のセーブには、SavegameManager(Source・Studio エディション)またはゲーム内メニューを使ってください。ISaveSystem を参照してください。

オートセーブ​

オプション画面の 2 つの設定(GameplayConfigurationFile に保存)が、オートセーブを制御します。

オプション保存されるタイミング
AutoSaveOnTeleportingプレイヤーが別のマップにテレポートするたび(ゲームのロード中を除く)
AutoSaveOnStoryグラフに AutoSaveIfEnabled ノードがあるストーリー上の箇所

各オートセーブは Autosave/ に入ります。以前のものは、新しいものの書き込みが成功した後にだけ OlderAutosave/ にローテーションされるため、中断されたオートセーブが最後の正常なセーブを壊すことはありません。

オートセーブのベストプラクティス
  • AutoSaveIfEnabled は、ストーリーの節目の後に置き、バトルやカットシーンの途中には決して置かないでください。
  • セーブ中は、オートセーブのインジケーターを表示してください。

セーブのバージョン管理​

セーブにはフォーマットのバージョンがあり、セーブ時に SavableGlobalGameData に書き込まれ、ロード時に SaveMigrationPipeline によって比較されて、古いセーブが必要とするマイグレーションが実行されます。

バージョン名前意味
0LegacyHashesバージョン刻印以前のセーブ:種、フォーム、特性、技、アイテムは、アセット名の実行時ハッシュで識別される
1StableNamesアセット名(安定した文字列)で識別する。現在のバージョン

フォーマットが変わるときは、新しい ISaveMigration がパイプラインに追加され、SaveFormatVersions.Current が引き上げられます。

シリアライズされたフィールド名とアセット名

マイグレーションを用意せずに、セーブ関連クラスのシリアライズされたフィールド名を変更してはいけません。また、種、技、特性、アイテムのアセット名は、セーブのキーとして扱ってください。アセットの名前を変えると、それを指すセーブが壊れます。フィールド名を変更すると、既存のセーブファイルはロード時にそのデータを失います。フィールド名の変更には [FormerlySerializedAs("oldName")] を使ってください。

GameVariables​

GameVariables システムは、MCE の永続的な名前付き値のストアです。CommandGraph ノードとスクリプトから読み書きされ、それを所有するオブジェクトとともに保存されます。

変数の型​

型説明例
Boolean真偽のフラグdefeatedBrock = true
Integer数値のカウンターfishCaught = 42
Float小数rivalTrust = 0.5
Stringテキストの値rivalName = "Gary"

すべての変数はホルダーに存在します:グローバル(GlobalGameData)、またはマップの SceneInfoAsset です。マップで定義された変数はそのマップに固有で、グローバルなものはゲーム全体で共有されます。

CommandGraph での使用​

  • SetBoolVariable、SetIntVariable:変数の値を設定します。
  • IfBool、IfIntEquals、IfIntCompare、SwitchIntVariable:変数で分岐します。

これらのノードにはそれぞれ変数参照があり、ホルダー、型、名前を選びます。

コードでの使用​

// globalGameData is the injected GlobalGameData (a GameVariableHolder);
// the class that receives it implements IPlayerDataReceiver
bool beatBrock = globalGameData.GetVariable<bool>("defeatedBrock");
int fishCount = globalGameData.GetVariable<int>("fishCaught");

globalGameData.SetVariable("defeatedBrock", true);
globalGameData.SetVariable("fishCaught", fishCount + 1);

カスタムセーブデータ​

GameVariables を使う(すべてのエディション)​

独自のフラグやカウンターをセーブとともに永続化する最も簡単な方法は、それらを GlobalGameData のゲーム変数として保存することです。ほかのすべてのものと一緒に、保存、ロード、マイグレーション、リセットされます。

SavableObject を拡張する(Source・Studio エディション)​

データ構造全体には、新しい SavableObject を書き、そのアセットを SavegameManager アセットの Savegame Objects リストに追加します。

[CreateAssetMenu(menuName = "MyGame/Custom Save Data")]
public class CustomSaveData : SavableObject
{
[Serializable] private class Data { public int counter; public List<string> unlocked; }
private Data data = new() { unlocked = new List<string>() };

public override string SaveToText(ISerializer<string> serializer, PlayerCharacter playerCharacter) =>
serializer.To(data);

public override IEnumerator LoadFromText(ISerializer<string> serializer, string data,
MCESettings mceSettings, MonsterDatabaseInstance monsterDatabase)
{
this.data = serializer.From<Data>(data);
yield break;
}

public override void ResetSave() => data = new Data { unlocked = new List<string>() };
}

これは、すべてのセーブで独自の .sav ファイルとして書き込まれ、マニフェストに載ります。ResetSave は、新しいゲームが始まるときに、クリーンな状態を与えます。

セーブファイルの形式​

すべての .sav ファイルは MCESavesSerializer が書き出すプレーンな JSON なので、デバッグ中に確認できます。正確な形は、それが属するオブジェクトによります(グローバルデータ、ロースターなどは、それぞれ独自のファイルを持ちます)。

セーブファイルを編集しない

セーブファイルは人間が読める JSON ですが、無効なデータ(たとえば、データベースに存在しない技)を入れてしまうと、手動で編集することで問題が起こりえます。代わりに、ゲーム内のツールやデバッグコマンドを使ってください。

ベストプラクティス​

  1. セーブ/ロードの往復をテストする。セーブして終了し、再ロードして、すべてが無傷であることを確認します。
  2. イベントフラグには GameVariables を使う。自動的に永続化され、CommandGraph と統合されます。
  3. セーブのマイグレーションを計画する。アップデートでフォーマットを変更する場合は、マイグレーションの手順を追加します。
  4. プレイヤーがセーブを持った後は、種、技、特性、アイテムのアセット名を変更しない。
  5. ロードの失敗を適切に処理する。破損または中断されたセーブは、部分的に読み込まれる代わりに、エラーダイアログとともに拒否されます。