using System;
using System.Collections.Generic;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.GameObjects;
using Robust.Shared.Utility;
namespace Robust.Client.Animations
{
///
/// An animation track that plays RSI state animations manually, so they can be precisely controlled etc.
///
public sealed class AnimationTrackSpriteFlick : AnimationTrack
{
///
/// A list of key frames for when to fire flicks.
///
public List KeyFrames { get; private set; } = new();
// TODO: Should this layer key be per keyframe maybe?
///
/// The layer key of the layer to flick on.
///
public object? LayerKey { get; set; }
public override (int KeyFrameIndex, float FramePlayingTime) InitPlayback()
{
if (LayerKey == null)
{
throw new InvalidOperationException("Must set LayerKey.");
}
return (-1, 0);
}
public override (int KeyFrameIndex, float FramePlayingTime)
AdvancePlayback(object context, int prevKeyFrameIndex, float prevPlayingTime, float frameTime)
{
DebugTools.AssertNotNull(LayerKey);
var entity = (IEntity) context;
var sprite = entity.GetComponent();
var playingTime = prevPlayingTime + frameTime;
var keyFrameIndex = prevKeyFrameIndex;
// Advance to the correct key frame.
while (keyFrameIndex != KeyFrames.Count - 1 && KeyFrames[keyFrameIndex + 1].KeyTime < playingTime)
{
playingTime -= KeyFrames[keyFrameIndex + 1].KeyTime;
keyFrameIndex += 1;
}
if (keyFrameIndex >= 0)
{
var keyFrame = KeyFrames[keyFrameIndex];
// Advance animation on current key frame.
var rsi = sprite.LayerGetActualRSI(LayerKey!);
if (rsi != null && rsi.TryGetState(keyFrame.State, out var state))
{
var animationTime = Math.Min(state.AnimationLength - 0.01f, playingTime);
sprite.LayerSetAutoAnimated(LayerKey!, false);
// TODO: Doesn't setting the state explicitly reset the animation
// so it's slightly more inefficient?
sprite.LayerSetState(LayerKey!, keyFrame.State);
sprite.LayerSetAnimationTime(LayerKey!, animationTime);
}
}
return (keyFrameIndex, playingTime);
}
public struct KeyFrame
{
///
/// The RSI state to play when this keyframe gets triggered.
///
public readonly RSI.StateId State;
///
/// The time between this keyframe and the last.
///
public readonly float KeyTime;
public KeyFrame(RSI.StateId state, float keyTime)
{
State = state;
KeyTime = keyTime;
}
}
}
}