From d2f8c22ac86bc6702752a2fd8fbc77c87bc657fd Mon Sep 17 00:00:00 2001 From: bd_ Date: Thu, 24 Nov 2022 17:19:37 -0800 Subject: [PATCH] Fix quadratic time behavior on exception Previously, processing would abort before clearing AvatarTagComponents when an exception is thrown. This would result in unprocessed AvatarTagComponents re-triggering processing as part of their Awake callback, causing O(n^2) behavior. --- .../Editor/AvatarProcessor.cs | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs b/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs index 0a1ae3dc..68503114 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs @@ -109,20 +109,27 @@ namespace nadena.dev.modular_avatar.core.editor BoneDatabase.ResetBones(); PathMappings.Clear(); - new RenameParametersHook().OnPreprocessAvatar(avatarGameObject); - new MenuInstallHook().OnPreprocessAvatar(avatarGameObject); - new MergeArmatureHook().OnPreprocessAvatar(avatarGameObject); - new RetargetMeshes().OnPreprocessAvatar(avatarGameObject); - new BoneProxyProcessor().OnPreprocessAvatar(avatarGameObject); - new VisibleHeadAccessoryProcessor(avatarGameObject.GetComponent()).Process(); - new MergeAnimatorProcessor().OnPreprocessAvatar(avatarGameObject); - new BlendshapeSyncAnimationProcessor().OnPreprocessAvatar(avatarGameObject); - - AfterProcessing?.Invoke(avatarGameObject); - - foreach (var component in avatarGameObject.GetComponentsInChildren(true)) + try { - UnityEngine.Object.DestroyImmediate(component); + new RenameParametersHook().OnPreprocessAvatar(avatarGameObject); + new MenuInstallHook().OnPreprocessAvatar(avatarGameObject); + new MergeArmatureHook().OnPreprocessAvatar(avatarGameObject); + new RetargetMeshes().OnPreprocessAvatar(avatarGameObject); + new BoneProxyProcessor().OnPreprocessAvatar(avatarGameObject); + new VisibleHeadAccessoryProcessor(avatarGameObject.GetComponent()).Process(); + new MergeAnimatorProcessor().OnPreprocessAvatar(avatarGameObject); + new BlendshapeSyncAnimationProcessor().OnPreprocessAvatar(avatarGameObject); + + AfterProcessing?.Invoke(avatarGameObject); + } + finally + { + // Ensure that we clean up AvatarTagComponents after failed processing. This ensures we don't re-enter + // processing from the Awake method on the unprocessed AvatarTagComponents + foreach (var component in avatarGameObject.GetComponentsInChildren(true)) + { + UnityEngine.Object.DestroyImmediate(component); + } } // The VRCSDK captures some debug information about animators as part of the build process, prior to invoking