最終更新日 2024-09-25

拡張セーブデータ

拡張セーブデータは、本来のセーブデータに対応する形で、
「独自のパラメータ」をセーブデータとは別のファイルにセーブデータとして保存するために
用意された機能となります。

独自ファイルへの拡張セーブデータ簡易機能

「独自のファイル」に拡張データをセーブするための簡易機能です。

この簡易機能は、別ファイル名(自分で名前を付ける)に別途拡張データをセーブするものとなります。

特に名前を変更しなかった場合は、「SAVEDAT.N6PEX」というファイルに、拡張部分のデータが格納されるようになります。

TSModのセーブデータの拡張との違い

TSModでは、セーブデータファイル(SAVEDATA.N6P)そのものに「拡張データ」を持っています。
この一部分を利用して、ScenarioModには「Get_フラグ()」や「Set_フラグ()」といった関数が提供されています。

しかし、セーブやロードと同時に、ある程度まとまった量の「独自のデータ」の保存や復元を行いたいという場合、
ScenarioModへと提供されている「フラグの機能」では、まかないないため 「各自が全て自前」でその機構を記述する必要があります。

今回はそれをある程度自動化し、短いソース記述で目的を達成する、という機能となります。

カスタム駆動関数.cpp

// 最終的にセーブしたいデータの「構造体(あるいはクラス)」を定義する。名前は自由。
// 構造体内のメンバフィールドの「型」として使えるのは「プリミティブ型」及び「ポインタ」である。
// あくまで「メモリブロック」として保存される、
// 何ビット目が0か1か、それだけが考慮対象である。
// よって一度保存した後に、「構造体のサイズ」や「フィールドの並び」を変更すると、読み込みデータが瓦解する。
// これを防止するため、下の例のように「予備領域」を事前に持っておき、「予備領域」を切り崩しながら、新たなフィールドを追加する。
//------------保--存--対--象------------------------------------------------------------------
struct my拡張構造体 {
    int a;
    char sz[12]; // string型を使うのは許されない。string型はプリミティブ型ではないので、Visual Stduioのライブラリのセットのバージョンが変わるだけで「メモリブロック上でのサイズ」が変化してしまうため。
                 // 「C++ プリミティブ型」などでググって使える「型」を検索すること。
    byte 予備[40]; // 予備データ。
};
//--------------------------------------------------------------------------------------------

// <***> (テンプレートパラメータ) の所はご自身で定義した構造体の名前を指定する。変数名は自由な名前をつければ良い。
拡張セーブデータ情報型<my拡張構造体> my拡張セーブデータ;

// この行を記述しておくと、後々変数に短い名前でアクセスできる。
// 下記の例では、「my拡張セーブデータ.拡張パラメタ」に「pex」という別名で参照できるようにしている。
auto &pex = my拡張セーブデータ.拡張パラメタ;


// 以下は「ScenaroModの既存のイベントハンドラ」に記述を足す。

void カスタム::On_トップメニュー表示時() {
    my拡張セーブデータ.Do_メモリクリア();
}

void カスタム::On_セーブデータ読込時(int スロット番号, string セーブファイル名) {
    my拡張セーブデータ.On_セーブデータ読込時(スロット番号, セーブファイル名); // 拡張データを独自のファイルからロード
}

void カスタム::On_セーブデータ保存時(int スロット番号, string セーブファイル名) {
    my拡張セーブデータ.On_セーブデータ保存時(スロット番号, セーブファイル名); // 拡張データを独自のファイルにセーブ
}

以上で準備が完了。

あとは、

void カスタム::On_軍団ターン変更《メイン画面》(int 軍団番号) {
    pex.a = 30;
    string s = "あああ";
    strcpy( pex.sz, s.c_str() ); // string型ではなく、char配列なので、strcpyを使う必要がある。
}

などと自由に使える。

これはセーブのタイミングで、セーブされ、ロードのタイミングで、読み込まれる。

拡張用のセーブデータの定義を「カスタム駆動関数.cpp」内ではなく、別ファイルにて作成する例

多くのデータ項目に拡張データを持つような場合、
例えば 「拡張セーブデータ.h」(ファイル名自由)
といったファイル名で自分で好きなように下のように定義して、

拡張セーブデータ.h
#pragma once

namespace ユーザー {

