app.hypergames.hypersdk 1.10.0 → 1.11.0-beta.2

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 (115) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/Editor/Scripts/Setup/HyperSDKInstaller.cs +42 -0
  3. package/Editor/Scripts/Tools/HyperGameModeMenu.cs +27 -7
  4. package/Runtime/Internal/AssemblyInfo.cs +1 -0
  5. package/Runtime/Internal/Bootstrap/HyperLoader.cs +186 -8
  6. package/Runtime/Internal/Core/HyperRuntime.cs +82 -0
  7. package/Runtime/Internal/Core/HyperRuntimeHost.cs +6 -0
  8. package/Runtime/Internal/Data/URLData.cs +18 -1
  9. package/Runtime/Internal/Managers/BackendManager.cs +281 -24
  10. package/Runtime/Internal/Managers/DataManager.cs +207 -21
  11. package/Runtime/Internal/Managers/GameManager.cs +365 -17
  12. package/Runtime/Internal/Managers/ReplayManager.cs +117 -0
  13. package/Runtime/Internal/Managers/ReplayManager.cs.meta +11 -0
  14. package/Runtime/Internal/Managers/TimeManager.cs +54 -12
  15. package/Runtime/Internal/Replay/ReplayActivityRecorder.cs +182 -0
  16. package/Runtime/Internal/Replay/ReplayActivityRecorder.cs.meta +2 -0
  17. package/Runtime/Internal/Replay/ReplaySessionState.cs +181 -0
  18. package/Runtime/Internal/Replay/ReplaySessionState.cs.meta +2 -0
  19. package/Runtime/Internal/Replay.meta +8 -0
  20. package/Runtime/Internal/ScriptableObjects/HyperSDKSettings.cs +5 -0
  21. package/Runtime/Internal/UI/Animation/LoadingTextAnimation.cs +15 -1
  22. package/Runtime/Internal/UI/Components/ControlBar.cs +25 -2
  23. package/Runtime/Internal/UI/Components/PauseButton.cs +4 -1
  24. package/Runtime/Internal/UI/Components/ReplayController.cs +527 -0
  25. package/Runtime/Internal/UI/Components/ReplayController.cs.meta +2 -0
  26. package/Runtime/Internal/UI/Components/ReplayMarkerPulse.cs +89 -0
  27. package/Runtime/Internal/UI/Components/ReplayMarkerPulse.cs.meta +2 -0
  28. package/Runtime/Internal/UI/Components/ReplayPresentationCanvas.cs +183 -0
  29. package/Runtime/Internal/UI/Components/ReplayPresentationCanvas.cs.meta +2 -0
  30. package/Runtime/Internal/UI/Modals/LoadingFailedModal.cs +12 -0
  31. package/Runtime/Internal/UI/Modals/ReplayOverModal.cs +61 -0
  32. package/Runtime/Internal/UI/Modals/ReplayOverModal.cs.meta +2 -0
  33. package/Runtime/Internal/UI/Modals/StartingInstructionModal.cs +38 -29
  34. package/Runtime/Public/AssemblyInfo.cs +3 -0
  35. package/Runtime/Public/AssemblyInfo.cs.meta +2 -0
  36. package/Runtime/Public/Core/HyperSDK.cs +305 -109
  37. package/Runtime/Public/Hyper.asmdef +2 -1
  38. package/Runtime/Public/Replay/ReplayPlaybackEngine.cs +555 -0
  39. package/Runtime/Public/Replay/ReplayPlaybackEngine.cs.meta +2 -0
  40. package/Runtime/Public/Replay.meta +8 -0
  41. package/Runtime/Resources/Fonts/Nunito/Nunito-Light SDF.asset +528 -521
  42. package/Runtime/Resources/Materials/HyperReplayScanlines.preset +340 -0
  43. package/Runtime/Resources/Materials/HyperReplayScanlines.preset.meta +8 -0
  44. package/Runtime/Resources/Materials/ReplayScanlineOverlay.mat +55 -0
  45. package/Runtime/Resources/Materials/ReplayScanlineOverlay.mat.meta +8 -0
  46. package/Runtime/Resources/Shaders/ReplayScanlineOverlay.shader +150 -0
  47. package/Runtime/Resources/Shaders/ReplayScanlineOverlay.shader.meta +10 -0
  48. package/Runtime/Resources/Sprites/Replays/Fallback avatar.png +0 -0
  49. package/Runtime/Resources/Sprites/Replays/Fallback avatar.png.meta +156 -0
  50. package/Runtime/Resources/Sprites/Replays/Recording.png +0 -0
  51. package/Runtime/Resources/Sprites/Replays/Recording.png.meta +156 -0
  52. package/Runtime/Resources/Sprites/Replays/Replay frame.png +0 -0
  53. package/Runtime/Resources/Sprites/Replays/Replay frame.png.meta +156 -0
  54. package/Runtime/Resources/Sprites/Replays/Replay modal icon.png +0 -0
  55. package/Runtime/Resources/Sprites/Replays/Replay modal icon.png.meta +156 -0
  56. package/Runtime/Resources/Sprites/Replays.meta +8 -0
  57. package/Runtime/Resources/UIPrefabs/ControlBar.prefab +169 -2
  58. package/Runtime/Resources/UIPrefabs/GamePausedModal_Battle.prefab +1 -1
  59. package/Runtime/Resources/UIPrefabs/ReplayController.prefab +1269 -0
  60. package/Runtime/Resources/UIPrefabs/ReplayController.prefab.meta +7 -0
  61. package/Runtime/Resources/UIPrefabs/ReplayInputBlocker.prefab +90 -0
  62. package/Runtime/Resources/UIPrefabs/ReplayInputBlocker.prefab.meta +7 -0
  63. package/Runtime/Resources/UIPrefabs/ReplayOverModal.prefab +958 -0
  64. package/Runtime/Resources/UIPrefabs/ReplayOverModal.prefab.meta +7 -0
  65. package/Runtime/Resources/UIPrefabs/ReplaySeekOverlay.prefab +189 -0
  66. package/Runtime/Resources/UIPrefabs/ReplaySeekOverlay.prefab.meta +7 -0
  67. package/Runtime/Resources/UIPrefabs/SnackBar.prefab +2 -2
  68. package/Runtime/Shared/AssemblyInfo.cs +5 -0
  69. package/Runtime/Shared/AssemblyInfo.cs.meta +11 -0
  70. package/Runtime/Shared/DTOs/Enums.cs +8 -3
  71. package/Runtime/Shared/DTOs/Score/ScoreSnapshot.cs +13 -1
  72. package/Runtime/Shared/Replay/IReplayPlaybackEngine.cs +37 -0
  73. package/Runtime/Shared/Replay/IReplayPlaybackEngine.cs.meta +11 -0
  74. package/Runtime/Shared/Replay.meta +8 -0
  75. package/Samples~/LaneRunner/LaneRunnerSample.unity +1603 -0
  76. package/Samples~/LaneRunner/LaneRunnerSample.unity.meta +7 -0
  77. package/Samples~/LaneRunner/Materials/DoubleScore.mat +86 -0
  78. package/Samples~/LaneRunner/Materials/DoubleScore.mat.meta +8 -0
  79. package/Samples~/LaneRunner/Materials/Ground.mat +84 -0
  80. package/Samples~/LaneRunner/Materials/Ground.mat.meta +8 -0
  81. package/Samples~/LaneRunner/Materials/Lane.mat +84 -0
  82. package/Samples~/LaneRunner/Materials/Lane.mat.meta +8 -0
  83. package/Samples~/LaneRunner/Materials/LaneMarker.mat +84 -0
  84. package/Samples~/LaneRunner/Materials/LaneMarker.mat.meta +8 -0
  85. package/Samples~/LaneRunner/Materials/Obstacle.mat +84 -0
  86. package/Samples~/LaneRunner/Materials/Obstacle.mat.meta +8 -0
  87. package/Samples~/LaneRunner/Materials/Player.mat +84 -0
  88. package/Samples~/LaneRunner/Materials/Player.mat.meta +8 -0
  89. package/Samples~/LaneRunner/Materials.meta +8 -0
  90. package/Samples~/LaneRunner/Prefabs/DoubleScorePickup.prefab +152 -0
  91. package/Samples~/LaneRunner/Prefabs/DoubleScorePickup.prefab.meta +7 -0
  92. package/Samples~/LaneRunner/Prefabs/Obstacle.prefab +152 -0
  93. package/Samples~/LaneRunner/Prefabs/Obstacle.prefab.meta +7 -0
  94. package/Samples~/LaneRunner/Prefabs.meta +8 -0
  95. package/Samples~/LaneRunner/README.md +35 -0
  96. package/Samples~/LaneRunner/README.md.meta +7 -0
  97. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerCommand.cs +9 -0
  98. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerCommand.cs.meta +2 -0
  99. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerGame.cs +93 -0
  100. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerGame.cs.meta +2 -0
  101. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerPlayer.cs +155 -0
  102. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerPlayer.cs.meta +2 -0
  103. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerSpawner.cs +110 -0
  104. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerSpawner.cs.meta +2 -0
  105. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerTrackItem.cs +41 -0
  106. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerTrackItem.cs.meta +2 -0
  107. package/Samples~/LaneRunner/Scripts/Gameplay.meta +8 -0
  108. package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerReplayAdapter.cs +62 -0
  109. package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerReplayAdapter.cs.meta +2 -0
  110. package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerTournamentAdapter.cs +64 -0
  111. package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerTournamentAdapter.cs.meta +2 -0
  112. package/Samples~/LaneRunner/Scripts/Hyper.meta +8 -0
  113. package/Samples~/LaneRunner/Scripts.meta +8 -0
  114. package/Tests.meta +8 -0
  115. package/package.json +8 -1
