app.hypergames.hypersdk 1.11.0-beta.1 → 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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ # [1.11.0-beta.2](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.1...v1.11.0-beta.2) (2026-08-27)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **replay:** respect custom restart flows ([7470a17](https://github.com/mvmhyper/hyper-sdk/commit/7470a17c60534465500a202c24b0e360f61850fc))
7
+ * **replay:** shorten automatic replay start ([d05dc92](https://github.com/mvmhyper/hyper-sdk/commit/d05dc9267fbf05d392135eac3bb7c4f69b786eff))
8
+ * **timer:** align game time with fixed simulation ([b690d86](https://github.com/mvmhyper/hyper-sdk/commit/b690d861e178f05b21f1a7fbd87e255d97008a8b))
9
+
1
10
  # [1.11.0-beta.1](https://github.com/mvmhyper/hyper-sdk/compare/v1.10.0...v1.11.0-beta.1) (2026-08-26)
2
11
 
3
12
 
@@ -118,13 +118,13 @@ namespace Hyper.Internal
118
118
  }
119
119
 
120
120
  /// <summary>
121
- /// Restarts a replay from HyperLoader even when custom restart is enabled.
122
- /// Replay metadata, including the original seed value, remains available to the loader.
121
+ /// Restarts replay playback while preserving its downloaded data and original seed.
122
+ /// Uses the configured custom restart flow when available, otherwise reloads HyperLoader.
123
123
  /// </summary>
124
124
  internal static void RestartReplaySession()
125
125
  {
126
126
  ReplaySessionState.ResetForWatchAgain();
127
- RestartReplayFromLoader();
127
+ RestartReplay();
128
128
  }
129
129
 
130
130
  internal static void SeekReplaySession(float targetProgress, float resumeSpeed, float seekSpeed)
@@ -133,14 +133,25 @@ namespace Hyper.Internal
133
133
 
134
134
  ReplaySessionState.RequestSeek(targetProgress, resumeSpeed, seekSpeed);
135
135
  ReplaySessionState.ResetForSeekRestart();
136
- RestartReplayFromLoader();
136
+ RestartReplay();
137
137
  }
138
138
 
139
- private static void RestartReplayFromLoader()
139
+ private static void RestartReplay()
140
140
  {
141
141
  _isSoftRestarting = true;
142
142
  Time.timeScale = 1f;
143
143
 
144
+ if (_settings != null && _settings.useCustomRestartFlow &&
145
+ _gameManager != null && _eventManager != null)
146
+ {
147
+ _replayManager?.PrepareForRestart();
148
+ ResetReplayRandomState();
149
+ _gameManager.ResetUIStateForCustomRestart();
150
+ _eventManager.InvokeCustomRestartEvent();
151
+ _isSoftRestarting = false;
152
+ return;
153
+ }
154
+
144
155
  if (_host != null)
145
156
  {
146
157
  _host.StartCoroutine(RestartSessionCoroutine());
@@ -152,6 +163,19 @@ namespace Hyper.Internal
152
163
  }
153
164
  }
154
165
 
166
+ internal static void ResetReplayRandomState()
167
+ {
168
+ int originalSeed = unchecked((int)ReplaySessionState.OriginalRandomSeed);
169
+ if (HyperRandom.CurrentSeed == originalSeed)
170
+ {
171
+ // Preserve references held by game code while rewinding every stream.
172
+ HyperRandom.ResetAll();
173
+ return;
174
+ }
175
+
176
+ HyperRandom.Init(ReplaySessionState.OriginalRandomSeed);
177
+ }
178
+
155
179
  /// <summary>
156
180
  /// Coroutine-based restart that properly unloads all scenes before reloading.
157
181
  /// Handles async scene operations and ensures clean state before restart.
@@ -1068,20 +1068,33 @@ namespace Hyper.Internal.Managers
1068
1068
  {
1069
1069
  HideGameOverModal();
1070
1070
  HidePauseModals();
1071
+ if (_replayOverModal != null) _replayOverModal.SetActive(false);
1071
1072
 
1072
1073
  // Reset game state flags
1073
1074
  _hasGameStarted = false;
1074
1075
  _gameStartRequested = false;
1075
1076
  _hasGameEnded = false;
1077
+ _replayEndHandled = false;
1078
+ _replayFocusSuspended = false;
1076
1079
  _isPaused = false;
1077
1080
  _isFrozenBeforePause = false;
1078
1081
 
1079
- HyperRuntime.Timer.Reset();
1082
+ HyperRuntime.Timer.ResetForGameRestart();
1080
1083
  HyperRuntime.DataManager.UpdateScore(0);
1081
1084
  HyperRuntime.DataManager.RestoreAudioAfterGameSessionEnd();
1082
1085
 
1083
1086
  ShowControlBarElements();
1084
- ShowStartingInstructionModal();
1087
+ _replayControllerComponent?.ResetForReplayRestart();
1088
+
1089
+ if (IsReplayMode && ReplaySessionState.IsSeeking)
1090
+ {
1091
+ HideStartingInstructionModal();
1092
+ StartCoroutine(StartSeekingReplayWhenReady());
1093
+ }
1094
+ else
1095
+ {
1096
+ ShowStartingInstructionModal();
1097
+ }
1085
1098
  }
1086
1099
 
1087
1100
  #endregion
@@ -39,6 +39,12 @@ namespace Hyper.Internal.Managers
39
39
  ReplaySessionState.SetProgress(_playback.Progress01);
40
40
  }
41
41
 
42
+ internal void PrepareForRestart()
43
+ {
44
+ _endingGame = false;
45
+ _playback?.Stop();
46
+ }
47
+
42
48
  internal void Cleanup()
43
49
  {
44
50
  if (_eventManager != null)
@@ -43,7 +43,7 @@ namespace Hyper.Internal.Managers
43
43
  private bool _isSessionRunning;
44
44
  private bool _sessionWarningTriggered;
45
45
  private bool _timeUpTriggered;
46
- private bool _replayTimeUpPending;
46
+ private bool _timeUpPending;
47
47
 
48
48
  private float _lastUnscaledTime;
49
49
  private bool _hasGameEnded;
@@ -65,7 +65,7 @@ namespace Hyper.Internal.Managers
65
65
  _hasBackendSessionDuration = false;
66
66
  _lastUnscaledTime = Time.unscaledTime;
67
67
  _timeUpTriggered = false;
68
- _replayTimeUpPending = false;
68
+ _timeUpPending = false;
69
69
  }
70
70
 
71
71
  #endregion
@@ -91,27 +91,21 @@ namespace Hyper.Internal.Managers
91
91
  float unscaledDelta = Time.unscaledTime - _lastUnscaledTime;
92
92
  _lastUnscaledTime = Time.unscaledTime;
93
93
 
94
- if (!_gameManager.IsReplayMode)
95
- {
96
- float gameTimerDelta = Mathf.Approximately(Time.timeScale, 0f)
97
- ? 0f
98
- : unscaledDelta;
99
-
100
- UpdatePracticeTimer(gameTimerDelta);
101
- UpdateBattleTimer(gameTimerDelta);
102
- }
103
-
104
94
  UpdateSessionTimer(unscaledDelta);
105
- DispatchPendingReplayTimeUp();
95
+ DispatchPendingTimeUp();
106
96
  }
