[Feat] TTS borgs & announcements (#342)

* tts for borgs

* tts for announcements
This commit is contained in:
HitPanda
2023-08-28 18:55:56 +03:00
committed by Aviu00
parent af38299925
commit 60aadc8919
7 changed files with 117 additions and 59 deletions

View File

@@ -55,5 +55,10 @@ namespace Content.Server.Communications
/// </summary>
[DataField]
public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Announcements/announce.ogg");
//WD-start
[DataField("ttsVoiceId")]
public string TtsVoiceId = "Glados";
//WD-end
}
}

View File

@@ -9,6 +9,7 @@ using Content.Server.RoundEnd;
using Content.Server.Shuttles.Systems;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Server.White.TTS;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Content.Shared.CCVar;
@@ -287,6 +288,11 @@ namespace Content.Server.Communications
}
_chatSystem.DispatchStationAnnouncement(uid, msg, title, colorOverride: comp.Color);
//WD-start
var ttsEv = new TTSAnnouncementEvent(message.Message, comp.TtsVoiceId, uid, comp.Global);
RaiseLocalEvent(ttsEv);
//WD-end
if (message.Session.AttachedEntity != null)
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} has sent the following station announcement: {msg}");
}

View File

@@ -0,0 +1,17 @@
namespace Content.Server.White.TTS;
public sealed class TTSAnnouncementEvent : EntityEventArgs
{
public readonly string Message;
public readonly bool Global;
public readonly string VoiceId;
public readonly EntityUid Source;
public TTSAnnouncementEvent(string message, string voiceId, EntityUid source , bool global)
{
Message = message;
Global = global;
VoiceId = voiceId;
Source = source;
}
}

View File

