Skip to content

Commit

Permalink
Барки (#216)
Browse files Browse the repository at this point in the history
<!-- ЭТО ШАБЛОН ВАШЕГО 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
FaDeOkno and Schrodinger71 authored Aug 13, 2024
1 parent d1bdff9 commit f462bb0
Show file tree
Hide file tree
Showing 67 changed files with 5,087 additions and 17 deletions.
90 changes: 90 additions & 0 deletions Content.Client/ADT/Bark/Systems/HumanoidProfileEditor.Barks.cs
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);
}
}
161 changes: 161 additions & 0 deletions Content.Client/ADT/Bark/Systems/SpeechBarksSystem.cs
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)));
}
}
}
1 change: 1 addition & 0 deletions Content.Client/Audio/ContentAudioSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
public const float LobbyMultiplier = 3f;
public const float InterfaceMultiplier = 2f;
public const float TtsMultiplier = 3f; // Corvax-TTS
public const float BarksMultiplier = 8f; // Corvax-TTS

public override void Initialize()
{
Expand Down
4 changes: 4 additions & 0 deletions Content.Client/Corvax/TTS/TTSSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Robust.Shared.Utility;
using Content.Shared.ADT.Language; // ADT Languages
using Robust.Shared.Player;
using Content.Shared.ADT.CCVar;

namespace Content.Client.Corvax.TTS;

Expand Down Expand Up @@ -69,6 +70,9 @@ private void OnTtsVolumeChanged(float volume)

private void OnPlayTTS(PlayTTSEvent ev)
{
if (_cfg.GetCVar(ADTCCVars.ReplaceTTSWithBarks) == true) // ADT Barks
return;

_sawmill.Verbose($"Play TTS audio {ev.Data.Length} bytes from {ev.SourceUid} entity");

var filePath = new ResPath($"{_fileIdx++}.ogg");
Expand Down
20 changes: 20 additions & 0 deletions Content.Client/Lobby/UI/HumanoidProfileEditor.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,26 @@
<Control HorizontalExpand="True"/>
<OptionButton Name="SpawnPriorityButton" HorizontalAlignment="Right" />
</BoxContainer>
<!-- ADT-Barks-Start -->
<BoxContainer HorizontalExpand="True" Visible="False" Name="BarksContainer">
<Label Text="{Loc 'humanoid-profile-editor-bark-label'}" />
<Control HorizontalExpand="True"/>
<OptionButton Name="BarkProtoButton" HorizontalAlignment="Right" />
<Button Name="BarkPlayButton" Text="{Loc 'humanoid-profile-editor-voice-play'}" MaxWidth="80" />
</BoxContainer>
<BoxContainer HorizontalExpand="True" Visible="False" Name="BarksPitchContainer">
<Label Text="{Loc 'humanoid-profile-editor-bark-pitch-label'}" />
<Control HorizontalExpand="True"/>
<LineEdit Name="PitchEdit" MinSize="40 0" HorizontalAlignment="Right" Margin="2 0 2 0" />
</BoxContainer>
<BoxContainer HorizontalExpand="True" Visible="False" Name="BarksDelayContainer">
<Label Text="{Loc 'humanoid-profile-editor-bark-delay-label'}" />
<Control HorizontalExpand="True"/>
<LineEdit Name="DelayVariationMinEdit" MinSize="40 0" HorizontalAlignment="Right" Margin="2 0 2 0" />
<LineEdit Name="DelayVariationMaxEdit" MinSize="40 0" HorizontalAlignment="Right" Margin="2 0 2 0" />
</BoxContainer>
<!-- ADT-Barks-End -->

<!-- Corvax-TTS-Start -->
<BoxContainer HorizontalExpand="True" Visible="False" Name="TTSContainer">
<Label Text="{Loc 'humanoid-profile-editor-voice-label'}" />
Expand Down
46 changes: 46 additions & 0 deletions Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
using Content.Client.Sprite;
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Systems.Guidebook;
using Content.Shared.ADT.CCVar;
using Content.Shared.ADT.SpeechBarks;
using Content.Shared.CCVar;
using Content.Shared.Clothing;
using Content.Shared.Corvax.CCCVars;
Expand Down Expand Up @@ -225,6 +227,20 @@ public HumanoidProfileEditor(
#endregion
// Corvax-TTS-End

// ADT Barks Start
#region Voice

if (configurationManager.GetCVar(ADTCCVars.BarksEnabled))
{
BarksContainer.Visible = true;
BarksPitchContainer.Visible = true;
BarksDelayContainer.Visible = true;
InitializeBarks();
}

#endregion
// ADT Barks End

RefreshSpecies();

SpeciesButton.OnItemSelected += args =>
Expand Down Expand Up @@ -455,6 +471,7 @@ public HumanoidProfileEditor(
SpeciesInfoButton.OnPressed += OnSpeciesInfoButtonPressed;

UpdateSpeciesGuidebookIcon();
ReloadPreview();
IsDirty = false;
}

Expand Down Expand Up @@ -766,6 +783,7 @@ public void SetProfile(HumanoidCharacterProfile? profile, int? slot)
UpdateSaveButton();
UpdateMarkings();
UpdateTTSVoicesControls(); // Corvax-TTS
UpdateBarkVoicesControls(); // ADT Barks
UpdateHairPickers();
UpdateCMarkingsHair();
UpdateCMarkingsFacialHair();
Expand Down Expand Up @@ -1215,6 +1233,34 @@ private void SetVoice(string newVoice)
}
// Corvax-TTS-End

private void SetBarkProto(string prototype)
{
Profile = Profile?.WithBarkProto(prototype);
ReloadPreview();
SetDirty();
}

private void SetBarkPitch(float pitch)
{
Profile = Profile?.WithBarkPitch(Math.Clamp(pitch, _cfgManager.GetCVar(ADTCCVars.BarksMinPitch), _cfgManager.GetCVar(ADTCCVars.BarksMaxPitch)));
ReloadPreview();
SetDirty();
}

private void SetBarkMinVariation(float variation)
{
Profile = Profile?.WithBarkMinVariation(Math.Clamp(variation, _cfgManager.GetCVar(ADTCCVars.BarksMinDelay), Profile.BarkHighVar));
ReloadPreview();
SetDirty();
}

private void SetBarkMaxVariation(float variation)
{
Profile = Profile?.WithBarkMaxVariation(Math.Clamp(variation, Profile.BarkLowVar, _cfgManager.GetCVar(ADTCCVars.BarksMaxDelay)));
ReloadPreview();
SetDirty();
}

private void SetSpecies(string newSpecies)
{
Profile = Profile?.WithSpecies(newSpecies);
Expand Down
Loading

0 comments on commit f462bb0

Please sign in to comment.