Resolve PoweredLightVisualizer is Obsolete (#13891)

This commit is contained in:
TemporalOroboros
2023-02-15 20:10:41 -08:00
committed by GitHub
parent 8f95ffe920
commit 6b381f7304
5 changed files with 192 additions and 141 deletions

View File

@@ -1,131 +0,0 @@
using Content.Shared.Light;
using JetBrains.Annotations;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Shared.Animations;
using Robust.Shared.Audio;
using Robust.Shared.Random;
namespace Content.Client.Light.Visualizers
{
[UsedImplicitly]
public sealed class PoweredLightVisualizer : AppearanceVisualizer
{
[DataField("minBlinkingTime")] private float _minBlinkingTime = 0.5f;
[DataField("maxBlinkingTime")] private float _maxBlinkingTime = 2;
[DataField("blinkingSound")] private SoundSpecifier? _blinkingSound = default;
private bool _wasBlinking;
private Action<string>? _blinkingCallback;
[Obsolete("Subscribe to AppearanceChangeEvent instead.")]
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);
var entities = IoCManager.Resolve<IEntityManager>();
if (!entities.TryGetComponent(component.Owner, out SpriteComponent? sprite)) return;
if (!component.TryGetData(PoweredLightVisuals.BulbState, out PoweredLightState state)) return;
switch (state)
{
case PoweredLightState.Empty:
sprite.LayerSetState(PoweredLightLayers.Base, "empty");
ToggleBlinkingAnimation(component, false);
break;
case PoweredLightState.Off:
sprite.LayerSetState(PoweredLightLayers.Base, "off");
ToggleBlinkingAnimation(component, false);
break;
case PoweredLightState.On:
if (component.TryGetData(PoweredLightVisuals.Blinking, out bool isBlinking))
ToggleBlinkingAnimation(component, isBlinking);
if (!isBlinking)
{
sprite.LayerSetState(PoweredLightLayers.Base, "on");
}
break;
case PoweredLightState.Broken:
sprite.LayerSetState(PoweredLightLayers.Base, "broken");
ToggleBlinkingAnimation(component, false);
break;
case PoweredLightState.Burned:
sprite.LayerSetState(PoweredLightLayers.Base, "burn");
ToggleBlinkingAnimation(component, false);
break;
}
}
private void ToggleBlinkingAnimation(AppearanceComponent component, bool isBlinking)
{
if (isBlinking == _wasBlinking)
return;
_wasBlinking = isBlinking;
component.Owner.EnsureComponent(out AnimationPlayerComponent animationPlayer);
if (isBlinking)
{
_blinkingCallback = (animName) => animationPlayer.Play(BlinkingAnimation(), "blinking");
animationPlayer.AnimationCompleted += _blinkingCallback;
animationPlayer.Play(BlinkingAnimation(), "blinking");
}
else if (animationPlayer.HasRunningAnimation("blinking"))
{
if (_blinkingCallback != null)
animationPlayer.AnimationCompleted -= _blinkingCallback;
animationPlayer.Stop("blinking");
}
}
private Animation BlinkingAnimation()
{
var random = IoCManager.Resolve<IRobustRandom>();
var randomTime = random.NextFloat() *
(_maxBlinkingTime - _minBlinkingTime) + _minBlinkingTime;
var blinkingAnim = new Animation()
{
Length = TimeSpan.FromSeconds(randomTime),
AnimationTracks =
{
new AnimationTrackComponentProperty
{
ComponentType = typeof(PointLightComponent),
InterpolationMode = AnimationInterpolationMode.Nearest,
Property = nameof(PointLightComponent.Enabled),
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(false, 0),
new AnimationTrackProperty.KeyFrame(true, 1)
}
},
new AnimationTrackSpriteFlick()
{
LayerKey = PoweredLightLayers.Base,
KeyFrames =
{
new AnimationTrackSpriteFlick.KeyFrame("off", 0),
new AnimationTrackSpriteFlick.KeyFrame("on", 0.5f)
}
}
}
};
if (_blinkingSound != null)
{
blinkingAnim.AnimationTracks.Add(new AnimationTrackPlaySound()
{
KeyFrames =
{
new AnimationTrackPlaySound.KeyFrame(_blinkingSound.GetSound(), 0.5f)
}
});
}
return blinkingAnim;
}
}
}

