#if MA_VRCSDK3_AVATARS using System; using System.Collections.Generic; using System.Linq; using nadena.dev.modular_avatar.core.editor.menu; using UnityEditor; using UnityEngine; using VRC.SDK3.Avatars.Components; using VRC.SDK3.Avatars.ScriptableObjects; namespace nadena.dev.modular_avatar.core.editor { internal class MenuInstallHook { private static Texture2D _moreIcon = AssetDatabase.LoadAssetAtPath( "Packages/nadena.dev.modular-avatar/Runtime/Icons/Icon_More_A.png" ); private BuildContext _context; private VRCExpressionsMenu _rootMenu; private Stack _visitedInstallerStack; public void OnPreprocessAvatar(GameObject avatarRoot, BuildContext context) { _context = context; ModularAvatarMenuInstaller[] menuInstallers = avatarRoot .GetComponentsInChildren(true) .Where(menuInstaller => menuInstaller.enabled) .ToArray(); if (menuInstallers.Length == 0) return; _visitedInstallerStack = new Stack(); VRCAvatarDescriptor avatar = avatarRoot.GetComponent(); if (avatar.expressionsMenu == null) { var menu = ScriptableObject.CreateInstance(); _context.SaveAsset(menu); avatar.expressionsMenu = menu; context.ClonedMenus[menu] = menu; } _rootMenu = avatar.expressionsMenu; var virtualMenu = VirtualMenu.ForAvatar(avatar, context); avatar.expressionsMenu = virtualMenu.SerializeMenu(asset => { context.SaveAsset(asset); if (asset is VRCExpressionsMenu menu) SplitMenu(menu); }); } private void SplitMenu(VRCExpressionsMenu targetMenu) { while (targetMenu.controls.Count > VRCExpressionsMenu.MAX_CONTROLS) { // Split target menu var newMenu = ScriptableObject.CreateInstance(); _context.SaveAsset(newMenu); const int keepCount = VRCExpressionsMenu.MAX_CONTROLS - 1; newMenu.controls.AddRange(targetMenu.controls.Skip(keepCount)); targetMenu.controls.RemoveRange(keepCount, targetMenu.controls.Count - keepCount ); targetMenu.controls.Add(new VRCExpressionsMenu.Control { name = "More", type = VRCExpressionsMenu.Control.ControlType.SubMenu, subMenu = newMenu, parameter = new VRCExpressionsMenu.Control.Parameter { name = "" }, subParameters = Array.Empty(), icon = _moreIcon, labels = Array.Empty() }); targetMenu = newMenu; } } } } #endif