app.hypergames.hypersdk 1.11.0-beta.3 → 1.11.0-beta.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +208 -0
  2. package/Editor/Scripts/Inspectors/HyperSDKSettingsEditor.cs +15 -0
  3. package/HyperLoader.unity +2 -2
  4. package/Runtime/Internal/Bootstrap/HyperLoader.cs +5 -1
  5. package/Runtime/Internal/Core/HyperRuntime.cs +88 -10
  6. package/Runtime/Internal/Managers/BackendManager.cs +26 -3
  7. package/Runtime/Internal/Managers/DataManager.cs +10 -1
  8. package/Runtime/Internal/Managers/EventManager.cs +7 -1
  9. package/Runtime/Internal/Managers/GameManager.cs +85 -50
  10. package/Runtime/Internal/Managers/ReplayManager.cs +5 -1
  11. package/Runtime/Internal/Managers/TimeManager.cs +46 -14
  12. package/Runtime/Internal/Replay/ReplaySessionState.cs +75 -7
  13. package/Runtime/Internal/ScriptableObjects/HyperSDKSettings.cs +10 -0
  14. package/Runtime/Internal/UI/Components/ReplayController.cs +217 -35
  15. package/Runtime/Internal/UI/Components/ReplaySeekOverlay.cs +18 -0
  16. package/Runtime/Internal/UI/Components/ReplaySeekOverlay.cs.meta +2 -0
  17. package/Runtime/Internal/UI/Modals/ReplayPausedModal.cs +153 -0
  18. package/Runtime/Internal/UI/Modals/ReplayPausedModal.cs.meta +2 -0
  19. package/Runtime/Internal/UI/Modals/StartingInstructionModal.cs +2 -1
  20. package/Runtime/Public/Core/HyperSDK.cs +16 -0
  21. package/Runtime/Public/Replay/ReplayPlaybackEngine.cs +127 -3
  22. package/Runtime/Resources/Fonts/Nunito/Nunito-Bold SDF.asset +500 -457
  23. package/Runtime/Resources/Fonts/Wonder Boys/Wonder Boys.asset +394 -379
  24. package/Runtime/Resources/HyperSDKSettings.asset +2 -0
  25. package/Runtime/Resources/Sprites/Buttons/Hyper Long White Button_Normal.png +0 -0
  26. package/Runtime/Resources/Sprites/Buttons/Hyper Long White Button_Normal.png.meta +156 -0
  27. package/Runtime/Resources/Sprites/Buttons/Hyper Long White Button_Pressed.png +0 -0
  28. package/Runtime/Resources/Sprites/Buttons/Hyper Long White Button_Pressed.png.meta +156 -0
  29. package/Runtime/Resources/Sprites/Circle Loader/Property 1=1.png.meta +7 -7
  30. package/Runtime/Resources/Sprites/Circle Loader/Property 1=2.png.meta +7 -7
  31. package/Runtime/Resources/Sprites/Circle Loader/Property 1=3.png.meta +7 -7
  32. package/Runtime/Resources/Sprites/Circle Loader/Property 1=4.png.meta +7 -7
  33. package/Runtime/Resources/Sprites/Circle Loader/Property 1=5.png.meta +7 -7
  34. package/Runtime/Resources/Sprites/Replays/Replay.png +0 -0
  35. package/Runtime/Resources/Sprites/Replays/{Recording.png.meta → Replay.png.meta} +9 -9
  36. package/Runtime/Resources/UIPrefabs/ControlBar.prefab +5 -5
  37. package/Runtime/Resources/UIPrefabs/ReplayController.prefab +595 -196
  38. package/Runtime/Resources/UIPrefabs/ReplayPausedModal.prefab +2194 -0
  39. package/Runtime/Resources/UIPrefabs/ReplayPausedModal.prefab.meta +7 -0
  40. package/Runtime/Resources/UIPrefabs/ReplaySeekOverlay.prefab +291 -6
  41. package/Runtime/Shared/Replay/IReplayPlaybackEngine.cs +3 -0
  42. package/Samples~/LaneRunner/Prefabs/DoubleScorePickup.prefab +1 -1
  43. package/Samples~/LaneRunner/Prefabs/Obstacle.prefab +1 -1
  44. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerSpawner.cs +1 -1
  45. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerTrackItem.cs +9 -2
  46. package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerTournamentAdapter.cs +2 -0
  47. package/package.json +1 -1
  48. package/Runtime/Resources/Sprites/Replays/Recording.png +0 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,211 @@
