fix: ТТС снова выдает правильные голоса
This commit is contained in:
@@ -972,7 +972,8 @@ public sealed partial class ChangelingSystem
|
||||
ClonePerson(polymorphEntity.Value, transformData.AppearanceComponent, polyAppearance);
|
||||
TransferDna(polymorphEntity.Value, transformData.Dna);
|
||||
|
||||
_humanoidAppearance.SetTTSVoice(polymorphEntity.Value, transformData.AppearanceComponent.Voice, polyAppearance);
|
||||
_humanoidAppearance.SetTTSVoice(polymorphEntity.Value, transformData.AppearanceComponent.Voice,
|
||||
humanoid: polyAppearance);
|
||||
|
||||
if (!TryComp<MetaDataComponent>(polymorphEntity.Value, out var meta))
|
||||
return null;
|
||||
|
||||
@@ -40,15 +40,15 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
|
||||
return;
|
||||
}
|
||||
|
||||
targetHumanoid.Species = sourceHumanoid.Species;
|
||||
targetHumanoid.SkinColor = sourceHumanoid.SkinColor;
|
||||
SetSpecies(target, sourceHumanoid.Species, false, targetHumanoid);
|
||||
SetSkinColor(target, sourceHumanoid.SkinColor, false, true, targetHumanoid);
|
||||
targetHumanoid.EyeColor = sourceHumanoid.EyeColor;
|
||||
targetHumanoid.Age = sourceHumanoid.Age;
|
||||
SetSex(target, sourceHumanoid.Sex, false, targetHumanoid);
|
||||
targetHumanoid.CustomBaseLayers = new(sourceHumanoid.CustomBaseLayers);
|
||||
targetHumanoid.MarkingSet = new(sourceHumanoid.MarkingSet);
|
||||
targetHumanoid.BodyType = sourceHumanoid.BodyType;
|
||||
SetTTSVoice(target, sourceHumanoid.Voice, targetHumanoid);
|
||||
SetSex(target, sourceHumanoid.Sex, false, targetHumanoid);
|
||||
SetBodyType(target, sourceHumanoid.BodyType, false, targetHumanoid);
|
||||
SetTTSVoice(target, sourceHumanoid.Voice, false, targetHumanoid);
|
||||
|
||||
targetHumanoid.Gender = sourceHumanoid.Gender;
|
||||
if (TryComp<GrammarComponent>(target, out var grammar))
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
using Content.Server._White.TTS;
|
||||
using Content.Shared.Humanoid;
|
||||
|
||||
namespace Content.Server.Humanoid;
|
||||
|
||||
public sealed partial class HumanoidAppearanceSystem
|
||||
{
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public void SetTTSVoice(EntityUid uid, string voiceId, HumanoidAppearanceComponent humanoid)
|
||||
{
|
||||
if (!TryComp<TTSComponent>(uid, out var comp))
|
||||
return;
|
||||
|
||||
humanoid.Voice = voiceId;
|
||||
comp.VoicePrototypeId = voiceId;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,11 @@
|
||||
namespace Content.Server._White.TTS;
|
||||
|
||||
public sealed class TTSAnnouncementEvent : EntityEventArgs
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public sealed class TTSAnnouncementEvent(string message, string voiceId, EntityUid source, bool global)
|
||||
: 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;
|
||||
}
|
||||
}
|
||||
public readonly string Message = message;
|
||||
public readonly bool Global = global;
|
||||
public readonly string VoiceId = voiceId;
|
||||
public readonly EntityUid Source = source;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using Content.Shared._White.TTS;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server._White.TTS;
|
||||
|
||||
/// <summary>
|
||||
/// Apply TTS for entity chat say messages
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public sealed partial class TTSComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Prototype of used voice for TTS.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("voice", customTypeSerializer:typeof(PrototypeIdSerializer<TTSVoicePrototype>))]
|
||||
public string VoicePrototypeId { get; set; } = "Eugene";
|
||||
}
|
||||
@@ -5,7 +5,6 @@ using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared._White;
|
||||
using Prometheus;
|
||||
using Robust.Shared.Configuration;
|
||||
@@ -18,9 +17,9 @@ public sealed class TTSManager
|
||||
private static readonly Histogram RequestTimings = Metrics.CreateHistogram(
|
||||
"tts_req_timings",
|
||||
"Timings of TTS API requests",
|
||||
new HistogramConfiguration()
|
||||
new HistogramConfiguration
|
||||
{
|
||||
LabelNames = new[] {"type"},
|
||||
LabelNames = new[] { "type" },
|
||||
Buckets = Histogram.ExponentialBuckets(.1, 1.5, 10),
|
||||
});
|
||||
|
||||
@@ -55,7 +54,12 @@ public sealed class TTSManager
|
||||
/// <param name="text">SSML formatted text</param>
|
||||
/// <returns>OGG audio bytes</returns>
|
||||
/// <exception cref="Exception">Throws if url or token CCVar not set or http request failed</exception>
|
||||
public async Task<byte[]?> ConvertTextToSpeech(string speaker, string text, string pitch, string rate, string? effect = null)
|
||||
public async Task<byte[]?> ConvertTextToSpeech(
|
||||
string speaker,
|
||||
string text,
|
||||
string pitch,
|
||||
string rate,
|
||||
string? effect = null)
|
||||
{
|
||||
var url = _cfg.GetCVar(WhiteCVars.TtsApiUrl);
|
||||
var maxCacheSize = _cfg.GetCVar(WhiteCVars.TtsMaxCacheSize);
|
||||
@@ -96,7 +100,7 @@ public sealed class TTSManager
|
||||
|
||||
var soundData = await response.Content.ReadAsByteArrayAsync(cts.Token);
|
||||
|
||||
if(_cache.Count > maxCacheSize)
|
||||
if (_cache.Count > maxCacheSize)
|
||||
{
|
||||
_cache.Remove(_cache.Last().Key);
|
||||
}
|
||||
@@ -104,7 +108,9 @@ public sealed class TTSManager
|
||||
_cache.Add(cacheKey, soundData);
|
||||
CachedCount.Inc();
|
||||
|
||||
_sawmill.Debug($"Generated new sound for '{text}' speech by '{speaker}' speaker ({soundData.Length} bytes)");
|
||||
_sawmill.Debug(
|
||||
$"Generated new sound for '{text}' speech by '{speaker}' speaker ({soundData.Length} bytes)");
|
||||
|
||||
RequestTimings.WithLabels("Success").Observe((DateTime.UtcNow - reqTime).TotalSeconds);
|
||||
|
||||
return soundData;
|
||||
@@ -149,7 +155,7 @@ public sealed class TTSManager
|
||||
private string GenerateCacheKey(string speaker, string text)
|
||||
{
|
||||
var key = $"{speaker}/{text}";
|
||||
byte[] keyData = Encoding.UTF8.GetBytes(key);
|
||||
var keyData = Encoding.UTF8.GetBytes(key);
|
||||
var sha256 = System.Security.Cryptography.SHA256.Create();
|
||||
var bytes = sha256.ComputeHash(keyData);
|
||||
return Convert.ToHexString(bytes);
|
||||
@@ -187,4 +193,4 @@ public sealed class TTSManager
|
||||
[JsonPropertyName("audio")]
|
||||
public string Audio { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ 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;
|
||||
@@ -31,7 +30,6 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
[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
|
||||
@@ -44,7 +42,7 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
_cfg.OnValueChanged(WhiteCVars.TtsApiUrl, url => _apiUrl = url, true);
|
||||
|
||||
SubscribeLocalEvent<TransformSpeechEvent>(OnTransformSpeech);
|
||||
SubscribeLocalEvent<TTSComponent, EntitySpokeEvent>(OnEntitySpoke);
|
||||
SubscribeLocalEvent<SharedTTSComponent, EntitySpokeEvent>(OnEntitySpoke);
|
||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestartCleanup);
|
||||
|
||||
SubscribeLocalEvent<TTSAnnouncementEvent>(OnAnnounceRequest);
|
||||
@@ -80,37 +78,37 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
|
||||
foreach (var player in filter.Recipients)
|
||||
{
|
||||
if (player.AttachedEntity != null)
|
||||
if (player.AttachedEntity == null)
|
||||
continue;
|
||||
|
||||
// Get emergency lights in range to broadcast from
|
||||
var entities = _lookup.GetEntitiesInRange(player.AttachedEntity.Value, 30f)
|
||||
.Where(HasComp<EmergencyLightComponent>)
|
||||
.ToList();
|
||||
|
||||
if (entities.Count == 0)
|
||||
return;
|
||||
|
||||
// Get closest emergency light
|
||||
var entity = entities.First();
|
||||
var range = new Vector2(100f);
|
||||
|
||||
foreach (var item in entities)
|
||||
{
|
||||
// Get emergency lights in range to broadcast from
|
||||
var entities = _lookup.GetEntitiesInRange(player.AttachedEntity.Value, 30f)
|
||||
.Where(HasComp<EmergencyLightComponent>)
|
||||
.ToList();
|
||||
var itemSource = _xforms.GetWorldPosition(Transform(item));
|
||||
var playerSource = _xforms.GetWorldPosition(Transform(player.AttachedEntity.Value));
|
||||
|
||||
if (entities.Count == 0)
|
||||
return;
|
||||
var distance = playerSource - itemSource;
|
||||
|
||||
// Get closest emergency light
|
||||
var entity = entities.First();
|
||||
var range = new Vector2(100f);
|
||||
|
||||
foreach (var item in entities)
|
||||
if (range.Length() > distance.Length())
|
||||
{
|
||||
var itemSource = _xforms.GetWorldPosition(Transform(item));
|
||||
var playerSource = _xforms.GetWorldPosition(Transform(player.AttachedEntity.Value));
|
||||
|
||||
var distance = playerSource - itemSource;
|
||||
|
||||
if (range.Length() > distance.Length())
|
||||
{
|
||||
range = distance;
|
||||
entity = item;
|
||||
}
|
||||
range = distance;
|
||||
entity = item;
|
||||
}
|
||||
|
||||
RaiseNetworkEvent(new PlayTTSEvent(GetNetEntity(entity), soundData, true), Filter.SinglePlayer(player),
|
||||
false);
|
||||
}
|
||||
|
||||
RaiseNetworkEvent(new PlayTTSEvent(GetNetEntity(entity), soundData, true), Filter.SinglePlayer(player),
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +119,7 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
return;
|
||||
|
||||
if (!_playerManager.TryGetSessionByChannel(ev.MsgChannel, out var session) ||
|
||||
!_prototypeManager.TryIndex<TTSVoicePrototype>(ev.VoiceId, out var protoVoice))
|
||||
!_prototypeManager.TryIndex(ev.VoiceId, out var protoVoice))
|
||||
return;
|
||||
|
||||
var soundData = await GenerateTTS(ev.Uid, ev.Text, protoVoice.Speaker);
|
||||
@@ -129,7 +127,7 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
RaiseNetworkEvent(new PlayTTSEvent(GetNetEntity(ev.Uid), soundData, false), Filter.SinglePlayer(session), false);
|
||||
}
|
||||
|
||||
private async void OnEntitySpoke(EntityUid uid, TTSComponent component, EntitySpokeEvent args)
|
||||
private async void OnEntitySpoke(EntityUid uid, SharedTTSComponent component, EntitySpokeEvent args)
|
||||
{
|
||||
if (!_isEnabled ||
|
||||
args.Message.Length > MaxMessageChars)
|
||||
@@ -145,7 +143,7 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
RaiseLocalEvent(uid, voiceEv);
|
||||
voiceId = voiceEv.VoiceId;
|
||||
|
||||
if (!_prototypeManager.TryIndex<TTSVoicePrototype>(voiceId, out var protoVoice))
|
||||
if (!_prototypeManager.TryIndex(voiceId, out var protoVoice))
|
||||
return;
|
||||
|
||||
var message = FormattedMessage.RemoveMarkup(args.Message);
|
||||
|
||||
@@ -5,7 +5,6 @@ using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Humanoid;
|
||||
@@ -73,14 +72,17 @@ public sealed partial class HumanoidAppearanceComponent : Component
|
||||
/// <summary>
|
||||
/// Current body type.
|
||||
/// </summary>
|
||||
[DataField("bodyType"), AutoNetworkedField]
|
||||
[DataField, AutoNetworkedField]
|
||||
public ProtoId<BodyTypePrototype> BodyType = SharedHumanoidAppearanceSystem.DefaultBodyType;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public Color EyeColor = Color.Brown;
|
||||
|
||||
[DataField("voice", customTypeSerializer: typeof(PrototypeIdSerializer<TTSVoicePrototype>)), AutoNetworkedField]
|
||||
public string Voice { get; set; } = SharedHumanoidAppearanceSystem.DefaultVoice;
|
||||
/// <summary>
|
||||
/// Current TTS voice.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public ProtoId<TTSVoicePrototype> Voice { get; set; } = SharedHumanoidAppearanceSystem.DefaultVoice;
|
||||
|
||||
/// <summary>
|
||||
/// Hair color of this humanoid. Used to avoid looping through all markings
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using Content.Shared._White.TTS;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
@@ -28,10 +29,13 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
[ValidatePrototypeId<SpeciesPrototype>]
|
||||
public const string DefaultSpecies = "Human";
|
||||
|
||||
[ValidatePrototypeId<BodyTypePrototype>]
|
||||
public const string DefaultBodyType = "HumanNormal";
|
||||
|
||||
[ValidatePrototypeId<TTSVoicePrototype>]
|
||||
public const string DefaultVoice = "Eugene";
|
||||
|
||||
public static readonly Dictionary<Sex, string> DefaultSexVoice = new()
|
||||
public static readonly Dictionary<Sex, ProtoId<TTSVoicePrototype>> DefaultSexVoice = new()
|
||||
{
|
||||
{ Sex.Male, "Eugene" },
|
||||
{ Sex.Female, "Kseniya" },
|
||||
@@ -75,7 +79,8 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
var species = GetSpeciesRepresentation(component.Species).ToLower();
|
||||
var age = GetAgeRepresentation(component.Species, component.Age);
|
||||
|
||||
args.PushText(Loc.GetString("humanoid-appearance-component-examine", ("user", identity), ("age", age), ("species", species)));
|
||||
args.PushText(Loc.GetString("humanoid-appearance-component-examine", ("user", identity), ("age", age),
|
||||
("species", species)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -244,6 +249,36 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a humanoid mob's body yupe. This will change their base sprites.
|
||||
/// </summary>
|
||||
/// <param name="uid">The humanoid mob's UID.</param>
|
||||
/// <param name="voiceId">The tts voice to set the mob to.</param>
|
||||
/// <param name="sync">Whether to immediately synchronize this to the humanoid mob, or not.</param>
|
||||
/// <param name="humanoid">Humanoid component of the entity</param>
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public void SetTTSVoice(
|
||||
EntityUid uid,
|
||||
ProtoId<TTSVoicePrototype> voiceId,
|
||||
bool sync = true,
|
||||
HumanoidAppearanceComponent? humanoid = null)
|
||||
{
|
||||
if (!TryComp<SharedTTSComponent>(uid, out var comp))
|
||||
return;
|
||||
|
||||
if (!Resolve(uid, ref humanoid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
humanoid.Voice = voiceId;
|
||||
comp.VoicePrototypeId = voiceId;
|
||||
if (sync)
|
||||
{
|
||||
Dirty(uid, humanoid);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the base layer ID of this humanoid mob. A humanoid mob's 'base layer' is
|
||||
/// the skin sprite that is applied to the mob's sprite upon appearance refresh.
|
||||
@@ -353,7 +388,8 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
humanoid.EyeColor = profile.Appearance.EyeColor;
|
||||
|
||||
SetSkinColor(uid, profile.Appearance.SkinColor, false);
|
||||
SetBodyType(uid, profile.BodyType, false);
|
||||
SetBodyType(uid, profile.BodyType, false, humanoid);
|
||||
SetTTSVoice(uid, profile.Voice, false, humanoid);
|
||||
|
||||
humanoid.MarkingSet.Clear();
|
||||
|
||||
@@ -545,4 +581,4 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
|
||||
return Loc.GetString("identity-age-old");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Lidgren.Network;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._White.TTS;
|
||||
@@ -10,8 +11,8 @@ public sealed class MsgRequestTTS : NetMessage
|
||||
public override MsgGroups MsgGroup => MsgGroups.Command;
|
||||
|
||||
public EntityUid Uid { get; set; } = EntityUid.Invalid;
|
||||
public string Text { get; set; } = String.Empty;
|
||||
public string VoiceId { get; set; } = String.Empty;
|
||||
public string Text { get; set; } = string.Empty;
|
||||
public ProtoId<TTSVoicePrototype> VoiceId { get; set; } = string.Empty;
|
||||
|
||||
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
|
||||
@@ -4,16 +4,11 @@ namespace Content.Shared._White.TTS;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public sealed class PlayTTSEvent : EntityEventArgs
|
||||
public sealed class PlayTTSEvent(NetEntity uid, byte[] data, bool boostVolume) : EntityEventArgs
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
public byte[] Data { get; }
|
||||
public bool BoostVolume { get; }
|
||||
public NetEntity Uid { get; } = uid;
|
||||
|
||||
public PlayTTSEvent(NetEntity uid, byte[] data, bool boostVolume)
|
||||
{
|
||||
Uid = uid;
|
||||
Data = data;
|
||||
BoostVolume = boostVolume;
|
||||
}
|
||||
}
|
||||
public byte[] Data { get; } = data;
|
||||
|
||||
public bool BoostVolume { get; } = boostVolume;
|
||||
}
|
||||
@@ -4,12 +4,7 @@ namespace Content.Shared._White.TTS;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public sealed class RequestTTSEvent : EntityEventArgs
|
||||
public sealed class RequestTTSEvent(string text) : EntityEventArgs
|
||||
{
|
||||
public string Text { get; }
|
||||
|
||||
public RequestTTSEvent(string text)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
public string Text { get; } = text;
|
||||
}
|
||||
17
Content.Shared/_White/TTS/SharedTTSComponent.cs
Normal file
17
Content.Shared/_White/TTS/SharedTTSComponent.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._White.TTS;
|
||||
|
||||
/// <summary>
|
||||
/// Apply TTS for entity chat say messages
|
||||
/// </summary>
|
||||
[RegisterComponent, AutoGenerateComponentState]
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public sealed partial class SharedTTSComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Prototype of used voice for TTS.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
|
||||
public ProtoId<TTSVoicePrototype> VoicePrototypeId { get; set; } = "Eugene";
|
||||
}
|
||||
@@ -3,12 +3,7 @@
|
||||
namespace Content.Shared.VoiceMask;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class VoiceMaskChangeVoiceMessage : BoundUserInterfaceMessage
|
||||
public sealed class VoiceMaskChangeVoiceMessage(string voice) : BoundUserInterfaceMessage
|
||||
{
|
||||
public string Voice { get; }
|
||||
|
||||
public VoiceMaskChangeVoiceMessage(string voice)
|
||||
{
|
||||
Voice = voice;
|
||||
}
|
||||
}
|
||||
public string Voice { get; } = voice;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Preferences;
|
||||
|
||||
namespace Content.Shared._White.TTS;
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public sealed class TTSPitchRateSystem : EntitySystem
|
||||
{
|
||||
|
||||
|
||||
@@ -10,28 +10,27 @@ namespace Content.Shared._White.TTS;
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public sealed class TTSVoicePrototype : IPrototype
|
||||
{
|
||||
[IdDataFieldAttribute]
|
||||
[IdDataField]
|
||||
public string ID { get; } = default!;
|
||||
|
||||
[DataField("name")]
|
||||
[DataField]
|
||||
public string Name { get; } = string.Empty;
|
||||
|
||||
[DataField("sex", required: true)]
|
||||
public Sex Sex { get; } = default!;
|
||||
[DataField(required: true)]
|
||||
public Sex Sex { get; }
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("speaker", required: true)]
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField(required: true)]
|
||||
public string Speaker { get; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the species is available "at round start" (In the character editor)
|
||||
/// </summary>
|
||||
[DataField("roundStart")]
|
||||
[DataField]
|
||||
public bool RoundStart { get; } = true;
|
||||
|
||||
[DataField("sponsorOnly")]
|
||||
public bool SponsorOnly { get; } = false;
|
||||
[DataField]
|
||||
public bool SponsorOnly { get; }
|
||||
|
||||
[DataField("borgVoice")]
|
||||
public bool BorgVoice { get; } = false;
|
||||
[DataField]
|
||||
public bool BorgVoice { get; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user