fixing issues with error reporting and dependent component cleanup

This commit is contained in:
bd_ 2023-03-04 13:51:05 +09:00
parent eaf01d8c31
commit 6ba3f95177

View File

@ -23,8 +23,10 @@
*/ */
using System; using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using nadena.dev.modular_avatar.editor.ErrorReporting; using nadena.dev.modular_avatar.editor.ErrorReporting;
@ -147,78 +149,120 @@ namespace nadena.dev.modular_avatar.core.editor
{ {
try try
{ {
AssetDatabase.StartAssetEditing(); try
nowProcessing = true;
ClearEditorOnlyTagComponents(avatarGameObject.transform);
BoneDatabase.ResetBones();
PathMappings.Init(vrcAvatarDescriptor.gameObject);
ClonedMenuMappings.Clear();
// Sometimes people like to nest one avatar in another, when transplanting clothing. To avoid issues
// with inconsistently determining the avatar root, we'll go ahead and remove the extra sub-avatars
// here.
foreach (Transform directChild in avatarGameObject.transform)
{ {
foreach (var component in directChild.GetComponentsInChildren<VRCAvatarDescriptor>(true)) AssetDatabase.StartAssetEditing();
nowProcessing = true;
ClearEditorOnlyTagComponents(avatarGameObject.transform);
BoneDatabase.ResetBones();
PathMappings.Init(vrcAvatarDescriptor.gameObject);
ClonedMenuMappings.Clear();
// Sometimes people like to nest one avatar in another, when transplanting clothing. To avoid issues
// with inconsistently determining the avatar root, we'll go ahead and remove the extra sub-avatars
// here.
foreach (Transform directChild in avatarGameObject.transform)
{ {
Object.DestroyImmediate(component); foreach (var component in directChild.GetComponentsInChildren<VRCAvatarDescriptor>(true))
{
Object.DestroyImmediate(component);
}
foreach (var component in directChild.GetComponentsInChildren<PipelineSaver>(true))
{
Object.DestroyImmediate(component);
}
} }
foreach (var component in directChild.GetComponentsInChildren<PipelineSaver>(true)) var context = new BuildContext(vrcAvatarDescriptor);
{
Object.DestroyImmediate(component); new ActionGenerator(context).OnPreprocessAvatar(vrcAvatarDescriptor);
} new RenameParametersHook().OnPreprocessAvatar(avatarGameObject, context);
new MergeAnimatorProcessor().OnPreprocessAvatar(avatarGameObject, context);
context.AnimationDatabase.Bootstrap(vrcAvatarDescriptor);
new MenuInstallHook().OnPreprocessAvatar(avatarGameObject, context);
new MergeArmatureHook().OnPreprocessAvatar(context, avatarGameObject);
new BoneProxyProcessor().OnPreprocessAvatar(avatarGameObject);
new VisibleHeadAccessoryProcessor(vrcAvatarDescriptor).Process(context);
new RemapAnimationPass(vrcAvatarDescriptor).Process(context.AnimationDatabase);
new BlendshapeSyncAnimationProcessor().OnPreprocessAvatar(avatarGameObject, context);
PhysboneBlockerPass.Process(avatarGameObject);
context.AnimationDatabase.Commit();
new GCGameObjectsPass(context, avatarGameObject).OnPreprocessAvatar();
AfterProcessing?.Invoke(avatarGameObject);
} }
finally
{
AssetDatabase.StopAssetEditing();
var context = new BuildContext(vrcAvatarDescriptor); nowProcessing = false;
new ActionGenerator(context).OnPreprocessAvatar(vrcAvatarDescriptor); // Ensure that we clean up AvatarTagComponents after failed processing. This ensures we don't re-enter
new RenameParametersHook().OnPreprocessAvatar(avatarGameObject, context); // processing from the Awake method on the unprocessed AvatarTagComponents
new MergeAnimatorProcessor().OnPreprocessAvatar(avatarGameObject, context); var toDestroy = avatarGameObject.GetComponentsInChildren<AvatarTagComponent>(true).ToList();
context.AnimationDatabase.Bootstrap(vrcAvatarDescriptor); var retryDestroy = new List<AvatarTagComponent>();
new MenuInstallHook().OnPreprocessAvatar(avatarGameObject, context); // Sometimes AvatarTagComponents have interdependencies and need to be deleted in the right order;
new MergeArmatureHook().OnPreprocessAvatar(context, avatarGameObject); // retry until we purge them all.
new BoneProxyProcessor().OnPreprocessAvatar(avatarGameObject); bool madeProgress = true;
new VisibleHeadAccessoryProcessor(vrcAvatarDescriptor).Process(context); while (toDestroy.Count > 0)
new RemapAnimationPass(vrcAvatarDescriptor).Process(context.AnimationDatabase); {
new BlendshapeSyncAnimationProcessor().OnPreprocessAvatar(avatarGameObject, context); if (!madeProgress)
PhysboneBlockerPass.Process(avatarGameObject); {
throw new Exception("One or more components failed to destroy." +
RuntimeUtil.AvatarRootPath(toDestroy[0].gameObject));
}
context.AnimationDatabase.Commit(); foreach (var component in toDestroy)
{
try
{
if (component != null)
{
UnityEngine.Object.DestroyImmediate(component);
madeProgress = true;
}
}
catch (Exception e)
{
retryDestroy.Add(component);
}
}
new GCGameObjectsPass(context, avatarGameObject).OnPreprocessAvatar(); toDestroy = retryDestroy;
retryDestroy = new List<AvatarTagComponent>();
}
AfterProcessing?.Invoke(avatarGameObject); var activator = avatarGameObject.GetComponent<AvatarActivator>();
if (activator != null)
{
UnityEngine.Object.DestroyImmediate(activator);
}
ClonedMenuMappings.Clear();
ErrorReportUI.MaybeOpenErrorReportUI();
AssetDatabase.SaveAssets();
Resources.UnloadUnusedAssets();
}
} }
finally catch (Exception e)
{ {
AssetDatabase.StopAssetEditing(); BuildReport.LogException(e);
throw;
}
nowProcessing = false; if (!BuildReport.CurrentReport.CurrentAvatar.successful)
{
// Ensure that we clean up AvatarTagComponents after failed processing. This ensures we don't re-enter throw new Exception("Fatal error reported during avatar processing.");
// processing from the Awake method on the unprocessed AvatarTagComponents
foreach (var component in avatarGameObject.GetComponentsInChildren<AvatarTagComponent>(true))
{
UnityEngine.Object.DestroyImmediate(component);
}
var activator = avatarGameObject.GetComponent<AvatarActivator>();
if (activator != null)
{
UnityEngine.Object.DestroyImmediate(activator);
}
ClonedMenuMappings.Clear();
ErrorReportUI.MaybeOpenErrorReportUI();
AssetDatabase.SaveAssets();
Resources.UnloadUnusedAssets();
} }
} }
} }