diff --git a/src/Cinematic/AnimatorUI/AnimatorCell.cs b/src/Cinematic/AnimatorUI/AnimatorCell.cs index 7c6e4b9..e06b1d2 100644 --- a/src/Cinematic/AnimatorUI/AnimatorCell.cs +++ b/src/Cinematic/AnimatorUI/AnimatorCell.cs @@ -11,7 +11,6 @@ namespace UnityExplorer.UI.Panels { public class AnimatorCell : ICell { - private bool autoIgnoreMasterToggleSet; public Toggle IgnoreMasterToggle; public Toggle AnimatorToggle; @@ -28,10 +27,10 @@ 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 - ButtonRef playButton; - private bool manuallyPlayedAnimation; private bool skippedStopFrames; + ButtonRef playButton; private AnimationClip currentAnimation; private AnimationClip defaultAnimation; @@ -67,22 +66,23 @@ namespace UnityExplorer.UI.Panels skippedStopFrames = false; + stopAfterAnimationFinishes = !AnimatorToggle.isOn; AnimatorToggle.isOn = true; - manuallyPlayedAnimation = true; animator.Play(currentAnimation.name); } // Disables the animator when the animation we manually triggered isn't present on the subject anymore public bool IsPlayingSelectedAnimation(){ - if (animator != null && currentAnimation != null && name.text == "Player"){ - if (manuallyPlayedAnimation && !GetAllCurrentAnimations().Contains(currentAnimation)){ - + 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; } - manuallyPlayedAnimation = false; + stopAfterAnimationFinishes = false; AnimatorToggle.isOn = false; return true; } @@ -100,7 +100,7 @@ namespace UnityExplorer.UI.Panels public void ResetAnimation(){ if (defaultAnimation != null){ - manuallyPlayedAnimation = false; + stopAfterAnimationFinishes = false; animator.Play(defaultAnimation.name); AnimatorToggle.isOn = true; @@ -109,21 +109,18 @@ namespace UnityExplorer.UI.Panels } #endif - // If it's the first time we are rendering the AnimatorCell, assign the ignore value automatically based on it's name - public void MaybeSetIgnoreMasterToggleSet(){ - if (animator != null && !autoIgnoreMasterToggleSet){ - // A weird canse insensitive "Contains" to identify the player - IgnoreMasterToggle.isOn = animator.gameObject.name.IndexOf("play", 0, StringComparison.OrdinalIgnoreCase) >= 0; - autoIgnoreMasterToggleSet = true; - } - } - public virtual GameObject CreateContent(GameObject parent) { GameObject AnimatorToggleObj = UIFactory.CreateToggle(parent, $"AnimatorToggle", out AnimatorToggle, out Text animatorToggleText); UIFactory.SetLayoutElement(AnimatorToggleObj, minHeight: 25); AnimatorToggle.isOn = true; - AnimatorToggle.onValueChanged.AddListener(value => animator.enabled = value); + AnimatorToggle.onValueChanged.AddListener(value => { + //ExplorerCore.LogWarning($"Animator toggled: {animator} to {animator.enabled}"); + 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; + } + ); UIRoot = AnimatorToggleObj; UIRoot.SetActive(false); @@ -148,9 +145,18 @@ namespace UnityExplorer.UI.Panels GameObject ignoresMasterTogglerObj = UIFactory.CreateToggle(UIRoot, $"AnimatorIgnoreMasterToggle", out IgnoreMasterToggle, out Text ignoreMasterToggleText); UIFactory.SetLayoutElement(ignoresMasterTogglerObj, minHeight: 25); IgnoreMasterToggle.isOn = false; + IgnoreMasterToggle.onValueChanged.AddListener(IgnoreMasterToggle_Clicked); ignoreMasterToggleText.text = "Ignore Master Toggle "; return UIRoot; } + + internal void IgnoreMasterToggle_Clicked(bool value){ + GetAnimatorPanel().shouldIgnoreMasterToggle[animator] = value; + } + + public UnityExplorer.UI.Panels.AnimatorPanel GetAnimatorPanel(){ + return UIManager.GetPanel(UIManager.Panels.AnimatorPanel); + } } } diff --git a/src/UI/Panels/AnimatorPanel.cs b/src/UI/Panels/AnimatorPanel.cs index 09ff26e..8aee48c 100644 --- a/src/UI/Panels/AnimatorPanel.cs +++ b/src/UI/Panels/AnimatorPanel.cs @@ -19,7 +19,7 @@ using Animator = UnityEngine.Behaviour; namespace UnityExplorer.UI.Panels { - internal class AnimatorPanel : UEPanel, ICellPoolDataSource + public class AnimatorPanel : UEPanel, ICellPoolDataSource { public AnimatorPanel(UIBase owner) : base(owner) { @@ -27,7 +27,7 @@ namespace UnityExplorer.UI.Panels public override string Name => "Animator"; public override UIManager.Panels PanelType => UIManager.Panels.AnimatorPanel; - public override int MinWidth => 500; + public override int MinWidth => 750; public override int MinHeight => 200; public override Vector2 DefaultAnchorMin => new(0.4f, 0.4f); public override Vector2 DefaultAnchorMax => new(0.6f, 0.6f); @@ -40,6 +40,7 @@ namespace UnityExplorer.UI.Panels private static ScrollPool animatorScrollPool; internal List animators = new List(); + public Dictionary shouldIgnoreMasterToggle = new Dictionary(); public int ItemCount => animators.Count; private static bool DoneScrollPoolInit; @@ -64,7 +65,9 @@ namespace UnityExplorer.UI.Panels 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. foreach (AnimatorCell animatorCell in animatorScrollPool.CellPool) { animatorCell.ResetAnimation(); @@ -79,18 +82,30 @@ namespace UnityExplorer.UI.Panels .OrderBy(x=>x.name) .ToList(); + foreach(Animator animator in animators){ + shouldIgnoreMasterToggle[animator] = animator.gameObject.name.IndexOf("play", 0, StringComparison.OrdinalIgnoreCase) >= 0; + } + animatorScrollPool.Refresh(true, false); } public void MasterToggleAnimators(bool enable){ // Load animators for the first time if there are not any if (animators.Count == 0) FindAllAnimators(); + foreach (AnimatorCell animatorCell in animatorScrollPool.CellPool) { if (animatorCell.animator != null && !animatorCell.IgnoreMasterToggle.isOn){ animatorCell.AnimatorToggle.isOn = enable; } } + + // We gotta do this for the animators which cell are not being currently rendered. + foreach (Animator animator in animators){ + if (!shouldIgnoreMasterToggle[animator]){ + animator.enabled = enable; + } + } } public void HotkeyToggleAnimators(){ @@ -146,8 +161,8 @@ namespace UnityExplorer.UI.Panels cell.animator = animator; cell.name.text = animator.gameObject.name; + cell.IgnoreMasterToggle.isOn = shouldIgnoreMasterToggle[animator]; - cell.MaybeSetIgnoreMasterToggleSet(); #if MONO cell.DrawAnimatorPlayer(); animationEndedFunctions[animator] = cell.IsPlayingSelectedAnimation; diff --git a/src/UI/Panels/FreeCamPanel.cs b/src/UI/Panels/FreeCamPanel.cs index 4938876..92af091 100644 --- a/src/UI/Panels/FreeCamPanel.cs +++ b/src/UI/Panels/FreeCamPanel.cs @@ -367,7 +367,7 @@ namespace UnityExplorer.UI.Panels $"- {ConfigManager.HUD_Toggle.Value}: HUD toggle\n" + $"- {ConfigManager.Pause.Value}: Pause\n" + $"- {ConfigManager.Frameskip.Value}: Frameskip\n" + - $"- {ConfigManager.Toggle_Animations.Value}: Toggle NPC animations"; + $"- {ConfigManager.Toggle_Animations.Value}: Toggle NPC animations\n"; if (ConfigManager.Frameskip.Value != KeyCode.None) instructions = instructions + $"- {ConfigManager.Screenshot.Value}: Screenshot\n";