Skip to content

Commit

Permalink
fix(ma-store): appending menu items to previous added submenu
Browse files Browse the repository at this point in the history
  • Loading branch information
poi-vrc committed Apr 19, 2024
1 parent 4da8078 commit 0ab5ecf
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 169 deletions.
9 changes: 9 additions & 0 deletions Editor/DKEditorUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using Chocopoi.DressingFramework.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;

namespace Chocopoi.DressingFramework
Expand Down Expand Up @@ -85,6 +86,14 @@ public static string RandomString(int length)
// referenced from: http://answers.unity3d.com/questions/458207/copy-a-component-at-runtime.html
public static Component CopyComponent(Component originalComponent, GameObject destGameObject)
{
if (destGameObject.scene == null)
{
throw new Exception("Report this to the DressingTools developer! Destination GameObject does not contain a scene!");

Check warning on line 91 in Editor/DKEditorUtils.cs

View check run for this annotation

Codecov / codecov/patch

Editor/DKEditorUtils.cs#L90-L91

Added lines #L90 - L91 were not covered by tests
}
if (PrefabUtility.IsPartOfAnyPrefab(destGameObject))
{
throw new Exception("Report this to the DressingTools developer! Destination GameObject is part of a prefab!");

Check warning on line 95 in Editor/DKEditorUtils.cs

View check run for this annotation

Codecov / codecov/patch

Editor/DKEditorUtils.cs#L94-L95

Added lines #L94 - L95 were not covered by tests
}
System.Type type = originalComponent.GetType();

// get the destination component or add new
Expand Down
129 changes: 41 additions & 88 deletions Editor/Detail/DK/DKMAMenuStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,22 @@ namespace Chocopoi.DressingFramework.Detail.DK
internal class DKMAMenuStore : MenuStore
{
private readonly Context _ctx;
private readonly Dictionary<string, MenuGroup> _buffer;
private readonly MenuGroup _buffer;
private readonly HashSet<VRCExpressionsMenu> _clonedVrcMenus;

public DKMAMenuStore(Context ctx)
{
_ctx = ctx;
_buffer = new Dictionary<string, MenuGroup>();
_buffer = new MenuGroup();
_clonedVrcMenus = new HashSet<VRCExpressionsMenu>();
}

public override void Append(MenuItem menuItem, string path = null)
{
if (path == null)
{
path = "";
}
path = path.Trim();

if (!_buffer.TryGetValue(path, out var menuItems))
{
menuItems = _buffer[path] = new MenuGroup();
}
menuItems.Add(menuItem);
// append the item to our buffer
// in cases the path falls on a VRC menu, that menu will be cloned and item will be added into it.
var target = VRCMenuUtils.FindInstallTarget(_buffer, path, _ctx, _clonedVrcMenus);
target.Add(menuItem);
}

private static VRCExpressionsMenu.Control MakeSubMenuControl(string name, Texture2D icon, VRCExpressionsMenu subMenu)
Expand All @@ -70,19 +63,7 @@ private static VRCExpressionsMenu.Control MakeSubMenuControl(string name, Textur
};
}

private VRCExpressionsMenu MakeDownwardsMenuGroups(string[] paths, int index)
{
var menu = Object.Instantiate(VRCMenuUtils.GetDefaultExpressionsMenu());
_ctx.CreateUniqueAsset(menu, string.Join("_", paths, 0, index));
if (index < paths.Length)
{
var newMenuItem = MakeSubMenuControl(paths[index], null, MakeDownwardsMenuGroups(paths, index + 1));
menu.controls.Add(newMenuItem);
}
return menu;
}

private VRCExpressionsMenu FindInstallTarget(VRCExpressionsMenu parent, string[] paths, int index)
private static VRCExpressionsMenu FindExistingVRCMenu(VRCExpressionsMenu parent, string[] paths, int index)
{
if (index >= paths.Length)
{
Expand All @@ -98,39 +79,37 @@ private VRCExpressionsMenu FindInstallTarget(VRCExpressionsMenu parent, string[]

if (item.type == VRCExpressionsMenu.Control.ControlType.SubMenu)
{
if (item.subMenu == null)
{
var newVrcMenu = Object.Instantiate(VRCMenuUtils.GetDefaultExpressionsMenu());
_ctx.CreateUniqueAsset(newVrcMenu, string.Join("_", paths, 0, index + 1));
item.subMenu = newVrcMenu;

_clonedVrcMenus.Add(item.subMenu);
}
else if (!_clonedVrcMenus.Contains(item.subMenu))
{
var menuCopy = Object.Instantiate(item.subMenu);
_ctx.CreateUniqueAsset(menuCopy, string.Join("_", paths, 0, index + 1));
item.subMenu = menuCopy;

_clonedVrcMenus.Add(item.subMenu);
}

return FindInstallTarget(item.subMenu, paths, index + 1);
return FindExistingVRCMenu(item.subMenu, paths, index + 1);
}
}

// if not found, we create empty menu groups recursively downwards
var newMenuItem = MakeSubMenuControl(paths[index], null, MakeDownwardsMenuGroups(paths, index + 1));
parent.controls.Add(newMenuItem);

// find again
return FindInstallTarget(parent, paths, index);
// not found
return null;
}

private static void DKToMAMenuItem(GameObject parent, MenuItem menuItem)
private static void DKToMAMenuItem(Transform dkMaRoot, VRCExpressionsMenu avatarRootMenu, Transform parent, MenuItem menuItem, string absolutePath)
{
if (menuItem is SubMenuItem)
{
// prefer using MA installer on existing menus for supporting path install
var newPath = $"{absolutePath.Trim()}/{menuItem.Name}";
var newPaths = newPath.Trim().Split('/');
var vrcMenu = FindExistingVRCMenu(avatarRootMenu, newPaths, 0);
if (vrcMenu != null)
{
// make a ma installer to that menu
var menuObj = new GameObject(string.Join("_", newPaths));
menuObj.transform.SetParent(dkMaRoot);
var maInstaller = menuObj.AddComponent<ModularAvatarMenuInstaller>();
maInstaller.installTargetMenu = vrcMenu;
var maGroup = menuObj.AddComponent<ModularAvatarMenuGroup>();
maGroup.targetObject = menuObj;
return;
}
}

var maItemObj = new GameObject(menuItem.Name);
maItemObj.transform.SetParent(parent.transform);
maItemObj.transform.SetParent(parent);

var maItem = maItemObj.AddComponent<ModularAvatarMenuItem>();

Expand All @@ -140,7 +119,7 @@ private static void DKToMAMenuItem(GameObject parent, MenuItem menuItem)
maItem.MenuSource = SubmenuSource.Children;
if (subMenuItem.SubMenu != null)
{
DKGroupToMAItems(maItemObj, subMenuItem.SubMenu);
DKGroupToMAItems(dkMaRoot, avatarRootMenu, maItemObj.transform, subMenuItem.SubMenu, $"{absolutePath}/{menuItem.Name}");
}
}
else if (menuItem is VRCSubMenuItem vrcSubMenuItem)
Expand All @@ -154,11 +133,11 @@ private static void DKToMAMenuItem(GameObject parent, MenuItem menuItem)
}
}

