app.hypergames.hypersdk 1.11.0-beta.20 → 1.11.0-beta.21

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,10 @@
1
+ # [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)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **replay:** align gameplay activities to fixed ticks ([1e681b9](https://github.com/mvmhyper/hyper-sdk/commit/1e681b9c7f314a48c417f6e76cb2d4024c890ad3))
7
+
1
8
  # [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)
2
9
 
3
10
 
@@ -29,6 +29,13 @@ namespace Hyper
29
29
  private double _stoppedElapsed;
30
30
  private bool _isSuspended;
31
31
  private bool _completionPending;
32
+ private bool _gameplayClockStarted;
33
+ private double _gameplaySourceStartTime;
34
+ private double _gameplayElapsedSeconds;
35
+ private double _gameplayStepSeconds;
36
+ private double _gameplayPauseDurationAtStart;
37
+ private long _gameplayTick;
38
+ private double _currentTickDelta;
32
39
 
33
40
  public event Action<float, float> OnValues2;
34
41
  public event Action<float> OnValue;
@@ -76,6 +83,13 @@ namespace Hyper
76
83
  _endedRaised = false;
77
84
  _completionPending = false;
78
85
  _nextActionPrepared = false;
86
+ _gameplayClockStarted = false;
87
+ _gameplaySourceStartTime = 0d;
88
+ _gameplayElapsedSeconds = 0d;
89
+ _gameplayStepSeconds = 0d;
90
+ _gameplayPauseDurationAtStart = 0d;
91
+ _gameplayTick = 0L;
92
+ _currentTickDelta = 0d;
79
93
  DurationSeconds = CalculateDuration(_ndjson);
80
94
  double gameplayStartSeconds = CalculateGameplayStart(_ndjson, out bool hasGameplayReadyMarker);
81
95
  HasGameplayReadyMarker = hasGameplayReadyMarker;
@@ -122,13 +136,19 @@ namespace Hyper
122
136
  double.IsInfinity(fixedSimulationDeltaSeconds)
123
137
  ? 0d
124
138
  : Math.Max(0d, fixedSimulationDeltaSeconds);
139
+ _currentTickDelta = delta;
125
140
  _elapsedSeconds += delta;
141
+ if (_gameplayClockStarted && delta > 0d)
142
+ {
143
+ if (_gameplayStepSeconds <= 0d) _gameplayStepSeconds = delta;
144
+ _gameplayElapsedSeconds += delta;
145
+ _gameplayTick++;
146
+ }
126
147
 
127
148
  int processed = 0;
128
149
  while (IsPlaying && !_completionPending && _hasNext && processed++ < MaxActivitiesPerTick)
129
150
  {
130
- double elapsed = GetElapsedSeconds();
131
- double dueTime = _next.Time - _sourceStartTime - _removedPauseDuration;
151
+ GetSchedulingTime(_next, out double elapsed, out double dueTime);
132
152
  PrepareNextActionIfDue(elapsed, dueTime);
133
153
  if (elapsed + 0.000001d < dueTime) return;
134
154
 
@@ -154,6 +174,13 @@ namespace Hyper
154
174
  _isSuspended = false;
155
175
  _completionPending = false;
156
176
  _nextActionPrepared = false;
177
+ _gameplayClockStarted = false;
178
+ _gameplaySourceStartTime = 0d;
179
+ _gameplayElapsedSeconds = 0d;
180
+ _gameplayStepSeconds = 0d;
181
+ _gameplayPauseDurationAtStart = 0d;
182
+ _gameplayTick = 0L;
183
+ _currentTickDelta = 0d;
157
184
  }
158
185
 
159
186
  public void Suspend()
@@ -224,6 +251,7 @@ namespace Hyper
224
251
  OnGameStarted?.Invoke();
225
252
  break;
226
253
  case GameplayReady:
254
+ StartGameplayClock(activity.Time);
227
255
  OnGameplayReady?.Invoke();
228
256
  break;
229
257
  case GamePaused:
@@ -255,6 +283,47 @@ namespace Hyper
255
283
  OnActionPreparing?.Invoke(_next.Action);
256
284
  }
257
285
 
286
+ private void StartGameplayClock(double sourceTime)
287
+ {
288
+ _gameplayClockStarted = true;
289
+ _gameplaySourceStartTime = sourceTime;
290
+ _gameplayElapsedSeconds = 0d;
291
+ _gameplayStepSeconds = _currentTickDelta;
292
+ _gameplayPauseDurationAtStart = _removedPauseDuration;
293
+ _gameplayTick = 0L;
294
+ }
295
+
296
+ private void GetSchedulingTime(ReplayActivity activity, out double elapsed, out double dueTime)
297
+ {
298
+ if (!_gameplayClockStarted)
299
+ {
300
+ elapsed = GetElapsedSeconds();
301
+ dueTime = activity.Time - _sourceStartTime - _removedPauseDuration;
302
+ return;
303
+ }
304
+
305
+ double removedGameplayPauses = Math.Max(0d,
306
+ _removedPauseDuration - _gameplayPauseDurationAtStart);
307
+ double rawDueTime = Math.Max(0d,
308
+ activity.Time - _gameplaySourceStartTime - removedGameplayPauses);
309
+
310
+ if (_gameplayStepSeconds <= 0d)
311
+ {
312
+ elapsed = _gameplayElapsedSeconds;
313
+ dueTime = rawDueTime;
314
+ return;
315
+ }
316
+
317
+ // Gameplay can only consume an activity on a fixed step. Mapping the
318
+ // timestamp to its nearest GPR-relative tick prevents sub-step JSON
319
+ // precision noise from moving an input to the following physics step.
320
+ long dueTick = Math.Max(0L, (long)Math.Round(
321
+ rawDueTime / _gameplayStepSeconds,
322
+ MidpointRounding.AwayFromZero));
323
+ elapsed = _gameplayTick * _gameplayStepSeconds;
324
+ dueTime = dueTick * _gameplayStepSeconds;
325
+ }
326
+
258
327
  private static bool IsLifecycleAction(string action)
259
328
  {
260
329
  return action == GameStarted || action == GamePaused ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "app.hypergames.hypersdk",
3
- "version": "1.11.0-beta.20",
3
+ "version": "1.11.0-beta.21",
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",