app.hypergames.hypersdk 1.9.1 → 1.11.0-beta.1

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 (124) hide show
  1. package/CHANGELOG.md +37 -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 +58 -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 +350 -15
  12. package/Runtime/Internal/Managers/ReplayManager.cs +111 -0
  13. package/Runtime/Internal/Managers/ReplayManager.cs.meta +11 -0
  14. package/Runtime/Internal/Managers/TimeManager.cs +56 -14
  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/ConcaveImage.cs +147 -0
  23. package/Runtime/Internal/UI/Components/ConcaveImage.cs.meta +11 -0
  24. package/Runtime/Internal/UI/Components/ControlBar.cs +86 -6
  25. package/Runtime/Internal/UI/Components/PauseButton.cs +4 -1
  26. package/Runtime/Internal/UI/Components/ReplayController.cs +501 -0
  27. package/Runtime/Internal/UI/Components/ReplayController.cs.meta +2 -0
  28. package/Runtime/Internal/UI/Components/ReplayMarkerPulse.cs +89 -0
  29. package/Runtime/Internal/UI/Components/ReplayMarkerPulse.cs.meta +2 -0
  30. package/Runtime/Internal/UI/Components/ReplayPresentationCanvas.cs +183 -0
  31. package/Runtime/Internal/UI/Components/ReplayPresentationCanvas.cs.meta +2 -0
  32. package/Runtime/Internal/UI/Components/SnackBar.cs +2 -9
  33. package/Runtime/Internal/UI/Modals/LoadingFailedModal.cs +12 -0
  34. package/Runtime/Internal/UI/Modals/ReplayOverModal.cs +54 -0
  35. package/Runtime/Internal/UI/Modals/ReplayOverModal.cs.meta +2 -0
  36. package/Runtime/Internal/UI/Modals/StartingInstructionModal.cs +38 -29
  37. package/Runtime/Public/AssemblyInfo.cs +3 -0
  38. package/Runtime/Public/AssemblyInfo.cs.meta +2 -0
  39. package/Runtime/Public/Core/HyperSDK.cs +305 -109
  40. package/Runtime/Public/Hyper.asmdef +2 -1
  41. package/Runtime/Public/Replay/ReplayPlaybackEngine.cs +555 -0
  42. package/Runtime/Public/Replay/ReplayPlaybackEngine.cs.meta +2 -0
  43. package/Runtime/Public/Replay.meta +8 -0
  44. package/Runtime/Resources/Fonts/Nunito/Nunito-Light SDF.asset +528 -521
  45. package/Runtime/Resources/Materials/HyperReplayScanlines.preset +340 -0
  46. package/Runtime/Resources/Materials/HyperReplayScanlines.preset.meta +8 -0
  47. package/Runtime/Resources/Materials/ReplayScanlineOverlay.mat +55 -0
  48. package/Runtime/Resources/Materials/ReplayScanlineOverlay.mat.meta +8 -0
  49. package/Runtime/Resources/Shaders/ConcaveImage.shader +155 -0
  50. package/Runtime/Resources/Shaders/ConcaveImage.shader.meta +10 -0
  51. package/Runtime/Resources/Shaders/ReplayScanlineOverlay.shader +150 -0
  52. package/Runtime/Resources/Shaders/ReplayScanlineOverlay.shader.meta +10 -0
  53. package/Runtime/Resources/Sprites/Replays/Fallback avatar.png +0 -0
  54. package/Runtime/Resources/Sprites/Replays/Fallback avatar.png.meta +156 -0
  55. package/Runtime/Resources/Sprites/Replays/Recording.png +0 -0
  56. package/Runtime/Resources/Sprites/{Control Bar/Top_Black_Rounded_Bar_Portrait_IV.png.meta → Replays/Recording.png.meta} +16 -29
  57. package/Runtime/Resources/Sprites/Replays/Replay frame.png +0 -0
  58. package/Runtime/Resources/Sprites/Replays/Replay frame.png.meta +156 -0
  59. package/Runtime/Resources/Sprites/Replays/Replay modal icon.png +0 -0
  60. package/Runtime/Resources/Sprites/Replays/Replay modal icon.png.meta +156 -0
  61. package/Runtime/Resources/Sprites/Replays.meta +8 -0
  62. package/Runtime/Resources/UIPrefabs/ControlBar.prefab +389 -42
  63. package/Runtime/Resources/UIPrefabs/GamePausedModal_Battle.prefab +1 -1
  64. package/Runtime/Resources/UIPrefabs/ReplayController.prefab +1269 -0
  65. package/Runtime/Resources/UIPrefabs/ReplayController.prefab.meta +7 -0
  66. package/Runtime/Resources/UIPrefabs/ReplayInputBlocker.prefab +90 -0
  67. package/Runtime/Resources/UIPrefabs/ReplayInputBlocker.prefab.meta +7 -0
  68. package/Runtime/Resources/UIPrefabs/ReplayOverModal.prefab +958 -0
  69. package/Runtime/Resources/UIPrefabs/ReplayOverModal.prefab.meta +7 -0
  70. package/Runtime/Resources/UIPrefabs/ReplaySeekOverlay.prefab +189 -0
  71. package/Runtime/Resources/UIPrefabs/ReplaySeekOverlay.prefab.meta +7 -0
  72. package/Runtime/Resources/UIPrefabs/Rounded Cutout.prefab +96 -0
  73. package/Runtime/Resources/UIPrefabs/Rounded Cutout.prefab.meta +7 -0
  74. package/Runtime/Resources/UIPrefabs/SnackBar.prefab +23 -6
  75. package/Runtime/Shared/AssemblyInfo.cs +5 -0
  76. package/Runtime/Shared/AssemblyInfo.cs.meta +11 -0
  77. package/Runtime/Shared/DTOs/Enums.cs +8 -3
  78. package/Runtime/Shared/DTOs/Score/ScoreSnapshot.cs +13 -1
  79. package/Runtime/Shared/Replay/IReplayPlaybackEngine.cs +37 -0
  80. package/Runtime/Shared/Replay/IReplayPlaybackEngine.cs.meta +11 -0
  81. package/Runtime/Shared/Replay.meta +8 -0
  82. package/Runtime/Shared/Utils/HyperRandom.cs +25 -5
  83. package/Samples~/LaneRunner/LaneRunnerSample.unity +1603 -0
  84. package/Samples~/LaneRunner/LaneRunnerSample.unity.meta +7 -0
  85. package/Samples~/LaneRunner/Materials/DoubleScore.mat +86 -0
  86. package/Samples~/LaneRunner/Materials/DoubleScore.mat.meta +8 -0
  87. package/Samples~/LaneRunner/Materials/Ground.mat +84 -0
  88. package/Samples~/LaneRunner/Materials/Ground.mat.meta +8 -0
  89. package/Samples~/LaneRunner/Materials/Lane.mat +84 -0
  90. package/Samples~/LaneRunner/Materials/Lane.mat.meta +8 -0
  91. package/Samples~/LaneRunner/Materials/LaneMarker.mat +84 -0
  92. package/Samples~/LaneRunner/Materials/LaneMarker.mat.meta +8 -0
  93. package/Samples~/LaneRunner/Materials/Obstacle.mat +84 -0
  94. package/Samples~/LaneRunner/Materials/Obstacle.mat.meta +8 -0
  95. package/Samples~/LaneRunner/Materials/Player.mat +84 -0
  96. package/Samples~/LaneRunner/Materials/Player.mat.meta +8 -0
  97. package/Samples~/LaneRunner/Materials.meta +8 -0
  98. package/Samples~/LaneRunner/Prefabs/DoubleScorePickup.prefab +152 -0
  99. package/Samples~/LaneRunner/Prefabs/DoubleScorePickup.prefab.meta +7 -0
  100. package/Samples~/LaneRunner/Prefabs/Obstacle.prefab +152 -0
  101. package/Samples~/LaneRunner/Prefabs/Obstacle.prefab.meta +7 -0
  102. package/Samples~/LaneRunner/Prefabs.meta +8 -0
  103. package/Samples~/LaneRunner/README.md +35 -0
  104. package/Samples~/LaneRunner/README.md.meta +7 -0
  105. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerCommand.cs +9 -0
  106. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerCommand.cs.meta +2 -0
  107. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerGame.cs +93 -0
  108. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerGame.cs.meta +2 -0
  109. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerPlayer.cs +155 -0
  110. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerPlayer.cs.meta +2 -0
  111. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerSpawner.cs +110 -0
  112. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerSpawner.cs.meta +2 -0
  113. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerTrackItem.cs +41 -0
  114. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerTrackItem.cs.meta +2 -0
  115. package/Samples~/LaneRunner/Scripts/Gameplay.meta +8 -0
  116. package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerReplayAdapter.cs +62 -0
  117. package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerReplayAdapter.cs.meta +2 -0
  118. package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerTournamentAdapter.cs +64 -0
  119. package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerTournamentAdapter.cs.meta +2 -0
  120. package/Samples~/LaneRunner/Scripts/Hyper.meta +8 -0
  121. package/Samples~/LaneRunner/Scripts.meta +8 -0
  122. package/Tests.meta +8 -0
  123. package/package.json +9 -3
  124. package/Runtime/Resources/Sprites/Control Bar/Top_Black_Rounded_Bar_Portrait_IV.png +0 -0