private static void DKGroupToMAItems(GameObject parent, MenuGroup menuGroup)
private static void DKGroupToMAItems(Transform dkMaRoot, VRCExpressionsMenu avatarRootMenu, Transform parent, MenuGroup menuGroup, string absolutePath)
{
foreach (var item in menuGroup)
{
DKToMAMenuItem(parent, item);
DKToMAMenuItem(dkMaRoot, avatarRootMenu, parent, item, absolutePath);
}
}

Expand All @@ -173,40 +152,14 @@ public override void Flush()
var dkMaRootObj = new GameObject("DKMAMenu");
dkMaRootObj.transform.SetParent(_ctx.AvatarGameObject.transform);

foreach (var kvp in _buffer)
{
var path = kvp.Key;
var items = kvp.Value;
var rootMenuObj = new GameObject("Root");
rootMenuObj.transform.SetParent(dkMaRootObj.transform);
var rootMaInstaller = rootMenuObj.AddComponent<ModularAvatarMenuInstaller>();
rootMaInstaller.installTargetMenu = avatarDesc.expressionsMenu;
var rootMaGroup = rootMenuObj.AddComponent<ModularAvatarMenuGroup>();
rootMaGroup.targetObject = rootMenuObj;

// find and create the install target and pass to MA
string menuObjName;
VRCExpressionsMenu installTarget;
if (string.IsNullOrEmpty(path))
{
menuObjName = "Root";
installTarget = avatarDesc.expressionsMenu;
}
else
{
var paths = path.Trim().Split('/');
menuObjName = string.Join("_", paths);
installTarget = FindInstallTarget(avatarDesc.expressionsMenu, paths, 0);
}

var menuObj = new GameObject(menuObjName);
menuObj.transform.SetParent(dkMaRootObj.transform);

// add installer
var maInstaller = menuObj.AddComponent<ModularAvatarMenuInstaller>();
maInstaller.installTargetMenu = installTarget;

// add menu group
var maGroup = menuObj.AddComponent<ModularAvatarMenuGroup>();
maGroup.targetObject = menuObj;

// add menu items
DKGroupToMAItems(menuObj, items);
}
DKGroupToMAItems(dkMaRootObj.transform, avatarDesc.expressionsMenu, rootMenuObj.transform, _buffer, "");
}

