app.hypergames.hypersdk 1.11.3 → 1.11.4

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 CHANGED
@@ -1,3 +1,11 @@
1
+ ## [1.11.4](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.3...v1.11.4) (2026-10-16)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **sdk:** keep Play Again overlay until scene handoff ([baf5397](https://github.com/mvmhyper/hyper-sdk/commit/baf5397fa8f397cc06223f6943abf9baae114035))
7
+ * **sdk:** remove tutorial modal when no tutorial exists ([e6c4f6a](https://github.com/mvmhyper/hyper-sdk/commit/e6c4f6a08e914c2e4b7cdd1488c71b8f2ff05a5c))
8
+
1
9
  ## [1.11.3](https://github.com/mvmhyper/hyper-sdk/compare/v1.11.2...v1.11.3) (2026-10-15)
2
10
 
3
11
 
@@ -120,6 +120,7 @@ namespace Hyper.Internal
120
120
  }
121
121
  else
122
122
  {
123
+ _gameManager?.PreserveUIForSceneRestart();
123
124
  ClearAllDontDestroyOnLoadObjects();
124
125
  SceneManager.LoadScene("HyperLoader");
125
126
  }
@@ -215,6 +216,7 @@ namespace Hyper.Internal
215
216
  }
216
217
  else
217
218
  {
219
+ _gameManager?.PreserveUIForSceneRestart();
218
220
  ClearAllDontDestroyOnLoadObjects();
219
221
  SceneManager.LoadScene("HyperLoader");
220
222
  }
@@ -267,6 +269,9 @@ namespace Hyper.Internal
267
269
  /// </summary>
268
270
  private static IEnumerator RestartSessionCoroutine()
269
271
  {
272
+ _gameManager?.PreserveUIForSceneRestart();
273
+ // Render the disabled buttons and spinner before scene cleanup starts.
274
+ yield return null;
270
275
  yield return UnloadAllScenesCoroutine();
271
276
 
272
277
  Clear();
@@ -74,6 +74,20 @@ namespace Hyper.Internal.Managers
74
74
  EndGame();
75
75
  }
76
76
 
77
+ internal void PreserveUIForSceneRestart()
78
+ {
79
+ if (_hyperCanvasObject == null) return;
80
+
81
+ // Keep the modal and shade until the game scene unloads, then let the
82
+ // scene destroy them before HyperLoader presents its own loading UI.
83
+ Scene activeScene = SceneManager.GetActiveScene();
84
+ if (_hyperCanvasObject.scene != activeScene)
85
+ {
86
+ SceneManager.MoveGameObjectToScene(_hyperCanvasObject, activeScene);
87
+ }
88
+ _hyperCanvasObject = null;
89
+ }
90
+
77
91
  internal void Cleanup()
