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.
- package/CHANGELOG.md +37 -0
- package/Editor/Scripts/Setup/HyperSDKInstaller.cs +42 -0
- package/Editor/Scripts/Tools/HyperGameModeMenu.cs +27 -7
- package/Runtime/Internal/AssemblyInfo.cs +1 -0
- package/Runtime/Internal/Bootstrap/HyperLoader.cs +186 -8
- package/Runtime/Internal/Core/HyperRuntime.cs +58 -0
- package/Runtime/Internal/Core/HyperRuntimeHost.cs +6 -0
- package/Runtime/Internal/Data/URLData.cs +18 -1
- package/Runtime/Internal/Managers/BackendManager.cs +281 -24
- package/Runtime/Internal/Managers/DataManager.cs +207 -21
- package/Runtime/Internal/Managers/GameManager.cs +350 -15
- package/Runtime/Internal/Managers/ReplayManager.cs +111 -0
- package/Runtime/Internal/Managers/ReplayManager.cs.meta +11 -0
- package/Runtime/Internal/Managers/TimeManager.cs +56 -14
- package/Runtime/Internal/Replay/ReplayActivityRecorder.cs +182 -0
- package/Runtime/Internal/Replay/ReplayActivityRecorder.cs.meta +2 -0
- package/Runtime/Internal/Replay/ReplaySessionState.cs +181 -0
- package/Runtime/Internal/Replay/ReplaySessionState.cs.meta +2 -0
- package/Runtime/Internal/Replay.meta +8 -0
- package/Runtime/Internal/ScriptableObjects/HyperSDKSettings.cs +5 -0
- package/Runtime/Internal/UI/Animation/LoadingTextAnimation.cs +15 -1
- package/Runtime/Internal/UI/Components/ConcaveImage.cs +147 -0
- package/Runtime/Internal/UI/Components/ConcaveImage.cs.meta +11 -0
- package/Runtime/Internal/UI/Components/ControlBar.cs +86 -6
- package/Runtime/Internal/UI/Components/PauseButton.cs +4 -1
- package/Runtime/Internal/UI/Components/ReplayController.cs +501 -0
- package/Runtime/Internal/UI/Components/ReplayController.cs.meta +2 -0
- package/Runtime/Internal/UI/Components/ReplayMarkerPulse.cs +89 -0
- package/Runtime/Internal/UI/Components/ReplayMarkerPulse.cs.meta +2 -0
- package/Runtime/Internal/UI/Components/ReplayPresentationCanvas.cs +183 -0
- package/Runtime/Internal/UI/Components/ReplayPresentationCanvas.cs.meta +2 -0
- package/Runtime/Internal/UI/Components/SnackBar.cs +2 -9
- package/Runtime/Internal/UI/Modals/LoadingFailedModal.cs +12 -0
- package/Runtime/Internal/UI/Modals/ReplayOverModal.cs +54 -0
- package/Runtime/Internal/UI/Modals/ReplayOverModal.cs.meta +2 -0
- package/Runtime/Internal/UI/Modals/StartingInstructionModal.cs +38 -29
- package/Runtime/Public/AssemblyInfo.cs +3 -0
- package/Runtime/Public/AssemblyInfo.cs.meta +2 -0
- package/Runtime/Public/Core/HyperSDK.cs +305 -109
- package/Runtime/Public/Hyper.asmdef +2 -1
- package/Runtime/Public/Replay/ReplayPlaybackEngine.cs +555 -0
- package/Runtime/Public/Replay/ReplayPlaybackEngine.cs.meta +2 -0
- package/Runtime/Public/Replay.meta +8 -0
- package/Runtime/Resources/Fonts/Nunito/Nunito-Light SDF.asset +528 -521
- package/Runtime/Resources/Materials/HyperReplayScanlines.preset +340 -0
- package/Runtime/Resources/Materials/HyperReplayScanlines.preset.meta +8 -0
- package/Runtime/Resources/Materials/ReplayScanlineOverlay.mat +55 -0
- package/Runtime/Resources/Materials/ReplayScanlineOverlay.mat.meta +8 -0
- package/Runtime/Resources/Shaders/ConcaveImage.shader +155 -0
- package/Runtime/Resources/Shaders/ConcaveImage.shader.meta +10 -0
- package/Runtime/Resources/Shaders/ReplayScanlineOverlay.shader +150 -0
- package/Runtime/Resources/Shaders/ReplayScanlineOverlay.shader.meta +10 -0
- package/Runtime/Resources/Sprites/Replays/Fallback avatar.png +0 -0
- package/Runtime/Resources/Sprites/Replays/Fallback avatar.png.meta +156 -0
- package/Runtime/Resources/Sprites/Replays/Recording.png +0 -0
- package/Runtime/Resources/Sprites/{Control Bar/Top_Black_Rounded_Bar_Portrait_IV.png.meta → Replays/Recording.png.meta} +16 -29
- package/Runtime/Resources/Sprites/Replays/Replay frame.png +0 -0
- package/Runtime/Resources/Sprites/Replays/Replay frame.png.meta +156 -0
- package/Runtime/Resources/Sprites/Replays/Replay modal icon.png +0 -0
- package/Runtime/Resources/Sprites/Replays/Replay modal icon.png.meta +156 -0
- package/Runtime/Resources/Sprites/Replays.meta +8 -0
- package/Runtime/Resources/UIPrefabs/ControlBar.prefab +389 -42
- package/Runtime/Resources/UIPrefabs/GamePausedModal_Battle.prefab +1 -1
- package/Runtime/Resources/UIPrefabs/ReplayController.prefab +1269 -0
- package/Runtime/Resources/UIPrefabs/ReplayController.prefab.meta +7 -0
- package/Runtime/Resources/UIPrefabs/ReplayInputBlocker.prefab +90 -0
- package/Runtime/Resources/UIPrefabs/ReplayInputBlocker.prefab.meta +7 -0
- package/Runtime/Resources/UIPrefabs/ReplayOverModal.prefab +958 -0
- package/Runtime/Resources/UIPrefabs/ReplayOverModal.prefab.meta +7 -0
- package/Runtime/Resources/UIPrefabs/ReplaySeekOverlay.prefab +189 -0
- package/Runtime/Resources/UIPrefabs/ReplaySeekOverlay.prefab.meta +7 -0
- package/Runtime/Resources/UIPrefabs/Rounded Cutout.prefab +96 -0
- package/Runtime/Resources/UIPrefabs/Rounded Cutout.prefab.meta +7 -0
- package/Runtime/Resources/UIPrefabs/SnackBar.prefab +23 -6
- package/Runtime/Shared/AssemblyInfo.cs +5 -0
- package/Runtime/Shared/AssemblyInfo.cs.meta +11 -0
- package/Runtime/Shared/DTOs/Enums.cs +8 -3
- package/Runtime/Shared/DTOs/Score/ScoreSnapshot.cs +13 -1
- package/Runtime/Shared/Replay/IReplayPlaybackEngine.cs +37 -0
- package/Runtime/Shared/Replay/IReplayPlaybackEngine.cs.meta +11 -0
- package/Runtime/Shared/Replay.meta +8 -0
- package/Runtime/Shared/Utils/HyperRandom.cs +25 -5
- package/Samples~/LaneRunner/LaneRunnerSample.unity +1603 -0
- package/Samples~/LaneRunner/LaneRunnerSample.unity.meta +7 -0
- package/Samples~/LaneRunner/Materials/DoubleScore.mat +86 -0
- package/Samples~/LaneRunner/Materials/DoubleScore.mat.meta +8 -0
- package/Samples~/LaneRunner/Materials/Ground.mat +84 -0
- package/Samples~/LaneRunner/Materials/Ground.mat.meta +8 -0
- package/Samples~/LaneRunner/Materials/Lane.mat +84 -0
- package/Samples~/LaneRunner/Materials/Lane.mat.meta +8 -0
- package/Samples~/LaneRunner/Materials/LaneMarker.mat +84 -0
- package/Samples~/LaneRunner/Materials/LaneMarker.mat.meta +8 -0
- package/Samples~/LaneRunner/Materials/Obstacle.mat +84 -0
- package/Samples~/LaneRunner/Materials/Obstacle.mat.meta +8 -0
- package/Samples~/LaneRunner/Materials/Player.mat +84 -0
- package/Samples~/LaneRunner/Materials/Player.mat.meta +8 -0
- package/Samples~/LaneRunner/Materials.meta +8 -0
- package/Samples~/LaneRunner/Prefabs/DoubleScorePickup.prefab +152 -0
- package/Samples~/LaneRunner/Prefabs/DoubleScorePickup.prefab.meta +7 -0
- package/Samples~/LaneRunner/Prefabs/Obstacle.prefab +152 -0
- package/Samples~/LaneRunner/Prefabs/Obstacle.prefab.meta +7 -0
- package/Samples~/LaneRunner/Prefabs.meta +8 -0
- package/Samples~/LaneRunner/README.md +35 -0
- package/Samples~/LaneRunner/README.md.meta +7 -0
- package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerCommand.cs +9 -0
- package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerCommand.cs.meta +2 -0
- package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerGame.cs +93 -0
- package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerGame.cs.meta +2 -0
- package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerPlayer.cs +155 -0
- package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerPlayer.cs.meta +2 -0
- package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerSpawner.cs +110 -0
- package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerSpawner.cs.meta +2 -0
- package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerTrackItem.cs +41 -0
- package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerTrackItem.cs.meta +2 -0
- package/Samples~/LaneRunner/Scripts/Gameplay.meta +8 -0
- package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerReplayAdapter.cs +62 -0
- package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerReplayAdapter.cs.meta +2 -0
- package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerTournamentAdapter.cs +64 -0
- package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerTournamentAdapter.cs.meta +2 -0
- package/Samples~/LaneRunner/Scripts/Hyper.meta +8 -0
- package/Samples~/LaneRunner/Scripts.meta +8 -0
- package/Tests.meta +8 -0
- package/package.json +9 -3
- package/Runtime/Resources/Sprites/Control Bar/Top_Black_Rounded_Bar_Portrait_IV.png +0 -0
|
@@ -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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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,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
|
+
}
|
|
@@ -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
|
|
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
|
}
|