using System;
using System.Collections.Generic;
using UnityEngine;
namespace SLSUtilities.Feedback
{
///
/// 反馈播放器状态枚举。
///
public enum FeedbackPlayerState
{
Idle,
Playing,
Paused
}
///
/// 运行时反馈播放器(纯 C# 类,非 MonoBehaviour),管理一个 FeedbackData 的播放生命周期。
/// 由 FeedbackManager 的 Update 集中驱动,也可由外部(如 FeedbackSubcontroller)手动驱动。
///
public class FeedbackPlayer
{
private const float MIN_DURATION = 0.001f;
private FeedbackData _data;
private FeedbackPlayerState _state;
private float _currentTime;
private IFeedbackTimeProvider _timeProvider;
private Transform _ownerTransform;
private bool _isCompleted;
// 每个 Clip 的运行时状态
private enum ClipState { Pending, Active, Finished }
private ClipState[,] _clipStates; // [trackIndex, clipIndex]
private float[,] _clipElapsedTimes; // [trackIndex, clipIndex]
private bool _hasSoloTracks;
public FeedbackData Data => _data;
public FeedbackPlayerState State => _state;
public float CurrentTime => _currentTime;
public IFeedbackTimeProvider TimeProvider => _timeProvider;
public Transform OwnerTransform => _ownerTransform;
///
/// 播放完毕事件。
///
public event Action OnComplete;
///
/// 被打断事件。
///
public event Action OnInterrupt;
///
/// 是否已播放完毕(自然结束)。
///
public bool IsCompleted => _isCompleted;
///
/// 是否处于活跃状态(Playing 或 Paused)。
///
public bool IsActive => _state == FeedbackPlayerState.Playing || _state == FeedbackPlayerState.Paused;
public FeedbackPlayer(FeedbackData data, IFeedbackTimeProvider timeProvider, Transform ownerTransform)
{
_data = data;
_timeProvider = timeProvider;
_ownerTransform = ownerTransform;
_state = FeedbackPlayerState.Idle;
_currentTime = 0f;
_isCompleted = false;
}
///
/// 开始播放。
///
public void Play()
{
if (_data == null)
{
Debug.LogWarning("[FeedbackPlayer] Cannot play: FeedbackData is null.");
return;
}
_currentTime = 0f;
_isCompleted = false;
_state = FeedbackPlayerState.Playing;
InitializeClipStates();
}
///
/// 暂停播放。
///
public void Pause()
{
if (_state == FeedbackPlayerState.Playing)
{
_state = FeedbackPlayerState.Paused;
}
}
///
/// 恢复播放。
///
public void Resume()
{
if (_state == FeedbackPlayerState.Paused)
{
_state = FeedbackPlayerState.Playing;
}
}
///
/// 立即停止并复位所有已启动的 Action。
///
public void Stop()
{
if (_state == FeedbackPlayerState.Idle) return;
InterruptAllActiveClips();
_state = FeedbackPlayerState.Idle;
OnInterrupt?.Invoke();
ClearEvents();
}
///
/// 每帧由外部驱动调用(FeedbackManager 或 Subcontroller)。
///
public void Tick(float unscaledDeltaTime)
{
if (_state != FeedbackPlayerState.Playing) return;
if (_data == null || _data.tracks == null) return;
float totalDuration = _data.TotalDuration;
// 处理 TotalDuration 为 0 的边界情况
if (totalDuration <= 0f)
{
_state = FeedbackPlayerState.Idle;
_isCompleted = true;
OnComplete?.Invoke();
ClearEvents();
return;
}
List tracks = _data.tracks;
for (int trackIdx = 0; trackIdx < tracks.Count; trackIdx++)
{
FeedbackTrack track = tracks[trackIdx];
if (!ShouldPlayTrack(track)) continue;
for (int clipIdx = 0; clipIdx < track.clips.Count; clipIdx++)
{
FeedbackClip clip = track.clips[clipIdx];
if (clip?.action == null) continue;
float clipDeltaTime = ComputeClipDeltaTime(clip, unscaledDeltaTime);
ProcessClip(trackIdx, clipIdx, clip, clipDeltaTime);
}
}
_currentTime += unscaledDeltaTime;
if (_currentTime >= totalDuration)
{
_state = FeedbackPlayerState.Idle;
_isCompleted = true;
OnComplete?.Invoke();
ClearEvents();
}
}
///
/// 清除所有事件订阅,防止完成/停止后残留引用。
///
private void ClearEvents()
{
OnComplete = null;
OnInterrupt = null;
}
///
/// 初始化所有 Clip 的运行时状态数组。
///
private void InitializeClipStates()
{
List tracks = _data.tracks;
if (tracks == null || tracks.Count == 0) return;
int maxClips = 0;
_hasSoloTracks = false;
for (int i = 0; i < tracks.Count; i++)
{
if (tracks[i].clips != null && tracks[i].clips.Count > maxClips)
maxClips = tracks[i].clips.Count;
if (tracks[i].solo)
_hasSoloTracks = true;
}
_clipStates = new ClipState[tracks.Count, maxClips];
_clipElapsedTimes = new float[tracks.Count, maxClips];
}
///
/// 判断轨道是否应该播放:处理 Mute 和 Solo 逻辑。
///
private bool ShouldPlayTrack(FeedbackTrack track)
{
if (track.mute) return false;
if (_hasSoloTracks && !track.solo) return false;
return true;
}
///
/// 根据 Clip 的时间设置计算实际 deltaTime。
///
private float ComputeClipDeltaTime(FeedbackClip clip, float unscaledDeltaTime)
{
if (_timeProvider == null) return unscaledDeltaTime;
FeedbackTimeSettings settings = clip.overrideTimeSettings
? clip.timeSettings
: _data.defaultTimeSettings;
if (settings == null || !settings.useTimeScale) return unscaledDeltaTime;
return _timeProvider.GetDeltaTime(settings);
}
///
/// 处理单个 Clip 的生命周期状态转换和回调调用。
///
private void ProcessClip(int trackIdx, int clipIdx, FeedbackClip clip, float deltaTime)
{
ref ClipState clipState = ref _clipStates[trackIdx, clipIdx];
ref float elapsed = ref _clipElapsedTimes[trackIdx, clipIdx];
float safeDuration = Mathf.Max(clip.duration, MIN_DURATION);
switch (clipState)
{
case ClipState.Pending:
if (_currentTime >= clip.startTime)
{
clipState = ClipState.Active;
elapsed = _currentTime - clip.startTime;
FeedbackContext ctx = CreateContext(deltaTime, elapsed, safeDuration);
clip.action.OnStart(ctx);
float normalizedTime = Mathf.Clamp01(elapsed / safeDuration);
clip.action.OnUpdate(CreateContext(deltaTime, elapsed, safeDuration), normalizedTime);
}
break;
case ClipState.Active:
elapsed += deltaTime;
if (elapsed >= safeDuration)
{
elapsed = safeDuration;
clipState = ClipState.Finished;
FeedbackContext ctx = CreateContext(deltaTime, elapsed, safeDuration);
clip.action.OnUpdate(ctx, 1f);
clip.action.OnEnd(ctx);
}
else
{
float normalizedTime = Mathf.Clamp01(elapsed / safeDuration);
FeedbackContext ctx = CreateContext(deltaTime, elapsed, safeDuration);
clip.action.OnUpdate(ctx, normalizedTime);
}
break;
case ClipState.Finished:
break;
}
}
///
/// 打断所有已激活的 Clip,调用其 OnInterrupt 进行复位。
///
private void InterruptAllActiveClips()
{
if (_data?.tracks == null || _clipStates == null) return;
List tracks = _data.tracks;
for (int trackIdx = 0; trackIdx < tracks.Count; trackIdx++)
{
if (tracks[trackIdx].clips == null) continue;
for (int clipIdx = 0; clipIdx < tracks[trackIdx].clips.Count; clipIdx++)
{
if (_clipStates[trackIdx, clipIdx] == ClipState.Active)
{
FeedbackClip clip = tracks[trackIdx].clips[clipIdx];
if (clip?.action == null) continue;
float elapsed = _clipElapsedTimes[trackIdx, clipIdx];
float safeDuration = Mathf.Max(clip.duration, MIN_DURATION);
FeedbackContext ctx = CreateContext(0f, elapsed, safeDuration);
clip.action.OnInterrupt(ctx);
}
_clipStates[trackIdx, clipIdx] = ClipState.Finished;
}
}
}
///
/// 创建 FeedbackContext 实例。
///
private FeedbackContext CreateContext(float deltaTime, float elapsedTime, float duration)
{
return new FeedbackContext
{
player = this,
owner = _ownerTransform,
deltaTime = deltaTime,
elapsedTime = elapsedTime,
duration = duration
};
}
}
}