diff --git a/Content.Client/White/Jukebox/JukeboxSystem.cs b/Content.Client/White/Jukebox/JukeboxSystem.cs index b62a733125..8095e8fcfb 100644 --- a/Content.Client/White/Jukebox/JukeboxSystem.cs +++ b/Content.Client/White/Jukebox/JukeboxSystem.cs @@ -1,20 +1,16 @@ -using System.Resources; -using Content.Shared.GameTicking; -using Content.Shared.Interaction.Events; +using Content.Shared.GameTicking; +using Content.Shared.Physics; 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.Audio.Components; -using Robust.Shared.Audio.Systems; +using Robust.Shared.Audio.Sources; using Robust.Shared.Configuration; -using Robust.Shared.ContentPack; using Robust.Shared.GameStates; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Systems; using Robust.Shared.Utility; namespace Content.Client.White.Jukebox; @@ -22,13 +18,11 @@ 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!; - - - + [Dependency] private readonly IAudioManager _clydeAudio = default!; + [Dependency] private readonly SharedPhysicsSystem _physicsSystem = default!; private readonly Dictionary _playingJukeboxes = new(); @@ -40,7 +34,7 @@ public sealed class JukeboxSystem : EntitySystem base.Initialize(); _cfg.OnValueChanged(WhiteCVars.MaxJukeboxSoundRange, range => _maxAudioRange = range, true); - _cfg.OnValueChanged(WhiteCVars.JukeboxVolume, volume => JukeboxVolumeChanged(volume), true); + _cfg.OnValueChanged(WhiteCVars.JukeboxVolume, JukeboxVolumeChanged, true); SubscribeLocalEvent(OnStateChanged); SubscribeLocalEvent(OnComponentRemoved); @@ -52,7 +46,6 @@ public sealed class JukeboxSystem : EntitySystem private void JukeboxVolumeChanged(float volume) { _jukeboxVolume = volume; - CleanUp(); } @@ -69,7 +62,7 @@ public sealed class JukeboxSystem : EntitySystem private void OnComponentRemoved(EntityUid uid, JukeboxComponent component, ComponentRemove args) { if (!_playingJukeboxes.TryGetValue(component, out var playingData)) return; - _audioSystem.Stop(playingData.PlayingStream, playingData.Component); + playingData.PlayingStream.StopPlaying(); _playingJukeboxes.Remove(component); } @@ -80,7 +73,7 @@ public sealed class JukeboxSystem : EntitySystem if(!_playingJukeboxes.TryGetValue(jukeboxComponent, out var jukeboxAudio)) return; - _audioSystem.Stop(jukeboxAudio.PlayingStream, jukeboxAudio.Component); + jukeboxAudio.PlayingStream.StopPlaying(); _playingJukeboxes.Remove(jukeboxComponent); } @@ -101,26 +94,20 @@ public sealed class JukeboxSystem : EntitySystem } - public override void Update(float frameTime) + public override void FrameUpdate(float frameTime) { - base.Update(frameTime); + base.FrameUpdate(frameTime); var localPlayerEntity = _playerManager.LocalPlayer!.ControlledEntity; - if(!localPlayerEntity.HasValue) return; + if (!localPlayerEntity.HasValue) + { + CleanUp(); + 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(); @@ -129,22 +116,35 @@ public sealed class JukeboxSystem : EntitySystem foreach (var (jukeboxComponent, jukeboxXform) in jukeboxes) { - if(jukeboxXform.MapID != playerXform.MapID) continue; - if ((jukeboxXform.MapPosition.Position - playerXform.MapPosition.Position).Length() > _maxAudioRange) continue; + if (jukeboxXform.MapID != playerXform.MapID || (jukeboxXform.MapPosition.Position - playerXform.MapPosition.Position).Length() > _maxAudioRange) + { + if (_playingJukeboxes.TryGetValue(jukeboxComponent, out var stream)) + { + _playingJukeboxes.Remove(jukeboxComponent); + + stream.PlayingStream.StopPlaying(); + stream.PlayingStream.Dispose(); + } + + continue; + } if (_playingJukeboxes.TryGetValue(jukeboxComponent, out var jukeboxAudio)) { - if (!jukeboxAudio.Component.Playing) + if (!jukeboxAudio.PlayingStream.Playing) { - HandleDoneStream(jukeboxAudio, jukeboxComponent); - return; + HandleDoneStream(jukeboxAudio, jukeboxComponent, jukeboxXform, playerXform); + continue; } if (jukeboxAudio.SongData.SongPath != jukeboxComponent.PlayingSongData?.SongPath) { - HandleSongChanged(jukeboxAudio, jukeboxComponent); - return; + HandleSongChanged(jukeboxAudio, jukeboxComponent, jukeboxXform, playerXform); + continue; } + + SetOcclusion(playerXform, jukeboxXform, jukeboxAudio); + SetPosition(jukeboxXform, jukeboxAudio); } else { @@ -154,11 +154,11 @@ public sealed class JukeboxSystem : EntitySystem continue; } - var stream = TryCreateStream(jukeboxComponent); + var stream = TryCreateStream(jukeboxComponent, jukeboxXform, playerXform); if (stream == null) { - return; + continue; } _playingJukeboxes.Add(jukeboxComponent, stream); @@ -167,13 +167,34 @@ public sealed class JukeboxSystem : EntitySystem } } - private void HandleSongChanged(JukeboxAudio jukeboxAudio, JukeboxComponent jukeboxComponent) + private void SetPosition(TransformComponent jukeboxXform, JukeboxAudio jukeboxAudio) { - _audioSystem.Stop(jukeboxAudio.PlayingStream, jukeboxAudio.Component); + jukeboxAudio.PlayingStream.Position = jukeboxXform.MapPosition.Position; + } + + private void SetOcclusion(TransformComponent playerXform, TransformComponent jukeboxXform, JukeboxAudio jukeboxAudio) + { + var collisionMask = CollisionGroup.Impassable; + var sourceRelative = playerXform.MapPosition.Position - jukeboxXform.MapPosition.Position; + var occlusion = 0f; + + if (sourceRelative.Length() > 0) + { + occlusion = _physicsSystem.IntersectRayPenetration(jukeboxXform.MapID, + new CollisionRay(jukeboxXform.MapPosition.Position, sourceRelative.Normalized(), (int)collisionMask), + sourceRelative.Length(), jukeboxXform.Owner) * 3f; + } + + jukeboxAudio.PlayingStream.Occlusion = occlusion; + } + + private void HandleSongChanged(JukeboxAudio jukeboxAudio, JukeboxComponent jukeboxComponent, TransformComponent jukeboxXform, TransformComponent playerXform) + { + jukeboxAudio.PlayingStream.StopPlaying(); if (jukeboxComponent.PlayingSongData != null && jukeboxComponent.PlayingSongData.SongPath == jukeboxAudio.SongData.SongPath) { - var newStream = TryCreateStream(jukeboxComponent); + var newStream = TryCreateStream(jukeboxComponent, jukeboxXform, playerXform); if(newStream == null) return; _playingJukeboxes[jukeboxComponent] = newStream; @@ -186,11 +207,11 @@ public sealed class JukeboxSystem : EntitySystem } } - private void HandleDoneStream(JukeboxAudio jukeboxAudio, JukeboxComponent jukeboxComponent) + private void HandleDoneStream(JukeboxAudio jukeboxAudio, JukeboxComponent jukeboxComponent, TransformComponent jukeboxXform, TransformComponent playerXform) { if (!jukeboxComponent.Repeating) { - _audioSystem.Stop(jukeboxAudio.PlayingStream, jukeboxAudio.Component); + jukeboxAudio.PlayingStream.StopPlaying(); _playingJukeboxes.Remove(jukeboxComponent); SetBarsLayerVisible(jukeboxComponent, false); return; @@ -199,7 +220,7 @@ public sealed class JukeboxSystem : EntitySystem if(jukeboxComponent.PlayingSongData == null) return; - var newStream = TryCreateStream(jukeboxComponent); + var newStream = TryCreateStream(jukeboxComponent, jukeboxXform, playerXform); if (newStream == null) { @@ -214,47 +235,35 @@ public sealed class JukeboxSystem : EntitySystem } } - private JukeboxAudio? TryCreateStream(JukeboxComponent jukeboxComponent) + private JukeboxAudio? TryCreateStream(JukeboxComponent jukeboxComponent, TransformComponent jukeboxXform, TransformComponent playerXform) { if (jukeboxComponent.PlayingSongData == null) return null; var resourcePath = jukeboxComponent.PlayingSongData.SongPath!; - var localSession = _playerManager.LocalPlayer!.Session; if(!_resource.TryGetResource((ResPath) resourcePath, out var audio)) return null!; - if (audio!.AudioStream.Length.TotalSeconds < jukeboxComponent.PlayingSongData!.PlaybackPosition) + if (audio.AudioStream.Length.TotalSeconds < jukeboxComponent.PlayingSongData!.PlaybackPosition) { return null!; } - var audioParams = new AudioParams - { - PlayOffsetSeconds = jukeboxComponent.PlayingSongData.PlaybackPosition, - Volume = _jukeboxVolume, - MaxDistance = _maxAudioRange - }; + var playingStream = _clydeAudio.CreateAudioSource(audio.AudioStream); + if (playingStream == null) + return null!; - var playingStream = _audioSystem.PlayEntity(resourcePath.ToString()!, localSession, jukeboxComponent.Owner, audioParams); + playingStream.Volume = _jukeboxVolume; + playingStream.RolloffFactor = 3.5f; - return new JukeboxAudio(playingStream.Value.Entity, playingStream.Value.Component, audio!, jukeboxComponent.PlayingSongData); - } + playingStream.Position = jukeboxXform.MapPosition.Position; - private class JukeboxAudio - { - public PlayingSongData SongData { get; } - public EntityUid PlayingStream { get; } - public AudioComponent Component { get; } - public AudioResource AudioStream { get; } + var jukeboxAudio = new JukeboxAudio(playingStream!, audio, jukeboxComponent.PlayingSongData); - public JukeboxAudio(EntityUid playingStream, AudioComponent component, AudioResource audioStream, PlayingSongData songData) - { - PlayingStream = playingStream; - Component = component; - AudioStream = audioStream; - SongData = songData; - } + SetOcclusion(playerXform, jukeboxXform, jukeboxAudio); + playingStream.StartPlaying(); + + return jukeboxAudio; } private void SetBarsLayerVisible(JukeboxComponent jukeboxComponent, bool visible) @@ -264,11 +273,36 @@ public sealed class JukeboxSystem : EntitySystem spriteComponent.LayerSetVisible(layer, visible); } + 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 class JukeboxAudio + { + public PlayingSongData SongData { get; } + public IAudioSource PlayingStream { get; } + public AudioResource AudioStream { get; } + + public JukeboxAudio(IAudioSource playingStream, AudioResource audioStream, PlayingSongData songData) + { + PlayingStream = playingStream; + AudioStream = audioStream; + SongData = songData; + } + } + private void CleanUp() { foreach (var playingJukebox in _playingJukeboxes.Values) { - _audioSystem.Stop(playingJukebox.PlayingStream, playingJukebox.Component); + playingJukebox.PlayingStream.StopPlaying(); + playingJukebox.PlayingStream.Dispose(); } _playingJukeboxes.Clear(); diff --git a/Resources/Prototypes/White/JukeboxAndStuff/jukebox_stuff.yml b/Resources/Prototypes/White/JukeboxAndStuff/jukebox_stuff.yml index 188c4d5bef..4b174034f6 100644 --- a/Resources/Prototypes/White/JukeboxAndStuff/jukebox_stuff.yml +++ b/Resources/Prototypes/White/JukeboxAndStuff/jukebox_stuff.yml @@ -16,13 +16,17 @@ - type: Item sprite: White/Objects/Devices/jukebox.rsi heldPrefix: boombox - size: 500 + size: Ginormous - type: UserInterface interfaces: - key: enum.JukeboxUIKey.Key type: JukeboxBUI - type: ActivatableUI key: enum.JukeboxUIKey.Key + - type: ContainerContainer + containers: + jukebox_tapes: !type:Container + jukebox_default_tapes: !type:Container - type: entity parent: BaseItem @@ -50,3 +54,6 @@ type: TapeCreatorBUI - type: ActivatableUI key: enum.TapeCreatorUIKey.Key + - type: ContainerContainer + containers: + tape_creator_container: !type:Container