【Unity】【エディタ】EditorBuildSettingsのConfigObjectでプロジェクト毎のエディタ設定を保存する

UnityでConfigObjectでプロジェクト毎のエディタ設定を保存する方法です。

Unity2020.1.10

ConfigObject?

ConfigObjectはエディタで使う任意のアセットを任意のキーで保存しておける機能です。
アセットパスやGUIDを使わずに任意のキーで保存・読み込みが行えるため、
ライブラリの設定ファイルなど、ライブラリのユーザが任意で作成するようなファイルを管理するのに有用です。

// AssetDatabaseだとアセットパスやGUIDが既知でないと読み込めない
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
var instance = AssetDatabase.LoadAssetAtPath<ScriptableObject>(assetPath);

// ConfigObjectは任意の名前で読み込める
EditorBuildSettings.TryGetConfigObject("key", out ScriptableObject instance)

ConfigObjectの使い方

アセットをConfigObjectとして登録するにはEditorBuildSettings.AddConfigObject()を使います。
第一引数に名前を、第二引数にアセットを渡して登録します。

// 第二引数のアセットを第一引数の名前で保存する
FooObj instance;
EditorBuildSettings.AddConfigObject("com.harumak.example", instance, true);

ConfigObjectは主にpackageで使うことを想定されていますが、
他パッケージとの競合を防ぐために名前には上記のようにパッケージ名を含めることが推奨されています。

登録したアセットを取得するにはEditorBuildSettings.TryGetConfigObject()を使います。

if (EditorBuildSettings.TryGetConfigObject("com.harumak.example", out FooObj instance))
{
}

他には削除用のAPIとすべてのConfigObjectの名前を取得するAPIが用意されています。

// 削除
EditorBuildSettings.RemoveConfigObject("com.harumak.example");

// 名前をすべて取得
var names = EditorBuildSettings.GetConfigObjectNames();

保存場所と共有範囲について

ConfigObjectの情報はEditorBuildSettings、つまりProjectSettings/EditorBuildSettings.assetに保存されます。
これはバージョン管理ツールで管理する対象のファイルであるため、
ConfigObjectの設定は同じプロジェクトを共有するユーザ間で共有されます。

ユーザごとの設定値や複数バージョンのUnityエディタで共有するPreference値には向かないので注意してください。

使用例

最後に具体的な仕様例を載せて終わります。

#if UNITY_EDITOR
using System;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;

public class FooEditorConfig : ScriptableObject
{
    private const string ConfigName = "com.harumak.fooeditorconfig";

    public static FooEditorConfig Instance
    {
        get
        {
            if (EditorBuildSettings.TryGetConfigObject(ConfigName, out FooEditorConfig instance))
            {
                return instance;
            }
            
            // ConfigObjectに登録されていないあるいは登録されているアセットが無い場合はデフォルトのものを作って返す
            return CreateInstance<FooEditorConfig>();
        }
    }

    [MenuItem("Assets/Create/FooEditorConfig")]
    private static void Create()
    {
        // 既に存在していたらエラー
        var guids = AssetDatabase.FindAssets($"{nameof(FooEditorConfig)} t:ScriptableObject");
        if (guids.Length >= 1)
        {
            var path = AssetDatabase.GUIDToAssetPath(guids.First());
            throw new InvalidOperationException($"{nameof(FooEditorConfig)} already exists in {path}.");
        }

        var assetPath = EditorUtility.SaveFilePanelInProject($"Save {nameof(FooEditorConfig)}", nameof(FooEditorConfig),
            "asset", "", "Assets");

        if (string.IsNullOrEmpty(assetPath))
        {
            // キャンセルボタン押下
            return;
        }

        // フォルダがなかったら作る
        var folderPath = Path.GetDirectoryName(assetPath);
        if (!string.IsNullOrEmpty(folderPath) && !Directory.Exists(folderPath))
        {
            Directory.CreateDirectory(folderPath);
        }

        // アセットを作成してConfigObjectに設定
        var instance = CreateInstance<FooEditorConfig>();
        AssetDatabase.CreateAsset(instance, assetPath);
        EditorBuildSettings.AddConfigObject(ConfigName, instance, true);
        AssetDatabase.SaveAssets();
    }
}
#endif

参考

docs.unity3d.com