fix: move reference replacement to VirtualMenu, detect circular references

This commit is contained in:
lilxyzw 2024-09-19 16:21:28 +09:00
parent e57371a3ed
commit e2afd2f1e7
2 changed files with 22 additions and 25 deletions

View File

@ -7,6 +7,7 @@ using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using nadena.dev.modular_avatar.core.menu; using nadena.dev.modular_avatar.core.menu;
using nadena.dev.modular_avatar.editor.ErrorReporting; using nadena.dev.modular_avatar.editor.ErrorReporting;
using nadena.dev.ndmf;
using UnityEngine; using UnityEngine;
using VRC.SDK3.Avatars.Components; using VRC.SDK3.Avatars.Components;
using VRC.SDK3.Avatars.ScriptableObjects; using VRC.SDK3.Avatars.ScriptableObjects;
@ -272,9 +273,23 @@ namespace nadena.dev.modular_avatar.core.editor.menu
) )
{ {
var menu = new VirtualMenu(avatar.expressionsMenu, context); var menu = new VirtualMenu(avatar.expressionsMenu, context);
var menuMap = new Dictionary<ObjectReference, VRCExpressionsMenu>();
void GetMenuReferences(VRCExpressionsMenu exMenu)
{
if (!exMenu || menuMap.ContainsValue(exMenu)) return;
menuMap[ObjectRegistry.GetReference(exMenu)] = exMenu;
foreach (var control in exMenu.controls)
{
if(control.type == VRCExpressionsMenu.Control.ControlType.SubMenu)
GetMenuReferences(control.subMenu);
}
}
GetMenuReferences(avatar.expressionsMenu);
foreach (var installer in avatar.GetComponentsInChildren<ModularAvatarMenuInstaller>(true)) foreach (var installer in avatar.GetComponentsInChildren<ModularAvatarMenuInstaller>(true))
{ {
menu.RegisterMenuInstaller(installer); menu.RegisterMenuInstaller(installer, menuMap);
} }
foreach (var target in avatar.GetComponentsInChildren<ModularAvatarMenuInstallTarget>(true)) foreach (var target in avatar.GetComponentsInChildren<ModularAvatarMenuInstallTarget>(true))
@ -306,12 +321,16 @@ namespace nadena.dev.modular_avatar.core.editor.menu
/// determine the effects of this menu installer, further processing is deferred until we freeze the menu. /// determine the effects of this menu installer, further processing is deferred until we freeze the menu.
/// </summary> /// </summary>
/// <param name="installer"></param> /// <param name="installer"></param>
internal void RegisterMenuInstaller(ModularAvatarMenuInstaller installer) internal void RegisterMenuInstaller(ModularAvatarMenuInstaller installer, Dictionary<ObjectReference, VRCExpressionsMenu> menuMap)
{ {
// initial validation // initial validation
if (installer.menuToAppend == null && installer.GetComponent<MenuSource>() == null) return; if (installer.menuToAppend == null && installer.GetComponent<MenuSource>() == null) return;
var target = installer.installTargetMenu ? (object) installer.installTargetMenu : RootMenuKey; var installTargetMenu = installer.installTargetMenu &&
menuMap.TryGetValue(ObjectRegistry.GetReference(installer.installTargetMenu), out var currentMenu) ?
currentMenu : installer.installTargetMenu;
var target = installTargetMenu ? (object) installTargetMenu : RootMenuKey;
if (!_targetMenuToInstaller.TryGetValue(target, out var targets)) if (!_targetMenuToInstaller.TryGetValue(target, out var targets))
{ {
targets = new List<ModularAvatarMenuInstaller>(); targets = new List<ModularAvatarMenuInstaller>();

View File

@ -4,7 +4,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using nadena.dev.modular_avatar.core.editor.menu; using nadena.dev.modular_avatar.core.editor.menu;
using nadena.dev.ndmf;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using VRC.SDK3.Avatars.Components; using VRC.SDK3.Avatars.Components;
@ -46,27 +45,6 @@ namespace nadena.dev.modular_avatar.core.editor
avatar.expressionsMenu = menu; avatar.expressionsMenu = menu;
context.ClonedMenus[menu] = menu; context.ClonedMenus[menu] = menu;
} }
else
{
IEnumerable<VRCExpressionsMenu> GetMenus(VRCExpressionsMenu menu)
{
if (!menu) yield break;
foreach (var m in menu.controls
.Where(control => control.type == VRCExpressionsMenu.Control.ControlType.SubMenu)
.SelectMany(control => GetMenus(control.subMenu)))
yield return m;
yield return menu;
}
var currentMenus = GetMenus(avatar.expressionsMenu)
.ToDictionary(menu => ObjectRegistry.GetReference(menu), menu => menu);
foreach (var menuInstaller in menuInstallers)
{
if (!menuInstaller.installTargetMenu) continue;
var reference = ObjectRegistry.GetReference(menuInstaller.installTargetMenu);
if (currentMenus.ContainsKey(reference))
menuInstaller.installTargetMenu = currentMenus[reference];
}
}
_rootMenu = avatar.expressionsMenu; _rootMenu = avatar.expressionsMenu;
var virtualMenu = VirtualMenu.ForAvatar(avatar, context); var virtualMenu = VirtualMenu.ForAvatar(avatar, context);