Skip to content
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
8 changes: 4 additions & 4 deletions Content.Client/_Art/TTS/TTSSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ namespace Content.Client._Art.TTS;
/// Plays TTS audio in world
/// </summary>
// ReSharper disable once InconsistentNaming
public sealed class TTSSystem : EntitySystem
public sealed partial class TTSSystem : EntitySystem
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IResourceManager _res = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private IConfigurationManager _cfg = default!;
[Dependency] private IResourceManager _res = default!;
[Dependency] private AudioSystem _audio = default!;

private ISawmill _sawmill = default!;
private readonly MemoryContentRoot _contentRoot = new();
Expand Down
42 changes: 35 additions & 7 deletions Content.Goobstation.Client/Barks/BarkSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
using Robust.Shared.Timing;
using Content.Goobstation.Common.CCVar;
using Content.Shared._Arcane.CCVars;
// Arcane-Start
using Content.Shared.CCVar;
using Content.Client.Audio;
// Arcane-End

namespace Content.Goobstation.Client.Barks;

Expand Down Expand Up @@ -48,6 +52,18 @@ public void OnPreviewBark(PreviewBarkEvent ev)
private void OnPlayBark(PlayBarkEvent ev)
{
var sourceEntity = GetEntity(ev.SourceUid);

// Arcane-Start - Radio bark: the speaker is not in the listener's PVS, so the bark prototype travels with the event.
if (ev.BarkProtoId is { } protoId)
{
if (!_prototypeManager.TryIndex<BarkPrototype>(protoId, out var barkProto))
return;

PlayBark(sourceEntity, ev.Message, ev.Whisper, barkProto, radio: true);
return;
}
// Arcane-End

if (!TryComp<SpeechSynthesisComponent>(sourceEntity, out var comp)
|| comp.VoicePrototypeId is null
|| !_prototypeManager.TryIndex<BarkPrototype>(comp.VoicePrototypeId, out var proto))
Expand All @@ -56,7 +72,7 @@ private void OnPlayBark(PlayBarkEvent ev)
PlayBark(sourceEntity, ev.Message, ev.Whisper, proto);
}

