@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.RhythmGame;
|
||||
using Unity.Profiling;
|
||||
|
||||
namespace Ichni
|
||||
{
|
||||
@@ -41,6 +42,20 @@ namespace Ichni
|
||||
private const int PhaseStep = 10;
|
||||
|
||||
private static readonly UpdatePhase[] AllPhases = (UpdatePhase[])Enum.GetValues(typeof(UpdatePhase));
|
||||
private static readonly ProfilerMarker[] PhaseMarkers =
|
||||
{
|
||||
new ProfilerMarker("Ichni.UpdateScheduler.TimeDuration"),
|
||||
new ProfilerMarker("Ichni.UpdateScheduler.Animation"),
|
||||
new ProfilerMarker("Ichni.UpdateScheduler.Apply"),
|
||||
new ProfilerMarker("Ichni.UpdateScheduler.SplineRebuild"),
|
||||
new ProfilerMarker("Ichni.UpdateScheduler.TrackCore"),
|
||||
new ProfilerMarker("Ichni.UpdateScheduler.TrackFollower"),
|
||||
new ProfilerMarker("Ichni.UpdateScheduler.Note"),
|
||||
new ProfilerMarker("Ichni.UpdateScheduler.Effect"),
|
||||
new ProfilerMarker("Ichni.UpdateScheduler.Misc")
|
||||
};
|
||||
private static readonly ProfilerMarker DirtyMarkMarker =
|
||||
new ProfilerMarker("Ichni.UpdateScheduler.DirtyMark");
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -56,6 +71,7 @@ namespace Ichni
|
||||
/// <summary>将 UpdatePhase 枚举值转换为数组索引。</summary>
|
||||
private static int PhaseIndex(UpdatePhase phase) => (int)phase / PhaseStep;
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region [轨道 Spline 列表] Track Spline List
|
||||
@@ -65,6 +81,13 @@ namespace Ichni
|
||||
|
||||
#endregion
|
||||
|
||||
#region [Apply Dirty Queues]
|
||||
|
||||
private readonly List<IHaveColorSubmodule> _dirtyColorSubmodules = new List<IHaveColorSubmodule>(256);
|
||||
private readonly List<IHaveTransformSubmodule> _dirtyTransformSubmodules = new List<IHaveTransformSubmodule>(256);
|
||||
|
||||
#endregion
|
||||
|
||||
#region [缓存] Cached State
|
||||
|
||||
/// <summary>TickEarly 中缓存的 songTime,供 TickLate 使用</summary>
|
||||
@@ -121,6 +144,48 @@ namespace Ichni
|
||||
_trackSplines.Remove(track);
|
||||
}
|
||||
|
||||
public void RegisterDirtyColor(IHaveColorSubmodule target)
|
||||
{
|
||||
if (target == null || target.colorSubmodule == null || target.colorSubmodule.queuedForApply)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
target.colorSubmodule.queuedForApply = true;
|
||||
_dirtyColorSubmodules.Add(target);
|
||||
}
|
||||
|
||||
public void RegisterDirtyTransform(IHaveTransformSubmodule target)
|
||||
{
|
||||
if (target == null || target.transformSubmodule == null || target.transformSubmodule.queuedForApply)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
target.transformSubmodule.queuedForApply = true;
|
||||
_dirtyTransformSubmodules.Add(target);
|
||||
}
|
||||
|
||||
public void UnregisterDirtyColor(IHaveColorSubmodule target)
|
||||
{
|
||||
if (target?.colorSubmodule != null)
|
||||
{
|
||||
target.colorSubmodule.queuedForApply = false;
|
||||
}
|
||||
|
||||
_dirtyColorSubmodules.Remove(target);
|
||||
}
|
||||
|
||||
public void UnregisterDirtyTransform(IHaveTransformSubmodule target)
|
||||
{
|
||||
if (target?.transformSubmodule != null)
|
||||
{
|
||||
target.transformSubmodule.queuedForApply = false;
|
||||
}
|
||||
|
||||
_dirtyTransformSubmodules.Remove(target);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region [主循环 - 早期阶段] TickEarly (Update)
|
||||
@@ -138,13 +203,19 @@ namespace Ichni
|
||||
_cachedSongTime = songTime;
|
||||
|
||||
// ─── Phase 0: TimeDuration(Legacy timeDurations 列表)─────────────────
|
||||
TickTimeDurationLegacy(songTime);
|
||||
using (PhaseMarkers[PhaseIndex(UpdatePhase.TimeDuration)].Auto())
|
||||
{
|
||||
TickTimeDurationLegacy(songTime);
|
||||
}
|
||||
|
||||
// ─── Phase 1: Animation ──────────────────────────────────────────────
|
||||
TickPhase(UpdatePhase.Animation, songTime);
|
||||
|
||||
// ─── Phase 2: Apply(Color + Transform from active lists)────────────
|
||||
TickApplyLegacy();
|
||||
using (PhaseMarkers[PhaseIndex(UpdatePhase.Apply)].Auto())
|
||||
{
|
||||
TickApplyLegacy();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -160,36 +231,49 @@ namespace Ichni
|
||||
// DirtyMark:保持原有 isStarting || isPlaying 条件,与 TickEarly 的 isUpdating 独立判断
|
||||
if (GameManager.Instance.songPlayer.isStarting || GameManager.Instance.songPlayer.isPlaying)
|
||||
{
|
||||
TickDirtyMarkLegacy();
|
||||
using (DirtyMarkMarker.Auto())
|
||||
{
|
||||
TickDirtyMarkLegacy();
|
||||
}
|
||||
}
|
||||
|
||||
if (!_isUpdating) return;
|
||||
float songTime = _cachedSongTime;
|
||||
|
||||
// ─── Phase 3: SplineRebuild(占位)───────────────────────────────────
|
||||
// SplineComputer 使用默认 UpdateMode.Update,已在 Update 中自行处理。
|
||||
TickPhase(UpdatePhase.SplineRebuild, songTime);
|
||||
// ─── Phase 3: SplineRebuild ──────────────────────────────────────────
|
||||
using (PhaseMarkers[PhaseIndex(UpdatePhase.SplineRebuild)].Auto())
|
||||
{
|
||||
TickTrackSplines();
|
||||
TickPhaseElements(UpdatePhase.SplineRebuild, songTime);
|
||||
}
|
||||
|
||||
// ─── Phase 4: TrackCore ──────────────────────────────────────────────
|
||||
TickPhase(UpdatePhase.TrackCore, songTime);
|
||||
|
||||
// ─── Phase 5: TrackFollower ──────────────────────────────────────────
|
||||
TickPhase(UpdatePhase.TrackFollower, songTime);
|
||||
|
||||
// 清除轨道 refreshedThisFrame 标记(TrackManager 保留此单一职责)
|
||||
GameManager.Instance.trackManager.ManualLateUpdate(songTime);
|
||||
using (PhaseMarkers[PhaseIndex(UpdatePhase.TrackFollower)].Auto())
|
||||
{
|
||||
TickPhaseElements(UpdatePhase.TrackFollower, songTime);
|
||||
GameManager.Instance.trackManager.ManualLateUpdate(songTime);
|
||||
}
|
||||
|
||||
// ─── Phase 6: Note(由 NoteManager 内部驱动)─────────────────────────
|
||||
TickPhase(UpdatePhase.Note, songTime);
|
||||
GameManager.Instance.noteManager.ManualUpdate(songTime);
|
||||
GameManager.Instance.noteManager.ManualLateUpdate(songTime);
|
||||
using (PhaseMarkers[PhaseIndex(UpdatePhase.Note)].Auto())
|
||||
{
|
||||
TickPhaseElements(UpdatePhase.Note, songTime);
|
||||
GameManager.Instance.noteManager.ManualUpdate(songTime);
|
||||
GameManager.Instance.noteManager.ManualLateUpdate(songTime);
|
||||
}
|
||||
|
||||
// ─── Phase 7: Effect ─────────────────────────────────────────────────
|
||||
TickPhase(UpdatePhase.Effect, songTime);
|
||||
|
||||
// ─── Phase 8: Misc ───────────────────────────────────────────────────
|
||||
TickPhase(UpdatePhase.Misc, songTime);
|
||||
GameManager.Instance.beatmapContainer?.ExecuteLowPriorityActions();
|
||||
using (PhaseMarkers[PhaseIndex(UpdatePhase.Misc)].Auto())
|
||||
{
|
||||
TickPhaseElements(UpdatePhase.Misc, songTime);
|
||||
GameManager.Instance.beatmapContainer?.ExecuteLowPriorityActions();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -201,6 +285,14 @@ namespace Ichni
|
||||
/// 倒序遍历防止更新途中元素自行销毁导致越界。
|
||||
/// </summary>
|
||||
private void TickPhase(UpdatePhase phase, float songTime)
|
||||
{
|
||||
using (PhaseMarkers[PhaseIndex(phase)].Auto())
|
||||
{
|
||||
TickPhaseElements(phase, songTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void TickPhaseElements(UpdatePhase phase, float songTime)
|
||||
{
|
||||
var list = _phaseElements[PhaseIndex(phase)];
|
||||
for (int i = list.Count - 1; i >= 0; i--)
|
||||
@@ -213,6 +305,27 @@ namespace Ichni
|
||||
}
|
||||
}
|
||||
|
||||
private void TickTrackSplines()
|
||||
{
|
||||
for (int i = _trackSplines.Count - 1; i >= 0; i--)
|
||||
{
|
||||
Track track = _trackSplines[i];
|
||||
if (track == null)
|
||||
{
|
||||
_trackSplines.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!track.isActiveAndEnabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
track.trackPathSubmodule?.path?.RunManualUpdate();
|
||||
track.trackRendererSubmodule?.meshGenerator?.RunManualUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region [Legacy] 过渡期内联逻辑
|
||||
@@ -235,17 +348,38 @@ namespace Ichni
|
||||
/// </summary>
|
||||
private void TickApplyLegacy()
|
||||
{
|
||||
var activeColorSubmodules = GameManager.Instance.activeColorSubmodules;
|
||||
var activeTransformSubmodules = GameManager.Instance.activeTransformSubmodules;
|
||||
|
||||
for (int i = 0; i < activeColorSubmodules.Count; i++)
|
||||
int colorCount = _dirtyColorSubmodules.Count;
|
||||
for (int i = 0; i < colorCount; i++)
|
||||
{
|
||||
activeColorSubmodules[i].UpdateColor(true);
|
||||
IHaveColorSubmodule target = _dirtyColorSubmodules[i];
|
||||
if (target?.colorSubmodule == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
target.colorSubmodule.queuedForApply = false;
|
||||
target.UpdateColor(true);
|
||||
}
|
||||
if (colorCount > 0)
|
||||
{
|
||||
_dirtyColorSubmodules.RemoveRange(0, Math.Min(colorCount, _dirtyColorSubmodules.Count));
|
||||
}
|
||||
|
||||
for (int i = 0; i < activeTransformSubmodules.Count; i++)
|
||||
int transformCount = _dirtyTransformSubmodules.Count;
|
||||
for (int i = 0; i < transformCount; i++)
|
||||
{
|
||||
activeTransformSubmodules[i].UpdateTransform(true);
|
||||
IHaveTransformSubmodule target = _dirtyTransformSubmodules[i];
|
||||
if (target?.transformSubmodule == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
target.transformSubmodule.queuedForApply = false;
|
||||
target.UpdateTransform(true);
|
||||
}
|
||||
if (transformCount > 0)
|
||||
{
|
||||
_dirtyTransformSubmodules.RemoveRange(0, Math.Min(transformCount, _dirtyTransformSubmodules.Count));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user