From 23a40e58e4f0534b889251b5467ca0c8c8d4380a Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Sat, 1 Jul 2023 22:02:33 +1000 Subject: [PATCH] Pause animations on ent pause (#4117) --- .../Components/Renderable/SpriteComponent.cs | 29 +-------------- .../EntitySystems/AnimationPlayerSystem.cs | 35 +++++++++++++++--- .../GameObjects/EntitySystems/SpriteSystem.cs | 36 +++++++++++++++++-- .../UserInterface/Control.Animations.cs | 21 +++++++---- 4 files changed, 79 insertions(+), 42 deletions(-) diff --git a/Robust.Client/GameObjects/Components/Renderable/SpriteComponent.cs b/Robust.Client/GameObjects/Components/Renderable/SpriteComponent.cs index 754e13bc2d..f5c2bb1ea1 100644 --- a/Robust.Client/GameObjects/Components/Renderable/SpriteComponent.cs +++ b/Robust.Client/GameObjects/Components/Renderable/SpriteComponent.cs @@ -312,7 +312,7 @@ namespace Robust.Client.GameObjects public const string LogCategory = "go.comp.sprite"; - [ViewVariables(VVAccess.ReadWrite)] public bool IsInert { get; private set; } + [ViewVariables(VVAccess.ReadWrite)] public bool IsInert { get; internal set; } void ISerializationHooks.AfterDeserialization() { @@ -1397,33 +1397,6 @@ namespace Robust.Client.GameObjects entities.EventBus.RaiseComponentEvent(this, ref ev); } - internal void DoUpdateIsInert() - { - _inertUpdateQueued = false; - IsInert = true; - - foreach (var layer in Layers) - { - // Since StateId is a struct, we can't null-check it directly. - if (!layer.State.IsValid || !layer.Visible || !layer.AutoAnimated || layer.Blank) - { - continue; - } - - var rsi = layer.RSI ?? BaseRSI; - if (rsi == null || !rsi.TryGetState(layer.State, out var state)) - { - state = GetFallbackState(resourceCache); - } - - if (state.IsAnimated) - { - IsInert = false; - break; - } - } - } - [Obsolete("Use SpriteSystem instead.")] internal static RSI.State GetFallbackState(IResourceCache cache) { diff --git a/Robust.Client/GameObjects/EntitySystems/AnimationPlayerSystem.cs b/Robust.Client/GameObjects/EntitySystems/AnimationPlayerSystem.cs index eb0cb66cc6..08acd32c03 100644 --- a/Robust.Client/GameObjects/EntitySystems/AnimationPlayerSystem.cs +++ b/Robust.Client/GameObjects/EntitySystems/AnimationPlayerSystem.cs @@ -4,6 +4,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.Utility; +using TerraFX.Interop.Windows; namespace Robust.Client.GameObjects { @@ -11,18 +12,40 @@ namespace Robust.Client.GameObjects { private readonly List _activeAnimations = new(); + private EntityQuery _metaQuery; + [Dependency] private readonly IComponentFactory _compFact = default!; [Dependency] private readonly ILogManager _logManager = default!; private ISawmill _sawmill = default!; + public override void Initialize() + { + base.Initialize(); + _metaQuery = GetEntityQuery(); + } + public override void FrameUpdate(float frameTime) { - for (var i = _activeAnimations.Count - 1; i >= 0; i--) + // TODO: Active or something idk. + for (var i = 0; i < _activeAnimations.Count; i++) { var anim = _activeAnimations[i]; - if (!Update(anim, frameTime)) continue; + var uid = anim.Owner; + + if (!_metaQuery.TryGetComponent(uid, out var metadata) || + metadata.EntityPaused) + { + continue; + } + + if (!Update(uid, anim, frameTime)) + { + continue; + } + _activeAnimations.RemoveSwap(i); + i--; anim.HasPlayingAnimation = false; } } @@ -34,16 +57,18 @@ namespace Robust.Client.GameObjects component.HasPlayingAnimation = true; } - private bool Update(AnimationPlayerComponent component, float frameTime) + private bool Update(EntityUid uid, AnimationPlayerComponent component, float frameTime) { if (component.PlayingAnimationCount == 0 || component.Deleted) + { return true; + } var remie = new RemQueue(); foreach (var (key, playback) in component.PlayingAnimations) { - var keep = AnimationPlaybackShared.UpdatePlayback(component.Owner, playback, frameTime); + var keep = AnimationPlaybackShared.UpdatePlayback(uid, playback, frameTime); if (!keep) { remie.Add(key); @@ -53,7 +78,7 @@ namespace Robust.Client.GameObjects foreach (var key in remie) { component.PlayingAnimations.Remove(key); - EntityManager.EventBus.RaiseLocalEvent(component.Owner, new AnimationCompletedEvent {Uid = component.Owner, Key = key}, true); + EntityManager.EventBus.RaiseLocalEvent(uid, new AnimationCompletedEvent {Uid = uid, Key = key}, true); component.AnimationComplete(key); } diff --git a/Robust.Client/GameObjects/EntitySystems/SpriteSystem.cs b/Robust.Client/GameObjects/EntitySystems/SpriteSystem.cs index f1ea655ea3..4cf76b9e37 100644 --- a/Robust.Client/GameObjects/EntitySystems/SpriteSystem.cs +++ b/Robust.Client/GameObjects/EntitySystems/SpriteSystem.cs @@ -91,21 +91,53 @@ namespace Robust.Client.GameObjects _inertUpdateQueue.Enqueue(sprite); } + private void DoUpdateIsInert(SpriteComponent component) + { + component._inertUpdateQueued = false; + component.IsInert = true; + + foreach (var layer in component.Layers) + { + // Since StateId is a struct, we can't null-check it directly. + if (!layer.State.IsValid || !layer.Visible || !layer.AutoAnimated || layer.Blank) + { + continue; + } + + var rsi = layer.RSI ?? component.BaseRSI; + if (rsi == null || !rsi.TryGetState(layer.State, out var state)) + { + state = GetFallbackState(); + } + + if (state.IsAnimated) + { + component.IsInert = false; + break; + } + } + } + /// public override void FrameUpdate(float frameTime) { while (_inertUpdateQueue.TryDequeue(out var sprite)) { - sprite.DoUpdateIsInert(); + DoUpdateIsInert(sprite); } var realtime = _timing.RealTime.TotalSeconds; var spriteQuery = GetEntityQuery(); var syncQuery = GetEntityQuery(); + var metaQuery = GetEntityQuery(); + foreach (var uid in _queuedFrameUpdate) { - if (!spriteQuery.TryGetComponent(uid, out var sprite)) + if (!spriteQuery.TryGetComponent(uid, out var sprite) || + metaQuery.GetComponent(uid).EntityPaused) + { continue; + } if (sprite.IsInert) continue; diff --git a/Robust.Client/UserInterface/Control.Animations.cs b/Robust.Client/UserInterface/Control.Animations.cs index b1c93310b8..6d4f6ea747 100644 --- a/Robust.Client/UserInterface/Control.Animations.cs +++ b/Robust.Client/UserInterface/Control.Animations.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using Robust.Client.Animations; +using Robust.Shared.Collections; using Robust.Shared.Timing; using static Robust.Client.Animations.AnimationPlaybackShared; @@ -45,15 +46,21 @@ namespace Robust.Client.UserInterface return; } - // TODO: Get rid of this ToArray() allocation. - foreach (var (key, playback) in _playingAnimations.ToArray()) + var toRemove = new ValueList(); + + foreach (var (key, playback) in _playingAnimations) { var keep = UpdatePlayback(this, playback, args.DeltaSeconds); - if (!keep) - { - _playingAnimations.Remove(key); - AnimationCompleted?.Invoke(key); - } + if (keep) + continue; + + toRemove.Add(key); + AnimationCompleted?.Invoke(key); + } + + foreach (var key in toRemove) + { + _playingAnimations.Remove(key); } } }