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 nadena.dev.modular_avatar.core.menu;
using nadena.dev.modular_avatar.editor.ErrorReporting;
using nadena.dev.ndmf;
using UnityEngine;
using VRC.SDK3.Avatars.Components;
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 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))
{
menu.RegisterMenuInstaller(installer);
menu.RegisterMenuInstaller(installer, menuMap);
}
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.
/// </summary>
/// <param name="installer"></param>
internal void RegisterMenuInstaller(ModularAvatarMenuInstaller installer)
internal void RegisterMenuInstaller(ModularAvatarMenuInstaller installer, Dictionary<ObjectReference, VRCExpressionsMenu> menuMap)
{
// initial validation
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))
{
targets = new List<ModularAvatarMenuInstaller>();

View File

@ -4,7 +4,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using nadena.dev.modular_avatar.core.editor.menu;
using nadena.dev.ndmf;
using UnityEditor;
using UnityEngine;
using VRC.SDK3.Avatars.Components;
@ -46,27 +45,6 @@ namespace nadena.dev.modular_avatar.core.editor
avatar.expressionsMenu = 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;
var virtualMenu = VirtualMenu.ForAvatar(avatar, context);