@@ -17,6 +17,7 @@ namespace Hyper
17
17
  private static EventAPIAdapter _eventAdapter;
18
18
  private static LoaderAPIAdapter _loaderAdapter;
19
19
  private static ScreenAPIAdapter _screenAdapter;
20
+ private static ReplayAPIAdapter _replayAdapter;
20
21
 
21
22
  /// <summary>
22
23
  /// Returns true if the SDK runtime has been initialized.
@@ -91,6 +92,19 @@ namespace Hyper
91
92
  }
92
93
  }
93
94
 
95
+ /// <summary>
96
+ /// Access replayed gameplay activities. The SDK owns loading, timing,
97
+ /// progress, suspension and completion.
98
+ /// </summary>
99
+ public static IReplayAPI Replay
100
+ {
101
+ get
102
+ {
103
+ EnsureAdaptersReady();
104
+ return _replayAdapter;
105
+ }
106
+ }
107
+
94
108
  /// <summary>
95
109
  /// Access loader control for custom pre-loading workflows.
96
110
  /// Use when EnableCustomLoading is enabled in HyperGameContentConfig.
@@ -149,7 +163,13 @@ namespace Hyper
149
163
  _eventAdapter = new EventAPIAdapter();
150
164
  }
151
165
 
166
+ if (_replayAdapter == null)
167
+ {
168
+ _replayAdapter = new ReplayAPIAdapter();
169
+ }
170
+
152
171
  _eventAdapter.RefreshBindings();
