From 06e62b031a036749ed1292a722169e94ab2f2bdf Mon Sep 17 00:00:00 2001 From: Acruid Date: Mon, 1 Mar 2021 20:22:28 -0800 Subject: [PATCH] SoundSystem (#1604) * Adds the SoundSystem static proxy class for the AudioSystem. Added a shared IAudioSystem interface for the future. * Moved ConnectedClient property from IPlayerSession down to ICommonSession. * Connected up the SoundSystem to the client/server AudioSystems. * Converted client calls over to the new system. * Marked the old serverside functions to play sound obsolete, use the new ones from the IAudioSystem. * Added ISharedPlayerManager to the IoC registration. --- .../Animations/AnimationTrackPlaySound.cs | 4 +- Robust.Client/ClientIoC.cs | 2 + .../GameObjects/EntitySystems/AudioSystem.cs | 103 ++------- Robust.Client/Player/PlayerManager.cs | 2 +- Robust.Client/Player/PlayerSession.cs | 3 + .../GameObjects/EntitySystems/AudioSystem.cs | 210 ++++++++++-------- Robust.Server/Player/IPlayerSession.cs | 1 - Robust.Server/ServerIoC.cs | 2 + Robust.Shared/Audio/IAudioSystem.cs | 48 ++++ Robust.Shared/Audio/IPlayingAudioStream.cs | 7 + Robust.Shared/Audio/SoundSystem.cs | 82 +++++++ Robust.Shared/Players/ICommonSession.cs | 9 + 12 files changed, 299 insertions(+), 174 deletions(-) create mode 100644 Robust.Shared/Audio/IAudioSystem.cs create mode 100644 Robust.Shared/Audio/IPlayingAudioStream.cs create mode 100644 Robust.Shared/Audio/SoundSystem.cs diff --git a/Robust.Client/Animations/AnimationTrackPlaySound.cs b/Robust.Client/Animations/AnimationTrackPlaySound.cs index 7fd23a612..b4cffde4e 100644 --- a/Robust.Client/Animations/AnimationTrackPlaySound.cs +++ b/Robust.Client/Animations/AnimationTrackPlaySound.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Robust.Client.GameObjects; using Robust.Shared.Audio; using Robust.Shared.GameObjects; +using Robust.Shared.Player; namespace Robust.Client.Animations { @@ -36,8 +37,7 @@ namespace Robust.Client.Animations var keyFrame = KeyFrames[keyFrameIndex]; - EntitySystem.Get() - .Play(keyFrame.Resource, entity, keyFrame.AudioParamsFunc.Invoke()); + SoundSystem.Play(Filter.Local(), keyFrame.Resource, entity, keyFrame.AudioParamsFunc.Invoke()); } return (keyFrameIndex, playingTime); diff --git a/Robust.Client/ClientIoC.cs b/Robust.Client/ClientIoC.cs index fe48d18d5..23654c4ad 100644 --- a/Robust.Client/ClientIoC.cs +++ b/Robust.Client/ClientIoC.cs @@ -24,6 +24,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Network; +using Robust.Shared.Players; using Robust.Shared.Prototypes; using Robust.Shared.Reflection; @@ -53,6 +54,7 @@ namespace Robust.Client IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); + IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); diff --git a/Robust.Client/GameObjects/EntitySystems/AudioSystem.cs b/Robust.Client/GameObjects/EntitySystems/AudioSystem.cs index 1ffdd21e2..1f6fe3be1 100644 --- a/Robust.Client/GameObjects/EntitySystems/AudioSystem.cs +++ b/Robust.Client/GameObjects/EntitySystems/AudioSystem.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using JetBrains.Annotations; using Robust.Client.Audio; @@ -11,12 +10,13 @@ using Robust.Shared.Log; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Physics; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Robust.Client.GameObjects { [UsedImplicitly] - public class AudioSystem : EntitySystem + public class AudioSystem : EntitySystem, IAudioSystem { [Dependency] private readonly IResourceCache _resourceCache = default!; [Dependency] private readonly IMapManager _mapManager = default!; @@ -25,9 +25,7 @@ namespace Robust.Client.GameObjects [Dependency] private readonly IEntityManager _entityManager = default!; private readonly List _playingClydeStreams = new(); - - public int OcclusionCollisionMask; - + /// public override void Initialize() { @@ -35,6 +33,8 @@ namespace Robust.Client.GameObjects SubscribeNetworkEvent(PlayAudioGlobalHandler); SubscribeNetworkEvent(PlayAudioPositionalHandler); SubscribeNetworkEvent(StopAudioMessageHandler); + + SubscribeLocalEvent((ev => ev.Audio = this)); } private void StopAudioMessageHandler(StopAudioMessageClient ev) @@ -176,7 +176,6 @@ namespace Robust.Client.GameObjects { stream.Source.Dispose(); stream.Done = true; - stream.DoPlaybackDone(); } /// @@ -335,92 +334,30 @@ namespace Robust.Client.GameObjects { Source.StopPlaying(); } - - public event Action? PlaybackDone; - - public void DoPlaybackDone() - { - PlaybackDone?.Invoke(); - } - } - } - - public interface IPlayingAudioStream - { - void Stop(); - - event Action PlaybackDone; - } - - public static class AudioSystemExtensions - { - - /// - /// Play an audio file following an entity. - /// - /// The resource path to the OGG Vorbis file to play. - /// The entity "emitting" the audio. - /// - /// A pre-fetched instance of to use, can be null. - public static IPlayingAudioStream? Play( - this IEntity entity, - string filename, - AudioParams? audioParams, - AudioSystem? audioSystem = null) - { - audioSystem ??= EntitySystem.Get(); - return audioSystem.Play(filename, entity, audioParams); } - /// - /// Play an audio stream following an entity. - /// - /// The audio stream to play. - /// The entity "emitting" the audio. - /// - /// A pre-fetched instance of to use, can be null. - public static IPlayingAudioStream? Play( - this IEntity entity, - AudioStream stream, - AudioParams? audioParams = null, - AudioSystem? audioSystem = null) + /// + public int DefaultSoundRange => 25; + + /// + public int OcclusionCollisionMask { get; set; } + + /// + public IPlayingAudioStream? Play(Filter playerFilter, string filename, AudioParams? audioParams = null) { - audioSystem ??= EntitySystem.Get(); - return audioSystem.Play(stream, entity, audioParams); + return Play(filename, audioParams); } - /// - /// Play an audio file at a static position. - /// - /// The resource path to the OGG Vorbis file to play. - /// The coordinates at which to play the audio. - /// - /// A pre-fetched instance of to use, can be null. - public static IPlayingAudioStream? Play( - this EntityCoordinates coordinates, - string filename, - AudioParams? audioParams = null, - AudioSystem? audioSystem = null) + /// + public IPlayingAudioStream? Play(Filter playerFilter, string filename, IEntity entity, AudioParams? audioParams = null) { - audioSystem ??= EntitySystem.Get(); - return audioSystem.Play(filename, coordinates, audioParams); + return Play(filename, entity, audioParams); } - /// - /// Play an audio stream at a static position. - /// - /// The audio stream to play. - /// The coordinates at which to play the audio. - /// - /// A pre-fetched instance of to use, can be null. - public static IPlayingAudioStream? Play( - this EntityCoordinates coordinates, - AudioStream stream, - AudioParams? audioParams = null, - AudioSystem? audioSystem = null) + /// + public IPlayingAudioStream? Play(Filter playerFilter, string filename, EntityCoordinates coordinates, AudioParams? audioParams = null) { - audioSystem ??= EntitySystem.Get(); - return audioSystem.Play(stream, coordinates, audioParams); + return Play(filename, coordinates, audioParams); } } } diff --git a/Robust.Client/Player/PlayerManager.cs b/Robust.Client/Player/PlayerManager.cs index 5f6eec5cc..49cdd25b0 100644 --- a/Robust.Client/Player/PlayerManager.cs +++ b/Robust.Client/Player/PlayerManager.cs @@ -207,7 +207,7 @@ namespace Robust.Client.Player if (state.UserId == LocalPlayer!.UserId) { LocalPlayer.InternalSession = newSession; - + newSession.ConnectedClient = _network.ServerChannel!; // We just connected to the server, hurray! LocalPlayer.SwitchState(SessionStatus.Connecting, newSession.Status); } diff --git a/Robust.Client/Player/PlayerSession.cs b/Robust.Client/Player/PlayerSession.cs index a2b9c4c38..c3e278d0b 100644 --- a/Robust.Client/Player/PlayerSession.cs +++ b/Robust.Client/Player/PlayerSession.cs @@ -39,6 +39,9 @@ namespace Robust.Client.Player /// internal short Ping { get; set; } + /// + public INetChannel ConnectedClient { get; internal set; } = null!; + /// short ICommonSession.Ping { diff --git a/Robust.Server/GameObjects/EntitySystems/AudioSystem.cs b/Robust.Server/GameObjects/EntitySystems/AudioSystem.cs index 5838b66b3..622a828db 100644 --- a/Robust.Server/GameObjects/EntitySystems/AudioSystem.cs +++ b/Robust.Server/GameObjects/EntitySystems/AudioSystem.cs @@ -1,29 +1,31 @@ -using System; +using System; using System.Collections.Generic; +using System.Linq; using Robust.Server.Player; using Robust.Shared.Audio; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; -using static Robust.Server.GameObjects.AudioSystem; +using Robust.Shared.Player; +using Robust.Shared.Players; namespace Robust.Server.GameObjects { - public class AudioSystem : EntitySystem + public class AudioSystem : EntitySystem, IAudioSystem { [Dependency] private readonly IPlayerManager _playerManager = default!; - public const int AudioDistanceRange = 25; + private const int AudioDistanceRange = 25; private uint _streamIndex; - public class AudioSourceServer + private class AudioSourceServer : IPlayingAudioStream { private readonly uint _id; private readonly AudioSystem _audioSystem; - private readonly IEnumerable? _sessions; + private readonly IEnumerable? _sessions; - internal AudioSourceServer(AudioSystem parent, uint identifier, IEnumerable? sessions = null) + internal AudioSourceServer(AudioSystem parent, uint identifier, IEnumerable? sessions = null) { _audioSystem = parent; _id = identifier; @@ -35,7 +37,13 @@ namespace Robust.Server.GameObjects } } - private void InternalStop(uint id, IEnumerable? sessions = null) + /// + public override void Initialize() + { + SubscribeLocalEvent((ev => ev.Audio = this)); + } + + private void InternalStop(uint id, IEnumerable? sessions = null) { var msg = new StopAudioMessageClient { @@ -65,7 +73,9 @@ namespace Robust.Server.GameObjects /// /// The predicate that will be used to send the audio to players, or null to send to everyone. /// Session that won't receive the audio message. - public AudioSourceServer PlayGlobal(string filename, AudioParams? audioParams = null, Func? predicate = null, IPlayerSession? excludedSession = null) + /// + [Obsolete("Use the Play() overload.")] + public IPlayingAudioStream PlayGlobal(string filename, AudioParams? audioParams = null, Func? predicate = null, IPlayerSession? excludedSession = null) { var id = CacheIdentifier(); var msg = new PlayAudioGlobalMessage @@ -81,7 +91,7 @@ namespace Robust.Server.GameObjects return new AudioSourceServer(this, id); } - var players = predicate != null ? _playerManager.GetPlayersBy(predicate) : _playerManager.GetAllPlayers(); + IList players = predicate != null ? _playerManager.GetPlayersBy(predicate) : _playerManager.GetAllPlayers(); for (var i = players.Count - 1; i >= 0; i--) { @@ -96,7 +106,6 @@ namespace Robust.Server.GameObjects } return new AudioSourceServer(this, id, players); - } /// @@ -107,7 +116,8 @@ namespace Robust.Server.GameObjects /// /// The max range at which the audio will be heard. Less than or equal to 0 to send to every player. /// Sessions that won't receive the audio message. - public AudioSourceServer PlayFromEntity(string filename, IEntity entity, AudioParams? audioParams = null, int range = AudioDistanceRange, IPlayerSession? excludedSession = null) + [Obsolete("Use the Play() overload.")] + public IPlayingAudioStream PlayFromEntity(string filename, IEntity entity, AudioParams? audioParams = null, int range = AudioDistanceRange, IPlayerSession? excludedSession = null) { var id = CacheIdentifier(); @@ -120,13 +130,19 @@ namespace Robust.Server.GameObjects Identifier = id, }; + // send to every player if (range <= 0 && excludedSession == null) { RaiseNetworkEvent(msg); return new AudioSourceServer(this, id); } - var players = range > 0.0f ? _playerManager.GetPlayersInRange(entity.Transform.Coordinates, range) : _playerManager.GetAllPlayers(); + List players; + + if (range > 0.0f) + players = _playerManager.GetPlayersInRange(entity.Transform.Coordinates, range); + else + players = _playerManager.GetAllPlayers(); for (var i = players.Count - 1; i >= 0; i--) { @@ -151,7 +167,8 @@ namespace Robust.Server.GameObjects /// /// The max range at which the audio will be heard. Less than or equal to 0 to send to every player. /// Session that won't receive the audio message. - public AudioSourceServer PlayAtCoords(string filename, EntityCoordinates coordinates, AudioParams? audioParams = null, int range = AudioDistanceRange, IPlayerSession? excludedSession = null) + [Obsolete("Use the Play() overload.")] + public IPlayingAudioStream PlayAtCoords(string filename, EntityCoordinates coordinates, AudioParams? audioParams = null, int range = AudioDistanceRange, IPlayerSession? excludedSession = null) { var id = CacheIdentifier(); var msg = new PlayAudioPositionalMessage @@ -168,7 +185,12 @@ namespace Robust.Server.GameObjects return new AudioSourceServer(this, id); } - var players = range > 0.0f ? _playerManager.GetPlayersInRange(coordinates, range) : _playerManager.GetAllPlayers(); + List players; + + if (range > 0.0f) + players = _playerManager.GetPlayersInRange(coordinates, range); + else + players = _playerManager.GetAllPlayers(); for (var i = players.Count - 1; i >= 0; i--) { @@ -185,88 +207,102 @@ namespace Robust.Server.GameObjects return new AudioSourceServer(this, id, players); } - #region DEPRECATED - /// - /// Play an audio file globally, without position. - /// - /// The resource path to the OGG Vorbis file to play. - /// - [Obsolete("Deprecated. Use PlayGlobal instead.")] - public void Play(string filename, AudioParams? audioParams = null) + /// + public int DefaultSoundRange => AudioDistanceRange; + + /// + public int OcclusionCollisionMask { get; set; } + + /// + public IPlayingAudioStream? Play(Filter playerFilter, string filename, AudioParams? audioParams = null) { - PlayGlobal(filename, audioParams); + var id = CacheIdentifier(); + var msg = new PlayAudioGlobalMessage + { + FileName = filename, + AudioParams = audioParams ?? AudioParams.Default, + Identifier = id + }; + + var players = (playerFilter as IFilter).Recipients; + foreach (var player in players) + { + RaiseNetworkEvent(msg, player.ConnectedClient); + } + + return new AudioSourceServer(this, id, players); } - - /// - /// Play an audio file following an entity. - /// - /// The resource path to the OGG Vorbis file to play. - /// The entity "emitting" the audio. - /// - [Obsolete("Deprecated. Use PlayFromEntity instead.")] - public void Play(string filename, IEntity entity, AudioParams? audioParams = null) + /// + public IPlayingAudioStream? Play(Filter playerFilter, string filename, IEntity entity, AudioParams? audioParams = null) { - PlayFromEntity(filename, entity, audioParams); + //TODO: Calculate this from PAS + var range = audioParams is null || audioParams.Value.MaxDistance <= 0 ? AudioDistanceRange : audioParams.Value.MaxDistance; + + var id = CacheIdentifier(); + + var msg = new PlayAudioEntityMessage + { + FileName = filename, + Coordinates = entity.Transform.Coordinates, + EntityUid = entity.Uid, + AudioParams = audioParams ?? AudioParams.Default, + Identifier = id, + }; + + IList players; + var recipients = (playerFilter as IFilter).Recipients; + + if (range > 0.0f) + players = PASInRange(recipients, entity.Transform.MapPosition, range); + else + players = recipients; + + foreach (var player in players) + { + RaiseNetworkEvent(msg, player.ConnectedClient); + } + + return new AudioSourceServer(this, id, players); } - /// - /// Play an audio file at a static position. - /// - /// The resource path to the OGG Vorbis file to play. - /// The coordinates at which to play the audio. - /// - [Obsolete("Deprecated. Use PlayAtCoords instead.")] - public void Play(string filename, EntityCoordinates coordinates, AudioParams? audioParams = null) + /// + public IPlayingAudioStream? Play(Filter playerFilter, string filename, EntityCoordinates coordinates, AudioParams? audioParams = null) { - PlayAtCoords(filename, coordinates, audioParams); + //TODO: Calculate this from PAS + var range = audioParams is null || audioParams.Value.MaxDistance <= 0 ? AudioDistanceRange : audioParams.Value.MaxDistance; + + var id = CacheIdentifier(); + var msg = new PlayAudioPositionalMessage + { + FileName = filename, + Coordinates = coordinates, + AudioParams = audioParams ?? AudioParams.Default, + Identifier = id + }; + + IList players; + var recipients = (playerFilter as IFilter).Recipients; + + if (range > 0.0f) + players = PASInRange(recipients, coordinates.ToMap(EntityManager), range); + else + players = recipients; + + foreach (var player in players) + { + RaiseNetworkEvent(msg, player.ConnectedClient); + } + + return new AudioSourceServer(this, id, players); } - #endregion - } - - public static class AudioSystemExtensions - { - /// - /// Play an audio file following an entity. - /// - /// The resource path to the OGG Vorbis file to play. - /// The entity "emitting" the audio. - /// - /// The max range at which the audio will be heard. Less than or equal to 0 to send to every player. - /// Sessions that won't receive the audio message. - /// A pre-fetched instance of to use, can be null. - public static void PlaySoundFrom( - this IEntity entity, - string filename, - AudioParams? audioParams = null, - int range = AudioDistanceRange, - IPlayerSession? excludedSession = null, - AudioSystem? audioSystem = null) + private static List PASInRange(IEnumerable players, MapCoordinates position, float range) { - audioSystem ??= EntitySystem.Get(); - audioSystem.PlayFromEntity(filename, entity, audioParams, range, excludedSession); - } - - /// - /// Play an audio file at a static position. - /// - /// The resource path to the OGG Vorbis file to play. - /// The coordinates at which to play the audio. - /// - /// The max range at which the audio will be heard. Less than or equal to 0 to send to every player. - /// Session that won't receive the audio message. - /// A pre-fetched instance of to use, can be null. - public static void PlaySoundFrom( - this EntityCoordinates coordinates, - string filename, - AudioParams? audioParams = null, - int range = AudioDistanceRange, - IPlayerSession? excludedSession = null, - AudioSystem? audioSystem = null) - { - audioSystem ??= EntitySystem.Get(); - audioSystem.PlayAtCoords(filename, coordinates, audioParams, range, excludedSession); + return players.Where(x => + x.AttachedEntity != null && + position.InRange(x.AttachedEntity.Transform.MapPosition, range)) + .ToList(); } } } diff --git a/Robust.Server/Player/IPlayerSession.cs b/Robust.Server/Player/IPlayerSession.cs index 8268f4ef5..b3d793481 100644 --- a/Robust.Server/Player/IPlayerSession.cs +++ b/Robust.Server/Player/IPlayerSession.cs @@ -7,7 +7,6 @@ namespace Robust.Server.Player { public interface IPlayerSession : ICommonSession { - INetChannel ConnectedClient { get; } DateTime ConnectedTime { get; } /// diff --git a/Robust.Server/ServerIoC.cs b/Robust.Server/ServerIoC.cs index 1bdf1e66e..d8fa5cc1e 100644 --- a/Robust.Server/ServerIoC.cs +++ b/Robust.Server/ServerIoC.cs @@ -18,6 +18,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Network; +using Robust.Shared.Players; using Robust.Shared.Prototypes; using Robust.Shared.Reflection; using Robust.Shared.Timing; @@ -45,6 +46,7 @@ namespace Robust.Server IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); + IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); diff --git a/Robust.Shared/Audio/IAudioSystem.cs b/Robust.Shared/Audio/IAudioSystem.cs new file mode 100644 index 000000000..79e09d84d --- /dev/null +++ b/Robust.Shared/Audio/IAudioSystem.cs @@ -0,0 +1,48 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Map; +using Robust.Shared.Player; + +namespace Robust.Shared.Audio +{ + /// + /// Common interface for the Audio System, which is used to play sounds on clients. + /// + public interface IAudioSystem + { + /// + /// Default max range at which the sound can be heard. + /// + int DefaultSoundRange { get; } + + /// + /// Used in the PAS to designate the physics collision mask of occluders. + /// + int OcclusionCollisionMask { get; set; } + + /// + /// Play an audio file globally, without position. + /// + /// The set of players that will hear the sound. + /// The resource path to the OGG Vorbis file to play. + /// Audio parameters to apply when playing the sound. + IPlayingAudioStream? Play(Filter playerFilter, string filename, AudioParams? audioParams = null); + + /// + /// Play an audio file following an entity. + /// + /// The set of players that will hear the sound. + /// The resource path to the OGG Vorbis file to play. + /// The entity "emitting" the audio. + /// Audio parameters to apply when playing the sound. + IPlayingAudioStream? Play(Filter playerFilter, string filename, IEntity entity, AudioParams? audioParams = null); + + /// + /// Play an audio file at a static position. + /// + /// The set of players that will hear the sound. + /// The resource path to the OGG Vorbis file to play. + /// The coordinates at which to play the audio. + /// Audio parameters to apply when playing the sound. + IPlayingAudioStream? Play(Filter playerFilter, string filename, EntityCoordinates coordinates, AudioParams? audioParams = null); + } +} diff --git a/Robust.Shared/Audio/IPlayingAudioStream.cs b/Robust.Shared/Audio/IPlayingAudioStream.cs new file mode 100644 index 000000000..11b41006c --- /dev/null +++ b/Robust.Shared/Audio/IPlayingAudioStream.cs @@ -0,0 +1,7 @@ +namespace Robust.Shared.Audio +{ + public interface IPlayingAudioStream + { + void Stop(); + } +} diff --git a/Robust.Shared/Audio/SoundSystem.cs b/Robust.Shared/Audio/SoundSystem.cs new file mode 100644 index 000000000..a7446c998 --- /dev/null +++ b/Robust.Shared/Audio/SoundSystem.cs @@ -0,0 +1,82 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Map; +using Robust.Shared.Player; + +namespace Robust.Shared.Audio +{ + /// + /// A static proxy class for interfacing with the AudioSystem. + /// + public static class SoundSystem + { + /// + /// Default max range at which the sound can be heard. + /// + public static int DefaultSoundRange => GetAudio()?.DefaultSoundRange ?? 0; + + /// + /// Used in the PAS to designate the physics collision mask of occluders. + /// + public static int OcclusionCollisionMask + { + get => GetAudio()?.OcclusionCollisionMask ?? 0; + set + { + var audio = GetAudio(); + + if (audio is null) + return; + audio.OcclusionCollisionMask = value; + } + } + + private static IAudioSystem? GetAudio() + { + // There appears to be no way to get a System by interface. + var args = new QueryAudioSystem(); + IoCManager.Resolve().EventBus.RaiseEvent(EventSource.Local, args); + return args.Audio; + } + + /// + /// Play an audio file globally, without position. + /// + /// The set of players that will hear the sound. + /// The resource path to the OGG Vorbis file to play. + /// Audio parameters to apply when playing the sound. + public static IPlayingAudioStream? Play(Filter playerFilter, string filename, AudioParams? audioParams = null) + { + return GetAudio()?.Play(playerFilter, filename, audioParams); + } + + /// + /// Play an audio file following an entity. + /// + /// The set of players that will hear the sound. + /// The resource path to the OGG Vorbis file to play. + /// The entity "emitting" the audio. + /// Audio parameters to apply when playing the sound. + public static IPlayingAudioStream? Play(Filter playerFilter, string filename, IEntity entity, AudioParams? audioParams = null) + { + return GetAudio()?.Play(playerFilter, filename, entity, audioParams); + } + + /// + /// Play an audio file at a static position. + /// + /// The set of players that will hear the sound. + /// The resource path to the OGG Vorbis file to play. + /// The coordinates at which to play the audio. + /// Audio parameters to apply when playing the sound. + public static IPlayingAudioStream? Play(Filter playerFilter, string filename, EntityCoordinates coordinates, AudioParams? audioParams = null) + { + return GetAudio()?.Play(playerFilter, filename, coordinates, audioParams); + } + + internal class QueryAudioSystem : EntitySystemMessage + { + public IAudioSystem? Audio { get; set; } + } + } +} diff --git a/Robust.Shared/Players/ICommonSession.cs b/Robust.Shared/Players/ICommonSession.cs index f373cc615..cad6f7b7e 100644 --- a/Robust.Shared/Players/ICommonSession.cs +++ b/Robust.Shared/Players/ICommonSession.cs @@ -38,5 +38,14 @@ namespace Robust.Shared.Players /// Current connection latency of this session from the server to their client. /// short Ping { get; internal set; } + + /// + /// The current network channel for this player. + /// + /// + /// On the Server every player has a network channel, + /// on the Client only the LocalPlayer has a network channel. + /// + INetChannel ConnectedClient { get; } } }