app.hypergames.hypersdk 1.2.1 → 1.3.0

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,17 @@
1
+ # [1.3.0](https://github.com/mvmhyper/hyper-sdk/compare/v1.2.2...v1.3.0) (2025-11-26)
2
+
3
+
4
+ ### Features
5
+
6
+ * Soft restart lifecycle management and build index automation ([4426307](https://github.com/mvmhyper/hyper-sdk/commit/44263076306a4d0ec1b84a053123f34a164450de))
7
+
8
+ ## [1.2.2](https://github.com/mvmhyper/hyper-sdk/compare/v1.2.1...v1.2.2) (2025-11-26)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * auto-manage HyperLoader scene and constants ([050567a](https://github.com/mvmhyper/hyper-sdk/commit/050567a44c0d78b4eed9ae31b19ba1fcbd8a986f))
14
+
1
15
  ## [1.2.1](https://github.com/mvmhyper/hyper-sdk/compare/v1.2.0...v1.2.1) (2025-11-26)
2
16
 
3
17
 
@@ -4,6 +4,7 @@ using UnityEditor;
4
4
  using System;
5
5
  using System.Collections.Generic;
6
6
  using System.Globalization;
7
+ using System.IO;
7
8
  using System.Linq;
8
9
  using UnityEditor.Build;
9
10
  using UnityEditor.Build.Reporting;
@@ -1010,61 +1011,25 @@ namespace Hyper.Editor
1010
1011
  break;
1011
1012
 
1012
1013
  case SettingType.HyperLoaderSceneIndex:
1013
- try
1014
1014
  {
1015
- var scenes = new List<EditorBuildSettingsScene>(EditorBuildSettings.scenes);
1016
- int hyperLoaderIndex = -1;
1017
-
1018
- for (int i = 0; i < scenes.Count; i++)
1015
+ if (TryEnsureSceneAtIndex(HyperConstants.HYPER_LOADER_SCENE_PATH, 0, out var sceneError))
1019
1016
  {
1020
- if (scenes[i].path.Contains("HyperLoader") ||
1021
- scenes[i].path.EndsWith("HyperLoader.unity", System.StringComparison.OrdinalIgnoreCase))
1022
- {
1023
- hyperLoaderIndex = i;
1024
- break;
1025
- }
1017
+ if (IsSDKDeveloper()) HyperDebug.LogSuccess("Applied: HyperLoader scene moved to build index 0");
1026
1018
  }
1027
-
1028
- if (hyperLoaderIndex == -1)
1019
+ else
1029
1020
  {
1030
1021
  EditorUtility.DisplayDialog(
1031
1022
  "HyperLoader Scene Not Found",
1032
- "HyperLoader scene not found in Build Settings.\n\n" +
1033
- "Please add it manually:\n" +
1034
- "1. File > Build Settings\n" +
1035
- "2. Add Open Scenes or drag HyperLoader.unity\n" +
1036
- "3. Move it to index 0",
1023
+ $"Could not locate the HyperLoader scene at:\n{HyperConstants.HYPER_LOADER_SCENE_PATH}\n\n" +
1024
+ "Please ensure the SDK is installed and the scene exists, then run this fix again.",
1037
1025
  "OK"
1038
1026
  );
1039
- HyperDebug.LogWarning("HyperLoader scene not found in Build Settings");
1040
- }
1041
- else if (hyperLoaderIndex == 0)
1042
- {
1043
- if (IsSDKDeveloper()) HyperDebug.Log("HyperLoader is already at index 0");
1044
- }
1045
- else
1046
- {
1047
- var hyperLoaderScene = scenes[hyperLoaderIndex];
1048
- scenes.RemoveAt(hyperLoaderIndex);
1049
- scenes.Insert(0, hyperLoaderScene);
1050
- hyperLoaderScene.enabled = true;
1051
-
1052
- EditorBuildSettings.scenes = scenes.ToArray();
1053
- if (IsSDKDeveloper()) HyperDebug.LogSuccess($"Applied: Moved HyperLoader scene to build index 0 (was at index {hyperLoaderIndex})");
1027
+ if (!string.IsNullOrEmpty(sceneError))
1028
+ {
1029
+ HyperDebug.LogWarning(sceneError);
1030
+ }
1054
1031
  }
1055
1032
  }
1056
- catch (System.Exception e)
1057
- {
1058
- EditorUtility.DisplayDialog(
1059
- "Build Settings Error",
1060
- "Could not automatically move HyperLoader to index 0.\n\n" +
1061
- "Please manually set it in:\n" +
1062
- "File > Build Settings\n\n" +
1063
- "Move HyperLoader scene to index 0",
1064
- "OK"
1065
- );
1066
- HyperDebug.LogWarning($"Could not move HyperLoader scene: {e.Message}");
1067
- }
1068
1033
  break;
1069
1034
 
1070
1035
  case SettingType.ColorSpace:
@@ -1466,6 +1431,39 @@ namespace Hyper.Editor
1466
1431
  return $"{len:0.##} {sizes[order]}";
1467
1432
  }
1468
1433
 
1434
+ #endregion
1435
+
1436
+ #region Build Settings Helpers
1437
+
1438
+ private static bool TryEnsureSceneAtIndex(string scenePath, int targetIndex, out string errorMessage)
1439
+ {
1440
+ errorMessage = null;
1441
+
1442
+ if (string.IsNullOrEmpty(scenePath))
1443
+ {
1444
+ errorMessage = "Scene path is null or empty.";
1445
+ return false;
1446
+ }
1447
+
1448
+ if (!File.Exists(scenePath))
1449
+ {
1450
+ errorMessage = $"Scene not found at path: {scenePath}";
1451
+ return false;
1452
+ }
1453
+
1454
+ var scenes = new List<EditorBuildSettingsScene>(EditorBuildSettings.scenes);
1455
+ scenes.RemoveAll(s => string.Equals(s.path, scenePath, StringComparison.OrdinalIgnoreCase));
1456
+
1457
+ targetIndex = Mathf.Clamp(targetIndex, 0, scenes.Count);
1458
+
1459
+ var newScene = new EditorBuildSettingsScene(scenePath, true);
1460
+ scenes.Insert(targetIndex, newScene);
1461
+
1462
+ EditorBuildSettings.scenes = scenes.ToArray();
1463
+ return true;
1464
+ }
1465
+
1466
+
1469
1467
  private static string FormatBuildTime(System.DateTime buildTime)
1470
1468
  {
1471
1469
  System.TimeSpan timeSince = System.DateTime.Now - buildTime;
@@ -2168,7 +2166,7 @@ namespace Hyper.Editor
2168
2166
  /// </summary>
2169
2167
  private static void ForceAssetRepack()
2170
2168
  {
2171
- const string hyperLoaderScenePath = "Assets/HyperSDK/HyperLoader.unity";
2169
+ const string hyperLoaderScenePath = HyperConstants.HYPER_LOADER_SCENE_PATH;
2172
2170
  const string markerPrefix = "__HyperSDK_BuildMarker";
2173
2171
  if (IsSDKDeveloper()) HyperDebug.Log("ForceAssetRepack() called");
2174
2172
 
@@ -2,6 +2,7 @@
2
2
  using UnityEditor;
3
3
  using UnityEngine;
4
4
  using Hyper.Shared;
5
+ using Hyper.Internal;
5
6
 
6
7
  namespace Hyper.Editor
7
8
  {
@@ -58,6 +59,9 @@ namespace Hyper.Editor
58
59
  guidProperty.stringValue = newGUID;
59
60
  pathProperty.stringValue = newPath;
60
61
  nameProperty.stringValue = newName;
62
+
63
+ // Automatically add scene to build index if not already present
64
+ EnsureSceneInBuildIndex(newPath, newName);
61
65
  }
62
66
  else
63
67
  {
@@ -69,6 +73,39 @@ namespace Hyper.Editor
69
73
 
70
74
  EditorGUI.EndProperty();
71
75
  }
76
+
77
+ /// <summary>
78
+ /// Ensures the scene is added to the build index if it's not already present.
79
+ /// </summary>
80
+ private void EnsureSceneInBuildIndex(string scenePath, string sceneName)
81
+ {
82
+ if (string.IsNullOrEmpty(scenePath))
83
+ return;
84
+
85
+ // Check if scene is already in build index
86
+ var buildScenes = EditorBuildSettings.scenes;
87
+ bool isInBuildIndex = false;
88
+
89
+ for (int i = 0; i < buildScenes.Length; i++)
90
+ {
91
+ if (buildScenes[i].path == scenePath)
92
+ {
93
+ isInBuildIndex = true;
94
+ break;
95
+ }
96
+ }
97
+
98
+ // Add to build index if not present
99
+ if (!isInBuildIndex)
100
+ {
101
+ var newScenes = new EditorBuildSettingsScene[buildScenes.Length + 1];
102
+ System.Array.Copy(buildScenes, newScenes, buildScenes.Length);
103
+ newScenes[buildScenes.Length] = new EditorBuildSettingsScene(scenePath, true);
104
+ EditorBuildSettings.scenes = newScenes;
105
+
106
+ HyperDebug.LogSuccess($"Automatically added scene '{sceneName}' to Build Settings.");
107
+ }
108
+ }
72
109
  }
73
110
  }
74
111
  #endif
package/HyperLoader.unity CHANGED
@@ -305,7 +305,7 @@ RectTransform:
305
305
  m_AnchorMin: {x: 0, y: 1}
306
306
  m_AnchorMax: {x: 0, y: 1}
307
307
  m_AnchoredPosition: {x: 489.20746, y: -280.1698}
308
- m_SizeDelta: {x: 1044.9, y: 239.347}
308
+ m_SizeDelta: {x: 0, y: 239.347}
309
309
  m_Pivot: {x: 0.5, y: 0.5}
310
310
  --- !u!114 &751153944
311
311
  MonoBehaviour:
@@ -1840,7 +1840,7 @@ MonoBehaviour:
1840
1840
  m_MinValue: 0
1841
1841
  m_MaxValue: 1
1842
1842
  m_WholeNumbers: 0
1843
- m_Value: 0.227
1843
+ m_Value: 0.065
1844
1844
  m_OnValueChanged:
1845
1845
  m_PersistentCalls:
1846
1846
  m_Calls: []
@@ -46,6 +46,11 @@ namespace Hyper.Internal
46
46
 
47
47
  private void Awake()
48
48
  {
49
+ // Entering a freshly loaded HyperLoader scene always ends any previous
50
+ // soft-restart window. From this point onward, teardown code should treat
51
+ // object destruction as part of a normal lifecycle again.
52
+ HyperRuntime.IsSoftRestarting = false;
53
+
49
54
  HyperRuntime.Clear();
50
55
 
51
56
  InitializeComponents();
@@ -1,5 +1,6 @@
1
1
  using System;
2
2
  using UnityEngine;
3
+ using UnityEngine.SceneManagement;
3
4
  using Hyper.Internal.Managers;
4
5
 
5
6
  namespace Hyper.Internal
@@ -15,6 +16,7 @@ namespace Hyper.Internal
15
16
  private static GameObject _singletonObject;
16
17
 
17
18
  private static bool _isInitialized;
19
+ private static bool _isSoftRestarting;
18
20
  private static HyperSDKSettings _settings;
19
21
  private static HyperGameContentConfig _gameContent;
20
22
  private static GameManager _gameManager;
@@ -24,6 +26,11 @@ namespace Hyper.Internal
24
26
  private static TimerManager _timerManager;
25
27
 
26
28
  internal static bool IsInitialized => _isInitialized;
29
+ internal static bool IsSoftRestarting
30
+ {
31
+ get => _isSoftRestarting;
32
+ set => _isSoftRestarting = value;
33
+ }
27
34
  internal static HyperSDKSettings Settings => _settings;
28
35
  internal static HyperGameContentConfig GameContent => _gameContent;
29
36
  internal static GameManager GameManager => _gameManager;
@@ -32,6 +39,20 @@ namespace Hyper.Internal
32
39
  internal static EventManager EventManager => _eventManager;
33
40
  internal static TimerManager Timer => _timerManager;
34
41
 
42
+ /// <summary>
43
+ /// Perform a full soft restart of the Hyper session.
44
+ ///
45
+ /// This is the internal implementation used by both the public
46
+ /// HyperSDK facade and internal UI flows (pause/game over modals).
47
+ /// </summary>
48
+ internal static void RestartSession()
49
+ {
50
+ _isSoftRestarting = true;
51
+
52
+ ClearAllDontDestroyOnLoadObjects();
53
+ SceneManager.LoadScene("HyperLoader");
54
+ }
55
+
35
56
  internal static void Initialize(Action callback)
36
57
  {
37
58
  ValidatePlatform();
@@ -141,10 +162,28 @@ namespace Hyper.Internal
141
162
 
142
163
  _host = null;
143
164
  _isInitialized = false;
165
+ _isSoftRestarting = false;
144
166
 
145
167
  HyperDebug.Log("Cleared and reset");
146
168
  }
147
169
 
170
+ /// <summary>
171
+ /// Clears all root objects residing in the DontDestroyOnLoad scene.
172
+ /// Intended to be used as part of a controlled soft restart flow.
173
+ /// </summary>
174
+ private static void ClearAllDontDestroyOnLoadObjects()
175
+ {
176
+ var allObjects = Resources.FindObjectsOfTypeAll<GameObject>();
177
+
178
+ foreach (var obj in allObjects)
179
+ {
180
+ if (obj.scene.name == "DontDestroyOnLoad" && obj.transform.parent == null)
181
+ {
182
+ UnityEngine.Object.Destroy(obj);
183
+ }
184
+ }
185
+ }
186
+
148
187
  internal static void OnHostDestroyed(HyperRuntimeHost host)
149
188
  {
150
189
  if (_host != host) return;
@@ -163,6 +202,7 @@ namespace Hyper.Internal
163
202
  _dataManager = null;
164
203
  _gameContent = null;
165
204
  _isInitialized = false;
205
+ _isSoftRestarting = false;
166
206
  }
167
207
  }
168
208
  }