172
+ _replayAdapter.RefreshBindings();
153
173
  }
154
174
 
155
175
  }
@@ -159,29 +179,34 @@ namespace Hyper
159
179
  /// </summary>
160
180
  public interface IGameAPI
161
181
  {
162
- /// <summary>
163
- /// True when the current mode is Battle (PvP or timed battle).
164
- /// </summary>
182
+ /// <summary>
183
+ /// True when using Battle gameplay. Replay mode also returns true so games
184
+ /// can load the same level and rules used by the original battle.
185
+ /// </summary>
165
186
  bool IsBattleMode { get; }
166
- /// <summary>
167
- /// True when the current mode is Practice.
168
- /// </summary>
187
+ /// <summary>
188
+ /// True when the current mode is Practice.
189
+ /// </summary>
169
190
  bool IsPracticeMode { get; }
170
- /// <summary>
171
- /// True if the game is currently paused by the SDK.
172
- /// </summary>
191
+ /// <summary>
192
+ /// True when the SDK is playing a recorded battle session.
193
+ /// </summary>
194
+ bool IsReplayMode { get; }
195
+ /// <summary>
196
+ /// True if the game is currently paused by the SDK.
197
+ /// </summary>
173
198
  bool IsPaused { get; }
174
- /// <summary>
175
- /// True once gameplay has begun (post countdown/start).
176
- /// </summary>
199
+ /// <summary>
200
+ /// True once gameplay has begun (post countdown/start).
201
+ /// </summary>
177
202
  bool HasGameStarted { get; }
178
- /// <summary>
179
- /// True after the current game session has ended.
180
- /// </summary>
203
+ /// <summary>
204
+ /// True after the current game session has ended.
205
+ /// </summary>
181
206
  bool HasGameEnded { get; }
182
207
 
183
208
  /// <summary>
184
- /// Seconds remaining on the PvP match clock. Zero in practice mode or when not in a timed battle.
209
+ /// Seconds remaining on the timed Battle or Replay clock. Zero in Practice mode.
185
210
  /// </summary>
186
211
  int BattleTimeRemaining { get; }
187
212
 
@@ -196,105 +221,155 @@ namespace Hyper
196
221
  [Obsolete("Use EndGame() instead; it ends practice or battle based on the current mode.")]
197
222
  void EndPracticeGame();
198
223
 
199
- /// <summary>
200
- /// Closes the practice menu and enters gameplay (only relevant when practice scene is a menu).
201
- /// </summary>
224
+ /// <summary>
225
+ /// Closes the practice menu and enters gameplay (only relevant when practice scene is a menu).
226
+ /// </summary>
202
227
  void ExitPracticeMenu();
203
228
 
204
229
  // Lives Management (only available when ControlBarLayout is HeartsLeft)
205
- /// <summary>
206
- /// Initialize the lives system with a maximum and optional initial value.
207
- /// </summary>
230
+ /// <summary>
231
+ /// Initialize the lives system with a maximum and optional initial value.
232
+ /// </summary>
208
233
  void InitializeLives(int maxLives, int initialLives = -1);
209
- /// <summary>
210
- /// Set the current number of lives.
211
- /// </summary>
234
+ /// <summary>
235
+ /// Set the current number of lives.
236
+ /// </summary>
212
237
  void SetLives(int lives);
213
- /// <summary>
214
- /// Increment lives by one.
215
- /// </summary>
238
+ /// <summary>
239
+ /// Increment lives by one.
240
+ /// </summary>
216
241
  void AddLife();
217
- /// <summary>
218
- /// Decrement lives by one.
219
- /// </summary>
242
+ /// <summary>
243
+ /// Decrement lives by one.
244
+ /// </summary>
220
245
  void RemoveLife();
221
- /// <summary>
222
- /// Get the current number of lives.
223
- /// </summary>
246
+ /// <summary>
247
+ /// Get the current number of lives.
248
+ /// </summary>
224
249
  int GetCurrentLives();
225
- /// <summary>
226
- /// Get the configured maximum number of lives.
227
- /// </summary>
250
+ /// <summary>
251
+ /// Get the configured maximum number of lives.
252
+ /// </summary>
228
253
  int GetMaxLives();
229
254
 
230
255
  // Health Management (only available when ControlBarLayout is HealthBarGreenLeft)
231
- /// <summary>
232
- /// Initialize the health system with a maximum and optional initial value.
233
- /// </summary>
256
+ /// <summary>
257
+ /// Initialize the health system with a maximum and optional initial value.
258
+ /// </summary>
234
259
  void InitializeHealth(float maxHealth, float initialHealth = -1f, bool isNormalized = false);
235
- /// <summary>
236
- /// Set the current health (absolute units).
237
- /// </summary>
260
+ /// <summary>
261
+ /// Set the current health (absolute units).
262
+ /// </summary>
238
263
  void SetHealth(float health);
239
- /// <summary>
240
- /// Set the current health as a normalized value in [0,1].
241
- /// </summary>
264
+ /// <summary>
265
+ /// Set the current health as a normalized value in [0,1].
266
+ /// </summary>
242
267
  void SetHealthNormalized(float normalizedHealth);
243
- /// <summary>
244
- /// Add to the current health by an absolute amount.
245
- /// </summary>
268
+ /// <summary>
269
+ /// Add to the current health by an absolute amount.
270
+ /// </summary>
246
271
  void AddHealth(float amount);
247
- /// <summary>
248
- /// Remove from the current health by an absolute amount.
249
- /// </summary>
272
+ /// <summary>
273
+ /// Remove from the current health by an absolute amount.
274
+ /// </summary>
250
275
  void RemoveHealth(float amount);
251
- /// <summary>
252
- /// Get the current health (absolute units).
253
- /// </summary>
276
+ /// <summary>
277
+ /// Get the current health (absolute units).
278
+ /// </summary>
254
279
  float GetCurrentHealth();
255
- /// <summary>
256
- /// Get the maximum health (absolute units).
257
- /// </summary>
280
+ /// <summary>
281
+ /// Get the maximum health (absolute units).
282
+ /// </summary>
258
283
  float GetMaxHealth();
259
- /// <summary>
260
- /// Get the current health normalized to [0,1].
261
- /// </summary>
284
+ /// <summary>
285
+ /// Get the current health normalized to [0,1].
286
+ /// </summary>
262
287
  float GetHealthNormalized();
263
288
  }
