From 975a9d930e13ff25f6045b185cfb235ece504a02 Mon Sep 17 00:00:00 2001 From: Janet Blackquill Date: Sat, 21 Dec 2024 23:31:20 -0500 Subject: [PATCH] Augment audio system with the ability to have captions --- Robust.Client/Audio/AudioSystem.cs | 12 +++++ .../ComponentTrees/CaptionTreeSystem.cs | 46 +++++++++++++++++++ .../Audio/Components/CaptionComponent.cs | 30 ++++++++++++ .../Audio/Components/CaptionTreeComponent.cs | 14 ++++++ .../Audio/SoundCollectionPrototype.cs | 4 ++ .../Audio/Systems/SharedAudioSystem.cs | 9 ++++ 6 files changed, 115 insertions(+) create mode 100644 Robust.Client/ComponentTrees/CaptionTreeSystem.cs create mode 100644 Robust.Shared/Audio/Components/CaptionComponent.cs create mode 100644 Robust.Shared/Audio/Components/CaptionTreeComponent.cs diff --git a/Robust.Client/Audio/AudioSystem.cs b/Robust.Client/Audio/AudioSystem.cs index 2e49b51a452..2d1d374aed7 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) 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.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/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/Systems/SharedAudioSystem.cs b/Robust.Shared/Audio/Systems/SharedAudioSystem.cs index 5fd14a2a90c..b773b2e9cdf 100644 --- a/Robust.Shared/Audio/Systems/SharedAudioSystem.cs +++ b/Robust.Shared/Audio/Systems/SharedAudioSystem.cs @@ -320,6 +320,15 @@ protected Entity SetupAudio(ResolvedSoundSpecifier? specifier, A 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) {