[Feat] TTS borgs & announcements (#342)
* tts for borgs * tts for announcements
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
|
||||
17
Content.Server/White/TTS/TTSAnnouncementEvent.cs
Normal file
17
Content.Server/White/TTS/TTSAnnouncementEvent.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
@@ -31,4 +31,7 @@ public sealed class TTSVoicePrototype : IPrototype
|
||||
|
||||
[DataField("sponsorOnly")]
|
||||
public bool SponsorOnly { get; } = false;
|
||||
|
||||
[DataField("borgVoice")]
|
||||
public bool BorgVoice { get; } = false;
|
||||
}
|
||||
|
||||
@@ -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 = Ламберт
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user