107
97
 
108
98
  internal void FixedTick()
109
99
  {
110
- if (!_gameManager.IsReplayMode || Mathf.Approximately(Time.timeScale, 0f))
100
+ if (Mathf.Approximately(Time.timeScale, 0f))
111
101
  return;
112
102
 
113
- UpdatePracticeTimer(Time.fixedDeltaTime);
114
- UpdateBattleTimer(Time.fixedDeltaTime, true);
103
+ float gameTimerDelta = _gameManager != null && _gameManager.IsReplayMode
104
+ ? Time.fixedDeltaTime
105
+ : Time.fixedUnscaledDeltaTime;
106
+
107
+ UpdatePracticeTimer(gameTimerDelta);
108
+ UpdateBattleTimer(gameTimerDelta);
115
109
  }
116
110
 
117
111
  public void Reset()
@@ -120,6 +114,19 @@ namespace Hyper.Internal.Managers
120
114
  _lastUnscaledTime = Time.unscaledTime;
121
115
  }
122
116
 
117
+ internal void ResetForGameRestart()
118
+ {
119
+ _practiceTimer = 0f;
120
+ _battleTimer = _gameManager != null ? _gameManager.Config.TimeLimit : 0f;
121
+ _isPracticeRunning = false;
122
+ _isBattleRunning = false;
123
+ _timeUpTriggered = false;
124
+ _timeUpPending = false;
125
+ _hasGameEnded = false;
126
+ _hasGameStarted = false;
127
+ _lastUnscaledTime = Time.unscaledTime;
128
+ }
129
+
123
130
  public void ResumeGameTimersAfterPause()
124
131
  {
125
132
  if (_gameManager.IsBattleMode)
@@ -150,7 +157,7 @@ namespace Hyper.Internal.Managers
150
157
  public void StopAllTimers()
151
158
  {
152
159
  _hasGameEnded = true;
153
- _replayTimeUpPending = false;
160
+ _timeUpPending = false;
154
161
  StopBattle();
155
162
  StopPractice();
156
163
  }
@@ -262,7 +269,7 @@ namespace Hyper.Internal.Managers
262
269
  }
263
270
  }
264
271
 
