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