diff --git a/Robust.Client/Animations/AnimationTrackPlaySound.cs b/Robust.Client/Animations/AnimationTrackPlaySound.cs index be5051a4d8f..11f6a6e7434 100644 --- a/Robust.Client/Animations/AnimationTrackPlaySound.cs +++ b/Robust.Client/Animations/AnimationTrackPlaySound.cs @@ -40,11 +40,7 @@ public override (int KeyFrameIndex, float FramePlayingTime) var keyFrame = KeyFrames[keyFrameIndex]; var audioParams = keyFrame.AudioParamsFunc.Invoke(); - var audio = new SoundPathSpecifier(keyFrame.Resource) - { - Params = audioParams - }; - IoCManager.Resolve().GetEntitySystem().PlayEntity(audio, Filter.Local(), entity, true); + IoCManager.Resolve().GetEntitySystem().PlayEntity(keyFrame.Specifier, Filter.Local(), entity, true, audioParams); } return (keyFrameIndex, playingTime); @@ -55,7 +51,7 @@ public struct KeyFrame /// /// The RSI state to play when this keyframe gets triggered. /// - public readonly string Resource; + public readonly ResolvedSoundSpecifier Specifier; /// /// A function that returns the audio parameter to be used. @@ -69,9 +65,9 @@ public struct KeyFrame /// public readonly float KeyTime; - public KeyFrame(string resource, float keyTime, Func? audioParams = null) + public KeyFrame(ResolvedSoundSpecifier specifier, float keyTime, Func? audioParams = null) { - Resource = resource; + Specifier = specifier; KeyTime = keyTime; AudioParamsFunc = audioParams ?? (() => AudioParams.Default); } diff --git a/Robust.Client/Audio/AudioSystem.cs b/Robust.Client/Audio/AudioSystem.cs index 5dfd954bb4c..93aedbbdaa9 100644 --- a/Robust.Client/Audio/AudioSystem.cs +++ b/Robust.Client/Audio/AudioSystem.cs @@ -43,6 +43,10 @@ public sealed partial class AudioSystem : SharedAudioSystem [Dependency] private readonly SharedMapSystem _maps = default!; [Dependency] private readonly SharedTransformSystem _xformSys = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + + public event Action? OnSubtitledAudioStart; + public event Action? OnSubtitledAudioEnd; /// /// Per-tick cache of relevant streams. @@ -172,17 +176,23 @@ public void SetMasterVolume(float value) private void OnAudioPaused(EntityUid uid, AudioComponent component, ref EntityPausedEvent args) { + if (_entityManager.TryGetComponent(uid, out CaptionComponent? caption)) + OnSubtitledAudioEnd?.Invoke(caption); component.Pause(); } protected override void OnAudioUnpaused(EntityUid uid, AudioComponent component, ref EntityUnpausedEvent args) { + if (_entityManager.TryGetComponent(uid, out CaptionComponent? caption)) + OnSubtitledAudioStart?.Invoke(caption); base.OnAudioUnpaused(uid, component, ref args); component.StartPlaying(); } private void OnAudioStartup(EntityUid uid, AudioComponent component, ComponentStartup args) { + if (_entityManager.TryGetComponent(uid, out CaptionComponent? caption)) + OnSubtitledAudioStart?.Invoke(caption); if (!Timing.ApplyingState && !Timing.IsFirstTimePredicted) { return; @@ -247,6 +257,8 @@ private void OnAudioShutdown(EntityUid uid, AudioComponent component, ComponentS component.Source.Dispose(); RemoveAudioLimit(component.FileName); + if (_entityManager.TryGetComponent(uid, out CaptionComponent? caption)) + OnSubtitledAudioEnd?.Invoke(caption); } private void OnAudioAttenuation(int obj) @@ -415,6 +427,16 @@ public float GetOcclusion(MapCoordinates listener, Vector2 delta, float distance return occlusion; } + private bool TryGetAudio(ResolvedSoundSpecifier specifier, [NotNullWhen(true)] out AudioResource? audio) + { + var filename = GetAudioPath(specifier); + if (_resourceCache.TryGetResource(new ResPath(filename), out audio)) + return true; + + Log.Error($"Server tried to play audio file {filename} which does not exist."); + return false; + } + private bool TryGetAudio(string filename, [NotNullWhen(true)] out AudioResource? audio) { if (_resourceCache.TryGetResource(new ResPath(filename), out audio)) @@ -433,15 +455,15 @@ private bool TryGetAudio(AudioStream stream, [NotNullWhen(true)] out AudioResour return false; } - public override (EntityUid Entity, AudioComponent Component)? PlayPvs(string? filename, EntityCoordinates coordinates, + public override (EntityUid Entity, AudioComponent Component)? PlayPvs(ResolvedSoundSpecifier? specifier, EntityCoordinates coordinates, AudioParams? audioParams = null) { - return PlayStatic(filename, Filter.Local(), coordinates, true, audioParams); + return PlayStatic(specifier, Filter.Local(), coordinates, true, audioParams); } - public override (EntityUid Entity, AudioComponent Component)? PlayPvs(string? filename, EntityUid uid, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayPvs(ResolvedSoundSpecifier? specifier, EntityUid uid, AudioParams? audioParams = null) { - return PlayEntity(filename, Filter.Local(), uid, true, audioParams); + return PlayEntity(specifier, Filter.Local(), uid, true, audioParams); } /// @@ -477,21 +499,21 @@ public override (EntityUid Entity, AudioComponent Component)? PlayPredicted(Soun /// /// The resource path to the OGG Vorbis file to play. /// - private (EntityUid Entity, AudioComponent Component)? PlayGlobal(string? filename, AudioParams? audioParams = null, bool recordReplay = true) + private (EntityUid Entity, AudioComponent Component)? PlayGlobal(ResolvedSoundSpecifier? specifier, AudioParams? audioParams = null, bool recordReplay = true) { - if (string.IsNullOrEmpty(filename)) + if (specifier is null) return null; if (recordReplay && _replayRecording.IsRecording) { _replayRecording.RecordReplayMessage(new PlayAudioGlobalMessage { - FileName = filename, + Specifier = specifier, AudioParams = audioParams ?? AudioParams.Default }); } - return TryGetAudio(filename, out var audio) ? PlayGlobal(audio, audioParams) : default; + return TryGetAudio(specifier, out var audio) ? PlayGlobal(audio, specifier, audioParams) : default; } /// @@ -499,9 +521,9 @@ public override (EntityUid Entity, AudioComponent Component)? PlayPredicted(Soun /// /// The audio stream to play. /// - public (EntityUid Entity, AudioComponent Component)? PlayGlobal(AudioStream stream, AudioParams? audioParams = null) + public (EntityUid Entity, AudioComponent Component)? PlayGlobal(AudioStream stream, ResolvedSoundSpecifier? specifier, AudioParams? audioParams = null) { - var (entity, component) = CreateAndStartPlayingStream(audioParams, stream); + var (entity, component) = CreateAndStartPlayingStream(audioParams, specifier, stream); component.Global = true; component.Source.Global = true; Dirty(entity, component); @@ -513,22 +535,22 @@ public override (EntityUid Entity, AudioComponent Component)? PlayPredicted(Soun /// /// The resource path to the OGG Vorbis file to play. /// The entity "emitting" the audio. - private (EntityUid Entity, AudioComponent Component)? PlayEntity(string? filename, EntityUid entity, AudioParams? audioParams = null, bool recordReplay = true) + private (EntityUid Entity, AudioComponent Component)? PlayEntity(ResolvedSoundSpecifier? specifier, EntityUid entity, AudioParams? audioParams = null, bool recordReplay = true) { - if (string.IsNullOrEmpty(filename)) + if (specifier is null) return null; if (recordReplay && _replayRecording.IsRecording) { _replayRecording.RecordReplayMessage(new PlayAudioEntityMessage { - FileName = filename, + Specifier = specifier, NetEntity = GetNetEntity(entity), AudioParams = audioParams ?? AudioParams.Default }); } - return TryGetAudio(filename, out var audio) ? PlayEntity(audio, entity, audioParams) : default; + return TryGetAudio(specifier, out var audio) ? PlayEntity(audio, entity, specifier, audioParams) : default; } /// @@ -537,7 +559,7 @@ public override (EntityUid Entity, AudioComponent Component)? PlayPredicted(Soun /// The audio stream to play. /// The entity "emitting" the audio. /// - public (EntityUid Entity, AudioComponent Component)? PlayEntity(AudioStream stream, EntityUid entity, AudioParams? audioParams = null) + public (EntityUid Entity, AudioComponent Component)? PlayEntity(AudioStream stream, EntityUid entity, ResolvedSoundSpecifier? specifier, AudioParams? audioParams = null) { if (TerminatingOrDeleted(entity)) { @@ -545,7 +567,7 @@ public override (EntityUid Entity, AudioComponent Component)? PlayPredicted(Soun return null; } - var playing = CreateAndStartPlayingStream(audioParams, stream); + var playing = CreateAndStartPlayingStream(audioParams, specifier, stream); _xformSys.SetCoordinates(playing.Entity, new EntityCoordinates(entity, Vector2.Zero)); return playing; @@ -557,22 +579,22 @@ public override (EntityUid Entity, AudioComponent Component)? PlayPredicted(Soun /// The resource path to the OGG Vorbis file to play. /// The coordinates at which to play the audio. /// - private (EntityUid Entity, AudioComponent Component)? PlayStatic(string? filename, EntityCoordinates coordinates, AudioParams? audioParams = null, bool recordReplay = true) + private (EntityUid Entity, AudioComponent Component)? PlayStatic(ResolvedSoundSpecifier? specifier, EntityCoordinates coordinates, AudioParams? audioParams = null, bool recordReplay = true) { - if (string.IsNullOrEmpty(filename)) + if (specifier is null) return null; if (recordReplay && _replayRecording.IsRecording) { _replayRecording.RecordReplayMessage(new PlayAudioPositionalMessage { - FileName = filename, + Specifier = specifier, Coordinates = GetNetCoordinates(coordinates), AudioParams = audioParams ?? AudioParams.Default }); } - return TryGetAudio(filename, out var audio) ? PlayStatic(audio, coordinates, audioParams) : default; + return TryGetAudio(specifier, out var audio) ? PlayStatic(audio, coordinates, specifier, audioParams) : default; } /// @@ -581,7 +603,7 @@ public override (EntityUid Entity, AudioComponent Component)? PlayPredicted(Soun /// The audio stream to play. /// The coordinates at which to play the audio. /// - public (EntityUid Entity, AudioComponent Component)? PlayStatic(AudioStream stream, EntityCoordinates coordinates, AudioParams? audioParams = null) + public (EntityUid Entity, AudioComponent Component)? PlayStatic(AudioStream stream, EntityCoordinates coordinates, ResolvedSoundSpecifier? specifier, AudioParams? audioParams = null) { if (TerminatingOrDeleted(coordinates.EntityId)) { @@ -589,33 +611,33 @@ public override (EntityUid Entity, AudioComponent Component)? PlayPredicted(Soun return null; } - var playing = CreateAndStartPlayingStream(audioParams, stream); + var playing = CreateAndStartPlayingStream(audioParams, specifier, stream); _xformSys.SetCoordinates(playing.Entity, coordinates); return playing; } /// - public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(string? filename, Filter playerFilter, bool recordReplay, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(ResolvedSoundSpecifier? specifier, Filter playerFilter, bool recordReplay, AudioParams? audioParams = null) { - return PlayGlobal(filename, audioParams); + return PlayGlobal(specifier, audioParams); } /// - public override (EntityUid Entity, AudioComponent Component)? PlayEntity(string? filename, Filter playerFilter, EntityUid entity, bool recordReplay, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayEntity(ResolvedSoundSpecifier? specifier, Filter playerFilter, EntityUid entity, bool recordReplay, AudioParams? audioParams = null) { - return PlayEntity(filename, entity, audioParams); + return PlayEntity(specifier, entity, audioParams); } /// - public override (EntityUid Entity, AudioComponent Component)? PlayStatic(string? filename, Filter playerFilter, EntityCoordinates coordinates, bool recordReplay, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayStatic(ResolvedSoundSpecifier? specifier, Filter playerFilter, EntityCoordinates coordinates, bool recordReplay, AudioParams? audioParams = null) { - return PlayStatic(filename, coordinates, audioParams); + return PlayStatic(specifier, coordinates, audioParams); } /// - public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(string? filename, ICommonSession recipient, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(ResolvedSoundSpecifier? specifier, ICommonSession recipient, AudioParams? audioParams = null) { - return PlayGlobal(filename, audioParams); + return PlayGlobal(specifier, audioParams); } public override void LoadStream(Entity entity, T stream) @@ -629,39 +651,39 @@ public override void LoadStream(Entity entity, T stream) } /// - public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(string? filename, EntityUid recipient, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(ResolvedSoundSpecifier? specifier, EntityUid recipient, AudioParams? audioParams = null) { - return PlayGlobal(filename, audioParams); + return PlayGlobal(specifier, audioParams); } /// - public override (EntityUid Entity, AudioComponent Component)? PlayEntity(string? filename, ICommonSession recipient, EntityUid uid, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayEntity(ResolvedSoundSpecifier? specifier, ICommonSession recipient, EntityUid uid, AudioParams? audioParams = null) { - return PlayEntity(filename, uid, audioParams); + return PlayEntity(specifier, uid, audioParams); } /// - public override (EntityUid Entity, AudioComponent Component)? PlayEntity(string? filename, EntityUid recipient, EntityUid uid, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayEntity(ResolvedSoundSpecifier? specifier, EntityUid recipient, EntityUid uid, AudioParams? audioParams = null) { - return PlayEntity(filename, uid, audioParams); + return PlayEntity(specifier, uid, audioParams); } /// - public override (EntityUid Entity, AudioComponent Component)? PlayStatic(string? filename, ICommonSession recipient, EntityCoordinates coordinates, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayStatic(ResolvedSoundSpecifier? specifier, ICommonSession recipient, EntityCoordinates coordinates, AudioParams? audioParams = null) { - return PlayStatic(filename, coordinates, audioParams); + return PlayStatic(specifier, coordinates, audioParams); } /// - public override (EntityUid Entity, AudioComponent Component)? PlayStatic(string? filename, EntityUid recipient, EntityCoordinates coordinates, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayStatic(ResolvedSoundSpecifier? specifier, EntityUid recipient, EntityCoordinates coordinates, AudioParams? audioParams = null) { - return PlayStatic(filename, coordinates, audioParams); + return PlayStatic(specifier, coordinates, audioParams); } - private (EntityUid Entity, AudioComponent Component) CreateAndStartPlayingStream(AudioParams? audioParams, AudioStream stream) + private (EntityUid Entity, AudioComponent Component) CreateAndStartPlayingStream(AudioParams? audioParams, ResolvedSoundSpecifier? specifier, AudioStream stream) { var audioP = audioParams ?? AudioParams.Default; - var entity = SetupAudio(null, audioP, initialize: false, length: stream.Length); + var entity = SetupAudio(specifier, audioP, initialize: false, length: stream.Length); LoadStream(entity, stream); EntityManager.InitializeAndStartEntity(entity); var comp = entity.Comp; @@ -694,17 +716,17 @@ private void ApplyAudioParams(AudioParams audioParams, IAudioSource source) private void OnEntityCoordinates(PlayAudioPositionalMessage ev) { - PlayStatic(ev.FileName, GetCoordinates(ev.Coordinates), ev.AudioParams, false); + PlayStatic(ev.Specifier, GetCoordinates(ev.Coordinates), ev.AudioParams, false); } private void OnEntityAudio(PlayAudioEntityMessage ev) { - PlayEntity(ev.FileName, GetEntity(ev.NetEntity), ev.AudioParams, false); + PlayEntity(ev.Specifier, GetEntity(ev.NetEntity), ev.AudioParams, false); } private void OnGlobalAudio(PlayAudioGlobalMessage ev) { - PlayGlobal(ev.FileName, ev.AudioParams, false); + PlayGlobal(ev.Specifier, ev.AudioParams, false); } protected override TimeSpan GetAudioLengthImpl(string filename) diff --git a/Robust.Client/ComponentTrees/CaptionTreeSystem.cs b/Robust.Client/ComponentTrees/CaptionTreeSystem.cs new file mode 100644 index 00000000000..886d45feb3d --- /dev/null +++ b/Robust.Client/ComponentTrees/CaptionTreeSystem.cs @@ -0,0 +1,46 @@ +using System.Numerics; +using Robust.Client.GameObjects; +using Robust.Shared.ComponentTrees; +using Robust.Shared.GameObjects; +using Robust.Shared.Maths; +using Robust.Shared.Physics; +using Robust.Shared.Audio.Components; +using Robust.Shared.IoC; + +namespace Robust.Client.ComponentTrees; + +public sealed class CaptionTreeSystem : ComponentTreeSystem +{ + [Dependency] private readonly IEntityManager _entityManager = default!; + + #region Component Tree Overrides + protected override bool DoFrameUpdate => false; + protected override bool DoTickUpdate => true; + protected override bool Recursive => true; + protected override int InitialCapacity => 128; + + protected override Box2 ExtractAabb(in ComponentTreeEntry entry, Vector2 pos, Angle rot) + { + if (_entityManager.TryGetComponent(entry.Uid, out AudioComponent? audio)) + { + var radius = audio.MaxDistance; + var radiusVec = new Vector2(radius, radius); + return new Box2(pos - radiusVec, pos + radiusVec); + } + return default; + } + + protected override Box2 ExtractAabb(in ComponentTreeEntry entry) + { + if (entry.Component.TreeUid == null) + return default; + + var pos = XformSystem.GetRelativePosition( + entry.Transform, + entry.Component.TreeUid.Value, + GetEntityQuery()); + + return ExtractAabb(in entry, pos, default); + } + #endregion +} diff --git a/Robust.Server/Audio/AudioSystem.cs b/Robust.Server/Audio/AudioSystem.cs index 981c01e770e..6d5bcc274eb 100644 --- a/Robust.Server/Audio/AudioSystem.cs +++ b/Robust.Server/Audio/AudioSystem.cs @@ -81,27 +81,27 @@ private void AddAudioFilter(EntityUid uid, AudioComponent component, Filter filt } /// - public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(string? filename, Filter playerFilter, bool recordReplay, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(ResolvedSoundSpecifier? specifier, Filter playerFilter, bool recordReplay, AudioParams? audioParams = null) { - if (string.IsNullOrEmpty(filename)) + if (specifier is null) return null; - var entity = SetupAudio(filename, audioParams); + var entity = SetupAudio(specifier, audioParams); AddAudioFilter(entity, entity.Comp, playerFilter); entity.Comp.Global = true; return (entity, entity.Comp); } /// - public override (EntityUid Entity, AudioComponent Component)? PlayEntity(string? filename, Filter playerFilter, EntityUid uid, bool recordReplay, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayEntity(ResolvedSoundSpecifier? specifier, Filter playerFilter, EntityUid uid, bool recordReplay, AudioParams? audioParams = null) { - if (string.IsNullOrEmpty(filename)) + if (specifier is null) return null; if (TerminatingOrDeleted(uid)) return null; - var entity = SetupAudio(filename, audioParams); + var entity = SetupAudio(specifier, audioParams); // Move it after setting it up XformSystem.SetCoordinates(entity, new EntityCoordinates(uid, Vector2.Zero)); AddAudioFilter(entity, entity.Comp, playerFilter); @@ -110,24 +110,24 @@ public override (EntityUid Entity, AudioComponent Component)? PlayEntity(string? } /// - public override (EntityUid Entity, AudioComponent Component)? PlayPvs(string? filename, EntityUid uid, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayPvs(ResolvedSoundSpecifier? specifier, EntityUid uid, AudioParams? audioParams = null) { - if (string.IsNullOrEmpty(filename)) + if (specifier is null) return null; if (TerminatingOrDeleted(uid)) return null; - var entity = SetupAudio(filename, audioParams); + var entity = SetupAudio(specifier, audioParams); XformSystem.SetCoordinates(entity, new EntityCoordinates(uid, Vector2.Zero)); return (entity, entity.Comp); } /// - public override (EntityUid Entity, AudioComponent Component)? PlayStatic(string? filename, Filter playerFilter, EntityCoordinates coordinates, bool recordReplay, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayStatic(ResolvedSoundSpecifier? specifier, Filter playerFilter, EntityCoordinates coordinates, bool recordReplay, AudioParams? audioParams = null) { - if (string.IsNullOrEmpty(filename)) + if (specifier is null) return null; if (TerminatingOrDeleted(coordinates.EntityId)) @@ -139,7 +139,7 @@ public override (EntityUid Entity, AudioComponent Component)? PlayStatic(string? if (!coordinates.IsValid(EntityManager)) return null; - var entity = SetupAudio(filename, audioParams); + var entity = SetupAudio(specifier, audioParams); XformSystem.SetCoordinates(entity, coordinates); AddAudioFilter(entity, entity.Comp, playerFilter); @@ -147,10 +147,10 @@ public override (EntityUid Entity, AudioComponent Component)? PlayStatic(string? } /// - public override (EntityUid Entity, AudioComponent Component)? PlayPvs(string? filename, EntityCoordinates coordinates, + public override (EntityUid Entity, AudioComponent Component)? PlayPvs(ResolvedSoundSpecifier? specifier, EntityCoordinates coordinates, AudioParams? audioParams = null) { - if (string.IsNullOrEmpty(filename)) + if (specifier is null) return null; if (TerminatingOrDeleted(coordinates.EntityId)) @@ -163,7 +163,7 @@ public override (EntityUid Entity, AudioComponent Component)? PlayPvs(string? fi return null; // TODO: Transform TryFindGridAt mess + optimisation required. - var entity = SetupAudio(filename, audioParams); + var entity = SetupAudio(specifier, audioParams); XformSystem.SetCoordinates(entity, coordinates); return (entity, entity.Comp); @@ -186,7 +186,7 @@ public override (EntityUid Entity, AudioComponent Component)? PlayPredicted(Soun if (sound == null) return null; - var audio = PlayPvs(GetSound(sound), source, audioParams ?? sound.Params); + var audio = PlayPvs(ResolveSound(sound), source, audioParams ?? sound.Params); if (audio == null) return null; @@ -201,7 +201,7 @@ public override (EntityUid Entity, AudioComponent Component)? PlayPredicted(Soun if (sound == null) return null; - var audio = PlayPvs(GetSound(sound), coordinates, audioParams ?? sound.Params); + var audio = PlayPvs(ResolveSound(sound), coordinates, audioParams ?? sound.Params); if (audio == null) return null; @@ -210,12 +210,12 @@ public override (EntityUid Entity, AudioComponent Component)? PlayPredicted(Soun return audio; } - public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(string? filename, ICommonSession recipient, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(ResolvedSoundSpecifier? filename, ICommonSession recipient, AudioParams? audioParams = null) { return PlayGlobal(filename, Filter.SinglePlayer(recipient), false, audioParams); } - public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(string? filename, EntityUid recipient, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(ResolvedSoundSpecifier? filename, EntityUid recipient, AudioParams? audioParams = null) { if (TryComp(recipient, out ActorComponent? actor)) return PlayGlobal(filename, actor.PlayerSession, audioParams); @@ -223,12 +223,12 @@ public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(string? return null; } - public override (EntityUid Entity, AudioComponent Component)? PlayEntity(string? filename, ICommonSession recipient, EntityUid uid, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayEntity(ResolvedSoundSpecifier? filename, ICommonSession recipient, EntityUid uid, AudioParams? audioParams = null) { return PlayEntity(filename, Filter.SinglePlayer(recipient), uid, false, audioParams); } - public override (EntityUid Entity, AudioComponent Component)? PlayEntity(string? filename, EntityUid recipient, EntityUid uid, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayEntity(ResolvedSoundSpecifier? filename, EntityUid recipient, EntityUid uid, AudioParams? audioParams = null) { if (TryComp(recipient, out ActorComponent? actor)) return PlayEntity(filename, actor.PlayerSession, uid, audioParams); @@ -236,12 +236,12 @@ public override (EntityUid Entity, AudioComponent Component)? PlayEntity(string? return null; } - public override (EntityUid Entity, AudioComponent Component)? PlayStatic(string? filename, ICommonSession recipient, EntityCoordinates coordinates, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayStatic(ResolvedSoundSpecifier? filename, ICommonSession recipient, EntityCoordinates coordinates, AudioParams? audioParams = null) { return PlayStatic(filename, Filter.SinglePlayer(recipient), coordinates, false, audioParams); } - public override (EntityUid Entity, AudioComponent Component)? PlayStatic(string? filename, EntityUid recipient, EntityCoordinates coordinates, AudioParams? audioParams = null) + public override (EntityUid Entity, AudioComponent Component)? PlayStatic(ResolvedSoundSpecifier? filename, EntityUid recipient, EntityCoordinates coordinates, AudioParams? audioParams = null) { if (TryComp(recipient, out ActorComponent? actor)) return PlayStatic(filename, actor.PlayerSession, coordinates, audioParams); diff --git a/Robust.Shared/Audio/Components/CaptionComponent.cs b/Robust.Shared/Audio/Components/CaptionComponent.cs new file mode 100644 index 00000000000..f39cfe865c4 --- /dev/null +++ b/Robust.Shared/Audio/Components/CaptionComponent.cs @@ -0,0 +1,30 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Localization; +using Robust.Shared.ViewVariables; +using Robust.Shared.Physics; +using Robust.Shared.ComponentTrees; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.GameStates; + +namespace Robust.Shared.Audio.Components; + +/// +/// Stores the caption data for an audio entity. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +public sealed partial class CaptionComponent : Component, IComponentTreeEntry +{ + [DataField, AutoNetworkedField] + public LocId? Caption { get; set; } + + [ViewVariables(VVAccess.ReadOnly)] + public string? LocalizedCaption => Caption != null ? Loc.GetString(Caption) : null; + + public EntityUid? TreeUid { get; set; } + + public DynamicTree>? Tree { get; set; } + + public bool AddToTree => true; + + public bool TreeUpdateQueued { get; set; } +} diff --git a/Robust.Shared/Audio/Components/CaptionTreeComponent.cs b/Robust.Shared/Audio/Components/CaptionTreeComponent.cs new file mode 100644 index 00000000000..5c38cb87e59 --- /dev/null +++ b/Robust.Shared/Audio/Components/CaptionTreeComponent.cs @@ -0,0 +1,14 @@ +using Robust.Shared.Physics; +using Robust.Shared.ComponentTrees; +using Robust.Shared.GameObjects; + +namespace Robust.Shared.Audio.Components; + +/// +/// Samples nearby . +/// +[RegisterComponent] +public sealed partial class CaptionTreeComponent : Component, IComponentTreeComponent +{ + public DynamicTree> Tree { get; set; } = default!; +} diff --git a/Robust.Shared/Audio/ResolvedSoundSpecifier.cs b/Robust.Shared/Audio/ResolvedSoundSpecifier.cs new file mode 100644 index 00000000000..e32e553dbcf --- /dev/null +++ b/Robust.Shared/Audio/ResolvedSoundSpecifier.cs @@ -0,0 +1,90 @@ +using System; +using JetBrains.Annotations; +using Robust.Shared.Utility; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.Prototypes; + +namespace Robust.Shared.Audio; + +/// +/// Represents a path to a sound resource, either as a literal path or as a collection ID and index. +/// +/// +/// +[Serializable, NetSerializable] +public abstract partial class ResolvedSoundSpecifier { + [Obsolete("String literals for sounds are deprecated, use a SoundSpecifier or ResolvedSoundSpecifier as appropriate instead")] + public static implicit operator ResolvedSoundSpecifier(string s) => new ResolvedPathSpecifier(s); + [Obsolete("String literals for sounds are deprecated, use a SoundSpecifier or ResolvedSoundSpecifier as appropriate instead")] + public static implicit operator ResolvedSoundSpecifier(ResPath s) => new ResolvedPathSpecifier(s); + + /// + /// Returns whether s is null, or if it contains an empty path/collection ID. + /// + public static bool IsNullOrEmpty(ResolvedSoundSpecifier? s) { + return s switch { + null => true, + ResolvedPathSpecifier path => path.Path.ToString() == "", + ResolvedCollectionSpecifier collection => string.IsNullOrEmpty(collection.Collection), + _ => throw new ArgumentOutOfRangeException("s", s, "argument is not a ResolvedPathSpecifier or a ResolvedCollectionSpecifier"), + }; + } +} + +/// +/// Represents a path to a sound resource as a literal path. +/// +/// +[Serializable, NetSerializable] +public sealed partial class ResolvedPathSpecifier : ResolvedSoundSpecifier { + /// + /// The resource path of the sound. + /// + public ResPath Path { get; private set; } + + override public string ToString() => + $"ResolvedPathSpecifier({Path})"; + + [UsedImplicitly] + private ResolvedPathSpecifier() + { + } + public ResolvedPathSpecifier(ResPath path) + { + Path = path; + } + public ResolvedPathSpecifier(string path) : this(new ResPath(path)) + { + } +} + +/// +/// Represents a path to a sound resource as a collection ID and index. +/// +/// +[Serializable, NetSerializable] +public sealed partial class ResolvedCollectionSpecifier : ResolvedSoundSpecifier { + /// + /// The ID of the sound collection to look up. + /// + public ProtoId? Collection { get; private set; } + /// + /// The index of the file in the associated sound collection to play. + /// + public int Index { get; private set; } + + override public string ToString() => + $"ResolvedCollectionSpecifier({Collection}, {Index})"; + + [UsedImplicitly] + private ResolvedCollectionSpecifier() + { + } + + public ResolvedCollectionSpecifier(string collection, int index) + { + Collection = collection; + Index = index; + } +} diff --git a/Robust.Shared/Audio/SoundCollectionPrototype.cs b/Robust.Shared/Audio/SoundCollectionPrototype.cs index 350bfb85dcb..ff13451c23c 100644 --- a/Robust.Shared/Audio/SoundCollectionPrototype.cs +++ b/Robust.Shared/Audio/SoundCollectionPrototype.cs @@ -3,6 +3,7 @@ using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Utility; using Robust.Shared.ViewVariables; +using Robust.Shared.Localization; namespace Robust.Shared.Audio; @@ -13,6 +14,9 @@ public sealed partial class SoundCollectionPrototype : IPrototype [IdDataField] public string ID { get; private set; } = default!; + [DataField] + public LocId? Caption { get; private set; } + [DataField("files")] public List PickFiles { get; private set; } = new(); } diff --git a/Robust.Shared/Audio/SoundSpecifier.cs b/Robust.Shared/Audio/SoundSpecifier.cs index f88254edc23..3378d34f8ad 100644 --- a/Robust.Shared/Audio/SoundSpecifier.cs +++ b/Robust.Shared/Audio/SoundSpecifier.cs @@ -27,6 +27,9 @@ public sealed partial class SoundPathSpecifier : SoundSpecifier [DataField(Node, customTypeSerializer: typeof(ResPathSerializer), required: true)] public ResPath Path { get; private set; } + override public string ToString() => + $"SoundPathSpecifier({Path})"; + [UsedImplicitly] private SoundPathSpecifier() { @@ -52,6 +55,9 @@ public sealed partial class SoundCollectionSpecifier : SoundSpecifier [DataField(Node, customTypeSerializer: typeof(PrototypeIdSerializer), required: true)] public string? Collection { get; private set; } + override public string ToString() => + $"SoundCollectionSpecifier({Collection})"; + [UsedImplicitly] public SoundCollectionSpecifier() { } diff --git a/Robust.Shared/Audio/Systems/SharedAudioSystem.cs b/Robust.Shared/Audio/Systems/SharedAudioSystem.cs index 4d79ff0e3d0..8498253745e 100644 --- a/Robust.Shared/Audio/Systems/SharedAudioSystem.cs +++ b/Robust.Shared/Audio/Systems/SharedAudioSystem.cs @@ -271,33 +271,60 @@ public float GetAudioDistance(float length) } /// - /// Resolves the filepath to a sound file. + /// Resolve a sound specifier so it can be consistently played back on all clients. /// - public string GetSound(SoundSpecifier specifier) + public ResolvedSoundSpecifier ResolveSound(SoundSpecifier specifier) { switch (specifier) { case SoundPathSpecifier path: - return path.Path == default ? string.Empty : path.Path.ToString(); + return new ResolvedPathSpecifier(path.Path == default ? string.Empty : path.Path.ToString()); case SoundCollectionSpecifier collection: { if (collection.Collection == null) - return string.Empty; + return new ResolvedPathSpecifier(string.Empty); var soundCollection = ProtoMan.Index(collection.Collection); - return RandMan.Pick(soundCollection.PickFiles).ToString(); + var index = RandMan.Next(soundCollection.PickFiles.Count); + return new ResolvedCollectionSpecifier(collection.Collection, index); } } - return string.Empty; + return new ResolvedPathSpecifier(string.Empty); + } + + /// + /// Resolves the filepath to a sound file. + /// + [Obsolete("Use ResolveSound() and pass around resolved sound specifiers instead.")] + public string GetSound(SoundSpecifier specifier) + { + var resolved = ResolveSound(specifier); + return GetAudioPath(resolved); } #region AudioParams - protected Entity SetupAudio(string? fileName, AudioParams? audioParams, bool initialize = true, TimeSpan? length = null) + [return: NotNullIfNotNull(nameof(specifier))] + public string? GetAudioPath(ResolvedSoundSpecifier? specifier) + { + return specifier switch { + ResolvedPathSpecifier path => + path.Path.ToString(), + ResolvedCollectionSpecifier collection => + collection.Collection is null ? + string.Empty : + ProtoMan.Index(collection.Collection).PickFiles[collection.Index].ToString(), + null => null, + _ => throw new ArgumentOutOfRangeException("specifier", specifier, "argument is not a ResolvedPathSpecifier or a ResolvedCollectionSpecifier"), + }; + } + + protected Entity SetupAudio(ResolvedSoundSpecifier? specifier, AudioParams? audioParams, bool initialize = true, TimeSpan? length = null) { var uid = EntityManager.CreateEntityUninitialized("Audio", MapCoordinates.Nullspace); + var fileName = GetAudioPath(specifier); DebugTools.Assert(!string.IsNullOrEmpty(fileName) || length is not null); MetadataSys.SetEntityName(uid, $"Audio ({fileName})", raiseEvents: false); audioParams ??= AudioParams.Default; @@ -305,6 +332,15 @@ protected Entity SetupAudio(string? fileName, AudioParams? audio comp.FileName = fileName ?? string.Empty; comp.Params = audioParams.Value; comp.AudioStart = Timing.CurTime; + if (specifier is ResolvedCollectionSpecifier collection && collection.Collection is string collectionID) + { + var caption = ProtoMan.Index(collectionID).Caption; + if (caption is not null) + { + var capt = AddComp(uid); + capt.Caption = caption; + } + } if (!audioParams.Value.Loop) { @@ -383,8 +419,9 @@ public void SetVolume(EntityUid? entity, float value, AudioComponent? component /// /// Gets the timespan of the specified audio. /// - public TimeSpan GetAudioLength(string filename) + public TimeSpan GetAudioLength(ResolvedSoundSpecifier specifier) { + var filename = GetAudioPath(specifier) ?? string.Empty; if (!filename.StartsWith("/")) throw new ArgumentException("Path must be rooted"); @@ -417,7 +454,7 @@ public TimeSpan GetAudioLength(string filename) /// /// The resource path to the OGG Vorbis file to play. /// The set of players that will hear the sound. - public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayGlobal(string? filename, Filter playerFilter, bool recordReplay, AudioParams? audioParams = null); + public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayGlobal(ResolvedSoundSpecifier? filename, Filter playerFilter, bool recordReplay, AudioParams? audioParams = null); /// /// Play an audio file globally, without position. @@ -426,7 +463,7 @@ public TimeSpan GetAudioLength(string filename) /// The set of players that will hear the sound. public (EntityUid Entity, Components.AudioComponent Component)? PlayGlobal(SoundSpecifier? sound, Filter playerFilter, bool recordReplay, AudioParams? audioParams = null) { - return sound == null ? null : PlayGlobal(GetSound(sound), playerFilter, recordReplay, audioParams ?? sound.Params); + return sound == null ? null : PlayGlobal(ResolveSound(sound), playerFilter, recordReplay, audioParams ?? sound.Params); } /// @@ -434,7 +471,7 @@ public TimeSpan GetAudioLength(string filename) /// /// The resource path to the OGG Vorbis file to play. /// The player that will hear the sound. - public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayGlobal(string? filename, ICommonSession recipient, AudioParams? audioParams = null); + public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayGlobal(ResolvedSoundSpecifier? filename, ICommonSession recipient, AudioParams? audioParams = null); /// /// Play an audio file globally, without position. @@ -443,7 +480,7 @@ public TimeSpan GetAudioLength(string filename) /// The player that will hear the sound. public (EntityUid Entity, Components.AudioComponent Component)? PlayGlobal(SoundSpecifier? sound, ICommonSession recipient, AudioParams? audioParams = null) { - return sound == null ? null : PlayGlobal(GetSound(sound), recipient, audioParams ?? sound.Params); + return sound == null ? null : PlayGlobal(ResolveSound(sound), recipient, audioParams ?? sound.Params); } public abstract void LoadStream(Entity entity, T stream); @@ -453,7 +490,7 @@ public TimeSpan GetAudioLength(string filename) /// /// The resource path to the OGG Vorbis file to play. /// The player that will hear the sound. - public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayGlobal(string? filename, EntityUid recipient, AudioParams? audioParams = null); + public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayGlobal(ResolvedSoundSpecifier? filename, EntityUid recipient, AudioParams? audioParams = null); /// /// Play an audio file globally, without position. @@ -462,7 +499,7 @@ public TimeSpan GetAudioLength(string filename) /// The player that will hear the sound. public (EntityUid Entity, Components.AudioComponent Component)? PlayGlobal(SoundSpecifier? sound, EntityUid recipient, AudioParams? audioParams = null) { - return sound == null ? null : PlayGlobal(GetSound(sound), recipient, audioParams ?? sound.Params); + return sound == null ? null : PlayGlobal(ResolveSound(sound), recipient, audioParams ?? sound.Params); } /// @@ -471,7 +508,7 @@ public TimeSpan GetAudioLength(string filename) /// The resource path to the OGG Vorbis file to play. /// The set of players that will hear the sound. /// The UID of the entity "emitting" the audio. - public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayEntity(string? filename, Filter playerFilter, EntityUid uid, bool recordReplay, AudioParams? audioParams = null); + public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayEntity(ResolvedSoundSpecifier? filename, Filter playerFilter, EntityUid uid, bool recordReplay, AudioParams? audioParams = null); /// /// Play an audio file following an entity. @@ -479,7 +516,7 @@ public TimeSpan GetAudioLength(string filename) /// The resource path to the OGG Vorbis file to play. /// The player that will hear the sound. /// The UID of the entity "emitting" the audio. - public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayEntity(string? filename, ICommonSession recipient, EntityUid uid, AudioParams? audioParams = null); + public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayEntity(ResolvedSoundSpecifier? filename, ICommonSession recipient, EntityUid uid, AudioParams? audioParams = null); /// /// Play an audio file following an entity. @@ -487,7 +524,7 @@ public TimeSpan GetAudioLength(string filename) /// The resource path to the OGG Vorbis file to play. /// The player that will hear the sound. /// The UID of the entity "emitting" the audio. - public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayEntity(string? filename, EntityUid recipient, EntityUid uid, AudioParams? audioParams = null); + public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayEntity(ResolvedSoundSpecifier? filename, EntityUid recipient, EntityUid uid, AudioParams? audioParams = null); /// /// Play an audio file following an entity. @@ -497,7 +534,7 @@ public TimeSpan GetAudioLength(string filename) /// The UID of the entity "emitting" the audio. public (EntityUid Entity, Components.AudioComponent Component)? PlayEntity(SoundSpecifier? sound, Filter playerFilter, EntityUid uid, bool recordReplay, AudioParams? audioParams = null) { - return sound == null ? null : PlayEntity(GetSound(sound), playerFilter, uid, recordReplay, audioParams ?? sound.Params); + return sound == null ? null : PlayEntity(ResolveSound(sound), playerFilter, uid, recordReplay, audioParams ?? sound.Params); } /// @@ -508,7 +545,7 @@ public TimeSpan GetAudioLength(string filename) /// The UID of the entity "emitting" the audio. public (EntityUid Entity, Components.AudioComponent Component)? PlayEntity(SoundSpecifier? sound, ICommonSession recipient, EntityUid uid, AudioParams? audioParams = null) { - return sound == null ? null : PlayEntity(GetSound(sound), recipient, uid, audioParams ?? sound.Params); + return sound == null ? null : PlayEntity(ResolveSound(sound), recipient, uid, audioParams ?? sound.Params); } /// @@ -519,7 +556,7 @@ public TimeSpan GetAudioLength(string filename) /// The UID of the entity "emitting" the audio. public (EntityUid Entity, Components.AudioComponent Component)? PlayEntity(SoundSpecifier? sound, EntityUid recipient, EntityUid uid, AudioParams? audioParams = null) { - return sound == null ? null : PlayEntity(GetSound(sound), recipient, uid, audioParams ?? sound.Params); + return sound == null ? null : PlayEntity(ResolveSound(sound), recipient, uid, audioParams ?? sound.Params); } /// @@ -529,7 +566,7 @@ public TimeSpan GetAudioLength(string filename) /// The UID of the entity "emitting" the audio. public (EntityUid Entity, Components.AudioComponent Component)? PlayPvs(SoundSpecifier? sound, EntityUid uid, AudioParams? audioParams = null) { - return sound == null ? null : PlayPvs(GetSound(sound), uid, audioParams ?? sound.Params); + return sound == null ? null : PlayPvs(ResolveSound(sound), uid, audioParams ?? sound.Params); } /// @@ -539,7 +576,7 @@ public TimeSpan GetAudioLength(string filename) /// The EntityCoordinates to attach the audio source to. public (EntityUid Entity, Components.AudioComponent Component)? PlayPvs(SoundSpecifier? sound, EntityCoordinates coordinates, AudioParams? audioParams = null) { - return sound == null ? null : PlayPvs(GetSound(sound), coordinates, audioParams ?? sound.Params); + return sound == null ? null : PlayPvs(ResolveSound(sound), coordinates, audioParams ?? sound.Params); } /// @@ -547,7 +584,7 @@ public TimeSpan GetAudioLength(string filename) /// /// The sound specifier that points the audio file(s) that should be played. /// The EntityCoordinates to attach the audio source to. - public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayPvs(string? filename, + public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayPvs(ResolvedSoundSpecifier? filename, EntityCoordinates coordinates, AudioParams? audioParams = null); /// @@ -555,7 +592,7 @@ public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayPvs /// /// The resource path to the OGG Vorbis file to play. /// The UID of the entity "emitting" the audio. - public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayPvs(string? filename, EntityUid uid, + public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayPvs(ResolvedSoundSpecifier? filename, EntityUid uid, AudioParams? audioParams = null); /// @@ -592,7 +629,7 @@ public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayPvs /// The resource path to the OGG Vorbis file to play. /// The set of players that will hear the sound. /// The coordinates at which to play the audio. - public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayStatic(string? filename, Filter playerFilter, EntityCoordinates coordinates, bool recordReplay, AudioParams? audioParams = null); + public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayStatic(ResolvedSoundSpecifier? filename, Filter playerFilter, EntityCoordinates coordinates, bool recordReplay, AudioParams? audioParams = null); /// /// Play an audio file at a static position. @@ -600,7 +637,7 @@ public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayPvs /// The resource path to the OGG Vorbis file to play. /// The player that will hear the sound. /// The coordinates at which to play the audio. - public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayStatic(string? filename, ICommonSession recipient, EntityCoordinates coordinates, AudioParams? audioParams = null); + public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayStatic(ResolvedSoundSpecifier? filename, ICommonSession recipient, EntityCoordinates coordinates, AudioParams? audioParams = null); /// /// Play an audio file at a static position. @@ -608,7 +645,7 @@ public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayPvs /// The resource path to the OGG Vorbis file to play. /// The player that will hear the sound. /// The coordinates at which to play the audio. - public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayStatic(string? filename, EntityUid recipient, EntityCoordinates coordinates, AudioParams? audioParams = null); + public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayStatic(ResolvedSoundSpecifier? filename, EntityUid recipient, EntityCoordinates coordinates, AudioParams? audioParams = null); /// /// Play an audio file at a static position. @@ -618,7 +655,7 @@ public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayPvs /// The coordinates at which to play the audio. public (EntityUid Entity, Components.AudioComponent Component)? PlayStatic(SoundSpecifier? sound, Filter playerFilter, EntityCoordinates coordinates, bool recordReplay, AudioParams? audioParams = null) { - return sound == null ? null : PlayStatic(GetSound(sound), playerFilter, coordinates, recordReplay, audioParams); + return sound == null ? null : PlayStatic(ResolveSound(sound), playerFilter, coordinates, recordReplay, audioParams); } /// @@ -629,7 +666,7 @@ public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayPvs /// The coordinates at which to play the audio. public (EntityUid Entity, Components.AudioComponent Component)? PlayStatic(SoundSpecifier? sound, ICommonSession recipient, EntityCoordinates coordinates, AudioParams? audioParams = null) { - return sound == null ? null : PlayStatic(GetSound(sound), recipient, coordinates, audioParams ?? sound.Params); + return sound == null ? null : PlayStatic(ResolveSound(sound), recipient, coordinates, audioParams ?? sound.Params); } /// @@ -640,7 +677,7 @@ public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayPvs /// The coordinates at which to play the audio. public (EntityUid Entity, Components.AudioComponent Component)? PlayStatic(SoundSpecifier? sound, EntityUid recipient, EntityCoordinates coordinates, AudioParams? audioParams = null) { - return sound == null ? null : PlayStatic(GetSound(sound), recipient, coordinates, audioParams ?? sound.Params); + return sound == null ? null : PlayStatic(ResolveSound(sound), recipient, coordinates, audioParams ?? sound.Params); } // These are just here for replays now. @@ -653,7 +690,7 @@ public abstract (EntityUid Entity, Components.AudioComponent Component)? PlayPvs [NetSerializable, Serializable] protected abstract class AudioMessage : EntityEventArgs { - public string FileName = string.Empty; + public ResolvedSoundSpecifier Specifier = new ResolvedPathSpecifier(string.Empty); public AudioParams AudioParams; }