using Content.Shared.CCVar; using Content.Shared.Station.Systems; using JetBrains.Annotations; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Player; using Robust.Shared.Serialization; namespace Content.Shared.Audio; /// /// Handles playing audio to all players globally unless disabled by cvar. Some events are grid-specific. /// public abstract partial class GlobalSoundSystem : EntitySystem { [Dependency] private StationSystem _station = default!; [Dependency] private SharedAudioSystem _audio = default!; /// /// Plays a non-admin global sound for players on the source entity's station /// and players who can see the source entity. /// /// Entity used to determine the station and PVS. /// Resolved sound to play. /// Optional playback parameters. [PublicAPI] public void PlayGlobalOnStation(EntityUid source, ResolvedSoundSpecifier specifier, AudioParams? audioParams = null) { var msg = new GameGlobalSoundEvent(specifier, audioParams); var filter = GetStationAndPvs(source); RaiseNetworkEvent(msg, filter); } /// /// Requests clients in the source entity's station and PVS to stop station event music. /// /// Entity used to determine the station and PVS. /// Category of station music to stop. [PublicAPI] public void StopStationEventMusic(EntityUid source, StationEventMusicType type) { // TODO REPLAYS // these start & stop events are gonna be a PITA // theres probably some nice way of handling them. Maybe it just needs dedicated replay data (in which case these events should NOT get recorded). var msg = new StopStationEventMusic(type); var filter = GetStationAndPvs(source); RaiseNetworkEvent(msg, filter); } /// /// Resolves and dispatches station event music at the default event-music volume. /// /// Entity used to determine the station and PVS. /// Sound to resolve and play. /// Category used to track the music stream on clients. [PublicAPI] public void DispatchStationEventMusic(EntityUid source, SoundSpecifier sound, StationEventMusicType type) { DispatchStationEventMusic(source, _audio.ResolveSound(sound), type); } /// /// Dispatches resolved station event music at the default event-music volume. /// /// Entity used to determine the station and PVS. /// Resolved sound to play. /// Category used to track the music stream on clients. [PublicAPI] public void DispatchStationEventMusic(EntityUid source, ResolvedSoundSpecifier specifier, StationEventMusicType type) { var audio = AudioParams.Default.AddVolume(-8); var msg = new StationEventMusicEvent(specifier, type, audio); var filter = GetStationAndPvs(source); RaiseNetworkEvent(msg, filter); } /// /// Builds a filter containing players on the source entity's station and players /// who can currently see the source entity. /// private Filter GetStationAndPvs(EntityUid source) { var stationFilter = _station.GetInOwningStation(source); stationFilter.AddPlayersByPvs(source, entityManager: EntityManager); return stationFilter; } } /// /// Base network event carrying a sound and optional playback parameters. /// [Virtual] [Serializable, NetSerializable] public class GlobalSoundEvent(ResolvedSoundSpecifier specifier, AudioParams? audioParams = null) : EntityEventArgs { public ResolvedSoundSpecifier Specifier = specifier; public AudioParams? AudioParams = audioParams; } /// /// Intended for admin music. Can be disabled by the cvar. /// [Serializable, NetSerializable] public sealed class AdminSoundEvent(ResolvedSoundSpecifier specifier, AudioParams? audioParams = null) : GlobalSoundEvent(specifier, audioParams); /// /// Intended for misc sound effects. Can't be disabled by cvar. /// [Serializable, NetSerializable] public sealed class GameGlobalSoundEvent(ResolvedSoundSpecifier specifier, AudioParams? audioParams = null) : GlobalSoundEvent(specifier, audioParams); /// /// Identifies a category of station event music for start/stop matching. /// public enum StationEventMusicType : byte { Nuke } /// /// Intended for music triggered by events on a specific station. Can be disabled by the cvar. /// [Serializable, NetSerializable] public sealed class StationEventMusicEvent( ResolvedSoundSpecifier specifier, StationEventMusicType type, AudioParams? audioParams = null) : GlobalSoundEvent(specifier, audioParams) { public StationEventMusicType Type = type; } /// /// Attempts to stop a playing stream. /// [Serializable, NetSerializable] public sealed class StopStationEventMusic(StationEventMusicType type) : EntityEventArgs { public StationEventMusicType Type = type; }