From ed1b9bde83b37ebd00457398eca59d48968eda05 Mon Sep 17 00:00:00 2001 From: TemporalOroboros Date: Thu, 18 May 2023 11:03:30 -0700 Subject: [PATCH] Resolves RadiationCollectorVisualizer is Obsolete (#13905) --- .../RadiationCollectorComponent.cs | 62 ++++++++++ .../Visualizers/RadiationCollectorSystem.cs | 109 ++++++++++++++++++ .../RadiationCollectorVisualizer.cs | 100 ---------------- .../SharedRadiationCollectorComponent.cs | 10 +- .../Generation/Singularity/collector.yml | 5 +- 5 files changed, 178 insertions(+), 108 deletions(-) create mode 100644 Content.Client/Singularity/Visualizers/RadiationCollectorComponent.cs create mode 100644 Content.Client/Singularity/Visualizers/RadiationCollectorSystem.cs delete mode 100644 Content.Client/Singularity/Visualizers/RadiationCollectorVisualizer.cs diff --git a/Content.Client/Singularity/Visualizers/RadiationCollectorComponent.cs b/Content.Client/Singularity/Visualizers/RadiationCollectorComponent.cs new file mode 100644 index 0000000000..218e10ceca --- /dev/null +++ b/Content.Client/Singularity/Visualizers/RadiationCollectorComponent.cs @@ -0,0 +1,62 @@ +using Content.Shared.Singularity.Components; +using Robust.Client.Animations; + +namespace Content.Client.Singularity.Visualizers; + +/// +/// The component used to reflect the state of a radiation collector in its appearance. +/// +[RegisterComponent] +[Access(typeof(RadiationCollectorSystem))] +public sealed class RadiationCollectorComponent : Component +{ + /// + /// The key used to index the (de)activation animations played when turning a radiation collector on/off. + /// + [ViewVariables] + public const string AnimationKey = "radiationcollector_animation"; + + /// + /// The current visual state of the radiation collector. + /// + [ViewVariables] + public RadiationCollectorVisualState CurrentState = RadiationCollectorVisualState.Deactive; + + /// + /// The RSI state used for the main sprite layer () when the radiation collector is active. + /// + [DataField("activeState")] + [ViewVariables(VVAccess.ReadWrite)] + public string ActiveState = "ca_on"; + + /// + /// The RSI state used for the main sprite layer () when the radiation collector is inactive. + /// + [DataField("inactiveState")] + [ViewVariables(VVAccess.ReadWrite)] + public string InactiveState = "ca_off"; + + /// + /// Used to build the activation animation when the component is initialized. + /// + [DataField("activatingState")] + public string ActivatingState = "ca_active"; + + /// + /// Used to build the deactivation animation when the component is initialized. + /// + [DataField("deactivatingState")] + public string DeactivatingState = "ca_deactive"; + + /// + /// The animation used when turning on the radiation collector. + /// + [ViewVariables(VVAccess.ReadWrite)] + public Animation ActivateAnimation = default!; + + /// + /// The animation used when turning off the radiation collector. + /// + [ViewVariables(VVAccess.ReadWrite)] + public Animation DeactiveAnimation = default!; +} diff --git a/Content.Client/Singularity/Visualizers/RadiationCollectorSystem.cs b/Content.Client/Singularity/Visualizers/RadiationCollectorSystem.cs new file mode 100644 index 0000000000..89c0f901b8 --- /dev/null +++ b/Content.Client/Singularity/Visualizers/RadiationCollectorSystem.cs @@ -0,0 +1,109 @@ +using System; +using Content.Shared.Singularity.Components; +using Robust.Client.Animations; +using Robust.Client.GameObjects; + +namespace Content.Client.Singularity.Visualizers; + +public sealed class RadiationCollectorSystem : VisualizerSystem +{ + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent(OnAnimationCompleted); + } + + private void OnComponentInit(EntityUid uid, RadiationCollectorComponent comp, ComponentInit args) + { + comp.ActivateAnimation = new Animation { + Length = TimeSpan.FromSeconds(0.8f), + AnimationTracks = { + new AnimationTrackSpriteFlick() { + LayerKey = RadiationCollectorVisualLayers.Main, + KeyFrames = {new AnimationTrackSpriteFlick.KeyFrame(comp.ActivatingState, 0f)} + }, // TODO: Make this play a sound when activating a radiation collector. + } + }; + + comp.DeactiveAnimation = new Animation { + Length = TimeSpan.FromSeconds(0.8f), + AnimationTracks = { + new AnimationTrackSpriteFlick() { + LayerKey = RadiationCollectorVisualLayers.Main, + KeyFrames = {new AnimationTrackSpriteFlick.KeyFrame(comp.DeactivatingState, 0f)} + }, // TODO: Make this play a sound when deactivating a radiation collector. + } + }; + } + + private void UpdateVisuals(EntityUid uid, RadiationCollectorVisualState state, RadiationCollectorComponent comp, SpriteComponent sprite, AnimationPlayerComponent? animPlayer = null) + { + if (state == comp.CurrentState) + return; + if (!Resolve(uid, ref animPlayer)) + return; + if (AnimationSystem.HasRunningAnimation(uid, animPlayer, RadiationCollectorComponent.AnimationKey)) + return; + + var targetState = (RadiationCollectorVisualState) (state & RadiationCollectorVisualState.Active); + var destinationState = (RadiationCollectorVisualState) (comp.CurrentState & RadiationCollectorVisualState.Active); + if (targetState != destinationState) // If where we're going is not where we want to be then we must go there next. + targetState = (RadiationCollectorVisualState) (targetState | RadiationCollectorVisualState.Deactivating); // Convert to transition state. + + comp.CurrentState = state; + + switch (targetState) + { + case RadiationCollectorVisualState.Activating: + AnimationSystem.Play(uid, animPlayer, comp.ActivateAnimation, RadiationCollectorComponent.AnimationKey); + break; + case RadiationCollectorVisualState.Deactivating: + AnimationSystem.Play(uid, animPlayer, comp.DeactiveAnimation, RadiationCollectorComponent.AnimationKey); + break; + + case RadiationCollectorVisualState.Active: + sprite.LayerSetState(RadiationCollectorVisualLayers.Main, comp.ActiveState); + break; + case RadiationCollectorVisualState.Deactive: + sprite.LayerSetState(RadiationCollectorVisualLayers.Main, comp.InactiveState); + break; + } + } + + private void OnAnimationCompleted(EntityUid uid, RadiationCollectorComponent comp, AnimationCompletedEvent args) + { + if (args.Key != RadiationCollectorComponent.AnimationKey) + return; + if (!TryComp(uid, out var sprite)) + return; + if (!TryComp(uid, out var animPlayer)) + return; // Why doesn't AnimationCompletedEvent propagate the AnimationPlayerComponent? No idea, but it's in engine so I'm not touching it. + + if (!AppearanceSystem.TryGetData(uid, RadiationCollectorVisuals.VisualState, out var state)) + state = comp.CurrentState; + + // Convert to terminal state. + var targetState = (RadiationCollectorVisualState) (state & RadiationCollectorVisualState.Active); + + UpdateVisuals(uid, targetState, comp, sprite, animPlayer); + } + + protected override void OnAppearanceChange(EntityUid uid, RadiationCollectorComponent comp, ref AppearanceChangeEvent args) + { + if (args.Sprite == null) + return; + if (!TryComp(uid, out var animPlayer)) + return; + + if (!AppearanceSystem.TryGetData(uid, RadiationCollectorVisuals.VisualState, out var state, args.Component)) + state = RadiationCollectorVisualState.Deactive; + + UpdateVisuals(uid, state, comp, args.Sprite, animPlayer); + } +} + +public enum RadiationCollectorVisualLayers : byte +{ + Main +} diff --git a/Content.Client/Singularity/Visualizers/RadiationCollectorVisualizer.cs b/Content.Client/Singularity/Visualizers/RadiationCollectorVisualizer.cs deleted file mode 100644 index a801910906..0000000000 --- a/Content.Client/Singularity/Visualizers/RadiationCollectorVisualizer.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using Content.Shared.Singularity.Components; -using JetBrains.Annotations; -using Robust.Client.Animations; -using Robust.Client.GameObjects; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Serialization; - -namespace Content.Client.Singularity.Visualizers -{ - [UsedImplicitly] - public sealed class RadiationCollectorVisualizer : AppearanceVisualizer, ISerializationHooks - { - private const string AnimationKey = "radiationcollector_animation"; - - private Animation ActivateAnimation = default!; - private Animation DeactiveAnimation = default!; - - void ISerializationHooks.AfterDeserialization() - { - ActivateAnimation = new Animation {Length = TimeSpan.FromSeconds(0.8f)}; - { - var flick = new AnimationTrackSpriteFlick(); - ActivateAnimation.AnimationTracks.Add(flick); - flick.LayerKey = RadiationCollectorVisualLayers.Main; - flick.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("ca_active", 0f)); - - /*var sound = new AnimationTrackPlaySound(); - CloseAnimation.AnimationTracks.Add(sound); - sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(closeSound, 0));*/ - } - - DeactiveAnimation = new Animation {Length = TimeSpan.FromSeconds(0.8f)}; - { - var flick = new AnimationTrackSpriteFlick(); - DeactiveAnimation.AnimationTracks.Add(flick); - flick.LayerKey = RadiationCollectorVisualLayers.Main; - flick.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("ca_deactive", 0f)); - - /*var sound = new AnimationTrackPlaySound(); - CloseAnimation.AnimationTracks.Add(sound); - sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(closeSound, 0));*/ - } - } - - [Obsolete("Subscribe to your component being initialised instead.")] - public override void InitializeEntity(EntityUid entity) - { - IoCManager.Resolve().EnsureComponent(entity); - } - - [Obsolete("Subscribe to AppearanceChangeEvent instead.")] - public override void OnChangeData(AppearanceComponent component) - { - base.OnChangeData(component); - - var entities = IoCManager.Resolve(); - if (!entities.TryGetComponent(component.Owner, out SpriteComponent? sprite)) return; - if (!entities.TryGetComponent(component.Owner, out AnimationPlayerComponent? animPlayer)) return; - if (!component.TryGetData(RadiationCollectorVisuals.VisualState, out RadiationCollectorVisualState state)) - { - state = RadiationCollectorVisualState.Deactive; - } - - switch (state) - { - case RadiationCollectorVisualState.Active: - sprite.LayerSetState(RadiationCollectorVisualLayers.Main, "ca_on"); - break; - case RadiationCollectorVisualState.Activating: - if (!animPlayer.HasRunningAnimation(AnimationKey)) - { - animPlayer.Play(ActivateAnimation, AnimationKey); - animPlayer.AnimationCompleted += _ => - component.SetData(RadiationCollectorVisuals.VisualState, - RadiationCollectorVisualState.Active); - } - break; - case RadiationCollectorVisualState.Deactivating: - if (!animPlayer.HasRunningAnimation(AnimationKey)) - { - animPlayer.Play(DeactiveAnimation, AnimationKey); - animPlayer.AnimationCompleted += _ => - component.SetData(RadiationCollectorVisuals.VisualState, - RadiationCollectorVisualState.Deactive); - } - break; - case RadiationCollectorVisualState.Deactive: - sprite.LayerSetState(RadiationCollectorVisualLayers.Main, "ca_off"); - break; - } - } - } - - public enum RadiationCollectorVisualLayers : byte - { - Main - } -} diff --git a/Content.Shared/Singularity/Components/SharedRadiationCollectorComponent.cs b/Content.Shared/Singularity/Components/SharedRadiationCollectorComponent.cs index 0553cc4054..44cdea4fb6 100644 --- a/Content.Shared/Singularity/Components/SharedRadiationCollectorComponent.cs +++ b/Content.Shared/Singularity/Components/SharedRadiationCollectorComponent.cs @@ -10,10 +10,10 @@ namespace Content.Shared.Singularity.Components [NetSerializable, Serializable] public enum RadiationCollectorVisualState - { - Active, - Activating, - Deactivating, - Deactive + { + Active = (1<<0), + Activating = (1<<1) | Active, + Deactivating = (1<<1), + Deactive = 0 } } diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/collector.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/collector.yml index 301d524973..d4d7979bfd 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/collector.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/collector.yml @@ -28,11 +28,10 @@ netsync: false snapCardinals: true layers: - - state: ca_on + - state: ca_off map: ["enum.RadiationCollectorVisualLayers.Main"] - type: Appearance - visuals: - - type: RadiationCollectorVisualizer + - type: AnimationPlayer - type: NodeContainer examinable: true nodes: