app.hypergames.hypersdk 1.11.0-beta.9 → 1.11.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 +188 -0
- package/Editor/Scripts/Inspectors/HyperSDKSettingsEditor.cs +15 -0
- package/HyperLoader.unity +2 -2
- package/Runtime/Internal/Bootstrap/HyperLoader.cs +5 -1
- package/Runtime/Internal/Core/HyperRuntime.cs +63 -1
- package/Runtime/Internal/Managers/BackendManager.cs +26 -3
- package/Runtime/Internal/Managers/DataManager.cs +8 -0
- package/Runtime/Internal/Managers/EventManager.cs +7 -1
- package/Runtime/Internal/Managers/GameManager.cs +21 -13
- package/Runtime/Internal/Managers/ReplayManager.cs +7 -2
- package/Runtime/Internal/Managers/TimeManager.cs +30 -12
- package/Runtime/Internal/Replay/ReplaySessionState.cs +15 -4
- package/Runtime/Internal/ScriptableObjects/HyperSDKSettings.cs +10 -0
- package/Runtime/Internal/UI/Components/ReplayController.cs +205 -27
- package/Runtime/Internal/UI/Components/ReplayPresentationCanvas.cs +1 -1
- package/Runtime/Internal/UI/Components/ReplaySeekOverlay.cs +18 -0
- package/Runtime/Internal/UI/Components/ReplaySeekOverlay.cs.meta +2 -0
- package/Runtime/Internal/UI/Modals/ReplayPausedModal.cs +9 -1
- package/Runtime/Internal/UI/Modals/StartingInstructionModal.cs +1 -1
- package/Runtime/Internal/UI/Modals/TimeUpModal.cs +2 -2
- package/Runtime/Public/Replay/ReplayPlaybackEngine.cs +71 -2
- package/Runtime/Resources/Fonts/Wonder Boys/Wonder Boys.asset +394 -379
- package/Runtime/Resources/HyperSDKSettings.asset +2 -0
- package/Runtime/Resources/Sprites/Circle Loader/Property 1=1.png.meta +7 -7
- package/Runtime/Resources/Sprites/Circle Loader/Property 1=2.png.meta +7 -7
- package/Runtime/Resources/Sprites/Circle Loader/Property 1=3.png.meta +7 -7
- package/Runtime/Resources/Sprites/Circle Loader/Property 1=4.png.meta +7 -7
- package/Runtime/Resources/Sprites/Circle Loader/Property 1=5.png.meta +7 -7
- package/Runtime/Resources/UIPrefabs/ReplayController.prefab +295 -15
- package/Runtime/Resources/UIPrefabs/ReplaySeekOverlay.prefab +291 -6
- package/Samples~/LaneRunner/Prefabs/DoubleScorePickup.prefab +1 -1
- package/Samples~/LaneRunner/Prefabs/Obstacle.prefab +1 -1
- package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerSpawner.cs +1 -1
- package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerTrackItem.cs +9 -2
- package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerTournamentAdapter.cs +1 -0
- package/package.json +1 -1
- /package/Runtime/{Public → Shared}/PlayerDeviceClassification.cs +0 -0
- /package/Runtime/{Public → Shared}/PlayerDeviceClassification.cs.meta +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,191 @@
|
|
|
1
|
+
## [1.11.1](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0...v1.11.1) (2026-09-24)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* stop battle gameplay on the fixed timeout tick ([d265c6d](https://github.com/mvmhyper/hyper-sdk/commit/d265c6de6d4fb19f6194b73000bfbef93397228d))
|
|
7
|
+
|
|
8
|
+
# [1.11.0](https://github.com/mvmhyper/hyper-sdk/compare/v1.10.0...v1.11.0) (2026-09-23)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **sdk:** promote replay support and stability improvements to stable ([#159](https://github.com/mvmhyper/hyper-sdk/issues/159)) ([8172b37](https://github.com/mvmhyper/hyper-sdk/commit/8172b376cc587d139a43c4f4b4204f5c29af7aef))
|
|
14
|
+
|
|
15
|
+
# [1.11.0-beta.33](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.32...v1.11.0-beta.33) (2026-09-11)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* **ui:** preserve mobile landscape canvas scaling ([c8a3f27](https://github.com/mvmhyper/hyper-sdk/commit/c8a3f2793bddaf89971a33d8752546a502de80e4))
|
|
21
|
+
|
|
22
|
+
# [1.11.0-beta.32](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.31...v1.11.0-beta.32) (2026-09-11)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
* **ui:** set landscape canvas scaler match to 0.75 ([edc44eb](https://github.com/mvmhyper/hyper-sdk/commit/edc44ebcc229d68ed40eb60b05df3ed25c5053f8))
|
|
28
|
+
|
|
29
|
+
# [1.11.0-beta.31](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.30...v1.11.0-beta.31) (2026-09-09)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Bug Fixes
|
|
33
|
+
|
|
34
|
+
* prevent gameplay timers jumping after pause ([d9d9de4](https://github.com/mvmhyper/hyper-sdk/commit/d9d9de4b7c71a0493b379bfb3f8e7712785c1401))
|
|
35
|
+
|
|
36
|
+
# [1.11.0-beta.30](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.29...v1.11.0-beta.30) (2026-09-08)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
### Bug Fixes
|
|
40
|
+
|
|
41
|
+
* **replay:** improve seek slider handle usability ([10c4847](https://github.com/mvmhyper/hyper-sdk/commit/10c48474c6dff689903aae99bff40215152710f6))
|
|
42
|
+
|
|
43
|
+
# [1.11.0-beta.29](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.28...v1.11.0-beta.29) (2026-09-08)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
### Bug Fixes
|
|
47
|
+
|
|
48
|
+
* **replay:** simplify seek progress presentation ([16cf45a](https://github.com/mvmhyper/hyper-sdk/commit/16cf45afb3bf4fed8abc094ce2405237f0bf3b1d))
|
|
49
|
+
|
|
50
|
+
# [1.11.0-beta.28](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.27...v1.11.0-beta.28) (2026-09-08)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
### Features
|
|
54
|
+
|
|
55
|
+
* update replay playback speed options ([fc5f653](https://github.com/mvmhyper/hyper-sdk/commit/fc5f65350b31425c53a131b7c44e8780e1b0ce2d))
|
|
56
|
+
|
|
57
|
+
# [1.11.0-beta.27](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.26...v1.11.0-beta.27) (2026-09-08)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
### Features
|
|
61
|
+
|
|
62
|
+
* **replay:** increase seek reconstruction speed ([97ce729](https://github.com/mvmhyper/hyper-sdk/commit/97ce72978d64711e0463def42283704e5d880266))
|
|
63
|
+
|
|
64
|
+
# [1.11.0-beta.26](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.25...v1.11.0-beta.26) (2026-09-07)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
### Bug Fixes
|
|
68
|
+
|
|
69
|
+
* **sample:** refine replay integration template ([5a345df](https://github.com/mvmhyper/hyper-sdk/commit/5a345df87d19a6df11af4117fbeed1e21e8e9f9a))
|
|
70
|
+
|
|
71
|
+
# [1.11.0-beta.25](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.24...v1.11.0-beta.25) (2026-09-04)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
### Features
|
|
75
|
+
|
|
76
|
+
* **replay:** include final score metadata ([463dcad](https://github.com/mvmhyper/hyper-sdk/commit/463dcadd4df5e5684f3be328b0ec361f25f26f2a))
|
|
77
|
+
|
|
78
|
+
# [1.11.0-beta.24](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.23...v1.11.0-beta.24) (2026-09-04)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
### Bug Fixes
|
|
82
|
+
|
|
83
|
+
* **replay:** add 1.5x playback speed ([3f7875f](https://github.com/mvmhyper/hyper-sdk/commit/3f7875fcc4934ed01aaa521dce45327a177f67a6))
|
|
84
|
+
|
|
85
|
+
# [1.11.0-beta.23](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.22...v1.11.0-beta.23) (2026-09-03)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
### Bug Fixes
|
|
89
|
+
|
|
90
|
+
* **replay:** smooth read-only progress display ([ead4579](https://github.com/mvmhyper/hyper-sdk/commit/ead45798883b24e4b4354f3aab22400a1399e212))
|
|
91
|
+
|
|
92
|
+
# [1.11.0-beta.22](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.21...v1.11.0-beta.22) (2026-09-03)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
### Features
|
|
96
|
+
|
|
97
|
+
* **replay:** finalize playback controls and settings ([559a7e4](https://github.com/mvmhyper/hyper-sdk/commit/559a7e48d9998efa022fe87253645dc13f83e901))
|
|
98
|
+
|
|
99
|
+
# [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)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
### Bug Fixes
|
|
103
|
+
|
|
104
|
+
* **replay:** align gameplay activities to fixed ticks ([1e681b9](https://github.com/mvmhyper/hyper-sdk/commit/1e681b9c7f314a48c417f6e76cb2d4024c890ad3))
|
|
105
|
+
|
|
106
|
+
# [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)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
### Bug Fixes
|
|
110
|
+
|
|
111
|
+
* **replay:** separate replay restart configuration ([de01d37](https://github.com/mvmhyper/hyper-sdk/commit/de01d37027fdde5d4f8803fa10e060d48a080316))
|
|
112
|
+
|
|
113
|
+
# [1.11.0-beta.19](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.18...v1.11.0-beta.19) (2026-09-01)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
### Bug Fixes
|
|
117
|
+
|
|
118
|
+
* **replay:** stop seeking at requested progress ([54bf74a](https://github.com/mvmhyper/hyper-sdk/commit/54bf74a4b66b7c19e1398acd611a7d9557ccbcf3))
|
|
119
|
+
|
|
120
|
+
# [1.11.0-beta.18](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.17...v1.11.0-beta.18) (2026-09-01)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
### Features
|
|
124
|
+
|
|
125
|
+
* **replay:** support custom replay restarts ([bf722ab](https://github.com/mvmhyper/hyper-sdk/commit/bf722abe48add18c356922c60231cb2017e28443))
|
|
126
|
+
|
|
127
|
+
# [1.11.0-beta.17](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.16...v1.11.0-beta.17) (2026-09-01)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
### Features
|
|
131
|
+
|
|
132
|
+
* **replay:** refine seek loading progress ([3d01f94](https://github.com/mvmhyper/hyper-sdk/commit/3d01f94d7e6ce360a61dd3d257149cf7f3237bcb))
|
|
133
|
+
|
|
134
|
+
# [1.11.0-beta.16](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.15...v1.11.0-beta.16) (2026-08-31)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
### Bug Fixes
|
|
138
|
+
|
|
139
|
+
* **replay:** show seek preparation progress ([60213f7](https://github.com/mvmhyper/hyper-sdk/commit/60213f784c5bff39da4634590545fe4d0e4c0911))
|
|
140
|
+
|
|
141
|
+
# [1.11.0-beta.15](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.14...v1.11.0-beta.15) (2026-08-31)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
### Features
|
|
145
|
+
|
|
146
|
+
* **replay:** show seek completion progress ([4e7c1b8](https://github.com/mvmhyper/hyper-sdk/commit/4e7c1b807bd9f34b97477ef39aa9ca3c06316ef3))
|
|
147
|
+
|
|
148
|
+
# [1.11.0-beta.14](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.13...v1.11.0-beta.14) (2026-08-31)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
### Bug Fixes
|
|
152
|
+
|
|
153
|
+
* **replay:** keep seek loader animating ([7e13938](https://github.com/mvmhyper/hyper-sdk/commit/7e13938ce718a238506c08c30744ff24ed7fa710))
|
|
154
|
+
|
|
155
|
+
# [1.11.0-beta.13](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.12...v1.11.0-beta.13) (2026-08-31)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
### Bug Fixes
|
|
159
|
+
|
|
160
|
+
* **replay:** reduce default seek speed to 10x ([ccaf5b9](https://github.com/mvmhyper/hyper-sdk/commit/ccaf5b9807fd9439627072518317ad7f079e544c))
|
|
161
|
+
|
|
162
|
+
# [1.11.0-beta.12](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.11...v1.11.0-beta.12) (2026-08-31)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
### Bug Fixes
|
|
166
|
+
|
|
167
|
+
* **replay:** reduce default seek speed ([d757710](https://github.com/mvmhyper/hyper-sdk/commit/d757710d107a0a496c9d7daa1434004a682bd355))
|
|
168
|
+
|
|
169
|
+
# [1.11.0-beta.11](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.10...v1.11.0-beta.11) (2026-08-30)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
### Bug Fixes
|
|
173
|
+
|
|
174
|
+
* **replay:** apply 30x seek speed on beta ([564769e](https://github.com/mvmhyper/hyper-sdk/commit/564769e4764f27fd301f0e1dc52a4434635f93b7))
|
|
175
|
+
* **replay:** reduce default seek speed ([2cd0a34](https://github.com/mvmhyper/hyper-sdk/commit/2cd0a34c6390725d1c57fc3fa5f691f618c45083))
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
### Features
|
|
179
|
+
|
|
180
|
+
* **replay:** increase default seek speed ([d1a5a46](https://github.com/mvmhyper/hyper-sdk/commit/d1a5a464c1e3e149255bf0d2d183439e9c29cfb3))
|
|
181
|
+
|
|
182
|
+
# [1.11.0-beta.10](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.9...v1.11.0-beta.10) (2026-08-30)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
### Bug Fixes
|
|
186
|
+
|
|
187
|
+
* **replay:** reduce default seek speed ([f70551a](https://github.com/mvmhyper/hyper-sdk/commit/f70551aea942274ace1cb952ddae4e9edb0c1c12))
|
|
188
|
+
|
|
1
189
|
# [1.11.0-beta.9](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.0-beta.8...v1.11.0-beta.9) (2026-08-30)
|
|
2
190
|
|
|
3
191
|
|
|
@@ -170,6 +170,21 @@ namespace Hyper.Editor
|
|
|
170
170
|
settings.useCustomRestartFlow = EditorGUILayout.Toggle(
|
|
171
171
|
new GUIContent("Use Custom Restart Flow"),
|
|
172
172
|
settings.useCustomRestartFlow);
|
|
173
|
+
settings.useCustomReplayRestartFlow = EditorGUILayout.Toggle(
|
|
174
|
+
new GUIContent(
|
|
175
|
+
"Replay Custom Restart",
|
|
176
|
+
"Use game-owned restart logic for replay Watch Again and seeking. " +
|
|
177
|
+
"Disabled uses HyperLoader to rebuild deterministic game state."),
|
|
178
|
+
settings.useCustomReplayRestartFlow);
|
|
179
|
+
|
|
180
|
+
EditorGUILayout.Space(12);
|
|
181
|
+
EditorGUILayout.LabelField("Replay Settings", EditorStyles.boldLabel);
|
|
182
|
+
settings.allowReplaySeeking = EditorGUILayout.Toggle(
|
|
183
|
+
new GUIContent(
|
|
184
|
+
"Allow Replay Seeking",
|
|
185
|
+
"Allow viewers to seek using the replay progress bar. " +
|
|
186
|
+
"Leave disabled until accelerated replay reconstruction is validated for this game."),
|
|
187
|
+
settings.allowReplaySeeking);
|
|
173
188
|
|
|
174
189
|
EditorGUILayout.Space(12);
|
|
175
190
|
// Draw Editor Testing
|
package/HyperLoader.unity
CHANGED
|
@@ -304,7 +304,7 @@ RectTransform:
|
|
|
304
304
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
305
305
|
m_AnchorMin: {x: 0, y: 1}
|
|
306
306
|
m_AnchorMax: {x: 0, y: 1}
|
|
307
|
-
m_AnchoredPosition: {x: 489.
|
|
307
|
+
m_AnchoredPosition: {x: 489.20746, y: -280.1698}
|
|
308
308
|
m_SizeDelta: {x: 1044.9, y: 239.347}
|
|
309
309
|
m_Pivot: {x: 0.5, y: 0.5}
|
|
310
310
|
--- !u!114 &751153944
|
|
@@ -1092,7 +1092,7 @@ RectTransform:
|
|
|
1092
1092
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
1093
1093
|
m_AnchorMin: {x: 0, y: 1}
|
|
1094
1094
|
m_AnchorMax: {x: 0, y: 1}
|
|
1095
|
-
m_AnchoredPosition: {x: 489.
|
|
1095
|
+
m_AnchoredPosition: {x: 489.20746, y: -133.2274}
|
|
1096
1096
|
m_SizeDelta: {x: 875, y: 54.5378}
|
|
1097
1097
|
m_Pivot: {x: 0.5, y: 0.5}
|
|
1098
1098
|
--- !u!1 &2874543288936963705
|
|
@@ -448,7 +448,11 @@ namespace Hyper.Internal
|
|
|
448
448
|
return false;
|
|
449
449
|
}
|
|
450
450
|
|
|
451
|
-
ReplaySessionState.SetMetadata(
|
|
451
|
+
ReplaySessionState.SetMetadata(
|
|
452
|
+
replay.PlayerName,
|
|
453
|
+
replay.AvatarUrl,
|
|
454
|
+
replay.Seed,
|
|
455
|
+
replay.FinalScore);
|
|
452
456
|
ReplaySessionState.SetReplayData(replay.ActivityNdjson);
|
|
453
457
|
HyperDebug.Log($"Replay loaded from {path}");
|
|
454
458
|
return true;
|
|
@@ -15,6 +15,8 @@ namespace Hyper.Internal
|
|
|
15
15
|
/// </summary>
|
|
16
16
|
internal static class HyperRuntime
|
|
17
17
|
{
|
|
18
|
+
private const float ReplayCustomRestartTimeoutSeconds = 10f;
|
|
19
|
+
|
|
18
20
|
private static HyperRuntimeHost _host;
|
|
19
21
|
private static GameObject _singletonObject;
|
|
20
22
|
|
|
@@ -22,6 +24,7 @@ namespace Hyper.Internal
|
|
|
22
24
|
private static bool _isSoftRestarting;
|
|
23
25
|
private static bool _replayRandomResetPending;
|
|
24
26
|
private static bool _replayCustomRestartPending;
|
|
27
|
+
private static int _replayCustomRestartVersion;
|
|
25
28
|
private static bool _customLoadingComplete;
|
|
26
29
|
private static bool _customLoadingActive;
|
|
27
30
|
private static float _customLoadingProgress;
|
|
@@ -123,7 +126,8 @@ namespace Hyper.Internal
|
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
/// <summary>
|
|
126
|
-
/// Restarts replay playback
|
|
129
|
+
/// Restarts replay playback while preserving replay session data. Uses the game-owned
|
|
130
|
+
/// replay restart flow only when explicitly enabled and otherwise reloads HyperLoader.
|
|
127
131
|
/// </summary>
|
|
128
132
|
internal static void RestartReplaySession()
|
|
129
133
|
{
|
|
@@ -147,8 +151,64 @@ namespace Hyper.Internal
|
|
|
147
151
|
|
|
148
152
|
_replayCustomRestartPending = false;
|
|
149
153
|
_replayRandomResetPending = false;
|
|
154
|
+
int restartVersion = ++_replayCustomRestartVersion;
|
|
150
155
|
_replayManager?.PrepareForRestart();
|
|
151
156
|
|
|
157
|
+
if (_settings != null && _settings.useCustomReplayRestartFlow &&
|
|
158
|
+
_host != null && _gameManager != null && _eventManager != null)
|
|
159
|
+
{
|
|
160
|
+
_replayCustomRestartPending = true;
|
|
161
|
+
_replayRandomResetPending = true;
|
|
162
|
+
_gameManager.ResetUIStateForCustomRestart();
|
|
163
|
+
|
|
164
|
+
try
|
|
165
|
+
{
|
|
166
|
+
if (!_eventManager.InvokeCustomRestartEvent())
|
|
167
|
+
{
|
|
168
|
+
HyperDebug.LogWarning(
|
|
169
|
+
"[Replay] Custom restart has no handler; falling back to HyperLoader.");
|
|
170
|
+
BeginReplaySceneRestart(restartVersion);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
_host.StartCoroutine(WaitForReplayCustomRestart(restartVersion));
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
catch (Exception exception)
|
|
178
|
+
{
|
|
179
|
+
HyperDebug.LogWarning(
|
|
180
|
+
$"[Replay] Custom restart failed; falling back to HyperLoader: {exception.Message}");
|
|
181
|
+
BeginReplaySceneRestart(restartVersion);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
BeginReplaySceneRestart(restartVersion);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private static IEnumerator WaitForReplayCustomRestart(int restartVersion)
|
|
190
|
+
{
|
|
191
|
+
float timeoutAt = Time.realtimeSinceStartup + ReplayCustomRestartTimeoutSeconds;
|
|
192
|
+
while (_replayCustomRestartPending && restartVersion == _replayCustomRestartVersion &&
|
|
193
|
+
Time.realtimeSinceStartup < timeoutAt)
|
|
194
|
+
{
|
|
195
|
+
yield return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (!_replayCustomRestartPending || restartVersion != _replayCustomRestartVersion) yield break;
|
|
199
|
+
|
|
200
|
+
HyperDebug.LogWarning(
|
|
201
|
+
$"[Replay] Custom restart did not complete within {ReplayCustomRestartTimeoutSeconds:0} seconds; " +
|
|
202
|
+
"falling back to HyperLoader.");
|
|
203
|
+
BeginReplaySceneRestart(restartVersion);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private static void BeginReplaySceneRestart(int restartVersion)
|
|
207
|
+
{
|
|
208
|
+
if (restartVersion != _replayCustomRestartVersion) return;
|
|
209
|
+
|
|
210
|
+
_replayCustomRestartPending = false;
|
|
211
|
+
_replayRandomResetPending = false;
|
|
152
212
|
if (_host != null)
|
|
153
213
|
{
|
|
154
214
|
_host.StartCoroutine(RestartSessionCoroutine());
|
|
@@ -443,6 +503,7 @@ namespace Hyper.Internal
|
|
|
443
503
|
_customLoadingProgress = 0f;
|
|
444
504
|
_replayRandomResetPending = false;
|
|
445
505
|
_replayCustomRestartPending = false;
|
|
506
|
+
_replayCustomRestartVersion++;
|
|
446
507
|
_fixedSimulationTimeSeconds = 0d;
|
|
447
508
|
|
|
448
509
|
if (_singletonObject != null)
|
|
@@ -504,6 +565,7 @@ namespace Hyper.Internal
|
|
|
504
565
|
_customLoadingProgress = 0f;
|
|
505
566
|
_replayRandomResetPending = false;
|
|
506
567
|
_replayCustomRestartPending = false;
|
|
568
|
+
_replayCustomRestartVersion++;
|
|
507
569
|
_fixedSimulationTimeSeconds = 0d;
|
|
508
570
|
}
|
|
509
571
|
}
|
|
@@ -179,7 +179,8 @@ namespace Hyper.Internal.Managers
|
|
|
179
179
|
ReplaySessionState.SetMetadata(
|
|
180
180
|
replay.PlayerName,
|
|
181
181
|
replay.AvatarUrl,
|
|
182
|
-
replay.Seed
|
|
182
|
+
replay.Seed,
|
|
183
|
+
replay.FinalScore);
|
|
183
184
|
ReplaySessionState.SetReplayData(replay.ActivityNdjson);
|
|
184
185
|
HyperDebug.Log($"Replay downloaded for entry {entryId}.");
|
|
185
186
|
onSuccess?.Invoke();
|
|
@@ -289,9 +290,10 @@ namespace Hyper.Internal.Managers
|
|
|
289
290
|
string seedLine = reader.ReadLine();
|
|
290
291
|
string nameLine = reader.ReadLine();
|
|
291
292
|
string avatarLine = reader.ReadLine();
|
|
293
|
+
string scoreLine = reader.ReadLine();
|
|
292
294
|
string activities = reader.ReadToEnd();
|
|
293
295
|
|
|
294
|
-
if (seedLine == null || nameLine == null || avatarLine == null)
|
|
296
|
+
if (seedLine == null || nameLine == null || avatarLine == null || scoreLine == null)
|
|
295
297
|
{
|
|
296
298
|
error = "The replay response is missing required metadata.";
|
|
297
299
|
return false;
|
|
@@ -302,6 +304,7 @@ namespace Hyper.Internal.Managers
|
|
|
302
304
|
JArray seedData = JArray.Parse(seedLine);
|
|
303
305
|
JArray nameData = JArray.Parse(nameLine);
|
|
304
306
|
JArray avatarData = JArray.Parse(avatarLine);
|
|
307
|
+
JArray scoreData = JArray.Parse(scoreLine);
|
|
305
308
|
|
|
306
309
|
if (seedData.Count != 1 ||
|
|
307
310
|
seedData[0].Type != JTokenType.Integer ||
|
|
@@ -327,6 +330,18 @@ namespace Hyper.Internal.Managers
|
|
|
327
330
|
return false;
|
|
328
331
|
}
|
|
329
332
|
|
|
333
|
+
if (scoreData.Count != 1 ||
|
|
334
|
+
scoreData[0].Type != JTokenType.Integer ||
|
|
335
|
+
!int.TryParse(
|
|
336
|
+
scoreData[0].ToString(),
|
|
337
|
+
NumberStyles.Integer,
|
|
338
|
+
CultureInfo.InvariantCulture,
|
|
339
|
+
out int finalScore))
|
|
340
|
+
{
|
|
341
|
+
error = "Replay metadata contains an invalid final score.";
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
|
|
330
345
|
if (string.IsNullOrWhiteSpace(activities))
|
|
331
346
|
{
|
|
332
347
|
error = "The replay response contains no gameplay activities.";
|
|
@@ -337,6 +352,7 @@ namespace Hyper.Internal.Managers
|
|
|
337
352
|
seed,
|
|
338
353
|
nameData[0].Value<string>() ?? string.Empty,
|
|
339
354
|
avatarData[0].Value<string>() ?? string.Empty,
|
|
355
|
+
finalScore,
|
|
340
356
|
activities);
|
|
341
357
|
|
|
342
358
|
return true;
|
|
@@ -354,13 +370,20 @@ namespace Hyper.Internal.Managers
|
|
|
354
370
|
internal long Seed { get; }
|
|
355
371
|
internal string PlayerName { get; }
|
|
356
372
|
internal string AvatarUrl { get; }
|
|
373
|
+
internal int FinalScore { get; }
|
|
357
374
|
internal string ActivityNdjson { get; }
|
|
358
375
|
|
|
359
|
-
internal ReplayResponse(
|
|
376
|
+
internal ReplayResponse(
|
|
377
|
+
long seed,
|
|
378
|
+
string playerName,
|
|
379
|
+
string avatarUrl,
|
|
380
|
+
int finalScore,
|
|
381
|
+
string activityNdjson)
|
|
360
382
|
{
|
|
361
383
|
Seed = seed;
|
|
362
384
|
PlayerName = playerName;
|
|
363
385
|
AvatarUrl = avatarUrl;
|
|
386
|
+
FinalScore = finalScore;
|
|
364
387
|
ActivityNdjson = activityNdjson;
|
|
365
388
|
}
|
|
366
389
|
}
|
|
@@ -375,6 +375,7 @@ namespace Hyper.Internal.Managers
|
|
|
375
375
|
new object[] { HyperRandom.CurrentSeed }));
|
|
376
376
|
_editorReplay.AppendLine(JsonConvert.SerializeObject(new object[] { "hypergamer" }));
|
|
377
377
|
_editorReplay.AppendLine(JsonConvert.SerializeObject(new object[] { string.Empty }));
|
|
378
|
+
_editorReplayMetadataLength = _editorReplay.Length;
|
|
378
379
|
#endif
|
|
379
380
|
_replayRecorder?.StartSession();
|
|
380
381
|
}
|
|
@@ -426,6 +427,7 @@ namespace Hyper.Internal.Managers
|
|
|
426
427
|
|
|
427
428
|
#if UNITY_EDITOR
|
|
428
429
|
private readonly StringBuilder _editorReplay = new StringBuilder(4096);
|
|
430
|
+
private int _editorReplayMetadataLength;
|
|
429
431
|
|
|
430
432
|
private void CaptureEditorReplayActivity(object[] activity)
|
|
431
433
|
{
|
|
@@ -434,6 +436,8 @@ namespace Hyper.Internal.Managers
|
|
|
434
436
|
|
|
435
437
|
private void SaveEditorReplay()
|
|
436
438
|
{
|
|
439
|
+
string finalScoreLine = JsonConvert.SerializeObject(new object[] { CurrentScore }) + Environment.NewLine;
|
|
440
|
+
_editorReplay.Insert(_editorReplayMetadataLength, finalScoreLine);
|
|
437
441
|
try
|
|
438
442
|
{
|
|
439
443
|
File.WriteAllText(ReplaySessionState.EditorReplayFilePath, _editorReplay.ToString());
|
|
@@ -443,6 +447,10 @@ namespace Hyper.Internal.Managers
|
|
|
443
447
|
{
|
|
444
448
|
HyperDebug.LogWarning($"Unable to save Editor replay: {exception.Message}");
|
|
445
449
|
}
|
|
450
|
+
finally
|
|
451
|
+
{
|
|
452
|
+
_editorReplay.Remove(_editorReplayMetadataLength, finalScoreLine.Length);
|
|
453
|
+
}
|
|
446
454
|
}
|
|
447
455
|
#endif
|
|
448
456
|
|
|
@@ -79,7 +79,13 @@ namespace Hyper.Internal.Managers
|
|
|
79
79
|
internal void InvokeGameEndedEvent() => OnGameEnded?.Invoke();
|
|
80
80
|
internal void InvokeLivesExhaustedEvent() => OnLivesExhausted?.Invoke();
|
|
81
81
|
internal void InvokeHealthExhaustedEvent() => OnHealthExhausted?.Invoke();
|
|
82
|
-
internal
|
|
82
|
+
internal bool InvokeCustomRestartEvent()
|
|
83
|
+
{
|
|
84
|
+
Action handler = OnCustomRestart;
|
|
85
|
+
if (handler == null) return false;
|
|
86
|
+
handler.Invoke();
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
83
89
|
internal void InvokeConnectionLostEvent() => OnInternetConnectionLost?.Invoke();
|
|
84
90
|
internal void InvokeConnectionFoundEvent() => OnInternetConnectionFound?.Invoke();
|
|
85
91
|
internal void InvokeBackendSocketManuallyClosedEvent() => OnBackendSocketManuallyClosed?.Invoke();
|
|
@@ -62,14 +62,14 @@ namespace Hyper.Internal.Managers
|
|
|
62
62
|
|
|
63
63
|
private void HandleLivesExhausted()
|
|
64
64
|
{
|
|
65
|
-
if (!IsInGameScene ||
|
|
65
|
+
if (!IsInGameScene || HasGameEnded || !_hasGameStarted) return;
|
|
66
66
|
|
|
67
67
|
EndGame();
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
private void HandleHealthExhausted()
|
|
71
71
|
{
|
|
72
|
-
if (!IsInGameScene ||
|
|
72
|
+
if (!IsInGameScene || HasGameEnded || !_hasGameStarted) return;
|
|
73
73
|
|
|
74
74
|
EndGame();
|
|
75
75
|
}
|
|
@@ -98,7 +98,10 @@ namespace Hyper.Internal.Managers
|
|
|
98
98
|
public bool IsReplayMode => Config.GameMode == GameMode.Replay;
|
|
99
99
|
public bool IsPaused => _isPaused;
|
|
100
100
|
public bool HasGameStarted => _hasGameStarted;
|
|
101
|
-
|
|
101
|
+
// Gameplay stops at the timer boundary; presentation/finalization may follow later.
|
|
102
|
+
public bool HasGameEnded => _hasGameEnded || _gameplayCutoffReached;
|
|
103
|
+
|
|
104
|
+
internal void ReachGameplayCutoff() => _gameplayCutoffReached = true;
|
|
102
105
|
|
|
103
106
|
internal int BattleTimeRemaining =>
|
|
104
107
|
IsBattleMode && HyperRuntime.Timer != null
|
|
@@ -177,7 +180,7 @@ namespace Hyper.Internal.Managers
|
|
|
177
180
|
internal void PauseGame()
|
|
178
181
|
{
|
|
179
182
|
if (IsReplayMode) return;
|
|
180
|
-
if (!_hasGameStarted || _isPaused ||
|
|
183
|
+
if (!_hasGameStarted || _isPaused || HasGameEnded) return;
|
|
181
184
|
|
|
182
185
|
_isPaused = true;
|
|
183
186
|
_isFrozenBeforePause = Time.timeScale == 0;
|
|
@@ -193,7 +196,7 @@ namespace Hyper.Internal.Managers
|
|
|
193
196
|
|
|
194
197
|
internal void PauseReplay()
|
|
195
198
|
{
|
|
196
|
-
if (!IsReplayMode || !_hasGameStarted || _isPaused ||
|
|
199
|
+
if (!IsReplayMode || !_hasGameStarted || _isPaused || HasGameEnded)
|
|
197
200
|
{
|
|
198
201
|
return;
|
|
199
202
|
}
|
|
@@ -214,7 +217,7 @@ namespace Hyper.Internal.Managers
|
|
|
214
217
|
|
|
215
218
|
internal void ResumeReplay()
|
|
216
219
|
{
|
|
217
|
-
if (!IsReplayMode || !_isPaused ||
|
|
220
|
+
if (!IsReplayMode || !_isPaused || HasGameEnded) return;
|
|
218
221
|
|
|
219
222
|
_isPaused = false;
|
|
220
223
|
HidePauseModals();
|
|
@@ -256,7 +259,7 @@ namespace Hyper.Internal.Managers
|
|
|
256
259
|
|
|
257
260
|
private void HandleReplayFocus(bool hasFocus)
|
|
258
261
|
{
|
|
259
|
-
if (!_hasGameStarted ||
|
|
262
|
+
if (!_hasGameStarted || HasGameEnded) return;
|
|
260
263
|
if (!hasFocus) PauseReplay();
|
|
261
264
|
}
|
|
262
265
|
|
|
@@ -292,13 +295,13 @@ namespace Hyper.Internal.Managers
|
|
|
292
295
|
|
|
293
296
|
// Always restart capturing when game resumes, even if offline,
|
|
294
297
|
// so scores accumulate for the offline batch and are flushed on reconnect.
|
|
295
|
-
if (!IsReplayMode && !
|
|
298
|
+
if (!IsReplayMode && !HasGameEnded && _hasGameStarted)
|
|
296
299
|
{
|
|
297
300
|
_dataManager.StartCapturingScores();
|
|
298
301
|
}
|
|
299
302
|
|
|
300
303
|
// Only resume server session if connected
|
|
301
|
-
if (!IsReplayMode && _backendManager.isSocketConnected && !
|
|
304
|
+
if (!IsReplayMode && _backendManager.isSocketConnected && !HasGameEnded && _hasGameStarted)
|
|
302
305
|
{
|
|
303
306
|
_backendManager.SendGameResumed();
|
|
304
307
|
}
|
|
@@ -714,6 +717,7 @@ namespace Hyper.Internal.Managers
|
|
|
714
717
|
private bool _gameStartRequested;
|
|
715
718
|
private bool _isPaused;
|
|
716
719
|
private bool _hasGameEnded;
|
|
720
|
+
private bool _gameplayCutoffReached;
|
|
717
721
|
private bool _replayEndHandled;
|
|
718
722
|
private bool _isFrozenBeforePause;
|
|
719
723
|
private bool _isPortrait;
|
|
@@ -948,6 +952,7 @@ namespace Hyper.Internal.Managers
|
|
|
948
952
|
_hasGameStarted = false;
|
|
949
953
|
_gameStartRequested = false;
|
|
950
954
|
_hasGameEnded = false;
|
|
955
|
+
_gameplayCutoffReached = false;
|
|
951
956
|
_isPaused = false;
|
|
952
957
|
_isFrozenBeforePause = false;
|
|
953
958
|
HideTopBarElements();
|
|
@@ -973,6 +978,7 @@ namespace Hyper.Internal.Managers
|
|
|
973
978
|
_hasGameStarted = false;
|
|
974
979
|
_gameStartRequested = false;
|
|
975
980
|
_hasGameEnded = false;
|
|
981
|
+
_gameplayCutoffReached = false;
|
|
976
982
|
_replayEndHandled = false;
|
|
977
983
|
_isPaused = false;
|
|
978
984
|
_isFrozenBeforePause = false;
|
|
@@ -1012,7 +1018,7 @@ namespace Hyper.Internal.Managers
|
|
|
1012
1018
|
|
|
1013
1019
|
internal void StartGameplay()
|
|
1014
1020
|
{
|
|
1015
|
-
if (_gameStartRequested || _hasGameStarted ||
|
|
1021
|
+
if (_gameStartRequested || _hasGameStarted || HasGameEnded || !IsInGameScene) return;
|
|
1016
1022
|
_gameStartRequested = true;
|
|
1017
1023
|
|
|
1018
1024
|
HyperRuntime.ApplyPendingReplayRandomReset();
|
|
@@ -1045,6 +1051,7 @@ namespace Hyper.Internal.Managers
|
|
|
1045
1051
|
{
|
|
1046
1052
|
_hasGameStarted = true;
|
|
1047
1053
|
_hasGameEnded = false;
|
|
1054
|
+
_gameplayCutoffReached = false;
|
|
1048
1055
|
HyperRuntime.DataManager.UpdateScore(0);
|
|
1049
1056
|
}
|
|
1050
1057
|
|
|
@@ -1066,6 +1073,7 @@ namespace Hyper.Internal.Managers
|
|
|
1066
1073
|
_hasGameStarted = false;
|
|
1067
1074
|
_gameStartRequested = false;
|
|
1068
1075
|
_hasGameEnded = false;
|
|
1076
|
+
_gameplayCutoffReached = false;
|
|
1069
1077
|
_replayEndHandled = false;
|
|
1070
1078
|
_isPaused = false;
|
|
1071
1079
|
_isFrozenBeforePause = false;
|
|
@@ -1096,7 +1104,7 @@ namespace Hyper.Internal.Managers
|
|
|
1096
1104
|
|
|
1097
1105
|
internal void CompleteReplayCustomRestart()
|
|
1098
1106
|
{
|
|
1099
|
-
if (!IsReplayMode || _gameStartRequested || _hasGameStarted ||
|
|
1107
|
+
if (!IsReplayMode || _gameStartRequested || _hasGameStarted || HasGameEnded) return;
|
|
1100
1108
|
|
|
1101
1109
|
if (ReplaySessionState.IsSeeking)
|
|
1102
1110
|
{
|
|
@@ -1143,7 +1151,7 @@ namespace Hyper.Internal.Managers
|
|
|
1143
1151
|
{
|
|
1144
1152
|
if (ReplaySessionState.IsSeekRestartPending) return;
|
|
1145
1153
|
|
|
1146
|
-
// Time Up marks _hasGameEnded before its
|
|
1154
|
+
// Time Up marks _hasGameEnded before its one-second presentation finishes.
|
|
1147
1155
|
// Track replay finalization separately so that delayed end still runs once.
|
|
1148
1156
|
if (_replayEndHandled) return;
|
|
1149
1157
|
|
|
@@ -1334,7 +1342,7 @@ namespace Hyper.Internal.Managers
|
|
|
1334
1342
|
_canvasScaler = _canvas.GetComponent<CanvasScaler>();
|
|
1335
1343
|
_canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
|
1336
1344
|
_canvasScaler.referenceResolution = new Vector2(1080, 2160);
|
|
1337
|
-
_canvasScaler.matchWidthOrHeight = IsPortrait() ? 1f : 0.593f;
|
|
1345
|
+
_canvasScaler.matchWidthOrHeight = IsPortrait() ? 1f : (PlayerDeviceClassification.PlayerDeviceIsPC ? 0.75f : 0.593f);
|
|
1338
1346
|
|
|
1339
1347
|
CreateHyperCanvasSafeArea();
|
|
1340
1348
|
CreateHyperCanvasBlockerUI();
|
|
@@ -36,7 +36,10 @@ namespace Hyper.Internal.Managers
|
|
|
36
36
|
{
|
|
37
37
|
if (_playback == null || !_playback.IsPlaying) return;
|
|
38
38
|
_playback.Tick();
|
|
39
|
-
ReplaySessionState.SetProgress(_playback.Progress01)
|
|
39
|
+
if (ReplaySessionState.SetProgress(_playback.Progress01))
|
|
40
|
+
{
|
|
41
|
+
UnityEngine.Time.timeScale = ReplaySessionState.PlaybackSpeed;
|
|
42
|
+
}
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
internal void PrepareForRestart()
|
|
@@ -100,7 +103,9 @@ namespace Hyper.Internal.Managers
|
|
|
100
103
|
ReplaySessionState.MarkEnded();
|
|
101
104
|
|
|
102
105
|
GameManager gameManager = HyperRuntime.GameManager;
|
|
103
|
-
|
|
106
|
+
// Time Up can freeze gameplay before the recorded GE arrives.
|
|
107
|
+
// EndReplayGame has its own once-only finalization guard.
|
|
108
|
+
if (gameManager == null) return;
|
|
104
109
|
|
|
105
110
|
_endingGame = true;
|
|
106
111
|
gameManager.EndGame();
|