264
289
 
265
290
  /// <summary>
266
291
  /// Public API for score and gameplay data management.
267
292
  /// </summary>
293
+ /// <remarks>
294
+ /// For deterministic physics replay, queue raw input from Update and record it in the
295
+ /// same FixedUpdate where the input is applied to the simulation.
296
+ /// </remarks>
268
297
  public interface IDataAPI
269
298
  {
270
- /// <summary>
271
- /// Current in-session score value.
272
- /// </summary>
299
+ /// <summary>
300
+ /// Current in-session score value.
301
+ /// </summary>
273
302
  int CurrentScore { get; }
274
303
 
275
- /// <summary>
276
- /// Overwrite the current score with a new value.
277
- /// </summary>
304
+ /// <summary>
305
+ /// Overwrite the current score with a new value.
306
+ /// </summary>
278
307
  void UpdateScore(int score);
279
- /// <summary>
280
- /// Set the combo multiplier applied to scoring.
281
- /// </summary>
308
+ /// <summary>Records one numeric replay value with a fixed-simulation-aligned session timestamp.</summary>
309
+ /// <param name="value">The value to record.</param>
310
+ /// <example><code>HyperSDK.Data.RecordActivity(0.39f); // [time, 0.39]</code></example>
311
+ void RecordActivity(float value);
312
+ /// <summary>Records two numeric replay values in the supplied order.</summary>
313
+ /// <param name="first">The first value.</param>
314
+ /// <param name="second">The second value.</param>
315
+ /// <example><code>HyperSDK.Data.RecordActivity(4f, 2f); // [time, 4, 2]</code></example>
316
+ void RecordActivity(float first, float second);
317
+ /// <summary>Records three numeric replay values in the supplied order.</summary>
318
+ /// <param name="first">The first value.</param>
319
+ /// <param name="second">The second value.</param>
320
+ /// <param name="third">The third value.</param>
321
+ /// <example><code>HyperSDK.Data.RecordActivity(1f, 5f, 3f); // [time, 1, 5, 3]</code></example>
322
+ void RecordActivity(float first, float second, float third);
323
+ /// <summary>Records one named replay action. GS, GP, GR, and GE are reserved by the SDK.</summary>
324
+ /// <param name="action">A non-empty game-defined action name.</param>
325
+ /// <example><code>HyperSDK.Data.RecordActivity("WoodenWand"); // [time, "WoodenWand"]</code></example>
326
+ void RecordActivity(string action);
327
+ /// <summary>Records two named replay actions in the supplied order.</summary>
328
+ /// <param name="firstAction">The first game-defined action.</param>
329
+ /// <param name="secondAction">The second game-defined action.</param>
330
+ /// <example><code>HyperSDK.Data.RecordActivity("D", "R"); // [time, "D", "R"]</code></example>
331
+ void RecordActivity(string firstAction, string secondAction);
332
+ /// <summary>Records a named action followed by one numeric value.</summary>
333
+ /// <param name="action">A non-empty game-defined action name.</param>
334
+ /// <param name="first">The numeric value associated with the action.</param>
335
+ /// <example><code>HyperSDK.Data.RecordActivity("B", 5f); // [time, "B", 5]</code></example>
336
+ void RecordActivity(string action, float first);
337
+ /// <summary>Records one numeric value followed by a named action.</summary>
338
+ /// <param name="first">The numeric value.</param>
339
+ /// <param name="action">A non-empty game-defined action name.</param>
340
+ /// <example><code>HyperSDK.Data.RecordActivity(5f, "B"); // [time, 5, "B"]</code></example>
341
+ void RecordActivity(float first, string action);
342
+ /// <summary>Records a named action followed by two numeric values.</summary>
343
+ /// <param name="action">A non-empty game-defined action name.</param>
344
+ /// <param name="first">The first numeric value.</param>
345
+ /// <param name="second">The second numeric value.</param>
346
+ /// <example><code>HyperSDK.Data.RecordActivity("B", 3f, 5f); // [time, "B", 3, 5]</code></example>
347
+ void RecordActivity(string action, float first, float second);
348
+ /// <summary>Records two numeric values followed by a named action.</summary>
349
+ /// <param name="first">The first numeric value.</param>
350
+ /// <param name="second">The second numeric value.</param>
351
+ /// <param name="action">A non-empty game-defined action name.</param>
352
+ /// <example><code>HyperSDK.Data.RecordActivity(4f, 2f, "R"); // [time, 4, 2, "R"]</code></example>
353
+ void RecordActivity(float first, float second, string action);
354
+ /// <summary>
355
+ /// Set the combo multiplier applied to scoring.
356
+ /// </summary>
282
357
  void SetComboMultiplier(float value);
283
- /// <summary>
284
- /// Set a global multiplier applied to scoring.
285
- /// </summary>
358
+ /// <summary>
359
+ /// Set a global multiplier applied to scoring.
360
+ /// </summary>
286
361
  void SetGlobalMultiplier(float value);
287
- /// <summary>
288
- /// Register that a powerup is active by type identifier.
289
- /// </summary>
362
+ /// <summary>
363
+ /// Register that a powerup is active by type identifier.
364
+ /// </summary>
290
365
  void AddPowerup(string powerupType);
291
- /// <summary>
292
- /// Remove an active powerup by type identifier.
293
- /// </summary>
366
+ /// <summary>
367
+ /// Remove an active powerup by type identifier.
368
+ /// </summary>
294
369
  void RemovePowerup(string powerupType);
295
- /// <summary>
296
- /// Retrieve the best/high score recorded for the player.
297
- /// </summary>
370
+ /// <summary>
371
+ /// Retrieve the best/high score recorded for the player.
372
+ /// </summary>
298
373
  int GetBestScore();
299
374
  }