@@ -1,7 +1,6 @@
1
1
  using System.Collections;
2
2
  using TMPro;
3
3
  using UnityEngine;
4
- using UnityEngine.SceneManagement;
5
4
  using UnityEngine.UI;
6
5
  using System.Runtime.InteropServices;
7
6
  using Hyper.Internal.Managers;
@@ -86,7 +85,7 @@ namespace Hyper.Internal
86
85
 
87
86
  while (elapsedTime < duration)
88
87
  {
89
- elapsedTime += Time.deltaTime;
88
+ elapsedTime += Time.unscaledDeltaTime;
90
89
  loadingBarSlider.value = Mathf.Lerp(startValue, targetValue, elapsedTime / duration);
91
90
  yield return null;
92
91
  }
@@ -168,26 +167,7 @@ namespace Hyper.Internal
168
167
 
169
168
  public void PlayAgain()
170
169
  {
171
- FullGameRestart();
172
- }
173
-
174
- private void FullGameRestart()
175
- {
176
- ClearAllDDOLObjects();
177
- SceneManager.LoadScene("HyperLoader");
178
- }
179
-
180
- private void ClearAllDDOLObjects()
181
- {
182
- GameObject[] allObjects = Resources.FindObjectsOfTypeAll<GameObject>();
183
-
184
- foreach (GameObject obj in allObjects)
185
- {
186
- if (obj.scene.name == "DontDestroyOnLoad" && obj.transform.parent == null)
187
- {
188
- Destroy(obj);
189
- }
190
- }
170
+ HyperRuntime.RestartSession();
191
171
  }
