はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】Unity 2023.1.0f1よりAssetDatabase.StartAssetEditing/StopAssetEditingをより安全に実行できるようにしたAssetEditingScopeが実装された

はじめに

AssetDatabaseはアセットの作成・削除・移動・コピーなどの操作をすることができます。特に大量のアセットに大して操作を行ったりすると、なかなか処理が終わらずにパフォーマンス上の問題がでてきたりします。
docs.unity3d.com

そこでAssetDatabase.StartAssetEditingAssetDatabase.StopAssetEditingを用いることで、複数のアセット操作を一度の処理で行うように指示することができます。

docs.unity3d.com

また今回はそれらをより安全に活用できるようにしたAssetEditingScopeについて紹介したいと思います。

StartAssetEditingとStopAssetEditingについて

StartAssetEditing()を呼び出すと、一時的にAssetDataabaseの操作が行われなくなります。そしてStopAssetEditingを呼び出すことでStartAssetEditingStopAssetEditingの間に行った変更をバッチ処理します。デフォルトでは各変更を順番に処理して毎回アセットの完全な更新処理を実行するのに対し、一連の操作を最後に一度だけ処理を行うようにすることで処理時間を大きく削減できるというわけです。

try
{
    AssetDatabase.StartAssetEditing();
    AssetDatabase.CopyAsset("Assets/SourceFolder/MyTexture.png", "Assets/DestinationFolder/MyTexture_copy.png");
    AssetDatabase.MoveAsset("Assets/SourceFolder/MyMaterial.mat", "Assets/DestinationFolder/MyMaterial_moved.mat");
}
finally
{
    AssetDatabase.StopAssetEditing();
}

またネストされている場合には、内部にカウンターを持っているのでStartAssetEditing()を実行した回数だけStopAssetEditing()を呼ぶ必要があります。

AssetDatabase.StartAssetEditing(); // Counter = 1
//... アセット操作...

AssetDatabase.StartAssetEditing(); // Counter = 2
//... アセット操作...

AssetDatabase.StopAssetEditing();  // Counter = 1 (まだインポートは再開されない)
//... アセット操作...

AssetDatabase.StopAssetEditing();  // Counter = 0 (ここでインポートが再開される)

ちなみにStopAssetEditingStartAssetEditing以上に呼び出してしまうと、以下のようなエラーがでてきます。

Assertion failed on expression: 'gRefreshReentrancyCount > 0'
StopAssetEditing invoked without a call to StartAssetEditing. Please make sure that for every call to StopAssetEditing there is at least one call to StartAssetEditing

AssetEditingScopeについて

IDisposableを実装して、usingを用いることでStartAssetEditingStopAssetEditingを確実に行えるようにしたAssetEditingScopeがUnity 2023.1.0f1より登場しました。
github.com

2023.1.0f1
Added: Added AssetDatabase.AssetEditingScope().

Unity Release Notes (Alpha) - Search

using (var editingScope = new AssetDatabase.AssetEditingScope())
{
    AssetDatabase.CopyAsset("Assets/CopyAsset.txt", "Assets/Text/CopyAsset.txt");
    AssetDatabase.MoveAsset("Assets/MoveAsset.txt", "Assets/Text/MoveAsset.txt");
}

AssetEditingScope - Unity スクリプトリファレンス

安全性とコードの明瞭性の観点から可能な限りAssetDatabase.AssetEditingScopeを使用して、StartAssetEditing/StopAssetEditingを直接使用する場合は、try...finallyを必ず利用するようにすると良いでしょう。