Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Corvax cherry pick 18 #389

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading