From 9ea8e655ce3e3511d4c5d2bf14341b666665dd55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=C3=AF=7E?= <60819407+hai-vr@users.noreply.github.com> Date: Thu, 13 Jun 2024 04:56:30 +0200 Subject: [PATCH] fix: CVRAvatar prevents removal of Animator (#260) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: CVRAvatar prevents removal of Animator The error "Can't remove Animator because CVRAvatar (Script) depends on it" occurs in ChilloutVR avatars during the recreation of the Animator component. This is because CVRAvatar has a RequireComponent annotation for Animator. This commit fixes this issue by removing CVRAvatar first, and recreates it in the same way. Tested on ChilloutVR CCK v3.9 RELEASE * review pass: introspect RequireComponent attribute instead * chore: update CHANGELOG.md --------- Co-authored-by: Haï~ Co-authored-by: bd_ --- CHANGELOG.md | 1 + Editor/ApplyOnPlay.cs | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01a1d454..49794b06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - [#257] Proxy renderers no longer appear in the hierarchy. +- [#260] [ChilloutVR] Fix: Build fails due to CVRAvatar preventing recreation of Animator (contributed by @hai-vr) ### Changed diff --git a/Editor/ApplyOnPlay.cs b/Editor/ApplyOnPlay.cs index 8c708a87..83a82608 100644 --- a/Editor/ApplyOnPlay.cs +++ b/Editor/ApplyOnPlay.cs @@ -27,6 +27,7 @@ #region using System; +using System.Collections.Generic; using System.Linq; using nadena.dev.ndmf.config; using nadena.dev.ndmf.runtime; @@ -135,19 +136,56 @@ private static void RecreateAnimators(Transform avatar) var tmpAnimator = tmpObject.AddComponent(); bool enabled = animator.enabled; + // Support components that need to be destroyed before the Animator is destroyed, + // such as ChilloutVR's CVRAvatar component. + var tmpComponentsRequiringAnimator = new List(); + foreach (var componentRequiringAnimator in FindSiblingComponentsRequiringAnimator(animator)) + { + var tmpComponentRequiringAnimator = tmpObject.AddComponent(componentRequiringAnimator.GetType()); + tmpComponentsRequiringAnimator.Add(tmpComponentRequiringAnimator); + EditorUtility.CopySerialized(componentRequiringAnimator, tmpComponentRequiringAnimator); + // Destroy this first before destroying the Animator below. + UnityObject.DestroyImmediate(componentRequiringAnimator); + } + EditorUtility.CopySerialized(animator, tmpAnimator); UnityObject.DestroyImmediate(animator); var newAnimator = obj.AddComponent(); newAnimator.enabled = false; EditorUtility.CopySerialized(tmpAnimator, newAnimator); newAnimator.enabled = enabled; + + foreach (var tmpComponentRequiringAnimator in tmpComponentsRequiringAnimator) + { + var newComponent = obj.AddComponent(tmpComponentRequiringAnimator.GetType()); + EditorUtility.CopySerialized(tmpComponentRequiringAnimator, newComponent); + // Even in the temporary object, destroy this first before destroying the Animator below. + UnityObject.DestroyImmediate(tmpComponentRequiringAnimator); + } UnityObject.DestroyImmediate(tmpAnimator); } UnityObject.DestroyImmediate(tmpObject); } - + + private static IEnumerable FindSiblingComponentsRequiringAnimator(Animator animator) + { + return animator.GetComponents() + // GetComponents may return null elements on unloaded MonoBehaviour scripts + .Where(component => component != null) + .Where(component => + { + var requiresAnimator = component.GetType() + .GetCustomAttributes(typeof(RequireComponent), true) + .Cast() + .Any(requireComponent => requireComponent.m_Type0 == typeof(Animator) + || requireComponent.m_Type1 == typeof(Animator) + || requireComponent.m_Type2 == typeof(Animator)); + return requiresAnimator; + }); + } + private static void OnPlayModeStateChanged(PlayModeStateChange obj) { if (obj == PlayModeStateChange.EnteredPlayMode)