Skip to content

Commit

Permalink
Ports Fixes to some Looping Systems, LightBehaviorSystem Refactor Fro…
Browse files Browse the repository at this point in the history
…m Wizden (#1552)

# Description

Ports over these commits from Wizden:

space-wizards/space-station-14@32e315c

space-wizards/space-station-14@8d015f5
Namely the first is a general refactor to LightBehaviorSystem and the
second is a bugfix that fixes some looping behaviors like the low
battery effect on a flashlight never stopping. If it's not atomic
enough, let me know and I can separate them into two.

# Changelog

:cl:
- fix: Fixed some errors with looping behaviors like jitter.
  • Loading branch information
VMSolidus authored Jan 17, 2025
2 parents 7ce8023 + 1885d33 commit ea9f7cb
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 169 deletions.
3 changes: 3 additions & 0 deletions Content.Client/Jittering/JitteringSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ private void OnAnimationCompleted(EntityUid uid, JitteringComponent jittering, A
if (args.Key != _jitterAnimationKey || jittering.LifeStage >= ComponentLifeStage.Stopping)
return;

if (!args.Finished)
return;

if (TryComp(uid, out AnimationPlayerComponent? animationPlayer)
&& TryComp(uid, out SpriteComponent? sprite))
_animationPlayer.Play(uid, animationPlayer, GetAnimation(jittering, sprite), _jitterAnimationKey);
Expand Down
163 changes: 10 additions & 153 deletions Content.Client/Light/Components/LightBehaviourComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public void UpdatePlaybackValues(Animation owner)

if (MinDuration > 0)
{
MaxTime = (float) _random.NextDouble() * (MaxDuration - MinDuration) + MinDuration;
MaxTime = (float)_random.NextDouble() * (MaxDuration - MinDuration) + MinDuration;
}
else
{
Expand Down Expand Up @@ -192,11 +192,11 @@ public override (int KeyFrameIndex, float FramePlayingTime) AdvancePlayback(
{
if (interpolateValue < 0.5f)
{
ApplyInterpolation(StartValue, EndValue, interpolateValue*2);
ApplyInterpolation(StartValue, EndValue, interpolateValue * 2);
}
else
{
ApplyInterpolation(EndValue, StartValue, (interpolateValue-0.5f)*2);
ApplyInterpolation(EndValue, StartValue, (interpolateValue - 0.5f) * 2);
}
}
else
Expand Down Expand Up @@ -238,9 +238,9 @@ public sealed partial class RandomizeBehaviour : LightBehaviourAnimationTrack

public override void OnInitialize()
{
_randomValue1 = (float) InterpolateLinear(StartValue, EndValue, (float) _random.NextDouble());
_randomValue2 = (float) InterpolateLinear(StartValue, EndValue, (float) _random.NextDouble());
_randomValue3 = (float) InterpolateLinear(StartValue, EndValue, (float) _random.NextDouble());
_randomValue1 = (float)InterpolateLinear(StartValue, EndValue, (float) _random.NextDouble());
_randomValue2 = (float)InterpolateLinear(StartValue, EndValue, (float) _random.NextDouble());
_randomValue3 = (float)InterpolateLinear(StartValue, EndValue, (float) _random.NextDouble());
}

public override void OnStart()
Expand All @@ -258,7 +258,7 @@ public override void OnStart()
}

_randomValue3 = _randomValue4;
_randomValue4 = (float) InterpolateLinear(StartValue, EndValue, (float) _random.NextDouble());
_randomValue4 = (float)InterpolateLinear(StartValue, EndValue, (float) _random.NextDouble());
}

public override (int KeyFrameIndex, float FramePlayingTime) AdvancePlayback(
Expand Down Expand Up @@ -362,7 +362,7 @@ public sealed partial class LightBehaviourComponent : SharedLightBehaviourCompon
[Dependency] private readonly IEntityManager _entMan = default!;
[Dependency] private readonly IRobustRandom _random = default!;

private const string KeyPrefix = nameof(LightBehaviourComponent);
public const string KeyPrefix = nameof(LightBehaviourComponent);

public sealed class AnimationContainer
{
Expand All @@ -387,7 +387,7 @@ public AnimationContainer(int key, Animation animation, LightBehaviourAnimationT
public readonly List<AnimationContainer> Animations = new();

[ViewVariables(VVAccess.ReadOnly)]
private Dictionary<string, object> _originalPropertyValues = new();
public Dictionary<string, object> OriginalPropertyValues = new();

void ISerializationHooks.AfterDeserialization()
{
Expand All @@ -397,155 +397,12 @@ void ISerializationHooks.AfterDeserialization()
{
var animation = new Animation()
{
AnimationTracks = {behaviour}
AnimationTracks = { behaviour }
};

Animations.Add(new AnimationContainer(key, animation, behaviour));
key++;
}
}

/// <summary>
/// If we disable all the light behaviours we want to be able to revert the light to its original state.
/// </summary>
private void CopyLightSettings(EntityUid uid, string property)
{
if (_entMan.TryGetComponent(uid, out PointLightComponent? light))
{
var propertyValue = AnimationHelper.GetAnimatableProperty(light, property);
if (propertyValue != null)
{
_originalPropertyValues.Add(property, propertyValue);
}
}
else
{
Logger.Warning($"{_entMan.GetComponent<MetaDataComponent>(uid).EntityName} has a {nameof(LightBehaviourComponent)} but it has no {nameof(PointLightComponent)}! Check the prototype!");
}
}

/// <summary>
/// Start animating a light behaviour with the specified ID. If the specified ID is empty, it will start animating all light behaviour entries.
/// If specified light behaviours are already animating, calling this does nothing.
/// Multiple light behaviours can have the same ID.
/// </summary>
public void StartLightBehaviour(string id = "")
{
var uid = Owner;
if (!_entMan.TryGetComponent(uid, out AnimationPlayerComponent? animation))
{
return;
}

var animations = _entMan.System<AnimationPlayerSystem>();

foreach (var container in Animations)
{
if (container.LightBehaviour.ID == id || id == string.Empty)
{
if (!animations.HasRunningAnimation(uid, animation, KeyPrefix + container.Key))
{
CopyLightSettings(uid, container.LightBehaviour.Property);
container.LightBehaviour.UpdatePlaybackValues(container.Animation);
animations.Play(uid, animation, container.Animation, KeyPrefix + container.Key);
}
}
}
}

/// <summary>
/// If any light behaviour with the specified ID is animating, then stop it.
/// If no ID is specified then all light behaviours will be stopped.
/// Multiple light behaviours can have the same ID.
/// </summary>
/// <param name="id"></param>
/// <param name="removeBehaviour">Should the behaviour(s) also be removed permanently?</param>
/// <param name="resetToOriginalSettings">Should the light have its original settings applied?</param>
public void StopLightBehaviour(string id = "", bool removeBehaviour = false, bool resetToOriginalSettings = false)
{
var uid = Owner;
if (!_entMan.TryGetComponent(uid, out AnimationPlayerComponent? animation))
{
return;
}

var toRemove = new List<AnimationContainer>();
var animations = _entMan.System<AnimationPlayerSystem>();

foreach (var container in Animations)
{
if (container.LightBehaviour.ID == id || id == string.Empty)
{
if (animations.HasRunningAnimation(uid, animation, KeyPrefix + container.Key))
{
animations.Stop(uid, animation, KeyPrefix + container.Key);
}

if (removeBehaviour)
{
toRemove.Add(container);
}
}
}

foreach (var container in toRemove)
{
Animations.Remove(container);
}

if (resetToOriginalSettings && _entMan.TryGetComponent(uid, out PointLightComponent? light))
{
foreach (var (property, value) in _originalPropertyValues)
{
AnimationHelper.SetAnimatableProperty(light, property, value);
}
}

_originalPropertyValues.Clear();
}

/// <summary>
/// Checks if at least one behaviour is running.
/// </summary>
/// <returns>Whether at least one behaviour is running, false if none is.</returns>
public bool HasRunningBehaviours()
{
var uid = Owner;
if (!_entMan.TryGetComponent(uid, out AnimationPlayerComponent? animation))
{
return false;
}

var animations = _entMan.System<AnimationPlayerSystem>();
return Animations.Any(container => animations.HasRunningAnimation(uid, animation, KeyPrefix + container.Key));
}

/// <summary>
/// Add a new light behaviour to the component and start it immediately unless otherwise specified.
/// </summary>
public void AddNewLightBehaviour(LightBehaviourAnimationTrack behaviour, bool playImmediately = true)
{
var key = 0;

while (Animations.Any(x => x.Key == key))
{
key++;
}

var animation = new Animation()
{
AnimationTracks = {behaviour}
};

behaviour.Initialize(Owner, _random, _entMan);

var container = new AnimationContainer(key, animation, behaviour);
Animations.Add(container);

if (playImmediately)
{
StartLightBehaviour(behaviour.ID);
}
}
}
}
5 changes: 3 additions & 2 deletions Content.Client/Light/EntitySystems/ExpendableLightSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public sealed class ExpendableLightSystem : VisualizerSystem<ExpendableLightComp
{
[Dependency] private readonly PointLightSystem _pointLightSystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly LightBehaviorSystem _lightBehavior = default!;

public override void Initialize()
{
Expand All @@ -32,11 +33,11 @@ protected override void OnAppearanceChange(EntityUid uid, ExpendableLightCompone
if (AppearanceSystem.TryGetData<string>(uid, ExpendableLightVisuals.Behavior, out var lightBehaviourID, args.Component)
&& TryComp<LightBehaviourComponent>(uid, out var lightBehaviour))
{
lightBehaviour.StopLightBehaviour();
_lightBehavior.StopLightBehaviour((uid, lightBehaviour));

if (!string.IsNullOrEmpty(lightBehaviourID))
{
lightBehaviour.StartLightBehaviour(lightBehaviourID);
_lightBehavior.StartLightBehaviour((uid, lightBehaviour), lightBehaviourID);
}
else if (TryComp<PointLightComponent>(uid, out var light))
{
Expand Down
Loading

0 comments on commit ea9f7cb

Please sign in to comment.