diff --git a/Packages/nadena.dev.modular-avatar/Editor/Menu/AddOutfitMenu.cs b/Packages/nadena.dev.modular-avatar/Editor/Menu/AddOutfitMenu.cs new file mode 100644 index 00000000..fba7a952 --- /dev/null +++ b/Packages/nadena.dev.modular-avatar/Editor/Menu/AddOutfitMenu.cs @@ -0,0 +1,70 @@ +using nadena.dev.modular_avatar.core; +using nadena.dev.modular_avatar.core.editor; +using UnityEditor; +using UnityEngine; +using VRC.SDK3.Avatars.Components; + +namespace nadena.dev.modular_avatar.core.editor +{ + internal static class AddOutfitMenu + { + private static readonly GameObject PREFAB_OUTFIT_MENU = + Util.LoadAssetByGuid("2097228906bdff44fb40a3d9f39cf599"); + + private static readonly string PATH_OUTFIT_MENU = AssetDatabase.GetAssetPath(PREFAB_OUTFIT_MENU); + + [MenuItem("GameObject/ModularAvatar/Add outfit menu", false, 49)] + internal static void CommandAddOutfitMenu(MenuCommand menuCommand) + { + if (!(menuCommand.context is GameObject gameObj)) return; + var avatar = gameObj.GetComponent(); + if (avatar == null || avatar.expressionsMenu == null) return; + + // Do we have a top-level menu we can install into? + // For our heuristic purposes we only look at menus at the top level of the avatar, where the avatar's own + // menu is empty. + GameObject topLevelMenu = null; + if (avatar.expressionsMenu?.controls?.Count == 0) + { + foreach (Transform t in avatar.transform) + { + var installer = t.GetComponent(); + var group = t.GetComponent(); + + if (installer != null && group != null && installer.installTargetMenu == null && + group.targetObject == null) + { + topLevelMenu = t.gameObject; + break; + } + } + } + + var parentObject = topLevelMenu != null ? topLevelMenu.transform : avatar.transform; + + // Avoid double registration + foreach (Transform t in parentObject.transform) + { + if (PrefabUtility.IsPartOfPrefabInstance(t) && + PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(t) == PATH_OUTFIT_MENU) + { + EditorGUIUtility.PingObject(t.gameObject); + return; + } + } + + var instance = (GameObject) PrefabUtility.InstantiatePrefab(PREFAB_OUTFIT_MENU, parentObject); + instance.name = "Outfits"; + Undo.RegisterCreatedObjectUndo(instance, "Added outfit menu"); + + var installerComponent = instance.GetComponent(); + if (topLevelMenu != null) + { + UnityEngine.Object.DestroyImmediate(installerComponent); + PrefabUtility.RecordPrefabInstancePropertyModifications(instance); + } + + EditorGUIUtility.PingObject(instance.transform.Find("BaseOutfit").gameObject); + } + } +} \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Editor/Menu/AddOutfitMenu.cs.meta b/Packages/nadena.dev.modular-avatar/Editor/Menu/AddOutfitMenu.cs.meta new file mode 100644 index 00000000..ca6e50d8 --- /dev/null +++ b/Packages/nadena.dev.modular-avatar/Editor/Menu/AddOutfitMenu.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ec7b467fa15c4826b90ee24441bdec83 +timeCreated: 1683801782 \ No newline at end of file