internal override void OnEnable() { }
Expand Down
84 changes: 4 additions & 80 deletions Editor/Menu/MenuRepositoryStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,89 +47,13 @@ public override void Append(MenuItem menuItem, string path = null)
_buffer[menuItem] = path;
}

private IMenuRepository FindInstallTarget(IMenuRepository parent, string[] paths, int index)
private void InstallMenuItem(IMenuRepository rootMenu, MenuItem item, string path)
{
if (index >= paths.Length)
{
return parent;
}

foreach (var item in parent)
{
if (item.Name != paths[index])
{
continue;
}

if (item is SubMenuItem subMenuItem)
{
if (subMenuItem.SubMenu == null)
{
subMenuItem.SubMenu = new MenuGroup();
}
return FindInstallTarget(subMenuItem.SubMenu, paths, index + 1);
}
#if DK_VRCSDK3A
else if (item is VRCSubMenuItem vrcSubMenuItem)
{
if (vrcSubMenuItem.SubMenu == null)
{
var newVrcMenu = Object.Instantiate(VRCMenuUtils.GetDefaultExpressionsMenu());
_ctx.CreateUniqueAsset(newVrcMenu, string.Join("_", paths, 0, index + 1));
vrcSubMenuItem.SubMenu = newVrcMenu;

_clonedVrcMenus.Add(vrcSubMenuItem.SubMenu);
}
else if (!_clonedVrcMenus.Contains(vrcSubMenuItem.SubMenu))
{
var menuCopy = Object.Instantiate(vrcSubMenuItem.SubMenu);
_ctx.CreateUniqueAsset(menuCopy, string.Join("_", paths, 0, index + 1));
vrcSubMenuItem.SubMenu = menuCopy;
_clonedVrcMenus.Add(vrcSubMenuItem.SubMenu);
}

return FindInstallTarget(new VRCMenuWrapper(vrcSubMenuItem.SubMenu, _ctx), paths, index + 1);
}
var installTarget = VRCMenuUtils.FindInstallTarget(rootMenu, path, _ctx, _clonedVrcMenus);
#else
var installTarget = MenuUtils.FindInstallTarget(rootMenu, path);
#endif
}

// if not found, we create empty menu groups recursively downwards
var newMenuItem = new SubMenuItem()
{
Name = paths[index],
Icon = null,
SubMenu = MakeDownwardsMenuGroups(paths, index + 1)
};
parent.Add(newMenuItem);

// find again, the menu group pointers above cannot be used after the CRUD operation
return FindInstallTarget(parent, paths, index);
}

private MenuGroup MakeDownwardsMenuGroups(string[] paths, int index)
{
var mg = new MenuGroup();
if (index < paths.Length)
{
var newMenuItem = new SubMenuItem()
{
Name = paths[index],
Icon = null,
SubMenu = MakeDownwardsMenuGroups(paths, index + 1)
};
mg.Add(newMenuItem);
}
return mg;
}

private void InstallMenuItem(IMenuRepository rootMenu, MenuItem item, string path)
{
var installTarget = rootMenu;
if (!string.IsNullOrEmpty(path))
{
var paths = path.Trim().Split('/');
installTarget = FindInstallTarget(rootMenu, paths, 0);
}
installTarget.Add(item);
}

Expand Down
Loading

0 comments on commit 0ab5ecf

Please sign in to comment.