Refactor audio system to send collection IDs over the network (#33610)

This commit is contained in:
pathetic meowmeow
2025-02-23 07:14:56 -05:00
committed by GitHub
parent 1d210b52e0
commit fabfdd0673
21 changed files with 44 additions and 43 deletions

View File

@@ -66,7 +66,7 @@ public sealed class ClientGlobalSoundSystem : SharedGlobalSoundSystem
{ {
if(!_adminAudioEnabled) return; if(!_adminAudioEnabled) return;
var stream = _audio.PlayGlobal(soundEvent.Filename, Filter.Local(), false, soundEvent.AudioParams); var stream = _audio.PlayGlobal(soundEvent.Specifier, Filter.Local(), false, soundEvent.AudioParams);
_adminAudio.Add(stream?.Entity); _adminAudio.Add(stream?.Entity);
} }
@@ -75,13 +75,13 @@ public sealed class ClientGlobalSoundSystem : SharedGlobalSoundSystem
// Either the cvar is disabled or it's already playing // Either the cvar is disabled or it's already playing
if(!_eventAudioEnabled || _eventAudio.ContainsKey(soundEvent.Type)) return; if(!_eventAudioEnabled || _eventAudio.ContainsKey(soundEvent.Type)) return;
var stream = _audio.PlayGlobal(soundEvent.Filename, Filter.Local(), false, soundEvent.AudioParams); var stream = _audio.PlayGlobal(soundEvent.Specifier, Filter.Local(), false, soundEvent.AudioParams);
_eventAudio.Add(soundEvent.Type, stream?.Entity); _eventAudio.Add(soundEvent.Type, stream?.Entity);
} }
private void PlayGameSound(GameGlobalSoundEvent soundEvent) private void PlayGameSound(GameGlobalSoundEvent soundEvent)
{ {
_audio.PlayGlobal(soundEvent.Filename, Filter.Local(), false, soundEvent.AudioParams); _audio.PlayGlobal(soundEvent.Specifier, Filter.Local(), false, soundEvent.AudioParams);
} }
private void StopStationEventMusic(StopStationEventMusic soundEvent) private void StopStationEventMusic(StopStationEventMusic soundEvent)

View File

@@ -218,7 +218,7 @@ public sealed partial class ContentAudioSystem
return; return;
var file = _gameTicker.RestartSound; var file = _gameTicker.RestartSound;
if (string.IsNullOrEmpty(file)) if (ResolvedSoundSpecifier.IsNullOrEmpty(file))
{ {
return; return;
} }

View File

@@ -144,7 +144,7 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
{ {
KeyFrames = KeyFrames =
{ {
new AnimationTrackPlaySound.KeyFrame(_audioSystem.GetSound(unit.FlushSound), 0) new AnimationTrackPlaySound.KeyFrame(_audioSystem.ResolveSound(unit.FlushSound), 0)
} }
}); });
} }

View File