@@ -1,8 +1,13 @@
using System.Threading.Tasks;
using System.Linq;
using System.Threading.Tasks;
using Content.Server.Chat.Systems;
using Content.Server.Light.Components;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared.White.TTS;
using Content.Shared.GameTicking;
using Content.Shared.White;
using Robust.Server.Audio;
using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
@@ -24,6 +29,9 @@ public sealed partial class TTSSystem : EntitySystem
[Dependency] private readonly IServerNetManager _netMgr = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly TTSPitchRateSystem _ttsPitchRateSystem = default!;
[Dependency] private readonly StationSystem _stationSystem = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
private const int MaxMessageChars = 100 * 2; // same as SingleBubbleCharLimit * 2
private bool _isEnabled = false;
@@ -38,9 +46,73 @@ public sealed partial class TTSSystem : EntitySystem
SubscribeLocalEvent<TTSComponent, EntitySpokeEvent>(OnEntitySpoke);
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestartCleanup);
SubscribeLocalEvent<TTSAnnouncementEvent>(OnAnnounceRequest);
_netMgr.RegisterNetMessage<MsgRequestTTS>(OnRequestTTS);
}
private async void OnAnnounceRequest(TTSAnnouncementEvent ev)
{
if (!_prototypeManager.TryIndex<TTSVoicePrototype>(ev.VoiceId, out var ttsPrototype))
return;
var message = FormattedMessage.RemoveMarkup(ev.Message);
var soundData = await GenerateTTS(null, message, ttsPrototype.Speaker);
if (soundData == null)
return;
Filter filter;
if (ev.Global)
filter = Filter.Broadcast();
else
{
var station = _stationSystem.GetOwningStation(ev.Source);
if (station == null)
return;
if (!EntityManager.TryGetComponent<StationDataComponent>(station, out var stationDataComp))
return;
filter = _stationSystem.GetInStation(stationDataComp);
}
foreach (var player in filter.Recipients)
{
if (player.AttachedEntity != null)
{
// Get emergency lights in range to broadcast from
var entities = _lookup.GetEntitiesInRange(player.AttachedEntity.Value, 20f)
.Where(HasComp<EmergencyLightComponent>)
.ToList();
if (entities.Count == 0)
return;
// Get closest emergency light
var entity = entities.First();
var range = 100f;
foreach (var item in entities)
{
var itemSource = _xforms.GetWorldPosition(Transform(item));
var playerSource = _xforms.GetWorldPosition(Transform(player.AttachedEntity.Value));
var distance = playerSource.Length() - itemSource.Length();
if (range > distance)
{
range = distance;
entity = item;
}
}
RaiseNetworkEvent(new PlayTTSEvent(GetNetEntity(entity), soundData), Filter.SinglePlayer(player),
false);
}
}
}
private async void OnRequestTTS(MsgRequestTTS ev)
{
var url = _cfg.GetCVar(WhiteCVars.TTSApiUrl);
@@ -138,7 +210,7 @@ public sealed partial class TTSSystem : EntitySystem
_ttsManager.ResetCache();
}
private async Task<byte[]?> GenerateTTS(EntityUid uid, string text, string speaker, string? speechPitch = null, string? speechRate = null)
private async Task<byte[]?> GenerateTTS(EntityUid? uid, string text, string speaker, string? speechPitch = null, string? speechRate = null)
{
var textSanitized = Sanitize(text);
if (textSanitized == "")
@@ -148,7 +220,7 @@ public sealed partial class TTSSystem : EntitySystem
string rate;
if (speechPitch == null || speechRate == null)
{
if (!_ttsPitchRateSystem.TryGetPitchRate(uid, out var pitchRate))
if (uid == null || !_ttsPitchRateSystem.TryGetPitchRate(uid.Value, out var pitchRate))
{
pitch = "medium";
rate = "medium";

View File

@@ -31,4 +31,7 @@ public sealed class TTSVoicePrototype : IPrototype
[DataField("sponsorOnly")]
public bool SponsorOnly { get; } = false;
[DataField("borgVoice")]
public bool BorgVoice { get; } = false;
}

View File

@@ -25,25 +25,17 @@ tts-voice-name-gman = G-Man
tts-voice-name-obama = Обама
tts-voice-name-trump = Трамп
tts-voice-name-briman = Брин
tts-voice-name-kleiner-alt = Кляйнер (Альт.)
tts-voice-name-father-grigori = Отец Григорий
tts-voice-name-vance = Вэнс
tts-voice-name-barni = Барни
tts-voice-name-gman-alt = G-Man (Альт.)
tts-voice-name-alyx = Аликс
tts-voice-name-mossman = Моссман
tts-voice-name-bandit = Бандит
tts-voice-name-papich-alt = Папич (Альт.)
tts-voice-name-bebey-alt = Бэбэй (Альт.)
tts-voice-name-glados-alt = Гладос (Альт.)
tts-voice-name-geralt = Геральт
tts-voice-name-triss = Трисс
tts-voice-name-kodlak-white-mane = Кодлак Белая Грива
tts-voice-name-cicero = Цицерон
tts-voice-name-sheogorath = Шеогорат
tts-voice-name-adventure-core-alt = Модуль Приключений (Альт.)
tts-voice-name-fact-core-alt = Модуль Фактов (Альт.)
tts-voice-name-space-core-alt = Модуль Космоса (Альт.)
tts-voice-name-turret-floor = Турель
tts-voice-name-cirilla = Цири
tts-voice-name-lambert = Ламберт

View File

@@ -69,12 +69,15 @@
name: tts-voice-name-glados
sex: Female
speaker: glados
roundStart: false
- type: ttsVoice
id: Sentrybot
name: tts-voice-name-sentrybot
sex: Male
speaker: sentrybot
roundStart: false
borgVoice: true
- type: ttsVoice
id: Mana
@@ -105,18 +108,24 @@
name: tts-voice-name-adventure-core
sex: Male
speaker: adventure_core
roundStart: false
borgVoice: true
- type: ttsVoice
id: SpaceCore
name: tts-voice-name-space-core
sex: Male
speaker: space_core
roundStart: false
borgVoice: true
- type: ttsVoice
id: FactCore
name: tts-voice-name-fact-core
sex: Male
speaker: fact_core
roundStart: false
borgVoice: true
- type: ttsVoice
id: Kleiner
@@ -160,12 +169,6 @@
sex: Male
speaker: briman
- type: ttsVoice
id: KleinerAlt
name: tts-voice-name-kleiner-alt
sex: Male
speaker: kleiner_alt
- type: ttsVoice
id: FatherGrigori
name: tts-voice-name-father-grigori
@@ -184,12 +187,6 @@
sex: Male
speaker: barni
- type: ttsVoice
id: GmanAlt
name: tts-voice-name-gman-alt
sex: Male
speaker: gman_alt
- type: ttsVoice
id: Alyx
name: tts-voice-name-alyx
@@ -208,24 +205,6 @@
sex: Male
speaker: bandit
- type: ttsVoice
id: PapichAlt
name: tts-voice-name-papich-alt
sex: Male
speaker: papich_alt
- type: ttsVoice
id: BebeyAlt
name: tts-voice-name-bebey-alt
sex: Male
speaker: bebey_alt
- type: ttsVoice
id: GladosAlt
name: tts-voice-name-glados-alt
sex: Female
speaker: glados_alt
- type: ttsVoice
id: Geralt
name: tts-voice-name-geralt
@@ -256,29 +235,13 @@
sex: Male
speaker: sheogorath
- type: ttsVoice
id: AdventureCoreAlt
name: tts-voice-name-adventure-core-alt
sex: Male
speaker: adventure_core_alt
- type: ttsVoice
id: FactCoreAlt
name: tts-voice-name-fact-core-alt
sex: Male
speaker: fact_core_alt
- type: ttsVoice
id: SpaceCoreAlt
name: tts-voice-name-space-core-alt
sex: Male
speaker: space_core_alt
- type: ttsVoice
id: TurretFloor
name: tts-voice-name-turret-floor
sex: Female
speaker: turret_floor
roundStart: false
borgVoice: true
- type: ttsVoice
id: Cirilla