576 lines
23 KiB
C#
576 lines
23 KiB
C#
#if UNITY_EDITOR
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using UnityEngine;
|
||
using UnityEditor;
|
||
using Sirenix.OdinInspector;
|
||
using Sirenix.OdinInspector.Editor;
|
||
using UnityEditor.Callbacks;
|
||
|
||
namespace SLSUtilities.FunctionalAnimation
|
||
{
|
||
public class FuncAnimEditorWindow : OdinEditorWindow
|
||
{
|
||
// 定义一个菜单项来打开这个窗口
|
||
[MenuItem("Tools/SLS Utilities/Functional Animation Editor")]
|
||
private static void OpenWindow()
|
||
{
|
||
GetWindow<FuncAnimEditorWindow>().Show();
|
||
}
|
||
|
||
[Title("技能数据编辑器")] [ShowInInspector, AssetsOnly, PropertyOrder(-100)] [LabelText("当前编辑的技能")] [OnValueChanged("OnDataChanged")]
|
||
// 当我们选择新的Data时,触发
|
||
public FuncAnimData targetData;
|
||
|
||
// ----------------- 内联数据编辑器 -----------------
|
||
|
||
[ShowInInspector, PropertyOrder(1)]
|
||
[ShowIf("targetData")] // 只有在选择了 targetData 时才显示
|
||
[InlineEditor(Expanded = true, ObjectFieldMode = InlineEditorObjectFieldModes.Hidden)]
|
||
public FuncAnimData dataEditor;
|
||
|
||
private enum DragMode
|
||
{
|
||
None,
|
||
Event,
|
||
IntervalLeft,
|
||
IntervalRight,
|
||
IntervalMove
|
||
}
|
||
|
||
private DragMode currentDragMode = DragMode.None;
|
||
private int draggingEventIndex = -1;
|
||
private int draggingIntervalIndex = -1; // 现在代表 interval 列表的索引
|
||
|
||
private bool isDirty = false;
|
||
|
||
// (修改) 新的布局常量
|
||
private const float RULER_HEIGHT = 20f; // 标尺的高度
|
||
private const float TRACK_HEIGHT = 22f; // 每个区间轨道的高度 (含2px间距)
|
||
private const float TRACK_LABEL_WIDTH = 120f; // 轨道标签的宽度
|
||
private const float DRAG_HANDLE_WIDTH = 5f;
|
||
|
||
// 颜色缓存
|
||
private static Dictionary<Type, Color> eventColorCache = new Dictionary<Type, Color>();
|
||
// ----------------- 自定义时间轴 GUI -----------------
|
||
|
||
// 双击资产时打开自定义编辑器窗口
|
||
[OnOpenAsset(1)]
|
||
public static bool OnOpenAsset(int instanceID, int line)
|
||
{
|
||
FuncAnimData funcAnimData = EditorUtility.InstanceIDToObject(instanceID) as FuncAnimData;
|
||
if (funcAnimData != null)
|
||
{
|
||
OpenWindow();
|
||
var window = GetWindow<FuncAnimEditorWindow>();
|
||
window.targetData = funcAnimData;
|
||
window.OnDataChanged();
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
[OnInspectorGUI]
|
||
[PropertyOrder(-99)]
|
||
[ShowIf("targetData")]
|
||
private void DrawTimelineGUI()
|
||
{
|
||
if (targetData.animationClip == null)
|
||
{
|
||
EditorGUILayout.HelpBox("请为 FuncAnimData 指定一个 AnimationClip。", MessageType.Warning);
|
||
return;
|
||
}
|
||
|
||
AutoSetupPayloadNames(this.targetData);
|
||
|
||
float duration = targetData.animationClip.length;
|
||
if (duration <= 0) duration = 1f; // 避免除零
|
||
float frameRate = targetData.animationClip.frameRate;
|
||
|
||
int numIntervalTracks = (targetData.intervals != null) ? targetData.intervals.Count : 0;
|
||
float totalHeight = RULER_HEIGHT + (numIntervalTracks * TRACK_HEIGHT);
|
||
|
||
Rect totalArea = GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, GUILayout.Height(totalHeight));
|
||
|
||
// --- (核心布局修改) ---
|
||
Rect trackLabelHeaderArea = new Rect(totalArea.x, totalArea.y, TRACK_LABEL_WIDTH, RULER_HEIGHT);
|
||
|
||
// (修改) 标尺区域现在向右偏移,与轨道对齐
|
||
Rect rulerArea = new Rect(
|
||
totalArea.x + TRACK_LABEL_WIDTH,
|
||
totalArea.y,
|
||
totalArea.width - TRACK_LABEL_WIDTH,
|
||
RULER_HEIGHT
|
||
);
|
||
|
||
// (修改) 轨道总区域也需要偏移,但它由 DrawIntervalTracks 内部处理
|
||
Rect allTracksArea = new Rect(
|
||
totalArea.x,
|
||
totalArea.y + RULER_HEIGHT,
|
||
totalArea.width,
|
||
totalHeight - RULER_HEIGHT
|
||
);
|
||
// --- (修改结束) ---
|
||
|
||
// 绘制背景 (给左上角标尺头也画上背景)
|
||
DrawTimelineBackground(totalArea);
|
||
EditorGUI.DrawRect(trackLabelHeaderArea, new Color(0.18f, 0.18f, 0.18f));
|
||
|
||
DrawTicks(rulerArea, duration, frameRate); // 刻度画在 *新* 的 rulerArea
|
||
DrawIntervalTracks(allTracksArea, duration); // 区间 (内部已处理偏移)
|
||
DrawEvents(totalArea, rulerArea, duration); // 事件画在 *新* 的 rulerArea
|
||
|
||
HandleMouseInput(totalArea, rulerArea, allTracksArea, duration);
|
||
|
||
if (isDirty)
|
||
{
|
||
Repaint();
|
||
isDirty = false;
|
||
}
|
||
|
||
if (FuncAnimData.EditorWantsRepaint)
|
||
{
|
||
FuncAnimData.EditorWantsRepaint = false;
|
||
Repaint();
|
||
}
|
||
|
||
GUILayout.Space(10);
|
||
}
|
||
|
||
private void DrawTimelineBackground(Rect area)
|
||
{
|
||
EditorGUI.DrawRect(area, new Color(0.18f, 0.18f, 0.18f));
|
||
}
|
||
|
||
private void DrawIntervalTracks(Rect allTracksArea, float duration)
|
||
{
|
||
if (targetData.intervals == null) return;
|
||
|
||
float currentY = allTracksArea.y;
|
||
|
||
for (int i = 0; i < targetData.intervals.Count; i++)
|
||
{
|
||
var interval = targetData.intervals[i];
|
||
|
||
Rect rowRect = new Rect(allTracksArea.x, currentY, allTracksArea.width, TRACK_HEIGHT);
|
||
Rect labelRect = new Rect(rowRect.x, rowRect.y, TRACK_LABEL_WIDTH, rowRect.height - 2);
|
||
Rect trackRect = new Rect(rowRect.x + TRACK_LABEL_WIDTH, rowRect.y, rowRect.width - TRACK_LABEL_WIDTH, rowRect.height - 2);
|
||
|
||
EditorGUI.DrawRect(trackRect, new Color(0.25f, 0.25f, 0.25f));
|
||
|
||
string label = interval.GetIntervalLabel();
|
||
GUIStyle labelStyle = new GUIStyle(EditorStyles.label);
|
||
if (i == draggingIntervalIndex)
|
||
{
|
||
labelStyle.fontStyle = FontStyle.Bold;
|
||
labelStyle.normal.textColor = Color.yellow;
|
||
}
|
||
|
||
EditorGUI.LabelField(labelRect, label, labelStyle);
|
||
|
||
// --- (核心数据修改) ---
|
||
// (修改) 直接使用秒
|
||
float startTime = interval.timeRange.x;
|
||
float endTime = interval.timeRange.y;
|
||
// --- (修改结束) ---
|
||
|
||
// (不变) 这里的归一化是 *为了绘制*,所以是正确的
|
||
float startX = trackRect.x + (startTime / duration) * trackRect.width;
|
||
float endX = trackRect.x + (endTime / duration) * trackRect.width;
|
||
float width = Math.Max(0, endX - startX);
|
||
|
||
Rect intervalBarRect = new Rect(startX, trackRect.y, width, trackRect.height);
|
||
|
||
Color color = GetColorForIntervalType(interval.intervalType);
|
||
if (i == draggingIntervalIndex) color *= 1.5f;
|
||
|
||
EditorGUI.DrawRect(intervalBarRect, color);
|
||
|
||
currentY += TRACK_HEIGHT;
|
||
}
|
||
}
|
||
|
||
// (修改)
|
||
private void DrawEvents(Rect totalArea, Rect rulerArea, float duration)
|
||
{
|
||
if (targetData.eventCollection.animEvents == null) return;
|
||
|
||
GUIStyle labelStyle = new GUIStyle(EditorStyles.miniLabel);
|
||
|
||
for (int i = 0; i < targetData.eventCollection.animEvents.Count; i++)
|
||
{
|
||
var evt = targetData.eventCollection.animEvents[i];
|
||
if (evt.payload == null) continue;
|
||
|
||
float triggerTime = evt.triggerTime;
|
||
float normalizedTime = Mathf.Clamp01(triggerTime / duration);
|
||
|
||
// --- (核心布局修改) ---
|
||
// (修改) X 坐标现在基于 rulerArea
|
||
float xPos = rulerArea.x + normalizedTime * rulerArea.width;
|
||
// --- (修改结束) ---
|
||
|
||
Type payloadType = evt.payload.GetType();
|
||
Color baseColor = GetColorForEventType(payloadType);
|
||
if (evt.isEnd) baseColor = new Color(1f, 0.3f, 1f);
|
||
|
||
Color finalColor = (i == draggingEventIndex) ? Color.yellow : baseColor;
|
||
|
||
// (修改) 标记线从标尺顶部开始
|
||
Rect eventMarkerRect = new Rect(xPos - 1, rulerArea.y, 2, totalArea.height - rulerArea.y);
|
||
EditorGUI.DrawRect(eventMarkerRect, finalColor);
|
||
|
||
string label = string.IsNullOrEmpty(evt.payload.eventName) ? payloadType.Name : evt.payload.eventName;
|
||
if (evt.isEnd) label = "[END] " + label;
|
||
|
||
Rect labelRect = new Rect(xPos + 3, rulerArea.y, 100, rulerArea.height);
|
||
labelStyle.normal.textColor = finalColor;
|
||
GUI.Label(labelRect, label, labelStyle);
|
||
|
||
GUI.Label(eventMarkerRect, new GUIContent("", label));
|
||
}
|
||
}
|
||
|
||
private void DrawTicks(Rect rulerArea, float duration, float frameRate)
|
||
{
|
||
// (不变) 此方法已基于 rulerArea,所以无需修改
|
||
if (duration <= 0) return;
|
||
Handles.color = Color.gray;
|
||
int numTicks = Mathf.FloorToInt(duration / 0.5f);
|
||
for (int i = 0; i <= numTicks; i++)
|
||
{
|
||
float time = i * 0.5f;
|
||
float xPos = rulerArea.x + (time / duration) * rulerArea.width;
|
||
Handles.DrawLine(new Vector3(xPos, rulerArea.y), new Vector3(xPos, rulerArea.yMax));
|
||
GUI.Label(new Rect(xPos + 3, rulerArea.y, 50, 20), $"{time:F1}s");
|
||
}
|
||
|
||
string totalTimeLabel = $"{duration:F2}s ({duration * frameRate:F0}f)";
|
||
GUI.Label(new Rect(rulerArea.xMax - 80, rulerArea.y, 80, 20), totalTimeLabel);
|
||
}
|
||
|
||
private Color GetColorForIntervalType(IntervalType type)
|
||
{
|
||
// (此方法与上一阶段完全相同,为节省空间已折叠)
|
||
switch (type)
|
||
{
|
||
case IntervalType.Cancellable: return new Color(1.0f, 1.0f, 0.5f, 0.6f);
|
||
case IntervalType.Startup: return new Color(1.0f, 0.5f, 0.5f, 0.6f);
|
||
case IntervalType.ExternalDisruption: return new Color(0.5f, 0.0f, 0.5f, 0.6f);
|
||
case IntervalType.Active: return new Color(0.5f, 1.0f, 0.5f, 0.6f);
|
||
case IntervalType.ActionDisruption: return new Color(0.5f, 0.5f, 1.0f, 0.6f);
|
||
case IntervalType.MovementDisruption: return new Color(1.0f, 0.5f, 1.0f, 0.6f);
|
||
case IntervalType.Invincible: return new Color(0.5f, 1.0f, 1.0f, 0.6f);
|
||
case IntervalType.RootMotion: return new Color(1.0f, 0.5f, 0.0f, 0.6f);
|
||
case IntervalType.Preinput: return new Color(0.0f, 0.5f, 1.0f, 0.6f);
|
||
case IntervalType.Custom: return new Color(0.7f, 0.7f, 0.7f, 0.6f);
|
||
default: return new Color(0.7f, 0.7f, 0.7f, 0.6f);
|
||
}
|
||
}
|
||
|
||
// 当 targetData 改变时,更新 dataEditor 的引用
|
||
private void OnDataChanged()
|
||
{
|
||
dataEditor = targetData;
|
||
}
|
||
|
||
private void HandleMouseInput(Rect totalArea, Rect rulerArea, Rect allTracksArea, float duration)
|
||
{
|
||
Event e = Event.current;
|
||
Vector2 mousePos = e.mousePosition;
|
||
|
||
if (!totalArea.Contains(mousePos))
|
||
{
|
||
if (e.type == EventType.MouseUp)
|
||
{
|
||
/* ... 重置拖拽 ... */
|
||
}
|
||
|
||
EditorGUIUtility.AddCursorRect(totalArea, MouseCursor.Arrow);
|
||
return;
|
||
}
|
||
|
||
// --- 1. (修改) 更新光标 ---
|
||
UpdateMouseCursor(totalArea, rulerArea, allTracksArea, mousePos, duration, e.control);
|
||
|
||
// --- 2. (修改) 鼠标按下 ---
|
||
if (e.type == EventType.MouseDown && e.button == 0)
|
||
{
|
||
Undo.RecordObject(targetData, "Modify FuncAnim Timeline");
|
||
|
||
// (修改) 检查事件 (使用 rulerArea)
|
||
int eventIndex = GetEventAt(rulerArea, mousePos, duration);
|
||
if (eventIndex != -1)
|
||
{
|
||
currentDragMode = DragMode.Event;
|
||
draggingEventIndex = eventIndex;
|
||
isDirty = true;
|
||
e.Use();
|
||
return;
|
||
}
|
||
|
||
// (不变) 检查区间
|
||
(int intervalIndex, DragMode dragMode, Rect trackRect) = GetIntervalAt(allTracksArea, mousePos, duration, e.control);
|
||
if (intervalIndex != -1)
|
||
{
|
||
currentDragMode = dragMode;
|
||
draggingIntervalIndex = intervalIndex;
|
||
isDirty = true;
|
||
e.Use();
|
||
return;
|
||
}
|
||
|
||
// ... (重置拖拽) ...
|
||
}
|
||
|
||
// --- 3. (修改) 鼠标拖拽 ---
|
||
if (e.type == EventType.MouseDrag && currentDragMode != DragMode.None)
|
||
{
|
||
float mouseTime = 0;
|
||
|
||
if (currentDragMode == DragMode.Event)
|
||
{
|
||
// (修改) 基于 rulerArea 计算时间
|
||
if (rulerArea.width <= 0) return;
|
||
mouseTime = Mathf.Clamp((mousePos.x - rulerArea.x) / rulerArea.width * duration, 0, duration);
|
||
var evt = targetData.eventCollection.animEvents[draggingEventIndex];
|
||
evt.triggerTime = SnapToFrame(mouseTime, duration);
|
||
}
|
||
else // 处理区间
|
||
{
|
||
Rect trackRect = GetTrackRect(allTracksArea, draggingIntervalIndex);
|
||
if (trackRect.width <= 0) return;
|
||
|
||
mouseTime = Mathf.Clamp((mousePos.x - trackRect.x) / trackRect.width * duration, 0, duration);
|
||
|
||
// --- (核心数据修改) ---
|
||
// (修改) 计算绝对时间增量
|
||
float mouseDeltaTime = (e.delta.x / trackRect.width) * duration;
|
||
// --- (修改结束) ---
|
||
|
||
var interval = targetData.intervals[draggingIntervalIndex];
|
||
|
||
switch (currentDragMode)
|
||
{
|
||
case DragMode.IntervalMove:
|
||
// (修改) 使用绝对时间
|
||
float newTimeX = interval.timeRange.x + mouseDeltaTime;
|
||
float newTimeY = interval.timeRange.y + mouseDeltaTime;
|
||
if (newTimeX < 0)
|
||
{
|
||
float offset = -newTimeX;
|
||
newTimeX += offset;
|
||
newTimeY += offset;
|
||
}
|
||
|
||
if (newTimeY > duration)
|
||
{
|
||
float offset = newTimeY - duration;
|
||
newTimeX -= offset;
|
||
newTimeY -= offset;
|
||
}
|
||
|
||
interval.timeRange.x = SnapToFrame(newTimeX, duration);
|
||
interval.timeRange.y = SnapToFrame(newTimeY, duration);
|
||
break;
|
||
case DragMode.IntervalLeft:
|
||
// (修改) 使用绝对时间
|
||
float newLeftTime = SnapToFrame(mouseTime, duration);
|
||
interval.timeRange.x = Mathf.Min(newLeftTime, interval.timeRange.y);
|
||
break;
|
||
case DragMode.IntervalRight:
|
||
// (修改) 使用绝对时间
|
||
float newRightTime = SnapToFrame(mouseTime, duration);
|
||
interval.timeRange.y = Mathf.Max(newRightTime, interval.timeRange.x);
|
||
break;
|
||
}
|
||
|
||
targetData.intervals[draggingIntervalIndex] = interval;
|
||
}
|
||
|
||
EditorUtility.SetDirty(targetData);
|
||
isDirty = true;
|
||
e.Use();
|
||
}
|
||
|
||
// --- 4. (不变) 鼠标松开 ---
|
||
if (e.type == EventType.MouseUp && e.button == 0)
|
||
{
|
||
currentDragMode = DragMode.None;
|
||
draggingEventIndex = -1;
|
||
draggingIntervalIndex = -1;
|
||
isDirty = true;
|
||
e.Use();
|
||
}
|
||
}
|
||
|
||
// --- (重构) 辅助方法 ---
|
||
|
||
// (修改)
|
||
private int GetEventAt(Rect rulerArea, Vector2 mousePos, float duration)
|
||
{
|
||
if (targetData.eventCollection.animEvents == null) return -1;
|
||
|
||
for (int i = targetData.eventCollection.animEvents.Count - 1; i >= 0; i--)
|
||
{
|
||
float triggerTime = targetData.eventCollection.animEvents[i].triggerTime;
|
||
float normalizedTime = Mathf.Clamp01(triggerTime / duration);
|
||
|
||
// (修改) 基于 rulerArea
|
||
float xPos = rulerArea.x + normalizedTime * rulerArea.width;
|
||
|
||
if (Mathf.Abs(mousePos.x - xPos) <= DRAG_HANDLE_WIDTH)
|
||
{
|
||
return i;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
private Rect GetTrackRect(Rect allTracksArea, int trackIndex)
|
||
{
|
||
return new Rect(
|
||
allTracksArea.x + TRACK_LABEL_WIDTH,
|
||
allTracksArea.y + (trackIndex * TRACK_HEIGHT),
|
||
allTracksArea.width - TRACK_LABEL_WIDTH,
|
||
TRACK_HEIGHT - 2
|
||
);
|
||
}
|
||
|
||
// (修改)
|
||
private (int, DragMode, Rect) GetIntervalAt(Rect allTracksArea, Vector2 mousePos, float duration, bool isCtrlPressed)
|
||
{
|
||
if (targetData.intervals == null || duration <= 0) return (-1, DragMode.None, Rect.zero);
|
||
if (!allTracksArea.Contains(mousePos)) return (-1, DragMode.None, Rect.zero);
|
||
|
||
float yInTracks = mousePos.y - allTracksArea.y;
|
||
int trackIndex = Mathf.FloorToInt(yInTracks / TRACK_HEIGHT);
|
||
if (trackIndex < 0 || trackIndex >= targetData.intervals.Count) return (-1, DragMode.None, Rect.zero);
|
||
|
||
var interval = targetData.intervals[trackIndex];
|
||
Rect trackRect = GetTrackRect(allTracksArea, trackIndex);
|
||
|
||
// --- (核心数据修改) ---
|
||
// (修改) 使用 timeRange (秒) 并归一化 *用于点击检测*
|
||
float startX = trackRect.x + (interval.timeRange.x / duration) * trackRect.width;
|
||
float endX = trackRect.x + (interval.timeRange.y / duration) * trackRect.width;
|
||
// --- (修改结束) ---
|
||
|
||
if (mousePos.x >= trackRect.x && mousePos.x <= trackRect.xMax)
|
||
{
|
||
if (mousePos.x >= startX && mousePos.x <= endX)
|
||
{
|
||
if (isCtrlPressed) return (trackIndex, DragMode.IntervalMove, trackRect);
|
||
if (mousePos.x - startX <= DRAG_HANDLE_WIDTH) return (trackIndex, DragMode.IntervalLeft, trackRect);
|
||
if (endX - mousePos.x <= DRAG_HANDLE_WIDTH) return (trackIndex, DragMode.IntervalRight, trackRect);
|
||
return (trackIndex, DragMode.IntervalMove, trackRect);
|
||
}
|
||
}
|
||
|
||
return (-1, DragMode.None, Rect.zero);
|
||
}
|
||
|
||
// (修改)
|
||
private void UpdateMouseCursor(Rect totalArea, Rect rulerArea, Rect allTracksArea, Vector2 mousePos, float duration, bool isCtrlPressed)
|
||
{
|
||
// (修改) 使用 rulerArea
|
||
if (GetEventAt(rulerArea, mousePos, duration) != -1)
|
||
{
|
||
EditorGUIUtility.AddCursorRect(totalArea, MouseCursor.MoveArrow);
|
||
return;
|
||
}
|
||
|
||
(int intervalIndex, DragMode dragMode, Rect trackRect) = GetIntervalAt(allTracksArea, mousePos, duration, isCtrlPressed);
|
||
if (intervalIndex != -1)
|
||
{
|
||
if (dragMode == DragMode.IntervalLeft || dragMode == DragMode.IntervalRight)
|
||
{
|
||
EditorGUIUtility.AddCursorRect(totalArea, MouseCursor.ResizeHorizontal);
|
||
}
|
||
else
|
||
{
|
||
EditorGUIUtility.AddCursorRect(totalArea, MouseCursor.MoveArrow);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
EditorGUIUtility.AddCursorRect(totalArea, MouseCursor.Arrow);
|
||
}
|
||
|
||
// 将时间吸附到最近的帧上
|
||
private float SnapToFrame(float time, float duration)
|
||
{
|
||
if (!targetData.animationClip) return time;
|
||
float frameRate = targetData.animationClip.frameRate;
|
||
if (frameRate <= 0) return time;
|
||
|
||
float frameDuration = 1.0f / frameRate;
|
||
int frame = Mathf.RoundToInt(time / frameDuration);
|
||
return Mathf.Clamp(frame * frameDuration, 0, duration);
|
||
}
|
||
|
||
// (全新) 辅助方法:获取事件类型对应的颜色
|
||
private Color GetColorForEventType(Type type)
|
||
{
|
||
if (eventColorCache.TryGetValue(type, out Color color))
|
||
{
|
||
return color;
|
||
}
|
||
|
||
// 没找到,通过反射查找 Attribute
|
||
var attr = type.GetCustomAttribute<EventColorAttribute>();
|
||
color = attr?.Color ?? Color.red; // 默认颜色
|
||
|
||
eventColorCache[type] = color;
|
||
return color;
|
||
}
|
||
|
||
private void AutoSetupPayloadNames(FuncAnimData data) // <-- (修改) 接收 data 参数
|
||
{
|
||
if (data == null) return; // <-- (新增) 安全检查
|
||
|
||
// 1. 处理简单的 Payload 列表
|
||
AutoNamePayloadList(data.eventCollection.startEvents, "Start");
|
||
AutoNamePayloadList(data.eventCollection.disruptionEvents, "Disruption");
|
||
AutoNamePayloadList(data.eventCollection.updateEvents, "Update");
|
||
AutoNamePayloadList(data.eventCollection.updateUntilEvents, "UpdateUntil");
|
||
|
||
// 2. 处理嵌套的列表 (timelineEvents)
|
||
if (data.eventCollection.animEvents != null) // (修改) 使用 data.
|
||
{
|
||
AutoNamePayloadList(data.eventCollection.animEvents.Select(e => e.payload).ToList(), "Anim");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 遍历一个Payload列表,为所有eventName为空的条目命名
|
||
/// (这个方法无需修改)
|
||
/// </summary>
|
||
private void AutoNamePayloadList<T>(List<T> list, string prefix) where T : FuncAnimPayloadBase
|
||
{
|
||
if (list == null || list.Count == 0) return;
|
||
|
||
var typeCounts = new Dictionary<Type, int>();
|
||
|
||
foreach (var payload in list)
|
||
{
|
||
if (payload == null) continue;
|
||
|
||
Type payloadType = payload.GetType();
|
||
typeCounts.TryGetValue(payloadType, out int currentCount);
|
||
|
||
if (string.IsNullOrEmpty(payload.eventName))
|
||
{
|
||
payload.eventName = $"{prefix}{payloadType.Name}{currentCount}";
|
||
}
|
||
|
||
typeCounts[payloadType] = currentCount + 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
#endif |