149 lines
4.5 KiB
C#
149 lines
4.5 KiB
C#
using System;
|
|
using System.Threading;
|
|
using BriarQueen.Data.Identifiers;
|
|
using BriarQueen.Framework.Coordinators.Events;
|
|
using BriarQueen.Framework.Events.Audio;
|
|
using BriarQueen.Framework.Events.UI;
|
|
using Cysharp.Threading.Tasks;
|
|
using VContainer;
|
|
|
|
namespace BriarQueen.Framework.Services.Subtitles
|
|
{
|
|
public class SubtitleService : IDisposable
|
|
{
|
|
private readonly EventCoordinator _eventCoordinator;
|
|
|
|
private CancellationTokenSource _subtitleCts;
|
|
private SubtitleKey _activeSubtitleKey = SubtitleKey.None;
|
|
private string _currentText = string.Empty;
|
|
|
|
public bool IsVisible => _activeSubtitleKey != SubtitleKey.None && !string.IsNullOrWhiteSpace(_currentText);
|
|
public string CurrentText => _currentText;
|
|
|
|
[Inject]
|
|
public SubtitleService(EventCoordinator eventCoordinator)
|
|
{
|
|
_eventCoordinator = eventCoordinator;
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
_eventCoordinator.Subscribe<VoicePlaybackStartedEvent>(OnVoicePlaybackStarted);
|
|
_eventCoordinator.Subscribe<VoicePlaybackFinishedEvent>(OnVoicePlaybackFinished);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_eventCoordinator.Unsubscribe<VoicePlaybackStartedEvent>(OnVoicePlaybackStarted);
|
|
_eventCoordinator.Unsubscribe<VoicePlaybackFinishedEvent>(OnVoicePlaybackFinished);
|
|
CancelCurrentSubtitle();
|
|
ClearSubtitle();
|
|
}
|
|
|
|
public void PlayScriptedSubtitle(SubtitleKey subtitleKey, float durationOverrideSeconds = 0f)
|
|
{
|
|
if (subtitleKey == SubtitleKey.None)
|
|
{
|
|
ClearScriptedSubtitle();
|
|
return;
|
|
}
|
|
|
|
if (!SubtitleIdentifiers.TryGet(subtitleKey, out var entry) || string.IsNullOrWhiteSpace(entry.Text))
|
|
return;
|
|
|
|
var duration = durationOverrideSeconds > 0f
|
|
? durationOverrideSeconds
|
|
: entry.PreferredDurationSeconds;
|
|
|
|
ShowSubtitle(subtitleKey, entry.Text, duration).Forget();
|
|
}
|
|
|
|
public void ClearScriptedSubtitle()
|
|
{
|
|
CancelCurrentSubtitle();
|
|
ClearSubtitle();
|
|
}
|
|
|
|
private void OnVoicePlaybackStarted(VoicePlaybackStartedEvent evt)
|
|
{
|
|
if (evt.SubtitleKey == SubtitleKey.None)
|
|
return;
|
|
|
|
if (!SubtitleIdentifiers.TryGet(evt.SubtitleKey, out var entry) || string.IsNullOrWhiteSpace(entry.Text))
|
|
return;
|
|
|
|
var duration = entry.PreferredDurationSeconds > 0f
|
|
? entry.PreferredDurationSeconds
|
|
: evt.ClipLengthSeconds;
|
|
|
|
ShowSubtitle(evt.SubtitleKey, entry.Text, duration).Forget();
|
|
}
|
|
|
|
private void OnVoicePlaybackFinished(VoicePlaybackFinishedEvent evt)
|
|
{
|
|
if (evt.SubtitleKey == SubtitleKey.None)
|
|
return;
|
|
|
|
if (_activeSubtitleKey != evt.SubtitleKey)
|
|
return;
|
|
|
|
CancelCurrentSubtitle();
|
|
ClearSubtitle();
|
|
}
|
|
|
|
private async UniTaskVoid ShowSubtitle(SubtitleKey subtitleKey, string text, float durationSeconds)
|
|
{
|
|
CancelCurrentSubtitle();
|
|
|
|
_activeSubtitleKey = subtitleKey;
|
|
_currentText = text;
|
|
_subtitleCts = new CancellationTokenSource();
|
|
|
|
_eventCoordinator.PublishImmediate(new SubtitleDisplayChangedEvent(text, true));
|
|
|
|
var safeDuration = Math.Max(0f, durationSeconds);
|
|
if (safeDuration <= 0f)
|
|
return;
|
|
|
|
try
|
|
{
|
|
await UniTask.Delay(
|
|
TimeSpan.FromSeconds(safeDuration),
|
|
DelayType.UnscaledDeltaTime,
|
|
cancellationToken: _subtitleCts.Token);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_activeSubtitleKey == subtitleKey)
|
|
ClearSubtitle();
|
|
}
|
|
|
|
private void CancelCurrentSubtitle()
|
|
{
|
|
if (_subtitleCts == null)
|
|
return;
|
|
|
|
try
|
|
{
|
|
_subtitleCts.Cancel();
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
_subtitleCts.Dispose();
|
|
_subtitleCts = null;
|
|
}
|
|
|
|
private void ClearSubtitle()
|
|
{
|
|
_activeSubtitleKey = SubtitleKey.None;
|
|
_currentText = string.Empty;
|
|
_eventCoordinator.PublishImmediate(new SubtitleDisplayChangedEvent(string.Empty, false));
|
|
}
|
|
}
|
|
}
|