Packagesフォルダのreadonlyなprefabのvariantを作る

2022/08/15に公開

はじめに

Unityでprefab variantを作るときは元のprefabと同じフォルダにしか作れないせいかPackagesフォルダにあるreadonlyなprefabからvariantを作れません。
prefabの右クリックメニューを開いても以下のように作成が無効になっています。

右クリックメニュー

そのため他のフォルダにprefab variantを作るエディタ拡張を作りました。

ソース

以下のソースをEditorフォルダに入れるとメニューが追加されてウインドウを開けます。
https://gist.github.com/shiena/1c79fc1d1ad26274e41294809ad199b8

メニュー
メニュー

ウインドウ
ウインドウ

使い方

  1. Source Prefabにprefabを設定するとボタンが表示されます。
  2. Create Variantボタンを押してファイル保存ダイアログで保存ボタンを押すとprefab variantが作られます。

ウインドウ

技術的な解説

エディタ拡張を作るにあたって調べた事、はまった事を解説します。

シーン更新を抑制

PrefabUtility.InstantiatePrefabを呼ぶとアクティブなシーンにインスタンス化されたprefabが追加されてしまうのですが、AssetDatabase.StartAssetEditingでアセットインポート抑制中にDestroyImmediateも合わせて呼ぶ事でシーンの更新を防ぎます。
また、try-finallyでAssetDatabase.StopAssetEditingを呼んで解除忘れを防ぎます。

Prefab Variant作成

PrefabUtility.SaveAsPrefabAssetAndConnectの第1引数はインスタンス化されたGameObjectなので一旦PrefabUtility.InstantiatePrefabでインスタンス化します。
また、保存中はAssetDatabase.StartAssetEditingでアセットインポートが抑制されているのでAssetDatabase.StopAssetEditingの後にAssetDatabase.LoadMainAssetAtPathでアセットをロードします。

PrefabアセットのGameObject取得

PrefabUtility.GetCorrespondingObjectFromSourceでPackagesフォルダのprefabを取得しても何故かnullが返ってくるためPrefabUtility.GetCorrespondingObjectFromOriginalSourceも合わせて使っています。

PrefabUtility.IsPartOfPrefabAssetEditorGUILayout.ObjectFieldの返り値がPrefabアセットである事を確認しています。
PrefabUtility.GetCorrespondingObjectFromSourceはPrefab Variantの親Prefabを返し、PrefabUtility.GetCorrespondingObjectFromOriginalSourceは多重Prefab Variantの大元のPrefabを返すものでした。

参考サイト

https://www.docswell.com/s/UnityJapan/5PRVQK-unityprefab#p81
https://light11.hatenadiary.com/entry/2019/01/21/232729

Discussion