この記事でのバージョン
Unity 2018.4.6f1
はじめに
UnityではAssetDatabaseのCreateAssetを使うことで、アセットを簡単に生成する事が出来ます。
//ScriptableObjectChildというScriptableObjectを作成 var child = ScriptableObject.CreateInstance<ScriptableObjectChild> (); //ScriptableObjectをアセットとして生成 string exportPath = "Assets/ScriptableObjects/Chid.asset"; AssetDatabase.CreateAsset(child, exportPath); Debug.Log(exportPath + "生成");
このCreateAsset、もし生成先に既にアセットがある場合は上書きで保存するのですが、
その際に当然ですがmetaファイルも上書きされます。
基本的にはそれで問題ないのですが、以下のようにどこかで参照されているものを上書きしてしまうと
参照がなくなってMissingと表示されるようになってしまいます。
///ScriptableObjectChildを参照しているScriptableObject public class ScriptableObjectParent : ScriptableObject { [SerializeField] private ScriptableObjectChild _child = null; }
参照を維持したままファイルを更新したい場合は、metaファイルをそのままにすればいいのですが、
残念ならがらUnityにはそういう機能がないようです。(もしある場合はご一報頂けると幸いです……!)
という事で今回は
ScriptableObjectなどをmetaファイルを変更せずに上書きする処理を作ってみました!
CreateAssetWithOverwrite
さっそくScriptableObjectなどをmetaファイルを変更せずに上書きする処理である
CreateAssetWithOverwrite (を実装しているAssetDatabaseExtension)のプログラムです。
ちなみに、UNITY_EDITORで囲っているので、Editorディレクトリ内でなくても使えます。
#if UNITY_EDITOR using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; using UnityEditor; /// <summary> /// AssetDatabaseの拡張クラス /// </summary> public static class AssetDatabaseExtension{ /// <summary> /// アセットを上書きで作成する(metaデータはそのまま) /// </summary> public static void CreateAssetWithOverwrite(UnityEngine.Object asset, string exportPath){ //アセットが存在しない場合はそのまま作成(metaファイルも新規作成) if (!File.Exists(exportPath)) { AssetDatabase.CreateAsset(asset, exportPath); return; } //仮ファイルを作るためのディレクトリを作成 var fileName = Path.GetFileName(exportPath); var tmpDirectoryPath = Path.Combine(exportPath.Replace(fileName, ""), "tmpDirectory"); Directory.CreateDirectory(tmpDirectoryPath); //仮ファイルを保存 var tmpFilePath = Path.Combine(tmpDirectoryPath, fileName); AssetDatabase.CreateAsset(asset, tmpFilePath); //仮ファイルを既存のファイルに上書き(metaデータはそのまま) FileUtil.ReplaceFile(tmpFilePath, exportPath); //仮ディレクトリとファイルを削除 AssetDatabase.DeleteAsset (tmpDirectoryPath); //データ変更をUnityに伝えるためインポートしなおし AssetDatabase.ImportAsset (exportPath); } } #endif
実装内容は至ってシンプルで、実際に上書きするファイルの階層に仮ディレクトリを作成し、
さらにそのディレクトリの中に仮ファイルを作成、そして、そのファイルだけを上書きするというもの。
使い方も簡単で、AssetDatabase.CreateAssetを
AssetDatabaseExtension.CreateAssetWithOverwriteに置き換えるだけ。
//ScriptableObjectChildというScriptableObjectを作成 var child = ScriptableObject.CreateInstance<ScriptableObjectChild> (); string exportPath = "Assets/ScriptableObjects/Chid.asset"; //ScriptableObjectをアセットとして上書きで生成 AssetDatabaseExtension.CreateAssetWithOverwrite(child, exportPath); Debug.Log(exportPath + "生成");
ちなみに別名で仮ファイルを作り、それを置き換えるという方法もありますが、
//一旦別名で保存 string extension = Path.GetExtension(exportPath); string copyPath = exportPath.Replace(extension, "") + "_Copy" + extension; AssetDatabase.CreateAsset(asset, copyPath); //別名で保存したやつを既存のファイルに上書き(metaデータはそのまま) FileUtil.ReplaceFile (copyPath, exportPath); AssetDatabase.DeleteAsset (copyPath);//別名ファイルを削除 //データ変更のUnityに伝えるためインポートしなおし AssetDatabase.ImportAsset (exportPath);
これだと、なぜか上書き後のアセットのm_nameという値が別名の状態になるので、
(実際のアセット名は元アセットと同じ)
仮ディレクトリを作って、その下に同名ファイルを作るという方式にしています