Skip to content

Commit

Permalink
Merge pull request #389 from TheArturZh/corvax-cherry-pick-18
Browse files Browse the repository at this point in the history
Corvax cherry pick 18
  • Loading branch information
TheArturZh authored Oct 4, 2023
2 parents 17c8eeb + 8d1f9d8 commit 01740ef
Show file tree
Hide file tree
Showing 88 changed files with 188 additions and 293 deletions.
2 changes: 1 addition & 1 deletion Content.Client/Corvax/TTS/Commands/TtsQueueResetCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public sealed class TtsQueueResetCommand : IConsoleCommand
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var ttsSys = _entitySystemManager.GetEntitySystem<TTSSystem>();
ttsSys.EndStreams();
//ttsSys.EndStreams();

shell.WriteLine("Local TTS queue has been reset.");
}
Expand Down
5 changes: 1 addition & 4 deletions Content.Client/Corvax/TTS/HumanoidProfileEditor.TTS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ namespace Content.Client.Preferences.UI;

public sealed partial class HumanoidProfileEditor
{
private TTSManager _ttsMgr = default!;
private TTSSystem _ttsSys = default!;
private List<TTSVoicePrototype> _voiceList = default!;
private readonly List<string> _sampleText = new()
Expand All @@ -22,7 +21,6 @@ public sealed partial class HumanoidProfileEditor

private void InitializeVoice()
{
_ttsMgr = IoCManager.Resolve<TTSManager>();
_ttsSys = _entMan.System<TTSSystem>();
_voiceList = _prototypeManager
.EnumeratePrototypes<TTSVoicePrototype>()
Expand Down Expand Up @@ -80,7 +78,6 @@ private void PlayTTS()
if (_previewDummy is null || Profile is null)
return;

_ttsSys.StopAllStreams();
_ttsMgr.RequestTTS(_previewDummy.Value, _random.Pick(_sampleText), Profile.Voice);
_ttsSys.RequestGlobalTTS(_random.Pick(_sampleText), Profile.Voice);
}
}
22 changes: 0 additions & 22 deletions Content.Client/Corvax/TTS/TTSManager.cs

This file was deleted.

182 changes: 27 additions & 155 deletions Content.Client/Corvax/TTS/TTSSystem.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using Content.Shared.Corvax.CCCVars;
using Content.Shared.Corvax.TTS;
using Content.Shared.Corvax.TTS.Commands;
using Content.Shared.Physics;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.Audio;
using Robust.Shared.Configuration;
using Robust.Shared.Map;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Systems;
using Robust.Shared.ContentPack;
using Robust.Shared.Player;
using Robust.Shared.Utility;

namespace Content.Client.Corvax.TTS;