300
375
 
@@ -334,44 +409,88 @@ namespace Hyper
334
409
  /// </summary>
335
410
  public interface IEventAPI
336
411
  {
337
- /// <summary>
338
- /// Fired when gameplay begins.
339
- /// </summary>
412
+ /// <summary>
413
+ /// Fired when gameplay begins.
414
+ /// </summary>
340
415
  event Action OnGameStart;
341
- /// <summary>
342
- /// Fired when the match timer reaches zero (battle mode).
343
- /// </summary>
416
+ /// <summary>
417
+ /// Fired when the match timer reaches zero (battle mode).
418
+ /// </summary>
344
419
  event Action OnTimeUp;
345
- /// <summary>
346
- /// Fired when the game is paused by the SDK.
347
- /// </summary>
420
+ /// <summary>
421
+ /// Fired when the game is paused by the SDK.
422
+ /// </summary>
348
423
  event Action OnGamePaused;
349
- /// <summary>
350
- /// Fired when the game resumes from a paused state.
351
- /// </summary>
424
+ /// <summary>
425
+ /// Fired when the game resumes from a paused state.
426
+ /// </summary>
352
427
  event Action OnGameResumed;
353
- /// <summary>
354
- /// Fired when the current game session ends.
355
- /// </summary>
428
+ /// <summary>
429
+ /// Fired when gameplay is frozen by setting <see cref="Time.timeScale"/> to zero.
430
+ /// </summary>
431
+ event Action OnTimeScaleFrozen;
432
+ /// <summary>
433
+ /// Fired when gameplay resumes from a zero <see cref="Time.timeScale"/>.
434
+ /// </summary>
435
+ event Action OnTimeScaleResumed;
436
+ /// <summary>
437
+ /// Fired when the current game session ends.
438
+ /// </summary>
356
439
  event Action OnGameEnded;
357
- /// <summary>
358
- /// Fired when the SDK sound setting changes (true = enabled).
359
- /// </summary>
440
+ /// <summary>
441
+ /// Fired when the SDK sound setting changes (true = enabled).
442
+ /// </summary>
360
443
  event Action<bool> OnSoundChanged;
361
- /// <summary>
362
- /// Fired when lives reach zero (when lives UI is in use).
363
- /// </summary>
444
+ /// <summary>
445
+ /// Fired when lives reach zero (when lives UI is in use).
446
+ /// </summary>
364
447
  event Action OnLivesExhausted;
365
- /// <summary>
366
- /// Fired when health reaches zero (when health UI is in use).
367
- /// </summary>
448
+ /// <summary>
449
+ /// Fired when health reaches zero (when health UI is in use).
450
+ /// </summary>
368
451
  event Action OnHealthExhausted;
369
- /// <summary>
370
- /// Fired when a custom restart flow is requested by the SDK.
371
- /// </summary>
452
+ /// <summary>
453
+ /// Fired when a custom restart flow is requested by the SDK.
454
+ /// </summary>
372
455
  event Action OnCustomRestart;
373
456
  }