192
172
 
193
173
  }
@@ -1,6 +1,5 @@
1
1
  using TMPro;
2
2
  using UnityEngine;
3
- using UnityEngine.SceneManagement;
4
3
  using UnityEngine.UI;
5
4
  using System.Runtime.InteropServices;
6
5
  using Hyper.Internal.Managers;
@@ -120,7 +119,7 @@ namespace Hyper.Internal
120
119
  {
121
120
  _dataManager.SetSound(_dataManager.GetSound() == 1 ? 0 : 1);
122
121
  soundIcon.sprite = _dataManager.GetSound() == 1 ? soundIconOn : soundIconOff;
123
- soundText.text = _dataManager.GetSound() == 1 ? "Sound ON" : "Sound OFF";
122
+ soundText.text = _dataManager.GetSound() == 1 ? "Sound On" : "Sound Off";
124
123
  }
125
124
 
126
125
  public void ShowTutorial()
@@ -136,22 +135,7 @@ namespace Hyper.Internal
136
135
 
137
136
  public void RestartGame()
138
137
  {
139
- ClearAllDDOLObjects();
140
- SceneManager.LoadScene("HyperLoader");
141
- }
142
-
143
- private void ClearAllDDOLObjects()
144
- {
145
- GameObject[] allObjects = Resources.FindObjectsOfTypeAll<GameObject>();
146
-
147
- foreach (GameObject obj in allObjects)
148
- {
149
- if (obj.scene.name == "DontDestroyOnLoad" && obj.transform.parent == null)
150
- {
151
- Debug.Log($"Destroying DDOL object: {obj.name}");
152
- Destroy(obj);
153
- }
154
- }
138
+ HyperRuntime.RestartSession();
155
139
  }
