@@ -47,6 +47,16 @@ public sealed class JukeboxBoundUserInterface : BoundUserInterface
|
||||
|
||||
_menu.OnSongSelected += SelectSong;
|
||||
|
||||
_menu.OnSongQueueAdd += songId =>
|
||||
{
|
||||
SendMessage(new JukeboxAddQueueMessage(songId));
|
||||
};
|
||||
|
||||
_menu.OnQueueRemove += index =>
|
||||
{
|
||||
SendMessage(new JukeboxRemoveQueueMessage(index));
|
||||
};
|
||||
|
||||
_menu.SetTime += SetTime;
|
||||
PopulateMusic();
|
||||
Reload();
|
||||
@@ -65,17 +75,24 @@ public sealed class JukeboxBoundUserInterface : BoundUserInterface
|
||||
if (_protoManager.TryIndex(jukebox.SelectedSongId, out var songProto))
|
||||
{
|
||||
var length = EntMan.System<AudioSystem>().GetAudioLength(songProto.Path.Path.ToString());
|
||||
_menu.SetSelectedSong(songProto.Name, (float) length.TotalSeconds);
|
||||
_menu.SetSelectedSong(songProto.ID, (float) length.TotalSeconds);
|
||||
}
|
||||
else
|
||||
{
|
||||
_menu.SetSelectedSong(string.Empty, 0f);
|
||||
_menu.SetSelectedSong(null, 0f);
|
||||
}
|
||||
|
||||
_menu.PopulateQueue(jukebox.SongIdQueue);
|
||||
_menu.SetIsPlaying(EntMan.System<AudioSystem>().IsPlaying(jukebox.AudioStream));
|
||||
}
|
||||
|
||||
public void PopulateMusic()
|
||||
{
|
||||
_menu?.Populate(_protoManager.EnumeratePrototypes<JukeboxPrototype>());
|
||||
if (_menu == null || !EntMan.TryGetComponent(Owner, out JukeboxComponent? jukebox))
|
||||
return;
|
||||
|
||||
_menu.Populate(_protoManager.EnumeratePrototypes<JukeboxPrototype>());
|
||||
_menu.PopulateQueue(jukebox.SongIdQueue);
|
||||
}
|
||||
|
||||
public void SelectSong(ProtoId<JukeboxPrototype> songid)
|
||||
|
||||
9
Content.Client/Audio/Jukebox/JukeboxEntry.xaml
Normal file
9
Content.Client/Audio/Jukebox/JukeboxEntry.xaml
Normal file
@@ -0,0 +1,9 @@
|
||||
<BoxContainer xmlns="https://spacestation14.io"
|
||||
Orientation="Horizontal"
|
||||
HorizontalExpand="True">
|
||||
<Label Name="SongName" HorizontalAlignment="Left" HorizontalExpand="True"/>
|
||||
<Button Name="PlayButton" StyleClasses="OpenRight" Text="{Loc 'jukebox-menu-buttonplay'}" />
|
||||
<Button Name="StopButton" StyleClasses="OpenLeft" Text="{Loc 'jukebox-menu-buttonstop'}" />
|
||||
<Button Name="RemoveButton" Text="{Loc 'jukebox-menu-buttonremove'}" />
|
||||
<Button Name="QueueButton" StyleClasses="OpenLeft" Text="{Loc 'jukebox-menu-buttonqueue'}" />
|
||||
</BoxContainer>
|
||||
127
Content.Client/Audio/Jukebox/JukeboxEntry.xaml.cs
Normal file
127
Content.Client/Audio/Jukebox/JukeboxEntry.xaml.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using Content.Shared.Audio.Jukebox;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
|
||||
namespace Content.Client.Audio.Jukebox;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class JukeboxEntry : BoxContainer
|
||||
{
|
||||
private JukeboxPrototype? _song;
|
||||
private bool _playPauseState = true;
|
||||
public bool PlayPauseState
|
||||
{
|
||||
get {return _playPauseState;}
|
||||
set {
|
||||
_playPauseState = value;
|
||||
UpdateLabel();
|
||||
}
|
||||
}
|
||||
|
||||
private JukeboxEntryType _entryType;
|
||||
public JukeboxEntryType EntryType
|
||||
{
|
||||
get {return _entryType;}
|
||||
set {
|
||||
_entryType = value;
|
||||
Buttons();
|
||||
}
|
||||
}
|
||||
|
||||
public JukeboxEntry()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
Buttons();
|
||||
}
|
||||
|
||||
public JukeboxEntry(JukeboxPrototype? song) : this()
|
||||
{
|
||||
SetSong(song);
|
||||
Buttons();
|
||||
}
|
||||
|
||||
public void SetSong(JukeboxPrototype? song)
|
||||
{
|
||||
_song = song;
|
||||
|
||||
if (song == null)
|
||||
{
|
||||
Buttons();
|
||||
return;
|
||||
}
|
||||
|
||||
SongName.Text = song.Name;
|
||||
|
||||
Buttons();
|
||||
}
|
||||
|
||||
public void SetOnPressedPlay(Action<JukeboxPrototype?, bool, BaseButton.ButtonEventArgs>? func)
|
||||
{
|
||||
if (func == null)
|
||||
return;
|
||||
|
||||
PlayButton.OnPressed += args => {
|
||||
if (_entryType == JukeboxEntryType.Current)
|
||||
{
|
||||
_playPauseState = !_playPauseState;
|
||||
UpdateLabel();
|
||||
}
|
||||
func(_song, _playPauseState, args);
|
||||
};
|
||||
}
|
||||
|
||||
public void SetOnPressedQueue(Action<JukeboxPrototype?, BaseButton.ButtonEventArgs>? func)
|
||||
{
|
||||
if (func == null)
|
||||
return;
|
||||
|
||||
QueueButton.OnPressed += args => {
|
||||
func(_song, args);
|
||||
};
|
||||
}
|
||||
|
||||
public void SetOnPressedStop(Action<BaseButton.ButtonEventArgs>? func)
|
||||
{
|
||||
StopButton.OnPressed += func;
|
||||
}
|
||||
|
||||
public void SetOnPressedRemove(Action<JukeboxEntry, BaseButton.ButtonEventArgs>? func)
|
||||
{
|
||||
if (func == null)
|
||||
return;
|
||||
|
||||
RemoveButton.OnPressed += args => {
|
||||
func(this, args);
|
||||
};
|
||||
}
|
||||
|
||||
private void Buttons()
|
||||
{
|
||||
PlayButton.Visible = _song != null && (_entryType == JukeboxEntryType.List || _entryType == JukeboxEntryType.Current);
|
||||
StopButton.Visible = _song != null && _entryType == JukeboxEntryType.Current;
|
||||
RemoveButton.Visible = _song != null && _entryType == JukeboxEntryType.Queue;
|
||||
QueueButton.Visible = _song != null && _entryType == JukeboxEntryType.List;
|
||||
}
|
||||
|
||||
private void UpdateLabel()
|
||||
{
|
||||
if (!_playPauseState)
|
||||
{
|
||||
PlayButton.Text = Loc.GetString("jukebox-menu-buttonplay");
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayButton.Text = Loc.GetString("jukebox-menu-buttonpause");
|
||||
}
|
||||
}
|
||||
|
||||
public enum JukeboxEntryType
|
||||
{
|
||||
List,
|
||||
Queue,
|
||||
Current,
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,23 @@
|
||||
<ui:FancyWindow xmlns="https://spacestation14.io" xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:jb="clr-namespace:Content.Client.Audio.Jukebox"
|
||||
SetSize="400 500" Title="{Loc 'jukebox-menu-title'}">
|
||||
<BoxContainer Margin="4 0" Orientation="Vertical">
|
||||
<ItemList Name="MusicList" SelectMode="Button" Margin="3 3 3 3"
|
||||
HorizontalExpand="True" VerticalExpand="True" SizeFlagsStretchRatio="8"/>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Label Name="SongSelected" Text="{Loc 'jukebox-menu-selectedsong'}" />
|
||||
<Label Name="SongName" Text="---" />
|
||||
<Slider Name="PlaybackSlider" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True"
|
||||
VerticalExpand="False" SizeFlagsStretchRatio="1">
|
||||
<Button Name="PlayButton" Text="{Loc 'jukebox-menu-buttonplay'}" />
|
||||
<Button Name="StopButton" Text="{Loc 'jukebox-menu-buttonstop'}" />
|
||||
<Label Name="DurationLabel" Text="00:00 / 00:00" HorizontalAlignment="Right" HorizontalExpand="True"/>
|
||||
<Label Text="{Loc 'jukebox-menu-songs'}"/>
|
||||
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True" Margin="13 3 3 3">
|
||||
<BoxContainer Name="MusicList" Orientation="Vertical"
|
||||
HorizontalExpand="True" VerticalExpand="True" SizeFlagsStretchRatio="8"/>
|
||||
</ScrollContainer>
|
||||
<Label Text="{Loc 'jukebox-menu-queue'}"/>
|
||||
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True" Margin="13 3 3 3">
|
||||
<BoxContainer Name="MusicListQueue" Orientation="Vertical"
|
||||
HorizontalExpand="True" VerticalExpand="True" SizeFlagsStretchRatio="8"/>
|
||||
</ScrollContainer>
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<Label Name="SongSelected" Text="{Loc 'jukebox-menu-selectedsong-none'}" />
|
||||
<BoxContainer HorizontalExpand="True"/>
|
||||
<Label Name="DurationLabel" Text="---" />
|
||||
</BoxContainer>
|
||||
<Slider Name="PlaybackSlider" Visible="false" HorizontalExpand="True" />
|
||||
<jb:JukeboxEntry Name="CurrentSong" Visible="false" EntryType="Current"/>
|
||||
</BoxContainer>
|
||||
</ui:FancyWindow>
|
||||
|
||||
@@ -14,12 +14,10 @@ namespace Content.Client.Audio.Jukebox;
|
||||
public sealed partial class JukeboxMenu : FancyWindow
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
|
||||
private AudioSystem _audioSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Are we currently 'playing' or paused for the play / pause button.
|
||||
/// </summary>
|
||||
private bool _playState;
|
||||
|
||||
/// <summary>
|
||||
/// True if playing, false if paused.
|
||||
@@ -29,6 +27,9 @@ public sealed partial class JukeboxMenu : FancyWindow
|
||||
public event Action<ProtoId<JukeboxPrototype>>? OnSongSelected;
|
||||
public event Action<float>? SetTime;
|
||||
|
||||
public event Action<ProtoId<JukeboxPrototype>>? OnSongQueueAdd;
|
||||
public event Action<int>? OnQueueRemove;
|
||||
|
||||
private EntityUid? _audio;
|
||||
|
||||
private float _lockTimer;
|
||||
@@ -39,28 +40,18 @@ public sealed partial class JukeboxMenu : FancyWindow
|
||||
IoCManager.InjectDependencies(this);
|
||||
_audioSystem = _entManager.System<AudioSystem>();
|
||||
|
||||
MusicList.OnItemSelected += args =>
|
||||
{
|
||||
var entry = MusicList[args.ItemIndex];
|
||||
|
||||
if (entry.Metadata is not string juke)
|
||||
return;
|
||||
|
||||
OnSongSelected?.Invoke(juke);
|
||||
};
|
||||
|
||||
PlayButton.OnPressed += args =>
|
||||
{
|
||||
OnPlayPressed?.Invoke(!_playState);
|
||||
};
|
||||
|
||||
StopButton.OnPressed += args =>
|
||||
CurrentSong.SetOnPressedStop(args =>
|
||||
{
|
||||
OnStopPressed?.Invoke();
|
||||
};
|
||||
});
|
||||
|
||||
CurrentSong.SetOnPressedPlay((song, playPauseState, args) =>
|
||||
{
|
||||
OnPlayPressed?.Invoke(playPauseState);
|
||||
});
|
||||
|
||||
PlaybackSlider.OnReleased += PlaybackSliderKeyUp;
|
||||
|
||||
SetPlayPauseButton(_audioSystem.IsPlaying(_audio), force: true);
|
||||
}
|
||||
|
||||
public JukeboxMenu(AudioSystem audioSystem)
|
||||
@@ -84,33 +75,43 @@ public sealed partial class JukeboxMenu : FancyWindow
|
||||
/// </summary>
|
||||
public void Populate(IEnumerable<JukeboxPrototype> jukeboxProtos)
|
||||
{
|
||||
MusicList.Clear();
|
||||
MusicList.RemoveAllChildren();
|
||||
|
||||
foreach (var entry in jukeboxProtos)
|
||||
{
|
||||
MusicList.AddItem(entry.Name, metadata: entry.ID);
|
||||
// MusicList.AddItem(entry.Name, metadata: entry.ID);
|
||||
var songControl = new JukeboxEntry(entry) {EntryType = JukeboxEntry.JukeboxEntryType.List};
|
||||
songControl.SetOnPressedPlay((song, _, args) =>
|
||||
{
|
||||
if (song == null)
|
||||
return;
|
||||
OnSongSelected?.Invoke(song.ID);
|
||||
OnPlayPressed?.Invoke(true);
|
||||
});
|
||||
|
||||
songControl.SetOnPressedQueue((song, args) =>
|
||||
{
|
||||
if (song == null)
|
||||
return;
|
||||
OnSongQueueAdd?.Invoke(song.ID);
|
||||
});
|
||||
|
||||
MusicList.AddChild(songControl);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPlayPauseButton(bool playing, bool force = false)
|
||||
public void SetSelectedSong(ProtoId<JukeboxPrototype>? song, float length)
|
||||
{
|
||||
if (_playState == playing && !force)
|
||||
if (song == null)
|
||||
return;
|
||||
|
||||
_playState = playing;
|
||||
|
||||
if (playing)
|
||||
{
|
||||
PlayButton.Text = Loc.GetString("jukebox-menu-buttonpause");
|
||||
if (!_prototype.TryIndex(song, out var songProto))
|
||||
return;
|
||||
}
|
||||
|
||||
PlayButton.Text = Loc.GetString("jukebox-menu-buttonplay");
|
||||
}
|
||||
|
||||
public void SetSelectedSong(string name, float length)
|
||||
{
|
||||
SetSelectedSongText(name);
|
||||
SongSelected.Text = Loc.GetString("jukebox-menu-selectedsong");
|
||||
PlaybackSlider.Visible = true;
|
||||
CurrentSong.Visible = true;
|
||||
CurrentSong.SetSong(songProto);
|
||||
PlaybackSlider.MaxValue = length;
|
||||
PlaybackSlider.SetValueWithoutEvent(0);
|
||||
}
|
||||
@@ -145,18 +146,34 @@ public sealed partial class JukeboxMenu : FancyWindow
|
||||
PlaybackSlider.SetValueWithoutEvent(0f);
|
||||
}
|
||||
|
||||
SetPlayPauseButton(_audioSystem.IsPlaying(_audio, audio));
|
||||
}
|
||||
|
||||
public void SetSelectedSongText(string? text)
|
||||
/// <summary>
|
||||
/// Re-populates the queue with avaiable jukebox prototypes.
|
||||
/// </summary>
|
||||
public void PopulateQueue(IEnumerable<ProtoId<JukeboxPrototype>> queue)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
MusicListQueue.RemoveAllChildren();
|
||||
int i = 0;
|
||||
foreach (var song in queue)
|
||||
{
|
||||
SongName.Text = text;
|
||||
}
|
||||
else
|
||||
{
|
||||
SongName.Text = "---";
|
||||
if (!_prototype.TryIndex(song, out var songProto))
|
||||
continue;
|
||||
|
||||
i += 1;
|
||||
var songControl = new JukeboxEntry(songProto) {EntryType = JukeboxEntry.JukeboxEntryType.Queue};
|
||||
MusicListQueue.AddChild(songControl);
|
||||
|
||||
songControl.SetOnPressedRemove((source, args) =>
|
||||
{
|
||||
int index = source.GetPositionInParent();
|
||||
OnQueueRemove?.Invoke(index);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void SetIsPlaying(bool isPlaying)
|
||||
{
|
||||
CurrentSong.PlayPauseState = isPlaying;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
|
||||
|
||||
var query = AllEntityQuery<JukeboxComponent, UserInterfaceComponent>();
|
||||
|
||||
while (query.MoveNext(out _, out var ui))
|
||||
while (query.MoveNext(out var uid, out var jukebox, out var ui))
|
||||
{
|
||||
if (!ui.OpenInterfaces.TryGetValue(JukeboxUiKey.Key, out var baseBui) ||
|
||||
baseBui is not JukeboxBoundUserInterface bui)
|
||||
@@ -43,6 +43,24 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obj.Removed?.TryGetValue(typeof(JukeboxPrototype), out var removed) ?? false)
|
||||
{
|
||||
var list = new List<ProtoId<JukeboxPrototype>>();
|
||||
while (jukebox.SongIdQueue.Count > 0)
|
||||
{
|
||||
var next = jukebox.SongIdQueue.Dequeue();
|
||||
if (removed.Contains(next))
|
||||
continue;
|
||||
|
||||
|
||||
list.Add(next);
|
||||
}
|
||||
foreach (var song in list)
|
||||
{
|
||||
jukebox.SongIdQueue.Enqueue(song);
|
||||
}
|
||||
}
|
||||
|
||||
bui.PopulateMusic();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||
[Dependency] private readonly AppearanceSystem _appearanceSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -26,6 +28,9 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
|
||||
SubscribeLocalEvent<JukeboxComponent, JukeboxSetTimeMessage>(OnJukeboxSetTime);
|
||||
SubscribeLocalEvent<JukeboxComponent, ComponentInit>(OnComponentInit);
|
||||
SubscribeLocalEvent<JukeboxComponent, ComponentShutdown>(OnComponentShutdown);
|
||||
SubscribeLocalEvent<JukeboxComponent, JukeboxAddQueueMessage>(OnJukeboxAddQueue);
|
||||
SubscribeLocalEvent<JukeboxComponent, JukeboxRemoveQueueMessage>(OnJukeboxRemoveQueue);
|
||||
SubscribeLocalEvent<JukeboxMusicComponent, ComponentShutdown>(OnAudioShutdown);
|
||||
|
||||
SubscribeLocalEvent<JukeboxComponent, PowerChangedEvent>(OnPowerChanged);
|
||||
}
|
||||
@@ -40,28 +45,44 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
|
||||
|
||||
private void OnJukeboxPlay(EntityUid uid, JukeboxComponent component, ref JukeboxPlayingMessage args)
|
||||
{
|
||||
if (Exists(component.AudioStream))
|
||||
OnJukeboxPlay(uid, component);
|
||||
}
|
||||
|
||||
private void OnJukeboxAddQueue(EntityUid uid, JukeboxComponent component, JukeboxAddQueueMessage args)
|
||||
{
|
||||
if (component.SelectedSongId == null)
|
||||
{
|
||||
Audio.SetState(component.AudioStream, AudioState.Playing);
|
||||
component.SelectedSongId = args.SongId;
|
||||
}
|
||||
else
|
||||
{
|
||||
component.AudioStream = Audio.Stop(component.AudioStream);
|
||||
|
||||
if (string.IsNullOrEmpty(component.SelectedSongId) ||
|
||||
!_protoManager.TryIndex(component.SelectedSongId, out var jukeboxProto))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
component.AudioStream = Audio.PlayPvs(jukeboxProto.Path, uid, AudioParams.Default.WithMaxDistance(10f))?.Entity;
|
||||
Dirty(uid, component);
|
||||
component.SongIdQueue.Enqueue(args.SongId);
|
||||
}
|
||||
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
private void OnJukeboxRemoveQueue(EntityUid uid, JukeboxComponent component, JukeboxRemoveQueueMessage args)
|
||||
{
|
||||
if (args.Index < 0 || args.Index >= component.SongIdQueue.Count)
|
||||
return;
|
||||
|
||||
var list = new List<ProtoId<JukeboxPrototype>>(component.SongIdQueue);
|
||||
list.RemoveAt(args.Index);
|
||||
component.SongIdQueue.Clear();
|
||||
foreach (var entry in list)
|
||||
{
|
||||
component.SongIdQueue.Enqueue(entry);
|
||||
}
|
||||
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
private void OnJukeboxPause(Entity<JukeboxComponent> ent, ref JukeboxPauseMessage args)
|
||||
{
|
||||
Audio.SetState(ent.Comp.AudioStream, AudioState.Paused);
|
||||
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
private void OnJukeboxSetTime(EntityUid uid, JukeboxComponent component, JukeboxSetTimeMessage args)
|
||||
@@ -85,6 +106,26 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
|
||||
Stop(entity);
|
||||
}
|
||||
|
||||
private void OnAudioShutdown(Entity<JukeboxMusicComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
var query = EntityQueryEnumerator<JukeboxComponent>();
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
{
|
||||
if (comp.AudioStream == ent.Owner)
|
||||
{
|
||||
var next = SongQueueDequeue((uid, comp));
|
||||
if (next == null)
|
||||
{
|
||||
Stop((uid, comp));
|
||||
continue;
|
||||
}
|
||||
|
||||
OnJukeboxSelected(uid, comp, next.Value);
|
||||
OnJukeboxPlay(uid, comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Stop(Entity<JukeboxComponent> entity)
|
||||
{
|
||||
Audio.SetState(entity.Comp.AudioStream, AudioState.Stopped);
|
||||
@@ -93,15 +134,7 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
|
||||
|
||||
private void OnJukeboxSelected(EntityUid uid, JukeboxComponent component, JukeboxSelectedMessage args)
|
||||
{
|
||||
if (!Audio.IsPlaying(component.AudioStream))
|
||||
{
|
||||
component.SelectedSongId = args.SongId;
|
||||
DirectSetVisualState(uid, JukeboxVisualState.Select);
|
||||
component.Selecting = true;
|
||||
component.AudioStream = Audio.Stop(component.AudioStream);
|
||||
}
|
||||
|
||||
Dirty(uid, component);
|
||||
OnJukeboxSelected(uid, component, args.SongId);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
@@ -135,6 +168,42 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
|
||||
_appearanceSystem.SetData(uid, JukeboxVisuals.VisualState, state);
|
||||
}
|
||||
|
||||
private void OnJukeboxPlay(EntityUid uid, JukeboxComponent component)
|
||||
{
|
||||
if (Exists(component.AudioStream))
|
||||
{
|
||||
Audio.SetState(component.AudioStream, AudioState.Playing);
|
||||
}
|
||||
else
|
||||
{
|
||||
component.AudioStream = Audio.Stop(component.AudioStream);
|
||||
|
||||
if (string.IsNullOrEmpty(component.SelectedSongId) ||
|
||||
!_protoManager.TryIndex(component.SelectedSongId, out var jukeboxProto))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
component.AudioStream = Audio.PlayPvs(jukeboxProto.Path, uid, AudioParams.Default.WithMaxDistance(10f))?.Entity;
|
||||
if (component.AudioStream != null)
|
||||
{
|
||||
AddComp<JukeboxMusicComponent>(component.AudioStream.Value);
|
||||
}
|
||||
|
||||
Dirty(uid, component);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnJukeboxSelected(EntityUid uid, JukeboxComponent component, ProtoId<JukeboxPrototype> songId)
|
||||
{
|
||||
component.SelectedSongId = songId;
|
||||
DirectSetVisualState(uid, JukeboxVisualState.Select);
|
||||
component.Selecting = true;
|
||||
component.AudioStream = Audio.Stop(component.AudioStream);
|
||||
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
private void TryUpdateVisualState(EntityUid uid, JukeboxComponent? jukeboxComponent = null)
|
||||
{
|
||||
if (!Resolve(uid, ref jukeboxComponent))
|
||||
@@ -149,4 +218,14 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
|
||||
|
||||
_appearanceSystem.SetData(uid, JukeboxVisuals.VisualState, finalState);
|
||||
}
|
||||
|
||||
private ProtoId<JukeboxPrototype>? SongQueueDequeue(Entity<JukeboxComponent> ent)
|
||||
{
|
||||
if (ent.Comp.SongIdQueue.Count == 0)
|
||||
return null;
|
||||
|
||||
var next = ent.Comp.SongIdQueue.Dequeue();
|
||||
|
||||
return next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,9 @@ public sealed partial class JukeboxComponent : Component
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityUid? AudioStream;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public Queue<ProtoId<JukeboxPrototype>> SongIdQueue = new();
|
||||
|
||||
/// <summary>
|
||||
/// RSI state for the jukebox being on.
|
||||
/// </summary>
|
||||
@@ -39,6 +42,9 @@ public sealed partial class JukeboxComponent : Component
|
||||
public float SelectAccumulator;
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class JukeboxMusicComponent : Component;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class JukeboxPlayingMessage : BoundUserInterfaceMessage;
|
||||
|
||||
@@ -60,6 +66,18 @@ public sealed class JukeboxSetTimeMessage(float songTime) : BoundUserInterfaceMe
|
||||
public float SongTime { get; } = songTime;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class JukeboxAddQueueMessage(ProtoId<JukeboxPrototype> songId) : BoundUserInterfaceMessage
|
||||
{
|
||||
public ProtoId<JukeboxPrototype> SongId { get; } = songId;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class JukeboxRemoveQueueMessage(int index) : BoundUserInterfaceMessage
|
||||
{
|
||||
public int Index { get; } = index;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum JukeboxVisuals : byte
|
||||
{
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
jukebox-menu-title = Jukebox
|
||||
jukebox-menu-selectedsong = Selected Song:
|
||||
jukebox-menu-selectedsong-none = No Song Selected
|
||||
jukebox-menu-buttonplay = Play
|
||||
jukebox-menu-buttonpause = Pause
|
||||
jukebox-menu-buttonstop = Stop
|
||||
jukebox-menu-buttonqueue = Queue
|
||||
jukebox-menu-buttonremove = Remove
|
||||
jukebox-menu-songs = Songs:
|
||||
jukebox-menu-queue = Song queue:
|
||||
|
||||
10
Resources/Locale/ru-RU/jukebox/jukebox-menu.ftl
Normal file
10
Resources/Locale/ru-RU/jukebox/jukebox-menu.ftl
Normal file
@@ -0,0 +1,10 @@
|
||||
jukebox-menu-title = Jukebox
|
||||
jukebox-menu-selectedsong = Выбранная песня:
|
||||
jukebox-menu-selectedsong-none = Песня не выбрана
|
||||
jukebox-menu-buttonplay = Играть
|
||||
jukebox-menu-buttonpause = Пауза
|
||||
jukebox-menu-buttonstop = Стоп
|
||||
jukebox-menu-buttonqueue = Очередь
|
||||
jukebox-menu-buttonremove = Убрать
|
||||
jukebox-menu-songs = Песни:
|
||||
jukebox-menu-queue = Очередь:
|
||||
Reference in New Issue
Block a user