using Robust.Shared.Prototypes; using Robust.Shared.Random; using Content.Shared._Horizon.Bark; using Content.Shared.Chat; using Robust.Client.Audio; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; using System.Threading.Tasks; using Content.Client.Chat; using Content.Shared._Horizon.CCVar; using Robust.Client.ResourceManagement; using Robust.Shared.Utility; using Robust.Client.Player; namespace Content.Client._Horizon.Bark; public sealed class SpeechBarksSystem : SharedSpeechBarksSystem { [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly AudioSystem _audio = default!; [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly IPlayerManager _player = default!; public override void Initialize() { base.Initialize(); _cfg.OnValueChanged(HorizonCCVars.BarksVolume, OnVolumeChanged, true); SubscribeNetworkEvent(OnEntitySpoke); } public override void Shutdown() { base.Shutdown(); _cfg.UnsubValueChanged(HorizonCCVars.BarksVolume, OnVolumeChanged); } private readonly List _sampleText = new() { "Тестик сообщениЯ 1.", "Тестик сообщениЯ 2!", "Тестик сообщениЯ 3?", "Здесь была лемя." }; private const float MinimalVolume = -10f; private float _volume = 0.0f; private const float WhisperFade = 4f; private void OnVolumeChanged(float volume) { _volume = volume; } private float AdjustVolume(bool isWhisper) { var volume = MinimalVolume + SharedAudioSystem.GainToVolume(_volume); if (isWhisper) { volume -= SharedAudioSystem.GainToVolume(WhisperFade); } return volume; } private float AdjustDistance(bool isWhisper) { return isWhisper ? 5 : 10; } private async void OnEntitySpoke(PlaySpeechBarksEvent ev) { if (_cfg.GetCVar(HorizonCCVars.ReplaceTTSWithBarks) == false) return; if (ev.Message == null) return; if (ev.Source != null) { var audioParams = AudioParams.Default .WithVolume(AdjustVolume(ev.IsWhisper)) .WithMaxDistance(AdjustDistance(ev.IsWhisper)) .WithPlayOffset(0f) .WithReferenceDistance(100f); if (ev.Message.EndsWith('!')) audioParams = audioParams.WithVolume(audioParams.Volume * 1.2f); var audioResource = new AudioResource(); string str = ev.Sound; var path = new ResPath(str); audioResource.Load(IoCManager.Instance!, path); var count = ev.Message.Length / 3f; for (var i = 0; i < count; i++) { if (_player.LocalSession == null) break; var entity = GetEntity(ev.Source.Value); if (entity == EntityUid.Invalid || _player.LocalEntity == null) break; if (Deleted(entity) || Terminating(entity)) break; if (!HasComp(entity) || !HasComp(_player.LocalEntity.Value)) continue; if (Transform(entity).Coordinates.TryDistance(EntityManager, Transform(_player.LocalEntity.Value).Coordinates, out var distance) && distance > 10) continue; if (Transform(entity).ParentUid == EntityUid.Invalid) continue; _audio.PlayEntity(audioResource.AudioStream, entity, new ResolvedPathSpecifier(path), audioParams.WithPitchScale(_random.NextFloat(ev.Pitch - 0.1f, ev.Pitch + 0.1f))); await Task.Delay(TimeSpan.FromSeconds(_random.NextFloat(ev.LowVar, ev.HighVar))); } } } public async void PlayDataPrewiew(string protoId, float pitch, float lowVar, float highVar) { if (!_proto.TryIndex(protoId, out var proto)) return; var message = _random.Pick(_sampleText); var audioParams = AudioParams.Default .WithVolume(AdjustVolume(false)); var count = message.Length / 3f; var audioResource = new AudioResource(); string str = proto.Sound; if (message.EndsWith('!')) audioParams = audioParams.WithVolume(audioParams.Volume * 1.2f); var path = new ResPath(str); audioResource.Load(IoCManager.Instance!, path); for (var i = 0; i < count; i++) { if (_player.LocalSession == null) break; _audio.PlayGlobal(str, _player.LocalSession, audioParams.WithPitchScale(_random.NextFloat(pitch - 0.1f, pitch + 0.1f))); await Task.Delay(TimeSpan.FromSeconds(_random.NextFloat(lowVar, highVar))); } } }