using Content.Shared.Audio.Jukebox; using Robust.Client.Audio; using Robust.Client.UserInterface; using Robust.Shared.Audio.Components; using Robust.Shared.Prototypes; namespace Content.Client.Audio.Jukebox; public sealed class JukeboxBoundUserInterface : BoundUserInterface { [Dependency] private readonly IPrototypeManager _protoManager = default!; [ViewVariables] private JukeboxMenu? _menu; public JukeboxBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { IoCManager.InjectDependencies(this); } protected override void Open() { base.Open(); _menu = this.CreateWindow(); _menu.OnPlayPressed += args => { if (args) { SendMessage(new JukeboxPlayingMessage()); } else { SendMessage(new JukeboxPauseMessage()); } }; _menu.OnStopPressed += () => { SendMessage(new JukeboxStopMessage()); }; _menu.OnSongSelected += SelectSong; _menu.SetTime += SetTime; PopulateMusic(); Reload(); } /// /// Reloads the attached menu if it exists. /// public void Reload() { if (_menu == null || !EntMan.TryGetComponent(Owner, out JukeboxComponent? jukebox)) return; _menu.SetAudioStream(jukebox.AudioStream); if (_protoManager.Resolve(jukebox.SelectedSongId, out var songProto)) { var length = EntMan.System().GetAudioLength(songProto.Path.Path.ToString()); _menu.SetSelectedSong(songProto.Name, (float) length.TotalSeconds); } else { _menu.SetSelectedSong(string.Empty, 0f); } } public void PopulateMusic() { _menu?.Populate(_protoManager.EnumeratePrototypes()); } public void SelectSong(ProtoId songid) { SendMessage(new JukeboxSelectedMessage(songid)); } public void SetTime(float time) { var sentTime = time; // You may be wondering, what the fuck is this // Well we want to be able to predict the playback slider change, of which there are many ways to do it // We can't just use SendPredictedMessage because it will reset every tick and audio updates every frame // so it will go BRRRRT // Using ping gets us close enough that it SHOULD, MOST OF THE TIME, fall within the 0.1 second tolerance // that's still on engine so our playback position never gets corrected. if (EntMan.TryGetComponent(Owner, out JukeboxComponent? jukebox) && EntMan.TryGetComponent(jukebox.AudioStream, out AudioComponent? audioComp)) { audioComp.PlaybackPosition = time; } SendMessage(new JukeboxSetTimeMessage(sentTime)); } }