374
457
 
458
+ /// <summary>
459
+ /// Callbacks for activities dispatched from an active replay. Games map
460
+ /// these callbacks to their existing gameplay commands.
461
+ /// </summary>
462
+ public interface IReplayAPI
463
+ {
464
+ event Action<float, float> OnValues2;
465
+ event Action<float> OnValue;
466
+ event Action<float, float, float> OnValues;
467
+ event Action<string> OnAction;
468
+ event Action<string, string> OnActions;
469
+ event Action<string, float, float> OnActionValues;
470
+ event Action<float, float, string> OnValuesAction;
471
+ event Action<string, float> OnActionValue;
472
+ event Action<float, string> OnValueAction;
473
+
474
+ /// <summary>
475
+ /// Fired before a named action when <see cref="ActionPreparationLeadSeconds"/>
476
+ /// is configured. Use it only for presentation such as button-down feedback.
477
+ /// </summary>
478
+ event Action<string> OnActionPreparing;
479
+
480
+ /// <summary>Fired when all replay activities have been dispatched.</summary>
481
+ event Action OnEnded;
482
+
483
+ bool IsPlaying { get; }
484
+ double DurationSeconds { get; }
485
+ double ElapsedSeconds { get; }
486
+ float Progress01 { get; }
487
+
488
+ /// <summary>
489
+ /// Optional visual lead time. Gameplay actions still fire at their recorded time.
490
+ /// </summary>
491
+ double ActionPreparationLeadSeconds { get; set; }
492
+ }
493
+
375
494
  /// <summary>
376
495
  /// Safe-area-adjusted screen dimensions.
377
496
  /// Use these instead of Screen.width / Screen.height to match the playable area after notch and system inset adjustments.
@@ -479,6 +598,7 @@ namespace Hyper
479
598
 
480
599
  public bool IsBattleMode => Manager != null && Manager.IsBattleMode;
481
600
  public bool IsPracticeMode => Manager != null && Manager.IsPracticeMode;
601
+ public bool IsReplayMode => Manager != null && Manager.IsReplayMode;
482
602
  public bool IsPaused => Manager != null && Manager.IsPaused;