@@ -0,0 +1,11 @@
1
+ fileFormatVersion: 2
2
+ guid: 26c94db513ed4191b3f0d4040f8a7d67
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant:
@@ -43,6 +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
47
 
47
48
  private float _lastUnscaledTime;
48
49
  private bool _hasGameEnded;
@@ -64,13 +65,14 @@ namespace Hyper.Internal.Managers
64
65
  _hasBackendSessionDuration = false;
65
66
  _lastUnscaledTime = Time.unscaledTime;
66
67
  _timeUpTriggered = false;
68
+ _replayTimeUpPending = false;
67
69
  }
68
70
 
69
71
  #endregion
70
72
 
71
73
  #region Public API Implementation (ITimerAPI)
72
74
 
73
- public int CurrentTime => _gameManager.Config.GameMode == GameMode.Battle
75
+ public int CurrentTime => _gameManager.IsBattleMode
74
76
  ? (int)_battleTimer
75
77
  : (int)_practiceTimer;
76
78
 
@@ -89,11 +91,27 @@ namespace Hyper.Internal.Managers
89
91
  float unscaledDelta = Time.unscaledTime - _lastUnscaledTime;
90
92
  _lastUnscaledTime = Time.unscaledTime;
91
93
 
92
- float gameTimerDelta = Mathf.Approximately(Time.timeScale, 0f) ? 0f : unscaledDelta;
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
+ }
93
103
 
