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 (!TryPlay(stateName, false, out var handle))
{
yield break;
}
yield return handle;
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 (!_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;
}
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 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);
}
}
}