265
- private void UpdateBattleTimer(float delta, bool deferTimeUp = false)
272
+ private void UpdateBattleTimer(float delta)
266
273
  {
267
274
  if (_isBattleRunning)
268
275
  {
@@ -280,7 +287,7 @@ namespace Hyper.Internal.Managers
280
287
  _battleTimer = 0;
281
288
  if (!_timeUpTriggered)
282
289
  {
283
- TriggerTimeUp(deferTimeUp);
290
+ QueueTimeUp();
284
291
  }
285
292
  }
286
293
  }
@@ -292,30 +299,23 @@ namespace Hyper.Internal.Managers
292
299
 
293
300
  if (_battleTimer <= 0 && !_timeUpTriggered)
294
301
  {
295
- TriggerTimeUp(deferTimeUp);
302
+ QueueTimeUp();
296
303
  }
297
304
  }
298
305
  }
299
306
  }
300
307
 
301
- private void TriggerTimeUp(bool defer)
308
+ private void QueueTimeUp()
302
309
  {
303
- if (defer)
304
- {
305
- _replayTimeUpPending = true;
306
- return;
307
- }
308
-
309
- _timeUpTriggered = true;
310
- _eventManager?.InvokeTimeUpEvent();
310
+ _timeUpPending = true;
311
311
  }
312
312
 
313
- private void DispatchPendingReplayTimeUp()
313
+ private void DispatchPendingTimeUp()
314
314
  {
315
- if (!_replayTimeUpPending)
315
+ if (!_timeUpPending)
316
316
  return;
317
317
 
318
- _replayTimeUpPending = false;
318
+ _timeUpPending = false;
319
319
  if (_hasGameEnded || _timeUpTriggered)
320
320
  return;
321
321
 
@@ -132,6 +132,32 @@ namespace Hyper.Internal
132
132
  if (progressSlider != null) progressSlider.SetValueWithoutNotify(1f);
133
133
  }
134
134
 
135
+ internal void ResetForReplayRestart()
136
+ {
137
+ float playbackSpeed = ReplaySessionState.UserPlaybackSpeed;
138
+ if (!ReplaySessionState.IsSeeking && playbackSpeeds != null && playbackSpeeds.Length > 0)
139
+ {
140
+ playbackSpeed = SanitizePlaybackSpeed(playbackSpeeds[0]);
141
+ ReplaySessionState.SetPlaybackSpeed(playbackSpeed);
142
+ Time.timeScale = playbackSpeed;
143
+ }
144
+
145
+ isCapturingSeek = false;
146
+ pendingSeekTarget = ReplaySessionState.IsSeeking
147
+ ? ReplaySessionState.SeekTarget01
148
+ : 0f;
149
+ wasSeeking = ReplaySessionState.IsSeeking;
150
+
151
+ if (progressSlider != null)
152
+ {
153
+ progressSlider.SetValueWithoutNotify(pendingSeekTarget);
154
+ }
155
+
156
+ UpdatePlaybackSpeedLabel(playbackSpeed);
157
+ AlignPlaybackSpeedIndex(playbackSpeed);
158
+ SetSeekingPresentation(ReplaySessionState.IsSeeking);
159
+ }
160
+
135
161
  private void ExitReplay()
136
162
  {
137
163
  if (exitButton != null) exitButton.interactable = false;
@@ -23,6 +23,13 @@ namespace Hyper.Internal
23
23
  if (exitButton != null) exitButton.onClick.AddListener(Exit);
24
24
  }
25
25
 
26
+ private void OnEnable()
27
+ {
28
+ _handled = false;
29
+ if (watchAgainButton != null) watchAgainButton.interactable = true;
30
+ if (exitButton != null) exitButton.interactable = true;
31
+ }
32
+
26
33
  private void OnDestroy()
27
34
  {
28
35
  if (watchAgainButton != null) watchAgainButton.onClick.RemoveListener(WatchAgain);
@@ -14,7 +14,7 @@ namespace Hyper.Internal
14
14
  [SerializeField] private BlinkingText blinkingText;
15
15
  [SerializeField] private RectTransform swipeGif;
16
16
  [SerializeField] private RectTransform handSpriteInGif;
17
- [SerializeField] private float replayAutoStartDelay = 2f;
17
+ [SerializeField] private float replayAutoStartDelay = 1f;
18
18
  private GameManager _gameManager;
19
19
  private StartCTA _currentCTA;
20
20
  private SwipeDirection _swipeDirection;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "app.hypergames.hypersdk",
3
- "version": "1.11.0-beta.1",
3
+ "version": "1.11.0-beta.2",
4
4
  "displayName": "HyperSDK",
5
5
  "description": "Official Unity SDK for Hyper: multiplayer battles, leaderboards, deterministic RNG, session management, tutorials, and WebGL optimizations for production-ready games.",
6
6
  "unity": "6000.0",