483
603
  public bool HasGameStarted => Manager != null && Manager.HasGameStarted;
484
604
  public bool HasGameEnded => Manager != null && Manager.HasGameEnded;
@@ -523,6 +643,15 @@ namespace Hyper
523
643
  public int CurrentScore => Manager?.CurrentScore ?? 0;
524
644
 
525
645
  public void UpdateScore(int score) => Manager?.UpdateScore(score);
646
+ public void RecordActivity(float value) => Manager?.RecordActivity(value);
647
+ public void RecordActivity(float first, float second) => Manager?.RecordActivity(first, second);
648
+ public void RecordActivity(float first, float second, float third) => Manager?.RecordActivity(first, second, third);
649
+ public void RecordActivity(string action) => Manager?.RecordActivity(action);
650
+ public void RecordActivity(string firstAction, string secondAction) => Manager?.RecordActivity(firstAction, secondAction);
651
+ public void RecordActivity(string action, float first) => Manager?.RecordActivity(action, first);
652
+ public void RecordActivity(float first, string action) => Manager?.RecordActivity(first, action);
653
+ public void RecordActivity(string action, float first, float second) => Manager?.RecordActivity(action, first, second);
654
+ public void RecordActivity(float first, float second, string action) => Manager?.RecordActivity(first, second, action);
526
655
  public void SetComboMultiplier(float value) => Manager?.SetComboMultiplier(value);
527
656
  public void SetGlobalMultiplier(float value) => Manager?.SetGlobalMultiplier(value);
528
657
  public void AddPowerup(string powerupType) => Manager?.AddPowerup(powerupType);
@@ -530,6 +659,41 @@ namespace Hyper
530
659
  public int GetBestScore() => Manager?.GetBestScore() ?? 0;
531
660
  }
532
661
 
662
+ /// <summary>
663
+ /// Bridges the SDK-owned scheduler to game-specific replay handlers.
664
+ /// </summary>
665
+ internal sealed class ReplayAPIAdapter : IReplayAPI
666
+ {
667
+ private readonly ReplayPlaybackEngine _playback = new ReplayPlaybackEngine();
668
+
669
+ public event Action<float, float> OnValues2 { add => _playback.OnValues2 += value; remove => _playback.OnValues2 -= value; }
670
+ public event Action<float> OnValue { add => _playback.OnValue += value; remove => _playback.OnValue -= value; }
671
+ public event Action<float, float, float> OnValues { add => _playback.OnValues += value; remove => _playback.OnValues -= value; }
672
+ public event Action<string> OnAction { add => _playback.OnAction += value; remove => _playback.OnAction -= value; }
673
+ public event Action<string, string> OnActions { add => _playback.OnActions += value; remove => _playback.OnActions -= value; }
674
+ public event Action<string, float, float> OnActionValues { add => _playback.OnActionValues += value; remove => _playback.OnActionValues -= value; }
675
+ public event Action<float, float, string> OnValuesAction { add => _playback.OnValuesAction += value; remove => _playback.OnValuesAction -= value; }
676
+ public event Action<string, float> OnActionValue { add => _playback.OnActionValue += value; remove => _playback.OnActionValue -= value; }
677
+ public event Action<float, string> OnValueAction { add => _playback.OnValueAction += value; remove => _playback.OnValueAction -= value; }
678
+ public event Action<string> OnActionPreparing { add => _playback.OnActionPreparing += value; remove => _playback.OnActionPreparing -= value; }
679
+ public event Action OnEnded { add => _playback.OnGameEnded += value; remove => _playback.OnGameEnded -= value; }
680
+
681
+ public bool IsPlaying => _playback.IsPlaying;
682
+ public double DurationSeconds => _playback.DurationSeconds;
683
+ public double ElapsedSeconds => _playback.ElapsedSeconds;
684
+ public float Progress01 => _playback.Progress01;
685
+ public double ActionPreparationLeadSeconds
686
+ {
687
+ get => _playback.ActionPreparationLeadSeconds;
688
+ set => _playback.ActionPreparationLeadSeconds = Math.Max(0d, value);
689
+ }
690
+
691
+ internal void RefreshBindings()
692
+ {
693
+ HyperRuntime.ReplayManager?.AttachPlayback(_playback);
694
+ }
695
+ }
696
+
533
697
  /// <summary>
534
698
  /// Bridges SDK events to consumers while allowing subscriptions before initialization.
535
699
  /// </summary>
@@ -541,6 +705,8 @@ namespace Hyper
541
705
  private Action _onTimeUp;
542
706
  private Action _onGamePaused;
543
707
  private Action _onGameResumed;
708
+ private Action _onTimeScaleFrozen;
709
+ private Action _onTimeScaleResumed;
544
710
  private Action _onGameEnded;
