app.hypergames.hypersdk 1.4.13 → 1.4.14
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 +8 -0
- package/Editor/Scripts/Setup/HyperSDKInstaller.cs +115 -16
- package/Editor/Scripts/Tools/HyperBuildAssistant.cs +4 -4
- package/HyperLoader.unity +3 -3
- package/Runtime/Internal/Managers/BackendManager.cs +106 -45
- package/Runtime/Internal/Managers/EventManager.cs +4 -0
- package/Runtime/Internal/Managers/GameManager.cs +36 -14
- package/Runtime/Internal/UI/Animation/SlideUp.cs +2 -2
- package/Runtime/Internal/UI/Modals/StartingInstructionModal.cs +76 -0
- package/Runtime/Resources/Fonts/Wonder Boys/Wonder Boys + Hyper BIG.mat +2 -2
- package/Runtime/Resources/Fonts/Wonder Boys/Wonder Boys + Shadows.mat +2 -2
- package/Runtime/Resources/Fonts/Wonder Boys/Wonder Boys.asset +1009 -311
- package/Runtime/Resources/UIPrefabs/SnackBar.prefab +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## [1.4.14](https://github.com/mvmhyper/hyper-sdk/compare/v1.4.13...v1.4.14) (2026-01-06)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* migrate final submit to websockets; refresh CSRF on freeze-resume ([8b445e7](https://github.com/mvmhyper/hyper-sdk/commit/8b445e78d677507cc2ef7bce54d815df0ee0f58b))
|
|
7
|
+
* Minor Bug fixes and improvements. ([a5004b5](https://github.com/mvmhyper/hyper-sdk/commit/a5004b5d054be4e5a432f30a6abcfad4287f70b7))
|
|
8
|
+
|
|
1
9
|
## [1.4.13](https://github.com/mvmhyper/hyper-sdk/compare/v1.4.12...v1.4.13) (2026-01-01)
|
|
2
10
|
|
|
3
11
|
|
|
@@ -55,35 +55,58 @@ namespace Hyper.Editor
|
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
var currentVersion = packageInfo.version;
|
|
58
59
|
var previousVersion = EditorPrefs.GetString(InstallerPrefsKey, string.Empty);
|
|
59
60
|
var sceneExists = File.Exists(HyperLoaderSceneDestination);
|
|
60
61
|
var templateExists = Directory.Exists(WebGLTemplateDestination);
|
|
61
62
|
var configExists = File.Exists(HyperGameContentConfigDestination);
|
|
62
63
|
var settingsExists = File.Exists(HyperSDKSettingsDestination);
|
|
63
64
|
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
configExists &&
|
|
69
|
-
settingsExists)
|
|
70
|
-
{
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
|
|
65
|
+
// Check what kind of version change we are dealing with
|
|
66
|
+
bool isMajorVersionChange = HasMajorVersionChanged(previousVersion, currentVersion);
|
|
67
|
+
bool isMajorOrMinorVersionChange = HasMajorOrMinorVersionChanged(previousVersion, currentVersion);
|
|
68
|
+
|
|
74
69
|
var packageRoot = packageInfo.resolvedPath;
|
|
75
70
|
var hyperLoaderSource = Path.Combine(packageRoot, HyperLoaderSceneRelativePath);
|
|
76
71
|
var templateSource = Path.Combine(packageRoot, WebGLTemplateRelativePath);
|
|
77
72
|
var hyperGameContentConfigSource = Path.Combine(packageRoot, HyperGameContentConfigRelativePath);
|
|
78
73
|
var hyperSDKSettingsSource = Path.Combine(packageRoot, HyperSDKSettingsRelativePath);
|
|
79
74
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
75
|
+
bool anyFileCopied = false;
|
|
76
|
+
|
|
77
|
+
if (!sceneExists || isMajorVersionChange)
|
|
78
|
+
{
|
|
79
|
+
CopyFileWithoutMeta(hyperLoaderSource, HyperLoaderSceneDestination);
|
|
80
|
+
anyFileCopied = true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!templateExists || isMajorOrMinorVersionChange)
|
|
84
|
+
{
|
|
85
|
+
CopyTemplate(templateSource);
|
|
86
|
+
anyFileCopied = true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!configExists || isMajorOrMinorVersionChange)
|
|
90
|
+
{
|
|
91
|
+
CopyFileWithoutMeta(hyperGameContentConfigSource, HyperGameContentConfigDestination);
|
|
92
|
+
anyFileCopied = true;
|
|
93
|
+
}
|
|
84
94
|
|
|
85
|
-
|
|
86
|
-
|
|
95
|
+
if (!settingsExists || isMajorOrMinorVersionChange)
|
|
96
|
+
{
|
|
97
|
+
CopyFileWithoutMeta(hyperSDKSettingsSource, HyperSDKSettingsDestination);
|
|
98
|
+
anyFileCopied = true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Always update the stored version, even if no files were copied
|
|
102
|
+
if (previousVersion != currentVersion)
|
|
103
|
+
{
|
|
104
|
+
EditorPrefs.SetString(InstallerPrefsKey, currentVersion);
|
|
105
|
+
if (anyFileCopied)
|
|
106
|
+
{
|
|
107
|
+
AssetDatabase.Refresh();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
87
110
|
}
|
|
88
111
|
|
|
89
112
|
private static void CopyFileWithoutMeta(string sourcePath, string destinationPath)
|
|
@@ -143,6 +166,82 @@ namespace Hyper.Editor
|
|
|
143
166
|
FileUtil.DeleteFileOrDirectory(meta);
|
|
144
167
|
}
|
|
145
168
|
}
|
|
169
|
+
|
|
170
|
+
/// <summary>
|
|
171
|
+
/// Parses a semantic version string (e.g., "1.4.5") and returns major, minor, patch components.
|
|
172
|
+
/// Returns (0, 0, 0) if version string is invalid or empty.
|
|
173
|
+
/// </summary>
|
|
174
|
+
private static (int major, int minor, int patch) ParseVersion(string version)
|
|
175
|
+
{
|
|
176
|
+
if (string.IsNullOrEmpty(version))
|
|
177
|
+
{
|
|
178
|
+
return (0, 0, 0);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Remove any pre-release or build metadata (e.g., "1.4.5-preview.1" -> "1.4.5")
|
|
182
|
+
var cleanVersion = version.Split('-')[0].Split('+')[0];
|
|
183
|
+
|
|
184
|
+
var parts = cleanVersion.Split('.');
|
|
185
|
+
if (parts.Length < 2)
|
|
186
|
+
{
|
|
187
|
+
return (0, 0, 0);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
int major = int.TryParse(parts[0], out int m) ? m : 0;
|
|
191
|
+
int minor = int.TryParse(parts[1], out int mi) ? mi : 0;
|
|
192
|
+
int patch = parts.Length > 2 && int.TryParse(parts[2], out int p) ? p : 0;
|
|
193
|
+
|
|
194
|
+
return (major, minor, patch);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/// <summary>
|
|
198
|
+
/// Returns true if the version change represents a major or minor version change (not just patch).
|
|
199
|
+
/// Examples:
|
|
200
|
+
/// - 1.4.5 -> 1.4.6: false (patch change)
|
|
201
|
+
/// - 1.4.5 -> 1.5.0: true (minor change)
|
|
202
|
+
/// - 1.4.5 -> 2.0.0: true (major change)
|
|
203
|
+
/// - Empty -> 1.0.0: true (first install)
|
|
204
|
+
/// </summary>
|
|
205
|
+
private static bool HasMajorOrMinorVersionChanged(string previousVersion, string currentVersion)
|
|
206
|
+
{
|
|
207
|
+
// First install or version is empty
|
|
208
|
+
if (string.IsNullOrEmpty(previousVersion))
|
|
209
|
+
{
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
var (prevMajor, prevMinor, _) = ParseVersion(previousVersion);
|
|
214
|
+
var (currMajor, currMinor, _) = ParseVersion(currentVersion);
|
|
215
|
+
|
|
216
|
+
// Major version changed
|
|
217
|
+
if (currMajor != prevMajor)
|
|
218
|
+
{
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Minor version changed
|
|
223
|
+
if (currMinor != prevMinor)
|
|
224
|
+
{
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Only patch version changed (or no change)
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
private static bool HasMajorVersionChanged(string previousVersion, string currentVersion)
|
|
233
|
+
{
|
|
234
|
+
if(string.IsNullOrEmpty(previousVersion))
|
|
235
|
+
{
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
var (prevMajor, _, _) = ParseVersion(previousVersion);
|
|
240
|
+
var (currMajor, _, _) = ParseVersion(currentVersion);
|
|
241
|
+
|
|
242
|
+
// Only major version
|
|
243
|
+
return currMajor != prevMajor;
|
|
244
|
+
}
|
|
146
245
|
}
|
|
147
246
|
}
|
|
148
247
|
|
|
@@ -563,7 +563,7 @@ namespace Hyper.Editor
|
|
|
563
563
|
isOptimal = status.hyperLoaderAtIndex0,
|
|
564
564
|
current = $"• Current: {(status.hyperLoaderAtIndex0 ? "HyperLoader at index 0" : "HyperLoader not at index 0")}",
|
|
565
565
|
recommended = "• Recommended: HyperLoader at build index 0",
|
|
566
|
-
description = "HyperLoader scene must be at build index 0 in Build Settings. This ensures proper SDK initialization before your game starts.",
|
|
566
|
+
description = "HyperLoader scene must be at build index 0 in Build Settings (from Assets/HyperSDK/HyperLoader.unity). This ensures proper SDK initialization before your game starts.",
|
|
567
567
|
priority = SettingPriority.Critical,
|
|
568
568
|
type = SettingType.HyperLoaderSceneIndex
|
|
569
569
|
};
|
|
@@ -2743,7 +2743,7 @@ namespace Hyper.Editor
|
|
|
2743
2743
|
// Property may not exist in this Unity version
|
|
2744
2744
|
}
|
|
2745
2745
|
|
|
2746
|
-
// Check if HyperLoader is at build index 0
|
|
2746
|
+
// Check if HyperLoader is at build index 0 (must be from Assets/HyperSDK/, not Packages/)
|
|
2747
2747
|
bool hyperLoaderAt0 = false;
|
|
2748
2748
|
try
|
|
2749
2749
|
{
|
|
@@ -2751,8 +2751,8 @@ namespace Hyper.Editor
|
|
|
2751
2751
|
if (scenes != null && scenes.Length > 0 && scenes[0].enabled)
|
|
2752
2752
|
{
|
|
2753
2753
|
string firstScenePath = scenes[0].path;
|
|
2754
|
-
|
|
2755
|
-
|
|
2754
|
+
// Only accept the HyperLoader scene from Assets/HyperSDK/, not from Packages/
|
|
2755
|
+
hyperLoaderAt0 = string.Equals(firstScenePath, HyperConstants.HYPER_LOADER_SCENE_PATH, StringComparison.OrdinalIgnoreCase);
|
|
2756
2756
|
}
|
|
2757
2757
|
}
|
|
2758
2758
|
catch (System.Exception)
|
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
|
|
@@ -840,7 +840,7 @@ GameObject:
|
|
|
840
840
|
m_Component:
|
|
841
841
|
- component: {fileID: 1064166296}
|
|
842
842
|
m_Layer: 0
|
|
843
|
-
m_Name:
|
|
843
|
+
m_Name: __HyperSDK_BuildMarker_639030030877789930
|
|
844
844
|
m_TagString: Untagged
|
|
845
845
|
m_Icon: {fileID: 0}
|
|
846
846
|
m_NavMeshLayer: 0
|
|
@@ -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
|
|
@@ -42,7 +42,7 @@ namespace Hyper.Internal.Managers
|
|
|
42
42
|
|
|
43
43
|
#region Public Properties (Internal API)
|
|
44
44
|
|
|
45
|
-
public int scoreSubmissionTimeout { get; private set; } =
|
|
45
|
+
public int scoreSubmissionTimeout { get; private set; } = 4;
|
|
46
46
|
public int CurrentRetryCount => _currentRetryCount;
|
|
47
47
|
public bool isSocketConnected { get; private set; }
|
|
48
48
|
public bool tutorialFetchSuccess { get; private set; }
|
|
@@ -373,6 +373,7 @@ namespace Hyper.Internal.Managers
|
|
|
373
373
|
};
|
|
374
374
|
|
|
375
375
|
string json = JsonConvert.SerializeObject(message);
|
|
376
|
+
HyperDebug.Log($"Sending game resumed message: {json}");
|
|
376
377
|
SendWebSocketMessage(json);
|
|
377
378
|
}
|
|
378
379
|
catch (Exception ex)
|
|
@@ -381,7 +382,7 @@ namespace Hyper.Internal.Managers
|
|
|
381
382
|
}
|
|
382
383
|
|
|
383
384
|
float elapsed = 0f;
|
|
384
|
-
const float timeout =
|
|
385
|
+
const float timeout = 1f;
|
|
385
386
|
|
|
386
387
|
while (!_gameResumed && elapsed < timeout)
|
|
387
388
|
{
|
|
@@ -390,7 +391,7 @@ namespace Hyper.Internal.Managers
|
|
|
390
391
|
}
|
|
391
392
|
}
|
|
392
393
|
|
|
393
|
-
yield return new WaitForSecondsRealtime(
|
|
394
|
+
yield return new WaitForSecondsRealtime(1.5f);
|
|
394
395
|
|
|
395
396
|
_sendGameResumedCoroutine = null;
|
|
396
397
|
}
|
|
@@ -529,6 +530,12 @@ namespace Hyper.Internal.Managers
|
|
|
529
530
|
_eventManager?.InvokeWebSocketScoreSubmitted(_lastScoreData);
|
|
530
531
|
}
|
|
531
532
|
|
|
533
|
+
if (_isFinalScoreSubmission)
|
|
534
|
+
{
|
|
535
|
+
_finalScoreSubmitted = true;
|
|
536
|
+
_isFinalScoreSubmission = false;
|
|
537
|
+
}
|
|
538
|
+
|
|
532
539
|
TryUpdateCSRFToken(message);
|
|
533
540
|
}
|
|
534
541
|
|
|
@@ -621,22 +628,22 @@ namespace Hyper.Internal.Managers
|
|
|
621
628
|
|
|
622
629
|
#endregion
|
|
623
630
|
|
|
624
|
-
#region Score Submission
|
|
631
|
+
#region Final Score Submission
|
|
625
632
|
|
|
626
|
-
private Coroutine
|
|
633
|
+
private Coroutine _finalScoreSubmissionCoroutine;
|
|
627
634
|
|
|
628
635
|
public void SubmitScore()
|
|
629
636
|
{
|
|
630
|
-
if (
|
|
637
|
+
if (_finalScoreSubmissionCoroutine != null)
|
|
631
638
|
{
|
|
632
639
|
HyperDebug.LogError("Score submission already in progress");
|
|
633
640
|
return;
|
|
634
641
|
}
|
|
635
642
|
|
|
636
643
|
#if UNITY_WEBGL && !UNITY_EDITOR
|
|
637
|
-
|
|
644
|
+
_finalScoreSubmissionCoroutine = StartCoroutine(FinalScoreSubmissionCoroutine());
|
|
638
645
|
#else
|
|
639
|
-
|
|
646
|
+
_finalScoreSubmissionCoroutine = StartCoroutine(FinalScoreSubmissionCoroutineDemo());
|
|
640
647
|
#endif
|
|
641
648
|
}
|
|
642
649
|
|
|
@@ -649,27 +656,34 @@ namespace Hyper.Internal.Managers
|
|
|
649
656
|
return;
|
|
650
657
|
}
|
|
651
658
|
|
|
652
|
-
if (
|
|
659
|
+
if (_finalScoreSubmissionCoroutine != null)
|
|
653
660
|
{
|
|
654
|
-
StopCoroutine(
|
|
661
|
+
StopCoroutine(_finalScoreSubmissionCoroutine);
|
|
655
662
|
}
|
|
656
663
|
|
|
657
|
-
|
|
664
|
+
_finalScoreSubmissionCoroutine = null;
|
|
658
665
|
|
|
659
666
|
#if UNITY_WEBGL && !UNITY_EDITOR
|
|
660
|
-
|
|
667
|
+
_finalScoreSubmissionCoroutine = StartCoroutine(FinalScoreSubmissionCoroutine());
|
|
661
668
|
#else
|
|
662
|
-
|
|
669
|
+
_finalScoreSubmissionCoroutine = StartCoroutine(FinalScoreSubmissionCoroutineDemo());
|
|
663
670
|
#endif
|
|
664
671
|
}
|
|
665
672
|
|
|
666
|
-
private IEnumerator
|
|
673
|
+
private IEnumerator FinalScoreSubmissionCoroutine()
|
|
667
674
|
{
|
|
668
675
|
_gameManager?.GameOverModalComponent?.Init();
|
|
669
676
|
_currentRetryCount = 0;
|
|
670
677
|
|
|
671
678
|
while (_currentRetryCount < MAX_RETRY_COUNT)
|
|
672
679
|
{
|
|
680
|
+
if (_hasSessionEnded)
|
|
681
|
+
{
|
|
682
|
+
_gameManager?.ShowRetryTimeExpiredModal();
|
|
683
|
+
_finalScoreSubmissionCoroutine = null;
|
|
684
|
+
yield break;
|
|
685
|
+
}
|
|
686
|
+
|
|
673
687
|
var finalScoreData = _dataManager?.CurrentScoreData;
|
|
674
688
|
finalScoreData.isFinal = true;
|
|
675
689
|
|
|
@@ -698,55 +712,100 @@ namespace Hyper.Internal.Managers
|
|
|
698
712
|
yield return _sendGameResumedCoroutine;
|
|
699
713
|
}
|
|
700
714
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
715
|
+
if (!isSocketConnected)
|
|
716
|
+
{
|
|
717
|
+
HyperDebug.LogError("WebSocket not connected - cannot submit final score");
|
|
718
|
+
_currentRetryCount++;
|
|
719
|
+
_gameManager?.GameOverModalComponent?.UpdateAttemptCount(_currentRetryCount, MAX_RETRY_COUNT);
|
|
704
720
|
|
|
705
|
-
|
|
721
|
+
if (_currentRetryCount < MAX_RETRY_COUNT)
|
|
722
|
+
{
|
|
723
|
+
yield return new WaitForSecondsRealtime(1f);
|
|
724
|
+
}
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
706
727
|
|
|
707
|
-
|
|
728
|
+
// Sending final score via WebSocket
|
|
729
|
+
_finalScoreSubmitted = false;
|
|
730
|
+
_isFinalScoreSubmission = true;
|
|
731
|
+
_lastSentBatch = new List<ScoreData> { finalScoreData };
|
|
732
|
+
|
|
733
|
+
bool sendFailed = false;
|
|
734
|
+
try
|
|
708
735
|
{
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
736
|
+
var message = new WebSocketScoreMessage(_cachedSessionId, _csrfToken, encryptedScoreData);
|
|
737
|
+
string json = JsonConvert.SerializeObject(message);
|
|
738
|
+
SendWebSocketMessage(json);
|
|
739
|
+
}
|
|
740
|
+
catch (Exception ex)
|
|
741
|
+
{
|
|
742
|
+
HyperDebug.LogError($"Failed to send final score via WebSocket: {ex.Message}");
|
|
743
|
+
_isFinalScoreSubmission = false;
|
|
744
|
+
sendFailed = true;
|
|
745
|
+
}
|
|
715
746
|
|
|
716
|
-
|
|
747
|
+
if (sendFailed)
|
|
748
|
+
{
|
|
749
|
+
_currentRetryCount++;
|
|
750
|
+
_gameManager?.GameOverModalComponent?.UpdateAttemptCount(_currentRetryCount, MAX_RETRY_COUNT);
|
|
717
751
|
|
|
718
|
-
if (
|
|
752
|
+
if (_currentRetryCount < MAX_RETRY_COUNT)
|
|
719
753
|
{
|
|
720
|
-
|
|
721
|
-
// TryUpdateCSRFToken(request.downloadHandler.text);
|
|
722
|
-
StopWebSocket();
|
|
723
|
-
_endGameCoroutine = null;
|
|
724
|
-
yield break;
|
|
754
|
+
yield return new WaitForSecondsRealtime(1f);
|
|
725
755
|
}
|
|
726
|
-
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// Waiting for WebSocket response
|
|
760
|
+
float elapsed = 0f;
|
|
761
|
+
float timeout = scoreSubmissionTimeout;
|
|
762
|
+
|
|
763
|
+
while (!_finalScoreSubmitted && elapsed < timeout)
|
|
764
|
+
{
|
|
765
|
+
if (_hasSessionEnded)
|
|
727
766
|
{
|
|
728
767
|
_gameManager?.ShowRetryTimeExpiredModal();
|
|
729
|
-
|
|
768
|
+
_isFinalScoreSubmission = false;
|
|
769
|
+
_finalScoreSubmissionCoroutine = null;
|
|
730
770
|
yield break;
|
|
731
771
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
_gameManager?.GameOverModalComponent?.UpdateAttemptCount(_currentRetryCount, MAX_RETRY_COUNT);
|
|
772
|
+
yield return null;
|
|
773
|
+
elapsed += Time.unscaledDeltaTime;
|
|
774
|
+
}
|
|
736
775
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
776
|
+
if (_finalScoreSubmitted)
|
|
777
|
+
{
|
|
778
|
+
_gameManager?.GameOverModalComponent?.ScoreHasBeenSubmitted();
|
|
779
|
+
StopWebSocket();
|
|
780
|
+
_finalScoreSubmissionCoroutine = null;
|
|
781
|
+
yield break;
|
|
782
|
+
}
|
|
783
|
+
else if (_hasSessionEnded)
|
|
784
|
+
{
|
|
785
|
+
_gameManager?.ShowRetryTimeExpiredModal();
|
|
786
|
+
_isFinalScoreSubmission = false;
|
|
787
|
+
_finalScoreSubmissionCoroutine = null;
|
|
788
|
+
yield break;
|
|
789
|
+
}
|
|
790
|
+
else
|
|
791
|
+
{
|
|
792
|
+
_isFinalScoreSubmission = false;
|
|
793
|
+
_currentRetryCount++;
|
|
794
|
+
_gameManager?.GameOverModalComponent?.UpdateAttemptCount(_currentRetryCount, MAX_RETRY_COUNT);
|
|
795
|
+
|
|
796
|
+
if (_currentRetryCount < MAX_RETRY_COUNT)
|
|
797
|
+
{
|
|
798
|
+
yield return new WaitForSecondsRealtime(1f);
|
|
741
799
|
}
|
|
742
800
|
}
|
|
743
801
|
}
|
|
744
802
|
|
|
803
|
+
_isFinalScoreSubmission = false;
|
|
745
804
|
_gameManager?.GameOverModalComponent?.AllAttemptsHaveFailed();
|
|
746
|
-
|
|
805
|
+
_finalScoreSubmissionCoroutine = null;
|
|
747
806
|
}
|
|
748
807
|
|
|
749
|
-
private IEnumerator
|
|
808
|
+
private IEnumerator FinalScoreSubmissionCoroutineDemo()
|
|
750
809
|
{
|
|
751
810
|
if (_dataManager == null) _dataManager = HyperRuntime.DataManager;
|
|
752
811
|
if (_eventManager == null) _eventManager = HyperRuntime.EventManager;
|
|
@@ -761,7 +820,7 @@ namespace Hyper.Internal.Managers
|
|
|
761
820
|
|
|
762
821
|
_gameManager.GameOverModalComponent.ScoreHasBeenSubmitted();
|
|
763
822
|
StopWebSocket();
|
|
764
|
-
|
|
823
|
+
_finalScoreSubmissionCoroutine = null;
|
|
765
824
|
}
|
|
766
825
|
|
|
767
826
|
#endregion
|
|
@@ -772,6 +831,8 @@ namespace Hyper.Internal.Managers
|
|
|
772
831
|
private List<ScoreData> _lastSentBatch = new List<ScoreData>();
|
|
773
832
|
private ScoreData _lastScoreData;
|
|
774
833
|
private readonly WaitForSeconds _scoreSendInterval = new WaitForSeconds(1f);
|
|
834
|
+
private bool _isFinalScoreSubmission;
|
|
835
|
+
private bool _finalScoreSubmitted;
|
|
775
836
|
|
|
776
837
|
public void StartSendingScores()
|
|
777
838
|
{
|
|
@@ -45,6 +45,8 @@ namespace Hyper.Internal.Managers
|
|
|
45
45
|
internal event Action OnTutorialFetchFailed;
|
|
46
46
|
internal event Action OnTutorialDoesNotExist;
|
|
47
47
|
internal event Action<ScoreData> OnLastSubmittedScoreReceived;
|
|
48
|
+
internal event Action OnTimeScaleFrozen; // Fired when Time.timeScale becomes 0
|
|
49
|
+
internal event Action OnTimeScaleResumed; // Fired when Time.timeScale becomes 1 (from any value)
|
|
48
50
|
|
|
49
51
|
#endregion
|
|
50
52
|
|
|
@@ -68,6 +70,8 @@ namespace Hyper.Internal.Managers
|
|
|
68
70
|
internal void InvokeTutorialFetchFailedEvent() => OnTutorialFetchFailed?.Invoke();
|
|
69
71
|
internal void InvokeTutorialNotExistsEvent() => OnTutorialDoesNotExist?.Invoke();
|
|
70
72
|
internal void InvokeWebSocketScoreSubmitted(ScoreData scoreData) => OnLastSubmittedScoreReceived?.Invoke(scoreData);
|
|
73
|
+
internal void InvokeTimeScaleFrozenEvent() => OnTimeScaleFrozen?.Invoke();
|
|
74
|
+
internal void InvokeTimeScaleResumedEvent() => OnTimeScaleResumed?.Invoke();
|
|
71
75
|
|
|
72
76
|
#endregion
|
|
73
77
|
}
|
|
@@ -158,12 +158,6 @@ namespace Hyper.Internal.Managers
|
|
|
158
158
|
{
|
|
159
159
|
if (!_hasGameStarted || _isPaused || _hasGameEnded) return;
|
|
160
160
|
|
|
161
|
-
if (_backendManager.isSocketConnected)
|
|
162
|
-
{
|
|
163
|
-
_dataManager.StopCapturingScores();
|
|
164
|
-
_backendManager.StopSendingScores();
|
|
165
|
-
}
|
|
166
|
-
|
|
167
161
|
_isPaused = true;
|
|
168
162
|
_isFrozenBeforePause = Time.timeScale == 0;
|
|
169
163
|
Time.timeScale = 0;
|
|
@@ -177,11 +171,6 @@ namespace Hyper.Internal.Managers
|
|
|
177
171
|
|
|
178
172
|
internal void ResumeGame()
|
|
179
173
|
{
|
|
180
|
-
if (_backendManager.isSocketConnected)
|
|
181
|
-
{
|
|
182
|
-
_backendManager.SendGameResumed();
|
|
183
|
-
}
|
|
184
|
-
|
|
185
174
|
_isPaused = false;
|
|
186
175
|
|
|
187
176
|
if (!_isFrozenBeforePause)
|
|
@@ -212,9 +201,37 @@ namespace Hyper.Internal.Managers
|
|
|
212
201
|
{
|
|
213
202
|
PauseGame();
|
|
214
203
|
}
|
|
215
|
-
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
void Update()
|
|
207
|
+
{
|
|
208
|
+
float currentTimeScale = Time.timeScale;
|
|
209
|
+
if (currentTimeScale != _previousTimeScale)
|
|
216
210
|
{
|
|
217
|
-
//
|
|
211
|
+
// detect intentional game-freeze states
|
|
212
|
+
if (currentTimeScale == 0f && _previousTimeScale != 0f)
|
|
213
|
+
{
|
|
214
|
+
_eventManager.InvokeTimeScaleFrozenEvent();
|
|
215
|
+
HyperDebug.Log("Time scale frozen event invoked");
|
|
216
|
+
|
|
217
|
+
if (_backendManager.isSocketConnected)
|
|
218
|
+
{
|
|
219
|
+
_dataManager.StopCapturingScores();
|
|
220
|
+
_backendManager.StopSendingScores();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
else if (currentTimeScale == 1f && _previousTimeScale != 1f)
|
|
224
|
+
{
|
|
225
|
+
_eventManager.InvokeTimeScaleResumedEvent();
|
|
226
|
+
HyperDebug.Log("Time scale resumed event invoked");
|
|
227
|
+
|
|
228
|
+
if (_backendManager.isSocketConnected && !_hasGameEnded && _hasGameStarted)
|
|
229
|
+
{
|
|
230
|
+
_backendManager.SendGameResumed();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
_previousTimeScale = currentTimeScale;
|
|
218
235
|
}
|
|
219
236
|
}
|
|
220
237
|
|
|
@@ -459,6 +476,8 @@ namespace Hyper.Internal.Managers
|
|
|
459
476
|
|
|
460
477
|
internal void ShowGameOverModal()
|
|
461
478
|
{
|
|
479
|
+
HidePauseModals();
|
|
480
|
+
|
|
462
481
|
if (IsBattleMode)
|
|
463
482
|
{
|
|
464
483
|
EnsureBattleGameOverModal();
|
|
@@ -469,7 +488,7 @@ namespace Hyper.Internal.Managers
|
|
|
469
488
|
EnsurePracticeGameOverModal();
|
|
470
489
|
_practiceGameOverModal.SetActive(true);
|
|
471
490
|
}
|
|
472
|
-
|
|
491
|
+
|
|
473
492
|
SetBlockerActive(true);
|
|
474
493
|
}
|
|
475
494
|
|
|
@@ -558,6 +577,7 @@ namespace Hyper.Internal.Managers
|
|
|
558
577
|
private bool _hasGameEnded;
|
|
559
578
|
private bool _isFrozenBeforePause;
|
|
560
579
|
private bool _isPortrait;
|
|
580
|
+
private float _previousTimeScale = 1f;
|
|
561
581
|
|
|
562
582
|
#endregion
|
|
563
583
|
|
|
@@ -769,6 +789,7 @@ namespace Hyper.Internal.Managers
|
|
|
769
789
|
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
|
770
790
|
{
|
|
771
791
|
Time.timeScale = 1;
|
|
792
|
+
_previousTimeScale = 1f; // Sync tracking on scene load
|
|
772
793
|
_dataManager.ConfigurePlayerSoundSetting();
|
|
773
794
|
|
|
774
795
|
string menuSceneName = HyperRuntime.GameContent.IsPracticeMenu ?
|
|
@@ -808,6 +829,7 @@ namespace Hyper.Internal.Managers
|
|
|
808
829
|
_hasGameEnded = false;
|
|
809
830
|
_isPaused = false;
|
|
810
831
|
_isFrozenBeforePause = false;
|
|
832
|
+
_previousTimeScale = Time.timeScale; // Sync with actual time scale on scene load
|
|
811
833
|
}
|
|
812
834
|
|
|
813
835
|
private void InitializeSceneUI()
|
|
@@ -83,7 +83,7 @@ namespace Hyper.Internal
|
|
|
83
83
|
|
|
84
84
|
// Animate to original position
|
|
85
85
|
rectTransform.DOAnchorPosY(originalAnchoredPosition.y, 0.5f)
|
|
86
|
-
.SetEase(
|
|
86
|
+
.SetEase(HyperTween.Ease.OutQuad)
|
|
87
87
|
.SetUpdate(true);
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -103,7 +103,7 @@ namespace Hyper.Internal
|
|
|
103
103
|
|
|
104
104
|
// Animate to off-screen position
|
|
105
105
|
rectTransform.DOAnchorPosY(offScreenY, 0.5f)
|
|
106
|
-
.SetEase(
|
|
106
|
+
.SetEase(HyperTween.Ease.InQuad)
|
|
107
107
|
.SetUpdate(true)
|
|
108
108
|
.OnComplete(() =>
|
|
109
109
|
{
|