Expand All @@ -19,24 +16,23 @@ namespace Content.Client.Corvax.TTS;
// ReSharper disable once InconsistentNaming
public sealed class TTSSystem : EntitySystem
{
[Dependency] private readonly IClydeAudio _clyde = default!;
[Dependency] private readonly IEntityManager _entity = default!;
[Dependency] private readonly IEyeManager _eye = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly SharedPhysicsSystem _broadPhase = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;

private ISawmill _sawmill = default!;

private readonly MemoryContentRoot _contentRoot = new();
private static readonly ResPath Prefix = ResPath.Root / "TTS";

private float _volume = 0.0f;
private float _radioVolume = 0.0f;

private readonly HashSet<AudioStream> _currentStreams = new();
private readonly Dictionary<EntityUid, Queue<AudioStream>> _entityQueues = new();
private int _fileIdx = 0;

public override void Initialize()
{
_sawmill = Logger.GetSawmill("tts");
_resourceCache.AddRoot(Prefix, _contentRoot);
_cfg.OnValueChanged(CCCVars.TTSVolume, OnTtsVolumeChanged, true);
_cfg.OnValueChanged(CCCVars.TTSRadioVolume, OnTtsRadioVolumeChanged, true);
SubscribeNetworkEvent<PlayTTSEvent>(OnPlayTTS);
Expand All @@ -48,58 +44,12 @@ public override void Shutdown()
base.Shutdown();
_cfg.UnsubValueChanged(CCCVars.TTSVolume, OnTtsVolumeChanged);
_cfg.UnsubValueChanged(CCCVars.TTSRadioVolume, OnTtsRadioVolumeChanged);
EndStreams();
_contentRoot.Dispose();
}

// Little bit of duplication logic from AudioSystem
public override void FrameUpdate(float frameTime)
public void RequestGlobalTTS(string text, string voiceId)
{
var streamToRemove = new HashSet<AudioStream>();

var ourPos = _eye.CurrentEye.Position.Position;
foreach (var stream in _currentStreams)
{
var streamUid = GetEntity(stream.Uid);
if (!stream.Source.IsPlaying ||
!_entity.TryGetComponent<MetaDataComponent>(streamUid, out var meta) ||
Deleted(streamUid, meta) ||
!_entity.TryGetComponent<TransformComponent>(streamUid, out var xform))
{
stream.Source.Dispose();
streamToRemove.Add(stream);
continue;
}

var mapPos = xform.MapPosition;
if (mapPos.MapId != MapId.Nullspace)
{
if (!stream.Source.SetPosition(mapPos.Position))
{
_sawmill.Warning("Can't set position for audio stream, stop stream.");
stream.Source.StopPlaying();
}
}

if (mapPos.MapId == _eye.CurrentMap)
{
var collisionMask = (int) CollisionGroup.Impassable;
var sourceRelative = ourPos - mapPos.Position;
var occlusion = 0f;
if (sourceRelative.Length() > 0)
{
occlusion = _broadPhase.IntersectRayPenetration(mapPos.MapId,
new CollisionRay(mapPos.Position, sourceRelative.Normalized(), collisionMask),
sourceRelative.Length(), streamUid);
}
stream.Source.SetOcclusion(occlusion);
}
}

foreach (var audioStream in streamToRemove)
{
_currentStreams.Remove(audioStream);
ProcessEntityQueue(GetEntity(audioStream.Uid));
}
RaiseNetworkEvent(new RequestGlobalTTSEvent(text, voiceId));
}

private void OnTtsVolumeChanged(float volume)
Expand All @@ -114,109 +64,31 @@ private void OnTtsRadioVolumeChanged(float volume)

private void OnQueueResetRequest(TtsQueueResetMessage ev)
{
EndStreams();
//EndStreams();
_sawmill.Debug("TTS queue was cleared by request from the server.");
}

private void OnPlayTTS(PlayTTSEvent ev)
{
var volume = (ev.IsRadio ? _radioVolume : _volume) * ev.VolumeModifier;

if (!TryCreateAudioSource(ev.Data, volume, out var source))
return;

var stream = new AudioStream(ev.Uid, source);
AddEntityStreamToQueue(stream);
}
_sawmill.Debug($"Play TTS audio {ev.Data.Length} bytes from {ev.SourceUid} entity");

public void StopAllStreams()
{
foreach (var stream in _currentStreams)
stream.Source.StopPlaying();
}
var volume = (ev.IsRadio ? _radioVolume : _volume) * ev.VolumeModifier;

private bool TryCreateAudioSource(byte[] data, float volume, [NotNullWhen(true)] out IClydeAudioSource? source)
{
var dataStream = new MemoryStream(data) { Position = 0 };
var audioStream = _clyde.LoadAudioOggVorbis(dataStream);
source = _clyde.CreateAudioSource(audioStream);
source?.SetVolume(volume);
return source != null;
}
var filePath = new ResPath($"{_fileIdx++}.ogg");
_contentRoot.AddOrUpdateFile(filePath, ev.Data);

private void AddEntityStreamToQueue(AudioStream stream)
{
var uid = GetEntity(stream.Uid);
if (_entityQueues.TryGetValue(uid, out var queue))
var audioParams = AudioParams.Default.WithVolume(volume);
var soundPath = new SoundPathSpecifier(Prefix / filePath, audioParams);
if (ev.SourceUid != null)
{
queue.Enqueue(stream);
var sourceUid = GetEntity(ev.SourceUid.Value);
_audio.PlayEntity(soundPath, new EntityUid(), sourceUid); // recipient arg ignored on client
}
else
{
_entityQueues.Add(uid, new Queue<AudioStream>(new[] { stream }));

if (!IsEntityCurrentlyPlayStream(stream.Uid))
ProcessEntityQueue(uid);
}
}

private bool IsEntityCurrentlyPlayStream(NetEntity uid)
{
return _currentStreams.Any(s => s.Uid == uid);
}

private void ProcessEntityQueue(EntityUid uid)
{
if (TryTakeEntityStreamFromQueue(uid, out var stream))
PlayEntity(stream);
}

private bool TryTakeEntityStreamFromQueue(EntityUid uid, [NotNullWhen(true)] out AudioStream? stream)
{
if (_entityQueues.TryGetValue(uid, out var queue))
{
stream = queue.Dequeue();
if (queue.Count == 0)
_entityQueues.Remove(uid);
return true;
_audio.PlayGlobal(soundPath, Filter.Local(), false);
}

stream = null;
return false;
}

private void PlayEntity(AudioStream stream)
{
if (!_entity.TryGetComponent<TransformComponent>(GetEntity(stream.Uid), out var xform) ||
!stream.Source.SetPosition(_transform.GetWorldPosition(xform)))
return;

stream.Source.StartPlaying();
_currentStreams.Add(stream);
}

public void EndStreams()
{
foreach (var stream in _currentStreams)
{
stream.Source.StopPlaying();
stream.Source.Dispose();
}

_currentStreams.Clear();
_entityQueues.Clear();
}

// ReSharper disable once InconsistentNaming
private sealed class AudioStream
{
public NetEntity Uid { get; }
public IClydeAudioSource Source { get; }

public AudioStream(NetEntity uid, IClydeAudioSource source)
{
Uid = uid;
Source = source;
}
_contentRoot.RemoveFile(filePath);
}
}
2 changes: 0 additions & 2 deletions Content.Client/Entry/EntryPoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ public sealed class EntryPoint : GameClient
[Dependency] private readonly ContentLocalizationManager _contentLoc = default!;
[Dependency] private readonly SponsorsManager _sponsorsManager = default!; // Corvax-Sponsors
[Dependency] private readonly JoinQueueManager _queueManager = default!; // Corvax-Queue
[Dependency] private readonly TTSManager _ttsManager = default!; // Corvax-TTS
[Dependency] private readonly DiscordAuthManager _discordAuthManager = default!; // Corvax-DiscordAuth
[Dependency] private readonly ContentReplayPlaybackManager _playbackMan = default!;
[Dependency] private readonly IResourceManager _resourceManager = default!;
Expand Down Expand Up @@ -174,7 +173,6 @@ public override void PostInit()
_userInterfaceManager.SetDefaultTheme("SS14DefaultTheme");
_sponsorsManager.Initialize(); // Corvax-Sponsors
_queueManager.Initialize(); // Corvax-Queue
_ttsManager.Initialize(); // Corvax-TTS
_discordAuthManager.Initialize(); // Corvax-DiscordAuth
_userInterfaceManager.SetActiveTheme(_configManager.GetCVar(CVars.InterfaceTheme));
_documentParsingManager.Initialize();
Expand Down
1 change: 0 additions & 1 deletion Content.Client/IoC/ClientContentIoC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ public static void Register()
IoCManager.Register<JobRequirementsManager>();
IoCManager.Register<SponsorsManager>(); // Corvax-Sponsors
IoCManager.Register<JoinQueueManager>(); // Corvax-Queue
IoCManager.Register<TTSManager>(); // Corvax-TTS
IoCManager.Register<DiscordAuthManager>(); // Corvax-DiscordAuth
IoCManager.Register<DocumentParsingManager>();
IoCManager.Register<ContentReplayPlaybackManager, ContentReplayPlaybackManager>();
Expand Down
20 changes: 8 additions & 12 deletions Content.Server/Corvax/TTS/TTSSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
using Content.Shared.Corvax.TTS;
using Content.Shared.GameTicking;
using Content.Shared.SS220.AnnounceTTS;
using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;

