// using UnityEngine; // // using System; // using System.Collections.Generic; // using Cysharp.Threading.Tasks; // using Cysharp.Threading.Tasks.Triggers; // using TMPro; // using UnityEngine; // using UnityEngine.Pool; // using System.Threading; // using System.Runtime.CompilerServices; // using Cysharp.Text; // // namespace text // { // public static class ZeroGCTypewriterPro // { // #region 核心结构体 // // private struct TypewriterHandle : IEquatable // { // public int InstanceID; // public int Version; // // public bool Equals(TypewriterHandle other) => // InstanceID == other.InstanceID && Version == other.Version; // } // // private struct TypewriterJob // { // public TypewriterHandle Handle; // public TMP_Text Target; // public string Content; // public float Speed; // public int LoopCount; // public Action OnUpdate; // public Action OnComplete; // public CancellationToken ExternalToken; // } // // #endregion // // #region 状态管理 // // private static readonly Dictionary activeJobs = // new Dictionary(32); // // private struct ActiveJob // { // public int Version; // public CancellationTokenSource Cts; // } // // private static readonly ObjectPool ctsPool = // ObjectPool( // createFunc: () => new CancellationTokenSource(), // actionOnRelease: cts => cts.Cancel(), // collectionCheck: false // ); // // #endregion // // #region 公开接口 // // [MethodImpl(MethodImplOptions.AggressiveInlining)] // public static void Play( // this TMP_Text text, // string content, // float charsPerSecond = 30, // int loopCount = 0, // Action onUpdate = null, // Action onComplete = null, // CancellationToken externalToken = default) // { // var instanceID = text.GetInstanceID(); // // // 停止当前任务(如果有) // if (activeJobs.TryGetValue(instanceID, out var existingJob)) // { // ctsPool.Release(existingJob.Cts); // activeJobs.Remove(instanceID); // } // // // 从对象池获取CTS // var cts = ctsPool.Get(); // var linkedToken = CombineTokens( // text.GetCancellationTokenOnDestroy(), // externalToken, // cts.Token // ); // // // 创建新任务 // var newVersion = activeJobs.TryGetValue(instanceID, out var job) ? job.Version + 1 : 1; // // activeJobs[instanceID] = new ActiveJob // { // Version = newVersion, // Cts = cts // }; // // RunJob(new TypewriterJob // { // Handle = new TypewriterHandle // { // InstanceID = instanceID, // Version = newVersion // }, // Target = text, // Content = content, // Speed = Mathf.Max(0.01f, charsPerSecond), // LoopCount = loopCount, // OnUpdate = onUpdate, // OnComplete = onComplete, // ExternalToken = linkedToken // }).Forget(); // } // // [MethodImpl(MethodImplOptions.AggressiveInlining)] // public static void Stop(this TMP_Text text) // { // var instanceID = text.GetInstanceID(); // if (activeJobs.TryGetValue(instanceID, out var job)) // { // ctsPool.Release(job.Cts); // activeJobs.Remove(instanceID); // ResetTextState(text); // } // } // // #endregion // // #region 核心逻辑 // // private static async UniTaskVoid RunJob(TypewriterJob job) // { // try // { // var target = job.Target; // using (var sb = ZString.CreateStringBuilder()) // { // sb.Append(job.Content); // target.text = sb.ToString(); // target.ForceMeshUpdate(); // // int currentLoop = 0; // var chars = sb.AsSpan(); // var interval = 1f / job.Speed; // var timer = 0f; // // while (IsLoopValid(currentLoop, job.LoopCount)) // { // target.maxVisibleCharacters = 0; // // for (int i = 0; i < chars.Length; i++) // { // // 版本校验 // if (!IsHandleValid(job.Handle)) return; // // // 基于时间的更新 // timer += Time.deltaTime; // var required = (int)(timer * job.Speed); // // if (required > i) // { // target.maxVisibleCharacters = required; // job.OnUpdate?.Invoke(required); // } // // await UniTask.Yield(PlayerLoopTiming.Update, job.ExternalToken); // } // // currentLoop++; // timer = 0f; // job.OnComplete?.Invoke(); // } // } // } // finally // { // if (IsHandleValid(job.Handle)) // { // activeJobs.Remove(job.Handle.InstanceID); // ResetTextState(job.Target); // } // } // } // // #endregion // // #region 工具方法 // // [MethodImpl(MethodImplOptions.AggressiveInlining)] // private static bool IsHandleValid(TypewriterHandle handle) // { // return activeJobs.TryGetValue(handle.InstanceID, out var job) && // job.Version == handle.Version; // } // // [MethodImpl(MethodImplOptions.AggressiveInlining)] // private static bool IsLoopValid(int current, int max) => // max < 0 || current <= max; // // private static CancellationToken CombineTokens( // CancellationToken token1, // CancellationToken token2, // CancellationToken token3) // { // if (token1.CanBeCanceled && token2.CanBeCanceled && token3.CanBeCanceled) // return CancellationTokenSource.CreateLinkedTokenSource( // token1, token2, token3).Token; // // if (token1.CanBeCanceled && token2.CanBeCanceled) // return CancellationTokenSource.CreateLinkedTokenSource( // token1, token2).Token; // // return token1.CanBeCanceled ? token1 : token2; // } // // private static void ResetTextState(TMP_Text text) // { // if (text != null) // { // text.maxVisibleCharacters = int.MaxValue; // text.SetVerticesDirty(); // } // } // // private static CancellationToken GetCancellationTokenOnDestroy(this TMP_Text text) // { // return text.gameObject.GetCancellationTokenOnDestroy(); // } // // #endregion // } // // }