156
140
  }
157
141
  }
@@ -37,6 +37,7 @@ namespace Hyper.Internal
37
37
  public const string SETTINGS_ASSET_PATH = "Assets/HyperSDK/Runtime/Resources/HyperSDKSettings.asset";
38
38
  public const string GAME_CONTENT_ASSET_PATH = "Assets/HyperSDK/Runtime/Resources/HyperGameContentConfig.asset";
39
39
  public const string RESOURCES_FOLDER_PATH = "Assets/HyperSDK/Runtime/Resources";
40
+ public const string HYPER_LOADER_SCENE_PATH = "Assets/HyperSDK/HyperLoader.unity";
40
41
 
41
42
  /// <summary>
42
43
  /// Returns the banner texture path, checking dev mode (Assets/) first, then package mode (Packages/).
@@ -1,5 +1,6 @@
1
1
  using System;
2
2
  using UnityEngine;
3
+ using UnityEngine.SceneManagement;
3
4
  using Hyper.Internal;
4
5
  using Hyper.Internal.Managers;
5
6
 
@@ -20,6 +21,23 @@ namespace Hyper
20
21
  /// </summary>
21
22
  public static bool IsInitialized => HyperRuntime.IsInitialized;
22
23
 
24
+ /// <summary>
25
+ /// Indicates that Hyper is currently performing a soft restart.
26
+ ///
27
+ /// This is only true during the teardown/transition between sessions
28
+ /// when DontDestroyOnLoad objects are being cleared and the HyperLoader
29
+ /// scene is being (re)loaded. Once the new loader starts, this flag is reset.
30
+ ///
31
+ /// Intended usage:
32
+ /// - Distinguish soft restart vs real quit in teardown logic
33
+ /// (e.g. singleton OnDestroy guards) to avoid false positives.
34
+ /// </summary>
35
+ public static bool IsSoftRestarting
36
+ {
37
+ get => HyperRuntime.IsSoftRestarting;
38
+ internal set => HyperRuntime.IsSoftRestarting = value;
39
+ }
40
+
23
41
  /// <summary>
