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.
This commit is contained in:
Acruid
2021-03-01 20:22:28 -08:00
committed by GitHub
parent 24707b7385
commit 06e62b031a
12 changed files with 299 additions and 174 deletions

View File

@@ -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<AudioSystem>()
.Play(keyFrame.Resource, entity, keyFrame.AudioParamsFunc.Invoke());
SoundSystem.Play(Filter.Local(), keyFrame.Resource, entity, keyFrame.AudioParamsFunc.Invoke());
}
return (keyFrameIndex, playingTime);

View File

@@ -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<IClientGameStateManager, ClientGameStateManager>();
IoCManager.Register<IBaseClient, BaseClient>();
IoCManager.Register<IPlayerManager, PlayerManager>();
IoCManager.Register<ISharedPlayerManager, PlayerManager>();
IoCManager.Register<IStateManager, StateManager>();
IoCManager.Register<IUserInterfaceManager, UserInterfaceManager>();
IoCManager.Register<IUserInterfaceManagerInternal, UserInterfaceManager>();

View File

@@ -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<PlayingStream> _playingClydeStreams = new();
public int OcclusionCollisionMask;
/// <inheritdoc />
public override void Initialize()
{
@@ -35,6 +33,8 @@ namespace Robust.Client.GameObjects
SubscribeNetworkEvent<PlayAudioGlobalMessage>(PlayAudioGlobalHandler);
SubscribeNetworkEvent<PlayAudioPositionalMessage>(PlayAudioPositionalHandler);
SubscribeNetworkEvent<StopAudioMessageClient>(StopAudioMessageHandler);
SubscribeLocalEvent<SoundSystem.QueryAudioSystem>((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();
}
/// <summary>
@@ -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
{
/// <summary>
/// Play an audio file following an entity.
/// </summary>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="entity">The entity "emitting" the audio.</param>
/// <param name="audioParams"></param>
/// <param name="audioSystem">A pre-fetched instance of <see cref="AudioSystem"/> to use, can be null.</param>
public static IPlayingAudioStream? Play(
this IEntity entity,
string filename,
AudioParams? audioParams,
AudioSystem? audioSystem = null)
{
audioSystem ??= EntitySystem.Get<AudioSystem>();
return audioSystem.Play(filename, entity, audioParams);
}
/// <summary>
/// Play an audio stream following an entity.
/// </summary>
/// <param name="stream">The audio stream to play.</param>
/// <param name="entity">The entity "emitting" the audio.</param>
/// <param name="audioParams"></param>
/// <param name="audioSystem">A pre-fetched instance of <see cref="AudioSystem"/> to use, can be null.</param>
public static IPlayingAudioStream? Play(
this IEntity entity,
AudioStream stream,
AudioParams? audioParams = null,
AudioSystem? audioSystem = null)
/// <inheritdoc />
public int DefaultSoundRange => 25;
/// <inheritdoc />
public int OcclusionCollisionMask { get; set; }
/// <inheritdoc />
public IPlayingAudioStream? Play(Filter playerFilter, string filename, AudioParams? audioParams = null)
{
audioSystem ??= EntitySystem.Get<AudioSystem>();
return audioSystem.Play(stream, entity, audioParams);
return Play(filename, audioParams);
}
/// <summary>
/// Play an audio file at a static position.
/// </summary>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="coordinates">The coordinates at which to play the audio.</param>
/// <param name="audioParams"></param>
/// <param name="audioSystem">A pre-fetched instance of <see cref="AudioSystem"/> to use, can be null.</param>
public static IPlayingAudioStream? Play(
this EntityCoordinates coordinates,
string filename,
AudioParams? audioParams = null,
AudioSystem? audioSystem = null)
/// <inheritdoc />
public IPlayingAudioStream? Play(Filter playerFilter, string filename, IEntity entity, AudioParams? audioParams = null)
{
audioSystem ??= EntitySystem.Get<AudioSystem>();
return audioSystem.Play(filename, coordinates, audioParams);
return Play(filename, entity, audioParams);
}
/// <summary>
/// Play an audio stream at a static position.
/// </summary>
/// <param name="stream">The audio stream to play.</param>
/// <param name="coordinates">The coordinates at which to play the audio.</param>
/// <param name="audioParams"></param>
/// <param name="audioSystem">A pre-fetched instance of <see cref="AudioSystem"/> to use, can be null.</param>
public static IPlayingAudioStream? Play(
this EntityCoordinates coordinates,
AudioStream stream,
AudioParams? audioParams = null,
AudioSystem? audioSystem = null)
/// <inheritdoc />
public IPlayingAudioStream? Play(Filter playerFilter, string filename, EntityCoordinates coordinates, AudioParams? audioParams = null)
{
audioSystem ??= EntitySystem.Get<AudioSystem>();
return audioSystem.Play(stream, coordinates, audioParams);
return Play(filename, coordinates, audioParams);
}
}
}

View File

@@ -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);
}

View File