Expand All @@ -17,8 +15,6 @@ public sealed partial class TTSSystem : EntitySystem
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IServerNetManager _netMgr = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly TTSManager _ttsManager = default!;
[Dependency] private readonly SharedTransformSystem _xforms = default!;

Expand All @@ -40,7 +36,7 @@ public override void Initialize()
SubscribeLocalEvent<AnnouncementSpokeEvent>(OnAnnouncementSpoke);
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestartCleanup);

_netMgr.RegisterNetMessage<MsgRequestTTS>(OnRequestTTS);
SubscribeNetworkEvent<RequestGlobalTTSEvent>(OnRequestGlobalTTS);
}

private void OnRadioReceiveEvent(RadioSpokeEvent args)
Expand Down Expand Up @@ -85,18 +81,18 @@ private void OnRoundRestartCleanup(RoundRestartCleanupEvent ev)
_ttsManager.ResetCache();
}

private async void OnRequestTTS(MsgRequestTTS ev)
private async void OnRequestGlobalTTS(RequestGlobalTTSEvent ev, EntitySessionEventArgs args)
{
if (!_isEnabled ||
ev.Text.Length > MaxMessageChars ||
!_playerManager.TryGetSessionByChannel(ev.MsgChannel, out var session) ||
!_prototypeManager.TryIndex<TTSVoicePrototype>(ev.VoiceId, out var protoVoice))
return;

var soundData = await GenerateTTS(ev.Text, protoVoice.Speaker);
if (soundData is null) return;
if (soundData is null)
return;

RaiseNetworkEvent(new PlayTTSEvent(GetNetEntity(ev.Uid), soundData, false), Filter.SinglePlayer(session));
RaiseNetworkEvent(new PlayTTSEvent(soundData), Filter.SinglePlayer(args.SenderSession));
}

