From 9d5ae8558e9cc86e8d8d166704571757e1461b35 Mon Sep 17 00:00:00 2001 From: originalnicodr Date: Sat, 17 Feb 2024 01:19:43 -0300 Subject: [PATCH] Refactored the animator panel to be able to play any animation, modified the pause animation feature with the recommended property, and added try/catch statements to the post-processing panel. Also deleted the "pause after an animation played" code since that doesn't work anymore with the new method. --- src/Cinematic/Cells/AnimatorCell.cs | 79 ++++++++++------------------ src/UI/Panels/AnimatorPanel.cs | 11 ---- src/UI/Panels/PostProcessingPanel.cs | 27 +++++----- 3 files changed, 42 insertions(+), 75 deletions(-) diff --git a/src/Cinematic/Cells/AnimatorCell.cs b/src/Cinematic/Cells/AnimatorCell.cs index 5e28359..a80a4e9 100644 --- a/src/Cinematic/Cells/AnimatorCell.cs +++ b/src/Cinematic/Cells/AnimatorCell.cs @@ -27,33 +27,34 @@ namespace UnityExplorer.UI.Panels public void Disable() => UIRoot.SetActive(false); // IL2CPP games seem to have animation-related code stripped from their builds - private bool stopAfterAnimationFinishes = false; #if MONO - private bool skippedStopFrames; ButtonRef playButton; private Dropdown animatorDropdown; - private AnimationClip currentAnimation; - private AnimationClip defaultAnimation; + private AnimationClip overridingAnimation; + private AnimationClip originalAnimation; + private RuntimeAnimatorController originalAnimatorController; public void DrawAnimatorPlayer(){ if (playButton == null){ List animations = animator.runtimeAnimatorController.animationClips.OrderBy(x=>x.name).Where(c => c.length > 0).Distinct().ToList(); + originalAnimatorController = animator.runtimeAnimatorController; + //ExplorerCore.LogWarning(animations.Count); AnimatorClipInfo[] playingAnimations = animator.GetCurrentAnimatorClipInfo(0); - currentAnimation = playingAnimations.Count() != 0 ? playingAnimations[0].clip : animations[0]; + overridingAnimation = playingAnimations.Count() != 0 ? playingAnimations[0].clip : animations[0]; ButtonRef prevAnimation = UIFactory.CreateButton(UIRoot, "PreviousAnimation", "◀", new Color(0.05f, 0.05f, 0.05f)); UIFactory.SetLayoutElement(prevAnimation.Component.gameObject, minHeight: 25, minWidth: 25); prevAnimation.OnClick += () => animatorDropdown.value = animatorDropdown.value == 0 ? animatorDropdown.options.Count - 1 : animatorDropdown.value - 1; - GameObject currentAnimationObj = UIFactory.CreateDropdown(UIRoot, $"Animations_{animator.name}", out animatorDropdown, null, 14, (idx) => currentAnimation = animations[idx]); - UIFactory.SetLayoutElement(currentAnimationObj, minHeight: 25, minWidth: 200); + GameObject overridingAnimationObj = UIFactory.CreateDropdown(UIRoot, $"Animations_{animator.name}", out animatorDropdown, null, 14, (idx) => overridingAnimation = animations[idx]); + UIFactory.SetLayoutElement(overridingAnimationObj, minHeight: 25, minWidth: 200); foreach (AnimationClip animation in animations) animatorDropdown.options.Add(new Dropdown.OptionData(animation.name)); - animatorDropdown.value = Math.Max(0, animations.FindIndex(a => a == currentAnimation)); + animatorDropdown.value = Math.Max(0, animations.FindIndex(a => a == overridingAnimation)); if (animatorDropdown.value == 0) animatorDropdown.captionText.text = animations[0].name; ButtonRef nextAnimation = UIFactory.CreateButton(UIRoot, "NextAnimation", "▶", new Color(0.05f, 0.05f, 0.05f)); @@ -68,38 +69,27 @@ namespace UnityExplorer.UI.Panels private void PlayButton_OnClick(){ // We save the last animation played by the game in case we want to go back to it - if (defaultAnimation == null){ + if (originalAnimation == null){ AnimatorClipInfo[] playingAnimations = animator.GetCurrentAnimatorClipInfo(0); - defaultAnimation = playingAnimations.Count() != 0 ? playingAnimations[0].clip : null; + originalAnimation = playingAnimations.Count() != 0 ? playingAnimations[0].clip : null; } + // Need to assign the original animator controller back so to get the correct currentClip + animator.runtimeAnimatorController = originalAnimatorController; + AnimationClip currentClip = animator.GetCurrentAnimatorClipInfo(0)[0].clip; - skippedStopFrames = false; + AnimatorOverrideController animatorOverrideController = new AnimatorOverrideController(); + animatorOverrideController.runtimeAnimatorController = originalAnimatorController; + animator.runtimeAnimatorController = animatorOverrideController; - stopAfterAnimationFinishes = !AnimatorToggle.isOn; - AnimatorToggle.isOn = true; - animator.Play(currentAnimation.name); + animatorOverrideController[currentClip.name] = overridingAnimation; + + animator.Play(currentClip.name); + + // Turn the toggle on to keep consistency + if (!AnimatorToggle.isOn) AnimatorToggle.isOn = true; } - // Disables the animator when the animation we manually triggered isn't present on the subject anymore - public bool IsPlayingSelectedAnimation(){ - if (animator != null && currentAnimation != null){ - if (stopAfterAnimationFinishes && !GetAllCurrentAnimations().Contains(currentAnimation)){ - - // Wait a frame. Otherwise, it will stop the animation immediately. - if (!skippedStopFrames){ - skippedStopFrames = true; - return false; - } - - stopAfterAnimationFinishes = false; - AnimatorToggle.isOn = false; - return true; - } - } - return false; - } - - private List GetAllCurrentAnimations(){ + private List GetAllAnimations(){ List allAnimations = new List(); for (int layer = 0; layer < animator.layerCount; layer++){ allAnimations.AddRange(animator.GetCurrentAnimatorClipInfo(layer).Select(ainfo => ainfo.clip).ToList()); @@ -108,13 +98,7 @@ namespace UnityExplorer.UI.Panels } public void ResetAnimation(){ - if (defaultAnimation != null){ - stopAfterAnimationFinishes = false; - - animator.Play(defaultAnimation.name); - AnimatorToggle.isOn = true; - defaultAnimation = null; - } + animator.runtimeAnimatorController = originalAnimatorController; } #endif @@ -124,23 +108,16 @@ namespace UnityExplorer.UI.Panels UIFactory.SetLayoutElement(AnimatorToggleObj, minHeight: 25); AnimatorToggle.isOn = true; AnimatorToggle.onValueChanged.AddListener(value => { - //ExplorerCore.LogWarning($"Animator toggled: {animator} to {animator.enabled}"); try { Type animatorClass = ReflectionUtility.GetTypeByName("UnityEngine.Animator"); - if (value) { - MethodInfo stopPlayBack = animatorClass.GetMethod("StopPlayback"); - stopPlayBack.Invoke(animator.TryCast(), null); - } else { - MethodInfo startPlayBack = animatorClass.GetMethod("StartPlayback"); - startPlayBack.Invoke(animator.TryCast(), null); - } + + PropertyInfo animatorSpeed = animatorClass.GetProperty("speed"); + animatorSpeed.SetValue(animator, value ? 1 : 0, null); } catch { // Fallback in case reflection isn't working animator.enabled = value; } - // If we play an animation and we disable the animator then don't stop the animation when it finishes after we enable the animator again - if (!value && stopAfterAnimationFinishes) stopAfterAnimationFinishes = false; } ); diff --git a/src/UI/Panels/AnimatorPanel.cs b/src/UI/Panels/AnimatorPanel.cs index 099dd7a..cd32fcf 100644 --- a/src/UI/Panels/AnimatorPanel.cs +++ b/src/UI/Panels/AnimatorPanel.cs @@ -34,8 +34,6 @@ namespace UnityExplorer.UI.Panels public override bool NavButtonWanted => true; public override bool ShouldSaveActiveState => true; - Dictionary> animationEndedFunctions = new Dictionary>(); - Toggle masterAnimatorToggle = new Toggle(); private static ScrollPool animatorScrollPool; @@ -64,7 +62,6 @@ namespace UnityExplorer.UI.Panels if (animators.Count != 0) { masterAnimatorToggle.isOn = true; // Will also trigger "MasterToggleAnimators(true)" animators.Clear(); - animationEndedFunctions.Clear(); shouldIgnoreMasterToggle.Clear(); #if MONO // TODO: Move the reset behavior to this panel, because we would only get the cells being currently displayed. @@ -125,13 +122,6 @@ namespace UnityExplorer.UI.Panels masterAnimatorToggle.isOn = !masterAnimatorToggle.isOn; } -#if MONO - public override void Update(){ - foreach (Animator animator in animators){ - animationEndedFunctions[animator](); - } - } -#endif // ~~~~~~~~ UI construction / callbacks ~~~~~~~~ protected override void ConstructPanelContent() @@ -178,7 +168,6 @@ namespace UnityExplorer.UI.Panels #if MONO cell.DrawAnimatorPlayer(); - animationEndedFunctions[animator] = cell.IsPlayingSelectedAnimation; #endif } diff --git a/src/UI/Panels/PostProcessingPanel.cs b/src/UI/Panels/PostProcessingPanel.cs index d0bcf7c..8e933f6 100644 --- a/src/UI/Panels/PostProcessingPanel.cs +++ b/src/UI/Panels/PostProcessingPanel.cs @@ -130,24 +130,25 @@ namespace UnityExplorer.UI.Panels } private void AddEffect(string baseClass, string effect){ - Type searchType = ReflectionUtility.GetTypeByName($"{baseClass}.{effect}"); - searchType = searchType is Type type ? type : searchType.GetActualType(); - List currentResults = RuntimeHelper.FindObjectsOfTypeAll(searchType).Select(obj => (object) obj).ToList(); + try { + Type searchType = ReflectionUtility.GetTypeByName($"{baseClass}.{effect}"); + searchType = searchType is Type type ? type : searchType.GetActualType(); + List currentResults = RuntimeHelper.FindObjectsOfTypeAll(searchType).Select(obj => (object) obj).ToList(); - //ExplorerCore.LogWarning($"Found {currentResults.Count()} objects for {baseClass}.{effect}"); + foreach (object obj in currentResults){ + PPEffect entry = new PPEffect(obj); + + // Ignore non-active objects and objects without a name, since those tend to be irrelevant + if ((bool) entry.Active.Value && entry.Name.Value.ToString() != ""){ + if (!postProcessingEffects.ContainsKey(effect)){ + postProcessingEffects.Add(effect, new List()); + } - foreach (object obj in currentResults){ - PPEffect entry = new PPEffect(obj); - - // Ignore non-active objects and objects without a name, since those tend to be irrelevant - if ((bool) entry.Active.Value && entry.Name.Value.ToString() != ""){ - if (!postProcessingEffects.ContainsKey(effect)){ - postProcessingEffects.Add(effect, new List()); + postProcessingEffects[effect].Add(entry); } - - postProcessingEffects[effect].Add(entry); } } + catch { ExplorerCore.Log($"Couldn't find {baseClass}.{effect}");} } private void SetEffect(bool value, List effects){