View File

@@ -0,0 +1,125 @@
using Content.Shared.Light;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Shared.Animations;
using Robust.Shared.Random;
namespace Content.Client.Light.Visualizers;
public sealed class PoweredLightVisualizerSystem : VisualizerSystem<PoweredLightVisualsComponent>
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PoweredLightVisualsComponent, AnimationCompletedEvent>(OnAnimationCompleted);
}
protected override void OnAppearanceChange(EntityUid uid, PoweredLightVisualsComponent comp, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
return;
if (!AppearanceSystem.TryGetData<PoweredLightState>(uid, PoweredLightVisuals.BulbState, out var state, args.Component))
return;
if (comp.SpriteStateMap.TryGetValue(state, out var spriteState))
args.Sprite.LayerSetState(PoweredLightLayers.Base, spriteState);
SetBlinkingAnimation(
uid,
state == PoweredLightState.On
&& (AppearanceSystem.TryGetData<bool>(uid, PoweredLightVisuals.Blinking, out var isBlinking, args.Component) && isBlinking),
comp
);
}
/// <summary>
/// Loops the blinking animation until the light should stop blinking.
/// </summary>
private void OnAnimationCompleted(EntityUid uid, PoweredLightVisualsComponent comp, AnimationCompletedEvent args)
{
if (args.Key != PoweredLightVisualsComponent.BlinkingAnimationKey)
return;
if(!comp.IsBlinking)
return;
AnimationSystem.Play(uid, Comp<AnimationPlayerComponent>(uid), BlinkingAnimation(comp), PoweredLightVisualsComponent.BlinkingAnimationKey);
}
/// <summary>
/// Sets whether or not the given light should be blinking.
/// Triggers or clears the blinking animation of the state changes.
/// </summary>
private void SetBlinkingAnimation(EntityUid uid, bool shouldBeBlinking, PoweredLightVisualsComponent comp)
{
if (shouldBeBlinking == comp.IsBlinking)
return;
comp.IsBlinking = shouldBeBlinking;
var animationPlayer = EnsureComp<AnimationPlayerComponent>(uid);
if (shouldBeBlinking)
{
AnimationSystem.Play(uid, animationPlayer, BlinkingAnimation(comp), PoweredLightVisualsComponent.BlinkingAnimationKey);
}
else if (AnimationSystem.HasRunningAnimation(uid, animationPlayer, PoweredLightVisualsComponent.BlinkingAnimationKey))
{
AnimationSystem.Stop(uid, animationPlayer, PoweredLightVisualsComponent.BlinkingAnimationKey);
}
}
/// <summary>
/// Generates a blinking animation.
/// Essentially just flashes the light off and on over a random time interval.
/// The resulting animation is looped indefinitely until the comp is set to stop blinking.
/// </summary>
private Animation BlinkingAnimation(PoweredLightVisualsComponent comp)
{
var randomTime = MathHelper.Lerp(comp.MinBlinkingAnimationCycleTime, comp.MaxBlinkingAnimationCycleTime, _random.NextFloat());
var blinkingAnim = new Animation()
{
Length = TimeSpan.FromSeconds(randomTime),
AnimationTracks =
{
new AnimationTrackComponentProperty
{
ComponentType = typeof(PointLightComponent),
InterpolationMode = AnimationInterpolationMode.Nearest,
Property = nameof(PointLightComponent.Enabled),
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(false, 0),
new AnimationTrackProperty.KeyFrame(true, 1)
}
},
new AnimationTrackSpriteFlick()
{
LayerKey = PoweredLightLayers.Base,
KeyFrames =
{
new AnimationTrackSpriteFlick.KeyFrame(comp.SpriteStateMap[PoweredLightState.Off], 0),
new AnimationTrackSpriteFlick.KeyFrame(comp.SpriteStateMap[PoweredLightState.On], 0.5f)
}
}
}
};
if (comp.BlinkingSound != null)
{
var sound = _audio.GetSound(comp.BlinkingSound);
blinkingAnim.AnimationTracks.Add(new AnimationTrackPlaySound()
{
KeyFrames =
{
new AnimationTrackPlaySound.KeyFrame(sound, 0.5f)
}
});
}
return blinkingAnim;
}
}