private async void OnEntitySpoke(EntityUid uid, TTSComponent component, EntitySpokeEvent args)
Expand Down Expand Up @@ -127,7 +123,7 @@ private async void HandleSay(EntityUid uid, string message, string speaker)
{
var soundData = await GenerateTTS(message, speaker);
if (soundData is null) return;
RaiseNetworkEvent(new PlayTTSEvent(GetNetEntity(uid), soundData, false), Filter.Pvs(uid));
RaiseNetworkEvent(new PlayTTSEvent(soundData, GetNetEntity(uid)), Filter.Pvs(uid));
}

private async void HandleWhisper(EntityUid uid, string message, string speaker, bool isRadio)
Expand All @@ -154,8 +150,8 @@ private async void HandleWhisper(EntityUid uid, string message, string speaker,
continue;

var ttsEvent = new PlayTTSEvent(
GetNetEntity(uid),
soundData,
GetNetEntity(uid),
false,
WhisperVoiceVolumeModifier * (1f - distance / WhisperVoiceRange));
RaiseNetworkEvent(ttsEvent, session);
Expand All @@ -170,7 +166,7 @@ private async void HandleRadio(EntityUid[] uids, string message, string speaker)

foreach (var uid in uids)
{
RaiseNetworkEvent(new PlayTTSEvent(GetNetEntity(uid), soundData, true), Filter.Entities(uid));
RaiseNetworkEvent(new PlayTTSEvent(soundData, GetNetEntity(uid), true), Filter.Entities(uid));
}
}

Expand Down
Loading

0 comments on commit 01740ef

Please sign in to comment.