diff --git a/Content.Client/Audio/AmbientSoundSystem.cs b/Content.Client/Audio/AmbientSoundSystem.cs index d241df4f6f..8b5cf4ad06 100644 --- a/Content.Client/Audio/AmbientSoundSystem.cs +++ b/Content.Client/Audio/AmbientSoundSystem.cs @@ -13,304 +13,302 @@ using Robust.Shared.Utility; using System.Linq; using Robust.Client.GameObjects; -namespace Content.Client.Audio +namespace Content.Client.Audio; +//TODO: This is using a incomplete version of the whole "only play nearest sounds" algo, that breaks down a bit should the ambient sound cap get hit. +//TODO: This'll be fixed when GetEntitiesInRange produces consistent outputs. + +/// +/// Samples nearby and plays audio. +/// +public sealed class AmbientSoundSystem : SharedAmbientSoundSystem { - //TODO: This is using a incomplete version of the whole "only play nearest sounds" algo, that breaks down a bit should the ambient sound cap get hit. - //TODO: This'll be fixed when GetEntitiesInRange produces consistent outputs. + [Dependency] private readonly AmbientSoundTreeSystem _treeSys = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly IRobustRandom _random = default!; + + protected override void QueueUpdate(EntityUid uid, AmbientSoundComponent ambience) + => _treeSys.QueueTreeUpdate(uid, ambience); + + private AmbientSoundOverlay? _overlay; + private int _maxAmbientCount; + private bool _overlayEnabled; + private float _maxAmbientRange; + private float _cooldown; + private TimeSpan _targetTime = TimeSpan.Zero; + private float _ambienceVolume = 0.0f; + + private static AudioParams _params = AudioParams.Default.WithVariation(0.01f).WithLoop(true).WithAttenuation(Attenuation.LinearDistance); /// - /// Samples nearby and plays audio. + /// How many times we can be playing 1 particular sound at once. /// - public sealed class AmbientSoundSystem : SharedAmbientSoundSystem + private int MaxSingleSound => (int) (_maxAmbientCount / (16.0f / 6.0f)); + + private readonly Dictionary _playingSounds = new(); + private readonly Dictionary _playingCount = new(); + + public bool OverlayEnabled { - [Dependency] private readonly AmbientSoundTreeSystem _treeSys = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly IConfigurationManager _cfg = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IPlayerManager _playerManager = default!; - [Dependency] private readonly IRobustRandom _random = default!; - - protected override void QueueUpdate(EntityUid uid, AmbientSoundComponent ambience) - => _treeSys.QueueTreeUpdate(uid, ambience); - - private AmbientSoundOverlay? _overlay; - private int _maxAmbientCount; - private bool _overlayEnabled; - private float _maxAmbientRange; - private float _cooldown; - private TimeSpan _targetTime = TimeSpan.Zero; - private float _ambienceVolume = 0.0f; - - private static AudioParams _params = AudioParams.Default.WithVariation(0.01f).WithLoop(true).WithAttenuation(Attenuation.LinearDistance); - - /// - /// How many times we can be playing 1 particular sound at once. - /// - private int MaxSingleSound => (int) (_maxAmbientCount / (16.0f / 6.0f)); - - private readonly Dictionary _playingSounds = new(); - private readonly Dictionary _playingCount = new(); - - public bool OverlayEnabled + get => _overlayEnabled; + set { - get => _overlayEnabled; - set - { - if (_overlayEnabled == value) return; - _overlayEnabled = value; - var overlayManager = IoCManager.Resolve(); + if (_overlayEnabled == value) return; + _overlayEnabled = value; + var overlayManager = IoCManager.Resolve(); - if (_overlayEnabled) - { - _overlay = new AmbientSoundOverlay(EntityManager, this, EntityManager.System()); - overlayManager.AddOverlay(_overlay); - } - else - { - overlayManager.RemoveOverlay(_overlay!); - _overlay = null; - } + if (_overlayEnabled) + { + _overlay = new AmbientSoundOverlay(EntityManager, this, EntityManager.System()); + overlayManager.AddOverlay(_overlay); + } + else + { + overlayManager.RemoveOverlay(_overlay!); + _overlay = null; } } + } - /// - /// Is this AmbientSound actively playing right now? - /// - /// - /// - public bool IsActive(AmbientSoundComponent component) + /// + /// Is this AmbientSound actively playing right now? + /// + /// + /// + public bool IsActive(AmbientSoundComponent component) + { + return _playingSounds.ContainsKey(component); + } + + public override void Initialize() + { + base.Initialize(); + UpdatesOutsidePrediction = true; + UpdatesAfter.Add(typeof(AmbientSoundTreeSystem)); + + _cfg.OnValueChanged(CCVars.AmbientCooldown, SetCooldown, true); + _cfg.OnValueChanged(CCVars.MaxAmbientSources, SetAmbientCount, true); + _cfg.OnValueChanged(CCVars.AmbientRange, SetAmbientRange, true); + _cfg.OnValueChanged(CCVars.AmbienceVolume, SetAmbienceVolume, true); + SubscribeLocalEvent(OnShutdown); + } + + private void OnShutdown(EntityUid uid, AmbientSoundComponent component, ComponentShutdown args) + { + if (!_playingSounds.Remove(component, out var sound)) + return; + + sound.Stream?.Stop(); + _playingCount[sound.Sound] -= 1; + if (_playingCount[sound.Sound] == 0) + _playingCount.Remove(sound.Sound); + } + + private void SetAmbienceVolume(float value) + { + _ambienceVolume = value; + + foreach (var (comp, values) in _playingSounds) { - return _playingSounds.ContainsKey(component); + if (values.Stream == null) + continue; + + var stream = (AudioSystem.PlayingStream) values.Stream; + stream.Volume = _params.Volume + comp.Volume + _ambienceVolume; + } + } + private void SetCooldown(float value) => _cooldown = value; + private void SetAmbientCount(int value) => _maxAmbientCount = value; + private void SetAmbientRange(float value) => _maxAmbientRange = value; + + public override void Shutdown() + { + base.Shutdown(); + ClearSounds(); + + _cfg.UnsubValueChanged(CCVars.AmbientCooldown, SetCooldown); + _cfg.UnsubValueChanged(CCVars.MaxAmbientSources, SetAmbientCount); + _cfg.UnsubValueChanged(CCVars.AmbientRange, SetAmbientRange); + _cfg.UnsubValueChanged(CCVars.AmbienceVolume, SetAmbienceVolume); + } + + private int PlayingCount(string countSound) + { + var count = 0; + + foreach (var (_, (_, sound)) in _playingSounds) + { + if (sound.Equals(countSound)) + count++; } - public override void Initialize() - { - base.Initialize(); - UpdatesOutsidePrediction = true; - UpdatesAfter.Add(typeof(AmbientSoundTreeSystem)); + return count; + } - _cfg.OnValueChanged(CCVars.AmbientCooldown, SetCooldown, true); - _cfg.OnValueChanged(CCVars.MaxAmbientSources, SetAmbientCount, true); - _cfg.OnValueChanged(CCVars.AmbientRange, SetAmbientRange, true); - _cfg.OnValueChanged(CCVars.AmbienceVolume, SetAmbienceVolume, true); - SubscribeLocalEvent(OnShutdown); + public override void Update(float frameTime) + { + base.Update(frameTime); + + if (!_gameTiming.IsFirstTimePredicted) + return; + + if (_cooldown <= 0f) + return; + + if (_gameTiming.CurTime < _targetTime) + return; + + _targetTime = _gameTiming.CurTime+TimeSpan.FromSeconds(_cooldown); + + var player = _playerManager.LocalPlayer?.ControlledEntity; + if (!EntityManager.TryGetComponent(player, out TransformComponent? xform)) + { + ClearSounds(); + return; } - private void OnShutdown(EntityUid uid, AmbientSoundComponent component, ComponentShutdown args) + ProcessNearbyAmbience(xform); + } + + private void ClearSounds() + { + foreach (var (stream, _) in _playingSounds.Values) { - if (!_playingSounds.Remove(component, out var sound)) - return; + stream?.Stop(); + } + + _playingSounds.Clear(); + _playingCount.Clear(); + } + + private readonly struct QueryState + { + public readonly Dictionary> SourceDict = new(); + public readonly Vector2 MapPos; + public readonly TransformComponent Player; + public readonly EntityQuery Query; + + public QueryState(Vector2 mapPos, TransformComponent player, EntityQuery query) + { + MapPos = mapPos; + Player = player; + Query = query; + } + } + + private static bool Callback( + ref QueryState state, + in ComponentTreeEntry value) + { + var (ambientComp, xform) = value; + + DebugTools.Assert(ambientComp.Enabled); + + var delta = xform.ParentUid == state.Player.ParentUid + ? xform.LocalPosition - state.Player.LocalPosition + : xform.WorldPosition - state.MapPos; + + var range = delta.Length; + if (range >= ambientComp.Range) + return true; + + string key; + + if (ambientComp.Sound is SoundPathSpecifier path) + key = path.Path.ToString(); + else + key = ((SoundCollectionSpecifier) ambientComp.Sound).Collection ?? string.Empty; + + // Prioritize far away & loud sounds. + var importance = range * (ambientComp.Volume + 32); + state.SourceDict.GetOrNew(key).Add((importance, ambientComp)); + return true; + } + + /// + /// Get a list of ambient components in range and determine which ones to start playing. + /// + private void ProcessNearbyAmbience(TransformComponent playerXform) + { + var query = GetEntityQuery(); + var metaQuery = GetEntityQuery(); + var mapPos = playerXform.MapPosition; + + // Remove out-of-range ambiences + foreach (var (comp, sound) in _playingSounds) + { + var entity = comp.Owner; + + if (comp.Enabled && + query.TryGetComponent(entity, out var xform) && + xform.MapID == playerXform.MapID && + !metaQuery.GetComponent(entity).EntityPaused) + { + var distance = (xform.ParentUid == playerXform.ParentUid) + ? xform.LocalPosition - playerXform.LocalPosition + : xform.WorldPosition - mapPos.Position; + + if (distance.LengthSquared < comp.Range * comp.Range) + continue; + } sound.Stream?.Stop(); + _playingSounds.Remove(comp); _playingCount[sound.Sound] -= 1; if (_playingCount[sound.Sound] == 0) _playingCount.Remove(sound.Sound); } - private void SetAmbienceVolume(float value) - { - _ambienceVolume = value; + if (_playingSounds.Count >= _maxAmbientCount) + return; - foreach (var (comp, values) in _playingSounds) + var pos = mapPos.Position; + var state = new QueryState(pos, playerXform, query); + var worldAabb = new Box2(pos - _maxAmbientRange, pos + _maxAmbientRange); + _treeSys.QueryAabb(ref state, Callback, mapPos.MapId, worldAabb); + + // Add in range ambiences + foreach (var (key, sources) in state.SourceDict) + { + if (_playingSounds.Count >= _maxAmbientCount) + break; + + if (_playingCount.TryGetValue(key, out var playingCount) && playingCount >= MaxSingleSound) + continue; + + sources.Sort(static (a, b) => b.Importance.CompareTo(a.Importance)); + + foreach (var (_, comp) in sources) { - if (values.Stream == null) + var uid = comp.Owner; + + if (_playingSounds.ContainsKey(comp) || + metaQuery.GetComponent(uid).EntityPaused) continue; - var stream = (AudioSystem.PlayingStream) values.Stream; - stream.Volume = _params.Volume + comp.Volume + _ambienceVolume; - } - } - private void SetCooldown(float value) => _cooldown = value; - private void SetAmbientCount(int value) => _maxAmbientCount = value; - private void SetAmbientRange(float value) => _maxAmbientRange = value; + var audioParams = _params + .AddVolume(comp.Volume + _ambienceVolume) + // Randomise start so 2 sources don't increase their volume. + .WithPlayOffset(_random.NextFloat(0.0f, 100.0f)) + .WithMaxDistance(comp.Range); - public override void Shutdown() - { - base.Shutdown(); - ClearSounds(); + var stream = _audio.PlayPvs(comp.Sound, uid, audioParams); + if (stream == null) + continue; - _cfg.UnsubValueChanged(CCVars.AmbientCooldown, SetCooldown); - _cfg.UnsubValueChanged(CCVars.MaxAmbientSources, SetAmbientCount); - _cfg.UnsubValueChanged(CCVars.AmbientRange, SetAmbientRange); - _cfg.UnsubValueChanged(CCVars.AmbienceVolume, SetAmbienceVolume); - } + _playingSounds[comp] = (stream, key); + playingCount++; - private int PlayingCount(string countSound) - { - var count = 0; - - foreach (var (_, (_, sound)) in _playingSounds) - { - if (sound.Equals(countSound)) - count++; - } - - return count; - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - if (!_gameTiming.IsFirstTimePredicted) - return; - - if (_cooldown <= 0f) - return; - - if (_gameTiming.CurTime < _targetTime) - return; - - _targetTime = _gameTiming.CurTime+TimeSpan.FromSeconds(_cooldown); - - var player = _playerManager.LocalPlayer?.ControlledEntity; - if (!EntityManager.TryGetComponent(player, out TransformComponent? xform)) - { - ClearSounds(); - return; - } - - ProcessNearbyAmbience(xform); - } - - private void ClearSounds() - { - foreach (var (stream, _) in _playingSounds.Values) - { - stream?.Stop(); - } - - _playingSounds.Clear(); - _playingCount.Clear(); - } - - private readonly struct QueryState - { - public readonly Dictionary> SourceDict = new(); - public readonly Vector2 MapPos; - public readonly TransformComponent Player; - public readonly EntityQuery Query; - - public QueryState(Vector2 mapPos, TransformComponent player, EntityQuery query) - { - MapPos = mapPos; - Player = player; - Query = query; - } - } - - private static bool Callback( - ref QueryState state, - in ComponentTreeEntry value) - { - var (ambientComp, xform) = value; - - DebugTools.Assert(ambientComp.Enabled); - - var delta = xform.ParentUid == state.Player.ParentUid - ? xform.LocalPosition - state.Player.LocalPosition - : xform.WorldPosition - state.MapPos; - - var range = delta.Length; - if (range >= ambientComp.Range) - return true; - - string key; - - if (ambientComp.Sound is SoundPathSpecifier path) - key = path.Path.ToString(); - else - key = ((SoundCollectionSpecifier) ambientComp.Sound).Collection ?? string.Empty; - - // Prioritize far away & loud sounds. - var importance = range * (ambientComp.Volume + 32); - state.SourceDict.GetOrNew(key).Add((importance, ambientComp)); - return true; - } - - /// - /// Get a list of ambient components in range and determine which ones to start playing. - /// - private void ProcessNearbyAmbience(TransformComponent playerXform) - { - var query = GetEntityQuery(); - var metaQuery = GetEntityQuery(); - var mapPos = playerXform.MapPosition; - - // Remove out-of-range ambiences - foreach (var (comp, sound) in _playingSounds) - { - var entity = comp.Owner; - - if (comp.Enabled && - query.TryGetComponent(entity, out var xform) && - xform.MapID == playerXform.MapID && - !metaQuery.GetComponent(entity).EntityPaused) - { - var distance = (xform.ParentUid == playerXform.ParentUid) - ? xform.LocalPosition - playerXform.LocalPosition - : xform.WorldPosition - mapPos.Position; - - if (distance.LengthSquared < comp.Range * comp.Range) - continue; - } - - sound.Stream?.Stop(); - _playingSounds.Remove(comp); - _playingCount[sound.Sound] -= 1; - if (_playingCount[sound.Sound] == 0) - _playingCount.Remove(sound.Sound); - } - - if (_playingSounds.Count >= _maxAmbientCount) - return; - - var pos = mapPos.Position; - var state = new QueryState(pos, playerXform, query); - var worldAabb = new Box2(pos - _maxAmbientRange, pos + _maxAmbientRange); - _treeSys.QueryAabb(ref state, Callback, mapPos.MapId, worldAabb); - - // Add in range ambiences - foreach (var (key, sources) in state.SourceDict) - { if (_playingSounds.Count >= _maxAmbientCount) break; - - if (_playingCount.TryGetValue(key, out var playingCount) && playingCount >= MaxSingleSound) - continue; - - sources.Sort(static (a, b) => b.Importance.CompareTo(a.Importance)); - - foreach (var (_, comp) in sources) - { - var uid = comp.Owner; - - if (_playingSounds.ContainsKey(comp) || - metaQuery.GetComponent(uid).EntityPaused) - continue; - - var audioParams = _params - .AddVolume(comp.Volume + _ambienceVolume) - // Randomise start so 2 sources don't increase their volume. - .WithPlayOffset(_random.NextFloat(0.0f, 100.0f)) - .WithMaxDistance(comp.Range); - - var stream = _audio.PlayPvs(comp.Sound, uid, audioParams); - if (stream == null) - continue; - - _playingSounds[comp] = (stream, key); - playingCount++; - - if (_playingSounds.Count >= _maxAmbientCount) - break; - } - - if (playingCount != 0) - _playingCount[key] = playingCount; } - DebugTools.Assert(_playingCount.All(x => x.Value == PlayingCount(x.Key))); + if (playingCount != 0) + _playingCount[key] = playingCount; } + + DebugTools.Assert(_playingCount.All(x => x.Value == PlayingCount(x.Key))); } } diff --git a/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs b/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs index 34bc83bdfb..15fc53222e 100644 --- a/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs +++ b/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs @@ -245,6 +245,12 @@ public sealed partial class ContentAudioSystem if (player == null) return null; + var ev = new PlayAmbientMusicEvent(); + RaiseLocalEvent(ref ev); + + if (ev.Cancelled) + return null; + var ambiences = _proto.EnumeratePrototypes().ToList(); ambiences.Sort((x, y) => y.Priority.CompareTo(x.Priority)); @@ -259,4 +265,13 @@ public sealed partial class ContentAudioSystem _sawmill.Warning($"Unable to find fallback ambience track"); return null; } + + /// + /// Fades out the current ambient music temporarily. + /// + public void DisableAmbientMusic() + { + FadeOut(_ambientMusicStream); + _ambientMusicStream = null; + } } diff --git a/Content.Client/Audio/ContentAudioSystem.cs b/Content.Client/Audio/ContentAudioSystem.cs index cd6a88f01d..696a5eb32d 100644 --- a/Content.Client/Audio/ContentAudioSystem.cs +++ b/Content.Client/Audio/ContentAudioSystem.cs @@ -122,3 +122,9 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem #endregion } + +/// +/// Raised whenever ambient music tries to play. +/// +[ByRefEvent] +public record struct PlayAmbientMusicEvent(bool Cancelled = false); diff --git a/Content.Client/Salvage/SalvageExpeditionComponent.cs b/Content.Client/Salvage/SalvageExpeditionComponent.cs new file mode 100644 index 0000000000..0c3bdd15a6 --- /dev/null +++ b/Content.Client/Salvage/SalvageExpeditionComponent.cs @@ -0,0 +1,9 @@ +using Content.Shared.Salvage.Expeditions; + +namespace Content.Client.Salvage; + +[RegisterComponent] +public sealed class SalvageExpeditionComponent : SharedSalvageExpeditionComponent +{ + +} diff --git a/Content.Client/Salvage/SalvageSystem.cs b/Content.Client/Salvage/SalvageSystem.cs index 97737bc3e3..0a73c727a4 100644 --- a/Content.Client/Salvage/SalvageSystem.cs +++ b/Content.Client/Salvage/SalvageSystem.cs @@ -1,8 +1,50 @@ +using Content.Client.Audio; using Content.Shared.Salvage; +using Content.Shared.Salvage.Expeditions; +using Robust.Client.Player; +using Robust.Shared.GameStates; namespace Content.Client.Salvage; public sealed class SalvageSystem : SharedSalvageSystem { + [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly ContentAudioSystem _audio = default!; + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnPlayAmbientMusic); + SubscribeLocalEvent(OnExpeditionHandleState); + } + + private void OnExpeditionHandleState(EntityUid uid, SalvageExpeditionComponent component, ref ComponentHandleState args) + { + if (args.Current is not SalvageExpeditionComponentState state) + return; + + component.Stage = state.Stage; + + if (component.Stage >= ExpeditionStage.MusicCountdown) + { + _audio.DisableAmbientMusic(); + } + } + + private void OnPlayAmbientMusic(ref PlayAmbientMusicEvent ev) + { + if (ev.Cancelled) + return; + + var player = _playerManager.LocalPlayer?.ControlledEntity; + + if (!TryComp(player, out var xform) || + !TryComp(xform.MapUid, out var expedition) || + expedition.Stage < ExpeditionStage.MusicCountdown) + { + return; + } + + ev.Cancelled = true; + } } diff --git a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs index ccc9fc36d0..6f5ee423e6 100644 --- a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs +++ b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs @@ -1,4 +1,5 @@ using Content.Shared.Salvage; +using Content.Shared.Salvage.Expeditions; using JetBrains.Annotations; using Robust.Client.GameObjects; diff --git a/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs b/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs index fcc8f7af0d..c27f2ad317 100644 --- a/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs +++ b/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs @@ -5,6 +5,7 @@ using Content.Client.UserInterface.Controls; using Content.Shared.CCVar; using Content.Shared.Parallax.Biomes; using Content.Shared.Salvage; +using Content.Shared.Salvage.Expeditions; using Content.Shared.Salvage.Expeditions.Modifiers; using Content.Shared.Shuttles.BUIStates; using Robust.Client.AutoGenerated; diff --git a/Content.Server/Audio/AmbientSoundSystem.cs b/Content.Server/Audio/AmbientSoundSystem.cs index 2adf94f891..53a03be2aa 100644 --- a/Content.Server/Audio/AmbientSoundSystem.cs +++ b/Content.Server/Audio/AmbientSoundSystem.cs @@ -2,25 +2,24 @@ using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Shared.Audio; -namespace Content.Server.Audio +namespace Content.Server.Audio; + +public sealed class AmbientSoundSystem : SharedAmbientSoundSystem { - public sealed class AmbientSoundSystem : SharedAmbientSoundSystem + public override void Initialize() { - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(HandlePowerChange); - SubscribeLocalEvent(HandlePowerSupply); - } + base.Initialize(); + SubscribeLocalEvent(HandlePowerChange); + SubscribeLocalEvent(HandlePowerSupply); + } - private void HandlePowerSupply(EntityUid uid, AmbientOnPoweredComponent component, ref PowerNetBatterySupplyEvent args) - { - SetAmbience(uid, args.Supply); - } + private void HandlePowerSupply(EntityUid uid, AmbientOnPoweredComponent component, ref PowerNetBatterySupplyEvent args) + { + SetAmbience(uid, args.Supply); + } - private void HandlePowerChange(EntityUid uid, AmbientOnPoweredComponent component, ref PowerChangedEvent args) - { - SetAmbience(uid, args.Powered); - } + private void HandlePowerChange(EntityUid uid, AmbientOnPoweredComponent component, ref PowerChangedEvent args) + { + SetAmbience(uid, args.Powered); } } diff --git a/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs b/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs index 1fcc4c3003..ce53041456 100644 --- a/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs +++ b/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs @@ -1,9 +1,8 @@ -using Content.Shared.Random; using Content.Shared.Salvage; +using Content.Shared.Salvage.Expeditions; using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Server.Salvage.Expeditions; @@ -12,7 +11,7 @@ namespace Content.Server.Salvage.Expeditions; /// Designates this entity as holding a salvage expedition. /// [RegisterComponent] -public sealed class SalvageExpeditionComponent : Component +public sealed class SalvageExpeditionComponent : SharedSalvageExpeditionComponent { public SalvageMissionParams MissionParams = default!; @@ -36,9 +35,6 @@ public sealed class SalvageExpeditionComponent : Component [ViewVariables] public bool Completed = false; - [ViewVariables(VVAccess.ReadWrite), DataField("stage")] - public ExpeditionStage Stage = ExpeditionStage.Added; - /// /// Countdown audio stream. /// @@ -50,7 +46,7 @@ public sealed class SalvageExpeditionComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField("sound")] public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Misc/tension_session.ogg") { - Params = AudioParams.Default.WithVolume(-15), + Params = AudioParams.Default.WithVolume(-5), }; /// @@ -65,12 +61,3 @@ public sealed class SalvageExpeditionComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField("rewards", customTypeSerializer: typeof(PrototypeIdListSerializer))] public List Rewards = default!; } - -public enum ExpeditionStage : byte -{ - Added, - Running, - Countdown, - MusicCountdown, - FinalCountdown, -} diff --git a/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs b/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs index 3239bc77e5..324bdf9e01 100644 --- a/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs +++ b/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs @@ -1,4 +1,5 @@ using Content.Shared.Salvage; +using Content.Shared.Salvage.Expeditions; using Robust.Server.GameObjects; namespace Content.Server.Salvage; diff --git a/Content.Server/Salvage/SalvageSystem.Expeditions.cs b/Content.Server/Salvage/SalvageSystem.Expeditions.cs index 12a1032cac..24b2b22196 100644 --- a/Content.Server/Salvage/SalvageSystem.Expeditions.cs +++ b/Content.Server/Salvage/SalvageSystem.Expeditions.cs @@ -2,16 +2,15 @@ using Content.Server.Cargo.Components; using Content.Server.Cargo.Systems; using Content.Server.Salvage.Expeditions; using Content.Server.Salvage.Expeditions.Structure; -using Content.Server.Station.Systems; using Content.Shared.CCVar; -using Content.Shared.Random; -using Content.Shared.Random.Helpers; using Content.Shared.Examine; using Content.Shared.Salvage; using Robust.Shared.CPUJob.JobQueues; using Robust.Shared.CPUJob.JobQueues.Queues; using System.Linq; using System.Threading; +using Content.Shared.Salvage.Expeditions; +using Robust.Shared.GameStates; namespace Content.Server.Salvage; @@ -42,6 +41,7 @@ public sealed partial class SalvageSystem SubscribeLocalEvent(OnExpeditionShutdown); SubscribeLocalEvent(OnExpeditionUnpaused); + SubscribeLocalEvent(OnExpeditionGetState); SubscribeLocalEvent(OnStructureExamine); @@ -51,6 +51,14 @@ public sealed partial class SalvageSystem _configurationManager.OnValueChanged(CCVars.SalvageExpeditionFailedCooldown, SetFailedCooldownChange); } + private void OnExpeditionGetState(EntityUid uid, SalvageExpeditionComponent component, ref ComponentGetState args) + { + args.State = new SalvageExpeditionComponentState() + { + Stage = component.Stage + }; + } + private void ShutdownExpeditions() { _configurationManager.UnsubValueChanged(CCVars.SalvageExpeditionCooldown, SetCooldownChange); diff --git a/Content.Server/Salvage/SalvageSystem.Runner.cs b/Content.Server/Salvage/SalvageSystem.Runner.cs index a52649ada0..208f3deca0 100644 --- a/Content.Server/Salvage/SalvageSystem.Runner.cs +++ b/Content.Server/Salvage/SalvageSystem.Runner.cs @@ -8,9 +8,7 @@ using Content.Shared.Chat; using Content.Shared.Humanoid; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; -using Content.Shared.Salvage; -using Content.Shared.Shuttles.Components; -using Robust.Shared.Audio; +using Content.Shared.Salvage.Expeditions; using Robust.Shared.Map.Components; using Robust.Shared.Player; using Robust.Shared.Utility; @@ -110,6 +108,7 @@ public sealed partial class SalvageSystem Announce(args.MapUid, Loc.GetString("salvage-expedition-announcement-dungeon", ("direction", component.DungeonLocation.GetDir()))); component.Stage = ExpeditionStage.Running; + Dirty(component); } private void OnFTLStarted(ref FTLStartedEvent ev) @@ -158,6 +157,7 @@ public sealed partial class SalvageSystem if (comp.Stage < ExpeditionStage.FinalCountdown && remaining < TimeSpan.FromSeconds(30)) { comp.Stage = ExpeditionStage.FinalCountdown; + Dirty(comp); Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-seconds", ("duration", TimeSpan.FromSeconds(30).Seconds))); } else if (comp.Stage < ExpeditionStage.MusicCountdown && remaining < TimeSpan.FromMinutes(2)) @@ -165,11 +165,13 @@ public sealed partial class SalvageSystem // TODO: Some way to play audio attached to a map for players. comp.Stream = _audio.PlayGlobal(comp.Sound, Filter.BroadcastMap(Comp(uid).MapId), true); comp.Stage = ExpeditionStage.MusicCountdown; + Dirty(comp); Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", TimeSpan.FromMinutes(2).Minutes))); } else if (comp.Stage < ExpeditionStage.Countdown && remaining < TimeSpan.FromMinutes(5)) { comp.Stage = ExpeditionStage.Countdown; + Dirty(comp); Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", TimeSpan.FromMinutes(5).Minutes))); } // Auto-FTL out any shuttles diff --git a/Content.Shared/Audio/SharedAmbientSoundSystem.cs b/Content.Shared/Audio/SharedAmbientSoundSystem.cs index c54e9589b2..3bda37c634 100644 --- a/Content.Shared/Audio/SharedAmbientSoundSystem.cs +++ b/Content.Shared/Audio/SharedAmbientSoundSystem.cs @@ -1,66 +1,65 @@ using Robust.Shared.GameStates; -namespace Content.Shared.Audio +namespace Content.Shared.Audio; + +public abstract class SharedAmbientSoundSystem : EntitySystem { - public abstract class SharedAmbientSoundSystem : EntitySystem + public override void Initialize() { - public override void Initialize() + base.Initialize(); + SubscribeLocalEvent(GetCompState); + SubscribeLocalEvent(HandleCompState); + } + + public virtual void SetAmbience(EntityUid uid, bool value, AmbientSoundComponent? ambience = null) + { + if (!Resolve(uid, ref ambience, false) || ambience.Enabled == value) + return; + + ambience.Enabled = value; + QueueUpdate(uid, ambience); + Dirty(ambience); + } + + public virtual void SetRange(EntityUid uid, float value, AmbientSoundComponent? ambience = null) + { + if (!Resolve(uid, ref ambience, false) || MathHelper.CloseToPercent(ambience.Range, value)) + return; + + ambience.Range = value; + QueueUpdate(uid, ambience); + Dirty(ambience); + } + + protected virtual void QueueUpdate(EntityUid uid, AmbientSoundComponent ambience) + { + // client side tree + } + + public virtual void SetVolume(EntityUid uid, float value, AmbientSoundComponent? ambience = null) + { + if (!Resolve(uid, ref ambience, false) || MathHelper.CloseToPercent(ambience.Volume, value)) + return; + + ambience.Volume = value; + Dirty(ambience); + } + + private void HandleCompState(EntityUid uid, AmbientSoundComponent component, ref ComponentHandleState args) + { + if (args.Current is not AmbientSoundComponentState state) return; + SetAmbience(uid, state.Enabled, component); + SetRange(uid, state.Range, component); + SetVolume(uid, state.Volume, component); + } + + private void GetCompState(EntityUid uid, AmbientSoundComponent component, ref ComponentGetState args) + { + args.State = new AmbientSoundComponentState { - base.Initialize(); - SubscribeLocalEvent(GetCompState); - SubscribeLocalEvent(HandleCompState); - } - - public virtual void SetAmbience(EntityUid uid, bool value, AmbientSoundComponent? ambience = null) - { - if (!Resolve(uid, ref ambience, false) || ambience.Enabled == value) - return; - - ambience.Enabled = value; - QueueUpdate(uid, ambience); - Dirty(ambience); - } - - public virtual void SetRange(EntityUid uid, float value, AmbientSoundComponent? ambience = null) - { - if (!Resolve(uid, ref ambience, false) || MathHelper.CloseToPercent(ambience.Range, value)) - return; - - ambience.Range = value; - QueueUpdate(uid, ambience); - Dirty(ambience); - } - - protected virtual void QueueUpdate(EntityUid uid, AmbientSoundComponent ambience) - { - // client side tree - } - - public virtual void SetVolume(EntityUid uid, float value, AmbientSoundComponent? ambience = null) - { - if (!Resolve(uid, ref ambience, false) || MathHelper.CloseToPercent(ambience.Volume, value)) - return; - - ambience.Volume = value; - Dirty(ambience); - } - - private void HandleCompState(EntityUid uid, AmbientSoundComponent component, ref ComponentHandleState args) - { - if (args.Current is not AmbientSoundComponentState state) return; - SetAmbience(uid, state.Enabled, component); - SetRange(uid, state.Range, component); - SetVolume(uid, state.Volume, component); - } - - private void GetCompState(EntityUid uid, AmbientSoundComponent component, ref ComponentGetState args) - { - args.State = new AmbientSoundComponentState - { - Enabled = component.Enabled, - Range = component.Range, - Volume = component.Volume, - }; - } + Enabled = component.Enabled, + Range = component.Range, + Volume = component.Volume, + }; } } diff --git a/Content.Shared/Salvage/Expeditions/ExpeditionStage.cs b/Content.Shared/Salvage/Expeditions/ExpeditionStage.cs new file mode 100644 index 0000000000..a92d6c292a --- /dev/null +++ b/Content.Shared/Salvage/Expeditions/ExpeditionStage.cs @@ -0,0 +1,10 @@ +namespace Content.Shared.Salvage.Expeditions; + +public enum ExpeditionStage : byte +{ + Added, + Running, + Countdown, + MusicCountdown, + FinalCountdown, +} \ No newline at end of file diff --git a/Content.Shared/Salvage/SalvageExpeditions.cs b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs similarity index 98% rename from Content.Shared/Salvage/SalvageExpeditions.cs rename to Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs index bac0819d57..85894d86fb 100644 --- a/Content.Shared/Salvage/SalvageExpeditions.cs +++ b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs @@ -1,10 +1,9 @@ -using Content.Shared.Salvage.Expeditions; using Content.Shared.Salvage.Expeditions.Modifiers; using Robust.Shared.GameStates; using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -namespace Content.Shared.Salvage; +namespace Content.Shared.Salvage.Expeditions; [Serializable, NetSerializable] public sealed class SalvageExpeditionConsoleState : BoundUserInterfaceState diff --git a/Content.Shared/Salvage/Expeditions/SharedSalvageExpeditionComponent.cs b/Content.Shared/Salvage/Expeditions/SharedSalvageExpeditionComponent.cs new file mode 100644 index 0000000000..5fa7fe05e9 --- /dev/null +++ b/Content.Shared/Salvage/Expeditions/SharedSalvageExpeditionComponent.cs @@ -0,0 +1,17 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Salvage.Expeditions; + +[NetworkedComponent] +public abstract class SharedSalvageExpeditionComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite), DataField("stage")] + public ExpeditionStage Stage = ExpeditionStage.Added; +} + +[Serializable, NetSerializable] +public sealed class SalvageExpeditionComponentState : ComponentState +{ + public ExpeditionStage Stage; +}