24
42
  /// Initialize the Hyper SDK. Must be called before accessing other APIs.
25
43
  /// </summary>
@@ -95,6 +113,7 @@ namespace Hyper
95
113
 
96
114
  _eventAdapter.RefreshBindings();
97
115
  }
116
+
98
117
  }
99
118
 
100
119
  /// <summary>
@@ -462,7 +462,7 @@ RectTransform:
462
462
  m_AnchorMin: {x: 0.5, y: 0.5}
463
463
  m_AnchorMax: {x: 0.5, y: 0.5}
464
464
  m_AnchoredPosition: {x: 0, y: 0}
465
- m_SizeDelta: {x: 2.5, y: 113.3299}
465
+ m_SizeDelta: {x: 3, y: 113.3299}
466
466
  m_Pivot: {x: 0.5, y: 0.5}
467
467
  --- !u!222 &3311437449879540859
468
468
  CanvasRenderer:
@@ -36,7 +36,7 @@ RectTransform:
36
36
  m_AnchorMin: {x: 0.5, y: 0.5}
37
37
  m_AnchorMax: {x: 0.5, y: 0.5}
38
38
  m_AnchoredPosition: {x: 0, y: 0}
39
- m_SizeDelta: {x: 2.5, y: 113.3299}
39
+ m_SizeDelta: {x: 3, y: 113.3299}
40
40
  m_Pivot: {x: 0.5, y: 0.5}