@@ -10,6 +10,7 @@ using Robust.Client.Graphics;
using Robust.Client.State; using Robust.Client.State;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Audio;
namespace Content.Client.GameTicking.Managers namespace Content.Client.GameTicking.Managers
{ {
@@ -26,7 +27,7 @@ namespace Content.Client.GameTicking.Managers
[ViewVariables] public bool AreWeReady { get; private set; } [ViewVariables] public bool AreWeReady { get; private set; }
[ViewVariables] public bool IsGameStarted { get; private set; } [ViewVariables] public bool IsGameStarted { get; private set; }
[ViewVariables] public string? RestartSound { get; private set; } [ViewVariables] public ResolvedSoundSpecifier? RestartSound { get; private set; }
[ViewVariables] public string? LobbyBackground { get; private set; } [ViewVariables] public string? LobbyBackground { get; private set; }
[ViewVariables] public bool DisallowedLateJoin { get; private set; } [ViewVariables] public bool DisallowedLateJoin { get; private set; }
[ViewVariables] public string? ServerInfoBlob { get; private set; } [ViewVariables] public string? ServerInfoBlob { get; private set; }

View File

@@ -122,7 +122,7 @@ public sealed class PoweredLightVisualizerSystem : VisualizerSystem<PoweredLight
if (comp.BlinkingSound != null) if (comp.BlinkingSound != null)
{ {
var sound = _audio.GetSound(comp.BlinkingSound); var sound = _audio.ResolveSound(comp.BlinkingSound);
blinkingAnim.AnimationTracks.Add(new AnimationTrackPlaySound() blinkingAnim.AnimationTracks.Add(new AnimationTrackPlaySound()
{ {
KeyFrames = KeyFrames =

View File

@@ -33,7 +33,7 @@ public sealed class TimerTriggerVisualizerSystem : VisualizerSystem<TimerTrigger
{ {
comp.PrimingAnimation.AnimationTracks.Add( comp.PrimingAnimation.AnimationTracks.Add(
new AnimationTrackPlaySound() { new AnimationTrackPlaySound() {
KeyFrames = { new AnimationTrackPlaySound.KeyFrame(_audioSystem.GetSound(comp.PrimingSound), 0) } KeyFrames = { new AnimationTrackPlaySound.KeyFrame(_audioSystem.ResolveSound(comp.PrimingSound), 0) }
} }
); );
} }

View File

@@ -19,9 +19,9 @@ public sealed class ServerGlobalSoundSystem : SharedGlobalSoundSystem
_conHost.UnregisterCommand("playglobalsound"); _conHost.UnregisterCommand("playglobalsound");
} }
public void PlayAdminGlobal(Filter playerFilter, string filename, AudioParams? audioParams = null, bool replay = true) public void PlayAdminGlobal(Filter playerFilter, ResolvedSoundSpecifier specifier, AudioParams? audioParams = null, bool replay = true)
{ {
var msg = new AdminSoundEvent(filename, audioParams); var msg = new AdminSoundEvent(specifier, audioParams);
RaiseNetworkEvent(msg, playerFilter, recordReplay: replay); RaiseNetworkEvent(msg, playerFilter, recordReplay: replay);
} }
@@ -32,9 +32,9 @@ public sealed class ServerGlobalSoundSystem : SharedGlobalSoundSystem
return stationFilter; return stationFilter;
} }
public void PlayGlobalOnStation(EntityUid source, string filename, AudioParams? audioParams = null) public void PlayGlobalOnStation(EntityUid source, ResolvedSoundSpecifier specifier, AudioParams? audioParams = null)
{ {
var msg = new GameGlobalSoundEvent(filename, audioParams); var msg = new GameGlobalSoundEvent(specifier, audioParams);
var filter = GetStationAndPvs(source); var filter = GetStationAndPvs(source);
RaiseNetworkEvent(msg, filter); RaiseNetworkEvent(msg, filter);
} }
@@ -52,13 +52,13 @@ public sealed class ServerGlobalSoundSystem : SharedGlobalSoundSystem
public void DispatchStationEventMusic(EntityUid source, SoundSpecifier sound, StationEventMusicType type) public void DispatchStationEventMusic(EntityUid source, SoundSpecifier sound, StationEventMusicType type)
{ {
DispatchStationEventMusic(source, _audio.GetSound(sound), type); DispatchStationEventMusic(source, _audio.ResolveSound(sound), type);
} }
public void DispatchStationEventMusic(EntityUid source, string sound, StationEventMusicType type) public void DispatchStationEventMusic(EntityUid source, ResolvedSoundSpecifier specifier, StationEventMusicType type)
{ {
var audio = AudioParams.Default.WithVolume(-8); var audio = AudioParams.Default.WithVolume(-8);
var msg = new StationEventMusicEvent(sound, type, audio); var msg = new StationEventMusicEvent(specifier, type, audio);
var filter = GetStationAndPvs(source); var filter = GetStationAndPvs(source);
RaiseNetworkEvent(msg, filter); RaiseNetworkEvent(msg, filter);

View File

@@ -369,7 +369,7 @@ namespace Content.Server.Cargo.Systems
private void PlayDenySound(EntityUid uid, CargoOrderConsoleComponent component) private void PlayDenySound(EntityUid uid, CargoOrderConsoleComponent component)
{ {
_audio.PlayPvs(_audio.GetSound(component.ErrorSound), uid); _audio.PlayPvs(_audio.ResolveSound(component.ErrorSound), uid);
} }
private static CargoOrderData GetOrderData(CargoConsoleAddOrderMessage args, CargoProductPrototype cargoProduct, int id) private static CargoOrderData GetOrderData(CargoConsoleAddOrderMessage args, CargoProductPrototype cargoProduct, int id)

View File

@@ -92,7 +92,7 @@ public sealed partial class CargoSystem
var currentOrder = comp.CurrentOrders.First(); var currentOrder = comp.CurrentOrders.First();
if (FulfillOrder(currentOrder, xform.Coordinates, comp.PrinterOutput)) if (FulfillOrder(currentOrder, xform.Coordinates, comp.PrinterOutput))
{ {
_audio.PlayPvs(_audio.GetSound(comp.TeleportSound), uid, AudioParams.Default.WithVolume(-8f)); _audio.PlayPvs(_audio.ResolveSound(comp.TeleportSound), uid, AudioParams.Default.WithVolume(-8f));
if (_station.GetOwningStation(uid) is { } station) if (_station.GetOwningStation(uid) is { } station)
UpdateOrders(station); UpdateOrders(station);

View File

@@ -328,7 +328,7 @@ public sealed partial class ChatSystem : SharedChatSystem
_chatManager.ChatMessageToAll(ChatChannel.Radio, message, wrappedMessage, default, false, true, colorOverride); _chatManager.ChatMessageToAll(ChatChannel.Radio, message, wrappedMessage, default, false, true, colorOverride);
if (playSound) if (playSound)
{ {
_audio.PlayGlobal(announcementSound == null ? DefaultAnnouncementSound : _audio.GetSound(announcementSound), Filter.Broadcast(), true, AudioParams.Default.WithVolume(-2f)); _audio.PlayGlobal(announcementSound == null ? DefaultAnnouncementSound : _audio.ResolveSound(announcementSound), Filter.Broadcast(), true, AudioParams.Default.WithVolume(-2f));
} }
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"Global station announcement from {sender}: {message}"); _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Global station announcement from {sender}: {message}");
} }

View File

@@ -585,7 +585,7 @@ namespace Content.Server.GameTicking
// This ordering mechanism isn't great (no ordering of minds) but functions // This ordering mechanism isn't great (no ordering of minds) but functions
var listOfPlayerInfoFinal = listOfPlayerInfo.OrderBy(pi => pi.PlayerOOCName).ToArray(); var listOfPlayerInfoFinal = listOfPlayerInfo.OrderBy(pi => pi.PlayerOOCName).ToArray();
var sound = RoundEndSoundCollection == null ? null : _audio.GetSound(new SoundCollectionSpecifier(RoundEndSoundCollection)); var sound = RoundEndSoundCollection == null ? null : _audio.ResolveSound(new SoundCollectionSpecifier(RoundEndSoundCollection));
var roundEndMessageEvent = new RoundEndMessageEvent( var roundEndMessageEvent = new RoundEndMessageEvent(
gamemodeTitle, gamemodeTitle,

View File

@@ -202,7 +202,7 @@ namespace Content.Server.Light.EntitySystems
if (!_powerCell.TryGetBatteryFromSlot(uid, out var battery) && if (!_powerCell.TryGetBatteryFromSlot(uid, out var battery) &&
!TryComp(uid, out battery)) !TryComp(uid, out battery))
{ {
_audio.PlayPvs(_audio.GetSound(component.TurnOnFailSound), uid); _audio.PlayPvs(_audio.ResolveSound(component.TurnOnFailSound), uid);
_popup.PopupEntity(Loc.GetString("handheld-light-component-cell-missing-message"), uid, user); _popup.PopupEntity(Loc.GetString("handheld-light-component-cell-missing-message"), uid, user);
return false; return false;
} }
@@ -212,7 +212,7 @@ namespace Content.Server.Light.EntitySystems
// Simple enough. // Simple enough.
if (component.Wattage > battery.CurrentCharge) if (component.Wattage > battery.CurrentCharge)
{ {
_audio.PlayPvs(_audio.GetSound(component.TurnOnFailSound), uid); _audio.PlayPvs(_audio.ResolveSound(component.TurnOnFailSound), uid);
_popup.PopupEntity(Loc.GetString("handheld-light-component-cell-dead-message"), uid, user); _popup.PopupEntity(Loc.GetString("handheld-light-component-cell-dead-message"), uid, user);
return false; return false;
} }

View File

@@ -49,7 +49,7 @@ public sealed class NukeSystem : EntitySystem
/// Used to calculate when the nuke song should start playing for maximum kino with the nuke sfx /// Used to calculate when the nuke song should start playing for maximum kino with the nuke sfx
/// </summary> /// </summary>
private float _nukeSongLength; private float _nukeSongLength;
private string _selectedNukeSong = String.Empty; private ResolvedSoundSpecifier _selectedNukeSong = String.Empty;
/// <summary> /// <summary>
/// Time to leave between the nuke song and the nuke alarm playing. /// Time to leave between the nuke song and the nuke alarm playing.
@@ -302,7 +302,7 @@ public sealed class NukeSystem : EntitySystem
// Start playing the nuke event song so that it ends a couple seconds before the alert sound // Start playing the nuke event song so that it ends a couple seconds before the alert sound
// should play // should play
if (nuke.RemainingTime <= _nukeSongLength + nuke.AlertSoundTime + NukeSongBuffer && !nuke.PlayedNukeSong && !string.IsNullOrEmpty(_selectedNukeSong)) if (nuke.RemainingTime <= _nukeSongLength + nuke.AlertSoundTime + NukeSongBuffer && !nuke.PlayedNukeSong && !ResolvedSoundSpecifier.IsNullOrEmpty(_selectedNukeSong))
{ {
_sound.DispatchStationEventMusic(uid, _selectedNukeSong, StationEventMusicType.Nuke); _sound.DispatchStationEventMusic(uid, _selectedNukeSong, StationEventMusicType.Nuke);
nuke.PlayedNukeSong = true; nuke.PlayedNukeSong = true;
@@ -311,7 +311,7 @@ public sealed class NukeSystem : EntitySystem
// play alert sound if time is running out // play alert sound if time is running out
if (nuke.RemainingTime <= nuke.AlertSoundTime && !nuke.PlayedAlertSound) if (nuke.RemainingTime <= nuke.AlertSoundTime && !nuke.PlayedAlertSound)
{ {
_sound.PlayGlobalOnStation(uid, _audio.GetSound(nuke.AlertSound), new AudioParams{Volume = -5f}); _sound.PlayGlobalOnStation(uid, _audio.ResolveSound(nuke.AlertSound), new AudioParams{Volume = -5f});
_sound.StopStationEventMusic(uid, StationEventMusicType.Nuke); _sound.StopStationEventMusic(uid, StationEventMusicType.Nuke);
nuke.PlayedAlertSound = true; nuke.PlayedAlertSound = true;
UpdateAppearance(uid, nuke); UpdateAppearance(uid, nuke);
@@ -469,7 +469,7 @@ public sealed class NukeSystem : EntitySystem
var posText = $"({x}, {y})"; var posText = $"({x}, {y})";
// We are collapsing the randomness here, otherwise we would get separate random song picks for checking duration and when actually playing the song afterwards // We are collapsing the randomness here, otherwise we would get separate random song picks for checking duration and when actually playing the song afterwards
_selectedNukeSong = _audio.GetSound(component.ArmMusic); _selectedNukeSong = _audio.ResolveSound(component.ArmMusic);
// warn a crew // warn a crew
var announcement = Loc.GetString("nuke-component-announcement-armed", var announcement = Loc.GetString("nuke-component-announcement-armed",
@@ -478,7 +478,7 @@ public sealed class NukeSystem : EntitySystem
var sender = Loc.GetString("nuke-component-announcement-sender"); var sender = Loc.GetString("nuke-component-announcement-sender");
_chatSystem.DispatchStationAnnouncement(stationUid ?? uid, announcement, sender, false, null, Color.Red); _chatSystem.DispatchStationAnnouncement(stationUid ?? uid, announcement, sender, false, null, Color.Red);
_sound.PlayGlobalOnStation(uid, _audio.GetSound(component.ArmSound)); _sound.PlayGlobalOnStation(uid, _audio.ResolveSound(component.ArmSound));
_nukeSongLength = (float) _audio.GetAudioLength(_selectedNukeSong).TotalSeconds; _nukeSongLength = (float) _audio.GetAudioLength(_selectedNukeSong).TotalSeconds;
// turn on the spinny light // turn on the spinny light
@@ -519,7 +519,7 @@ public sealed class NukeSystem : EntitySystem
_chatSystem.DispatchStationAnnouncement(uid, announcement, sender, false); _chatSystem.DispatchStationAnnouncement(uid, announcement, sender, false);
component.PlayedNukeSong = false; component.PlayedNukeSong = false;
_sound.PlayGlobalOnStation(uid, _audio.GetSound(component.DisarmSound)); _sound.PlayGlobalOnStation(uid, _audio.ResolveSound(component.DisarmSound));
_sound.StopStationEventMusic(uid, StationEventMusicType.Nuke); _sound.StopStationEventMusic(uid, StationEventMusicType.Nuke);
// reset nuke remaining time to either itself or the minimum time, whichever is higher // reset nuke remaining time to either itself or the minimum time, whichever is higher

View File

@@ -43,7 +43,7 @@ namespace Content.Server.Nutrition.EntitySystems
{ {
// The entity is deleted, so play the sound at its position rather than parenting // The entity is deleted, so play the sound at its position rather than parenting
var coordinates = Transform(uid).Coordinates; var coordinates = Transform(uid).Coordinates;
_audio.PlayPvs(_audio.GetSound(creamPie.Sound), coordinates, AudioParams.Default.WithVariation(0.125f)); _audio.PlayPvs(_audio.ResolveSound(creamPie.Sound), coordinates, AudioParams.Default.WithVariation(0.125f));
if (EntityManager.TryGetComponent(uid, out FoodComponent? foodComp)) if (EntityManager.TryGetComponent(uid, out FoodComponent? foodComp))
{ {

View File

@@ -161,7 +161,7 @@ public sealed class GeigerSystem : SharedGeigerSystem
if (!_player.TryGetSessionByEntity(component.User.Value, out var session)) if (!_player.TryGetSessionByEntity(component.User.Value, out var session))
return; return;
var sound = _audio.GetSound(sounds); var sound = _audio.ResolveSound(sounds);
var param = sounds.Params.WithLoop(true).WithVolume(-4f); var param = sounds.Params.WithLoop(true).WithVolume(-4f);
component.Stream = _audio.PlayGlobal(sound, session, param)?.Entity; component.Stream = _audio.PlayGlobal(sound, session, param)?.Entity;

View File

@@ -56,5 +56,5 @@ public sealed partial class SalvageExpeditionComponent : SharedSalvageExpedition
/// Song selected on MapInit so we can predict the audio countdown properly. /// Song selected on MapInit so we can predict the audio countdown properly.
/// </summary> /// </summary>
[DataField] [DataField]
public SoundPathSpecifier SelectedSong; public ResolvedSoundSpecifier SelectedSong;
} }

View File

@@ -69,8 +69,7 @@ public sealed partial class SalvageSystem
private void OnExpeditionMapInit(EntityUid uid, SalvageExpeditionComponent component, MapInitEvent args) private void OnExpeditionMapInit(EntityUid uid, SalvageExpeditionComponent component, MapInitEvent args)
{ {
var selectedFile = _audio.GetSound(component.Sound); component.SelectedSong = _audio.ResolveSound(component.Sound);
component.SelectedSong = new SoundPathSpecifier(selectedFile, component.Sound.Params);
} }
private void OnExpeditionShutdown(EntityUid uid, SalvageExpeditionComponent component, ComponentShutdown args) private void OnExpeditionShutdown(EntityUid uid, SalvageExpeditionComponent component, ComponentShutdown args)

View File

@@ -144,7 +144,7 @@ public sealed partial class SalvageSystem
while (query.MoveNext(out var uid, out var comp)) while (query.MoveNext(out var uid, out var comp))
{ {
var remaining = comp.EndTime - _timing.CurTime; var remaining = comp.EndTime - _timing.CurTime;
var audioLength = _audio.GetAudioLength(comp.SelectedSong.Path.ToString()); var audioLength = _audio.GetAudioLength(comp.SelectedSong);
if (comp.Stage < ExpeditionStage.FinalCountdown && remaining < TimeSpan.FromSeconds(45)) if (comp.Stage < ExpeditionStage.FinalCountdown && remaining < TimeSpan.FromSeconds(45))
{ {

View File

@@ -14,11 +14,11 @@ public abstract class SharedGlobalSoundSystem : EntitySystem
[Serializable, NetSerializable] [Serializable, NetSerializable]
public class GlobalSoundEvent : EntityEventArgs public class GlobalSoundEvent : EntityEventArgs
{ {
public string Filename; public ResolvedSoundSpecifier Specifier;
public AudioParams? AudioParams; public AudioParams? AudioParams;
public GlobalSoundEvent(string filename, AudioParams? audioParams = null) public GlobalSoundEvent(ResolvedSoundSpecifier specifier, AudioParams? audioParams = null)
{ {
Filename = filename; Specifier = specifier;
AudioParams = audioParams; AudioParams = audioParams;
} }
} }
@@ -29,7 +29,7 @@ public class GlobalSoundEvent : EntityEventArgs
[Serializable, NetSerializable] [Serializable, NetSerializable]
public sealed class AdminSoundEvent : GlobalSoundEvent public sealed class AdminSoundEvent : GlobalSoundEvent
{ {
public AdminSoundEvent(string filename, AudioParams? audioParams = null) : base(filename, audioParams){} public AdminSoundEvent(ResolvedSoundSpecifier specifier, AudioParams? audioParams = null) : base(specifier, audioParams){}
} }
/// <summary> /// <summary>
@@ -38,7 +38,7 @@ public sealed class AdminSoundEvent : GlobalSoundEvent
[Serializable, NetSerializable] [Serializable, NetSerializable]
public sealed class GameGlobalSoundEvent : GlobalSoundEvent public sealed class GameGlobalSoundEvent : GlobalSoundEvent
{ {
public GameGlobalSoundEvent(string filename, AudioParams? audioParams = null) : base(filename, audioParams){} public GameGlobalSoundEvent(ResolvedSoundSpecifier specifier, AudioParams? audioParams = null) : base(specifier, audioParams){}
} }
public enum StationEventMusicType : byte public enum StationEventMusicType : byte
@@ -54,8 +54,8 @@ public sealed class StationEventMusicEvent : GlobalSoundEvent
{ {
public StationEventMusicType Type; public StationEventMusicType Type;
public StationEventMusicEvent(string filename, StationEventMusicType type, AudioParams? audioParams = null) : base( public StationEventMusicEvent(ResolvedSoundSpecifier specifier, StationEventMusicType type, AudioParams? audioParams = null) : base(
filename, audioParams) specifier, audioParams)
{ {
Type = type; Type = type;
} }

View File

@@ -6,6 +6,7 @@ using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Markdown.Mapping; using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Value; using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using Robust.Shared.Audio;
namespace Content.Shared.GameTicking namespace Content.Shared.GameTicking
{ {
@@ -196,7 +197,7 @@ namespace Content.Shared.GameTicking
/// <summary> /// <summary>
/// Sound gets networked due to how entity lifecycle works between client / server and to avoid clipping. /// Sound gets networked due to how entity lifecycle works between client / server and to avoid clipping.
/// </summary> /// </summary>
public string? RestartSound; public ResolvedSoundSpecifier? RestartSound;
public RoundEndMessageEvent( public RoundEndMessageEvent(
string gamemodeTitle, string gamemodeTitle,
@@ -205,7 +206,7 @@ namespace Content.Shared.GameTicking
int roundId, int roundId,
int playerCount, int playerCount,
RoundEndPlayerInfo[] allPlayersEndInfo, RoundEndPlayerInfo[] allPlayersEndInfo,
string? restartSound) ResolvedSoundSpecifier? restartSound)
{ {
GamemodeTitle = gamemodeTitle; GamemodeTitle = gamemodeTitle;
RoundEndText = roundEndText; RoundEndText = roundEndText;

View File

@@ -187,7 +187,7 @@ public abstract class SharedEmitSoundSystem : EntitySystem
if (_netMan.IsServer && sound != null) if (_netMan.IsServer && sound != null)
{ {
_audioSystem.PlayPvs(_audioSystem.GetSound(sound), uid, AudioParams.Default.WithVolume(volume)); _audioSystem.PlayPvs(_audioSystem.ResolveSound(sound), uid, AudioParams.Default.WithVolume(volume));
} }
} }