View File

@@ -0,0 +1,60 @@
using Content.Shared.Light;
using Robust.Shared.Audio;
namespace Content.Client.Light.Visualizers;
[RegisterComponent]
[Access(typeof(PoweredLightVisualizerSystem))]
public sealed class PoweredLightVisualsComponent : Component
{
/// <summary>
/// A map of the sprite states used by this visualizer indexed by the light state they correspond to.
/// </summary>
[DataField("spriteStateMap")]
[ViewVariables(VVAccess.ReadOnly)]
public readonly Dictionary<PoweredLightState, string> SpriteStateMap = new()
{
[PoweredLightState.Empty] = "empty",
[PoweredLightState.Off] = "off",
[PoweredLightState.On] = "on",
[PoweredLightState.Broken] = "broken",
[PoweredLightState.Burned] = "burn",
};
#region Blinking
/// <summary>
/// The id used to track the blinking animation for lights.
/// </summary>
[ViewVariables(VVAccess.ReadOnly)]
public const string BlinkingAnimationKey = "poweredlight_blinking";
/// <summary>
/// The minimum length of the base blinking animation (one on-off-on cycle) in seconds.
/// </summary>
[DataField("minBlinkingTime")]
[ViewVariables(VVAccess.ReadWrite)]
public float MinBlinkingAnimationCycleTime = 0.5f;
/// <summary>
/// The maximum length of the base blinking animation (one on-off-on cycle) in seconds.
/// </summary>
[DataField("maxBlinkingTime")]
[ViewVariables(VVAccess.ReadWrite)]
public float MaxBlinkingAnimationCycleTime = 2;
/// <summary>
/// The sound that plays when the blinking animation cycles.
/// </summary>
[DataField("blinkingSound")]
[ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier? BlinkingSound = default;
/// <summary>
/// Whether or not this light is currently blinking.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public bool IsBlinking;
#endregion Blinking
}

View File

@@ -90,10 +90,9 @@
receiveFrequencyId: SmartLight receiveFrequencyId: SmartLight
- type: ApcNetworkConnection - type: ApcNetworkConnection
- type: Appearance - type: Appearance
visuals: - type: PoweredLightVisuals
- type: PoweredLightVisualizer blinkingSound:
blinkingSound: path: "/Audio/Machines/light_tube_on.ogg"
path: "/Audio/Machines/light_tube_on.ogg"
- type: SignalReceiver - type: SignalReceiver
inputs: inputs:
On: [] On: []
@@ -263,8 +262,7 @@
receiveFrequencyId: SmartLight receiveFrequencyId: SmartLight
- type: ApcNetworkConnection - type: ApcNetworkConnection
- type: Appearance - type: Appearance
visuals: - type: PoweredLightVisuals
- type: PoweredLightVisualizer
- type: SignalReceiver - type: SignalReceiver
inputs: inputs:
On: [] On: []

View File

@@ -91,10 +91,9 @@
graph: LightFixture graph: LightFixture
node: groundLight node: groundLight
- type: Appearance - type: Appearance
visuals: - type: PoweredLightVisuals
- type: PoweredLightVisualizer blinkingSound:
blinkingSound: path: "/Audio/Machines/light_tube_on.ogg"
path: "/Audio/Machines/light_tube_on.ogg"
- type: SignalReceiver - type: SignalReceiver
inputs: inputs:
On: [] On: []