Files
OldThink/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs
MJSailor a95fe13180 Goida revert (#600)
* Revert "- fix: YAML linter fixes. (#598)"

This reverts commit 012bf3c357.

* Revert "Automatic changelog update"

This reverts commit cf1c3a9af5.

* Revert "[Fix] Base Layer Prototype (#597)"

This reverts commit b000423999.

* Revert "Modules update (#596)"

This reverts commit 00fbdead77.

* Revert "Automatic changelog update"

This reverts commit 0d7a12b2a2.

* Revert "Fixes (#593)"

This reverts commit 943c77031c.

* Revert "minor loadout fixes (#594)"

This reverts commit 143c010a89.

* Revert "Update DryDock.yml (#595)"

This reverts commit 4cd0100ac7.

* Revert "Automatic changelog update"

This reverts commit 08eadc690f.

* Revert "fix: Maximum message size (#591)"

This reverts commit 343f3612eb.

* Revert "Черри пики 7 (#592)"

This reverts commit 3f97bdce2f.

* Revert "Automatic changelog update"

This reverts commit 0678eca250.

* Revert "Рандомфиксы (#590)"

This reverts commit 2b9e5e2437.

* Revert "Нижнее бельё в лодауты (#580)"

This reverts commit e01a47b089.

* Revert "add lathe sounds (#588)"

This reverts commit c80a2985f2.

* Revert "Добавил параметр группы для некоторых реагентов (#585)"

This reverts commit 713b16bb98.

* Revert "add hrp ++++ aspect (#587)"

This reverts commit a6a69cc60f.

* Revert "Новые амбиенты и пару песен (#586)"

This reverts commit 48c86bd846.

* Revert "Сообщения в ПДА 2 (#583)"

This reverts commit cced3cc98b.

* Revert "Automatic changelog update"

This reverts commit abf435b11d.

* Revert "Chem stuff and more (#584)"

This reverts commit 3608960f5c.

* Revert "JobRequiremet refactor (#579)"

This reverts commit 9a9c9598e0.

* Revert "Revert "Reapply "Нижнее бельё в лодауты"""

This reverts commit 44447d573f.

* Revert "Reapply "Нижнее бельё в лодауты""

This reverts commit 0c4d082ad3.

* Revert "Revert "Нижнее бельё в лодауты""

This reverts commit 56473c5492.

* Revert "Нижнее бельё в лодауты"

This reverts commit d1cb0cb364.

* Revert "DryDock and WhiteMoose update (#578)"

This reverts commit 14755808af.

* Revert "Automatic changelog update"

This reverts commit 0133f82722.

* Revert "Fixes (#576)"

This reverts commit b7cc49896c.

* Revert "порт системы регенерации солюшена цинки (#574)"

This reverts commit a22cf3d50b.

* Revert "Воровские перчатки (#573)"

This reverts commit bb7140f3d4.

* Revert "mood resprite (#572)"

This reverts commit 4db96dc569.

* Revert "fix missing letter (#571)"

This reverts commit 94ea756794.

* Revert "Сообщения в ПДА (#564)"

This reverts commit d023d29e54.

* Revert "- fix: No visible aghost."

This reverts commit 27e7f25f7e.

* Revert "- tweak: Nerf cult shield."

This reverts commit 6a384246b8.
2024-08-09 19:09:22 +03:00

266 lines
8.2 KiB
C#

using System.Linq;
using Content.Client.Gameplay;
using Content.Shared.Audio;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
using Content.Shared.Random;
using Robust.Client.GameObjects;
using Robust.Client.Player;
using Robust.Client.ResourceManagement;
using Robust.Client.State;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Components;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.Audio;
public sealed partial class ContentAudioSystem
{
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IStateManager _state = default!;
[Dependency] private readonly RulesSystem _rules = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
private readonly TimeSpan _minAmbienceTime = TimeSpan.FromSeconds(30);
private readonly TimeSpan _maxAmbienceTime = TimeSpan.FromSeconds(60);
private const float AmbientMusicFadeTime = 10f;
private static float _volumeSlider;
// Don't need to worry about this being serializable or pauseable as it doesn't affect the sim.
private TimeSpan _nextAudio;
private EntityUid? _ambientMusicStream;
private AmbientMusicPrototype? _musicProto;
/// <summary>
/// If we find a better ambient music proto can we interrupt this one.
/// </summary>
private bool _interruptable;
/// <summary>
/// Track what ambient sounds we've played. This is so they all get played an even
/// number of times.
/// When we get to the end of the list we'll re-shuffle
/// </summary>
private readonly Dictionary<string, List<ResPath>> _ambientSounds = new();
private ISawmill _sawmill = default!;
private void InitializeAmbientMusic()
{
Subs.CVar(_configManager, CCVars.AmbientMusicVolume, AmbienceCVarChanged, true);
_sawmill = IoCManager.Resolve<ILogManager>().GetSawmill("audio.ambience");
// Reset audio
_nextAudio = TimeSpan.MaxValue;
SetupAmbientSounds();
SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnProtoReload);
_state.OnStateChanged += OnStateChange;
// On round end summary OR lobby cut audio.
SubscribeNetworkEvent<RoundEndMessageEvent>(OnRoundEndMessage);
}
private void AmbienceCVarChanged(float obj)
{
_volumeSlider = SharedAudioSystem.GainToVolume(obj);
if (_ambientMusicStream != null && _musicProto != null)
{
_audio.SetVolume(_ambientMusicStream, _musicProto.Sound.Params.Volume + _volumeSlider);
}
}
private void ShutdownAmbientMusic()
{
_state.OnStateChanged -= OnStateChange;
_ambientMusicStream = _audio.Stop(_ambientMusicStream);
}
private void OnProtoReload(PrototypesReloadedEventArgs obj)
{
if (obj.WasModified<AmbientMusicPrototype>() || obj.WasModified<RulesPrototype>())
SetupAmbientSounds();
}
private void OnStateChange(StateChangedEventArgs obj)
{
if (obj.NewState is not GameplayState)
return;
// If they go to game then reset the ambience timer.
_nextAudio = _timing.CurTime + _random.Next(_minAmbienceTime, _maxAmbienceTime);
}
private void SetupAmbientSounds()
{
_ambientSounds.Clear();
foreach (var ambience in _proto.EnumeratePrototypes<AmbientMusicPrototype>())
{
var tracks = _ambientSounds.GetOrNew(ambience.ID);
RefreshTracks(ambience.Sound, tracks, null);
_random.Shuffle(tracks);
}
}
private void OnRoundEndMessage(RoundEndMessageEvent ev)
{
// If scoreboard shows then just stop the music
_ambientMusicStream = _audio.Stop(_ambientMusicStream);
_nextAudio = TimeSpan.FromMinutes(3);
}
private void RefreshTracks(SoundSpecifier sound, List<ResPath> tracks, ResPath? lastPlayed)
{
DebugTools.Assert(tracks.Count == 0);
switch (sound)
{
case SoundCollectionSpecifier collection:
if (collection.Collection == null)
break;
var slothCud = _proto.Index<SoundCollectionPrototype>(collection.Collection);
tracks.AddRange(slothCud.PickFiles);
break;
case SoundPathSpecifier path:
tracks.Add(path.Path);
break;
}
// Just so the same track doesn't play twice
if (tracks.Count > 1 && tracks[^1] == lastPlayed)
{
(tracks[0], tracks[^1]) = (tracks[^1], tracks[0]);
}
}
private void UpdateAmbientMusic()
{
// Update still runs in lobby so just ignore it.
if (_state.CurrentState is not GameplayState)
{
_ambientMusicStream = Audio.Stop(_ambientMusicStream);
_musicProto = null;
return;
}
bool? isDone = null;
if (TryComp(_ambientMusicStream, out AudioComponent? audioComp))
{
isDone = !audioComp.Playing;
}
if (_interruptable)
{
var player = _player.LocalSession?.AttachedEntity;
if (player == null || _musicProto == null || !_rules.IsTrue(player.Value, _proto.Index<RulesPrototype>(_musicProto.Rules)))
{
FadeOut(_ambientMusicStream, duration: AmbientMusicFadeTime);
_musicProto = null;
_interruptable = false;
isDone = true;
}
}
// Still running existing ambience
if (isDone == false)
return;
// If ambience finished reset the CD (this also means if we have long ambience it won't clip)
if (isDone == true)
{
// Also don't need to worry about rounding here as it doesn't affect the sim
_nextAudio = _timing.CurTime + _random.Next(_minAmbienceTime, _maxAmbienceTime);
}
_ambientMusicStream = null;
if (_nextAudio > _timing.CurTime)
return;
_musicProto = GetAmbience();
if (_musicProto == null)
{
_interruptable = false;
return;
}
_interruptable = _musicProto.Interruptable;
var tracks = _ambientSounds[_musicProto.ID];
var track = tracks[^1];
tracks.RemoveAt(tracks.Count - 1);
var strim = _audio.PlayGlobal(
track.ToString(),
Filter.Local(),
false,
AudioParams.Default.WithVolume(_musicProto.Sound.Params.Volume + _volumeSlider));
_ambientMusicStream = strim.Value.Entity;
if (_musicProto.FadeIn)
{
FadeIn(_ambientMusicStream, strim.Value.Component, AmbientMusicFadeTime);
}
// Refresh the list
if (tracks.Count == 0)
{
RefreshTracks(_musicProto.Sound, tracks, track);
}
}
private AmbientMusicPrototype? GetAmbience()
{
var player = _player.LocalEntity;
if (player == null)
return null;
var ev = new PlayAmbientMusicEvent();
RaiseLocalEvent(ref ev);
if (ev.Cancelled)
return null;
var ambiences = _proto.EnumeratePrototypes<AmbientMusicPrototype>().ToList();
ambiences.Sort((x, y) => y.Priority.CompareTo(x.Priority));
foreach (var amb in ambiences)
{
if (!_rules.IsTrue(player.Value, _proto.Index<RulesPrototype>(amb.Rules)))
continue;
return amb;
}
_sawmill.Warning($"Unable to find fallback ambience track");
return null;
}
/// <summary>
/// Fades out the current ambient music temporarily.
/// </summary>
public void DisableAmbientMusic()
{
FadeOut(_ambientMusicStream);
_ambientMusicStream = null;
}
}