using System; using System.Collections.Generic; using System.Numerics; using Robust.Shared.Audio.Effects; using Robust.Shared.Audio.Sources; using Robust.Shared.Audio.Systems; using Robust.Shared.GameObjects; using Robust.Shared.GameStates; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.ViewVariables; namespace Robust.Shared.Audio.Components; /// /// Stores the audio data for an audio entity. /// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedAudioSystem))] public sealed partial class AudioComponent : Component, IAudioSource { #region Filter public override bool SessionSpecific => true; /// /// Used for synchronising audio on client that comes into PVS range. /// [DataField(customTypeSerializer:typeof(TimeOffsetSerializer)), AutoNetworkedField] public TimeSpan AudioStart; #region Filters // Don't need to network these as client doesn't care. /// /// If this sound was predicted do we exclude it from a specific entity. /// Useful for predicted audio. /// [DataField] public EntityUid? ExcludedEntity; /// /// If the sound was filtered what entities were included. /// [DataField] public HashSet? IncludedEntities; #endregion #endregion // We can't just start playing on audio creation as we don't have the correct position yet. // As such we'll wait for FrameUpdate before we start playing to avoid the position being cooked. public bool Started = false; [AutoNetworkedField] [DataField(required: true)] public string FileName = string.Empty; /// /// Audio params. Set this if you want to adjust default volume, max distance, etc. /// [AutoNetworkedField] [DataField] public AudioParams Params = AudioParams.Default; /// /// Audio source that interacts with OpenAL. /// [ViewVariables(VVAccess.ReadOnly)] internal IAudioSource Source = default!; /// /// Auxiliary entity to pass audio to. /// [DataField, AutoNetworkedField] public EntityUid? Auxiliary; /* * Values for IAudioSource stored on the component and sent to IAudioSource as applicable. * Most of these aren't networked as they double AudioParams data and these just interact with IAudioSource. */ #region Source public void Pause() => Source.Pause(); /// public void StartPlaying() => Source.StartPlaying(); /// public void StopPlaying() => Source.StopPlaying(); /// /// /// [ViewVariables] public bool Playing { get => Source.Playing; set => Source.Playing = value; } /// /// /// [ViewVariables] public bool Looping { get => Source.Looping; set => Source.Looping = value; } /// /// /// [AutoNetworkedField] public bool Global { get; set; } /// /// /// public float Pitch { get => Source.Pitch; set => Source.Pitch = value; } /// /// /// public float MaxDistance { get => Source.MaxDistance; set => Source.MaxDistance = value; } /// /// /// public float RolloffFactor { get => Source.RolloffFactor; set => Source.RolloffFactor = value; } /// /// /// public float ReferenceDistance { get => Source.ReferenceDistance; set => Source.ReferenceDistance = value; } /// /// /// /// /// Not replicated as audio always tracks the entity's position. /// [ViewVariables] public Vector2 Position { get => Source.Position; set => Source.Position = value; } /// /// /// [ViewVariables] [Access(Other = AccessPermissions.ReadWriteExecute)] public float Volume { get => Source.Volume; set => Source.Volume = value; } /// /// /// [ViewVariables] [Access(Other = AccessPermissions.ReadWriteExecute)] public float Gain { get => Source.Gain; set => Source.Gain = value; } /// /// /// [ViewVariables] [Access(Other = AccessPermissions.ReadWriteExecute)] public float Occlusion { get => Source.Occlusion; set => Source.Occlusion = value; } /// /// /// [ViewVariables] public float PlaybackPosition { get => Source.PlaybackPosition; set => Source.PlaybackPosition = value; } /// /// /// /// /// Not replicated. /// [ViewVariables] public Vector2 Velocity { get => Source.Velocity; set => Source.Velocity = value; } void IAudioSource.SetAuxiliary(IAuxiliaryAudio? audio) { Source.SetAuxiliary(audio); } #endregion public void Dispose() { Source.Dispose(); } }