はじめに
Unityのリソースをディレクトリごと複製することはよくあることだと思います。
例えばスキルのカットインや、イベントをフォルダごと複製することがあるかと思います。
フォルダの中にプレファブや画像、アニメーションなどのリソースが入っていて参照をフォルダの中で完結させて、複製した後は画像の差し替えだけで終わらせたいです。
しかし、普通に複製しただけだと複製されたディレクトリ内にあるプレファブが持つ参照はオリジナルのディレクトリ内のファイルになってしまいます。
ですので、複製した際は手動で参照を変更するという面倒な作業が必要になります。
参照が少ない場合でしたら問題ないですが、大量にある場合は骨が折れる作業になります。
そこで私は複製と参照を切り替えるためのパッケージを作成しました。
OpenUPMにも登録しています。
インストール方法
Unity2022.2以上のバージョンに対応しています。
PackageManager
GitHubから直接インストール
Window/Package Managerを開き、add package from git URL...で以下を入力して追加してください。
https://github.com/k-okawa/DirectoryDuplicator.git?path=Assets/Bg/DirectoryDuplicator
OpenUPMでインストール
OpenUPM-CLIを事前にインストールする必要があります。
インストール後に対象のプロジェクトのルートディレクトリ(Assetsディレクトリの上の階層)で以下のコマンドを実行します。
openupm add com.bg.directoryduplicator
UnityPackageを展開してインストール
昔ながらの方法ですが、コードに変更を加えたい場合はこちらのほうが便利です。
こちらからダウンロード可能です。
使い方
使い方はシンプルです。
複製したいディレクトリを選択して、右クリックで表示されるメニューのBg/DuplicateDirectoryWithDependenciesを実行すれば終了です。
ユーティリティ関数
こちらの複製機能を自前のエディタ拡張に組み込みたい場合などにご利用ください。
/// <summary>
/// ディレクトリを複製し、対象ディレクトリ内のファイル参照も複製先のディレクトリに移す
/// </summary>
/// <param name="originDirectory">コピー対象ディレクトリ絶対パス</param>
/// <param name="targetDirectory">コピー先のディレクトリ絶対パス</param>
/// <param name="copyExcludeDirectories">コピー対象ディレクトリ内で複製の対象に入れないサブディレクトリを指定</param>
/// <param name="progressCallback">処理進行時に呼ばれるコールバック。戻り値はファイル数の合計と処理済みファイル数</param>
public static Task CopyDirectoryWithDependencies(string originDirectory, string targetDirectory, string[] copyExcludeDirectories = null, Action<(int progress, int total)> progressCallback = null);
/// <summary>
/// ディレクトリを複製する(サブディレクトリも含め)
/// </summary>
/// <param name="originDirectory">コピー対象ディレクトリ絶対パス</param>
/// <param name="targetDirectory">コピー先のディレクトリ絶対パス</param>
/// <param name="copyExcludeDirectories">コピー対象ディレクトリ内で複製の対象に入れないサブディレクトリを指定</param>
public static void CopyDirectory(string originDirectory, string targetDirectory, string[] copyExcludeDirectories = null);
/// <summary>
/// 二つのディレクトリを比較して参照を変更する
/// </summary>
/// <param name="originDirectory">コピー対象ディレクトリ絶対パス</param>
/// <param name="targetDirectory">コピー先のディレクトリ絶対パス</param>
/// <param name="progressCallback">処理進行時に呼ばれるコールバック。戻り値はファイル数の合計と処理済みファイル数</param>
public static Task ChangeGuidToNewFile(string originDirectory, string targetDirectory, Action<(int progress, int total)> progressCallback = null);
仕組み
UnityのAssetはmetaファイルが生成されてそれぞれ固有のguidを持っています。
また、アニメーションやプレファブ、マテリアルなどのリソースはYAML形式のファイルで表現されていて、その中でguidを指定されています。
つまり、YAML内のguidをすべて差し替えれば参照を変更することが可能です。
始めに通常の複製をし、オリジナルディレクトリ内のguidとコピー先のディレクトリ内のguidを比較できるマップを作成し、オリジナルディレクトリ内のguidと一致するものはコピー先のguidに置き換えています。
サポートされるファイル
基本的にYaml形式のファイルであればどのファイルでも対象になりますが、処理の都合上拡張子を指定する必要があります。
現段階でサポートされている拡張子は以下です。
anim, controller, overrideContoroller, prefab, mat, material, playable, asset, unity
もし不足している拡張子があれば、こちらに追記お願いします。
また可能であればissueとプルリクエストを頂ければ幸いです。
外部ライブラリ
YAMLを解析するためにYamlDotNet for Unityをパッケージ内に含ませています。
名前空間を変更しているので、もし既存のプロジェクトにこちらのライブラリを使用している場合でもコンフリクトは起きないはずです。
最後に
機能が一つだけのかなりシンプルなパッケージですが、結構役に立つと思います。
複製する際にファイルを直接編集しているので、もしファイル破損が起きたとしても責任はとれないので、ご利用の際は自己責任でお願いします。