    // 武将1人分の拡張パラメタ
    struct 武将情報EX型 {
        int a;                    // 4バイトの数値
        int b;                    // 4バイトの数値
        int c;                    // 4バイトの数値
        char 渾名[15];            // 14バイト+NULLの文字列(もしくは15バイトのデータ)

        byte 予備[40];            // 40バイトを保持。将来データを増やした時に、ここから削って増やす。合計のバイト数をかならずぴったり合わせる。
    };

    // 大名家1つ分の拡張パラメタ
    struct 大名情報EX型 {
        int a;                    // 4バイトの数値
        int b;                    // 4バイトの数値
        byte 予備[20];            // 予備として20バイトを保持。将来データを増やした時に、ここから削って増やす。合計のバイト数をかならずぴったり合わせる。
    };

    // 軍団1つ分の拡張パラメタ
    struct 軍団情報EX型 {
        int a;                    // 4バイトの数値
        int b;                    // 4バイトの数値
        byte 予備[20];            // 予備として20バイトを保持。将来データを増やした時に、ここから削って増やす。合計のバイト数をかならずぴったり合わせる。
    };

    // 城1つ分の拡張パラメタ
    struct 城情報EX型 {
        int a;                    // 4バイトの数値
        int b;                    // 4バイトの数値
        byte 予備[20];            // 予備として20バイトを保持。将来データを増やした時に、ここから削って増やす。合計のバイト数をかならずぴったり合わせる。
    };

    // 家宝1つ分の拡張パラメタ
    struct 家宝情報EX型 {
        int a;                    // 4バイトの数値
        int b;                    // 4バイトの数値
        byte 予備[20];            // 予備として20バイトを保持。将来データを増やした時に、ここから削って増やす。合計のバイト数をかならずぴったり合わせる。
    };

    // 官位1つ分の拡張パラメタ
    struct 官位情報EX型 {
        int a;                    // 4バイトの数値
        int b;                    // 4バイトの数値
        byte 予備[20];            // 予備として20バイトを保持。将来データを増やした時に、ここから削って増やす。合計のバイト数をかならずぴったり合わせる。
    };

    struct 予備情報EX型 {
        int 予備[100];            // 予備として100バイトを保持。将来データを増やした時に、ここから削って増やす。合計のバイト数をかならずぴったり合わせる。
    };

    // 1つのセーブスロットに対応する拡張データ
    struct 自分の拡張セーブデータ型 {
        武将情報EX型 p武将情報[最大数::武将情報::配列数];   // 武将の拡張データ。p武将情報の配列と同じ番号で良い。
        大名情報EX型 p大名情報[最大数::大名情報::配列数];   // 大名の拡張データ。p大名情報の配列と同じ番号で良い。
        軍団情報EX型 p軍団情報[最大数::軍団情報::配列数];   // 軍団の拡張データ。p軍団情報の配列と同じ番号で良い。
        城情報EX型   p城情報[最大数::城情報::配列数];       // 城の拡張データ。p城情報の配列と同じ番号で良い。
        家宝情報EX型 p家宝情報[最大数::家宝情報::配列数];   // 家宝の拡張データ。p家宝情報の配列と同じ番号で良い。
        官位情報EX型 p官位情報[最大数::官位情報::配列数];   // 官位の拡張データ。p官位情報の配列と同じ番号で良い。
        予備情報EX型 p汎用情報;                             // これら以外の何か汎用のデータ。
    };
}

といったファイル名で保存し、 カスタム駆動関数.cpp

#include "拡張セーブデータ.h"

拡張セーブデータ情報型<ユーザー::自分の拡張セーブデータ型> my拡張セーブデータ;

auto &pex = my拡張セーブデータ.拡張パラメタ;

// 後は、同じ

といった感じにすれば良いだろう。

あとは、短い名前として用意した「pex」で値に自由にアクセス出来る。

void カスタム::On_相場変更直前() {
    int iBushouID = Get_武将番号【配列用】(顔番号::武田晴信); // 武田信玄
    if ( 0<=iBushouID && iBushouID < 最大数::武将情報::配列数) {
        デバッグ出力 << pex.p武将情報[iBushouID].渾名 << endl;
    }
}

より詳細を知るには...

「拡張セーブデータ」に関する主な所は以上となります。 詳しくは「拡張セーブデータ情報型.h」などを参照してください。