3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Unity】指定したアセットだけを保存する方法【AssetDatabase.SaveAssetIfDirty】

Last updated at Posted at 2021-12-13

はじめに

EditorUtility.SetDirty() してあるアセットは AssetDatabase.SaveAssets() によって一括で保存することができますが、エディタ拡張を作ってると「このアセット1つだけ保存したい!」という場面はけっこうあると思います。

これを実現するやり方は個人的に3年くらい前から探してたのですが、最近になってようやくやり方がわかったのでご紹介します。

  • Unity2020.3.16以降のやり方:
    • AssetDatabase.SaveAssetIfDirty() を使う
  • それ以前のUnityでのやり方:
    • AssetModificationProcessor.OnWillSaveAssets(string[]) で頑張る

の2種類があります。

Unity2020.3.16以降のやり方

AssetDatabase.SaveAssetIfDirty を使います。

以下はリファレンスからの引用です。

Description
Writes all unsaved changes to the specified asset to disk.

This function is similar to SaveAssets, and likewise should not be called during serialization.

It does not invoke AssetModificationProcessor.OnWillSaveAssets, as the asset is directly specified.

DeepL翻訳:

指定されたアセットに対する保存されていないすべての変更をディスクに書き込みます。

この関数は、SaveAssets に似ており、同様にシリアライズ中に呼び出されるべきではありません。

アセットが直接指定されているので、AssetModificationProcessor.OnWillSaveAssets は呼び出されません。

以下の2種類のオーバーロードがあります。

  • public static void SaveAssetIfDirty(Object obj);
  • public static void SaveAssetIfDirty(GUID guid);

余談ですが GUID っていう構造体があることを今回初めて知りました。

それ以前のUnityでのやり方

AssetModificationProcessor.OnWillSaveAssets(string[]) を使用します。

以下のようなヘルパークラスを作ると便利です。

AssetDatabaseHelper.cs
#if UNITY_EDITOR
using System.Linq;
using UnityEditor;
using UnityEngine;

public static class AssetDatabaseHelper
{
    private static string _pathToSave;

    public static void SaveAssetIfDirty(Object obj)
    {
        _pathToSave = AssetDatabase.GetAssetPath(obj);
        AssetDatabase.SaveAssets();
        _pathToSave = null;
    }

    public static void SaveAssetIfDirty(GUID guid)
    {
        _pathToSave = AssetDatabase.GUIDToAssetPath(guid);
        AssetDatabase.SaveAssets();
        _pathToSave = null;
    }

    private class AssetModificationProcessor : UnityEditor.AssetModificationProcessor
    {
        private static readonly string[] _pathsToSave = new string[1];

        // 指定したアセットだけ保存する
        static string[] OnWillSaveAssets(string[] paths)
        {
            _pathsToSave[0] = null;

            if (paths.Length == 0) return paths;
            if (_pathToSave == null) return paths;

            if (paths.Contains(_pathToSave) == false)
            {
                // NOTE: 空の配列を返す
                return _pathsToSave;
            }

            _pathsToSave[0] = _pathToSave;
            return _pathsToSave;
        }
    }
}
#endif

動作原理としては

  • OnWillSaveAssets(string[] paths) に保存しようとしているアセットのパスが渡ってくる
  • 保存したいアセットのパスだけを返すことで保存するアセットをフィルタする

みたいな感じです。

AssetDatabaseHelper 以外からの保存には影響を与えないようにするため、保存し終わったら何もしない状態に戻しておきます。

 
AssetModificationProcessor.OnWillSaveAssets(string[]) についてはUnity2019くらいから SaveAssetsProcessor を継承する形から UnityEditor.AssetModificationProcessor を継承する形に変わったみたいですが、機能自体は変わってなさそうなので比較的古いUnityでも実現できそうです。

あとがき

今回の AssetDatabase.SaveAssetIfDirty() は「こういうAPIほしいんだよな〜」となんとなくタイプしたら出てきた補完一覧から知ったので、ほしいAPIがある場合はたまにそういうことをするといつの間にか実装されてたりするのでおすすめです。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?