-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
<!-- ЭТО ШАБЛОН ВАШЕГО PULL REQUEST. Текст между стрелками - это комментарии - они не будут видны в PR. --> ## Описание PR <!-- Ниже опишите ваш Pull Request. Что он изменяет? На что еще это может повлиять? Постарайтесь описать все внесённые вами изменения! --> Та самая тема, которую я планировал сделать ещё с полгода назад, или раньше. Даёт возможность использовать как голос персонажа не ТТС, а барки. Игроки могут переключаться между тем, что из этого слышать. **Медиа** <!-- Если приемлемо, добавьте скриншоты для демонстрации вашего PR. Если ваш PR представляет собой визуальное изменение, добавьте скриншоты, иначе он может быть закрыт. --> ![image](https://github.com/user-attachments/assets/e34246de-eca6-44e4-b545-b0c51df91ac5) ![image](https://github.com/user-attachments/assets/1ab90804-18e1-49db-9725-398878d7f103) **Проверки** <!-- Выполнение всех следующих действий, если это приемлемо для вида изменений сильно ускорит разбор вашего PR --> - [x] PR полностью завершён и мне не нужна помощь чтобы его закончить. - [x] Я внимательно просмотрел все свои изменения и багов в них не нашёл. - [x] Я запускал локальный сервер со своими изменениями и всё протестировал. - [x] Я добавил скриншот/видео демонстрации PR в игре, **или** этот PR этого не требует. **Изменения** <!-- Здесь вы можете написать список изменений, который будет автоматически добавлен в игру, когда ваш PR будет принят. В журнал изменений следует помещать только то, что действительно важно игрокам. В списке изменений тип значка не является часть предложения, поэтому явно указывайте - Добавлен, Удалён, Изменён. плохо: - add: Новый инструмент для инженеров хорошо: - add: Добавлен новый инструмент для инженеров Вы можете указать своё имя после символа 🆑 именно оно будет отображаться в журнале изменений (иначе будет использоваться ваше имя на GitHub) Например: 🆑 Ian --> 🆑 Котя - add: Добавлена система барков. Вы можете переключить вид сопровождения текста. ТТС - привычная говорилка, Барки - короткие звуки, имитирующие речь. --------- Co-authored-by: Schrödinger <[email protected]>
- Loading branch information
1 parent
d1bdff9
commit f462bb0
Showing
67 changed files
with
5,087 additions
and
17 deletions.
There are no files selected for viewing
90 changes: 90 additions & 0 deletions
90
Content.Client/ADT/Bark/Systems/HumanoidProfileEditor.Barks.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
using System.Linq; | ||
using Content.Client.ADT.SpeechBarks; | ||
using Content.Shared.ADT.SpeechBarks; | ||
|
||
namespace Content.Client.Lobby.UI; | ||
|
||
public sealed partial class HumanoidProfileEditor | ||
{ | ||
private List<BarkPrototype> _barkList = new(); | ||
|
||
private void InitializeBarks() | ||
{ | ||
_barkList = _prototypeManager | ||
.EnumeratePrototypes<BarkPrototype>() | ||
.Where(o => o.RoundStart) | ||
.OrderBy(o => Loc.GetString(o.Name)) | ||
.ToList(); | ||
|
||
BarkProtoButton.OnItemSelected += args => | ||
{ | ||
BarkProtoButton.SelectId(args.Id); | ||
SetBarkProto(_barkList[args.Id].ID); | ||
}; | ||
|
||
PitchEdit.OnTextChanged += args => | ||
{ | ||
if (!float.TryParse(args.Text, out var newPitch)) | ||
return; | ||
|
||
SetBarkPitch(newPitch); | ||
}; | ||
|
||
DelayVariationMinEdit.OnTextChanged += args => | ||
{ | ||
if (!float.TryParse(args.Text, out var newVar)) | ||
return; | ||
|
||
SetBarkMinVariation(newVar); | ||
}; | ||
|
||
DelayVariationMaxEdit.OnTextChanged += args => | ||
{ | ||
if (!float.TryParse(args.Text, out var newVar)) | ||
return; | ||
|
||
SetBarkMaxVariation(newVar); | ||
}; | ||
|
||
BarkPlayButton.OnPressed += _ => PlayPreviewBark(); | ||
} | ||
|
||
private void UpdateBarkVoicesControls() | ||
{ | ||
if (Profile is null) | ||
return; | ||
|
||
BarkProtoButton.Clear(); | ||
|
||
PitchEdit.Text = Profile.BarkPitch.ToString(); | ||
DelayVariationMinEdit.Text = Profile.BarkLowVar.ToString(); | ||
DelayVariationMaxEdit.Text = Profile.BarkHighVar.ToString(); | ||
|
||
var firstVoiceChoiceId = 1; | ||
for (var i = 0; i < _barkList.Count; i++) | ||
{ | ||
var voice = _barkList[i]; | ||
|
||
var name = Loc.GetString(voice.Name); | ||
BarkProtoButton.AddItem(name, i); | ||
|
||
if (firstVoiceChoiceId == 1) | ||
firstVoiceChoiceId = i; | ||
} | ||
|
||
var voiceChoiceId = _barkList.FindIndex(x => x.ID == Profile.BarkProto); | ||
if (!BarkProtoButton.TrySelectId(voiceChoiceId) && | ||
BarkProtoButton.TrySelectId(firstVoiceChoiceId)) | ||
{ | ||
SetBarkProto(_barkList[firstVoiceChoiceId].ID); | ||
} | ||
} | ||
|
||
private void PlayPreviewBark() | ||
{ | ||
if (Profile is null) | ||
return; | ||
|
||
_entManager.System<SpeechBarksSystem>().PlayDataPrewiew(Profile.BarkProto, Profile.BarkPitch, Profile.BarkLowVar, Profile.BarkHighVar); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
using Robust.Shared.Prototypes; | ||
using Robust.Shared.Random; | ||
using Content.Shared.ADT.SpeechBarks; | ||
using Content.Shared.Chat; | ||
using Robust.Shared.Player; | ||
using Robust.Client.Audio; | ||
using Robust.Shared.Audio; | ||
using Robust.Shared.Audio.Systems; | ||
using Robust.Shared.Configuration; | ||
using System.Threading.Tasks; | ||
using Robust.Client.ResourceManagement; | ||
using Robust.Shared.Utility; | ||
using Robust.Client.Player; | ||
using Content.Shared.ADT.CCVar; | ||
using Robust.Shared.Timing; | ||
using Content.Shared.Corvax.CCCVars; | ||
using Robust.Client.Audio.Effects; | ||
using Robust.Shared.Audio.Effects; | ||
|
||
namespace Content.Client.ADT.SpeechBarks; | ||
|
||
public sealed class SpeechBarksSystem : SharedSpeechBarksSystem | ||
{ | ||
[Dependency] private readonly IRobustRandom _random = default!; | ||
[Dependency] private readonly IConfigurationManager _cfg = default!; | ||
[Dependency] private readonly AudioSystem _audio = default!; | ||
[Dependency] private readonly IPrototypeManager _proto = default!; | ||
[Dependency] private readonly IPlayerManager _player = default!; | ||
[Dependency] private readonly IGameTiming _time = default!; | ||
|
||
public override void Initialize() | ||
{ | ||
base.Initialize(); | ||
|
||
_cfg.OnValueChanged(ADTCCVars.BarksVolume, OnVolumeChanged, true); | ||
|
||
SubscribeNetworkEvent<PlaySpeechBarksEvent>(OnEntitySpoke); | ||
} | ||
|
||
public override void Shutdown() | ||
{ | ||
base.Shutdown(); | ||
_cfg.UnsubValueChanged(ADTCCVars.BarksVolume, OnVolumeChanged); | ||
} | ||
|
||
private readonly List<string> _sampleText = | ||
new() | ||
{ | ||
"Тест мессЭдж 1.", | ||
"Тест мессЭдж 2!", | ||
"Тест мессЭдж 3?", | ||
"Здесь был котя." | ||
}; | ||
|
||
private const float MinimalVolume = -10f; | ||
private float _volume = 0.0f; | ||
private const float WhisperFade = 4f; | ||
|
||
private void OnVolumeChanged(float volume) | ||
{ | ||
_volume = volume; | ||
} | ||
|
||
private float AdjustVolume(bool isWhisper) | ||
{ | ||
var volume = MinimalVolume + SharedAudioSystem.GainToVolume(_volume); | ||
|
||
if (isWhisper) | ||
{ | ||
volume -= SharedAudioSystem.GainToVolume(WhisperFade); | ||
} | ||
|
||
return volume; | ||
} | ||
|
||
private float AdjustDistance(bool isWhisper) | ||
{ | ||
return isWhisper ? SharedChatSystem.WhisperMuffledRange : SharedChatSystem.VoiceRange; | ||
} | ||
|
||
private async void OnEntitySpoke(PlaySpeechBarksEvent ev) | ||
{ | ||
if (_cfg.GetCVar(ADTCCVars.ReplaceTTSWithBarks) == false) | ||
return; | ||
|
||
if (ev.Message == null) | ||
return; | ||
|
||
if (ev.Source != null) | ||
{ | ||
var audioParams = AudioParams.Default | ||
.WithVolume(AdjustVolume(ev.IsWhisper)) | ||
.WithMaxDistance(AdjustDistance(ev.IsWhisper)) | ||
.WithPlayOffset(0f) | ||
.WithReferenceDistance(100f); | ||
|
||
if (ev.Message.EndsWith('!')) | ||
audioParams = audioParams.WithVolume(audioParams.Volume * 1.2f); | ||
|
||
var audioResource = new AudioResource(); | ||
string str = ev.Sound; | ||
|
||
var path = new ResPath(str); | ||
audioResource.Load(IoCManager.Instance!, path); | ||
|
||
var count = (int)ev.Message.Length / 3f; | ||
|
||
for (var i = 0; i < count; i++) | ||
{ | ||
if (_player.LocalSession == null) | ||
break; | ||
var entity = GetEntity(ev.Source.Value); | ||
if (entity == EntityUid.Invalid || _player.LocalEntity == null) | ||
continue; | ||
if (Deleted(entity) || Terminating(entity)) | ||
continue; | ||
if (!HasComp<TransformComponent>(entity) || !HasComp<TransformComponent>(_player.LocalEntity.Value)) | ||
continue; | ||
if (Transform(entity).Coordinates.TryDistance(EntityManager, Transform(_player.LocalEntity.Value).Coordinates, out var distance) && | ||
distance > SharedChatSystem.VoiceRange) | ||
continue; | ||
|
||
_audio.PlayEntity(audioResource.AudioStream, entity, audioParams.WithPitchScale(_random.NextFloat(ev.Pitch - 0.1f, ev.Pitch + 0.1f))); | ||
|
||
await Task.Delay(TimeSpan.FromSeconds(_random.NextFloat(ev.LowVar, ev.HighVar))); | ||
} | ||
|
||
} | ||
} | ||
|
||
public async void PlayDataPrewiew(string protoId, float pitch, float lowVar, float highVar) | ||
{ | ||
if (!_proto.TryIndex<BarkPrototype>(protoId, out var proto)) | ||
return; | ||
|
||
var message = _random.Pick(_sampleText); | ||
|
||
var audioParams = AudioParams.Default | ||
.WithVolume(AdjustVolume(false)); | ||
|
||
var count = (int)message.Length / 3f; | ||
var audioResource = new AudioResource(); | ||
string str = proto.Sound; | ||
|
||
if (message.EndsWith('!')) | ||
audioParams = audioParams.WithVolume(audioParams.Volume * 1.2f); | ||
|
||
var path = new ResPath(str); | ||
audioResource.Load(IoCManager.Instance!, path); | ||
|
||
for (var i = 0; i < count; i++) | ||
{ | ||
if (_player.LocalSession == null) | ||
break; | ||
|
||
_audio.PlayGlobal(str, _player.LocalSession, audioParams.WithPitchScale(_random.NextFloat(pitch - 0.1f, pitch + 0.1f))); | ||
|
||
await Task.Delay(TimeSpan.FromSeconds(_random.NextFloat(lowVar, highVar))); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.