94
- UpdatePracticeTimer(gameTimerDelta);
95
- UpdateBattleTimer(gameTimerDelta);
96
104
  UpdateSessionTimer(unscaledDelta);
105
+ DispatchPendingReplayTimeUp();
106
+ }
107
+
108
+ internal void FixedTick()
109
+ {
110
+ if (!_gameManager.IsReplayMode || Mathf.Approximately(Time.timeScale, 0f))
111
+ return;
112
+
113
+ UpdatePracticeTimer(Time.fixedDeltaTime);
114
+ UpdateBattleTimer(Time.fixedDeltaTime, true);
97
115
  }
98
116
 
99
117
  public void Reset()
@@ -104,7 +122,7 @@ namespace Hyper.Internal.Managers
104
122
 
105
123
  public void ResumeGameTimersAfterPause()
106
124
  {
107
- if (_gameManager.Config.GameMode == GameMode.Battle)
125
+ if (_gameManager.IsBattleMode)
108
126
  {
109
127
  StartBattle();
110
128
  }
@@ -116,7 +134,7 @@ namespace Hyper.Internal.Managers
116
134
 
117
135
  public void StartActiveGameTimer()
118
136
  {
119
- if (_gameManager.Config.GameMode == GameMode.Battle)
137
+ if (_gameManager.IsBattleMode)
120
138
  {
121
139
  StartSessionTimer();
122
140
  StartBattle();
@@ -132,6 +150,7 @@ namespace Hyper.Internal.Managers
132
150
  public void StopAllTimers()
133
151
  {
134
152
  _hasGameEnded = true;
153
+ _replayTimeUpPending = false;
135
154
  StopBattle();
136
155
  StopPractice();
137
156
  }
@@ -243,11 +262,11 @@ namespace Hyper.Internal.Managers
243
262
  }
244
263
  }
245
264
 
246
- private void UpdateBattleTimer(float delta)
265
+ private void UpdateBattleTimer(float delta, bool deferTimeUp = false)
247
266
  {
248
267
  if (_isBattleRunning)
249
268
  {
250
- if (_gameManager.Config.GameMode == GameMode.Battle &&
269
+ if (_gameManager.IsBattleMode &&
251
270
  _hasGameStarted &&
252
271
  _isPreSessionRunning &&
253
272
  _sessionTimer <= _battleTimer)
@@ -261,8 +280,7 @@ namespace Hyper.Internal.Managers
261
280
  _battleTimer = 0;
262
281
  if (!_timeUpTriggered)
263
282
  {
264
- _timeUpTriggered = true;
265
- _eventManager?.InvokeTimeUpEvent();
283
+ TriggerTimeUp(deferTimeUp);
266
284
  }
267
285
  }
268
286
  }
@@ -274,13 +292,37 @@ namespace Hyper.Internal.Managers
274
292
 
275
293
  if (_battleTimer <= 0 && !_timeUpTriggered)
276
294
  {
277
- _timeUpTriggered = true;
278
- _eventManager?.InvokeTimeUpEvent();
295
+ TriggerTimeUp(deferTimeUp);
279
296
  }
280
297
  }
281
298
  }
