[feat]jukebox (#9)
This commit is contained in:
@@ -22,6 +22,7 @@ using Content.Client.Stylesheets;
|
||||
using Content.Client.Viewport;
|
||||
using Content.Client.Voting;
|
||||
using Content.Client.White.JoinQueue;
|
||||
using Content.Client.White.Jukebox;
|
||||
using Content.Client.White.Sponsors;
|
||||
using Content.Shared.Ame;
|
||||
using Content.Client.White.Stalin;
|
||||
@@ -78,6 +79,7 @@ namespace Content.Client.Entry
|
||||
[Dependency] private readonly SponsorsManager _sponsorsManager = default!;
|
||||
[Dependency] private readonly JoinQueueManager _queueManager = default!;
|
||||
[Dependency] private readonly StalinManager _stalinManager = default!;
|
||||
[Dependency] private readonly ClientJukeboxSongsSyncManager _jukeboxSyncManager = default!;
|
||||
//WD-EDIT
|
||||
|
||||
public override void Init()
|
||||
@@ -183,6 +185,7 @@ namespace Content.Client.Entry
|
||||
//WD-EDIT
|
||||
_sponsorsManager.Initialize();
|
||||
_queueManager.Initialize();
|
||||
_jukeboxSyncManager.Initialize();
|
||||
//WD-EDIT
|
||||
|
||||
_baseClient.RunLevelChanged += (_, args) =>
|
||||
|
||||
@@ -18,6 +18,7 @@ using Content.Shared.Administration.Logs;
|
||||
using Content.Client.Guidebook;
|
||||
using Content.Client.Replay;
|
||||
using Content.Client.White.JoinQueue;
|
||||
using Content.Client.White.Jukebox;
|
||||
using Content.Client.White.Sponsors;
|
||||
using Content.Client.White.Stalin;
|
||||
using Content.Shared.Administration.Managers;
|
||||
@@ -53,6 +54,7 @@ namespace Content.Client.IoC
|
||||
IoCManager.Register<JoinQueueManager>();
|
||||
IoCManager.Register<SponsorsManager>();
|
||||
IoCManager.Register<StalinManager>();
|
||||
IoCManager.Register<ClientJukeboxSongsSyncManager>();
|
||||
//WD-EDIT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,19 @@
|
||||
<Label Name="TtsVolumeLabel" MinSize="48 0" Align="Right" />
|
||||
<Control MinSize="4 0"/>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
|
||||
<Label Text="{Loc 'ui-options-jukebox-volume'}" HorizontalExpand="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Slider Name="JukeboxVolumeSlider"
|
||||
MinValue="25"
|
||||
MaxValue="200"
|
||||
HorizontalExpand="True"
|
||||
MinSize="80 0"
|
||||
Rounded="True" />
|
||||
<Control MinSize="8 0" />
|
||||
<Label Name="JukeboxVolumeLabel" MinSize="48 0" Align="Right" />
|
||||
<Control MinSize="4 0"/>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
|
||||
<Label Text="{Loc 'ui-options-lobby-volume'}" HorizontalExpand="True" />
|
||||
<Control MinSize="8 0" />
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace Content.Client.Options.UI.Tabs
|
||||
LobbyVolumeSlider.OnValueChanged += OnLobbyVolumeSliderChanged;
|
||||
TtsVolumeSlider.OnValueChanged += OnTtsVolumeSliderChanged;
|
||||
InterfaceVolumeSlider.OnValueChanged += OnInterfaceVolumeSliderChanged;
|
||||
JukeboxVolumeSlider.OnValueChanged += OnJukeboxVolumeSliderChanged;
|
||||
LobbyMusicCheckBox.OnToggled += OnLobbyMusicCheckToggled;
|
||||
RestartSoundsCheckBox.OnToggled += OnRestartSoundsCheckToggled;
|
||||
EventMusicCheckBox.OnToggled += OnEventMusicCheckToggled;
|
||||
@@ -63,6 +64,7 @@ namespace Content.Client.Options.UI.Tabs
|
||||
|
||||
//WD-EDIT
|
||||
TtsVolumeSlider.OnValueChanged -= OnTtsVolumeSliderChanged;
|
||||
JukeboxVolumeSlider.OnValueChanged -= OnJukeboxVolumeSliderChanged;
|
||||
//WD-EDIT
|
||||
|
||||
base.Dispose(disposing);
|
||||
@@ -76,6 +78,13 @@ namespace Content.Client.Options.UI.Tabs
|
||||
}
|
||||
//TTS-End
|
||||
|
||||
//JUKEBOX
|
||||
private void OnJukeboxVolumeSliderChanged(Range obj)
|
||||
{
|
||||
UpdateChanges();
|
||||
}
|
||||
//JUKEBOX
|
||||
|
||||
private void OnLobbyVolumeSliderChanged(Range obj)
|
||||
{
|
||||
UpdateChanges();
|
||||
@@ -150,6 +159,7 @@ namespace Content.Client.Options.UI.Tabs
|
||||
|
||||
//WD-EDIT
|
||||
_cfg.SetCVar(WhiteCVars.TtsVolume, LV100ToDB(TtsVolumeSlider.Value));
|
||||
_cfg.SetCVar(WhiteCVars.JukeboxVolume, LV100ToDB(JukeboxVolumeSlider.Value));
|
||||
//WD-EDIT
|
||||
|
||||
_cfg.SaveToFile();
|
||||
@@ -179,6 +189,7 @@ namespace Content.Client.Options.UI.Tabs
|
||||
|
||||
//WD-EDIT
|
||||
TtsVolumeSlider.Value = DBToLV100(_cfg.GetCVar(WhiteCVars.TtsVolume));
|
||||
JukeboxVolumeSlider.Value = DBToLV100(_cfg.GetCVar(WhiteCVars.JukeboxVolume));
|
||||
//WD-EDIT
|
||||
|
||||
|
||||
@@ -222,6 +233,8 @@ namespace Content.Client.Options.UI.Tabs
|
||||
//WD-EDIT
|
||||
var isTtsVolumeSame =
|
||||
Math.Abs(TtsVolumeSlider.Value - DBToLV100(_cfg.GetCVar(WhiteCVars.TtsVolume))) < 0.01f;
|
||||
var isJukeboxVolumeSame =
|
||||
Math.Abs(JukeboxVolumeSlider.Value - DBToLV100(_cfg.GetCVar(WhiteCVars.JukeboxVolume))) < 0.01f;
|
||||
//WD-EDIT
|
||||
|
||||
var isRestartSoundsSame = RestartSoundsCheckBox.Pressed == _cfg.GetCVar(CCVars.RestartSoundsEnabled);
|
||||
@@ -230,6 +243,7 @@ namespace Content.Client.Options.UI.Tabs
|
||||
var isEverythingSame = isMasterVolumeSame && isMidiVolumeSame && isAmbientVolumeSame && isAmbientMusicVolumeSame && isAmbientSoundsSame && isLobbySame && isRestartSoundsSame && isEventSame
|
||||
&& isAdminSoundsSame && isLobbyVolumeSame && isInterfaceVolumeSame;
|
||||
isEverythingSame = isEverythingSame && isTtsVolumeSame; //WD-EDIT
|
||||
isEverythingSame = isEverythingSame && isTtsVolumeSame && isJukeboxVolumeSame; //WD-EDIT
|
||||
ApplyButton.Disabled = isEverythingSame;
|
||||
ResetButton.Disabled = isEverythingSame;
|
||||
MasterVolumeLabel.Text =
|
||||
@@ -249,6 +263,8 @@ namespace Content.Client.Options.UI.Tabs
|
||||
//WD-EDIT
|
||||
TtsVolumeLabel.Text =
|
||||
Loc.GetString("ui-options-volume-percent", ("volume", TtsVolumeSlider.Value / 100));
|
||||
JukeboxVolumeLabel.Text =
|
||||
Loc.GetString("ui-options-volume-percent", ("volume", JukeboxVolumeSlider.Value / 100));
|
||||
//WD-EDIT
|
||||
}
|
||||
}
|
||||
|
||||
10
Content.Client/White/CheZaHuetaSystem.cs
Normal file
10
Content.Client/White/CheZaHuetaSystem.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Content.Client.White;
|
||||
|
||||
//Система со смешным названием, чье предназначение заключается лишь в одном - отправке нетворк ивентов.
|
||||
public sealed class CheZaHuetaSystem : EntitySystem
|
||||
{
|
||||
public void SendNetMessage(EntityEventArgs message)
|
||||
{
|
||||
RaiseNetworkEvent(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Content.Shared.White.Jukebox;
|
||||
|
||||
namespace Content.Client.White.Jukebox;
|
||||
|
||||
public sealed class ClientJukeboxSongsSyncManager : JukeboxSongsSyncManager
|
||||
{
|
||||
public override void OnSongUploaded(JukeboxSongUploadNetMessage message)
|
||||
{
|
||||
ContentRoot.AddOrUpdateFile(message.RelativePath!, message.Data);
|
||||
}
|
||||
}
|
||||
70
Content.Client/White/Jukebox/JukeboxBUI.cs
Normal file
70
Content.Client/White/Jukebox/JukeboxBUI.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.White.Jukebox;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
|
||||
namespace Content.Client.White.Jukebox;
|
||||
|
||||
public sealed class JukeboxBUI : BoundUserInterface
|
||||
{
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
private readonly SharedPopupSystem _sharedPopupSystem = default!;
|
||||
|
||||
private JukeboxMenu? _window;
|
||||
public JukeboxBUI(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_sharedPopupSystem = _entityManager.System<SharedPopupSystem>();
|
||||
|
||||
var uid = owner.Owner;
|
||||
|
||||
if (!_entityManager.TryGetComponent<JukeboxComponent>(uid, out var jukeboxComponent))
|
||||
{
|
||||
_sharedPopupSystem.PopupEntity($"Тут нет JukeboxComponent, звоните кодерам", uid);
|
||||
return;
|
||||
}
|
||||
|
||||
_window = new JukeboxMenu(jukeboxComponent);
|
||||
_window.RepeatButton.OnToggled += OnRepeatButtonToggled;
|
||||
_window.StopButton.OnPressed += OnStopButtonPressed;
|
||||
_window.EjectButton.OnPressed += OnEjectButtonPressed;
|
||||
}
|
||||
|
||||
private void OnEjectButtonPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
SendMessage(new JukeboxEjectRequest());
|
||||
}
|
||||
|
||||
private void OnStopButtonPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
SendMessage(new JukeboxStopRequest());
|
||||
}
|
||||
|
||||
private void OnRepeatButtonToggled(BaseButton.ButtonToggledEventArgs obj)
|
||||
{
|
||||
SendMessage(new JukeboxRepeatToggled(obj.Pressed));
|
||||
}
|
||||
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
if (_window == null)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
_window.OpenCentered();
|
||||
_window.OnClose += Close;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing) return;
|
||||
|
||||
_window?.Dispose();
|
||||
}
|
||||
}
|
||||
29
Content.Client/White/Jukebox/JukeboxMenu.xaml
Normal file
29
Content.Client/White/Jukebox/JukeboxMenu.xaml
Normal file
@@ -0,0 +1,29 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io" MinSize="600 700" Name="BoomBoxWindow" Title="Альфа-Шкварки">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<Label Name="CurrenSongLabel" HorizontalAlignment="Center" HorizontalExpand="True"></Label>
|
||||
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Button Access="Internal" Name="StopButton" Text="Остановить" HorizontalAlignment="Right"></Button>
|
||||
<Button Access="Internal" Name="RepeatButton" Text="Повторять" HorizontalAlignment="Right" ToggleMode="True"></Button>
|
||||
<Button Access="Internal" Name="EjectButton" Text="Извлечь"></Button>
|
||||
</BoxContainer>
|
||||
|
||||
<TabContainer VerticalExpand="True" HorizontalExpand="True">
|
||||
<!-- <ScrollContainer Name="DefaultSongsTab"
|
||||
HScrollEnabled="False">
|
||||
<BoxContainer Name="DefaultSongsContainer"
|
||||
Orientation="Vertical"
|
||||
Margin="2 2 0 0"
|
||||
HorizontalExpand="True">
|
||||
</BoxContainer>
|
||||
</ScrollContainer> -->
|
||||
<ScrollContainer Name="TapeSongsTab"
|
||||
HScrollEnabled="False">
|
||||
<BoxContainer Name="TapeSongsContainer"
|
||||
Orientation="Vertical"
|
||||
Margin="2 2 0 0"
|
||||
HorizontalExpand="True">
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
</TabContainer>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
100
Content.Client/White/Jukebox/JukeboxMenu.xaml.cs
Normal file
100
Content.Client/White/Jukebox/JukeboxMenu.xaml.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.White.Jukebox;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Timing;
|
||||
using TerraFX.Interop.Windows;
|
||||
|
||||
namespace Content.Client.White.Jukebox;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class JukeboxMenu : DefaultWindow
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
private readonly JukeboxSystem _jukeboxSystem = default!;
|
||||
|
||||
private readonly JukeboxComponent _component;
|
||||
|
||||
private List<JukeboxSongEntry> _defaultSongsEntries = new();
|
||||
private List<JukeboxSongEntry> _tapeSongsEntries = new();
|
||||
|
||||
public JukeboxMenu(JukeboxComponent component)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_jukeboxSystem = _entityManager.System<JukeboxSystem>();
|
||||
|
||||
_component = component;
|
||||
|
||||
/*TabContainer.SetTabTitle(DefaultSongsTab, "Прямо с завода");*/
|
||||
TabContainer.SetTabTitle(TapeSongsTab, "Песенки с кассеты");
|
||||
|
||||
/*PopulateDefaultSongsContainer(DefaultSongsContainer);*/
|
||||
PopulateTapeSongsContainer(TapeSongsContainer);
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
CurrenSongLabel.Text = _component.PlayingSongData == null ? "..." : _component.PlayingSongData.SongName!;
|
||||
|
||||
RepeatButton.Pressed = _component.Repeating;
|
||||
|
||||
base.FrameUpdate(args);
|
||||
}
|
||||
|
||||
private void PopulateDefaultSongsContainer(BoxContainer defaultSongsContainer)
|
||||
{
|
||||
var tapes = _component.DefaultSongsContainer.ContainedEntities.ToList();
|
||||
|
||||
foreach (var tapeUid in tapes)
|
||||
{
|
||||
if (_entityManager.TryGetComponent<TapeComponent>(tapeUid, out var tape))
|
||||
{
|
||||
foreach (var song in tape.Songs)
|
||||
{
|
||||
var songEntry = new JukeboxSongEntry(song, RequestSongPlay);
|
||||
|
||||
_defaultSongsEntries.Add(songEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_defaultSongsEntries.Sort((x,y ) => string.Compare(x.Name!, y.Name!, StringComparison.Ordinal));
|
||||
|
||||
foreach (var defaultSongsEntry in _defaultSongsEntries)
|
||||
{
|
||||
defaultSongsContainer.AddChild(defaultSongsEntry);
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateTapeSongsContainer(BoxContainer tapeSongsContainer)
|
||||
{
|
||||
var tapes = _component.TapeContainer.ContainedEntities.ToList();
|
||||
|
||||
foreach (var tapeUid in tapes)
|
||||
{
|
||||
if (_entityManager.TryGetComponent<TapeComponent>(tapeUid, out var tape))
|
||||
{
|
||||
foreach (var song in tape.Songs)
|
||||
{
|
||||
var songEntry = new JukeboxSongEntry(song, RequestSongPlay);
|
||||
|
||||
_tapeSongsEntries.Add(songEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var tapeSongsEntry in _tapeSongsEntries)
|
||||
{
|
||||
tapeSongsContainer.AddChild(tapeSongsEntry);
|
||||
}
|
||||
}
|
||||
|
||||
private void RequestSongPlay(JukeboxSong song)
|
||||
{
|
||||
_jukeboxSystem.RequestSongToPlay(_component, song);
|
||||
}
|
||||
}
|
||||
13
Content.Client/White/Jukebox/JukeboxSongEntry.xaml
Normal file
13
Content.Client/White/Jukebox/JukeboxSongEntry.xaml
Normal file
@@ -0,0 +1,13 @@
|
||||
<Control xmlns="https://spacestation14.io"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client">
|
||||
<PanelContainer MaxHeight="32" HorizontalExpand="True" Margin="2 2 2 2">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#7B7E7E"></gfx:StyleBoxFlat>
|
||||
</PanelContainer.PanelOverride>
|
||||
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" >
|
||||
<Label Name="SongNameLabel" HorizontalAlignment="Left" HorizontalExpand="True"></Label>
|
||||
<Button Name="PlaySongButton" HorizontalAlignment="Right" Text="Запустить"></Button>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</Control>
|
||||
25
Content.Client/White/Jukebox/JukeboxSongEntry.xaml.cs
Normal file
25
Content.Client/White/Jukebox/JukeboxSongEntry.xaml.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Content.Shared.White.Jukebox;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client.White.Jukebox;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class JukeboxSongEntry : Control
|
||||
{
|
||||
public JukeboxSong? Song { get; private set; }
|
||||
|
||||
private JukeboxSongEntry()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
public JukeboxSongEntry(JukeboxSong song, Action<JukeboxSong> callback) : this()
|
||||
{
|
||||
Song = song;
|
||||
SongNameLabel.Text = Song.SongName;
|
||||
PlaySongButton.OnPressed += _ => callback.Invoke(Song);
|
||||
}
|
||||
}
|
||||
277
Content.Client/White/Jukebox/JukeboxSystem.cs
Normal file
277
Content.Client/White/Jukebox/JukeboxSystem.cs
Normal file
@@ -0,0 +1,277 @@
|
||||
using System.Resources;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.White;
|
||||
using Content.Shared.White.Jukebox;
|
||||
using Robust.Client.Audio;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Physics;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.White.Jukebox;
|
||||
|
||||
public sealed class JukeboxSystem : EntitySystem
|
||||
{
|
||||
|
||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IResourceCache _resource = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
|
||||
|
||||
|
||||
|
||||
private readonly Dictionary<JukeboxComponent, JukeboxAudio> _playingJukeboxes = new();
|
||||
|
||||
private float _maxAudioRange;
|
||||
private float _jukeboxVolume;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_cfg.OnValueChanged(WhiteCVars.MaxJukeboxSoundRange, range => _maxAudioRange = range, true);
|
||||
_cfg.OnValueChanged(WhiteCVars.JukeboxVolume, volume => JukeboxVolumeChanged(volume), true);
|
||||
|
||||
SubscribeLocalEvent<JukeboxComponent, ComponentHandleState>(OnStateChanged);
|
||||
SubscribeLocalEvent<JukeboxComponent, ComponentRemove>(OnComponentRemoved);
|
||||
SubscribeNetworkEvent<RoundRestartCleanupEvent>(OnRoundRestart);
|
||||
SubscribeNetworkEvent<TickerJoinLobbyEvent>(JoinLobby);
|
||||
SubscribeNetworkEvent<JukeboxStopPlaying>(OnStopPlaying);
|
||||
}
|
||||
|
||||
private void JukeboxVolumeChanged(float volume)
|
||||
{
|
||||
_jukeboxVolume = volume;
|
||||
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
private void JoinLobby(TickerJoinLobbyEvent ev)
|
||||
{
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
private void OnRoundRestart(RoundRestartCleanupEvent ev)
|
||||
{
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
private void OnComponentRemoved(EntityUid uid, JukeboxComponent component, ComponentRemove args)
|
||||
{
|
||||
if (!_playingJukeboxes.TryGetValue(component, out var playingData)) return;
|
||||
playingData.PlayingStream.Stop();
|
||||
_playingJukeboxes.Remove(component);
|
||||
}
|
||||
|
||||
private void OnStopPlaying(JukeboxStopPlaying ev)
|
||||
{
|
||||
if (!ev.JukeboxUid.HasValue) return;
|
||||
if(!TryComp<JukeboxComponent>(ev.JukeboxUid, out var jukeboxComponent)) return;
|
||||
|
||||
if(!_playingJukeboxes.TryGetValue(jukeboxComponent, out var jukeboxAudio)) return;
|
||||
|
||||
jukeboxAudio.PlayingStream.Stop();
|
||||
_playingJukeboxes.Remove(jukeboxComponent);
|
||||
}
|
||||
|
||||
public void RequestSongToPlay(JukeboxComponent component, JukeboxSong jukeboxSong)
|
||||
{
|
||||
if (!_resource.TryGetResource<AudioResource>((ResPath) jukeboxSong.SongPath!, out var songResource))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RaiseNetworkEvent(new JukeboxRequestSongPlay()
|
||||
{
|
||||
Jukebox = component.Owner,
|
||||
SongName = jukeboxSong.SongName,
|
||||
SongPath = jukeboxSong.SongPath,
|
||||
SongDuration = (float)songResource.AudioStream.Length.TotalSeconds
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var localPlayerEntity = _playerManager.LocalPlayer!.ControlledEntity;
|
||||
if(!localPlayerEntity.HasValue) return;
|
||||
|
||||
ProcessJukeboxes();
|
||||
}
|
||||
|
||||
private void OnStateChanged(EntityUid uid, JukeboxComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is JukeboxComponentState state)
|
||||
{
|
||||
component.Repeating = state.Playing;
|
||||
component.Volume = state.Volume;
|
||||
component.PlayingSongData = state.SongData;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessJukeboxes()
|
||||
{
|
||||
var jukeboxes = EntityQuery<JukeboxComponent, TransformComponent>();
|
||||
var playerXform = Comp<TransformComponent>(_playerManager.LocalPlayer!.ControlledEntity!.Value);
|
||||
|
||||
foreach (var (jukeboxComponent, jukeboxXform) in jukeboxes)
|
||||
{
|
||||
|
||||
if(jukeboxXform.MapID != playerXform.MapID) continue;
|
||||
if ((jukeboxXform.MapPosition.Position - playerXform.MapPosition.Position).Length > _maxAudioRange) continue;
|
||||
|
||||
if (_playingJukeboxes.TryGetValue(jukeboxComponent, out var jukeboxAudio))
|
||||
{
|
||||
if (jukeboxAudio.PlayingStream.Done)
|
||||
{
|
||||
HandleDoneStream(jukeboxAudio, jukeboxComponent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (jukeboxAudio.SongData.SongPath != jukeboxComponent.PlayingSongData?.SongPath)
|
||||
{
|
||||
HandleSongChanged(jukeboxAudio, jukeboxComponent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (jukeboxComponent.PlayingSongData == null)
|
||||
{
|
||||
SetBarsLayerVisible(jukeboxComponent, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
var stream = TryCreateStream(jukeboxComponent);
|
||||
|
||||
if (stream == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_playingJukeboxes.Add(jukeboxComponent, stream);
|
||||
SetBarsLayerVisible(jukeboxComponent, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSongChanged(JukeboxAudio jukeboxAudio, JukeboxComponent jukeboxComponent)
|
||||
{
|
||||
jukeboxAudio.PlayingStream.Stop();
|
||||
|
||||
if (jukeboxComponent.PlayingSongData != null && jukeboxComponent.PlayingSongData.SongPath == jukeboxAudio.SongData.SongPath)
|
||||
{
|
||||
var newStream = TryCreateStream(jukeboxComponent);
|
||||
if(newStream == null) return;
|
||||
|
||||
_playingJukeboxes[jukeboxComponent] = newStream;
|
||||
SetBarsLayerVisible(jukeboxComponent, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_playingJukeboxes.Remove(jukeboxComponent);
|
||||
SetBarsLayerVisible(jukeboxComponent, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDoneStream(JukeboxAudio jukeboxAudio, JukeboxComponent jukeboxComponent)
|
||||
{
|
||||
if (!jukeboxComponent.Repeating)
|
||||
{
|
||||
jukeboxAudio.PlayingStream.Stop();
|
||||
_playingJukeboxes.Remove(jukeboxComponent);
|
||||
SetBarsLayerVisible(jukeboxComponent, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if(jukeboxComponent.PlayingSongData == null) return;
|
||||
|
||||
|
||||
var newStream = TryCreateStream(jukeboxComponent);
|
||||
|
||||
if (newStream == null)
|
||||
{
|
||||
_playingJukeboxes.Remove(jukeboxComponent);
|
||||
SetBarsLayerVisible(jukeboxComponent, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
_playingJukeboxes[jukeboxComponent] = newStream;
|
||||
SetBarsLayerVisible(jukeboxComponent, true);
|
||||
}
|
||||
}
|
||||
|
||||
private JukeboxAudio? TryCreateStream(JukeboxComponent jukeboxComponent)
|
||||
{
|
||||
if (jukeboxComponent.PlayingSongData == null) return null;
|
||||
|
||||
var resourcePath = jukeboxComponent.PlayingSongData.SongPath!;
|
||||
var localSession = _playerManager.LocalPlayer!.Session;
|
||||
|
||||
if(!_resource.TryGetResource<AudioResource>((ResPath) resourcePath, out var audio))
|
||||
return null!;
|
||||
|
||||
if (audio!.AudioStream.Length.TotalSeconds < jukeboxComponent.PlayingSongData!.PlaybackPosition)
|
||||
{
|
||||
return null!;
|
||||
}
|
||||
|
||||
var audioParams = new AudioParams
|
||||
{
|
||||
PlayOffsetSeconds = jukeboxComponent.PlayingSongData.PlaybackPosition,
|
||||
Volume = _jukeboxVolume,
|
||||
MaxDistance = _maxAudioRange
|
||||
};
|
||||
|
||||
AudioSystem.PlayingStream? playingStream = null!;
|
||||
|
||||
playingStream = _audioSystem.PlayEntity(resourcePath.ToString()!, localSession, jukeboxComponent.Owner, audioParams) as AudioSystem.PlayingStream;
|
||||
|
||||
if (playingStream == null)
|
||||
return null!;
|
||||
|
||||
return new JukeboxAudio(playingStream, audio!, jukeboxComponent.PlayingSongData);
|
||||
}
|
||||
|
||||
private class JukeboxAudio
|
||||
{
|
||||
public PlayingSongData SongData { get; }
|
||||
public AudioSystem.PlayingStream PlayingStream { get; }
|
||||
public AudioResource AudioStream { get; }
|
||||
|
||||
public JukeboxAudio(AudioSystem.PlayingStream playingStream, AudioResource audioStream, PlayingSongData songData)
|
||||
{
|
||||
PlayingStream = playingStream;
|
||||
AudioStream = audioStream;
|
||||
SongData = songData;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetBarsLayerVisible(JukeboxComponent jukeboxComponent, bool visible)
|
||||
{
|
||||
var spriteComponent = Comp<SpriteComponent>(jukeboxComponent.Owner);
|
||||
spriteComponent.LayerMapTryGet("bars", out var layer);
|
||||
spriteComponent.LayerSetVisible(layer, visible);
|
||||
}
|
||||
|
||||
private void CleanUp()
|
||||
{
|
||||
foreach (var playingJukebox in _playingJukeboxes.Values)
|
||||
{
|
||||
playingJukebox.PlayingStream.Stop();
|
||||
}
|
||||
|
||||
_playingJukeboxes.Clear();
|
||||
}
|
||||
}
|
||||
51
Content.Client/White/Jukebox/TapeCreatorBUI.cs
Normal file
51
Content.Client/White/Jukebox/TapeCreatorBUI.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.White.Jukebox;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.White.Jukebox;
|
||||
|
||||
public sealed class TapeCreatorBUI : BoundUserInterface
|
||||
{
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
private readonly SharedPopupSystem _sharedPopupSystem = default!;
|
||||
|
||||
private TapeCreatorMenu? _window;
|
||||
|
||||
public TapeCreatorBUI(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_sharedPopupSystem = _entityManager.System<SharedPopupSystem>();
|
||||
|
||||
var uid = owner.Owner;
|
||||
|
||||
if (!_entityManager.TryGetComponent<TapeCreatorComponent>(uid, out var tapeCreatorComponent))
|
||||
{
|
||||
_sharedPopupSystem.PopupEntity($"Тут нет TapeCreatorComponent, звоните кодерам", uid);
|
||||
return;
|
||||
}
|
||||
|
||||
_window = new TapeCreatorMenu(tapeCreatorComponent);
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
if (_window == null)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
_window.OpenCentered();
|
||||
_window.OnClose += Close;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing) return;
|
||||
|
||||
_window?.Dispose();
|
||||
}
|
||||
}
|
||||
16
Content.Client/White/Jukebox/TapeCreatorMenu.xaml
Normal file
16
Content.Client/White/Jukebox/TapeCreatorMenu.xaml
Normal file
@@ -0,0 +1,16 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io" MinSize="200 300" Title="Мысль">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" SetHeight="30">
|
||||
<Label Text="Осталось циклов записи: "></Label>
|
||||
<Label Name="CoinsLabel" Text="0"></Label>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Vertical" SeparationOverride="5">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" SetHeight="30">
|
||||
<Label Text="Название"></Label>
|
||||
<LineEdit Name="SongNameField" MinWidth="200"></LineEdit>
|
||||
<Button Name="LoadSongButton" Access="Internal" Text="Загрузить песню"></Button>
|
||||
</BoxContainer>
|
||||
<Button Name="UploadSong" Access="Internal" Text="Записать мозговую активность" MinHeight="50" HorizontalExpand="True"></Button>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
125
Content.Client/White/Jukebox/TapeCreatorMenu.xaml.cs
Normal file
125
Content.Client/White/Jukebox/TapeCreatorMenu.xaml.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.White;
|
||||
using Content.Shared.White.Jukebox;
|
||||
using JetBrains.Annotations;
|
||||
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.Configuration;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.White.Jukebox;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class TapeCreatorMenu : DefaultWindow
|
||||
{
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IFileDialogManager _fileDialogManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
private readonly CheZaHuetaSystem _huetaSystem = default!;
|
||||
private readonly SharedPopupSystem _popupSystem = default!;
|
||||
|
||||
private bool _fileDialogOpened;
|
||||
private double _maxFileSize;
|
||||
private double _currentFileSize;
|
||||
private readonly List<byte> _songBytes = new();
|
||||
private TapeCreatorComponent _component;
|
||||
|
||||
private const double BytesToMegabytes = 0.000001d;
|
||||
|
||||
public TapeCreatorMenu(TapeCreatorComponent component)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_huetaSystem = _entityManager.System<CheZaHuetaSystem>();
|
||||
_popupSystem = _entityManager.System<SharedPopupSystem>();
|
||||
|
||||
_cfg.OnValueChanged(WhiteCVars.MaxJukeboxSongSizeInMB, x => _maxFileSize = x, true);
|
||||
|
||||
_component = component;
|
||||
|
||||
LoadSongButton.OnPressed += TryLoadSong;
|
||||
UploadSong.OnPressed += OnUploadButtonPressed;
|
||||
}
|
||||
|
||||
private void OnUploadButtonPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
if(!CanUploadSong()) return;
|
||||
|
||||
var input = SongNameField.Text;
|
||||
|
||||
string pattern = @"[^a-zA-Zа-яА-Я ]+";
|
||||
string replacement = "";
|
||||
|
||||
var songName = Regex.Replace(input, pattern, replacement);
|
||||
songName = Regex.Replace(songName, @"\s+", " ");
|
||||
|
||||
var songBytes = _songBytes;
|
||||
|
||||
var msg = new JukeboxSongUploadRequest()
|
||||
{
|
||||
SongName = songName,
|
||||
SongBytes = songBytes,
|
||||
TapeCreatorUid = _component.Owner
|
||||
};
|
||||
|
||||
_huetaSystem.SendNetMessage(msg);
|
||||
|
||||
_currentFileSize = 0;
|
||||
_songBytes.Clear();
|
||||
SongNameField.Clear();
|
||||
|
||||
_popupSystem.PopupEntity("Внимание. Начинается запись мозговой активности.", _component.Owner);
|
||||
}
|
||||
|
||||
private async void TryLoadSong(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
var fileFilter = new FileDialogFilters(new FileDialogFilters.Group("ogg"));
|
||||
|
||||
var file = await _fileDialogManager.OpenFile(fileFilter);
|
||||
|
||||
if (Disposed) return;
|
||||
|
||||
if(file == null) return;
|
||||
|
||||
_currentFileSize = file.Length * BytesToMegabytes;
|
||||
|
||||
if (_currentFileSize > _maxFileSize)
|
||||
{
|
||||
_popupSystem.PopupEntity($"Лимит активности мозговых волн превышен на {_currentFileSize - _maxFileSize} мегахрюков", _component.Owner);
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: Песня слишком длинная пиздец
|
||||
|
||||
_songBytes.AddRange(file.CopyToArray());
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
|
||||
CoinsLabel.Text = _component.CoinBalance.ToString();
|
||||
|
||||
if (CanUploadSong())
|
||||
{
|
||||
UploadSong.Disabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
UploadSong.Disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanUploadSong()
|
||||
{
|
||||
return SongNameField.Text.Length > 0 && _songBytes.Count > 0 && _component.CoinBalance > 0 && _component.InsertedTape.HasValue && !_component.Recording;
|
||||
}
|
||||
}
|
||||
41
Content.Client/White/Jukebox/TapeCreatorSystem.cs
Normal file
41
Content.Client/White/Jukebox/TapeCreatorSystem.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Content.Shared.White.Jukebox;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Client.White.Jukebox;
|
||||
|
||||
public sealed class TapeCreatorSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<TapeCreatorComponent, ComponentHandleState>(OnStateChanged);
|
||||
SubscribeLocalEvent<TapeComponent, ComponentHandleState>(OnTapeStateChanged);
|
||||
}
|
||||
|
||||
private void OnTapeStateChanged(EntityUid uid, TapeComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not TapeComponentState state) return;
|
||||
|
||||
component.Songs = state.Songs;
|
||||
}
|
||||
|
||||
private void OnStateChanged(EntityUid uid, TapeCreatorComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not TapeCreatorComponentState state) return;
|
||||
|
||||
component.Recording = state.Recording;
|
||||
component.CoinBalance = state.CoinBalance;
|
||||
component.InsertedTape = state.InsertedTape;
|
||||
|
||||
SetTapeLayerVisible(component, state.InsertedTape.HasValue);
|
||||
}
|
||||
|
||||
private void SetTapeLayerVisible(TapeCreatorComponent component, bool visible)
|
||||
{
|
||||
var spriteComponent = Comp<SpriteComponent>(component.Owner);
|
||||
spriteComponent.LayerMapTryGet("tape", out var layer);
|
||||
spriteComponent.LayerSetVisible(layer, visible);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Server.UtkaIntegration;
|
||||
using Content.Server.White.JoinQueue;
|
||||
using Content.Server.White.Jukebox;
|
||||
using Content.Server.White.Sponsors;
|
||||
using Content.Server.White.Stalin;
|
||||
using Content.Server.White.TTS;
|
||||
@@ -113,6 +114,7 @@ namespace Content.Server.Entry
|
||||
IoCManager.Resolve<JoinQueueManager>().Initialize();
|
||||
IoCManager.Resolve<TTSManager>().Initialize();
|
||||
IoCManager.Resolve<StalinManager>().Initialize();
|
||||
IoCManager.Resolve<ServerJukeboxSongsSyncManager>().Initialize();
|
||||
//WD-EDIT
|
||||
|
||||
_voteManager.Initialize();
|
||||
|
||||
@@ -21,6 +21,7 @@ using Content.Server.Voting.Managers;
|
||||
using Content.Server.Worldgen.Tools;
|
||||
using Content.Server.UtkaIntegration;
|
||||
using Content.Server.White.JoinQueue;
|
||||
using Content.Server.White.Jukebox;
|
||||
using Content.Server.White.Sponsors;
|
||||
using Content.Server.White.Stalin;
|
||||
using Content.Server.White.TTS;
|
||||
@@ -71,6 +72,7 @@ namespace Content.Server.IoC
|
||||
IoCManager.Register<UtkaTCPWrapper>();
|
||||
IoCManager.Register<TTSManager>();
|
||||
IoCManager.Register<StalinManager>();
|
||||
IoCManager.Register<ServerJukeboxSongsSyncManager>();
|
||||
// WD-EDIT
|
||||
}
|
||||
}
|
||||
|
||||
207
Content.Server/White/Jukebox/JukeboxSystem.cs
Normal file
207
Content.Server/White/Jukebox/JukeboxSystem.cs
Normal file
@@ -0,0 +1,207 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.White.Jukebox;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameStates;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.White.Jukebox;
|
||||
|
||||
public sealed class JukeboxSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AudioSystem _audioSystem = default!;
|
||||
[Dependency] private readonly IResourceManager _resourceManager = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly PVSOverrideSystem _pvsOverrideSystem = default!;
|
||||
|
||||
|
||||
private readonly List<JukeboxComponent> _playingJukeboxes = new();
|
||||
|
||||
private float _updateTimerDefaultTime = 1f;
|
||||
private float _updateTimer;
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeNetworkEvent<JukeboxRequestSongPlay>(OnSongRequestPlay);
|
||||
SubscribeLocalEvent<JukeboxComponent, InteractUsingEvent>(OnInteract);
|
||||
SubscribeLocalEvent<JukeboxComponent, ComponentGetState>(OnGetState);
|
||||
SubscribeLocalEvent<JukeboxComponent, JukeboxStopRequest>(OnRequestStop);
|
||||
SubscribeLocalEvent<JukeboxComponent, JukeboxRepeatToggled>(OnRepeatToggled);
|
||||
SubscribeLocalEvent<JukeboxComponent, JukeboxEjectRequest>(OnEjectRequest);
|
||||
SubscribeLocalEvent<JukeboxComponent, GetVerbsEvent<Verb>>(OnGetVerb);
|
||||
SubscribeLocalEvent<JukeboxComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart);
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, JukeboxComponent component, ComponentInit args)
|
||||
{
|
||||
_pvsOverrideSystem.AddGlobalOverride(uid);
|
||||
}
|
||||
|
||||
private void OnRoundRestart(RoundRestartCleanupEvent ev)
|
||||
{
|
||||
_playingJukeboxes.Clear();
|
||||
}
|
||||
|
||||
private void OnEjectRequest(EntityUid uid, JukeboxComponent component, JukeboxEjectRequest args)
|
||||
{
|
||||
if(component.PlayingSongData != null) return;
|
||||
|
||||
var containedEntities = component.TapeContainer.ContainedEntities;
|
||||
|
||||
if (containedEntities.Count > 0)
|
||||
{
|
||||
_containerSystem.EmptyContainer(component.TapeContainer, true).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGetVerb(EntityUid uid, JukeboxComponent jukeboxComponent, GetVerbsEvent<Verb> ev)
|
||||
{
|
||||
if (ev.Hands == null) return;
|
||||
if (jukeboxComponent.PlayingSongData != null) return;
|
||||
if (jukeboxComponent.TapeContainer.ContainedEntities.Count == 0) return;
|
||||
|
||||
var removeTapeVerb = new Verb()
|
||||
{
|
||||
Text = "Вытащить касету",
|
||||
Priority = 10000,
|
||||
Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/remove_tape.png")),
|
||||
Act = () =>
|
||||
{
|
||||
var tapes = jukeboxComponent.TapeContainer.ContainedEntities.ToList();
|
||||
_containerSystem.EmptyContainer(jukeboxComponent.TapeContainer, true);
|
||||
|
||||
foreach (var tape in tapes)
|
||||
{
|
||||
_handsSystem.PickupOrDrop(ev.User, tape);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ev.Verbs.Add(removeTapeVerb);
|
||||
}
|
||||
|
||||
private void OnRepeatToggled(EntityUid uid, JukeboxComponent component, JukeboxRepeatToggled args)
|
||||
{
|
||||
component.Repeating = args.NewState;
|
||||
Dirty(component);
|
||||
}
|
||||
|
||||
private void OnRequestStop(EntityUid uid, JukeboxComponent component, JukeboxStopRequest args)
|
||||
{
|
||||
component.PlayingSongData = null;
|
||||
Dirty(component);
|
||||
}
|
||||
|
||||
|
||||
private void OnInteract(EntityUid uid, JukeboxComponent component, InteractUsingEvent args)
|
||||
{
|
||||
if(component.PlayingSongData != null) return;
|
||||
|
||||
if (TryComp<TapeComponent>(args.Used, out var tape))
|
||||
{
|
||||
var containedEntities = component.TapeContainer.ContainedEntities;
|
||||
|
||||
if (containedEntities.Count >= 1)
|
||||
{
|
||||
var removedTapes = _containerSystem.EmptyContainer(component.TapeContainer, true).ToList();
|
||||
component.TapeContainer.Insert(args.Used);
|
||||
|
||||
foreach (var tapeUid in removedTapes)
|
||||
{
|
||||
_handsSystem.PickupOrDrop(args.User, tapeUid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
component.TapeContainer.Insert(args.Used);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSongRequestPlay(JukeboxRequestSongPlay msg, EntitySessionEventArgs args)
|
||||
{
|
||||
var jukebox = Comp<JukeboxComponent>(msg.Jukebox!.Value);
|
||||
jukebox.Repeating = true;
|
||||
|
||||
var songData = new PlayingSongData()
|
||||
{
|
||||
SongName = msg.SongName,
|
||||
SongPath = msg.SongPath,
|
||||
ActualSongLengthSeconds = msg.SongDuration,
|
||||
PlaybackPosition = 0f
|
||||
};
|
||||
jukebox.PlayingSongData = songData;
|
||||
|
||||
_playingJukeboxes.Add(jukebox);
|
||||
|
||||
Dirty(jukebox);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
if (_updateTimer <= _updateTimerDefaultTime)
|
||||
{
|
||||
_updateTimer += frameTime;
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessPlayingJukeboxes(frameTime);
|
||||
}
|
||||
|
||||
private void ProcessPlayingJukeboxes(float frameTime)
|
||||
{
|
||||
for (int i = _playingJukeboxes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var playingJukeboxData = _playingJukeboxes[i];
|
||||
|
||||
if (playingJukeboxData.PlayingSongData == null)
|
||||
{
|
||||
_playingJukeboxes.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
playingJukeboxData.PlayingSongData.PlaybackPosition += _updateTimer;
|
||||
|
||||
if (playingJukeboxData.PlayingSongData.PlaybackPosition >= playingJukeboxData.PlayingSongData.ActualSongLengthSeconds)
|
||||
{
|
||||
if (playingJukeboxData.Repeating)
|
||||
{
|
||||
playingJukeboxData.PlayingSongData.PlaybackPosition = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
RaiseNetworkEvent(new JukeboxStopPlaying());
|
||||
_playingJukeboxes.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
Dirty(playingJukeboxData);
|
||||
}
|
||||
|
||||
_updateTimer = 0;
|
||||
}
|
||||
|
||||
private void OnGetState(EntityUid uid, JukeboxComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new JukeboxComponentState()
|
||||
{
|
||||
SongData = component.PlayingSongData,
|
||||
Playing = component.Repeating,
|
||||
Volume = component.Volume
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using Content.Shared.White.Jukebox;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.White.Jukebox;
|
||||
|
||||
public sealed class ServerJukeboxSongsSyncManager : JukeboxSongsSyncManager
|
||||
{
|
||||
[Dependency] private readonly INetManager _netManager = default!;
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_netManager.Connected += OnClientConnected;
|
||||
}
|
||||
|
||||
private void OnClientConnected(object? sender, NetChannelArgs e)
|
||||
{
|
||||
foreach (var (path, data) in ContentRoot.GetAllFiles())
|
||||
{
|
||||
var msg = new JukeboxSongUploadNetMessage
|
||||
{
|
||||
RelativePath = path,
|
||||
Data = data
|
||||
};
|
||||
|
||||
e.Channel.SendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public (string songName, ResPath path) SyncSongData(string songName, List<byte> bytes)
|
||||
{
|
||||
if (ContentRoot.TryGetFile(new ResPath(songName + ".ogg"), out _))
|
||||
{
|
||||
songName += "a";
|
||||
}
|
||||
|
||||
var msg = new JukeboxSongUploadNetMessage()
|
||||
{
|
||||
Data = bytes.ToArray(),
|
||||
RelativePath = new ResPath(songName + ".ogg")
|
||||
};
|
||||
|
||||
OnSongUploaded(msg);
|
||||
var path = new ResPath($"{Prefix}/{songName}.ogg");
|
||||
return (songName, path);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override void OnSongUploaded(JukeboxSongUploadNetMessage message)
|
||||
{
|
||||
|
||||
ContentRoot.AddOrUpdateFile(message.RelativePath, message.Data);
|
||||
|
||||
foreach (var channel in _netManager.Channels)
|
||||
{
|
||||
channel.SendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
181
Content.Server/White/Jukebox/TapeCreatorSystem.cs
Normal file
181
Content.Server/White/Jukebox/TapeCreatorSystem.cs
Normal file
@@ -0,0 +1,181 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.White.Jukebox;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.White.Jukebox;
|
||||
|
||||
public sealed class TapeCreatorSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly ServerJukeboxSongsSyncManager _songsSyncManager = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||
|
||||
|
||||
private readonly int _recordTime = 25;
|
||||
|
||||
private static string TapeCreatorContainerName = "tape_creator_container";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeNetworkEvent<JukeboxSongUploadRequest>(OnSongUploaded);
|
||||
SubscribeLocalEvent<TapeCreatorComponent, ComponentInit>(OnComponentInit);
|
||||
SubscribeLocalEvent<TapeCreatorComponent, InteractUsingEvent>(OnInteract);
|
||||
SubscribeLocalEvent<TapeCreatorComponent, GetVerbsEvent<Verb>>(OnTapeCreatorGetVerb);
|
||||
SubscribeLocalEvent<TapeCreatorComponent, ComponentGetState>(OnTapeCreatorStateChanged);
|
||||
SubscribeLocalEvent<TapeComponent, ComponentGetState>(OnTapeStateChanged);
|
||||
}
|
||||
|
||||
private void OnTapeCreatorGetVerb(EntityUid uid, TapeCreatorComponent component, GetVerbsEvent<Verb> ev)
|
||||
{
|
||||
if (component.Recording) return;
|
||||
if (ev.Hands == null) return;
|
||||
if (component.TapeContainer.ContainedEntities.Count == 0) return;
|
||||
|
||||
var removeTapeVerb = new Verb()
|
||||
{
|
||||
Text = "Вытащить касету",
|
||||
Priority = 10000,
|
||||
Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/remove_tape.png")),
|
||||
Act = () =>
|
||||
{
|
||||
var tapes = component.TapeContainer.ContainedEntities.ToList();
|
||||
_containerSystem.EmptyContainer(component.TapeContainer, true);
|
||||
|
||||
foreach (var tape in tapes)
|
||||
{
|
||||
_handsSystem.PickupOrDrop(ev.User, tape);
|
||||
}
|
||||
|
||||
component.InsertedTape = null;
|
||||
Dirty(component);
|
||||
}
|
||||
};
|
||||
|
||||
ev.Verbs.Add(removeTapeVerb);
|
||||
}
|
||||
|
||||
private void OnTapeStateChanged(EntityUid uid, TapeComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new TapeComponentState()
|
||||
{
|
||||
Songs = component.Songs
|
||||
};
|
||||
}
|
||||
|
||||
private void OnTapeCreatorStateChanged(EntityUid uid, TapeCreatorComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new TapeCreatorComponentState
|
||||
{
|
||||
Recording = component.Recording,
|
||||
CoinBalance = component.CoinBalance,
|
||||
InsertedTape = component.InsertedTape
|
||||
};
|
||||
}
|
||||
|
||||
private void OnComponentInit(EntityUid uid, TapeCreatorComponent component, ComponentInit args)
|
||||
{
|
||||
component.TapeContainer = _containerSystem.EnsureContainer<Container>(uid, TapeCreatorContainerName);
|
||||
}
|
||||
|
||||
private void OnInteract(EntityUid uid, TapeCreatorComponent component, InteractUsingEvent args)
|
||||
{
|
||||
if(component.Recording) return;
|
||||
|
||||
if (TryComp<TapeComponent>(args.Used, out var tape))
|
||||
{
|
||||
var containedEntities = component.TapeContainer.ContainedEntities;
|
||||
|
||||
if (containedEntities.Count > 1)
|
||||
{
|
||||
var removedTapes = _containerSystem.EmptyContainer(component.TapeContainer, true).ToList();
|
||||
component.TapeContainer.Insert(args.Used);
|
||||
|
||||
foreach (var tapes in removedTapes)
|
||||
{
|
||||
_handsSystem.PickupOrDrop(args.User, tapes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
component.TapeContainer.Insert(args.Used);
|
||||
}
|
||||
|
||||
component.InsertedTape = tape.Owner;
|
||||
Dirty(component);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_tagSystem.HasTag(args.Used, "TapeRecorderCoin"))
|
||||
{
|
||||
Del(args.Used);
|
||||
component.CoinBalance += 1;
|
||||
Dirty(component);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSongUploaded(JukeboxSongUploadRequest ev)
|
||||
{
|
||||
if(!TryComp<TapeCreatorComponent>(ev.TapeCreatorUid, out var tapeCreatorComponent)) return;
|
||||
|
||||
if (!tapeCreatorComponent.InsertedTape.HasValue || tapeCreatorComponent.CoinBalance <= 0)
|
||||
{
|
||||
_popupSystem.PopupEntity("Т# %ак@ э*^о сdf{ал б2я~b? Запись была прервана.", tapeCreatorComponent.Owner);
|
||||
return;
|
||||
}
|
||||
|
||||
tapeCreatorComponent.CoinBalance -= 1;
|
||||
tapeCreatorComponent.Recording = true;
|
||||
|
||||
var tapeComponent = Comp<TapeComponent>(tapeCreatorComponent.InsertedTape.Value);
|
||||
var songData = _songsSyncManager.SyncSongData(ev.SongName, ev.SongBytes);
|
||||
|
||||
var song = new JukeboxSong()
|
||||
{
|
||||
SongName = songData.songName,
|
||||
SongPath = songData.path
|
||||
};
|
||||
|
||||
tapeComponent.Songs.Add(song);
|
||||
_popupSystem.PopupEntity($"Запись началась, примерное время ожидания: {_recordTime} секунд", tapeCreatorComponent.Owner);
|
||||
Dirty(ev.TapeCreatorUid);
|
||||
Dirty(tapeComponent);
|
||||
StartRecordDelayAsync(tapeCreatorComponent, _popupSystem, _containerSystem);
|
||||
}
|
||||
|
||||
private async void StartRecordDelayAsync(TapeCreatorComponent component, SharedPopupSystem popupSystem, SharedContainerSystem containerSystem)
|
||||
{
|
||||
var recordTimeDelay = _recordTime * 1000 / 10;
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
popupSystem.PopupEntity($"Запись мозговой активности выполнена на {i * 10}%", component.Owner);
|
||||
await Task.Delay(recordTimeDelay);
|
||||
}
|
||||
|
||||
|
||||
containerSystem.EmptyContainer(component.TapeContainer, force: true).ToList();
|
||||
|
||||
component.Recording = false;
|
||||
component.InsertedTape = null;
|
||||
|
||||
popupSystem.PopupEntity($"Запись мозговой активности завершена", component.Owner);
|
||||
Dirty(component);
|
||||
}
|
||||
}
|
||||
20
Content.Shared/White/Jukebox/JukeboxBUIMessagess.cs
Normal file
20
Content.Shared/White/Jukebox/JukeboxBUIMessagess.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.White.Jukebox;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class JukeboxStopRequest : BoundUserInterfaceMessage { }
|
||||
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class JukeboxRepeatToggled : BoundUserInterfaceMessage
|
||||
{
|
||||
public bool NewState { get; }
|
||||
public JukeboxRepeatToggled(bool newState)
|
||||
{
|
||||
NewState = newState;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class JukeboxEjectRequest : BoundUserInterfaceMessage { }
|
||||
133
Content.Shared/White/Jukebox/JukeboxComponentsAndStuff.cs
Normal file
133
Content.Shared/White/Jukebox/JukeboxComponentsAndStuff.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using System.Linq;
|
||||
using Lidgren.Network;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.White.Jukebox;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum JukeboxUIKey : byte
|
||||
{
|
||||
Key
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum TapeCreatorUIKey : byte
|
||||
{
|
||||
Key
|
||||
}
|
||||
|
||||
[NetworkedComponent, RegisterComponent]
|
||||
public class JukeboxComponent : Component
|
||||
{
|
||||
|
||||
public static string JukeboxContainerName = "jukebox_tapes";
|
||||
public static string JukeboxDefaultSongsName = "jukebox_default_tapes";
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public Container TapeContainer = default!;
|
||||
|
||||
[DataField("defaultTapes")]
|
||||
public List<string> DefaultTapes = new();
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public Container DefaultSongsContainer = default!;
|
||||
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public bool Repeating { get; set; } = true;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float Volume { get; set; }
|
||||
|
||||
public PlayingSongData? PlayingSongData { get; set; }
|
||||
}
|
||||
|
||||
public class TapeContainerComponent : Component
|
||||
{
|
||||
public int MaxTapeCount = 1;
|
||||
public Container TapeContainer { get; set; } = new();
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class PlayingSongData
|
||||
{
|
||||
public ResPath? SongPath;
|
||||
public string? SongName;
|
||||
public float PlaybackPosition;
|
||||
public float ActualSongLengthSeconds;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class JukeboxComponentState : ComponentState
|
||||
{
|
||||
public bool Playing { get; set; }
|
||||
|
||||
public PlayingSongData? SongData { get; set; }
|
||||
public float Volume { get; set; }
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable, DataDefinition]
|
||||
public class JukeboxSong
|
||||
{
|
||||
[DataField("songName")]
|
||||
public string? SongName;
|
||||
[DataField("path")]
|
||||
public ResPath? SongPath;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class JukeboxRequestSongPlay : EntityEventArgs
|
||||
{
|
||||
public string? SongName { get; set; }
|
||||
public ResPath? SongPath { get; set; }
|
||||
public EntityUid? Jukebox { get; set; }
|
||||
public float SongDuration { get; set; }
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class JukeboxRequestStop : EntityEventArgs
|
||||
{
|
||||
public EntityUid? JukeboxUid { get; set; }
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class JukeboxStopPlaying : EntityEventArgs
|
||||
{
|
||||
public EntityUid? JukeboxUid { get; set; }
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class JukeboxSongUploadRequest : EntityEventArgs
|
||||
{
|
||||
public string SongName = string.Empty;
|
||||
public List<byte> SongBytes = new();
|
||||
public EntityUid TapeCreatorUid = default!;
|
||||
}
|
||||
|
||||
public class JukeboxSongUploadNetMessage : NetMessage
|
||||
{
|
||||
public override NetDeliveryMethod DeliveryMethod => NetDeliveryMethod.ReliableUnordered;
|
||||
public override MsgGroups MsgGroup => MsgGroups.Command;
|
||||
|
||||
public ResPath RelativePath { get; set; } = ResPath.Self;
|
||||
public byte[] Data { get; set; } = Array.Empty<byte>();
|
||||
|
||||
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
var dataLength = buffer.ReadVariableInt32();
|
||||
Data = buffer.ReadBytes(dataLength);
|
||||
RelativePath = new ResPath(buffer.ReadString());
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
buffer.WriteVariableInt32(Data.Length);
|
||||
buffer.Write(Data);
|
||||
buffer.Write(RelativePath.ToString());
|
||||
buffer.Write(ResPath.Separator);
|
||||
}
|
||||
}
|
||||
37
Content.Shared/White/Jukebox/JukeboxSharedSystem.cs
Normal file
37
Content.Shared/White/Jukebox/JukeboxSharedSystem.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Content.Shared.White.Jukebox;
|
||||
|
||||
public class JukeboxSharedSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
[Dependency] private readonly INetManager _netManager = default!;
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<JukeboxComponent, ComponentStartup>(OnJukeboxInit);
|
||||
}
|
||||
|
||||
public void OnJukeboxInit(EntityUid uid, JukeboxComponent component, ComponentStartup args)
|
||||
{
|
||||
component.TapeContainer = _containerSystem.EnsureContainer<Container>(uid, JukeboxComponent.JukeboxContainerName);
|
||||
component.DefaultSongsContainer = _containerSystem.EnsureContainer<Container>(uid, JukeboxComponent.JukeboxDefaultSongsName);
|
||||
|
||||
if (_netManager.IsServer)
|
||||
{
|
||||
var transform = Transform(component.Owner);
|
||||
|
||||
foreach (var tapePrototype in component.DefaultTapes)
|
||||
{
|
||||
var tapeUid = EntityManager.SpawnEntity(tapePrototype, transform.MapPosition);
|
||||
|
||||
if(!TryComp<TapeComponent>(tapeUid, out _)) continue;
|
||||
|
||||
component.DefaultSongsContainer.Insert(tapeUid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Content.Shared/White/Jukebox/JukeboxSongsSyncManager.cs
Normal file
29
Content.Shared/White/Jukebox/JukeboxSongsSyncManager.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.White.Jukebox;
|
||||
|
||||
public abstract class JukeboxSongsSyncManager : IDisposable
|
||||
{
|
||||
[Dependency] private readonly INetManager _netManager = default!;
|
||||
[Dependency] protected readonly IResourceManager ResourceManager = default!;
|
||||
|
||||
public static readonly ResPath Prefix = ResPath.Root / "Jukebox";
|
||||
|
||||
protected readonly MemoryContentRoot ContentRoot = new();
|
||||
|
||||
public virtual void Initialize()
|
||||
{
|
||||
ResourceManager.AddRoot(Prefix, ContentRoot);
|
||||
|
||||
_netManager.RegisterNetMessage<JukeboxSongUploadNetMessage>(OnSongUploaded);
|
||||
}
|
||||
|
||||
public abstract void OnSongUploaded(JukeboxSongUploadNetMessage message);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ContentRoot.Dispose();
|
||||
}
|
||||
}
|
||||
17
Content.Shared/White/Jukebox/TapeComponent.cs
Normal file
17
Content.Shared/White/Jukebox/TapeComponent.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.White.Jukebox;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class TapeComponent : Component
|
||||
{
|
||||
[DataField("songs")]
|
||||
public List<JukeboxSong> Songs { get; set; } = new();
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class TapeComponentState : ComponentState
|
||||
{
|
||||
public List<JukeboxSong> Songs { get; set; } = new();
|
||||
}
|
||||
29
Content.Shared/White/Jukebox/TapeCreatorComponent.cs
Normal file
29
Content.Shared/White/Jukebox/TapeCreatorComponent.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.White.Jukebox;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class TapeCreatorComponent : Component
|
||||
{
|
||||
[DataField("coins")]
|
||||
public int CoinBalance { get; set; }
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public bool Recording { get; set; }
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public EntityUid? InsertedTape { get; set; }
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public Container TapeContainer { get; set; } = default!;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class TapeCreatorComponentState : ComponentState
|
||||
{
|
||||
public int CoinBalance { get; set; }
|
||||
public bool Recording { get; set; }
|
||||
public EntityUid? InsertedTape { get; set; }
|
||||
}
|
||||
@@ -158,6 +158,19 @@ public sealed class WhiteCVars
|
||||
public static readonly CVarDef<float> BwoinkVolume =
|
||||
CVarDef.Create("white.admin.bwoinkVolume", 0f, CVar.CLIENTONLY | CVar.ARCHIVE);
|
||||
|
||||
/*
|
||||
* Jukebox
|
||||
*/
|
||||
|
||||
public static readonly CVarDef<float> MaxJukeboxSongSizeInMB = CVarDef.Create("white.max_jukebox_song_size",
|
||||
3.5f, CVar.SERVER | CVar.REPLICATED | CVar.ARCHIVE);
|
||||
|
||||
public static readonly CVarDef<float> MaxJukeboxSoundRange = CVarDef.Create("white.max_jukebox_sound_range", 20f,
|
||||
CVar.SERVER | CVar.REPLICATED | CVar.ARCHIVE);
|
||||
|
||||
public static readonly CVarDef<float> JukeboxVolume =
|
||||
CVarDef.Create("white.jukebox_volume", 0f, CVar.CLIENTONLY | CVar.ARCHIVE);
|
||||
|
||||
|
||||
/*
|
||||
* Chat
|
||||
|
||||
BIN
Resources/Audio/White/Jukebox/Tapes/tape_fall.ogg
Normal file
BIN
Resources/Audio/White/Jukebox/Tapes/tape_fall.ogg
Normal file
Binary file not shown.
52
Resources/Prototypes/White/JukeboxAndStuff/jukebox_stuff.yml
Normal file
52
Resources/Prototypes/White/JukeboxAndStuff/jukebox_stuff.yml
Normal file
@@ -0,0 +1,52 @@
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: Jukebox
|
||||
name: jukebox
|
||||
description: Альфа-Шкварки
|
||||
suffix: Empty
|
||||
components:
|
||||
- type: Jukebox
|
||||
- type: Sprite
|
||||
sprite: White/Objects/Devices/jukebox.rsi
|
||||
layers:
|
||||
- state: boombox
|
||||
- state: boombox_working_overlay
|
||||
map: ["bars"]
|
||||
netsync: false
|
||||
- type: Item
|
||||
sprite: White/Objects/Devices/jukebox.rsi
|
||||
heldPrefix: boombox
|
||||
size: 500
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
- key: enum.JukeboxUIKey.Key
|
||||
type: JukeboxBUI
|
||||
- type: ActivatableUI
|
||||
key: enum.JukeboxUIKey.Key
|
||||
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: TapeRecorder
|
||||
name: tape recorder
|
||||
suffix: Empty
|
||||
components:
|
||||
- type: TapeCreator
|
||||
coins: 3
|
||||
- type: Sprite
|
||||
scale: 0.7, 0.7
|
||||
sprite: White/Objects/Devices/tapeRecorder.rsi
|
||||
layers:
|
||||
- state: base
|
||||
- state: tape
|
||||
map: ["tape"]
|
||||
visible: false
|
||||
netsync: false
|
||||
- type: Item
|
||||
sprite: White/Objects/Devices/tapeRecorder.rsi
|
||||
heldPrefix: tapeRecorder
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
- key: enum.TapeCreatorUIKey.Key
|
||||
type: TapeCreatorBUI
|
||||
- type: ActivatableUI
|
||||
key: enum.TapeCreatorUIKey.Key
|
||||
27
Resources/Prototypes/White/JukeboxAndStuff/tapes.yml
Normal file
27
Resources/Prototypes/White/JukeboxAndStuff/tapes.yml
Normal file
@@ -0,0 +1,27 @@
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: BaseTape
|
||||
name: baseTape
|
||||
abstract: true
|
||||
noSpawn: true
|
||||
description: это база
|
||||
suffix: Empty
|
||||
components:
|
||||
- type: Tape
|
||||
- type: Sprite
|
||||
sprite: Objects/Devices/jukeboxStuff/tape.rsi
|
||||
layers:
|
||||
- state: tape
|
||||
netsync: false
|
||||
- type: Item
|
||||
sprite: Objects/Devices/jukeboxStuff/tape.rsi
|
||||
heldPrefix: tape
|
||||
- type: EmitSoundOnLand
|
||||
sound:
|
||||
path: /Audio/White/Jukebox/Tapes/tape_fall.ogg
|
||||
|
||||
- type: entity
|
||||
parent: BaseTape
|
||||
id: TapeEmpty
|
||||
name: Old tape
|
||||
description: Ligma balls
|
||||
@@ -1197,3 +1197,6 @@
|
||||
id: Crystal
|
||||
|
||||
# WHITE END
|
||||
|
||||
- type: Tag
|
||||
id: TapeRecorderCoin
|
||||
|
||||
BIN
Resources/Textures/Interface/VerbIcons/remove_tape.png
Normal file
BIN
Resources/Textures/Interface/VerbIcons/remove_tape.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 973 B |
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from infinity baystation 12, https://github.com/infinitystation/Baystation12/blob/073f678cdce92edb8fcd55f9ffc9f0523bf31506/icons/obj/radio.dmi",
|
||||
"size": {
|
||||
"x": 14,
|
||||
"y": 8
|
||||
},
|
||||
"states" : [
|
||||
{"name": "tape"}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 656 B |
Reference in New Issue
Block a user