📘

[Unity]MessagePackをjsonで読み書きするEditorWindow対応をしました

2023/10/02に公開

はじめに

デバッグ用にPlayerPrefsにデータを格納していたのをMessagePackに変更しました。

MessagePackについてはこちらを使用させていただいています。

はじめはPlayerPrefsにjson形式でデータを格納しており表示や編集がしやすかったのですが、バイナリファイルとして保存することになったため確認ができない状態でした。
そこで簡易的に表示・編集をするようなものを作ろうと思いました。

環境

Unity 2022.3.5f1
MessagePack-CSharp 2.4.35

確認用に作成したクラス

Userクラス

[MessagePackObject]
public sealed class User
{
    [Key(0)]
    public string Name { get; set; }
    [Key(1)]
    public int Level { get; set; }
}

UserQuestクラス

[MessagePackObject]
public sealed class UserQuest
{
    [Key(0)]
    public Dictionary<int, Dictionary<int, List<int>>> ClearQuestMap { get; set; }
}

データ

こんな感じで入れてみます。

var user = new User();
user.Name = "hoge";
user.Level = 1;
var bytes = MessagePackSerializer.Serialize(user);
File.WriteAllBytes($"{Application.dataPath}/UserData.bin", bytes);

var userQuest = new UserQuest();
userQuest.ClearQuestMap = new Dictionary<int, Dictionary<int, List<int>>>();
userQuest.ClearQuestMap.Add(1, new Dictionary<int, List<int>>());
userQuest.ClearQuestMap[1].Add(1, new List<int>());
userQuest.ClearQuestMap[1][1].Add(1);
userQuest.ClearQuestMap[1][1].Add(2);
userQuest.ClearQuestMap[1][1].Add(3);
var questBytes = MessagePackSerializer.Serialize(userQuest);
File.WriteAllBytes($"{Application.dataPath}/UserQuest.bin", questBytes);

EditorWindowのコード

UnityのメニューバーのTools => Save File Editでファイルを開くウィンドウを出すようにしてあります。
Saveボタンを押すとファイルを保存します。

public sealed class SaveFileEditorWindow : EditorWindow
{
    string _filePath;
    string _json;
    Vector2 _scroll;

    [MenuItem("Tools/Save File Edit")]
    static void Init()
    {
        var filePath = EditorUtility.OpenFilePanel("Select SaveFile", Application.dataPath, "bin");
        if (string.IsNullOrEmpty(filePath)) return; // Not selected File

        var result = MessagePackSerializer.Deserialize<dynamic>(File.ReadAllBytes(filePath));
        var json = MessagePackSerializer.SerializeToJson(result);

        var self = (SaveFileEditorWindow)GetWindow(
            typeof(SaveFileEditorWindow),
            false,
            Path.GetFileName(filePath),
            true
        );
        self._json = json;
        self._filePath = filePath;
        self.Show();
    }

    void OnGUI()
    {
        _scroll = EditorGUILayout.BeginScrollView(_scroll, GUILayout.Height(500));
        _json = EditorGUILayout.TextArea(_json, GUILayout.ExpandHeight(true));
        EditorGUILayout.EndScrollView();

        using (new GUILayout.HorizontalScope()) {
            GUILayout.FlexibleSpace();

            if (GUILayout.Button("Save", EditorStyles.miniButton)) {
                File.WriteAllBytes(_filePath, MessagePackSerializer.ConvertFromJson(_json));
                Close();
            }
        }
    }
}

表示

UserData.bin

UserQuest.bin

まとめ

MessagePackSerializerのjson対応のコードを使うことで簡単に対応できました。
jsonとMessagePackで変換するときの型はbyte[]などは問題ありそうですが、今回使いそうなのは数値・文字列・Dictionary・List・Arrayくらいだったので問題なさそうです。

またこのバイナリファイルはこのクラスに対応したものだから、このクラスでDeserializeしないといけないみたいな紐付けする部分が大変かもと思ってたのですが、dynamicが使えたことで解決しました。
il2cppでは使えないのですが、Editorでの動作用なので問題ありませんでした。

Happy Elements

Discussion