78
92
  {
79
93
  StopAllCoroutines();
@@ -637,6 +651,8 @@ namespace Hyper.Internal.Managers
637
651
 
638
652
  internal void AddTutorialModal(bool showModal = false)
639
653
  {
654
+ if (_backendManager.tutorialDoesNotExist) return;
655
+
640
656
  bool isPortrait = ResolvePortraitFlag();
641
657
  var activeModal = EnsureTutorialModal(isPortrait);
642
658
  _tutorialModalComponent = activeModal.GetComponent<TutorialModal>();
@@ -23,11 +23,15 @@ namespace Hyper.Internal
23
23
  [SerializeField]
24
24
  private GameObject loadingBar;
25
25
  [SerializeField]
26
- private GameObject loadingCircle;
26
+ [UnityEngine.Serialization.FormerlySerializedAs("loadingCircle")]
27
+ private GameObject exitLoadingCircle;
28
+ [SerializeField]
29
+ private GameObject playAgainLoadingCircle;
27
30
  private Slider loadingBarSlider;
28
31
  Coroutine sliderCoroutine;
29
32
 
30
33
  private GameManager _gameManager;
34
+ private bool _restartRequested;
31
35
 
32
36
  private void Awake()
33
37
  {
@@ -37,8 +41,10 @@ namespace Hyper.Internal
37
41
  if (loadingBarSlider != null)
38
42
  loadingBarSlider.value = 0.075f;
39
43
 
40
- if (loadingCircle != null)
41
- loadingCircle.SetActive(false);
44
+ if (exitLoadingCircle != null)
45
+ exitLoadingCircle.SetActive(false);
46
+
47
+ SetPlayAgainLoading(false);
42
48
 
43
49
  _gameManager = HyperRuntime.GameManager;
44
50
 
@@ -103,6 +109,15 @@ namespace Hyper.Internal
103
109
 
104
110
  private void OnEnable()
105
111
  {
112
+ _restartRequested = false;
113
+ if (buttonHolder != null)
114
+ {
115
+ buttonHolder.interactable = true;
116
+ buttonHolder.alpha = 1f;
117
+ }
118
+ if (exitLoadingCircle != null) exitLoadingCircle.SetActive(false);
119
+ SetPlayAgainLoading(false);
120
+
106
121
  currentScore.text = HyperRuntime.DataManager.CurrentScore.ToString("N0");
107
122
  bestScore.text = HyperRuntime.DataManager.GetBestScore().ToString("N0");
108
123
  }
@@ -171,15 +186,40 @@ namespace Hyper.Internal
171
186
  buttonHolder.interactable = false;
172
187
  buttonHolder.alpha = 0.6f;
173
188
 
174
- // Enable loading circle for exit action
175
- loadingCircle.SetActive(true);
189
+ // Enable only the exit button's loading circle.
190
+ SetPlayAgainLoading(false);
191
+ exitLoadingCircle.SetActive(true);
176
192
 
177
193
  HyperRuntime.DataManager.MuteAudioForGameSessionEnd();
178
194
  HyperRuntime.BackendManager.LogEvent(ConsoleEventType.PracticeGameEnd);
179
195
  }
180
196
 
197
+ private void SetPlayAgainLoading(bool isLoading)
198
+ {
199
+ if (playAgainLoadingCircle == null) return;
200
+
201
+ playAgainLoadingCircle.SetActive(isLoading);
202
+ Transform button = playAgainLoadingCircle.transform.parent;
203
+ if (button != null)
204
+ {
205
+ TMP_Text label = button.GetComponentInChildren<TMP_Text>(true);
206
+ if (label != null) label.gameObject.SetActive(!isLoading);
207
+ }
208
+ }
209
+
181
210
  public void PlayAgain()
182
211
  {
212
+ if (_restartRequested) return;
213
+ _restartRequested = true;
214
+
215
+ if (buttonHolder != null)
216
+ {
217
+ buttonHolder.interactable = false;
218
+ buttonHolder.alpha = 0.6f;
219
+ }
220
+ if (exitLoadingCircle != null) exitLoadingCircle.SetActive(false);
221
+ SetPlayAgainLoading(true);
222
+
183
223
  HyperRuntime.RestartSession();
184
224
  }
185
225
 
@@ -26,7 +26,6 @@ namespace Hyper.Internal
26
26
  rectTransform = GetComponent<RectTransform>();
27
27
 
28
28
  _eventManager.OnTutorialLoadingComplete += HandleTutorialLoadingComplete;
29
- _eventManager.OnTutorialDoesNotExist += HandleTutorialFailed;
30
29
  _eventManager.OnTutorialFetchFailed += HandleTutorialFailed;
31
30
  }
32
31
 
@@ -48,7 +47,6 @@ namespace Hyper.Internal
48
47
  {
49
48
  _eventManager.OnTutorialLoadingComplete -= HandleTutorialLoadingComplete;
50
49
  _eventManager.OnTutorialFetchFailed -= HandleTutorialFailed;
51
- _eventManager.OnTutorialDoesNotExist -= HandleTutorialFailed;
52
50
  }
53
51
  }
54
52
 
@@ -108,6 +108,7 @@ namespace Hyper.Internal
108
108
 
109
109
  _eventManager.OnTutorialResourcesReferenced += ShowTutorialBasedOnType;
110
110
  _eventManager.OnTutorialLoadingComplete += HandleTutorialLoadingComplete;
111
+ _eventManager.OnTutorialDoesNotExist += HandleTutorialDoesNotExist;
111
112
  }
112
113
 
113
114
  void OnEnable()
@@ -1133,12 +1134,19 @@ namespace Hyper.Internal
1133
1134
  }
1134
1135
  }
1135
1136
 
1137
+ private void HandleTutorialDoesNotExist()
1138
+ {
1139
+ gameObject.SetActive(false);
1140
+ Destroy(gameObject);
1141
+ }
1142
+
1136
1143
  private void OnDestroy()
