using Content.Shared.Audio.Jukebox; using Robust.Client.Animations; using Robust.Client.GameObjects; using Robust.Shared.Prototypes; namespace Content.Client.Audio.Jukebox; public sealed class JukeboxSystem : SharedJukeboxSystem { [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!; [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnAppearanceChange); SubscribeLocalEvent(OnAnimationCompleted); SubscribeLocalEvent(OnJukeboxAfterState); _protoManager.PrototypesReloaded += OnProtoReload; } public override void Shutdown() { base.Shutdown(); _protoManager.PrototypesReloaded -= OnProtoReload; } private void OnProtoReload(PrototypesReloadedEventArgs obj) { if (!obj.WasModified()) return; var query = AllEntityQuery(); while (query.MoveNext(out _, out var ui)) { if (!ui.OpenInterfaces.TryGetValue(JukeboxUiKey.Key, out var baseBui) || baseBui is not JukeboxBoundUserInterface bui) { continue; } bui.PopulateMusic(); } } private void OnJukeboxAfterState(Entity ent, ref AfterAutoHandleStateEvent args) { if (!TryComp(ent, out UserInterfaceComponent? ui)) return; if (!ui.OpenInterfaces.TryGetValue(JukeboxUiKey.Key, out var baseBui) || baseBui is not JukeboxBoundUserInterface bui) { return; } bui.Reload(); } private void OnAnimationCompleted(EntityUid uid, JukeboxComponent component, AnimationCompletedEvent args) { if (!TryComp(uid, out var sprite)) return; if (!TryComp(uid, out var appearance) || !_appearanceSystem.TryGetData(uid, JukeboxVisuals.VisualState, out var visualState, appearance)) { visualState = JukeboxVisualState.On; } UpdateAppearance(uid, visualState, component, sprite); } private void OnAppearanceChange(EntityUid uid, JukeboxComponent component, ref AppearanceChangeEvent args) { if (args.Sprite == null) return; if (!args.AppearanceData.TryGetValue(JukeboxVisuals.VisualState, out var visualStateObject) || visualStateObject is not JukeboxVisualState visualState) { visualState = JukeboxVisualState.On; } UpdateAppearance(uid, visualState, component, args.Sprite); } private void UpdateAppearance(EntityUid uid, JukeboxVisualState visualState, JukeboxComponent component, SpriteComponent sprite) { SetLayerState(JukeboxVisualLayers.Base, component.OffState, sprite); switch (visualState) { case JukeboxVisualState.On: SetLayerState(JukeboxVisualLayers.Base, component.OnState, sprite); break; case JukeboxVisualState.Off: SetLayerState(JukeboxVisualLayers.Base, component.OffState, sprite); break; case JukeboxVisualState.Select: PlayAnimation(uid, JukeboxVisualLayers.Base, component.SelectState, 1.0f, sprite); break; } } private void PlayAnimation(EntityUid uid, JukeboxVisualLayers layer, string? state, float animationTime, SpriteComponent sprite) { if (string.IsNullOrEmpty(state)) return; if (!_animationPlayer.HasRunningAnimation(uid, state)) { var animation = GetAnimation(layer, state, animationTime); sprite.LayerSetVisible(layer, true); _animationPlayer.Play(uid, animation, state); } } private static Animation GetAnimation(JukeboxVisualLayers layer, string state, float animationTime) { return new Animation { Length = TimeSpan.FromSeconds(animationTime), AnimationTracks = { new AnimationTrackSpriteFlick { LayerKey = layer, KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(state, 0f) } } } }; } private void SetLayerState(JukeboxVisualLayers layer, string? state, SpriteComponent sprite) { if (string.IsNullOrEmpty(state)) return; sprite.LayerSetVisible(layer, true); sprite.LayerSetAutoAnimated(layer, true); sprite.LayerSetState(layer, state); } }