app.hypergames.hypersdk 1.4.21 → 1.5.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.
@@ -44,7 +44,7 @@ namespace Hyper.Internal.Managers
44
44
  public void UpdateScore(int score)
45
45
  {
46
46
  if (_gameManager == null) _gameManager = HyperRuntime.GameManager;
47
-
47
+
48
48
  if (_gameManager.HasGameEnded) return;
49
49
 
50
50
  CurrentScore = score;
@@ -56,23 +56,26 @@ namespace Hyper.Internal.Managers
56
56
 
57
57
  float currentGameSecond = Mathf.Floor(currentTimestamp);
58
58
 
59
- CurrentScoreData = new ScoreData
59
+ // Reuse a single ScoreData graph for CurrentScoreData to avoid per-call allocations
60
+ if (CurrentScoreData == null)
60
61
  {
61
- cumulativeScore = CurrentScore,
62
- timestampUtc = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(),
63
- isFinal = true,
64
- scoreSnapshot = new ScoreSnapshot
65
- {
66
- scoreTime = currentGameSecond,
67
- scoreDelta = CurrentScore - _lastCapturedScore,
68
- gameplayModifiers = new GameplayModifiers
69
- {
70
- comboModifiers = ComboMultiplier,
71
- globalModifiers = GlobalMultiplier,
72
- activePowerUps = ActivePowerups.ToList()
73
- }
74
- }
75
- };
62
+ CurrentScoreData = _currentScoreDataBuffer;
63
+ CurrentScoreData.scoreSnapshot = _currentSnapshotBuffer;
64
+ CurrentScoreData.scoreSnapshot.gameplayModifiers = _currentModifiersBuffer;
65
+ }
66
+
67
+ CurrentScoreData.cumulativeScore = CurrentScore;
68
+ CurrentScoreData.timestampUtc = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
69
+ CurrentScoreData.isFinal = true;
70
+
71
+ var snapshot = CurrentScoreData.scoreSnapshot;
72
+ snapshot.scoreTime = currentGameSecond;
73
+ snapshot.scoreDelta = CurrentScore - _lastCapturedScore;
74
+
75
+ var modifiers = snapshot.gameplayModifiers;
76
+ modifiers.comboModifiers = ComboMultiplier;
77
+ modifiers.globalModifiers = GlobalMultiplier;
78
+ modifiers.activePowerUps = ActivePowerups;
76
79
 
77
80
  if (score > GetBestScore())