1137
1144
  {
1138
1145
  if (_eventManager == null) return;
1139
1146
 
1140
1147
  _eventManager.OnTutorialResourcesReferenced -= ShowTutorialBasedOnType;
1141
1148
  _eventManager.OnTutorialLoadingComplete -= HandleTutorialLoadingComplete;
1149
+ _eventManager.OnTutorialDoesNotExist -= HandleTutorialDoesNotExist;
1142
1150
  }
1143
1151
 
1144
1152
  private void DisplayImage(int index)
@@ -254,7 +254,7 @@ MonoBehaviour:
254
254
  scoreSubmissionText: {fileID: 4314462782470164325}
255
255
  buttonHolder: {fileID: 0}
256
256
  loadingBar: {fileID: 7071240272076755227}
257
- loadingCircle: {fileID: 0}
257
+ exitLoadingCircle: {fileID: 0}
258
258
  --- !u!114 &7863664679590643807
259
259
  MonoBehaviour:
260
260
  m_ObjectHideFlags: 0
@@ -193,7 +193,8 @@ MonoBehaviour:
193
193
  scoreSubmissionText: {fileID: 0}
194
194
  buttonHolder: {fileID: 1454075834828744570}
195
195
  loadingBar: {fileID: 0}
196
- loadingCircle: {fileID: 4090140612718772822}
196
+ exitLoadingCircle: {fileID: 4090140612718772822}
197
+ playAgainLoadingCircle: {fileID: 700000000000000001}
197
198
  --- !u!114 &2358495542796786633
198
199
  MonoBehaviour:
199
200
  m_ObjectHideFlags: 0
@@ -1261,7 +1262,10 @@ PrefabInstance:
1261
1262
  objectReference: {fileID: 0}
1262
1263
  m_RemovedComponents: []
1263
1264
  m_RemovedGameObjects: []
1264
- m_AddedGameObjects: []
1265
+ m_AddedGameObjects:
1266
+ - targetCorrespondingSourceObject: {fileID: 446956918503945639, guid: 7196382af023e984dbe20e6bcdc9933c, type: 3}
1267
+ insertIndex: -1
1268
+ addedObject: {fileID: 700000000000000002}
1265
1269
  m_AddedComponents: []
1266
1270
  m_SourcePrefab: {fileID: 100100000, guid: 7196382af023e984dbe20e6bcdc9933c, type: 3}
1267
1271
  --- !u!224 &4567816188166193046 stripped
@@ -1455,3 +1459,114 @@ RectTransform:
1455
1459
  m_CorrespondingSourceObject: {fileID: 446956918503945639, guid: 51f1fa5ca88e94a4f8c654ed76e16c02, type: 3}
1456
1460
  m_PrefabInstance: {fileID: 6772588356203191674}
1457
1461
  m_PrefabAsset: {fileID: 0}