1
+ # [1.11.0-beta.31](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.30...v1.11.0-beta.31) (2026-09-09)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * prevent gameplay timers jumping after pause ([d9d9de4](https://github.com/mvmhyper/hyper-sdk/commit/d9d9de4b7c71a0493b379bfb3f8e7712785c1401))
7
+
8
+ # [1.11.0-beta.30](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.29...v1.11.0-beta.30) (2026-09-08)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **replay:** improve seek slider handle usability ([10c4847](https://github.com/mvmhyper/hyper-sdk/commit/10c48474c6dff689903aae99bff40215152710f6))
14
+
15
+ # [1.11.0-beta.29](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.28...v1.11.0-beta.29) (2026-09-08)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **replay:** simplify seek progress presentation ([16cf45a](https://github.com/mvmhyper/hyper-sdk/commit/16cf45afb3bf4fed8abc094ce2405237f0bf3b1d))
21
+
22
+ # [1.11.0-beta.28](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.27...v1.11.0-beta.28) (2026-09-08)
23
+
24
+
25
+ ### Features
26
+
27
+ * update replay playback speed options ([fc5f653](https://github.com/mvmhyper/hyper-sdk/commit/fc5f65350b31425c53a131b7c44e8780e1b0ce2d))
28
+
29
+ # [1.11.0-beta.27](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.26...v1.11.0-beta.27) (2026-09-08)
30
+
31
+
32
+ ### Features
33
+
34
+ * **replay:** increase seek reconstruction speed ([97ce729](https://github.com/mvmhyper/hyper-sdk/commit/97ce72978d64711e0463def42283704e5d880266))
35
+
36
+ # [1.11.0-beta.26](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.25...v1.11.0-beta.26) (2026-09-07)
37
+
38
+
39
+ ### Bug Fixes
40
+
41
+ * **sample:** refine replay integration template ([5a345df](https://github.com/mvmhyper/hyper-sdk/commit/5a345df87d19a6df11af4117fbeed1e21e8e9f9a))
42
+
43
+ # [1.11.0-beta.25](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.24...v1.11.0-beta.25) (2026-09-04)
44
+
45
+
46
+ ### Features
47
+
48
+ * **replay:** include final score metadata ([463dcad](https://github.com/mvmhyper/hyper-sdk/commit/463dcadd4df5e5684f3be328b0ec361f25f26f2a))
49
+
50
+ # [1.11.0-beta.24](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.23...v1.11.0-beta.24) (2026-09-04)
51
+
52
+
53
+ ### Bug Fixes
54
+
55
+ * **replay:** add 1.5x playback speed ([3f7875f](https://github.com/mvmhyper/hyper-sdk/commit/3f7875fcc4934ed01aaa521dce45327a177f67a6))
56
+
57
+ # [1.11.0-beta.23](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.22...v1.11.0-beta.23) (2026-09-03)
58
+
59
+
60
+ ### Bug Fixes
61
+
62
+ * **replay:** smooth read-only progress display ([ead4579](https://github.com/mvmhyper/hyper-sdk/commit/ead45798883b24e4b4354f3aab22400a1399e212))
63
+
64
+ # [1.11.0-beta.22](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.21...v1.11.0-beta.22) (2026-09-03)
65
+
66
+
67
+ ### Features
68
+
69
+ * **replay:** finalize playback controls and settings ([559a7e4](https://github.com/mvmhyper/hyper-sdk/commit/559a7e48d9998efa022fe87253645dc13f83e901))
70
+
71
+ # [1.11.0-beta.21](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.20...v1.11.0-beta.21) (2026-09-03)
72
+
73
+
74
+ ### Bug Fixes
75
+
76
+ * **replay:** align gameplay activities to fixed ticks ([1e681b9](https://github.com/mvmhyper/hyper-sdk/commit/1e681b9c7f314a48c417f6e76cb2d4024c890ad3))
77
+
78
+ # [1.11.0-beta.20](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.19...v1.11.0-beta.20) (2026-09-02)
79
+
80
+
81
+ ### Bug Fixes
82
+
83
+ * **replay:** separate replay restart configuration ([de01d37](https://github.com/mvmhyper/hyper-sdk/commit/de01d37027fdde5d4f8803fa10e060d48a080316))
84
+
85
+ # [1.11.0-beta.19](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.18...v1.11.0-beta.19) (2026-09-01)
86
+
87
+
88
+ ### Bug Fixes
89
+
90
+ * **replay:** stop seeking at requested progress ([54bf74a](https://github.com/mvmhyper/hyper-sdk/commit/54bf74a4b66b7c19e1398acd611a7d9557ccbcf3))
91
+
92
+ # [1.11.0-beta.18](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.17...v1.11.0-beta.18) (2026-09-01)
93
+
94
+
95
+ ### Features
96
+
97
+ * **replay:** support custom replay restarts ([bf722ab](https://github.com/mvmhyper/hyper-sdk/commit/bf722abe48add18c356922c60231cb2017e28443))
98
+
99
+ # [1.11.0-beta.17](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.16...v1.11.0-beta.17) (2026-09-01)
100
+
101
+
102
+ ### Features
103
+
104
+ * **replay:** refine seek loading progress ([3d01f94](https://github.com/mvmhyper/hyper-sdk/commit/3d01f94d7e6ce360a61dd3d257149cf7f3237bcb))
105
+
106
+ # [1.11.0-beta.16](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.15...v1.11.0-beta.16) (2026-08-31)
107
+
108
+
109
+ ### Bug Fixes
110
+
111
+ * **replay:** show seek preparation progress ([60213f7](https://github.com/mvmhyper/hyper-sdk/commit/60213f784c5bff39da4634590545fe4d0e4c0911))
112
+
113
+ # [1.11.0-beta.15](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.14...v1.11.0-beta.15) (2026-08-31)
114
+
115
+
116
+ ### Features
117
+
118
+ * **replay:** show seek completion progress ([4e7c1b8](https://github.com/mvmhyper/hyper-sdk/commit/4e7c1b807bd9f34b97477ef39aa9ca3c06316ef3))
119
+
120
+ # [1.11.0-beta.14](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.13...v1.11.0-beta.14) (2026-08-31)
121
+
122
+
123
+ ### Bug Fixes
124
+
125
+ * **replay:** keep seek loader animating ([7e13938](https://github.com/mvmhyper/hyper-sdk/commit/7e13938ce718a238506c08c30744ff24ed7fa710))
126
+
127
+ # [1.11.0-beta.13](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.12...v1.11.0-beta.13) (2026-08-31)
128
+
129
+
130
+ ### Bug Fixes
131
+
132
+ * **replay:** reduce default seek speed to 10x ([ccaf5b9](https://github.com/mvmhyper/hyper-sdk/commit/ccaf5b9807fd9439627072518317ad7f079e544c))
133
+
134
+ # [1.11.0-beta.12](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.11...v1.11.0-beta.12) (2026-08-31)
135
+
136
+
137
+ ### Bug Fixes
138
+
139
+ * **replay:** reduce default seek speed ([d757710](https://github.com/mvmhyper/hyper-sdk/commit/d757710d107a0a496c9d7daa1434004a682bd355))
140
+
141
+ # [1.11.0-beta.11](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.10...v1.11.0-beta.11) (2026-08-30)
142
+
143
+
144
+ ### Bug Fixes
145
+
146
+ * **replay:** apply 30x seek speed on beta ([564769e](https://github.com/mvmhyper/hyper-sdk/commit/564769e4764f27fd301f0e1dc52a4434635f93b7))
147
+ * **replay:** reduce default seek speed ([2cd0a34](https://github.com/mvmhyper/hyper-sdk/commit/2cd0a34c6390725d1c57fc3fa5f691f618c45083))
148
+
149
+
150
+ ### Features
151
+
152
+ * **replay:** increase default seek speed ([d1a5a46](https://github.com/mvmhyper/hyper-sdk/commit/d1a5a464c1e3e149255bf0d2d183439e9c29cfb3))
153
+
154
+ # [1.11.0-beta.10](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.9...v1.11.0-beta.10) (2026-08-30)
155
+
156
+
157
+ ### Bug Fixes
158
+
159
+ * **replay:** reduce default seek speed ([f70551a](https://github.com/mvmhyper/hyper-sdk/commit/f70551aea942274ace1cb952ddae4e9edb0c1c12))
160
+
161
+ # [1.11.0-beta.9](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.8...v1.11.0-beta.9) (2026-08-30)
162
+
163
+
164
+ ### Bug Fixes
165
+
166
+ * **replay:** show loader while exiting paused replay ([4a2e7a6](https://github.com/mvmhyper/hyper-sdk/commit/4a2e7a6045017ea8ed3ae3525271440dbf013e6c))
167
+
168
+ # [1.11.0-beta.8](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.7...v1.11.0-beta.8) (2026-08-30)
169
+
170
+
171
+ ### Bug Fixes
172
+
173
+ * **replay:** mute audio while seeking ([5ab8cd1](https://github.com/mvmhyper/hyper-sdk/commit/5ab8cd1411493cb5add07b51dc190c85251f99d2))
174
+
175
+ # [1.11.0-beta.7](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.6...v1.11.0-beta.7) (2026-08-30)
176
+
177
+
178
+ ### Bug Fixes
179
+
180
+ * **replay:** stabilize scene reload seeking ([dd9ac63](https://github.com/mvmhyper/hyper-sdk/commit/dd9ac632d08349d9578f64ae0b2dc2ab905a26af))
181
+
182
+ # [1.11.0-beta.6](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.5...v1.11.0-beta.6) (2026-08-29)
183
+
184
+
185
+ ### Bug Fixes
186
+
187
+ * **timer:** restore gameplay timers after pause ([ca82d57](https://github.com/mvmhyper/hyper-sdk/commit/ca82d57df87618807cbae611c0a9d6acc14f8470))
188
+
189
+ # [1.11.0-beta.5](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.4...v1.11.0-beta.5) (2026-08-28)
190
+
191
+
192
+ ### Bug Fixes
193
+
194
+ * **replay:** wait for custom restart readiness ([43f1aeb](https://github.com/mvmhyper/hyper-sdk/commit/43f1aeb6a127c8c12dbb8379e7230d64ef5e0763))
195
+
196
+
197
+ ### Features
198
+
199
+ * **replay:** add replay pause controls ([b9fb470](https://github.com/mvmhyper/hyper-sdk/commit/b9fb470e65c69e66a8a9611b0caa7e5417b1e4bf))
200
+ * **replay:** update replay control bar assets ([79ce8c0](https://github.com/mvmhyper/hyper-sdk/commit/79ce8c0f1b68129ae5b8bcf18a302117cf11c885))
201
+
202
+ # [1.11.0-beta.4](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.3...v1.11.0-beta.4) (2026-08-28)
203
+
204
+
205
+ ### Bug Fixes
206
+
207
+ * **replay:** align recording with fixed simulation ([ae2b322](https://github.com/mvmhyper/hyper-sdk/commit/ae2b32216a0a9ea125572d788eee3bfd846414b0))
208
+
1
209
  # [1.11.0-beta.3](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.2...v1.11.0-beta.3) (2026-08-28)
2
210
 
3
211
 
@@ -170,6 +170,21 @@ namespace Hyper.Editor
170
170
  settings.useCustomRestartFlow = EditorGUILayout.Toggle(
171
171
  new GUIContent("Use Custom Restart Flow"),
172
172
  settings.useCustomRestartFlow);
173
+ settings.useCustomReplayRestartFlow = EditorGUILayout.Toggle(
174
+ new GUIContent(
175
+ "Replay Custom Restart",
176
+ "Use game-owned restart logic for replay Watch Again and seeking. " +
177
+ "Disabled uses HyperLoader to rebuild deterministic game state."),
178
+ settings.useCustomReplayRestartFlow);
179
+
180
+ EditorGUILayout.Space(12);
181
+ EditorGUILayout.LabelField("Replay Settings", EditorStyles.boldLabel);
182
+ settings.allowReplaySeeking = EditorGUILayout.Toggle(
183
+ new GUIContent(
184
+ "Allow Replay Seeking",
185
+ "Allow viewers to seek using the replay progress bar. " +
186
+ "Leave disabled until accelerated replay reconstruction is validated for this game."),
187
+ settings.allowReplaySeeking);
173
188
 
174
189
  EditorGUILayout.Space(12);
175
190
  // Draw Editor Testing
package/HyperLoader.unity CHANGED
@@ -304,7 +304,7 @@ RectTransform:
304
304
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
305
305
  m_AnchorMin: {x: 0, y: 1}
306
306
  m_AnchorMax: {x: 0, y: 1}
307
- m_AnchoredPosition: {x: 489.112, y: -280.1698}
307
+ m_AnchoredPosition: {x: 489.20746, y: -280.1698}
308
308
  m_SizeDelta: {x: 1044.9, y: 239.347}
309
309
  m_Pivot: {x: 0.5, y: 0.5}
310
310
  --- !u!114 &751153944
@@ -1092,7 +1092,7 @@ RectTransform:
1092
1092
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
1093
1093
  m_AnchorMin: {x: 0, y: 1}
1094
1094
  m_AnchorMax: {x: 0, y: 1}
1095
- m_AnchoredPosition: {x: 489.112, y: -133.2274}
1095
+ m_AnchoredPosition: {x: 489.20746, y: -133.2274}
1096
1096
  m_SizeDelta: {x: 875, y: 54.5378}
1097
1097
  m_Pivot: {x: 0.5, y: 0.5}
1098
1098
  --- !u!1 &2874543288936963705
@@ -448,7 +448,11 @@ namespace Hyper.Internal
448
448
  return false;
449
449
  }
450
450
 
451
- ReplaySessionState.SetMetadata(replay.PlayerName, replay.AvatarUrl, replay.Seed);
451
+ ReplaySessionState.SetMetadata(
452
+ replay.PlayerName,
453
+ replay.AvatarUrl,
454
+ replay.Seed,
455
+ replay.FinalScore);
452
456
  ReplaySessionState.SetReplayData(replay.ActivityNdjson);
453
457
  HyperDebug.Log($"Replay loaded from {path}");
454
458
  return true;
@@ -15,12 +15,16 @@ namespace Hyper.Internal
15
15
  /// </summary>
16
16
  internal static class HyperRuntime
17
17
  {
18
+ private const float ReplayCustomRestartTimeoutSeconds = 10f;
19
+
18
20
  private static HyperRuntimeHost _host;
19
21
  private static GameObject _singletonObject;
20
22
 
21
23
  private static bool _isInitialized;
22
24
  private static bool _isSoftRestarting;
23
25
  private static bool _replayRandomResetPending;
26
+ private static bool _replayCustomRestartPending;
27
+ private static int _replayCustomRestartVersion;
24
28
  private static bool _customLoadingComplete;
25
29
  private static bool _customLoadingActive;
26
30
  private static float _customLoadingProgress;
@@ -33,6 +37,7 @@ namespace Hyper.Internal
33
37
  private static EventManager _eventManager;
34
38
  private static TimerManager _timerManager;
35
39
  private static ReplayManager _replayManager;
40
+ private static double _fixedSimulationTimeSeconds;
36
41
 
37
42
  internal static bool IsInitialized => _isInitialized;
38
43
  internal static bool IsSoftRestarting
@@ -40,6 +45,7 @@ namespace Hyper.Internal
40
45
  get => _isSoftRestarting;
41
46
  set => _isSoftRestarting = value;
42
47
  }
48
+ internal static bool IsReplayCustomRestartPending => _replayCustomRestartPending;
43
49
  internal static bool CustomLoadingComplete
44
50
  {
45
51
  get => _customLoadingComplete;
@@ -59,6 +65,7 @@ namespace Hyper.Internal
59
65
  internal static EventManager EventManager => _eventManager;
60
66
  internal static TimerManager Timer => _timerManager;
61
67
  internal static ReplayManager ReplayManager => _replayManager;
68
+ internal static double FixedSimulationTimeSeconds => _fixedSimulationTimeSeconds;
62
69
 
63
70
  internal static event Action CustomLoadingStarted
64
71
  {
@@ -119,8 +126,8 @@ namespace Hyper.Internal
119
126
  }
120
127
 
121
128
  /// <summary>
122
- /// Restarts replay playback while preserving its downloaded data and original seed.
123
- /// Uses the configured custom restart flow when available, otherwise reloads HyperLoader.
129
+ /// Restarts replay playback while preserving replay session data. Uses the game-owned
130
+ /// replay restart flow only when explicitly enabled and otherwise reloads HyperLoader.
124
131
  /// </summary>
125
132
  internal static void RestartReplaySession()
126
133
  {
@@ -142,18 +149,66 @@ namespace Hyper.Internal
142
149
  _isSoftRestarting = true;
143
150
  Time.timeScale = 1f;
144
151
 
145
- if (_settings != null && _settings.useCustomRestartFlow &&
146
- _gameManager != null && _eventManager != null)
152
+ _replayCustomRestartPending = false;
153
+ _replayRandomResetPending = false;
154
+ int restartVersion = ++_replayCustomRestartVersion;
155
+ _replayManager?.PrepareForRestart();
156
+
157
+ if (_settings != null && _settings.useCustomReplayRestartFlow &&
158
+ _host != null && _gameManager != null && _eventManager != null)
147
159
  {
148
- _replayManager?.PrepareForRestart();
149
- // Custom cleanup may use random streams. Rewind after cleanup, immediately before OnGameStart.
150
- DeferReplayRandomReset();
160
+ _replayCustomRestartPending = true;
161
+ _replayRandomResetPending = true;
151
162
  _gameManager.ResetUIStateForCustomRestart();
152
- _eventManager.InvokeCustomRestartEvent();
153
- _isSoftRestarting = false;
154
- return;
163
+
164
+ try
165
+ {
166
+ if (!_eventManager.InvokeCustomRestartEvent())
167
+ {
168
+ HyperDebug.LogWarning(
169
+ "[Replay] Custom restart has no handler; falling back to HyperLoader.");
170
+ BeginReplaySceneRestart(restartVersion);
171
+ return;
172
+ }
173
+
174
+ _host.StartCoroutine(WaitForReplayCustomRestart(restartVersion));
175
+ return;
176
+ }
177
+ catch (Exception exception)
178
+ {
179
+ HyperDebug.LogWarning(
180
+ $"[Replay] Custom restart failed; falling back to HyperLoader: {exception.Message}");
181
+ BeginReplaySceneRestart(restartVersion);
182
+ return;
183
+ }
184
+ }
185
+
186
+ BeginReplaySceneRestart(restartVersion);
187
+ }
188
+
189
+ private static IEnumerator WaitForReplayCustomRestart(int restartVersion)
190
+ {
191
+ float timeoutAt = Time.realtimeSinceStartup + ReplayCustomRestartTimeoutSeconds;
192
+ while (_replayCustomRestartPending && restartVersion == _replayCustomRestartVersion &&
193
+ Time.realtimeSinceStartup < timeoutAt)
194
+ {
195
+ yield return null;
155
196
  }
156
197
 
198
+ if (!_replayCustomRestartPending || restartVersion != _replayCustomRestartVersion) yield break;
199
+
200
+ HyperDebug.LogWarning(
201
+ $"[Replay] Custom restart did not complete within {ReplayCustomRestartTimeoutSeconds:0} seconds; " +
202
+ "falling back to HyperLoader.");
203
+ BeginReplaySceneRestart(restartVersion);
204
+ }
205
+
206
+ private static void BeginReplaySceneRestart(int restartVersion)
207
+ {
208
+ if (restartVersion != _replayCustomRestartVersion) return;
209
+
210
+ _replayCustomRestartPending = false;
211
+ _replayRandomResetPending = false;
157
212
  if (_host != null)
158
213
  {
159
214
  _host.StartCoroutine(RestartSessionCoroutine());
@@ -191,6 +246,21 @@ namespace Hyper.Internal
191
246
  _replayRandomResetPending = true;
192
247
  }
193
248
 
249
+ internal static void CompleteCustomRestart()
250
+ {
251
+ if (!_replayCustomRestartPending || _host == null) return;
252
+
253
+ _replayCustomRestartPending = false;
254
+ _host.StartCoroutine(CompleteReplayCustomRestartNextFrame());
255
+ }
256
+
257
+ private static IEnumerator CompleteReplayCustomRestartNextFrame()
258
+ {
259
+ yield return null;
260
+ _gameManager?.CompleteReplayCustomRestart();
261
+ _isSoftRestarting = false;
262
+ }
263
+
194
264
  /// <summary>
195
265
  /// Coroutine-based restart that properly unloads all scenes before reloading.
196
266
  /// Handles async scene operations and ensures clean state before restart.
@@ -199,6 +269,7 @@ namespace Hyper.Internal
199
269
  {
200
270
  yield return UnloadAllScenesCoroutine();
201
271
 
272
+ Clear();
202
273
  ClearAllDontDestroyOnLoadObjects();
203
274
  SceneManager.LoadScene("HyperLoader");
204
275
  }
@@ -396,6 +467,7 @@ namespace Hyper.Internal
396
467
  internal static void FixedTick()
397
468
  {
398
469
  if (!_isInitialized) return;
470
+ _fixedSimulationTimeSeconds += Time.fixedDeltaTime;
399
471
  _replayManager?.FixedTick();
400
472
  _timerManager?.FixedTick();
401
473
  }
@@ -430,6 +502,9 @@ namespace Hyper.Internal
430
502
  _customLoadingActive = false;
431
503
  _customLoadingProgress = 0f;
432
504
  _replayRandomResetPending = false;
505
+ _replayCustomRestartPending = false;
506
+ _replayCustomRestartVersion++;
507
+ _fixedSimulationTimeSeconds = 0d;
433
508
 
434
509
  if (_singletonObject != null)
435
510
  {
@@ -489,6 +564,9 @@ namespace Hyper.Internal
489
564
  _customLoadingActive = false;
490
565
  _customLoadingProgress = 0f;
491
566
  _replayRandomResetPending = false;
567
+ _replayCustomRestartPending = false;
568
+ _replayCustomRestartVersion++;
569
+ _fixedSimulationTimeSeconds = 0d;
492
570
  }
493
571
  }
494
572
  }
@@ -179,7 +179,8 @@ namespace Hyper.Internal.Managers
179
179
  ReplaySessionState.SetMetadata(
180
180
  replay.PlayerName,
181
181
  replay.AvatarUrl,
182
- replay.Seed);
182
+ replay.Seed,
183
+ replay.FinalScore);
183
184
  ReplaySessionState.SetReplayData(replay.ActivityNdjson);
184
185
  HyperDebug.Log($"Replay downloaded for entry {entryId}.");
185
186
  onSuccess?.Invoke();
@@ -289,9 +290,10 @@ namespace Hyper.Internal.Managers
289
290
  string seedLine = reader.ReadLine();
290
291
  string nameLine = reader.ReadLine();
291
292
  string avatarLine = reader.ReadLine();
293
+ string scoreLine = reader.ReadLine();
292
294
  string activities = reader.ReadToEnd();
293
295
 
294
- if (seedLine == null || nameLine == null || avatarLine == null)
296
+ if (seedLine == null || nameLine == null || avatarLine == null || scoreLine == null)
295
297
  {
296
298
  error = "The replay response is missing required metadata.";
297
299
  return false;
@@ -302,6 +304,7 @@ namespace Hyper.Internal.Managers
302
304
  JArray seedData = JArray.Parse(seedLine);
303
305
  JArray nameData = JArray.Parse(nameLine);
304
306
  JArray avatarData = JArray.Parse(avatarLine);
307
+ JArray scoreData = JArray.Parse(scoreLine);
305
308
 
306
309
  if (seedData.Count != 1 ||
307
310
  seedData[0].Type != JTokenType.Integer ||
@@ -327,6 +330,18 @@ namespace Hyper.Internal.Managers
327
330
  return false;
328
331
  }
329
332
 
333
+ if (scoreData.Count != 1 ||
334
+ scoreData[0].Type != JTokenType.Integer ||
335
+ !int.TryParse(
336
+ scoreData[0].ToString(),
337
+ NumberStyles.Integer,
338
+ CultureInfo.InvariantCulture,
339
+ out int finalScore))
340
+ {
341
+ error = "Replay metadata contains an invalid final score.";
342
+ return false;
343
+ }
344
+
330
345
  if (string.IsNullOrWhiteSpace(activities))
331
346
  {
332
347
  error = "The replay response contains no gameplay activities.";
@@ -337,6 +352,7 @@ namespace Hyper.Internal.Managers
337
352
  seed,
338
353
  nameData[0].Value<string>() ?? string.Empty,
339
354
  avatarData[0].Value<string>() ?? string.Empty,
355
+ finalScore,
340
356
  activities);
341
357
 
342
358
  return true;
@@ -354,13 +370,20 @@ namespace Hyper.Internal.Managers
354
370
  internal long Seed { get; }
355
371
  internal string PlayerName { get; }
356
372
  internal string AvatarUrl { get; }
373
+ internal int FinalScore { get; }
357
374
  internal string ActivityNdjson { get; }
358
375
 
359
- internal ReplayResponse(long seed, string playerName, string avatarUrl, string activityNdjson)
376
+ internal ReplayResponse(
377
+ long seed,
378
+ string playerName,
379
+ string avatarUrl,
380
+ int finalScore,
381
+ string activityNdjson)
360
382
  {
361
383
  Seed = seed;
362
384
  PlayerName = playerName;
363
385
  AvatarUrl = avatarUrl;
386
+ FinalScore = finalScore;
364
387
  ActivityNdjson = activityNdjson;
365
388
  }
366
389
  }
@@ -219,6 +219,7 @@ namespace Hyper.Internal.Managers
219
219
  internal void ConfigurePlayerSoundSetting()
220
220
  {
221
221
  SetSound(GetSound());
222
+ ReplaySessionState.EnsureAudioMutedDuringSeek();
222
223
  if (_gameManager == null) _gameManager = HyperRuntime.GameManager;
223
224
  }
224
225
 
@@ -374,6 +375,7 @@ namespace Hyper.Internal.Managers
374
375
  new object[] { HyperRandom.CurrentSeed }));
375
376
  _editorReplay.AppendLine(JsonConvert.SerializeObject(new object[] { "hypergamer" }));
376
377
  _editorReplay.AppendLine(JsonConvert.SerializeObject(new object[] { string.Empty }));
378
+ _editorReplayMetadataLength = _editorReplay.Length;
377
379
  #endif
378
380
  _replayRecorder?.StartSession();
379
381
  }
@@ -425,6 +427,7 @@ namespace Hyper.Internal.Managers
425
427
 
426
428
  #if UNITY_EDITOR
427
429
  private readonly StringBuilder _editorReplay = new StringBuilder(4096);
430
+ private int _editorReplayMetadataLength;
428
431
 
429
432
  private void CaptureEditorReplayActivity(object[] activity)
430
433
  {
@@ -433,6 +436,8 @@ namespace Hyper.Internal.Managers
433
436
 
434
437
  private void SaveEditorReplay()
435
438
  {
439
+ string finalScoreLine = JsonConvert.SerializeObject(new object[] { CurrentScore }) + Environment.NewLine;
440
+ _editorReplay.Insert(_editorReplayMetadataLength, finalScoreLine);
436
441
  try
437
442
  {
438
443
  File.WriteAllText(ReplaySessionState.EditorReplayFilePath, _editorReplay.ToString());
@@ -442,6 +447,10 @@ namespace Hyper.Internal.Managers
442
447
  {
443
448
  HyperDebug.LogWarning($"Unable to save Editor replay: {exception.Message}");
444
449
  }
450
+ finally
451
+ {
452
+ _editorReplay.Remove(_editorReplayMetadataLength, finalScoreLine.Length);
453
+ }
445
454
  }
446
455
  #endif
447
456
 
@@ -462,7 +471,7 @@ namespace Hyper.Internal.Managers
462
471
 
463
472
  private static double GetSimulationTimeSeconds()
464
473
  {
465
- return Time.fixedTimeAsDouble;
474
+ return HyperRuntime.FixedSimulationTimeSeconds;
466
475
  }
467
476
 
468
477
  private ScoreData GetPooledScoreData()
@@ -79,7 +79,13 @@ namespace Hyper.Internal.Managers
79
79
  internal void InvokeGameEndedEvent() => OnGameEnded?.Invoke();
80
80
  internal void InvokeLivesExhaustedEvent() => OnLivesExhausted?.Invoke();
81
81
  internal void InvokeHealthExhaustedEvent() => OnHealthExhausted?.Invoke();
82
- internal void InvokeCustomRestartEvent() => OnCustomRestart?.Invoke();
82
+ internal bool InvokeCustomRestartEvent()
83
+ {
84
+ Action handler = OnCustomRestart;
85
+ if (handler == null) return false;
86
+ handler.Invoke();
87
+ return true;
88
+ }
83
89
  internal void InvokeConnectionLostEvent() => OnInternetConnectionLost?.Invoke();
84
90
  internal void InvokeConnectionFoundEvent() => OnInternetConnectionFound?.Invoke();
85
91
  internal void InvokeBackendSocketManuallyClosedEvent() => OnBackendSocketManuallyClosed?.Invoke();