@@ -39,6 +39,9 @@ namespace Robust.Client.Player
/// <inheritdoc />
internal short Ping { get; set; }
/// <inheritdoc />
public INetChannel ConnectedClient { get; internal set; } = null!;
/// <inheritdoc />
short ICommonSession.Ping
{

View File

@@ -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<IPlayerSession>? _sessions;
private readonly IEnumerable<ICommonSession>? _sessions;
internal AudioSourceServer(AudioSystem parent, uint identifier, IEnumerable<IPlayerSession>? sessions = null)
internal AudioSourceServer(AudioSystem parent, uint identifier, IEnumerable<ICommonSession>? sessions = null)
{
_audioSystem = parent;
_id = identifier;
@@ -35,7 +37,13 @@ namespace Robust.Server.GameObjects
}
}
private void InternalStop(uint id, IEnumerable<IPlayerSession>? sessions = null)
/// <inheritdoc />
public override void Initialize()
{
SubscribeLocalEvent<SoundSystem.QueryAudioSystem>((ev => ev.Audio = this));
}
private void InternalStop(uint id, IEnumerable<ICommonSession>? sessions = null)
{
var msg = new StopAudioMessageClient
{
@@ -65,7 +73,9 @@ namespace Robust.Server.GameObjects
/// <param name="audioParams"></param>
/// <param name="predicate">The predicate that will be used to send the audio to players, or null to send to everyone.</param>
/// <param name="excludedSession">Session that won't receive the audio message.</param>
public AudioSourceServer PlayGlobal(string filename, AudioParams? audioParams = null, Func<IPlayerSession, bool>? predicate = null, IPlayerSession? excludedSession = null)
/// <param name="recipients"></param>
[Obsolete("Use the Play() overload.")]
public IPlayingAudioStream PlayGlobal(string filename, AudioParams? audioParams = null, Func<IPlayerSession, bool>? 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<IPlayerSession> 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);
}
/// <summary>
@@ -107,7 +116,8 @@ namespace Robust.Server.GameObjects
/// <param name="audioParams"></param>
/// <param name="range">The max range at which the audio will be heard. Less than or equal to 0 to send to every player.</param>
/// <param name="excludedSession">Sessions that won't receive the audio message.</param>
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<IPlayerSession> 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
/// <param name="audioParams"></param>
/// <param name="range">The max range at which the audio will be heard. Less than or equal to 0 to send to every player.</param>
/// <param name="excludedSession">Session that won't receive the audio message.</param>
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<IPlayerSession> 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
/// <summary>
/// Play an audio file globally, without position.
/// </summary>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="audioParams"></param>
[Obsolete("Deprecated. Use PlayGlobal instead.")]
public void Play(string filename, AudioParams? audioParams = null)
/// <inheritdoc />
public int DefaultSoundRange => AudioDistanceRange;
/// <inheritdoc />
public int OcclusionCollisionMask { get; set; }
/// <inheritdoc />
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);
}
/// <summary>
/// Play an audio file following an entity.
/// </summary>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="entity">The entity "emitting" the audio.</param>
/// <param name="audioParams"></param>
[Obsolete("Deprecated. Use PlayFromEntity instead.")]
public void Play(string filename, IEntity entity, AudioParams? audioParams = null)
/// <inheritdoc />
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<ICommonSession> 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);
}
/// <summary>
/// Play an audio file at a static position.
/// </summary>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="coordinates">The coordinates at which to play the audio.</param>
/// <param name="audioParams"></param>
[Obsolete("Deprecated. Use PlayAtCoords instead.")]
public void Play(string filename, EntityCoordinates coordinates, AudioParams? audioParams = null)
/// <inheritdoc />
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<ICommonSession> 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
{
/// <summary>
/// Play an audio file following an entity.
/// </summary>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="entity">The entity "emitting" the audio.</param>
/// <param name="audioParams"></param>
/// <param name="range">The max range at which the audio will be heard. Less than or equal to 0 to send to every player.</param>
/// <param name="excludedSession">Sessions that won't receive the audio message.</param>
/// <param name="audioSystem">A pre-fetched instance of <see cref="AudioSystem"/> to use, can be null.</param>
public static void PlaySoundFrom(
this IEntity entity,
string filename,
AudioParams? audioParams = null,
int range = AudioDistanceRange,
IPlayerSession? excludedSession = null,
AudioSystem? audioSystem = null)
private static List<ICommonSession> PASInRange(IEnumerable<ICommonSession> players, MapCoordinates position, float range)
{
audioSystem ??= EntitySystem.Get<AudioSystem>();
audioSystem.PlayFromEntity(filename, entity, audioParams, range, excludedSession);
}
/// <summary>
/// Play an audio file at a static position.
/// </summary>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="coordinates">The coordinates at which to play the audio.</param>
/// <param name="audioParams"></param>
/// <param name="range">The max range at which the audio will be heard. Less than or equal to 0 to send to every player.</param>
/// <param name="excludedSession">Session that won't receive the audio message.</param>
/// <param name="audioSystem">A pre-fetched instance of <see cref="AudioSystem"/> to use, can be null.</param>
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>();
audioSystem.PlayAtCoords(filename, coordinates, audioParams, range, excludedSession);
return players.Where(x =>
x.AttachedEntity != null &&
position.InRange(x.AttachedEntity.Transform.MapPosition, range))
.ToList();
}
}
}

