From 2078ca82301c6b8e00310ef3dab6e45f95097a0b Mon Sep 17 00:00:00 2001 From: "J. Scott" Date: Tue, 21 Jul 2026 22:10:27 +0200 Subject: [PATCH 1/3] Add onReplaySeeked API callback --- src/Core/ReplayPlayback.cs | 11 ++++++++--- src/Replay/ReplayAPI.cs | 6 ++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Core/ReplayPlayback.cs b/src/Core/ReplayPlayback.cs index 471e657..4d2dde4 100644 --- a/src/Core/ReplayPlayback.cs +++ b/src/Core/ReplayPlayback.cs @@ -106,7 +106,7 @@ public void HandlePlayback() if (elapsedPlaybackTime >= currentReplay.Frames[^1].Time) { - SetPlaybackTime(currentReplay.Frames[^1].Time); + UpdatePlayback(currentReplay.Frames[^1].Time); if (Main.instance.StopReplayWhenDone.Value) StopReplay(); @@ -116,7 +116,7 @@ public void HandlePlayback() if (elapsedPlaybackTime <= 0f) { - SetPlaybackTime(0f); + UpdatePlayback(0f); if (Main.instance.StopReplayWhenDone.Value) StopReplay(); @@ -124,7 +124,7 @@ public void HandlePlayback() return; } - SetPlaybackTime(elapsedPlaybackTime); + UpdatePlayback(elapsedPlaybackTime); ReplayPlaybackControls.timeline?.GetComponent()?.material?.SetFloat("_BP_Current", elapsedPlaybackTime * 1000f); @@ -1579,6 +1579,11 @@ public void SetPlaybackFrame(int frame) } public void SetPlaybackTime(float time) + { + UpdatePlayback(time); + } + + public void UpdatePlayback(float time) { float oldTime = elapsedPlaybackTime; diff --git a/src/Replay/ReplayAPI.cs b/src/Replay/ReplayAPI.cs index fe28f49..39e824c 100644 --- a/src/Replay/ReplayAPI.cs +++ b/src/Replay/ReplayAPI.cs @@ -60,6 +60,11 @@ public static class ReplayAPI /// Invoked when the playback time changes (seek or progression). /// public static event Action onReplayTimeChanged; + + /// + /// Invoked when the playback time changes (seek only). + /// + public static event Action onReplaySeeked; /// /// Invoked when playback is paused or resumed, along with the new toggle state. @@ -126,6 +131,7 @@ private static void InvokeSafe(Delegate action, params object[] args) internal static void RecordingStartedInternal() => InvokeSafe(onRecordingStarted); internal static void RecordingStoppedInternal() => InvokeSafe(onRecordingStopped); internal static void ReplayTimeChangedInternal(float time) => InvokeSafe(onReplayTimeChanged, time); + internal static void ReplaySeekedInternal(float time) => InvokeSafe(onReplaySeeked, time); internal static void ReplayPauseChangedInternal(bool paused) => InvokeSafe(onReplayPauseChanged, paused); internal static void OnPlaybackFrameInternal(Frame frame, Frame nextFrame) => InvokeSafe(OnPlaybackFrame, frame, nextFrame); From 40af8bc5afdaed58e8c3874168c6ff5cf1d190b8 Mon Sep 17 00:00:00 2001 From: "J. Scott" Date: Tue, 21 Jul 2026 22:13:13 +0200 Subject: [PATCH 2/3] Add onSpeedChanged API callback --- src/Core/ReplayPlayback.cs | 2 ++ src/Replay/ReplayAPI.cs | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Core/ReplayPlayback.cs b/src/Core/ReplayPlayback.cs index 4d2dde4..ccb5fb9 100644 --- a/src/Core/ReplayPlayback.cs +++ b/src/Core/ReplayPlayback.cs @@ -1553,6 +1553,8 @@ public void SetPlaybackSpeed(float newSpeed) ReplayPlaybackControls.playbackSpeedText.text = label; ReplayPlaybackControls.playbackSpeedText.ForceMeshUpdate(); } + + ReplayAPI.ReplaySpeedChangedInternal(newSpeed); } public void AddPlaybackSpeed(float delta, float minSpeed = -8f, float maxSpeed = 8f) diff --git a/src/Replay/ReplayAPI.cs b/src/Replay/ReplayAPI.cs index 39e824c..2fde1ad 100644 --- a/src/Replay/ReplayAPI.cs +++ b/src/Replay/ReplayAPI.cs @@ -66,6 +66,11 @@ public static class ReplayAPI /// public static event Action onReplaySeeked; + /// + /// Invoked when the playback speed changes. + /// + public static event Action onSpeedChanged; + /// /// Invoked when playback is paused or resumed, along with the new toggle state. /// @@ -133,7 +138,7 @@ private static void InvokeSafe(Delegate action, params object[] args) internal static void ReplayTimeChangedInternal(float time) => InvokeSafe(onReplayTimeChanged, time); internal static void ReplaySeekedInternal(float time) => InvokeSafe(onReplaySeeked, time); internal static void ReplayPauseChangedInternal(bool paused) => InvokeSafe(onReplayPauseChanged, paused); - + internal static void ReplaySpeedChangedInternal(float time) => InvokeSafe(onSpeedChanged, time); internal static void OnPlaybackFrameInternal(Frame frame, Frame nextFrame) => InvokeSafe(OnPlaybackFrame, frame, nextFrame); internal static void OnRecordFrameInternal(Frame frame, bool isBuffer) => InvokeSafe(OnRecordFrame, frame, isBuffer); From 2ab30e5b4cf47c690bf6f37903b49c9844aad47f Mon Sep 17 00:00:00 2001 From: "J. Scott" Date: Tue, 21 Jul 2026 22:14:02 +0200 Subject: [PATCH 3/3] Add onCloneSpawned API callback --- src/Core/ReplayPlayback.cs | 2 ++ src/Replay/ReplayAPI.cs | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/Core/ReplayPlayback.cs b/src/Core/ReplayPlayback.cs index ccb5fb9..89663cb 100644 --- a/src/Core/ReplayPlayback.cs +++ b/src/Core/ReplayPlayback.cs @@ -606,6 +606,8 @@ private IEnumerator SpawnClones(Action done = null) temp.gameObject.SetActive(true); PlaybackPlayers[i] = temp; temp.Controller.transform.SetParent(replayPlayers.transform); + + ReplayAPI.CloneSpawnedInternal(temp); } done?.Invoke(); diff --git a/src/Replay/ReplayAPI.cs b/src/Replay/ReplayAPI.cs index 2fde1ad..834325a 100644 --- a/src/Replay/ReplayAPI.cs +++ b/src/Replay/ReplayAPI.cs @@ -103,6 +103,11 @@ public static class ReplayAPI /// public static event Action onReplayRenamed; + /// + /// Invoked as a clone is spawned or reset. + /// + public static event Action onCloneSpawned; + private static void InvokeSafe(Delegate action, params object[] args) { if (action == null) @@ -146,6 +151,8 @@ private static void InvokeSafe(Delegate action, params object[] args) internal static void ReplayDeletedInternal(string path) => InvokeSafe(onReplayDeleted, path); internal static void ReplayRenamedInternal(ReplaySerializer.ReplayHeader header, string newPath) => InvokeSafe(onReplayRenamed, header, newPath); + internal static void CloneSpawnedInternal(ReplayPlayback.Clone clone) => InvokeSafe(onCloneSpawned, clone); + /// /// Gets whether a recording is currently active. /// This is enabled when a user manually starts recording.