78
81
  {
@@ -130,6 +133,7 @@ namespace Hyper.Internal.Managers
130
133
  internal List<ScoreData> PendingScores { get; private set; } = new List<ScoreData>();
131
134
  internal TutorialData TutorialData { get; private set; }
132
135
  internal bool HasReferencedTutorialResources { get; private set; }
136
+ private const int SCORE_POOL_CAPACITY = 15;
133
137
 
134
138
  internal void ConfigurePlayerSoundSetting()
135
139
  {
@@ -152,7 +156,7 @@ namespace Hyper.Internal.Managers
152
156
  internal void StartCapturingScores()
153
157
  {
154
158
  if (_gameManager == null) _gameManager = HyperRuntime.GameManager;
155
-
159
+
156
160
  if (_scoreCaptureCoroutine == null)
157
161
  {
158
162
  _scoreCaptureCoroutine = StartCoroutine(CaptureScoreEverySecond());
@@ -200,6 +204,16 @@ namespace Hyper.Internal.Managers
200
204
  private float _lastCapturedGameSecond = -1f;
201
205
  private int _lastCapturedScore = 0;
202
206
 
207
+ // Reusable object graph for CurrentScoreData to avoid allocations in UpdateScore()
208
+ private readonly ScoreData _currentScoreDataBuffer = new ScoreData();
209
+ private readonly ScoreSnapshot _currentSnapshotBuffer = new ScoreSnapshot();
210
+ private readonly GameplayModifiers _currentModifiersBuffer = new GameplayModifiers();
211
+
212
+ // Pools used for per-second score snapshots captured into PendingScores
213
+ private readonly Queue<ScoreData> _scoreDataPool = new Queue<ScoreData>();
214
+ private readonly Queue<ScoreSnapshot> _scoreSnapshotPool = new Queue<ScoreSnapshot>();
215
+ private readonly Queue<GameplayModifiers> _gameplayModifiersPool = new Queue<GameplayModifiers>();
216
+
203
217
  #endregion
204
218
 
205
219
  #region Score Capture Logic
@@ -216,23 +230,24 @@ namespace Hyper.Internal.Managers
216
230
 
217
231
  if (currentGameSecond > _lastCapturedGameSecond)
218
232
  {
219
- ScoreData newScore = new ScoreData
220
- {
221
- cumulativeScore = CurrentScore,
222
- timestampUtc = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(),
223
- isFinal = false,
224
- scoreSnapshot = new ScoreSnapshot
225
- {
226
- scoreTime = currentGameSecond,
227
- scoreDelta = CurrentScore - _lastCapturedScore,
228
- gameplayModifiers = new GameplayModifiers
229
- {
230
- comboModifiers = ComboMultiplier,
231
- globalModifiers = GlobalMultiplier,
232
- activePowerUps = ActivePowerups.ToList()
233
- }
234
- }
235
- };
233
+ // Get objects from pools to avoid allocations in this hot path
234
+ var newScore = GetPooledScoreData();
235
+ var snapshot = GetPooledScoreSnapshot();
236
+ var modifiers = GetPooledGameplayModifiers();
237
+
238
+ newScore.cumulativeScore = CurrentScore;
239
+ newScore.timestampUtc = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
240
+ newScore.isFinal = false;
241
+
242
+ snapshot.scoreTime = currentGameSecond;
243
+ snapshot.scoreDelta = CurrentScore - _lastCapturedScore;
244
+
245
+ modifiers.comboModifiers = ComboMultiplier;
246
+ modifiers.globalModifiers = GlobalMultiplier;
247
+ modifiers.activePowerUps = ActivePowerups;
248
+
249
+ snapshot.gameplayModifiers = modifiers;
250
+ newScore.scoreSnapshot = snapshot;
236
251
 
237
252
  PendingScores.Add(newScore);
238
253
 
@@ -244,6 +259,84 @@ namespace Hyper.Internal.Managers
244
259
  }
245
260
  }
246
261
 
262
+ private ScoreData GetPooledScoreData()
263
+ {
264
+ return _scoreDataPool.Count > 0 ? _scoreDataPool.Dequeue() : new ScoreData();
265
+ }
266
+
267
+ private ScoreSnapshot GetPooledScoreSnapshot()
268
+ {
269
+ return _scoreSnapshotPool.Count > 0 ? _scoreSnapshotPool.Dequeue() : new ScoreSnapshot();
270
+ }
271
+
272
+ private GameplayModifiers GetPooledGameplayModifiers()
273
+ {
274
+ return _gameplayModifiersPool.Count > 0 ? _gameplayModifiersPool.Dequeue() : new GameplayModifiers();
275
+ }
276
+
277
+ internal void ReturnScoreDataToPool(List<ScoreData> scores)
278
+ {
279
+ if (scores == null) return;
280
+
281
+ for (int i = 0; i < scores.Count; i++)
282
+ {
283
+ ReturnScoreDataToPool(scores[i]);
284
+ }
285
+ }
286
+
287
+ private void ReturnScoreDataToPool(ScoreData data)
288
+ {
289
+ if (data == null) return;
290
+
291
+ if (data.scoreSnapshot != null)
292
+ {
293
+ ReturnScoreSnapshotToPool(data.scoreSnapshot);
294
+ data.scoreSnapshot = null;
295
+ }
296
+
297
+ data.cumulativeScore = 0;
298
+ data.isFinal = false;
299
+ data.timestampUtc = null;
300
+
301
+ if (_scoreDataPool.Count < SCORE_POOL_CAPACITY)
302
+ {
303
+ _scoreDataPool.Enqueue(data);
304
+ }
305
+ }
306
+
307
+ private void ReturnScoreSnapshotToPool(ScoreSnapshot snapshot)
308
+ {
309
+ if (snapshot == null) return;
310
+
311
+ if (snapshot.gameplayModifiers != null)
312
+ {
313
+ ReturnGameplayModifiersToPool(snapshot.gameplayModifiers);
314
+ snapshot.gameplayModifiers = null;
315
+ }
316
+
317
+ snapshot.scoreTime = 0f;
318
+ snapshot.scoreDelta = 0;
319
+
320
+ if (_scoreSnapshotPool.Count < SCORE_POOL_CAPACITY)
321
+ {
322
+ _scoreSnapshotPool.Enqueue(snapshot);
323
+ }
324
+ }
325
+
326
+ private void ReturnGameplayModifiersToPool(GameplayModifiers modifiers)
327
+ {
328
+ if (modifiers == null) return;
329
+
330
+ modifiers.comboModifiers = 0f;
331
+ modifiers.globalModifiers = 0f;
332
+ modifiers.activePowerUps = null;
333
+
334
+ if (_gameplayModifiersPool.Count < SCORE_POOL_CAPACITY)
335
+ {
336
+ _gameplayModifiersPool.Enqueue(modifiers);
337
+ }
338
+ }
339
+
247
340
  private void SetBestScore(ScoreData scoreData, string sessionId)
248
341
  {
249
342
  BestScoreWrapper bestScore = new BestScoreWrapper(scoreData, sessionId);
@@ -190,11 +190,6 @@ namespace Hyper.Internal.Managers
190
190
  HandlePauseState(!hasFocus);
191
191
  }
192
192
 
193
- void OnApplicationPause(bool pauseStatus)
194
- {
195
- HandlePauseState(pauseStatus);
196
- }
197
-
198
193
  void HandlePauseState(bool shouldPause)
199
194
  {
200
195
  if (shouldPause && !_isPaused)
@@ -38,6 +38,9 @@ namespace Hyper.Internal
38
38
  [Tooltip("Choose the start CTA overlay shown before gameplay begins. Hyper requires one of these overlays - do not add your own start buttons.")]
39
39
  public StartCTA startCTA = StartCTA.TapToPlay;
40
40
 
41
+ [Tooltip("If Start CTA is set to Swipe to Play, choose the swipe direction used for the visual cue.")]
42
+ public SwipeDirection swipeDirection = SwipeDirection.Up;
43
+
41
44
  #endregion
42
45
 
43
46
  #region Control Bar Settings
@@ -52,6 +52,9 @@ namespace Hyper.Internal
52
52
  private const float DARK_THEME_PAUSE_BUTTON_ALPHA = 0.25f;
53
53
  private const float LIGHT_THEME_PAUSE_BUTTON_ALPHA = 1f;
54
54
 
55
+ private int lastScore = -1;
56
+ private readonly char[] _scoreBuffer = new char[16];
57
+
55
58
  void Awake()
56
59
  {
57
60
  _gameManager = HyperRuntime.GameManager;
@@ -260,7 +263,12 @@ namespace Hyper.Internal
260
263
 
261
264
  public void UpdateScoreLabel()
262
265
  {
263
- scoreText.SetText(HyperRuntime.DataManager.CurrentScore.ToString("N0"));
266
+ int currentScore = HyperRuntime.DataManager.CurrentScore;
267
+ if (currentScore != lastScore)
268
+ {
269
+ lastScore = currentScore;
270
+ HyperNumberFormatter.SetScoreNoAlloc(_scoreTextComponent, currentScore, _scoreBuffer);
271
+ }
264
272
  }
265
273
 
266
274
  /// <summary>
@@ -3,6 +3,7 @@ using UnityEngine;
3
3
  using TMPro;
4
4
  using UnityEngine.UI;
5
5
  using Hyper.Internal.Animation;
6
+ using System.Text;
6
7
 
7
8
  namespace Hyper.Internal
8
9
  {
@@ -33,6 +34,7 @@ namespace Hyper.Internal
33
34
  private int _maxLives;
34
35
  private Image[] _heartImages;
35
36
  private bool _livesExhaustedTriggered;
37
+ private readonly StringBuilder _overflowLabelText = new StringBuilder(10);
36
38
 
37
39
  private void Awake()
38
40
  {
@@ -311,16 +313,13 @@ namespace Hyper.Internal
311
313
 
312
314
  int heartSlots = _heartImages != null ? _heartImages.Length : 0;
313
315
  int overflow = Mathf.Max(0, _currentLives - heartSlots);
316
+
314
317
  if (overflow > 0)
315
318
  {
316
- overflowLabel.gameObject.SetActive(true);
317
- overflowLabel.text = $"+{overflow}";
318
- }
319
- else
320
- {
321
- overflowLabel.text = string.Empty;
322
- overflowLabel.gameObject.SetActive(false);
319
+ overflowLabel.SetText("+{0}", overflow);
323
320
  }
321
+
322
+ overflowLabel.gameObject.SetActive(overflow > 0);
324
323
  }
325
324
  }
326
325
  }
@@ -19,7 +19,7 @@ namespace Hyper.Internal
19
19
  int seconds = Mathf.FloorToInt(HyperRuntime.Timer.CurrentTime % 60);
20
20
 
21
21
  // Update the UI text to display in the format 00:00
22
- timerText.text = string.Format("{0:00}:{1:00}", minutes, seconds);
22
+ timerText.SetText("{0:00}:{1:00}", minutes, seconds);
23
23
 
24
24
  }
25
25
  }
@@ -104,11 +104,16 @@ namespace Hyper.Internal
104
104
  // Called from the SlideRight script once the animation is finished
105
105
  public void StartAction()
106
106
  {
107
- StartLerpingSlider(0.7f, HyperRuntime.BackendManager.scoreSubmissionTimeout);
107
+ StartLerpingSlider(0.6f, HyperRuntime.BackendManager.scoreSubmissionTimeout);
108
108
  }
109
109
 
110
110
  public void ScoreHasBeenSubmitted()
111
111
  {
112
+ // Change back to "Submitting score" since submission is now successful
113
+ // and we're just loading to completion
114
+ if (scoreSubmissionText != null)
115
+ scoreSubmissionText.text = "Submitting score";
116
+
112
117
  StopLerpingSlider();
113
118
  StartCoroutine(SetLoadingBarComplete());
114
119
  }
@@ -22,6 +22,7 @@ namespace Hyper.Internal
22
22
  private GameManager _gameManager;
23
23
  private BackendManager _backendManager;
24
24
  private StartCTA _currentCTA;
25
+ private SwipeDirection _swipeDirection;
25
26
 
26
27
  // Swipe detection variables
27
28
  private Vector2 _swipeStartPosition;
@@ -56,6 +57,9 @@ namespace Hyper.Internal
56
57
  public void Configure(StartCTA cta)
57
58
  {
58
59
  _currentCTA = cta;
60
+ _swipeDirection = HyperRuntime.Settings != null
61
+ ? HyperRuntime.Settings.swipeDirection
62
+ : SwipeDirection.Up;
59
63
 
60
64
  if (startCtaLabel == null)
61
65
  {
@@ -276,27 +280,49 @@ namespace Hyper.Internal
276
280
 
277
281
  private void UpdateSwipeGraphics()
278
282
  {
279
- bool showVertical = _currentCTA == StartCTA.SwipeToPlayVertical;
280
- bool showHorizontal = _currentCTA == StartCTA.SwipeToPlayHorizontal;
281
-
282
283
  if (swipeGif != null)
283
284
  {
284
- if (showVertical)
285
- {
286
- swipeGif.anchoredPosition = new Vector3(0, 286, 0);
287
- swipeGif.transform.rotation = Quaternion.Euler(0, 0, 90);
288
- swipeGif.gameObject.SetActive(true);
289
- }
290
- else if (showHorizontal)
285
+ bool isSwipe =
286
+ _currentCTA == StartCTA.SwipeToPlayVertical ||
287
+ _currentCTA == StartCTA.SwipeToPlayHorizontal;
288
+
289
+ if (!isSwipe)
291
290
  {
292
- swipeGif.anchoredPosition = new Vector3(0, 220, 0);
293
- swipeGif.transform.rotation = Quaternion.Euler(0, 0, 0);
294
- swipeGif.gameObject.SetActive(true);
291
+ swipeGif.gameObject.SetActive(false);
292
+ return;
295
293
  }
296
- else
294
+
295
+ // Default positions based on axis (vertical vs horizontal)
296
+ Vector3 verticalPosition = new Vector3(0, 286, 0);
297
+ Vector3 horizontalPosition = new Vector3(0, 220, 0);
298
+
299
+ float rotationZ;
300
+ Vector3 anchoredPosition;
301
+
302
+ switch (_swipeDirection)
297
303
  {
298
- swipeGif.gameObject.SetActive(false);
304
+ case SwipeDirection.Up:
305
+ rotationZ = 90f;
306
+ anchoredPosition = verticalPosition;
307
+ break;
308
+ case SwipeDirection.Down:
309
+ rotationZ = -90f;
310
+ anchoredPosition = verticalPosition;
311
+ break;
312
+ case SwipeDirection.Left:
313
+ rotationZ = 180f;
314
+ anchoredPosition = horizontalPosition;
315
+ break;
316
+ case SwipeDirection.Right:
317
+ default:
318
+ rotationZ = 0f;
319
+ anchoredPosition = horizontalPosition;
320
+ break;
299
321
  }
322
+
323
+ swipeGif.anchoredPosition = anchoredPosition;
324
+ swipeGif.transform.rotation = Quaternion.Euler(0, 0, rotationZ);
325
+ swipeGif.gameObject.SetActive(true);
300
326
  }
301
327
  }
302
328
 
@@ -305,12 +331,16 @@ namespace Hyper.Internal
305
331
  float absX = Mathf.Abs(delta.x);
306
332
  float absY = Mathf.Abs(delta.y);
307
333
 
308
- switch (_currentCTA)
334
+ switch (_swipeDirection)
309
335
  {
310
- case StartCTA.SwipeToPlayVertical:
311
- return absY >= SWIPE_THRESHOLD && absY >= absX;
312
- case StartCTA.SwipeToPlayHorizontal:
313
- return absX >= SWIPE_THRESHOLD && absX >= absY;
336
+ case SwipeDirection.Up:
337
+ return delta.y >= SWIPE_THRESHOLD && absY >= absX;
338
+ case SwipeDirection.Down:
339
+ return -delta.y >= SWIPE_THRESHOLD && absY >= absX;
340
+ case SwipeDirection.Right:
341
+ return delta.x >= SWIPE_THRESHOLD && absX >= absY;
342
+ case SwipeDirection.Left:
343
+ return -delta.x >= SWIPE_THRESHOLD && absX >= absY;
314
344
  default:
315
345
  return false;
316
346
  }
@@ -17,6 +17,7 @@ MonoBehaviour:
17
17
  pc: 0
18
18
  mobile: 1
19
19
  startCTA: 0
20
+ swipeDirection: 0
20
21
  controlBarLayout: 0
21
22
  controlBarTheme: 1
22
23
  useCustomRestartFlow: 0
@@ -24,9 +24,9 @@ RectTransform:
24
24
  m_PrefabInstance: {fileID: 0}
25
25
  m_PrefabAsset: {fileID: 0}
26
26
  m_GameObject: {fileID: 812134488303599474}
27
- m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
27
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
28
28
  m_LocalPosition: {x: 0, y: 0, z: 0}
29
- m_LocalScale: {x: 1.1, y: 1.1, z: 1.1}
29
+ m_LocalScale: {x: 0.9, y: 0.9, z: 0.9}
30
30
  m_ConstrainProportionsScale: 1
31
31
  m_Children:
32
32
  - {fileID: 312166748021578777}
@@ -35,7 +35,7 @@ RectTransform:
35
35
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
36
36
  m_AnchorMin: {x: 0.5, y: 0.5}
37
37
  m_AnchorMax: {x: 0.5, y: 0.5}
38
- m_AnchoredPosition: {x: 0, y: 220}
38
+ m_AnchoredPosition: {x: 0, y: 210}
39
39
  m_SizeDelta: {x: 279.2293, y: 106.4023}
40
40
  m_Pivot: {x: 0.5, y: 0.5}
41
41
  --- !u!222 &277624337904105659
@@ -325,7 +325,7 @@ PrefabInstance:
325
325
  objectReference: {fileID: 0}
326
326
  - target: {fileID: 596696483668891729, guid: bc5495c08b5534447938b4459527fa86, type: 3}
327
327
  propertyPath: m_fontSize
328
- value: 130
328
+ value: 120.8
329
329
  objectReference: {fileID: 0}
330
330
  - target: {fileID: 596696483668891729, guid: bc5495c08b5534447938b4459527fa86, type: 3}
331
331
  propertyPath: m_margin.x
@@ -145,4 +145,30 @@ namespace Hyper.Shared
145
145
  /// </summary>
146
146
  SwipeToPlayHorizontal
147
147
  }
148
+
149
+ /// <summary>
150
+ /// Direction of swipe used for Start CTA visuals and gesture.
151
+ /// </summary>
152
+ public enum SwipeDirection
153
+ {
154
+ /// <summary>
155
+ /// Swipe upwards.
156
+ /// </summary>
157
+ Up,
158
+
159
+ /// <summary>
160
+ /// Swipe downwards.
161
+ /// </summary>
162
+ Down,
163
+
164
+ /// <summary>
165
+ /// Swipe to the left.
166
+ /// </summary>
167
+ Left,
168
+
169
+ /// <summary>
170
+ /// Swipe to the right.
171
+ /// </summary>
172
+ Right
173
+ }
148
174
  }
@@ -1,7 +1,9 @@
1
1
  {
2
2
  "name": "Hyper.Shared",
3
3
  "rootNamespace": "Hyper.Shared",
4
- "references": [],
4
+ "references": [
5
+ "GUID:6055be8ebefd69e48b49212b09b47b2f"
6
+ ],
5
7
  "includePlatforms": [],
6
8
  "excludePlatforms": [],
7
9
  "allowUnsafeCode": false,
@@ -30,7 +30,7 @@ namespace Hyper.Internal
30
30
  {
31
31
  #if UNITY_EDITOR
32
32
  return true;
33
- #elif DEVELOPMENT_BUILD
33
+ #elif HYPER_DEVELOPMENT_BUILD
34
34
  return true;
35
35
  #else
36
36
  return false;
@@ -45,7 +45,7 @@ namespace Hyper.Internal
45
45
  /// <summary>
46
46
  /// Standard log message with HyperSDK prefix.
47
47
  /// </summary>
48
- [Conditional("UNITY_EDITOR"), Conditional("DEVELOPMENT_BUILD")]
48
+ [Conditional("UNITY_EDITOR"), Conditional("HYPER_DEVELOPMENT_BUILD")]
49
49
  public static void Log(string message, UnityEngine.Object context = null)
50
50
  {
51
51
  if (!IsLoggingEnabled) return;
@@ -55,7 +55,7 @@ namespace Hyper.Internal
55
55
  /// <summary>
56
56
  /// Info log with automatic caller detection.
57
57
  /// </summary>
58
- [Conditional("UNITY_EDITOR"), Conditional("DEVELOPMENT_BUILD")]
58
+ [Conditional("UNITY_EDITOR"), Conditional("HYPER_DEVELOPMENT_BUILD")]
59
59
  public static void Info(string message, UnityEngine.Object context = null)
60
60
  {
61
61
  if (!IsLoggingEnabled) return;
@@ -66,7 +66,7 @@ namespace Hyper.Internal
66
66
  /// <summary>
67
67
  /// Success log (green) with automatic caller detection.
68
68
  /// </summary>
69
- [Conditional("UNITY_EDITOR"), Conditional("DEVELOPMENT_BUILD")]
69
+ [Conditional("UNITY_EDITOR"), Conditional("HYPER_DEVELOPMENT_BUILD")]
70
70
  public static void LogSuccess(string message, UnityEngine.Object context = null)
71
71
  {
72
72
  if (!IsLoggingEnabled) return;
@@ -77,7 +77,7 @@ namespace Hyper.Internal
77
77
  /// <summary>
78
78
  /// Action log (blue) with automatic caller detection.
79
79
  /// </summary>
80
- [Conditional("UNITY_EDITOR"), Conditional("DEVELOPMENT_BUILD")]
80
+ [Conditional("UNITY_EDITOR"), Conditional("HYPER_DEVELOPMENT_BUILD")]
81
81
  public static void Action(string message, UnityEngine.Object context = null)
82
82
  {
83
83
  if (!IsLoggingEnabled) return;
@@ -88,7 +88,7 @@ namespace Hyper.Internal
88
88
  /// <summary>
89
89
  /// Warning log (orange) with HyperSDK prefix.
90
90
  /// </summary>
91
- [Conditional("UNITY_EDITOR"), Conditional("DEVELOPMENT_BUILD")]
91
+ [Conditional("UNITY_EDITOR"), Conditional("HYPER_DEVELOPMENT_BUILD")]
92
92
  public static void LogWarning(string message, UnityEngine.Object context = null)
93
93
  {
94
94
  if (!IsLoggingEnabled) return;
@@ -114,12 +114,22 @@ namespace Hyper.Internal
114
114
  /// </summary>
115
115
  private static string FormatMessage(string color, string prefix, string message)
116
116
  {
117
+
118
+ #if UNITY_EDITOR
117
119
  if (string.IsNullOrEmpty(prefix))
118
120
  {
119
121
  return $"<color={color}>{message}</color>";
120
122
  }
121
-
123
+
122
124
  return $"<color={color}>[{prefix}]</color> {message}";
125
+ #else
126
+ if (string.IsNullOrEmpty(prefix))
127
+ {
128
+ return $"{message}";
129
+ }
130
+
131
+ return $"[{prefix}] {message}";
132
+ #endif
123
133
  }
124
134
 
125
135
  #endregion
@@ -0,0 +1,67 @@
1
+ using TMPro;
2
+
3
+ namespace Hyper.Internal
4
+ {
5
+ /// <summary>
6
+ /// Internal number formatting utilities with minimal GC allocations.
7
+ /// </summary>
8
+ public static class HyperNumberFormatter
9
+ {
10
+ /// <summary>
11
+ /// Formats an <see cref="int"/> with thousand separators into the provided buffer.
12
+ /// Returns the number of characters written.
13
+ /// </summary>
14
+ /// <remarks>
15
+ /// - No string allocations.
16
+ /// - Caller must ensure <paramref name="buffer"/> is large enough for the largest expected value.
17
+ /// </remarks>
18
+ internal static int FormatIntWithCommas(int value, char[] buffer)
19
+ {
20
+ long v = value;
21
+ bool neg = v < 0;
22
+ if (neg) v = -v;
23
+
24
+ int i = buffer.Length;
25
+ int group = 0;
26
+
27
+ do
28
+ {
29
+ if (group == 3)
30
+ {
31
+ buffer[--i] = ',';
32
+ group = 0;
33
+ }
34
+
35
+ buffer[--i] = (char)('0' + (v % 10));
36
+ v /= 10;
37
+ group++;
38
+ } while (v != 0);
39
+
40
+ if (neg)
41
+ {
42
+ buffer[--i] = '-';
43
+ }
44
+
45
+ int len = buffer.Length - i;
46
+
47
+ // Shift to the beginning of the buffer
48
+ for (int k = 0; k < len; k++)
49
+ {
50
+ buffer[k] = buffer[i + k];
51
+ }
52
+
53
+ return len;
54
+ }
55
+
56
+ /// <summary>
57
+ /// Convenience helper: formats <paramref name="value"/> into <paramref name="buffer"/>
58
+ /// and applies it to the given <see cref="TMP_Text"/> without allocations.
59
+ /// </summary>
60
+ public static void SetScoreNoAlloc(TMP_Text text, int value, char[] buffer)
61
+ {
62
+ int len = FormatIntWithCommas(value, buffer);
63
+ text.SetCharArray(buffer, 0, len);
64
+ }
65
+ }
66
+ }
67
+
@@ -0,0 +1,2 @@
1
+ fileFormatVersion: 2
2
+ guid: 759fa1992061f1d42b7eeef01700a5a7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "app.hypergames.hypersdk",
3
- "version": "1.4.21",
3
+ "version": "1.5.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",