View File

@@ -7,7 +7,6 @@ namespace Robust.Server.Player
{
public interface IPlayerSession : ICommonSession
{
INetChannel ConnectedClient { get; }
DateTime ConnectedTime { get; }
/// <summary>

View File

@@ -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<IMapLoader, MapLoader>();
IoCManager.Register<IPlacementManager, PlacementManager>();
IoCManager.Register<IPlayerManager, PlayerManager>();
IoCManager.Register<ISharedPlayerManager, PlayerManager>();
IoCManager.Register<IPrototypeManager, ServerPrototypeManager>();
IoCManager.Register<IReflectionManager, ServerReflectionManager>();
IoCManager.Register<IResourceManager, ResourceManager>();

View File

@@ -0,0 +1,48 @@
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Player;
namespace Robust.Shared.Audio
{
/// <summary>
/// Common interface for the Audio System, which is used to play sounds on clients.
/// </summary>
public interface IAudioSystem
{
/// <summary>
/// Default max range at which the sound can be heard.
/// </summary>
int DefaultSoundRange { get; }
/// <summary>
/// Used in the PAS to designate the physics collision mask of occluders.
/// </summary>
int OcclusionCollisionMask { get; set; }
/// <summary>
/// Play an audio file globally, without position.
/// </summary>
/// <param name="playerFilter">The set of players that will hear the sound.</param>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="audioParams">Audio parameters to apply when playing the sound.</param>
IPlayingAudioStream? Play(Filter playerFilter, string filename, AudioParams? audioParams = null);
/// <summary>
/// Play an audio file following an entity.
/// </summary>
/// <param name="playerFilter">The set of players that will hear the sound.</param>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="entity">The entity "emitting" the audio.</param>
/// <param name="audioParams">Audio parameters to apply when playing the sound.</param>
IPlayingAudioStream? Play(Filter playerFilter, string filename, IEntity entity, AudioParams? audioParams = null);
/// <summary>
/// Play an audio file at a static position.
/// </summary>
/// <param name="playerFilter">The set of players that will hear the sound.</param>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="coordinates">The coordinates at which to play the audio.</param>
/// <param name="audioParams">Audio parameters to apply when playing the sound.</param>
IPlayingAudioStream? Play(Filter playerFilter, string filename, EntityCoordinates coordinates, AudioParams? audioParams = null);
}
}

View File

@@ -0,0 +1,7 @@
namespace Robust.Shared.Audio
{
public interface IPlayingAudioStream
{
void Stop();
}
}

View File

@@ -0,0 +1,82 @@
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Player;
namespace Robust.Shared.Audio
{
/// <summary>
/// A static proxy class for interfacing with the AudioSystem.
/// </summary>
public static class SoundSystem
{
/// <summary>
/// Default max range at which the sound can be heard.
/// </summary>
public static int DefaultSoundRange => GetAudio()?.DefaultSoundRange ?? 0;
/// <summary>
/// Used in the PAS to designate the physics collision mask of occluders.
/// </summary>
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<IEntityManager>().EventBus.RaiseEvent(EventSource.Local, args);
return args.Audio;
}
/// <summary>
/// Play an audio file globally, without position.
/// </summary>
/// <param name="playerFilter">The set of players that will hear the sound.</param>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="audioParams">Audio parameters to apply when playing the sound.</param>
public static IPlayingAudioStream? Play(Filter playerFilter, string filename, AudioParams? audioParams = null)
{
return GetAudio()?.Play(playerFilter, filename, audioParams);
}
/// <summary>
/// Play an audio file following an entity.
/// </summary>
/// <param name="playerFilter">The set of players that will hear the sound.</param>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="entity">The entity "emitting" the audio.</param>
/// <param name="audioParams">Audio parameters to apply when playing the sound.</param>
public static IPlayingAudioStream? Play(Filter playerFilter, string filename, IEntity entity, AudioParams? audioParams = null)
{
return GetAudio()?.Play(playerFilter, filename, entity, audioParams);
}
/// <summary>
/// Play an audio file at a static position.
/// </summary>
/// <param name="playerFilter">The set of players that will hear the sound.</param>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="coordinates">The coordinates at which to play the audio.</param>
/// <param name="audioParams">Audio parameters to apply when playing the sound.</param>
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; }
}
}
}

View File

@@ -38,5 +38,14 @@ namespace Robust.Shared.Players
/// Current connection latency of this session from the server to their client.
/// </summary>
short Ping { get; internal set; }
/// <summary>
/// The current network channel for this player.
/// </summary>
/// <remarks>
/// On the Server every player has a network channel,
/// on the Client only the LocalPlayer has a network channel.
/// </remarks>
INetChannel ConnectedClient { get; }
}
}