282
299
  }
283
300
 
301
+ private void TriggerTimeUp(bool defer)
302
+ {
303
+ if (defer)
304
+ {
305
+ _replayTimeUpPending = true;
306
+ return;
307
+ }
308
+
309
+ _timeUpTriggered = true;
310
+ _eventManager?.InvokeTimeUpEvent();
311
+ }
312
+
313
+ private void DispatchPendingReplayTimeUp()
314
+ {
315
+ if (!_replayTimeUpPending)
316
+ return;
317
+
318
+ _replayTimeUpPending = false;
319
+ if (_hasGameEnded || _timeUpTriggered)
320
+ return;
321
+
322
+ _timeUpTriggered = true;
323
+ _eventManager?.InvokeTimeUpEvent();
324
+ }
325
+
284
326
  private void UpdateSessionTimer(float unscaledDelta)
285
327
  {
286
328
  if (!_isPreSessionRunning) return;
@@ -311,7 +353,7 @@ namespace Hyper.Internal.Managers
311
353
  _isSessionRunning = false;
312
354
  _isPreSessionRunning = false;
313
355
 
314
- if (_hasGameStarted && _gameManager.Config.GameMode == GameMode.Battle)
356
+ if (_hasGameStarted && _gameManager.IsBattleMode)
315
357
  {
316
358
  _battleTimer = 0;
317
359
  if (!_timeUpTriggered)
@@ -341,7 +383,7 @@ namespace Hyper.Internal.Managers
341
383
  }
342
384
  };
343
385
 
