-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
Addition of the Jukebox #20418
Changes from 1 commit
a823c2e
bc32a7e
b40b90a
88d838d
756b1fe
96b1624
417753f
e0579fa
8918765
fc1d197
40131a6
67ef7b9
ab240f8
b2497b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 JukeboxComponent.JukeboxPlayingMessage()); | ||
|
||
//var playing = !jukeboxComp.Playing; | ||
|
||
if(_menu == null) | ||
return; | ||
|
||
if (Jukebox is null) | ||
return; | ||
_menu.SetPlayPauseButton(!Jukebox.Playing); | ||
} | ||
|
||
public void Stop() | ||
{ | ||
SendMessage(new JukeboxComponent.JukeboxStopMessage()); | ||
} | ||
|
||
public void SelectSong(int songid) | ||
{ | ||
SendMessage(new JukeboxComponent.JukeboxSelectedMessage(songid)); | ||
|
||
if (Jukebox == null) | ||
return; | ||
|
||
if(_menu == null) | ||
return; | ||
|
||
_menu.SetSelectedSong(Jukebox.JukeboxMusicCollection.Songs[songid]); | ||
} | ||
|
||
public void SetTime(float time) | ||
{ | ||
SendMessage(new JukeboxComponent.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(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<DefaultWindow xmlns="https://spacestation14.io" 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> | ||
</DefaultWindow> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
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; | ||
|
||
namespace Content.Client.Jukebox.UI | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. filescope your namespaces (this applies to the other files as well) |
||
{ | ||
[GenerateTypedNameReferences] | ||
public sealed partial class JukeboxMenu : DefaultWindow | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. make it a FancyWindow |
||
{ | ||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; | ||
private readonly JukeboxBoundUserInterface _owner; | ||
|
||
public JukeboxMenu(JukeboxBoundUserInterface owner) : base() | ||
{ | ||
RobustXamlLoader.Load(this); | ||
|
||
_owner = owner; | ||
MusicList.OnItemSelected += OnItemSelected; | ||
PausePlayButton.OnPressed += OnPlayPausePressed; | ||
StopButton.OnPressed += OnStopPressed; | ||
PlaybackSlider.OnValueChanged += PlaybackSliderSeek; | ||
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); | ||
} | ||
|
||
private void PlaybackSliderSeek(Range _) | ||
{ | ||
if (PlaybackSlider.Grabbed) | ||
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 = "---"; | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. . |
||
{ | ||
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); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.