private void PlayBark(EntityUid? source, string message, bool whisper, BarkPrototype proto)
private void PlayBark(EntityUid? source, string message, bool whisper, BarkPrototype proto, bool radio = false) // Arcane-Edit
{
// Arcane-start
if (_cfg.GetCVar(ACCVars.UseTTS))
Expand All @@ -69,7 +85,7 @@ private void PlayBark(EntityUid? source, string message, bool whisper, BarkProto
if (message.Length > 50)
message = message[..50];

var volume = GetVolume(whisper, proto);
var volume = GetVolume(whisper, proto, radio); // Arcane-Edit
if (volume <= -20f)
return;

Expand All @@ -91,6 +107,7 @@ private void PlayBark(EntityUid? source, string message, bool whisper, BarkProto
{
Source = source,
IsPreview = source == null,
IsRadio = radio, // Arcane
Message = message,
Prototype = proto,
Volume = volume,
Expand All @@ -113,7 +130,7 @@ public override void Update(float frameTime)
if (bark.NextSound > _timing.CurTime)
continue;

if (!bark.IsPreview && TerminatingOrDeleted(bark.Source!.Value))
if (!bark.IsRadio && !bark.IsPreview && TerminatingOrDeleted(bark.Source!.Value)) // Arcane-Edit
{
_activeBarks.RemoveAt(i);
continue;
Expand Down Expand Up @@ -170,27 +187,37 @@ private void PlaySound(ActiveBark bark, char character)
audioParams = audioParams.WithVolume(bark.Volume);

var filter = Filter.Local();
var soundEntity = bark.IsPreview
var soundEntity = bark.IsRadio || bark.IsPreview // Arcane-Edit
? _sharedAudio.PlayGlobal(sound, filter, false, audioParams)
: _sharedAudio.PlayEntity(sound, filter, bark.Source!.Value, false, audioParams);

if (!bark.IsPreview && proto.Stop)
if (!bark.IsRadio && !bark.IsPreview && proto.Stop) // Arcane-Edit
{
if (_playingSounds.TryGetValue(GetNetEntity(bark.Source!.Value), out var playing))
_sharedAudio.Stop(playing);
}

if (!bark.IsPreview && soundEntity is not null)
if (!bark.IsRadio && !bark.IsPreview && soundEntity is not null) // Arcane-Edit
_playingSounds[GetNetEntity(bark.Source!.Value)] = soundEntity.Value.Entity;
}

private float GetVolume(bool whisper, BarkPrototype proto)
private float GetVolume(bool whisper, BarkPrototype proto, bool radio = false) // Arcane-Edit
{
var volume = proto.Volume;

if (whisper)
volume = 0.05f + (volume - 0.05f) * 0.25f;

// Arcane-Start - Radio barks follow the Radio Volume setting, like the other radio sounds.
if (radio)
{
var radioVolume = _cfg.GetCVar(CCVars.RadioVolume) * ContentAudioSystem.RadioMultiplier;
volume *= radioVolume;

return SharedAudioSystem.GainToVolume(volume);
}
// Arcane-End

var barksVolume = _cfg.GetCVar(GoobCVars.BarksVolume);
volume *= barksVolume / 3f;

Expand All @@ -201,6 +228,7 @@ private sealed class ActiveBark
{
public EntityUid? Source;
public bool IsPreview;
public bool IsRadio; // Arcane
public string Message = string.Empty;
public BarkPrototype Prototype = default!;
public float Volume;
Expand Down
9 changes: 8 additions & 1 deletion Content.Goobstation.Common/Barks/BarkEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@
namespace Content.Goobstation.Common.Barks;

[Serializable, NetSerializable]
public sealed class PlayBarkEvent(NetEntity sourceUid, string message, bool whisper) : EntityEventArgs
public sealed class PlayBarkEvent(NetEntity sourceUid, string message, bool whisper, string? barkProtoId = null) : EntityEventArgs // Arcane
{
public NetEntity SourceUid { get; } = sourceUid;
public string Message { get; } = message;
public bool Whisper { get; } = whisper;

// Arcane-Start
/// <summary>
/// Bark prototype id, when the bark is played for a radio listener that cannot see the speaker entity.
/// </summary>
public string? BarkProtoId { get; } = barkProtoId;
// Arcane-End
}

[Serializable, NetSerializable]
Expand Down
3 changes: 2 additions & 1 deletion Content.Server/Communications/CommunicationsConsoleSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,8 @@ private void OnAnnounceMessage(EntityUid uid, CommunicationsConsoleComponent com
if (TryComp<StationDataComponent>(station, out var stationDataComp))
{
var filter = _stationSystem.GetInStation(stationDataComp);
RaiseLocalEvent(new TTSAnnouncePlayEvent(msg, message.Actor, filter));
var ttsEv = new TTSAnnouncePlayEvent(msg, message.Actor, filter);
RaiseLocalEvent(ref ttsEv);
}

// if (comp.AnnounceSentBy)
Expand Down
52 changes: 50 additions & 2 deletions Content.Server/Radio/EntitySystems/HeadsetSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
using Robust.Shared.Network;
using Robust.Shared.Player;
using Content.Shared.Whitelist;
// Arcane-Start
using Content.Shared._Art.TTS;
using Content.Goobstation.Common.Barks;
using Content.Shared._Orion.Radio;
using Robust.Shared.Audio;
// Arcane-End

namespace Content.Server.Radio.EntitySystems;

Expand Down Expand Up @@ -57,8 +63,13 @@ private void OnSpeak(EntityUid uid, WearingHeadsetComponent component, EntitySpo
&& keys.Channels.Contains(args.Channel.ID)
&& _whitelist.IsWhitelistPassOrNull(args.Channel.SendWhitelist, uid)) // Goobstation - Whitelisted channels
{
_radio.SendRadioMessage(uid, args.Message, args.Channel, component.Headset);
args.Channel = null; // prevent duplicate messages from other listeners.
// Arcane-Edit-Start
if (_radio.SendRadioMessage(uid, args.Message, args.Channel, component.Headset))
{
args.RadioMessageSent = true;
args.Channel = null; // prevent duplicate messages from other listeners.
}
// Arcane-Edit-End
}
}

Expand Down Expand Up @@ -104,6 +115,8 @@ public void SetEnabled(EntityUid uid, bool value, HeadsetComponent? component =
}
}

private static readonly SoundSpecifier DefaultOnSound = new SoundPathSpecifier("/Audio/_Orion/Radio/basic.ogg"); // Arcane

private void OnHeadsetReceive(EntityUid uid, HeadsetComponent component, ref RadioReceiveEvent args)
{
// TODO: change this when a code refactor is done
Expand All @@ -126,7 +139,42 @@ private void OnHeadsetReceive(EntityUid uid, HeadsetComponent component, ref Rad
{
Message = canUnderstand ? args.OriginalChatMsg : args.LanguageObfuscatedChatMsg
};

// Arcane-Start
if (canUnderstand && args.Voice is { } voice)
{
var ev = new TTSRadioPlayEvent(args.OriginalChatMsg.Message, args.Language, voice);
RaiseLocalEvent(parent, ref ev);
}
// Arcane-End

_netMan.ServerSendMessage(msg, actor.PlayerSession.Channel);

// Arcane-Start: Radio sound
var sound = args.Channel.OnSendSound ?? DefaultOnSound;
if (sound is SoundPathSpecifier sps)
{
RaiseNetworkEvent(new PlayRadioBarkEvent
{
Path = sps.Path.ToString(),
Params = sps.Params,
Source = GetNetEntity(args.MessageSource),
}, actor.PlayerSession.Channel);
}
else if (sound is SoundCollectionSpecifier)
{
Log.Warning($"Radio channel {args.Channel.ID} uses SoundCollectionSpecifier, which is not supported for PlayRadioBarkEvent. Falling back to silent playback.");
}

if (parent != args.MessageSource
&& TryComp<SpeechSynthesisComponent>(args.MessageSource, out var speech)
&& speech.VoicePrototypeId is { } barkVoice)
{
RaiseNetworkEvent(
new PlayBarkEvent(GetNetEntity(args.MessageSource), args.OriginalChatMsg.Message, false, barkVoice),
actor.PlayerSession.Channel);
}
// Arcane-End
}
// Einstein Engines - Language end
}
Expand Down
Loading
Loading