using Content.Shared._Scp.Audio; using Content.Shared._Scp.Audio.Components; using Content.Shared._Scp.ScpCCVars; using Content.Client._Scp.Audio.Components; using Robust.Shared.Audio; using Robust.Shared.Audio.Components; using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; using Robust.Shared.Prototypes; using Robust.Shared.Timing; namespace Content.Client._Scp.Audio; /// /// Система, накладывающая эффект эхо каждому неглобальному звуку. /// Эффект может быть отключен игроком в настройках /// public sealed class EchoEffectSystem : EntitySystem { [Dependency] private readonly AudioEffectsManagerSystem _effectsManager = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; private static readonly ProtoId StandardEchoEffectPreset = "Bathroom"; private static readonly ProtoId StrongEchoEffectPreset = "SewerPipe"; private bool _isClientSideEnabled; private bool _strongPresetPreferred; public override void Initialize() { base.Initialize(); // Форсируем статическую инициализацию CVars ДО всех GetCVar (фикс проблемы с регистрацией) var _ = ScpCCVars.EchoEnabled; SubscribeLocalEvent(OnAudioAdd); SubscribeLocalEvent(OnEffectedAudioStartup, after: [typeof(SharedAudioSystem)]); _isClientSideEnabled = _cfg.GetCVar(ScpCCVars.EchoEnabled); _strongPresetPreferred = _cfg.GetCVar(ScpCCVars.EchoStrongPresetPreferred); _cfg.OnValueChanged(ScpCCVars.EchoEnabled, OnEnabledToggled); _cfg.OnValueChanged(ScpCCVars.EchoStrongPresetPreferred, OnPreferredPresetToggled); } public override void Shutdown() { base.Shutdown(); _cfg.UnsubValueChanged(ScpCCVars.EchoEnabled, OnEnabledToggled); _cfg.UnsubValueChanged(ScpCCVars.EchoStrongPresetPreferred, OnPreferredPresetToggled); } private void OnAudioAdd(Entity ent, ref ComponentAdd args) { if (!_isClientSideEnabled) return; EnsureComp(ent); } private void OnEffectedAudioStartup(Entity ent, ref ComponentStartup args) { if (!_isClientSideEnabled) return; if (!TryComp(ent.Owner, out var audio)) return; TryApplyEcho((ent.Owner, audio)); } /// /// Пытается применить эхо к данном звуку /// /// Звук, к которому будет применен эффект /// Пресет, если нужно выставить какой-то особенный /// Получилось или не получилось применить эффект public bool TryApplyEcho(Entity sound, ProtoId? preset = null) { if (TerminatingOrDeleted(sound) || Paused(sound)) return false; // Фоновая музыка не должна подвергаться эффектам эха if (sound.Comp.Global) return false; // Выбираем пресет для эха исходя из настроек игрока и возможного приоритетного эффекта при вызове извне системы var clientPreferredPreset = _strongPresetPreferred ? StrongEchoEffectPreset : StandardEchoEffectPreset; var targetPreset = preset ?? clientPreferredPreset; _effectsManager.TryAddEffect(sound, targetPreset); // Добавляем компонент-маркер к звуку, который будет хранить эффект эха var echoComp = EnsureComp(sound); echoComp.Preset = targetPreset; return true; } /// /// Пытается убрать эффект эхо у выбранного звука /// public bool TryRemoveEcho(Entity sound, AudioEchoEffectAffectedComponent? echoComp = null) { if (!Resolve(sound, ref echoComp)) return false; if (!_effectsManager.TryRemoveEffect(sound, echoComp.Preset)) return false; return true; } private void OnEnabledToggled(bool enabled) { _isClientSideEnabled = enabled; if (!enabled) RevertChanges(); } private void OnPreferredPresetToggled(bool useStrong) { _strongPresetPreferred = useStrong; var newPreferredPreset = useStrong ? StrongEchoEffectPreset : StandardEchoEffectPreset; TogglePreset(newPreferredPreset); } /// /// Убирает эффекты эхо у всех звуков, что имеют его. /// Вызывается при выключении эффекта эха игроком. /// private void RevertChanges() { var query = AllEntityQuery(); while (query.MoveNext(out var uid, out var echoComp, out var audio)) { TryRemoveEcho((uid, audio), echoComp); } } private void TogglePreset(ProtoId newPreferredPreset) { var query = AllEntityQuery(); while (query.MoveNext(out var uid, out var echoComp, out var audio)) { if (!TryRemoveEcho((uid, audio), echoComp)) continue; TryApplyEcho((uid, audio), newPreferredPreset); } } }