1462
+ --- !u!1 &700000000000000001
1463
+ GameObject:
1464
+ m_ObjectHideFlags: 0
1465
+ m_CorrespondingSourceObject: {fileID: 0}
1466
+ m_PrefabInstance: {fileID: 0}
1467
+ m_PrefabAsset: {fileID: 0}
1468
+ serializedVersion: 6
1469
+ m_Component:
1470
+ - component: {fileID: 700000000000000002}
1471
+ - component: {fileID: 700000000000000003}
1472
+ - component: {fileID: 700000000000000004}
1473
+ - component: {fileID: 700000000000000005}
1474
+ - component: {fileID: 700000000000000006}
1475
+ m_Layer: 5
1476
+ m_Name: Play Again Loader
1477
+ m_TagString: Untagged
1478
+ m_Icon: {fileID: 0}
1479
+ m_NavMeshLayer: 0
1480
+ m_StaticEditorFlags: 0
1481
+ m_IsActive: 0
1482
+ --- !u!224 &700000000000000002
1483
+ RectTransform:
1484
+ m_ObjectHideFlags: 0
1485
+ m_CorrespondingSourceObject: {fileID: 0}
1486
+ m_PrefabInstance: {fileID: 0}
1487
+ m_PrefabAsset: {fileID: 0}
1488
+ m_GameObject: {fileID: 700000000000000001}
1489
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
1490
+ m_LocalPosition: {x: 0, y: 0, z: 0}
1491
+ m_LocalScale: {x: 0.75, y: 0.75, z: 0.75}
1492
+ m_ConstrainProportionsScale: 1
1493
+ m_Children: []
1494
+ m_Father: {fileID: 4567816188166193046}
1495
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
1496
+ m_AnchorMin: {x: 0.5, y: 0.5}
1497
+ m_AnchorMax: {x: 0.5, y: 0.5}
1498
+ m_AnchoredPosition: {x: 0, y: 14}
1499
+ m_SizeDelta: {x: 100, y: 100}
1500
+ m_Pivot: {x: 0.5, y: 0.5}
1501
+ --- !u!222 &700000000000000003
1502
+ CanvasRenderer:
1503
+ m_ObjectHideFlags: 0
1504
+ m_CorrespondingSourceObject: {fileID: 0}
1505
+ m_PrefabInstance: {fileID: 0}
1506
+ m_PrefabAsset: {fileID: 0}
1507
+ m_GameObject: {fileID: 700000000000000001}
1508
+ m_CullTransparentMesh: 1
1509
+ --- !u!114 &700000000000000004
1510
+ MonoBehaviour:
1511
+ m_ObjectHideFlags: 0
1512
+ m_CorrespondingSourceObject: {fileID: 0}
1513
+ m_PrefabInstance: {fileID: 0}
1514
+ m_PrefabAsset: {fileID: 0}
1515
+ m_GameObject: {fileID: 700000000000000001}
1516
+ m_Enabled: 1
1517
+ m_EditorHideFlags: 0
1518
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
1519
+ m_Name:
1520
+ m_EditorClassIdentifier:
1521
+ m_Material: {fileID: 0}
1522
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
1523
+ m_RaycastTarget: 1
1524
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
1525
+ m_Maskable: 1
1526
+ m_OnCullStateChanged:
1527
+ m_PersistentCalls:
1528
+ m_Calls: []
1529
+ m_Sprite: {fileID: 21300000, guid: 5c57961c662dfdd46a321974424c3f15, type: 3}
1530
+ m_Type: 0
1531
+ m_PreserveAspect: 1
1532
+ m_FillCenter: 1
1533
+ m_FillMethod: 4
1534
+ m_FillAmount: 1
1535
+ m_FillClockwise: 1
1536
+ m_FillOrigin: 0
1537
+ m_UseSpriteMesh: 0
1538
+ m_PixelsPerUnitMultiplier: 1
1539
+ --- !u!95 &700000000000000005
1540
+ Animator:
1541
+ serializedVersion: 7
1542
+ m_ObjectHideFlags: 0
1543
+ m_CorrespondingSourceObject: {fileID: 0}
1544
+ m_PrefabInstance: {fileID: 0}
1545
+ m_PrefabAsset: {fileID: 0}
1546
+ m_GameObject: {fileID: 700000000000000001}
1547
+ m_Enabled: 1
1548
+ m_Avatar: {fileID: 0}
1549
+ m_Controller: {fileID: 9100000, guid: 3b038a3cf997e10408e5ae13866f375e, type: 2}
1550
+ m_CullingMode: 0
1551
+ m_UpdateMode: 0
1552
+ m_ApplyRootMotion: 0
1553
+ m_LinearVelocityBlending: 0
1554
+ m_StabilizeFeet: 0
1555
+ m_AnimatePhysics: 0
1556
+ m_WarningMessage:
1557
+ m_HasTransformHierarchy: 1
1558
+ m_AllowConstantClipSamplingOptimization: 1
1559
+ m_KeepAnimatorStateOnDisable: 0
1560
+ m_WriteDefaultValuesOnDisable: 0
1561
+ --- !u!225 &700000000000000006
1562
+ CanvasGroup:
1563
+ m_ObjectHideFlags: 0
1564
+ m_CorrespondingSourceObject: {fileID: 0}
1565
+ m_PrefabInstance: {fileID: 0}
1566
+ m_PrefabAsset: {fileID: 0}
1567
+ m_GameObject: {fileID: 700000000000000001}
1568
+ m_Enabled: 1
1569
+ m_Alpha: 1
1570
+ m_Interactable: 1
1571
+ m_BlocksRaycasts: 1
1572
+ m_IgnoreParentGroups: 1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "app.hypergames.hypersdk",
3
- "version": "1.11.3",
3
+ "version": "1.11.4",
4
4
  "displayName": "HyperSDK",
5
5
  "description": "Official Unity SDK for Hyper: multiplayer battles, leaderboards, deterministic RNG, session management, tutorials, and WebGL optimizations for production-ready games.",
6
6
  "unity": "6000.0",