41
41
  --- !u!222 &6183820688932751126
42
42
  CanvasRenderer:
@@ -603,7 +603,7 @@ RectTransform:
603
603
  m_AnchorMin: {x: 0.5, y: 0.5}
604
604
  m_AnchorMax: {x: 0.5, y: 0.5}
605
605
  m_AnchoredPosition: {x: 0, y: 0}
606
- m_SizeDelta: {x: 2.5, y: 113.3299}
606
+ m_SizeDelta: {x: 3, y: 113.3299}
607
607
  m_Pivot: {x: 0.5, y: 0.5}
608
608
  --- !u!222 &7271924545119143605
609
609
  CanvasRenderer:
@@ -36,7 +36,7 @@ RectTransform:
36
36
  m_AnchorMin: {x: 0.5, y: 0.5}
37
37
  m_AnchorMax: {x: 0.5, y: 0.5}
38
38
  m_AnchoredPosition: {x: 0, y: 0}
39
- m_SizeDelta: {x: 2.5, y: 113.3299}
39
+ m_SizeDelta: {x: 3, y: 113.3299}
40
40
  m_Pivot: {x: 0.5, y: 0.5}
41
41
  --- !u!222 &533477767077768701
42
42
  CanvasRenderer:
@@ -270,7 +270,7 @@ MonoBehaviour:
270
270
  m_text: FINAL SCORE
271
271
  m_isRightToLeft: 0
272
272
  m_fontAsset: {fileID: 11400000, guid: b61cc31493416594290d3793968a7776, type: 2}
273
- m_sharedMaterial: {fileID: 392085163434936357, guid: b61cc31493416594290d3793968a7776, type: 2}
273
+ m_sharedMaterial: {fileID: -6106472849309118677, guid: b61cc31493416594290d3793968a7776, type: 2}
274
274
  m_fontSharedMaterials: []
275
275
  m_fontMaterial: {fileID: 0}
276
276
  m_fontMaterials: []
@@ -408,7 +408,7 @@ MonoBehaviour:
408
408
  m_text: LAST SUBMITTED
409
409
  m_isRightToLeft: 0
410
410
  m_fontAsset: {fileID: 11400000, guid: b61cc31493416594290d3793968a7776, type: 2}
411
- m_sharedMaterial: {fileID: 392085163434936357, guid: b61cc31493416594290d3793968a7776, type: 2}
411
+ m_sharedMaterial: {fileID: -6106472849309118677, guid: b61cc31493416594290d3793968a7776, type: 2}
412
412
  m_fontSharedMaterials: []
413
413
  m_fontMaterial: {fileID: 0}
414
414
  m_fontMaterials: []
@@ -556,7 +556,7 @@ MonoBehaviour:
556
556
  m_text: 10,200
557
557
  m_isRightToLeft: 0
558
558
  m_fontAsset: {fileID: 11400000, guid: 39c484b4a22288c488625a88b6da2145, type: 2}
559
- m_sharedMaterial: {fileID: 2121445518252921147, guid: 39c484b4a22288c488625a88b6da2145, type: 2}
559
+ m_sharedMaterial: {fileID: -8342687123090027242, guid: 39c484b4a22288c488625a88b6da2145, type: 2}
560
560
  m_fontSharedMaterials: []
561
561
  m_fontMaterial: {fileID: 0}
562
562
  m_fontMaterials: []
@@ -692,7 +692,7 @@ MonoBehaviour:
692
692
  m_text: 10,000
693
693
  m_isRightToLeft: 0
694
694
  m_fontAsset: {fileID: 11400000, guid: 39c484b4a22288c488625a88b6da2145, type: 2}
695
- m_sharedMaterial: {fileID: 2121445518252921147, guid: 39c484b4a22288c488625a88b6da2145, type: 2}
695
+ m_sharedMaterial: {fileID: -8342687123090027242, guid: 39c484b4a22288c488625a88b6da2145, type: 2}
696
696
  m_fontSharedMaterials: []
697
697
  m_fontMaterial: {fileID: 0}
698
698
  m_fontMaterials: []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "app.hypergames.hypersdk",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
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",