344
- if (_gameManager.Config.GameMode == GameMode.Battle)
386
+ if (_gameManager.IsBattleMode)
345
387
  {
346
388
  _eventManager.OnStartDeadlineReached += () =>
347
389
  {
@@ -0,0 +1,182 @@
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace Hyper.Internal.Replay
5
+ {
6
+ internal sealed class ReplayActivityRecorder
7
+ {
8
+ internal const string GameStarted = "GS";
9
+ internal const string GamePaused = "GP";
10
+ internal const string GameResumed = "GR";
11
+ internal const string GameEnded = "GE";
12
+
13
+ private readonly Func<double> _utcNow;
14
+ private readonly Func<double> _simulationNow;
15
+ private List<object[]> _activities;
16
+ private bool _hasStarted;
17
+ private bool _isPaused;
18
+ private bool _hasEnded;
19
+ private double _sessionStartUtc;
20
+ private double _sessionStartSimulation;
21
+ private double _pauseStartedUtc;
22
+ private double _pauseStartedReplayTime;
23
+ private double _recordedPauseDuration;
24
+
25
+ internal event Action<object[]> ActivityRecorded;
26
+
27
+ internal ReplayActivityRecorder(Func<double> utcNow) : this(utcNow, utcNow)
28
+ {
29
+ }
30
+
31
+ internal ReplayActivityRecorder(Func<double> utcNow, Func<double> simulationNow)
32
+ {
33
+ _utcNow = utcNow ?? throw new ArgumentNullException(nameof(utcNow));
34
+ _simulationNow = simulationNow ?? throw new ArgumentNullException(nameof(simulationNow));
35
+ }
36
+
37
+ internal void StartSession()
38
+ {
39
+ if (_hasStarted && !_hasEnded) return;
40
+
41
+ _activities?.Clear();
42
+ _hasStarted = true;
43
+ _isPaused = false;
44
+ _hasEnded = false;
45
+ _recordedPauseDuration = 0d;
46
+ _sessionStartUtc = _utcNow();
47
+ _sessionStartSimulation = _simulationNow();
48
+ AddAction(GameStarted, _sessionStartUtc);
49
+ }
50
+
51
+ internal void PauseSession()
52
+ {
53
+ if (!_hasStarted || _hasEnded || _isPaused) return;
54
+
55
+ _pauseStartedReplayTime = GetReplayTime();
56
+ _pauseStartedUtc = _utcNow();
57
+ _isPaused = true;
58
+ AddAction(GamePaused, _pauseStartedReplayTime);
59
+ }
60
+
61
+ internal void ResumeSession()
62
+ {
63
+ if (!_hasStarted || _hasEnded || !_isPaused) return;
64
+
65
+ double pauseDuration = Math.Max(0d, _utcNow() - _pauseStartedUtc);
66
+ _recordedPauseDuration += pauseDuration;
67
+ _isPaused = false;
68
+ AddAction(GameResumed, _pauseStartedReplayTime + pauseDuration);
69
+ }
70
+
71
+ internal void EndSession()
72
+ {
73
+ if (!_hasStarted || _hasEnded) return;
74
+
75
+ _hasEnded = true;
76
+ AddAction(GameEnded);
77
+ }
78
+
79
+ internal void RecordValues(float first, float second)
80
+ {
81
+ if (!CanRecordGameplay()) return;
82
+ AddActivity(new object[] { GetReplayTime(), first, second });
83
+ }
84
+
85
+ internal void RecordValue(float value)
86
+ {
87
+ if (!CanRecordGameplay()) return;
88
+ AddActivity(new object[] { GetReplayTime(), value });
89
+ }
90
+
91
+ internal void RecordValues(float first, float second, float third)
92
+ {
93
+ if (!CanRecordGameplay()) return;
94
+ AddActivity(new object[] { GetReplayTime(), first, second, third });
95
+ }
96
+
97
+ internal void RecordAction(string actionName)
98
+ {
99
+ if (!CanRecordGameplay() || string.IsNullOrWhiteSpace(actionName) || IsLifecycleAction(actionName)) return;
100
+ AddAction(actionName);
101
+ }
102
+
103
+ internal void RecordActions(string firstAction, string secondAction)
104
+ {
105
+ if (!CanRecordGameplay() || !IsValidAction(firstAction) || !IsValidAction(secondAction)) return;
106
+ AddActivity(new object[] { GetReplayTime(), firstAction, secondAction });
107
+ }
108
+
109
+ internal void RecordActionValues(string actionName, float first, float second)
110
+ {
111
+ if (!CanRecordGameplay() || !IsValidAction(actionName)) return;
112
+ AddActivity(new object[] { GetReplayTime(), actionName, first, second });
113
+ }
114
+
115
+ internal void RecordActionValue(string actionName, float value)
116
+ {
117
+ if (!CanRecordGameplay() || !IsValidAction(actionName)) return;
118
+ AddActivity(new object[] { GetReplayTime(), actionName, value });
119
+ }
120
+
121
+ internal void RecordValuesAction(float first, float second, string actionName)
122
+ {
123
+ if (!CanRecordGameplay() || !IsValidAction(actionName)) return;
124
+ AddActivity(new object[] { GetReplayTime(), first, second, actionName });
125
+ }
126
+
127
+ internal void RecordValueAction(float value, string actionName)
128
+ {
129
+ if (!CanRecordGameplay() || !IsValidAction(actionName)) return;
130
+ AddActivity(new object[] { GetReplayTime(), value, actionName });
131
+ }
132
+
133
+ internal List<object[]> Drain()
134
+ {
135
+ if (_activities == null || _activities.Count == 0) return null;
136
+
137
+ var drained = _activities;
138
+ _activities = null;
139
+ return drained;
140
+ }
141
+
142
+ private List<object[]> Activities => _activities ??= new List<object[]>(32);
143
+
144
+ private bool CanRecordGameplay()
145
+ {
146
+ return _hasStarted && !_isPaused && !_hasEnded;
147
+ }
148
+
149
+ private void AddAction(string actionName)
150
+ {
151
+ AddAction(actionName, GetReplayTime());
152
+ }
153
+
154
+ private void AddAction(string actionName, double replayTime)
155
+ {
156
+ AddActivity(new object[] { replayTime, actionName });
157
+ }
158
+
159
+ private void AddActivity(object[] activity)
160
+ {
161
+ Activities.Add(activity);
162
+ ActivityRecorded?.Invoke(activity);
163
+ }
164
+
165
+ private double GetReplayTime()
166
+ {
167
+ double simulationElapsed = Math.Max(0d, _simulationNow() - _sessionStartSimulation);
168
+ return _sessionStartUtc + simulationElapsed + _recordedPauseDuration;
169
+ }
170
+
171
+ private static bool IsValidAction(string actionName)
172
+ {
173
+ return !string.IsNullOrWhiteSpace(actionName) && !IsLifecycleAction(actionName);
174
+ }
175
+
176
+ internal static bool IsLifecycleAction(string actionName)
177
+ {
178
+ return actionName == GameStarted || actionName == GamePaused ||
179
+ actionName == GameResumed || actionName == GameEnded;
180
+ }
181
+ }
182
+ }
@@ -0,0 +1,2 @@
1
+ fileFormatVersion: 2
2
+ guid: b9b36e61a5cd881439809d4248abfb9c
@@ -0,0 +1,181 @@
1
+ using System;
2
+ using System.IO;
3
+ using UnityEngine;
4
+
5
+ namespace Hyper.Internal
6
+ {
7
+ /// <summary>
8
+ /// Holds replay metadata and presentation state across scene reloads and seeks.
9
+ /// </summary>
10
+ internal static class ReplaySessionState
11
+ {
12
+ public static bool IsActive { get; private set; }
13
+ public static string PlayerName { get; private set; }
14
+ public static string AvatarUrl { get; private set; }
15
+ public static string EntryId { get; private set; }
16
+ public static string ReplayNdjson { get; private set; }
17
+ public static Texture2D AvatarTexture { get; private set; }
18
+ public static bool HasReplayData => !string.IsNullOrWhiteSpace(ReplayNdjson);
19
+ public static long OriginalRandomSeed { get; private set; }
20
+ public static float Progress01 { get; private set; }
21
+ public static float PlaybackSpeed { get; private set; } = 1f;
22
+ public static float UserPlaybackSpeed { get; private set; } = 1f;
23
+ public static bool IsSeeking { get; private set; }
24
+ public static bool IsSeekRestartPending => IsSeeking && !_seekPlaybackReady;
25
+ public static float SeekTarget01 { get; private set; }
26
+ public static bool HasEnded { get; private set; }
27
+
28
+ internal static string EditorReplayFilePath =>
29
+ Path.Combine(Application.persistentDataPath, "hyper-replay.ndjson");
30
+
31
+ public static event Action<float> SeekCompleted;
32
+
33
+ private static bool _seekPlaybackReady;
34
+
35
+ public static void Configure(
36
+ string playerName,
37
+ string avatarUrl,
38
+ long originalRandomSeed,
39
+ string entryId = null)
40
+ {
41
+ IsActive = true;
42
+ PlayerName = playerName ?? string.Empty;
43
+ AvatarUrl = avatarUrl ?? string.Empty;
44
+ EntryId = entryId ?? string.Empty;
45
+ ReplayNdjson = string.Empty;
46
+ ReleaseAvatarTexture();
47
+ OriginalRandomSeed = originalRandomSeed;
48
+ Progress01 = 0f;
49
+ PlaybackSpeed = 1f;
50
+ UserPlaybackSpeed = 1f;
51
+ IsSeeking = false;
52
+ SeekTarget01 = 0f;
53
+ _seekPlaybackReady = false;
54
+ HasEnded = false;
55
+ }
56
+
57
+ public static void SetMetadata(string playerName, string avatarUrl, long originalRandomSeed)
58
+ {
59
+ if (!IsActive) return;
60
+
61
+ PlayerName = playerName ?? string.Empty;
62
+ AvatarUrl = avatarUrl ?? string.Empty;
63
+ OriginalRandomSeed = originalRandomSeed;
64
+ }
65
+
66
+ public static void SetReplayData(string ndjson)
67
+ {
68
+ if (!IsActive) return;
69
+ ReplayNdjson = ndjson ?? string.Empty;
70
+ }
71
+
72
+ public static void SetAvatarTexture(Texture2D texture)
73
+ {
74
+ if (!IsActive || AvatarTexture == texture) return;
75
+ ReleaseAvatarTexture();
76
+ AvatarTexture = texture;
77
+ }
78
+
79
+ public static void SetProgress(float progress)
80
+ {
81
+ if (!IsActive) return;
82
+ if (IsSeeking && !_seekPlaybackReady) return;
83
+ Progress01 = Math.Max(0f, Math.Min(1f, progress));
84
+
85
+ if (IsSeeking && Progress01 >= SeekTarget01)
86
+ {
87
+ IsSeeking = false;
88
+ _seekPlaybackReady = false;
89
+ PlaybackSpeed = UserPlaybackSpeed;
90
+ SeekCompleted?.Invoke(PlaybackSpeed);
91
+ }
92
+ }
93
+
94
+ public static void SetPlaybackSpeed(float speed)
95
+ {
96
+ if (!IsActive) return;
97
+ PlaybackSpeed = SanitizeSpeed(speed);
98
+ if (!IsSeeking) UserPlaybackSpeed = PlaybackSpeed;
99
+ }
100
+
101
+ public static void MarkEnded()
102
+ {
103
+ if (!IsActive) return;
104
+ if (IsSeeking && !_seekPlaybackReady) return;
105
+ Progress01 = 1f;
106
+ if (IsSeeking) PlaybackSpeed = UserPlaybackSpeed;
107
+ IsSeeking = false;
108
+ HasEnded = true;
109
+ }
110
+
111
+ public static void RequestSeek(float targetProgress, float resumeSpeed, float seekSpeed)
112
+ {
113
+ if (!IsActive || HasEnded) return;
114
+
115
+ SeekTarget01 = Math.Max(0f, Math.Min(1f, targetProgress));
116
+ UserPlaybackSpeed = SanitizeSpeed(resumeSpeed);
117
+ PlaybackSpeed = SanitizeSpeed(seekSpeed);
118
+ IsSeeking = true;
119
+ _seekPlaybackReady = false;
120
+ }
121
+
122
+ public static void ResetForSeekRestart()
123
+ {
124
+ if (!IsActive || !IsSeeking) return;
125
+ Progress01 = 0f;
126
+ _seekPlaybackReady = false;
127
+ HasEnded = false;
128
+ }
129
+
130
+ public static void NotifySeekPlaybackStarted()
131
+ {
132
+ if (!IsActive || !IsSeeking) return;
133
+ _seekPlaybackReady = true;
134
+ }
135
+
136
+ public static void ResetForWatchAgain()
137
+ {
138
+ if (!IsActive) return;
139
+ Progress01 = 0f;
140
+ PlaybackSpeed = 1f;
141
+ UserPlaybackSpeed = 1f;
142
+ IsSeeking = false;
143
+ SeekTarget01 = 0f;
144
+ _seekPlaybackReady = false;
145
+ HasEnded = false;
146
+ }
147
+
148
+ public static void Clear()
149
+ {
150
+ IsActive = false;
151
+ PlayerName = string.Empty;
152
+ AvatarUrl = string.Empty;
153
+ EntryId = string.Empty;
154
+ ReplayNdjson = string.Empty;
155
+ ReleaseAvatarTexture();
156
+ OriginalRandomSeed = 0;
157
+ Progress01 = 0f;
158
+ PlaybackSpeed = 1f;
159
+ UserPlaybackSpeed = 1f;
160
+ IsSeeking = false;
161
+ SeekTarget01 = 0f;
162
+ _seekPlaybackReady = false;
163
+ HasEnded = false;
164
+ SeekCompleted = null;
165
+ }
166
+
167
+ private static float SanitizeSpeed(float speed)
168
+ {
169
+ return float.IsNaN(speed) || float.IsInfinity(speed) || speed <= 0f ? 1f : speed;
170
+ }
171
+
172
+ private static void ReleaseAvatarTexture()
173
+ {
174
+ if (AvatarTexture != null)
175
+ {
176
+ UnityEngine.Object.Destroy(AvatarTexture);
177
+ AvatarTexture = null;
178
+ }
179
+ }
180
+ }
181
+ }
@@ -0,0 +1,2 @@
1
+ fileFormatVersion: 2
2
+ guid: e2073f1e0560836419268d91a01396eb
@@ -0,0 +1,8 @@
1
+ fileFormatVersion: 2
2
+ guid: e33926a8ee756c34e92345e72c0c8e17
3
+ folderAsset: yes
4
+ DefaultImporter:
5
+ externalObjects: {}
6
+ userData:
7
+ assetBundleName:
8
+ assetBundleVariant:
@@ -93,6 +93,11 @@ namespace Hyper.Internal
93
93
  _settings.SetModeAsPractice();
94
94
  }
95
95
 
96
+ public void SetModeAsReplay()
97
+ {
98
+ _settings.SetModeAsReplay();
99
+ }
100
+
96
101
  #endregion
97
102
  }
98
103
  }
@@ -16,13 +16,27 @@ namespace Hyper.Internal
16
16
  {
17
17
  StartCoroutine(AnimateLoadingText());
18
18
  }
19
+
20
+ internal void SetBaseText(string value)
21
+ {
22
+ if (string.IsNullOrWhiteSpace(value)) return;
23
+
24
+ loadingBaseText = value;
25
+ if (loadingText != null)
26
+ {
27
+ loadingText.text = loadingBaseText;
28
+ }
29
+ }
19
30
 
20
31
  private IEnumerator AnimateLoadingText()
21
32
  {
22
33
  int i = 0;
23
34
  while (true)
24
35
  {
25
- loadingText.text = loadingBaseText + loadingStates[i];
36
+ if (loadingText != null)
37
+ {
38
+ loadingText.text = loadingBaseText + loadingStates[i];
39
+ }
26
40
  i = (i + 1) % loadingStates.Length;
27
41
  yield return new WaitForSecondsRealtime(dotInterval);
28
42
  }