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.
- package/CHANGELOG.md +34 -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 +82 -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 +365 -17
- package/Runtime/Internal/Managers/ReplayManager.cs +117 -0
- package/Runtime/Internal/Managers/ReplayManager.cs.meta +11 -0
- package/Runtime/Internal/Managers/TimeManager.cs +54 -12
- 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/ControlBar.cs +25 -2
- package/Runtime/Internal/UI/Components/PauseButton.cs +4 -1
- package/Runtime/Internal/UI/Components/ReplayController.cs +527 -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/Modals/LoadingFailedModal.cs +12 -0
- package/Runtime/Internal/UI/Modals/ReplayOverModal.cs +61 -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/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/Replays/Recording.png.meta +156 -0
- 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 +169 -2
- 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/SnackBar.prefab +2 -2
- 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/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 +8 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,37 @@
|
|
|
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
|
+
|
|
10
|
+
# [1.11.0-beta.1](https://github.com/mvmhyper/hyper-sdk/compare/v1.10.0...v1.11.0-beta.1) (2026-08-26)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **replay:** add player handle font glyph ([5ba9f0d](https://github.com/mvmhyper/hyper-sdk/commit/5ba9f0d0c3e207b4ff0a4b4f16ffe53bd215ea14))
|
|
16
|
+
* **replay:** handle backend loading failures ([1d299cf](https://github.com/mvmhyper/hyper-sdk/commit/1d299cf7d1002d5632cd0b1da2c928405b50e56a))
|
|
17
|
+
* **replay:** harden web replay playback ([96f0521](https://github.com/mvmhyper/hyper-sdk/commit/96f05215f6a483306622b632366de20b58ede6e9))
|
|
18
|
+
* **replay:** preserve recorded action timing ([48ff268](https://github.com/mvmhyper/hyper-sdk/commit/48ff268c16b0ddd5fd4e81e0903d4b54b05d4a1c))
|
|
19
|
+
* **replay:** refine replay ui behavior ([8a9364f](https://github.com/mvmhyper/hyper-sdk/commit/8a9364fb19f6ccd6df31a396bf7fef30c5f66040))
|
|
20
|
+
* **score:** preserve latest final snapshot time ([b9242cd](https://github.com/mvmhyper/hyper-sdk/commit/b9242cd5478702621fbc30a1bd21a972bbf9fb4c))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
* **replay:** add math rush replay integration ([394e8b0](https://github.com/mvmhyper/hyper-sdk/commit/394e8b0591c99899b5f2433bbadf159aa4631d47))
|
|
26
|
+
* **replay:** add replay activity recording ([8b87b42](https://github.com/mvmhyper/hyper-sdk/commit/8b87b425440ebfa4d08fcc9d62586afde58fda33))
|
|
27
|
+
* **replay:** add replay playback scheduling ([40c9c83](https://github.com/mvmhyper/hyper-sdk/commit/40c9c83a886b06434ee886fa85f490ca74710ac6))
|
|
28
|
+
* **replay:** add replay ui flows ([e287986](https://github.com/mvmhyper/hyper-sdk/commit/e287986222763c814a299cfcb81d1cd14bcf49e9))
|
|
29
|
+
* **replay:** add replay visual assets ([4c61645](https://github.com/mvmhyper/hyper-sdk/commit/4c616458155e04444feac9fb187b63f646035f7a))
|
|
30
|
+
* **replay:** add stable replay launch mode ([fbfd8fc](https://github.com/mvmhyper/hyper-sdk/commit/fbfd8fcdc5a7119f7c3655f1a033705ccd47608f))
|
|
31
|
+
* **replay:** align playback with fixed simulation ([8e4051d](https://github.com/mvmhyper/hyper-sdk/commit/8e4051d5d41fe3dbc4d050ee4f961ae6d690d1bd))
|
|
32
|
+
* **replay:** finalize playback simulation and seeking ([de3b6e7](https://github.com/mvmhyper/hyper-sdk/commit/de3b6e79be4ecde5abc4bb20190e80f12fbe3598))
|
|
33
|
+
* **replay:** load replay data from backend ([f89c067](https://github.com/mvmhyper/hyper-sdk/commit/f89c067b6e55074c08f75e34c0d378af969b60c5))
|
|
34
|
+
|
|
1
35
|
# [1.10.0](https://github.com/mvmhyper/hyper-sdk/compare/v1.9.1...v1.10.0) (2026-08-10)
|
|
2
36
|
|
|
3
37
|
|
|
@@ -20,9 +20,51 @@ namespace Hyper.Editor
|
|
|
20
20
|
private const string HyperSDKSettingsRelativePath = "Runtime/Resources/HyperSDKSettings.asset";
|
|
21
21
|
private const string HyperGameContentConfigDestination = "Assets/HyperSDK/Runtime/Resources/HyperGameContentConfig.asset";
|
|
22
22
|
private const string HyperSDKSettingsDestination = "Assets/HyperSDK/Runtime/Resources/HyperSDKSettings.asset";
|
|
23
|
+
private const string LaneRunnerSampleRelativePath = "Samples~/LaneRunner";
|
|
24
|
+
private const string LaneRunnerSampleDestination = "Assets/Samples/HyperSDK/Lane Runner";
|
|
23
25
|
|
|
24
26
|
private static bool _hasChecked = false;
|
|
25
27
|
|
|
28
|
+
[MenuItem("Hyper/Samples/Import Lane Runner", priority = 100)]
|
|
29
|
+
private static void ImportLaneRunnerSample()
|
|
30
|
+
{
|
|
31
|
+
var packageInfo = UnityEditor.PackageManager.PackageInfo.FindForAssembly(typeof(HyperSDKInstaller).Assembly);
|
|
32
|
+
if (packageInfo == null || string.IsNullOrEmpty(packageInfo.resolvedPath) ||
|
|
33
|
+
packageInfo.resolvedPath.Replace('\\', '/').Contains("/Assets/"))
|
|
34
|
+
{
|
|
35
|
+
var developmentSample = AssetDatabase.LoadAssetAtPath<SceneAsset>(
|
|
36
|
+
"Assets/SampleGame (Lane Runner)/LaneRunnerSample.unity");
|
|
37
|
+
Selection.activeObject = developmentSample;
|
|
38
|
+
EditorGUIUtility.PingObject(developmentSample);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
string sourcePath = Path.Combine(packageInfo.resolvedPath, LaneRunnerSampleRelativePath);
|
|
43
|
+
|
|
44
|
+
if (!Directory.Exists(sourcePath))
|
|
45
|
+
{
|
|
46
|
+
EditorUtility.DisplayDialog("Lane Runner Sample",
|
|
47
|
+
"The Lane Runner sample was not found in this HyperSDK installation.", "OK");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (Directory.Exists(LaneRunnerSampleDestination))
|
|
52
|
+
{
|
|
53
|
+
EditorUtility.DisplayDialog("Lane Runner Sample",
|
|
54
|
+
"Lane Runner is already imported at Assets/Samples/HyperSDK/Lane Runner.", "OK");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
Directory.CreateDirectory(Path.GetDirectoryName(LaneRunnerSampleDestination));
|
|
59
|
+
FileUtil.CopyFileOrDirectory(sourcePath, LaneRunnerSampleDestination);
|
|
60
|
+
AssetDatabase.Refresh();
|
|
61
|
+
|
|
62
|
+
var scene = AssetDatabase.LoadAssetAtPath<SceneAsset>(
|
|
63
|
+
LaneRunnerSampleDestination + "/LaneRunnerSample.unity");
|
|
64
|
+
Selection.activeObject = scene;
|
|
65
|
+
EditorGUIUtility.PingObject(scene);
|
|
66
|
+
}
|
|
67
|
+
|
|
26
68
|
static HyperSDKInstaller()
|
|
27
69
|
{
|
|
28
70
|
// Only register delayCall once per domain reload
|
|
@@ -8,11 +8,12 @@ namespace Hyper.Editor
|
|
|
8
8
|
{
|
|
9
9
|
static class HyperGameModeMenu
|
|
10
10
|
{
|
|
11
|
-
private enum DevMode { Practice = 0, Battle = 1 }
|
|
11
|
+
private enum DevMode { Practice = 0, Battle = 1, Replay = 2 }
|
|
12
12
|
private const string PrefKey = "Hyper.DevMode";
|
|
13
13
|
|
|
14
14
|
private const string BattlePath = "Hyper/Battle Game Mode";
|
|
15
15
|
private const string PracticePath = "Hyper/Practice Game Mode";
|
|
16
|
+
private const string ReplayPath = "Hyper/Replay Game Mode";
|
|
16
17
|
|
|
17
18
|
private static HyperSDKSettings _settings;
|
|
18
19
|
|
|
@@ -26,10 +27,14 @@ namespace Hyper.Editor
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
private static DevMode FromSettings(GameMode gm)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
{
|
|
31
|
+
switch (gm)
|
|
32
|
+
{
|
|
33
|
+
case GameMode.Battle: return DevMode.Battle;
|
|
34
|
+
case GameMode.Replay: return DevMode.Replay;
|
|
35
|
+
default: return DevMode.Practice;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
33
38
|
|
|
34
39
|
private static DevMode Current
|
|
35
40
|
{
|
|
@@ -44,8 +49,12 @@ namespace Hyper.Editor
|
|
|
44
49
|
{
|
|
45
50
|
if (TryLoadSettings(out var s))
|
|
46
51
|
{
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
switch (value)
|
|
53
|
+
{
|
|
54
|
+
case DevMode.Battle: s.SetModeAsBattle(); break;
|
|
55
|
+
case DevMode.Replay: s.SetModeAsReplay(); break;
|
|
56
|
+
default: s.SetModeAsPractice(); break;
|
|
57
|
+
}
|
|
49
58
|
|
|
50
59
|
EditorUtility.SetDirty(s);
|
|
51
60
|
AssetDatabase.SaveAssets();
|
|
@@ -84,6 +93,16 @@ namespace Hyper.Editor
|
|
|
84
93
|
return !EditorApplication.isPlaying;
|
|
85
94
|
}
|
|
86
95
|
|
|
96
|
+
[MenuItem(ReplayPath, priority = 300)]
|
|
97
|
+
private static void SetReplay() => SetMode(DevMode.Replay);
|
|
98
|
+
|
|
99
|
+
[MenuItem(ReplayPath, validate = true)]
|
|
100
|
+
private static bool ValidateReplay()
|
|
101
|
+
{
|
|
102
|
+
Menu.SetChecked(ReplayPath, Current == DevMode.Replay);
|
|
103
|
+
return !EditorApplication.isPlaying;
|
|
104
|
+
}
|
|
105
|
+
|
|
87
106
|
#endregion
|
|
88
107
|
|
|
89
108
|
private static void SetMode(DevMode mode)
|
|
@@ -94,6 +113,7 @@ namespace Hyper.Editor
|
|
|
94
113
|
|
|
95
114
|
Menu.SetChecked(BattlePath, mode == DevMode.Battle);
|
|
96
115
|
Menu.SetChecked(PracticePath, mode == DevMode.Practice);
|
|
116
|
+
Menu.SetChecked(ReplayPath, mode == DevMode.Replay);
|
|
97
117
|
|
|
98
118
|
HyperDebug.LogSuccess($"Game Mode set to: {mode}");
|
|
99
119
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
using Hyper.Internal.Managers;
|
|
2
2
|
using System;
|
|
3
3
|
using System.Collections;
|
|
4
|
+
#if UNITY_EDITOR
|
|
5
|
+
using System.IO;
|
|
6
|
+
#endif
|
|
4
7
|
using TMPro;
|
|
5
8
|
using UnityEngine;
|
|
6
9
|
using UnityEngine.SceneManagement;
|
|
@@ -60,6 +63,11 @@ namespace Hyper.Internal
|
|
|
60
63
|
InitializeComponents();
|
|
61
64
|
LoadConfiguration();
|
|
62
65
|
SetupSplashScreen();
|
|
66
|
+
|
|
67
|
+
if (ReplaySessionState.IsSeeking)
|
|
68
|
+
{
|
|
69
|
+
SetLoaderCanvasVisible(false);
|
|
70
|
+
}
|
|
63
71
|
}
|
|
64
72
|
|
|
65
73
|
private void Start()
|
|
@@ -74,6 +82,15 @@ namespace Hyper.Internal
|
|
|
74
82
|
|
|
75
83
|
#endregion
|
|
76
84
|
|
|
85
|
+
private void SetLoaderCanvasVisible(bool isVisible)
|
|
86
|
+
{
|
|
87
|
+
Canvas[] canvases = GetComponentsInChildren<Canvas>(true);
|
|
88
|
+
for (int i = 0; i < canvases.Length; i++)
|
|
89
|
+
{
|
|
90
|
+
canvases[i].enabled = isVisible;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
77
94
|
#region Initialization
|
|
78
95
|
|
|
79
96
|
private void InitializeComponents()
|
|
@@ -115,7 +132,7 @@ namespace Hyper.Internal
|
|
|
115
132
|
private static T LoadResourceFromAssets<T>(string resourceName) where T : UnityEngine.Object
|
|
116
133
|
{
|
|
117
134
|
T[] allResources = Resources.LoadAll<T>(string.Empty);
|
|
118
|
-
|
|
135
|
+
|
|
119
136
|
if (allResources == null || allResources.Length == 0)
|
|
120
137
|
{
|
|
121
138
|
return Resources.Load<T>(resourceName);
|
|
@@ -247,9 +264,13 @@ namespace Hyper.Internal
|
|
|
247
264
|
{
|
|
248
265
|
sdkInitialized = true;
|
|
249
266
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
267
|
+
// Bootstrap retries recreate the runtime managers. Always bind the
|
|
268
|
+
// current instances rather than retaining objects queued for destruction.
|
|
269
|
+
_eventManager = HyperRuntime.EventManager;
|
|
270
|
+
_gameManager = HyperRuntime.GameManager;
|
|
271
|
+
_backendManager = HyperRuntime.BackendManager;
|
|
272
|
+
UpdateLoadingTextForMode();
|
|
273
|
+
UpdateHintVisibilityForMode();
|
|
253
274
|
SubscribeToEvents();
|
|
254
275
|
});
|
|
255
276
|
|
|
@@ -264,14 +285,23 @@ namespace Hyper.Internal
|
|
|
264
285
|
_loadingBarSlider.value = _bootstrapProgress;
|
|
265
286
|
|
|
266
287
|
// Start tutorial discovery early, but never wait for it before loading gameplay.
|
|
267
|
-
|
|
288
|
+
if (!_gameManager.IsReplayMode)
|
|
289
|
+
{
|
|
290
|
+
HyperRuntime.BackendManager.GetTutorial(null);
|
|
291
|
+
}
|
|
268
292
|
|
|
269
293
|
// Step 2: Handle Backend/PVP or Practice mode initialization
|
|
270
|
-
if (_gameManager.
|
|
294
|
+
if (_gameManager.IsReplayMode)
|
|
295
|
+
{
|
|
296
|
+
bool replayInitialized = false;
|
|
297
|
+
yield return InitializeReplay(success => replayInitialized = success);
|
|
298
|
+
if (!replayInitialized) yield break;
|
|
299
|
+
}
|
|
300
|
+
else if (_gameManager.Config.IsBackendGame && _gameManager.Config.isPVP)
|
|
271
301
|
{
|
|
272
302
|
yield return InitializeBackendGame();
|
|
273
303
|
}
|
|
274
|
-
else if (_gameManager.
|
|
304
|
+
else if (_gameManager.IsBattleMode)
|
|
275
305
|
{
|
|
276
306
|
InitializeNonBackendBattle();
|
|
277
307
|
}
|
|
@@ -328,6 +358,117 @@ namespace Hyper.Internal
|
|
|
328
358
|
_loadingBarSlider.value = _bootstrapProgress;
|
|
329
359
|
}
|
|
330
360
|
|
|
361
|
+
private IEnumerator InitializeReplay(Action<bool> onComplete)
|
|
362
|
+
{
|
|
363
|
+
_targetSceneName = _gameContentConfig.GameScene?.SceneName;
|
|
364
|
+
|
|
365
|
+
if (!ReplaySessionState.HasReplayData)
|
|
366
|
+
{
|
|
367
|
+
#if UNITY_EDITOR
|
|
368
|
+
if (string.IsNullOrWhiteSpace(_gameManager.Config.EntryId))
|
|
369
|
+
{
|
|
370
|
+
if (TryLoadEditorReplay(out string editorReplayError))
|
|
371
|
+
{
|
|
372
|
+
_backendManager.RegisterSeed(GetRandomSeed());
|
|
373
|
+
onComplete?.Invoke(true);
|
|
374
|
+
yield break;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
HandleReplayLoadingFailure(editorReplayError, onComplete);
|
|
378
|
+
yield break;
|
|
379
|
+
}
|
|
380
|
+
#endif
|
|
381
|
+
bool replayDownloaded = false;
|
|
382
|
+
string replayError = null;
|
|
383
|
+
yield return _backendManager.FetchReplay(
|
|
384
|
+
_gameManager.Config.EntryId,
|
|
385
|
+
() => replayDownloaded = true,
|
|
386
|
+
error => replayError = error);
|
|
387
|
+
|
|
388
|
+
if (!replayDownloaded || !ReplaySessionState.HasReplayData)
|
|
389
|
+
{
|
|
390
|
+
HandleReplayLoadingFailure($"Unable to load replay: {replayError}", onComplete);
|
|
391
|
+
yield break;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (ReplaySessionState.AvatarTexture == null &&
|
|
397
|
+
!string.IsNullOrWhiteSpace(ReplaySessionState.AvatarUrl))
|
|
398
|
+
{
|
|
399
|
+
Texture2D downloadedAvatar = null;
|
|
400
|
+
string avatarError = null;
|
|
401
|
+
|
|
402
|
+
yield return _backendManager.FetchReplayAvatar(
|
|
403
|
+
ReplaySessionState.AvatarUrl,
|
|
404
|
+
texture => downloadedAvatar = texture,
|
|
405
|
+
error => avatarError = error);
|
|
406
|
+
|
|
407
|
+
if (downloadedAvatar != null)
|
|
408
|
+
{
|
|
409
|
+
Texture2D circularAvatar = ReplayController.CreateCircularAvatar(
|
|
410
|
+
downloadedAvatar,
|
|
411
|
+
ReplayController.AvatarTextureSize);
|
|
412
|
+
|
|
413
|
+
Destroy(downloadedAvatar);
|
|
414
|
+
ReplaySessionState.SetAvatarTexture(circularAvatar);
|
|
415
|
+
}
|
|
416
|
+
else
|
|
417
|
+
{
|
|
418
|
+
HyperDebug.LogWarning(
|
|
419
|
+
$"Unable to load replay avatar. Using fallback avatar. Error: {avatarError}");
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
_backendManager.RegisterSeed(GetRandomSeed());
|
|
424
|
+
_bootstrapProgress = _progressAfterBackend;
|
|
425
|
+
_loadingBarSlider.value = _bootstrapProgress;
|
|
426
|
+
onComplete?.Invoke(true);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
#if UNITY_EDITOR
|
|
430
|
+
private bool TryLoadEditorReplay(out string error)
|
|
431
|
+
{
|
|
432
|
+
error = null;
|
|
433
|
+
string path = ReplaySessionState.EditorReplayFilePath;
|
|
434
|
+
if (!File.Exists(path))
|
|
435
|
+
{
|
|
436
|
+
error = $"No Editor replay has been recorded at {path}.";
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
try
|
|
441
|
+
{
|
|
442
|
+
string ndjson = File.ReadAllText(path);
|
|
443
|
+
if (!BackendManager.TryParseReplayResponse(
|
|
444
|
+
ndjson,
|
|
445
|
+
out BackendManager.ReplayResponse replay,
|
|
446
|
+
out error))
|
|
447
|
+
{
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
ReplaySessionState.SetMetadata(replay.PlayerName, replay.AvatarUrl, replay.Seed);
|
|
452
|
+
ReplaySessionState.SetReplayData(replay.ActivityNdjson);
|
|
453
|
+
HyperDebug.Log($"Replay loaded from {path}");
|
|
454
|
+
return true;
|
|
455
|
+
}
|
|
456
|
+
catch (Exception exception)
|
|
457
|
+
{
|
|
458
|
+
error = $"Unable to load Editor replay: {exception.Message}";
|
|
459
|
+
return false;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
#endif
|
|
463
|
+
|
|
464
|
+
private void HandleReplayLoadingFailure(string error, Action<bool> onComplete)
|
|
465
|
+
{
|
|
466
|
+
HyperDebug.LogError(error);
|
|
467
|
+
onComplete?.Invoke(false);
|
|
468
|
+
_gameManager.ShowLoadingFailedModal(true);
|
|
469
|
+
_gameManager.LoadingFailedModalComponent?.AllAttemptsHaveFailed();
|
|
470
|
+
}
|
|
471
|
+
|
|
331
472
|
private void InitializeNonBackendBattle()
|
|
332
473
|
{
|
|
333
474
|
_targetSceneName = _gameContentConfig.GameScene?.SceneName;
|
|
@@ -377,8 +518,21 @@ namespace Hyper.Internal
|
|
|
377
518
|
|
|
378
519
|
private long GetRandomSeed()
|
|
379
520
|
{
|
|
521
|
+
if (_gameManager.IsReplayMode)
|
|
522
|
+
{
|
|
523
|
+
if (ReplaySessionState.OriginalRandomSeed != 0)
|
|
524
|
+
{
|
|
525
|
+
return ReplaySessionState.OriginalRandomSeed;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (HyperRuntime.Settings != null && HyperRuntime.Settings._settings != null)
|
|
529
|
+
{
|
|
530
|
+
return HyperRuntime.Settings._settings.RandomSeed;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
380
534
|
#if UNITY_EDITOR
|
|
381
|
-
// In editor, use the seed from editor simulation settings if available
|
|
535
|
+
// In editor, use the seed from editor simulation settings if available.
|
|
382
536
|
if (HyperRuntime.Settings != null && HyperRuntime.Settings._settings != null)
|
|
383
537
|
{
|
|
384
538
|
return HyperRuntime.Settings._settings.RandomSeed;
|
|
@@ -464,6 +618,30 @@ namespace Hyper.Internal
|
|
|
464
618
|
|
|
465
619
|
#region UI Control
|
|
466
620
|
|
|
621
|
+
private void UpdateLoadingTextForMode()
|
|
622
|
+
{
|
|
623
|
+
if (_gameManager == null) return;
|
|
624
|
+
|
|
625
|
+
SetLoadingText(_gameManager.IsReplayMode ? "LOADING REPLAY" : "LAUNCHING GAME");
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
private void SetLoadingText(string text)
|
|
629
|
+
{
|
|
630
|
+
if (launchingGameAnimation == null) return;
|
|
631
|
+
|
|
632
|
+
LoadingTextAnimation animation =
|
|
633
|
+
launchingGameAnimation.GetComponentInChildren<LoadingTextAnimation>(true);
|
|
634
|
+
animation?.SetBaseText(text);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
private void UpdateHintVisibilityForMode()
|
|
638
|
+
{
|
|
639
|
+
if (hintContainer != null && _gameManager != null && _gameManager.IsReplayMode)
|
|
640
|
+
{
|
|
641
|
+
hintContainer.SetActive(false);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
467
645
|
private void ShowLoadingScreenElements(bool show)
|
|
468
646
|
{
|
|
469
647
|
if (launchingGameAnimation != null)
|
|
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|
|
4
4
|
using UnityEngine;
|
|
5
5
|
using UnityEngine.SceneManagement;
|
|
6
6
|
using Hyper.Internal.Managers;
|
|
7
|
+
using Hyper.Shared;
|
|
7
8
|
|
|
8
9
|
namespace Hyper.Internal
|
|
9
10
|
{
|
|
@@ -30,6 +31,7 @@ namespace Hyper.Internal
|
|
|
30
31
|
private static DataManager _dataManager;
|
|
31
32
|
private static EventManager _eventManager;
|
|
32
33
|
private static TimerManager _timerManager;
|
|
34
|
+
private static ReplayManager _replayManager;
|
|
33
35
|
|
|
34
36
|
internal static bool IsInitialized => _isInitialized;
|
|
35
37
|
internal static bool IsSoftRestarting
|
|
@@ -55,6 +57,7 @@ namespace Hyper.Internal
|
|
|
55
57
|
internal static DataManager DataManager => _dataManager;
|
|
56
58
|
internal static EventManager EventManager => _eventManager;
|
|
57
59
|
internal static TimerManager Timer => _timerManager;
|
|
60
|
+
internal static ReplayManager ReplayManager => _replayManager;
|
|
58
61
|
|
|
59
62
|
internal static event Action CustomLoadingStarted
|
|
60
63
|
{
|
|
@@ -114,6 +117,65 @@ namespace Hyper.Internal
|
|
|
114
117
|
}
|
|
115
118
|
}
|
|
116
119
|
|
|
120
|
+
/// <summary>
|
|
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
|
+
/// </summary>
|
|
124
|
+
internal static void RestartReplaySession()
|
|
125
|
+
{
|
|
126
|
+
ReplaySessionState.ResetForWatchAgain();
|
|
127
|
+
RestartReplay();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
internal static void SeekReplaySession(float targetProgress, float resumeSpeed, float seekSpeed)
|
|
131
|
+
{
|
|
132
|
+
if (!ReplaySessionState.IsActive || ReplaySessionState.HasEnded) return;
|
|
133
|
+
|
|
134
|
+
ReplaySessionState.RequestSeek(targetProgress, resumeSpeed, seekSpeed);
|
|
135
|
+
ReplaySessionState.ResetForSeekRestart();
|
|
136
|
+
RestartReplay();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private static void RestartReplay()
|
|
140
|
+
{
|
|
141
|
+
_isSoftRestarting = true;
|
|
142
|
+
Time.timeScale = 1f;
|
|
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
|
+
|
|
155
|
+
if (_host != null)
|
|
156
|
+
{
|
|
157
|
+
_host.StartCoroutine(RestartSessionCoroutine());
|
|
158
|
+
}
|
|
159
|
+
else
|
|
160
|
+
{
|
|
161
|
+
ClearAllDontDestroyOnLoadObjects();
|
|
162
|
+
SceneManager.LoadScene("HyperLoader");
|
|
163
|
+
}
|
|
164
|
+
}
|
|
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
|
+
|
|
117
179
|
/// <summary>
|
|
118
180
|
/// Coroutine-based restart that properly unloads all scenes before reloading.
|
|
119
181
|
/// Handles async scene operations and ensures clean state before restart.
|
|
@@ -302,6 +364,9 @@ namespace Hyper.Internal
|
|
|
302
364
|
_gameManager = _singletonObject.AddComponent<GameManager>();
|
|
303
365
|
_gameManager.Initialize();
|
|
304
366
|
|
|
367
|
+
_replayManager = new ReplayManager();
|
|
368
|
+
_replayManager.Initialize(_eventManager);
|
|
369
|
+
|
|
305
370
|
_timerManager = new TimerManager();
|
|
306
371
|
_timerManager.Initialize();
|
|
307
372
|
_timerManager.InjectEventHooks();
|
|
@@ -313,6 +378,13 @@ namespace Hyper.Internal
|
|
|
313
378
|
_timerManager?.Update();
|
|
314
379
|
}
|
|
315
380
|
|
|
381
|
+
internal static void FixedTick()
|
|
382
|
+
{
|
|
383
|
+
if (!_isInitialized) return;
|
|
384
|
+
_replayManager?.FixedTick();
|
|
385
|
+
_timerManager?.FixedTick();
|
|
386
|
+
}
|
|
387
|
+
|
|
316
388
|
internal static void Clear()
|
|
317
389
|
{
|
|
318
390
|
if (_host == null)
|
|
@@ -323,6 +395,9 @@ namespace Hyper.Internal
|
|
|
323
395
|
|
|
324
396
|
_timerManager = null;
|
|
325
397
|
|
|
398
|
+
_replayManager?.Cleanup();
|
|
399
|
+
_replayManager = null;
|
|
400
|
+
|
|
326
401
|
_dataManager?.Cleanup();
|
|
327
402
|
_dataManager = null;
|
|
328
403
|
|
|
@@ -364,6 +439,11 @@ namespace Hyper.Internal
|
|
|
364
439
|
{
|
|
365
440
|
if (obj.scene.name == "DontDestroyOnLoad" && obj.transform.parent == null)
|
|
366
441
|
{
|
|
442
|
+
if (ReplaySessionState.IsSeeking && ReplayPresentationCanvas.IsPresentationRoot(obj))
|
|
443
|
+
{
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
|
|
367
447
|
UnityEngine.Object.Destroy(obj);
|
|
368
448
|
}
|
|
369
449
|
}
|
|
@@ -372,6 +452,7 @@ namespace Hyper.Internal
|
|
|
372
452
|
internal static void OnHostDestroyed(HyperRuntimeHost host)
|
|
373
453
|
{
|
|
374
454
|
if (_host != host) return;
|
|
455
|
+
_replayManager?.Cleanup();
|
|
375
456
|
ResetStaticState();
|
|
376
457
|
}
|
|
377
458
|
|
|
@@ -385,6 +466,7 @@ namespace Hyper.Internal
|
|
|
385
466
|
_gameManager = null;
|
|
386
467
|
_backendManager = null;
|
|
387
468
|
_dataManager = null;
|
|
469
|
+
_replayManager = null;
|
|
388
470
|
_gameContent = null;
|
|
389
471
|
_isInitialized = false;
|
|
390
472
|
_customLoadingComplete = false;
|
|
@@ -6,6 +6,7 @@ namespace Hyper.Internal
|
|
|
6
6
|
/// Lightweight MonoBehaviour that allows the internal runtime to participate in
|
|
7
7
|
/// Unity's update loop without exposing managed objects to public assemblies.
|
|
8
8
|
/// </summary>
|
|
9
|
+
[DefaultExecutionOrder(-10000)]
|
|
9
10
|
internal sealed class HyperRuntimeHost : MonoBehaviour
|
|
10
11
|
{
|
|
11
12
|
private void Awake()
|
|
@@ -18,6 +19,11 @@ namespace Hyper.Internal
|
|
|
18
19
|
HyperRuntime.Tick();
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
private void FixedUpdate()
|
|
23
|
+
{
|
|
24
|
+
HyperRuntime.FixedTick();
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
private void OnDestroy()
|
|
22
28
|
{
|
|
23
29
|
HyperRuntime.OnHostDestroyed(this);
|
|
@@ -27,6 +27,11 @@ namespace Hyper.Internal
|
|
|
27
27
|
/// </summary>
|
|
28
28
|
public bool isPVP => GameMode == GameMode.Battle;
|
|
29
29
|
|
|
30
|
+
/// <summary>
|
|
31
|
+
/// Returns true for modes that use battle gameplay, scenes, and timers.
|
|
32
|
+
/// </summary>
|
|
33
|
+
public bool IsBattleGameplay => GameMode == GameMode.Battle || GameMode == GameMode.Replay;
|
|
34
|
+
|
|
30
35
|
#endregion
|
|
31
36
|
|
|
32
37
|
#region Internal Fields
|
|
@@ -114,5 +119,17 @@ namespace Hyper.Internal
|
|
|
114
119
|
{
|
|
115
120
|
GameMode = GameMode.Practice;
|
|
116
121
|
}
|
|
122
|
+
|
|
123
|
+
public void SetModeAsReplay()
|
|
124
|
+
{
|
|
125
|
+
GameMode = GameMode.Replay;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
internal void SetModeFromLaunchFlags(bool isPVP, bool isReplay)
|
|
129
|
+
{
|
|
130
|
+
GameMode = isReplay
|
|
131
|
+
? GameMode.Replay
|
|
132
|
+
: isPVP ? GameMode.Battle : GameMode.Practice;
|
|
133
|
+
}
|
|
117
134
|
}
|
|
118
|
-
}
|
|
135
|
+
}
|