mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-05-10 13:19:01 +08:00
integrate with menu generation pass and menu target UI
This commit is contained in:
parent
19e42f3422
commit
52dd314f8a
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using nadena.dev.modular_avatar.core.editor.menu;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
@ -28,7 +29,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
set => _treeView.TargetInstaller = value;
|
||||
}
|
||||
|
||||
public Action<VRCExpressionsMenu> OnMenuSelected = (menu) => { };
|
||||
public Action<object> OnMenuSelected = (menu) => { };
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@ -58,7 +59,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
_treeView.OnGUI(new Rect(0, 0, position.width, position.height));
|
||||
}
|
||||
|
||||
internal static void Show(VRCAvatarDescriptor Avatar, ModularAvatarMenuInstaller Installer, Action<VRCExpressionsMenu> OnSelect)
|
||||
internal static void Show(VRCAvatarDescriptor Avatar, ModularAvatarMenuInstaller Installer,
|
||||
Action<object> OnSelect)
|
||||
{
|
||||
var window = GetWindow<AvMenuTreeViewWindow>();
|
||||
window.titleContent = new GUIContent("Select menu");
|
||||
@ -97,14 +99,14 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
}
|
||||
}
|
||||
|
||||
internal Action<VRCExpressionsMenu> OnSelect = (menu) => { };
|
||||
internal Action<object> OnSelect = (menu) => { };
|
||||
internal Action OnDoubleclickSelect = () => { };
|
||||
|
||||
private List<VRCExpressionsMenu> _menuItems = new List<VRCExpressionsMenu>();
|
||||
private HashSet<VRCExpressionsMenu> _visitedMenus = new HashSet<VRCExpressionsMenu>();
|
||||
private List<object> _nodeKeys = new List<object>();
|
||||
private HashSet<object> _visitedMenus = new HashSet<object>();
|
||||
|
||||
private MenuTree _menuTree;
|
||||
private Stack<VRCExpressionsMenu> _visitedMenuStack = new Stack<VRCExpressionsMenu>();
|
||||
private VirtualMenu _menuTree;
|
||||
private Stack<object> _visitedMenuStack = new Stack<object>();
|
||||
|
||||
public AvMenuTreeView(TreeViewState state) : base(state)
|
||||
{
|
||||
@ -112,27 +114,21 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
protected override void SelectionChanged(IList<int> selectedIds)
|
||||
{
|
||||
OnSelect.Invoke(_menuItems[selectedIds[0]]);
|
||||
OnSelect.Invoke(_nodeKeys[selectedIds[0]]);
|
||||
}
|
||||
|
||||
protected override void DoubleClickedItem(int id)
|
||||
{
|
||||
OnSelect.Invoke(_menuItems[id]);
|
||||
OnSelect.Invoke(_nodeKeys[id]);
|
||||
OnDoubleclickSelect.Invoke();
|
||||
}
|
||||
|
||||
protected override TreeViewItem BuildRoot()
|
||||
{
|
||||
_menuItems.Clear();
|
||||
_nodeKeys.Clear();
|
||||
_visitedMenuStack.Clear();
|
||||
|
||||
_menuTree = new MenuTree(Avatar);
|
||||
_menuTree.TraverseAvatarMenu();
|
||||
foreach (ModularAvatarMenuInstaller installer in Avatar.gameObject.GetComponentsInChildren<ModularAvatarMenuInstaller>(true))
|
||||
{
|
||||
if (installer == TargetInstaller) continue;
|
||||
_menuTree.TraverseMenuInstaller(installer);
|
||||
}
|
||||
_menuTree = VirtualMenu.ForAvatar(_avatar);
|
||||
|
||||
var root = new TreeViewItem(-1, -1, "<root>");
|
||||
List<TreeViewItem> treeItems = new List<TreeViewItem>
|
||||
@ -141,27 +137,27 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
id = 0,
|
||||
depth = 0,
|
||||
displayName = $"{Avatar.gameObject.name} ({(Avatar.expressionsMenu == null ? "None" : Avatar.expressionsMenu.name)})"
|
||||
displayName =
|
||||
$"{Avatar.gameObject.name} ({(Avatar.expressionsMenu == null ? "None" : Avatar.expressionsMenu.name)})"
|
||||
}
|
||||
};
|
||||
_menuItems.Add(Avatar.expressionsMenu);
|
||||
_visitedMenuStack.Push(Avatar.expressionsMenu);
|
||||
|
||||
TraverseMenu(1, treeItems, Avatar.expressionsMenu);
|
||||
_nodeKeys.Add(_menuTree.RootMenuKey);
|
||||
_visitedMenuStack.Push(_menuTree.RootMenuKey);
|
||||
TraverseMenu(1, treeItems, _menuTree.RootMenuNode);
|
||||
SetupParentsAndChildrenFromDepths(root, treeItems);
|
||||
return root;
|
||||
}
|
||||
|
||||
private void TraverseMenu(int depth, List<TreeViewItem> items, VRCExpressionsMenu menu)
|
||||
private void TraverseMenu(int depth, List<TreeViewItem> items, MenuNode node)
|
||||
{
|
||||
IEnumerable<MenuTree.ChildElement> children = _menuTree.GetChildren(menu)
|
||||
.Where(child => !_visitedMenuStack.Contains(child.menu));
|
||||
foreach (MenuTree.ChildElement child in children)
|
||||
IEnumerable<VirtualControl> children = node.Controls
|
||||
.Where(control => control.type == VRCExpressionsMenu.Control.ControlType.SubMenu &&
|
||||
control.SubmenuNode != null &&
|
||||
!_visitedMenuStack.Contains(control.SubmenuNode));
|
||||
foreach (var child in children)
|
||||
{
|
||||
if (child.menu == null) continue;
|
||||
string displayName = child.installer == null ?
|
||||
$"{child.menuName} ({child.menu.name})" :
|
||||
$"{child.menuName} ({child.menu.name}) InstallerObject : {child.installer.name}";
|
||||
string displayName = child.name;
|
||||
|
||||
items.Add(
|
||||
new TreeViewItem
|
||||
{
|
||||
@ -170,9 +166,9 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
displayName = displayName
|
||||
}
|
||||
);
|
||||
_menuItems.Add(child.menu);
|
||||
_visitedMenuStack.Push(child.menu);
|
||||
TraverseMenu(depth + 1, items, child.menu);
|
||||
_nodeKeys.Add(child.SubmenuNode.NodeKey);
|
||||
_visitedMenuStack.Push(child.SubmenuNode);
|
||||
TraverseMenu(depth + 1, items, child.SubmenuNode);
|
||||
_visitedMenuStack.Pop();
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
if (name != null)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var targetGameObject = ((ModularAvatarMenuItem) target).gameObject;
|
||||
var newName = EditorGUILayout.TextField("Name", targetGameObject.name);
|
||||
var newName = EditorGUILayout.TextField("Name", name);
|
||||
if (EditorGUI.EndChangeCheck() && commitName != null)
|
||||
{
|
||||
commitName(newName);
|
||||
|
@ -1,6 +1,7 @@
|
||||
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;
|
||||
@ -101,7 +102,20 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
AvMenuTreeViewWindow.Show(avatar, _installer, menu =>
|
||||
{
|
||||
installTo.objectReferenceValue = menu;
|
||||
if (menu is VRCExpressionsMenu expMenu)
|
||||
{
|
||||
if (expMenu == avatar.expressionsMenu) installTo.objectReferenceValue = null;
|
||||
else installTo.objectReferenceValue = expMenu;
|
||||
}
|
||||
else if (menu is RootMenu)
|
||||
{
|
||||
installTo.objectReferenceValue = null;
|
||||
}
|
||||
else if (menu is ModularAvatarMenuItem item)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
});
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||
using nadena.dev.modular_avatar.editor.ErrorReporting;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
using VRC.SDK3.Avatars.ScriptableObjects;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core.editor.menu
|
||||
@ -71,7 +72,7 @@ namespace nadena.dev.modular_avatar.core.editor.menu
|
||||
*/
|
||||
internal class VirtualMenu
|
||||
{
|
||||
private readonly object RootMenuKey;
|
||||
internal readonly object RootMenuKey;
|
||||
|
||||
/// <summary>
|
||||
/// Indexes which menu installers are contributing to which VRCExpressionMenu assets.
|
||||
@ -92,6 +93,7 @@ namespace nadena.dev.modular_avatar.core.editor.menu
|
||||
|
||||
// TODO: immutable?
|
||||
public Dictionary<object, MenuNode> ResolvedMenu => _resolvedMenu;
|
||||
public MenuNode RootMenuNode => ResolvedMenu[RootMenuKey];
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the VirtualMenu.
|
||||
@ -111,6 +113,24 @@ namespace nadena.dev.modular_avatar.core.editor.menu
|
||||
}
|
||||
}
|
||||
|
||||
internal static VirtualMenu ForAvatar(VRCAvatarDescriptor avatar)
|
||||
{
|
||||
var menu = new VirtualMenu(avatar.expressionsMenu);
|
||||
foreach (var installer in avatar.GetComponentsInChildren<ModularAvatarMenuInstaller>(true))
|
||||
{
|
||||
menu.RegisterMenuInstaller(installer);
|
||||
}
|
||||
|
||||
foreach (var target in avatar.GetComponentsInChildren<ModularAvatarMenuInstallTarget>(true))
|
||||
{
|
||||
menu.RegisterMenuInstallTarget(target);
|
||||
}
|
||||
|
||||
menu.FreezeMenu();
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
private MenuNode ImportMenu(VRCExpressionsMenu menu, object menuKey = null)
|
||||
{
|
||||
if (menuKey == null) menuKey = menu;
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using nadena.dev.modular_avatar.core.editor.menu;
|
||||
using nadena.dev.modular_avatar.editor.ErrorReporting;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
@ -22,7 +23,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
private VRCExpressionsMenu _rootMenu;
|
||||
|
||||
private MenuTree _menuTree;
|
||||
private Stack<ModularAvatarMenuInstaller> _visitedInstallerStack;
|
||||
|
||||
public void OnPreprocessAvatar(GameObject avatarRoot, BuildContext context)
|
||||
@ -48,55 +48,15 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
}
|
||||
|
||||
_rootMenu = avatar.expressionsMenu;
|
||||
_menuTree = new MenuTree(avatar);
|
||||
_menuTree.TraverseAvatarMenu();
|
||||
|
||||
avatar.expressionsMenu = _context.CloneMenu(avatar.expressionsMenu);
|
||||
|
||||
foreach (ModularAvatarMenuInstaller installer in menuInstallers)
|
||||
var virtualMenu = VirtualMenu.ForAvatar(avatar);
|
||||
avatar.expressionsMenu = virtualMenu.SerializeMenu(asset =>
|
||||
{
|
||||
BuildReport.ReportingObject(installer, () => _menuTree.TraverseMenuInstaller(installer));
|
||||
context.SaveAsset(asset);
|
||||
if (asset is VRCExpressionsMenu menu) SplitMenu(menu);
|
||||
});
|
||||
}
|
||||
|
||||
foreach (MenuTree.ChildElement childElement in _menuTree.GetChildInstallers(null))
|
||||
{
|
||||
BuildReport.ReportingObject(childElement.installer, () => InstallMenu(childElement.installer));
|
||||
}
|
||||
}
|
||||
|
||||
private void InstallMenu(ModularAvatarMenuInstaller installer, VRCExpressionsMenu installTarget = null)
|
||||
{
|
||||
if (!installer.enabled) return;
|
||||
|
||||
if (installer.installTargetMenu == null)
|
||||
{
|
||||
installer.installTargetMenu = _rootMenu;
|
||||
}
|
||||
|
||||
if (installTarget == null)
|
||||
{
|
||||
installTarget = installer.installTargetMenu;
|
||||
}
|
||||
|
||||
if (installer.installTargetMenu == null || installer.menuToAppend == null) return;
|
||||
if (!_context.ClonedMenus.TryGetValue(installTarget, out var targetMenu)) return;
|
||||
|
||||
// Clone before appending to sanitize menu icons
|
||||
targetMenu.controls.AddRange(_context.CloneMenu(installer.menuToAppend).controls);
|
||||
|
||||
SplitMenu(installer, targetMenu);
|
||||
|
||||
if (_visitedInstallerStack.Contains(installer)) return;
|
||||
_visitedInstallerStack.Push(installer);
|
||||
foreach (MenuTree.ChildElement childElement in _menuTree.GetChildInstallers(installer))
|
||||
{
|
||||
InstallMenu(childElement.installer, childElement.parent);
|
||||
}
|
||||
|
||||
_visitedInstallerStack.Pop();
|
||||
}
|
||||
|
||||
private void SplitMenu(ModularAvatarMenuInstaller installer, VRCExpressionsMenu targetMenu)
|
||||
private void SplitMenu(VRCExpressionsMenu targetMenu)
|
||||
{
|
||||
while (targetMenu.controls.Count > VRCExpressionsMenu.MAX_CONTROLS)
|
||||
{
|
||||
@ -123,7 +83,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
labels = Array.Empty<VRCExpressionsMenu.Control.Label>()
|
||||
});
|
||||
|
||||
_context.ClonedMenus[installer.installTargetMenu] = newMenu;
|
||||
targetMenu = newMenu;
|
||||
}
|
||||
}
|
||||
|
@ -1,209 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
using VRC.SDK3.Avatars.ScriptableObjects;
|
||||
using static VRC.SDK3.Avatars.ScriptableObjects.VRCExpressionsMenu.Control;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
internal class MenuTree
|
||||
{
|
||||
|
||||
public struct ChildElement
|
||||
{
|
||||
/// <summary>
|
||||
/// Parent menu control name
|
||||
/// </summary>
|
||||
public string menuName;
|
||||
public VRCExpressionsMenu menu;
|
||||
public VRCExpressionsMenu parent;
|
||||
/// <summary>
|
||||
/// Installer to install this menu. Is null if the this menu is not installed by the installer.
|
||||
/// </summary>
|
||||
public ModularAvatarMenuInstaller installer;
|
||||
/// <summary>
|
||||
/// Whether the this submenu is added directly by the installer
|
||||
/// </summary>
|
||||
public bool isInstallerRoot;
|
||||
}
|
||||
|
||||
private readonly HashSet<VRCExpressionsMenu> _included;
|
||||
|
||||
private readonly VRCExpressionsMenu _rootMenu;
|
||||
|
||||
/// <summary>
|
||||
/// Map to link child menus from parent menu
|
||||
/// </summary>
|
||||
private readonly Dictionary<VRCExpressionsMenu, ImmutableList<ChildElement>> _menuChildrenMap;
|
||||
|
||||
public MenuTree(VRCAvatarDescriptor descriptor)
|
||||
{
|
||||
_rootMenu = descriptor.expressionsMenu;
|
||||
_included = new HashSet<VRCExpressionsMenu>();
|
||||
_menuChildrenMap = new Dictionary<VRCExpressionsMenu, ImmutableList<ChildElement>>();
|
||||
|
||||
if (_rootMenu == null)
|
||||
{
|
||||
// If the route menu is null, create a temporary menu indicating the route
|
||||
_rootMenu = ScriptableObject.CreateInstance<VRCExpressionsMenu>();
|
||||
}
|
||||
|
||||
_included.Add(_rootMenu);
|
||||
}
|
||||
|
||||
public void TraverseAvatarMenu()
|
||||
{
|
||||
if (_rootMenu == null) return;
|
||||
TraverseMenu(_rootMenu);
|
||||
}
|
||||
|
||||
public void TraverseMenuInstaller(ModularAvatarMenuInstaller installer)
|
||||
{
|
||||
if (!installer.enabled) return;
|
||||
if (installer.menuToAppend == null) return;
|
||||
TraverseMenu(installer);
|
||||
}
|
||||
|
||||
public ImmutableList<ChildElement> GetChildren(VRCExpressionsMenu parent)
|
||||
{
|
||||
if (parent == null) parent = _rootMenu;
|
||||
return !_menuChildrenMap.TryGetValue(parent, out ImmutableList<ChildElement> immutableList) ? ImmutableList<ChildElement>.Empty : immutableList;
|
||||
}
|
||||
|
||||
public IEnumerable<ChildElement> GetChildInstallers(ModularAvatarMenuInstaller parentInstaller)
|
||||
{
|
||||
HashSet<VRCExpressionsMenu> visitedMenus = new HashSet<VRCExpressionsMenu>();
|
||||
Queue<VRCExpressionsMenu> queue = new Queue<VRCExpressionsMenu>();
|
||||
if (parentInstaller != null && parentInstaller.menuToAppend == null) yield break;
|
||||
if (parentInstaller == null)
|
||||
{
|
||||
queue.Enqueue(_rootMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parentInstaller.menuToAppend == null) yield break;
|
||||
foreach (KeyValuePair<string, VRCExpressionsMenu> childMenu in GetChildMenus(parentInstaller.menuToAppend))
|
||||
{
|
||||
queue.Enqueue(childMenu.Value);
|
||||
}
|
||||
}
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
VRCExpressionsMenu parentMenu = queue.Dequeue();
|
||||
if (visitedMenus.Contains(parentMenu)) continue;
|
||||
visitedMenus.Add(parentMenu);
|
||||
HashSet<ModularAvatarMenuInstaller> returnedInstallers = new HashSet<ModularAvatarMenuInstaller>();
|
||||
foreach (ChildElement childElement in GetChildren(parentMenu))
|
||||
{
|
||||
if (!childElement.isInstallerRoot)
|
||||
{
|
||||
queue.Enqueue(childElement.menu);
|
||||
continue;
|
||||
}
|
||||
|
||||
// One installer may add multiple children, so filter to return only one.
|
||||
if (returnedInstallers.Contains(childElement.installer)) continue;
|
||||
returnedInstallers.Add(childElement.installer);
|
||||
yield return childElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void TraverseMenu(VRCExpressionsMenu root)
|
||||
{
|
||||
foreach (KeyValuePair<string, VRCExpressionsMenu> childMenu in GetChildMenus(root))
|
||||
{
|
||||
TraverseMenu(root, new ChildElement
|
||||
{
|
||||
menuName = childMenu.Key,
|
||||
menu = childMenu.Value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void TraverseMenu(ModularAvatarMenuInstaller installer)
|
||||
{
|
||||
IEnumerable<KeyValuePair<string, VRCExpressionsMenu>> childMenus = GetChildMenus(installer.menuToAppend);
|
||||
IEnumerable<VRCExpressionsMenu> parents = Enumerable.Empty<VRCExpressionsMenu>();
|
||||
if (installer.installTargetMenu != null &&
|
||||
ClonedMenuMappings.TryGetClonedMenus(installer.installTargetMenu, out ImmutableList<VRCExpressionsMenu> parentMenus))
|
||||
{
|
||||
parents = parentMenus;
|
||||
}
|
||||
|
||||
VRCExpressionsMenu[] parentsMenus = parents.DefaultIfEmpty(installer.installTargetMenu).ToArray();
|
||||
bool hasChildMenu = false;
|
||||
/*
|
||||
* Installer adds the controls in specified menu to the installation destination.
|
||||
* So, since the specified menu itself does not exist as a child menu,
|
||||
* and the child menus of the specified menu are the actual child menus, a single installer may add multiple child menus.
|
||||
*/
|
||||
foreach (KeyValuePair<string, VRCExpressionsMenu> childMenu in childMenus)
|
||||
{
|
||||
hasChildMenu = true;
|
||||
ChildElement childElement = new ChildElement
|
||||
{
|
||||
menuName = childMenu.Key,
|
||||
menu = childMenu.Value,
|
||||
installer = installer,
|
||||
isInstallerRoot = true
|
||||
};
|
||||
foreach (VRCExpressionsMenu parentMenu in parentsMenus)
|
||||
{
|
||||
TraverseMenu(parentMenu, childElement);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasChildMenu) return;
|
||||
/*
|
||||
* If the specified menu does not have any submenus, it is not mapped as a child menu and the Installer information itself is not registered.
|
||||
* Therefore, register elements that do not have child menus themselves, but only have information about the installer.
|
||||
*/
|
||||
foreach (VRCExpressionsMenu parentMenu in parentsMenus)
|
||||
{
|
||||
TraverseMenu(parentMenu, new ChildElement
|
||||
{
|
||||
installer = installer,
|
||||
isInstallerRoot = true
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void TraverseMenu(VRCExpressionsMenu parent, ChildElement childElement)
|
||||
{
|
||||
if (parent == null) parent = _rootMenu;
|
||||
childElement.parent = parent;
|
||||
if (!_menuChildrenMap.TryGetValue(parent, out ImmutableList<ChildElement> children))
|
||||
{
|
||||
children = ImmutableList<ChildElement>.Empty;
|
||||
_menuChildrenMap[parent] = children;
|
||||
}
|
||||
|
||||
_menuChildrenMap[parent] = children.Add(childElement);
|
||||
if (childElement.menu == null) return;
|
||||
if (_included.Contains(childElement.menu)) return;
|
||||
_included.Add(childElement.menu);
|
||||
foreach (KeyValuePair<string, VRCExpressionsMenu> childMenu in GetChildMenus(childElement.menu))
|
||||
{
|
||||
TraverseMenu(childElement.menu, new ChildElement
|
||||
{
|
||||
menuName = childMenu.Key,
|
||||
menu = childMenu.Value,
|
||||
installer = childElement.installer
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<KeyValuePair<string, VRCExpressionsMenu>> GetChildMenus(VRCExpressionsMenu expressionsMenu)
|
||||
{
|
||||
return expressionsMenu.controls
|
||||
.Where(control => control.type == ControlType.SubMenu && control.subMenu != null)
|
||||
.Select(control => new KeyValuePair<string, VRCExpressionsMenu>(control.name, control.subMenu));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: effd4557902f4578af42d3bdfb7f876d
|
||||
timeCreated: 1670746991
|
@ -178,6 +178,26 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ModularAvatarMenuItem menuItem:
|
||||
{
|
||||
if (menuItem.Control.parameter?.name != null &&
|
||||
remaps.TryGetValue(menuItem.Control.parameter.name, out var newVal))
|
||||
{
|
||||
menuItem.Control.parameter.name = newVal;
|
||||
}
|
||||
|
||||
foreach (var subParam in menuItem.Control.subParameters ??
|
||||
Array.Empty<VRCExpressionsMenu.Control.Parameter>())
|
||||
{
|
||||
if (subParam?.name != null && remaps.TryGetValue(subParam.name, out var subNewVal))
|
||||
{
|
||||
subParam.name = subNewVal;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user