using Content.Shared._Sunrise.Footprints;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Random;
namespace Content.Client._Sunrise.Footprints;
///
/// Handles the visual appearance and updates of footprint entities on the client
///
public sealed class FootprintVisualizerSystem : VisualizerSystem
{
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly IRobustRandom _random = default!;
///
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent(OnFootprintInitialized);
SubscribeLocalEvent(OnFootprintShutdown);
}
///
/// Initializes the visual appearance of a new footprint
///
private void OnFootprintInitialized(EntityUid uid, FootprintComponent component, ComponentInit args)
{
if (!TryComp(uid, out var sprite))
return;
InitializeSpriteLayers(sprite);
UpdateFootprintVisuals(uid, component, sprite);
}
///
/// Cleans up the visual elements when a footprint is removed
///
private void OnFootprintShutdown(EntityUid uid, FootprintComponent component, ComponentShutdown args)
{
if (!TryComp(uid, out var sprite))
return;
RemoveSpriteLayers(sprite);
}
///
/// Sets up the initial sprite layers for the footprint
///
private void InitializeSpriteLayers(SpriteComponent sprite)
{
sprite.LayerMapReserveBlank(FootprintSpriteLayer.MainLayer);
}
///
/// Removes sprite layers when cleaning up footprint
///
private void RemoveSpriteLayers(SpriteComponent sprite)
{
if (sprite.LayerMapTryGet(FootprintSpriteLayer.MainLayer, out var layer))
{
sprite.RemoveLayer(layer);
}
}
///
/// Updates the visual appearance of a footprint based on its current state
///
private void UpdateFootprintVisuals(EntityUid uid, FootprintComponent footprint, SpriteComponent sprite)
{
if (!sprite.LayerMapTryGet(FootprintSpriteLayer.MainLayer, out var layer)
|| !TryComp(footprint.CreatorEntity, out var emitterComponent)
|| !TryComp(uid, out var appearance))
return;
if (!_appearanceSystem.TryGetData(
uid,
FootprintVisualParameter.VisualState,
out var visualType,
appearance))
return;
UpdateSpriteState(sprite, layer, visualType, emitterComponent);
UpdateSpriteColor(sprite, layer, uid, appearance);
}
///
/// Updates the sprite state based on the footprint type
///
private void UpdateSpriteState(
SpriteComponent sprite,
int layer,
FootprintVisualType visualType,
FootprintEmitterComponent emitter)
{
var stateId = new RSI.StateId(GetStateId(visualType, emitter));
sprite.LayerSetState(layer, stateId, emitter.SpritePath);
}
///
/// Determines the appropriate state ID for the footprint based on its type
///
private string GetStateId(FootprintVisualType visualType, FootprintEmitterComponent emitter)
{
return visualType switch
{
FootprintVisualType.BareFootprint => emitter.IsRightStep
? _random.Pick(emitter.RightBareFootState)
: _random.Pick(emitter.LeftBareFootState),
FootprintVisualType.ShoeFootprint => _random.Pick(emitter.ShoeFootState),
FootprintVisualType.SuitFootprint => _random.Pick(emitter.PressureSuitFootState),
FootprintVisualType.DragMark => _random.Pick(emitter.DraggingStates),
_ => throw new ArgumentOutOfRangeException(
$"Unknown footprint visual type: {visualType}")
};
}
///
/// Updates the sprite color based on appearance data
///
private void UpdateSpriteColor(
SpriteComponent sprite,
int layer,
EntityUid uid,
AppearanceComponent appearance)
{
if (_appearanceSystem.TryGetData(uid,
FootprintVisualParameter.TrackColor,
out var color,
appearance))
{
sprite.LayerSetColor(layer, color);
}
}
///
protected override void OnAppearanceChange(
EntityUid uid,
FootprintComponent component,
ref AppearanceChangeEvent args)
{
if (args.Sprite is not { } sprite)
return;
UpdateFootprintVisuals(uid, component, sprite);
}
}