using System.Collections; using System.Linq; using AibisDream.FrameAnimation; using AibisDream.Framework; using AibisDream.SaveSystem; using AibisDream.Utility; using UnityEngine; using UnityEngine.ResourceManagement.AsyncOperations; namespace AibisDream { /// /// 由 FrameAnimationGraph 驱动的 ActorManager 角色实现。 /// Graph 使用 FrameAnimation/{ActorName} 的场景级 Addressable key。 /// public sealed class FrameAnimationActor : AbsActor { private FrameAnimationPlayer _player; private string _currentStateName = string.Empty; private bool _isReady; public override bool IsReady => _isReady; protected override void InitInternal() { _player = GetComponent(); base.InitInternal(); _actorType = ActorType.FrameAnimation; _isReady = false; } public override IEnumerator InitializeAsync() { if (_player == null) { Debug.LogError( $"[FrameAnimationActor] 角色 '{ActorName}' 缺少 FrameAnimationPlayer。", this); yield break; } var graphKey = ConstRef.FrameAnimationGraphPrefix + ActorName; var handle = ResourceSystem.LoadSceneAsync(graphKey); if (!handle.IsValid()) { Debug.LogError( $"[FrameAnimationActor] 角色 '{ActorName}' 无法开始加载 Graph,key='{graphKey}'。", this); yield break; } yield return handle; if (handle.Status != AsyncOperationStatus.Succeeded || handle.Result == null) { Debug.LogError( $"[FrameAnimationActor] 角色 '{ActorName}' 的 Graph 加载失败,key='{graphKey}'。", this); yield break; } var validation = FrameAnimationGraphValidator.Validate(handle.Result); if (validation.HasErrors) { var errors = string.Join( " | ", validation.Issues .Where(issue => issue.Severity == FrameAnimationValidationSeverity.Error) .Select(issue => $"{issue.Code}: {issue.Message}")); Debug.LogError( $"[FrameAnimationActor] 角色 '{ActorName}' 的 Graph 校验失败,key='{graphKey}':{errors}", this); yield break; } if (!_player.TryBindGraph(handle.Result, out var bindError)) { Debug.LogError( $"[FrameAnimationActor] 角色 '{ActorName}' 绑定 Graph 失败,key='{graphKey}', error={bindError}", this); yield break; } _isReady = true; } public override void ChangeState(string stateName) { if (!TryPlay(stateName, false, out var handle)) { return; } handle.RegisterCompleted(result => LogFailedResult(stateName, result)); } public override IEnumerator ChangeStateAsync(string stateName) { if (!TryPlayAsync(stateName, out var awaitable)) { yield break; } yield return awaitable; var handle = awaitable.PlaybackHandle; if (handle.IsCompleted) { LogFailedResult(stateName, handle.Result); } } public override ActorEntrySnapshotDto CaptureEntry() { var entry = new ActorEntrySnapshotDto(); FillBaseEntry(entry); entry.stateName = _currentStateName; return entry; } public override IEnumerator ApplyEntryAsync(ActorEntrySnapshotDto entry) { ApplyAlphaFromEntry(entry); if (string.IsNullOrWhiteSpace(entry.stateName)) { yield break; } if (!TryPlay(entry.stateName, true, out var handle)) { yield break; } // 非循环终态会同步完成;Loop 会继续播放,读档 Barrier 不等待它。 if (handle.IsCompleted) { LogFailedResult(entry.stateName, handle.Result); } } private bool TryPlay( string stateName, bool restoreTerminalState, out FrameAnimationPlaybackHandle handle) { handle = null; if (!CanPlay(stateName)) { return false; } handle = restoreTerminalState ? _player.RestoreTerminalState(stateName) : _player.Play(stateName); if (handle.IsCompleted && handle.Result.Reason == FrameAnimationCompletionReason.Failed) { LogFailedResult(stateName, handle.Result); return false; } _currentStateName = stateName; return true; } private bool TryPlayAsync( string stateName, out FrameAnimationPlaybackAwaitable awaitable) { awaitable = null; if (!CanPlay(stateName)) { return false; } awaitable = _player.PlayAsync(stateName); var handle = awaitable.PlaybackHandle; if (handle.IsCompleted && handle.Result.Reason == FrameAnimationCompletionReason.Failed) { LogFailedResult(stateName, handle.Result); return false; } _currentStateName = stateName; return true; } private bool CanPlay(string stateName) { if (!_isReady || _player == null) { Debug.LogError( $"[FrameAnimationActor] 角色 '{ActorName}' 尚未完成初始化,playable='{stateName}'。", this); return false; } if (string.IsNullOrWhiteSpace(stateName)) { Debug.LogWarning( $"[FrameAnimationActor] 角色 '{ActorName}' 收到空 playable id。", this); return false; } return true; } private void LogFailedResult( string stateName, FrameAnimationPlaybackResult result) { if (result.Reason != FrameAnimationCompletionReason.Failed) { return; } var graphKey = ConstRef.FrameAnimationGraphPrefix + ActorName; Debug.LogError( $"[FrameAnimationActor] 角色 '{ActorName}' 播放失败,Graph='{graphKey}', " + $"playable='{stateName}', error={result.Error}", this); } } }