545
711
  private Action<bool> _onSoundChanged;
546
712
  private Action _onLivesExhausted;
@@ -551,6 +717,8 @@ namespace Hyper
551
717
  private Action _timeUpBridge;
552
718
  private Action _gamePausedBridge;
553
719
  private Action _gameResumedBridge;
720
+ private Action _timeScaleFrozenBridge;
721
+ private Action _timeScaleResumedBridge;
554
722
  private Action _gameEndedBridge;
555
723
  private Action<bool> _soundChangedBridge;
556
724
  private Action _livesExhaustedBridge;
@@ -597,6 +765,26 @@ namespace Hyper
597
765
  remove => _onGameResumed -= value;
598
766
  }
599
767
 
768
+ public event Action OnTimeScaleFrozen
769
+ {
770
+ add
771
+ {
772
+ _onTimeScaleFrozen += value;
773
+ RefreshBindings();
774
+ }
775
+ remove => _onTimeScaleFrozen -= value;
776
+ }
777
+
778
+ public event Action OnTimeScaleResumed
779
+ {
780
+ add
781
+ {
782
+ _onTimeScaleResumed += value;
783
+ RefreshBindings();
784
+ }
785
+ remove => _onTimeScaleResumed -= value;
786
+ }
787
+
600
788
  public event Action OnGameEnded
601
789
  {
602
790
  add
@@ -671,6 +859,8 @@ namespace Hyper
671
859
  _timeUpBridge = () => _onTimeUp?.Invoke();
672
860
  _gamePausedBridge = () => _onGamePaused?.Invoke();
673
861
  _gameResumedBridge = () => _onGameResumed?.Invoke();
862
+ _timeScaleFrozenBridge = () => _onTimeScaleFrozen?.Invoke();
863
+ _timeScaleResumedBridge = () => _onTimeScaleResumed?.Invoke();
674
864
  _gameEndedBridge = () => _onGameEnded?.Invoke();
675
865
  _soundChangedBridge = enabled => _onSoundChanged?.Invoke(enabled);
676
866
  _livesExhaustedBridge = () => _onLivesExhausted?.Invoke();
@@ -681,6 +871,8 @@ namespace Hyper
681
871
  manager.OnTimeUp += _timeUpBridge;
682
872
  manager.OnGamePaused += _gamePausedBridge;
683
873
  manager.OnGameResumed += _gameResumedBridge;
874
+ manager.OnTimeScaleFrozen += _timeScaleFrozenBridge;
875
+ manager.OnTimeScaleResumed += _timeScaleResumedBridge;
684
876
  manager.OnGameEnded += _gameEndedBridge;
685
877
  manager.OnSoundChanged += _soundChangedBridge;
686
878
  manager.OnLivesExhausted += _livesExhaustedBridge;
@@ -701,6 +893,8 @@ namespace Hyper
701
893
  if (_timeUpBridge != null) _attachedManager.OnTimeUp -= _timeUpBridge;
702
894
  if (_gamePausedBridge != null) _attachedManager.OnGamePaused -= _gamePausedBridge;
703
895
  if (_gameResumedBridge != null) _attachedManager.OnGameResumed -= _gameResumedBridge;
896
+ if (_timeScaleFrozenBridge != null) _attachedManager.OnTimeScaleFrozen -= _timeScaleFrozenBridge;
897
+ if (_timeScaleResumedBridge != null) _attachedManager.OnTimeScaleResumed -= _timeScaleResumedBridge;
704
898
  if (_gameEndedBridge != null) _attachedManager.OnGameEnded -= _gameEndedBridge;
705
899
  if (_soundChangedBridge != null) _attachedManager.OnSoundChanged -= _soundChangedBridge;
706
900
  if (_livesExhaustedBridge != null) _attachedManager.OnLivesExhausted -= _livesExhaustedBridge;
@@ -711,6 +905,8 @@ namespace Hyper
711
905
  _timeUpBridge = null;
712
906
  _gamePausedBridge = null;
713
907
  _gameResumedBridge = null;
908
+ _timeScaleFrozenBridge = null;
909
+ _timeScaleResumedBridge = null;
714
910
  _gameEndedBridge = null;
715
911
  _soundChangedBridge = null;
716
912
  _livesExhaustedBridge = null;
@@ -3,7 +3,8 @@
3
3
  "rootNamespace": "Hyper",
4
4
  "references": [
5
5
  "GUID:a05ed6f43b536684b893d8a6a28d33bc",
6
- "GUID:a701715b74d53214c9a994c9a64f14b6"
6
+ "GUID:a701715b74d53214c9a994c9a64f14b6",
7
+ "GUID:6055be8ebefd69e48b49212b09b47b2f"
7
8
  ],
8
9
  "includePlatforms": [],
9
10
  "excludePlatforms": [],