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

そのため他のフォルダにprefab variantを作るエディタ拡張を作りました。
ソース
以下のソースをEditorフォルダに入れるとメニューが追加されてウインドウを開けます。
メニュー

ウインドウ

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

技術的な解説
エディタ拡張を作るにあたって調べた事、はまった事を解説します。
シーン更新を抑制
- AssetDatabase.StartAssetEditing
- AssetDatabase.StopAssetEditing
- PrefabUtility.InstantiatePrefab
- DestroyImmediate
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.GetCorrespondingObjectFromSourcePrefabUtility.GetCorrespondingObjectFromOriginalSource
PrefabUtility.GetCorrespondingObjectFromSourceでPackagesフォルダのprefabを取得しても何故かnullが返ってくるためPrefabUtility.GetCorrespondingObjectFromOriginalSourceも合わせて使っています。
PrefabUtility.IsPartOfPrefabAssetでEditorGUILayout.ObjectFieldの返り値がPrefabアセットである事を確認しています。
PrefabUtility.GetCorrespondingObjectFromSourceはPrefab Variantの親Prefabを返し、PrefabUtility.GetCorrespondingObjectFromOriginalSourceは多重Prefab Variantの大元のPrefabを返すものでした。
参考サイト
Discussion