[unity]ゲームデータのセーブ・ロード(バイナリ形式)

前回の記事JSON 形式の簡単なセーブ・ロードクラスを公開しましたが、凝ったゲームでは以下の問題が出てくるかもしれません。

  • Dictionary も使えるようにしたい
  • JSON 形式だと、ユーザーにもデータがまる見えなので、なんとかしたい
  • ユーザーがデータを改変した場合、検知できるようにしたい

これらも可能なセーブロードクラスを紹介します。
使い勝手はほとんど jsonSaveLoad と同じです。

ダウンロード(リポジトリ)

使い方

今回も SampleScene.unity にて確認できます。
厳密なエラー情報を返せるようにしたため、jsonSaveLoad とは多少引数が異なります。

保存するクラスについて

クラスは Serializable 属性をつける必要があります。
JSON 形式とは違い、Dictionary をメンバに含めることも可能です。

[System.Serializable]
public class TestData
{
    public int      ID;
    public string   Message;
    public Dictionary<string, int> StageCounter;
}

リファレンス

binarySaveLoad.Save(string filename, object data)

クラスの中身をファイルに保存します。

filename .. ファイル名
data .. 保存したいクラス(のインスタンス)
戻り値 .. eResult.Success(成功)、それ以外はエラー

[System.Serializable]
public class TestData
{
    public int      ID;
    public string   Message;
}

TestData savedata = new TestData()
{
    ID = 10,
    Message = "TestData",
};

binarySaveLoad.Save("savedata", savedata);

binarySaveLoad.Load<T>(string filename, out T data)

指定したファイルからクラスデータを取得します。

filename .. ファイル名
data .. 任意のセーブデータクラスを指定
戻り値 .. eResult.Success(成功)、それ以外はエラー

binarySaveLoad.Load("savedata", out loaddata);

string text =
    $"ID = {loaddata.ID}{Environment.NewLine}" +
    $"Message = '{loaddata.Message}'{Environment.NewLine}";

binarySaveLoad.Delete(string filename)

保存したファイルを削除します。

filename .. ファイル名

binarySaveLoad.Delete("savedata");

binarySaveLoad.IsZipArchive

true にすると、セーブデータを ZIP 圧縮します。
(セーブデータが大きくなりすぎるようであれば、使ってもいいかも)

binarySaveLoad.IsZipArchive = true;

binarySaveLoad.IsSimpleEncryption

true にすると、セーブデータを暗号化します。
暗号化ロジックについては、テスト用の簡単なものだけです。
より複雑な暗号化が必要であれば、次に紹介するユーザーメソッドの自作をオススメします。

binarySaveLoad.IsSimpleEncryption = true;

binarySaveLoad.UserEncrypt(byte[] data)
binarySaveLoad.UserDecrypt(byte[] data)

暗号化・複合化ルールを自分で定義することができます。
あまり重い処理にするとセーブ・ロードの時間にも影響するので、程ほどに。

binarySaveLoad.UserEncrypt = (data) => { for (int i = 0; i < data.Length; i++) data[i] += i % 256; };
binarySaveLoad.UserDecrypt = (data) => { for (int i = 0; i < data.Length; i++) data[i] -= i % 256; };

技術解説

今回はバイナリ形式のため、パッと見でデータを解析・変更することが困難です。

もちろん、どんなに複雑なデータ形式にしても解析不可能にはなりませんが、「これは解析する気が起こらないな…」とウンザリさせるだけでも、大きな効果が期待できます。

例:JSON 形式(わかりやすく、素人でも改変可能)

{"ID":10,"Message":"TestData","Flag":true,"Test":1,"Stage":[1,2,3,4,5]}

例:バイナリ形式(素人はまず手を出せない)

変換には BinaryFormatter Serialized メソッドを使っています。

また、バイナリファイルの内容から4バイトのチェックサムを作成し、内部に保持しておきます。
こうすることで、例えバイナリを解析し、特定の値を変更(チート)したとしても「チェックサムと合わないからこのデータはおかしい」と判定され、読み込みに失敗します。

チェックサムが合わない理由として、セーブが不完全だった場合もあり得ます。
チートとは限らない事に注意してください。

バイナリ形式+チェックサムでほとんどの人がチート解析を諦めると思いますが、ZIP 圧縮暗号化で更に解析を困難にすることも可能です。

バイナリのデメリットとしては、ファイルの保存サイズが大きくなる事です。
が、余程巨大なクラスでなければパフォーマンスの差は出ないと思います(たぶん)。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA