Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addition of the Jukebox #20418

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions Content.Client/Jukebox/UI/JukeboxBoundUserInterface.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
using Content.Shared.Jukebox;
using Robust.Client.GameObjects;
using Robust.Shared.Timing;

namespace Content.Client.Jukebox.UI;

public sealed class JukeboxBoundUserInterface : BoundUserInterface
{
[ViewVariables]
private JukeboxMenu? _menu;
[ViewVariables]
private JukeboxSystem? _system;

[ViewVariables]
private List<MusicListDefinition> _cachedList = new();

public JukeboxComponent? Jukebox { get; private set; }

[Dependency] public readonly IGameTiming _timing = default!;

public JukeboxBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
IoCManager.InjectDependencies(this);
}

protected override void Open()
{
base.Open();

if (!EntMan.TryGetComponent(Owner, out JukeboxComponent? jukebox))
return;

Jukebox = jukebox;

_menu = new JukeboxMenu(this);

_menu.OnClose += Close;

_menu.OpenCentered();

_system = EntMan.System<JukeboxSystem>();

_cachedList = _system.GetList(Owner);
_menu.SetPlayPauseButton(Jukebox.Playing);
_menu.SetSelectedSong(Jukebox.JukeboxMusicCollection.Songs[Jukebox.SelectedSongID]);

_menu.Populate(_cachedList);
}

public void TogglePlaying()
{
SendMessage(new JukeboxPlayingMessage());

//var playing = !jukeboxComp.Playing;

if(_menu == null)
return;

if (Jukebox is null)
return;
_menu.SetPlayPauseButton(!Jukebox.Playing);
}

public void Stop()
{
SendMessage(new JukeboxStopMessage());
}

public void SelectSong(int songid)
{
SendMessage(new JukeboxSelectedMessage(songid));

if (Jukebox == null)
return;

if(_menu == null)
return;

_menu.SetSelectedSong(Jukebox.JukeboxMusicCollection.Songs[songid]);
}

public void SetTime(float time)
{
SendMessage(new JukeboxSetTimeMessage(time));
}
public void CLSetTime(float time)
{
if (Jukebox is null || _system is null)
return;
_system.setTime(Jukebox, time);
}

protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);

if (state is not JukeboxBoundUserInterfaceState newState)
return;

if (Jukebox == null)
return;

if(_menu == null)
return;

_menu.SetPlayPauseButton(newState.Playing);
_menu.SetSelectedSong(Jukebox.JukeboxMusicCollection.Songs[newState.SelectedSongID]);
}

protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;

if (_menu == null)
return;

_menu.OnClose -= Close;
_menu.Dispose();
}
}

17 changes: 17 additions & 0 deletions Content.Client/Jukebox/UI/JukeboxMenu.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<ui:FancyWindow xmlns="https://spacestation14.io" xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
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="PausePlayButton" Text="{Loc 'jukebox-menu-buttonplay'}" />
<Button Name="StopButton" Text="{Loc 'jukebox-menu-buttonstop'}" />
</BoxContainer>
</BoxContainer>
</ui:FancyWindow>
121 changes: 121 additions & 0 deletions Content.Client/Jukebox/UI/JukeboxMenu.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using Content.Shared.Jukebox;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Input;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Range = Robust.Client.UserInterface.Controls.Range;
using FancyWindow = Content.Client.UserInterface.Controls.FancyWindow;

namespace Content.Client.Jukebox.UI;

[GenerateTypedNameReferences]
public sealed partial class JukeboxMenu : FancyWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private readonly JukeboxBoundUserInterface _owner;

public JukeboxMenu(JukeboxBoundUserInterface owner)
{
RobustXamlLoader.Load(this);

_owner = owner;
MusicList.OnItemSelected += OnItemSelected;
PausePlayButton.OnPressed += OnPlayPausePressed;
StopButton.OnPressed += OnStopPressed;
PlaybackSlider.OnKeyBindUp += PlaybackSliderKeyUp;
}

private void OnItemSelected(ItemList.ItemListSelectedEventArgs args)
{
if(_owner.Jukebox is not null)
{
if(_owner.Jukebox.Playing)
return;
}

_owner.SelectSong(args.ItemIndex);
_owner.CLSetTime(PlaybackSlider.Value);
}

private void OnPlayPausePressed(BaseButton.ButtonEventArgs obj)
{
_owner.TogglePlaying();
}

private void OnStopPressed(BaseButton.ButtonEventArgs obj)
{
_owner.Stop();
}

private void PlaybackSliderKeyUp(GUIBoundKeyEventArgs args)
{
if (args.Function != EngineKeyFunctions.UIClick)
return;

_owner.CLSetTime(PlaybackSlider.Value);
_owner.SetTime(PlaybackSlider.Value);
}

public void Populate(List<MusicListDefinition> MusicDefs)
{
MusicList.Clear();

for (var i = 0; i < MusicDefs.Count; i++)
{
var entry = MusicDefs[i];
MusicList.AddItem(entry.Name);
}
}

public void SetPlayPauseButton(bool Playing)
{
if(Playing)
{
PausePlayButton.Text = Loc.GetString("jukebox-menu-buttonpause");
return;
}
PausePlayButton.Text = Loc.GetString("jukebox-menu-buttonplay");
}

public void SetSelectedSong(MusicListDefinition selected)
{
SetSelectedSongText(selected.Name);
PlaybackSlider.MaxValue = selected.SongLength;
PlaybackSlider.SetValueWithoutEvent(0);
}

protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);

if (_owner.Jukebox == null)
return;

if (PlaybackSlider.Grabbed)
return;

if (_owner.Jukebox.Playing)
{
var time = (float) (_owner._timing.CurTime.TotalSeconds - _owner.Jukebox.SongStartTime);
PlaybackSlider.SetValueWithoutEvent(time);
return;
}
PlaybackSlider.SetValueWithoutEvent(_owner.Jukebox.SongTime);
}

public void SetSelectedSongText(string? text)
{
if(text != null)
{
SongName.Text = text;
}
else
{
SongName.Text = "---";
}
}
}
117 changes: 117 additions & 0 deletions Content.Client/Jukebox/UI/JukeboxSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using Content.Shared.Jukebox;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Shared.Timing;
namespace Content.Client.Jukebox;


public sealed class JukeboxSystem : SharedJukeboxSystem
Comment on lines +4 to +8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.

{
[Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!;
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly IGameTiming _timing = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<JukeboxComponent, AppearanceChangeEvent>(OnAppearanceChange);
SubscribeLocalEvent<JukeboxComponent, AnimationCompletedEvent>(OnAnimationCompleted);
}

public void setTime(JukeboxComponent component, float time)
{
component.SongTime = time;
component.SongStartTime = (float) (_timing.CurTime.TotalSeconds - component.SongTime);
}

private void OnAnimationCompleted(EntityUid uid, JukeboxComponent component, AnimationCompletedEvent args)
{
if (!TryComp<SpriteComponent>(uid, out var sprite))
return;

if (!TryComp<AppearanceComponent>(uid, out var appearance) ||
!_appearanceSystem.TryGetData<JukeboxVisualState>(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 static 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);
}
}
Loading
Loading