using System; using System.Collections.Generic; using System.Linq; using Sirenix.OdinInspector; using UniRx; using UnityEngine; namespace SLSUtilities.Feedback { /// /// 单个反馈序列的完整数据定义,是 Feedback 系统的核心 ScriptableObject。 /// 包含多条轨道(Track),每条轨道包含按时间排列的片段(Clip)。 /// [CreateAssetMenu(fileName = "NewFeedbackData", menuName = "SLS/Feedback/FeedbackData")] public partial class FeedbackData : SerializedScriptableObject { /// /// 父级集合引用,由 FeedbackDataCollection 自动维护。 /// [ReadOnly, ShowInInspector] public FeedbackDataCollection parentCollection; /// /// 用于字典索引的名称,在 FeedbackDataCollection 中按此名称查找。 /// [Title("Editor Settings")] public string feedbackName; /// /// 全局默认的时间设置。Clip 可选择覆盖此设置。 /// public FeedbackTimeSettings defaultTimeSettings = new FeedbackTimeSettings(); /// /// 反馈轨道列表,多条轨道天然并行播放。 /// [Title("Feedback Tracks")] [ListDrawerSettings(ShowFoldout = true, ListElementLabelName = "trackName")] public List tracks = new List(); /// /// 所有轨道的最大时长。 /// public float TotalDuration => tracks.Count > 0 ? tracks.Max(t => t.TotalDuration) : 0f; /// /// 运行时预览:通过 FeedbackManager 播放此反馈。 /// 仅在 Play 模式下可用。 /// [Button("Preview", ButtonSizes.Medium)] [EnableIf("@UnityEngine.Application.isPlaying")] public void Preview() { if (!Application.isPlaying) { Debug.LogWarning("[FeedbackData] Preview is only available in Play mode."); return; } if (FeedbackManager.Instance == null) { Debug.LogWarning("[FeedbackData] Preview failed: FeedbackManager not found in scene. " + "Add a GameObject with FeedbackManager component."); return; } FeedbackPlayer player = FeedbackManager.Instance.Play(this); Debug.Log($"[FeedbackData] Previewing '{feedbackName}' (Duration: {TotalDuration:F2}s)"); } } public partial class FeedbackData { public FeedbackTrack Track(string name) { FeedbackTrack track = tracks.FirstOrDefault(t => t.trackName == name); if (track == null) { Debug.LogWarning($"[FeedbackData] Track '{name}' not found in FeedbackData '{feedbackName}'."); } return track; } public FeedbackClip Clip(string trackName, Func predicate) { FeedbackTrack track = Track(trackName); if (track == null) return null; FeedbackClip clip = track.clips.FirstOrDefault(predicate); if (clip == null) { Debug.LogWarning($"[FeedbackData] Clip matching predicate not found in Track '{trackName}' of FeedbackData '{feedbackName}'."); } return clip; } public FeedbackClip Clip(string trackName) where T : FeedbackActionBase { return Clip(trackName, c => c.action.GetType() == typeof(T)); } public FeedbackClip Clip(string trackName, string clipName) { return Clip(trackName, c => c.clipName == clipName); } public T Action(string trackName) where T : FeedbackActionBase { FeedbackTrack track = Track(trackName); FeedbackClip clip = track?.clips.FirstOrDefault(c => c.action.GetType() == typeof(T)); return clip?.action as T; } } }