using System; using System.Threading; using System.Threading.Tasks; using AibisDream.Kit; using AibisDream.Utility; using UnityEngine; using Yarn.Unity; namespace AibisDream { public class LineSyncToken { private Action _nextStep; private readonly ITextShown _textShown; public LineInfo lineInfo; public LineSyncState state; public CancellationTokenSource AdvanceDelayToken { get; private set; } public event Action SkipTextAnima; public event Action OnAdvance; public LineSyncToken(LocalizedLine lineInfo, Action nextStep, bool isAutoSkip = false) { this.lineInfo = LineInfo.Generate(lineInfo); _nextStep = nextStep; state = LineSyncState.PlayText; if (this.lineInfo.isAutoSkip && isAutoSkip) { _textShown = new AutoNextTextShown(); } else { _textShown = new DefaultTextShown(); } } public void TrySkip() { if (state == LineSyncState.PlayText) { SkipTextAnima?.Invoke(); SkipTextAnima = null; } else { Debug.Log($"line{lineInfo.lineId} 状态为{state.ToString()}, 不能跳过文本"); } } public void TryAdvance() { if (state == LineSyncState.WaitForAdvance) { Advance(); Dispose(); } else { Debug.Log($"line{lineInfo.lineId} 状态为{state.ToString()}, 不能向前推进"); } } public void ForceAdvance() { // 先中断延时 AdvanceDelayToken?.Cancel(); // 推进 Advance(); Dispose(); } private void Advance() { OnAdvance?.Invoke(); OnAdvance = null; _nextStep?.Invoke(); state = LineSyncState.Advanced; } private void Dispose() { _nextStep = null; SkipTextAnima = null; } public async void TextShown() { AdvanceDelayToken = new CancellationTokenSource(); await _textShown.OnTextShown(this); } } public struct LineInfo { public string lineId; public string lineText; public CharacterVo character; public bool isAutoSkip; public static LineInfo Generate(LocalizedLine dialogueLine) { return new LineInfo { lineId = dialogueLine.TextID, lineText = dialogueLine.TextWithoutCharacterName.Text, character = dialogueLine.GetCharacterVo(), isAutoSkip = dialogueLine.IsAutoSkipLine() }; } public int CalcDelayTime() { var delayTime = lineText.RemoveRichTextTags().Length * ConstRef.CharacterDelayTime; return CommonUtil.Limit(delayTime, ConstRef.LineMaxDelay, ConstRef.LineMinDelay); } } public interface ITextShown { Task OnTextShown(LineSyncToken token); } public class DefaultTextShown : ITextShown { public async Task OnTextShown(LineSyncToken token) { token.state = LineSyncState.AdvanceDelay; await Task.Delay(token.lineInfo.CalcDelayTime(), token.AdvanceDelayToken.Token); token.state = LineSyncState.WaitForAdvance; } } public class AutoNextTextShown : ITextShown { public async Task OnTextShown(LineSyncToken token) { token.state = LineSyncState.AdvanceDelay; await Task.Delay(token.lineInfo.CalcDelayTime(), token.AdvanceDelayToken.Token); token.state = LineSyncState.WaitForAdvance; token.TryAdvance(); } } public enum LineSyncState { Default, PlayText, AdvanceDelay, WaitForAdvance, Advanced } }