steamworks-ffi-node 0.3.1 → 0.4.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.
Files changed (57) hide show
  1. package/README.md +53 -20
  2. package/dist/index.d.ts +4 -3
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +24 -2
  5. package/dist/index.js.map +1 -1
  6. package/dist/internal/SteamAPICore.d.ts +32 -9
  7. package/dist/internal/SteamAPICore.d.ts.map +1 -1
  8. package/dist/internal/SteamAPICore.js +46 -15
  9. package/dist/internal/SteamAPICore.js.map +1 -1
  10. package/dist/internal/SteamAchievementManager.d.ts +25 -25
  11. package/dist/internal/SteamAchievementManager.js +26 -26
  12. package/dist/internal/SteamAchievementManager.js.map +1 -1
  13. package/dist/internal/SteamCallbackPoller.d.ts +68 -0
  14. package/dist/internal/SteamCallbackPoller.d.ts.map +1 -0
  15. package/dist/internal/SteamCallbackPoller.js +134 -0
  16. package/dist/internal/SteamCallbackPoller.js.map +1 -0
  17. package/dist/internal/SteamLeaderboardManager.d.ts +338 -0
  18. package/dist/internal/SteamLeaderboardManager.d.ts.map +1 -0
  19. package/dist/internal/SteamLeaderboardManager.js +734 -0
  20. package/dist/internal/SteamLeaderboardManager.js.map +1 -0
  21. package/dist/internal/SteamLibraryLoader.d.ts +15 -0
  22. package/dist/internal/SteamLibraryLoader.d.ts.map +1 -1
  23. package/dist/internal/SteamLibraryLoader.js +26 -0
  24. package/dist/internal/SteamLibraryLoader.js.map +1 -1
  25. package/dist/internal/SteamStatsManager.d.ts +57 -45
  26. package/dist/internal/SteamStatsManager.d.ts.map +1 -1
  27. package/dist/internal/SteamStatsManager.js +146 -101
  28. package/dist/internal/SteamStatsManager.js.map +1 -1
  29. package/dist/steam.d.ts +115 -172
  30. package/dist/steam.d.ts.map +1 -1
  31. package/dist/steam.js +24 -241
  32. package/dist/steam.js.map +1 -1
  33. package/dist/{types.d.ts → types/achievements.d.ts} +19 -30
  34. package/dist/types/achievements.d.ts.map +1 -0
  35. package/dist/types/achievements.js +6 -0
  36. package/dist/types/achievements.js.map +1 -0
  37. package/dist/types/core.d.ts +18 -0
  38. package/dist/types/core.d.ts.map +1 -0
  39. package/dist/types/core.js +6 -0
  40. package/dist/types/core.js.map +1 -0
  41. package/dist/types/index.d.ts +14 -0
  42. package/dist/types/index.d.ts.map +1 -0
  43. package/dist/types/index.js +34 -0
  44. package/dist/types/index.js.map +1 -0
  45. package/dist/types/leaderboards.d.ts +121 -0
  46. package/dist/types/leaderboards.d.ts.map +1 -0
  47. package/dist/types/leaderboards.js +45 -0
  48. package/dist/types/leaderboards.js.map +1 -0
  49. package/dist/types/stats.d.ts +37 -0
  50. package/dist/types/stats.d.ts.map +1 -0
  51. package/dist/types/stats.js +6 -0
  52. package/dist/types/stats.js.map +1 -0
  53. package/package.json +4 -3
  54. package/dist/types.d.ts.map +0 -1
  55. package/dist/types.js +0 -3
  56. package/dist/types.js.map +0 -1
  57. package/steamworks_sdk/README.md +0 -82
@@ -82,13 +82,14 @@ class SteamStatsManager {
82
82
  * that track player progress and can be used for leaderboards and analytics.
83
83
  *
84
84
  * @param statName - Name of the stat to retrieve (as defined in Steamworks Partner site)
85
- * @returns The stat value, or null if not found or on error
85
+ * @returns SteamStat object with name, value, and type, or null if not found or on error
86
86
  *
87
87
  * @example
88
88
  * ```typescript
89
- * const totalKills = await statsManager.getStatInt('total_kills');
90
- * if (totalKills !== null) {
91
- * console.log(`Total kills: ${totalKills}`);
89
+ * const killsStat = await statsManager.getStatInt('total_kills');
90
+ * if (killsStat) {
91
+ * console.log(`[Steamworks] ${killsStat.name}: ${killsStat.value}`);
92
+ * // Access value directly: killsStat.value
92
93
  * }
93
94
  * ```
94
95
  *
@@ -96,13 +97,14 @@ class SteamStatsManager {
96
97
  * - Returns null if Steam API is not initialized
97
98
  * - Stat names are case-sensitive and must match Steamworks configuration
98
99
  * - Use getStatFloat() for decimal values
100
+ * - Returns structured SteamStat object with full metadata
99
101
  *
100
102
  * Steamworks SDK Functions:
101
103
  * - `SteamAPI_ISteamUserStats_GetStatInt32()` - Get int32 stat value
102
104
  */
103
105
  async getStatInt(statName) {
104
106
  if (!this.apiCore.isInitialized()) {
105
- console.warn('⚠️ Steam API not initialized');
107
+ console.warn('[Steamworks] Steam API not initialized');
106
108
  return null;
107
109
  }
108
110
  try {
@@ -111,16 +113,20 @@ class SteamStatsManager {
111
113
  const success = this.libraryLoader.SteamAPI_ISteamUserStats_GetStatInt32(userStatsInterface, statName, valueOut);
112
114
  if (success) {
113
115
  const value = koffi.decode(valueOut, 'int32');
114
- console.log(`📊 Got stat "${statName}": ${value}`);
115
- return value;
116
+ console.log(`[Steamworks] Got stat "${statName}": ${value}`);
117
+ return {
118
+ name: statName,
119
+ value,
120
+ type: 'int'
121
+ };
116
122
  }
117
123
  else {
118
- console.warn(`⚠️ Failed to get stat: ${statName}`);
124
+ console.warn(`[Steamworks] Failed to get stat: ${statName}`);
119
125
  return null;
120
126
  }
121
127
  }
122
128
  catch (error) {
123
- console.error(`❌ Error getting stat "${statName}":`, error.message);
129
+ console.error(`[Steamworks] Error getting stat "${statName}":`, error.message);
124
130
  return null;
125
131
  }
126
132
  }
@@ -131,26 +137,27 @@ class SteamStatsManager {
131
137
  * require decimal precision (e.g., average accuracy, distance traveled).
132
138
  *
133
139
  * @param statName - Name of the stat to retrieve (as defined in Steamworks Partner site)
134
- * @returns The stat value, or null if not found or on error
140
+ * @returns SteamStat object with name, value, and type, or null if not found or on error
135
141
  *
136
142
  * @example
137
143
  * ```typescript
138
- * const accuracy = await statsManager.getStatFloat('shooting_accuracy');
139
- * if (accuracy !== null) {
140
- * console.log(`Accuracy: ${(accuracy * 100).toFixed(2)}%`);
144
+ * const accuracyStat = await statsManager.getStatFloat('shooting_accuracy');
145
+ * if (accuracyStat) {
146
+ * console.log(`[Steamworks] ${accuracyStat.name}: ${(accuracyStat.value * 100).toFixed(2)}%`);
141
147
  * }
142
148
  * ```
143
149
  *
144
150
  * @remarks
145
151
  * - Returns null if Steam API is not initialized
146
152
  * - Use getStatInt() for whole number values
153
+ * - Returns structured SteamStat object with full metadata
147
154
  *
148
155
  * Steamworks SDK Functions:
149
156
  * - `SteamAPI_ISteamUserStats_GetStatFloat()` - Get float stat value
150
157
  */
151
158
  async getStatFloat(statName) {
152
159
  if (!this.apiCore.isInitialized()) {
153
- console.warn('⚠️ Steam API not initialized');
160
+ console.warn('[Steamworks] Steam API not initialized');
154
161
  return null;
155
162
  }
156
163
  try {
@@ -159,16 +166,20 @@ class SteamStatsManager {
159
166
  const success = this.libraryLoader.SteamAPI_ISteamUserStats_GetStatFloat(userStatsInterface, statName, valueOut);
160
167
  if (success) {
161
168
  const value = koffi.decode(valueOut, 'float');
162
- console.log(`📊 Got stat "${statName}": ${value}`);
163
- return value;
169
+ console.log(`[Steamworks] Got stat "${statName}": ${value}`);
170
+ return {
171
+ name: statName,
172
+ value,
173
+ type: 'float'
174
+ };
164
175
  }
165
176
  else {
166
- console.warn(`⚠️ Failed to get stat: ${statName}`);
177
+ console.warn(`[Steamworks] Failed to get stat: ${statName}`);
167
178
  return null;
168
179
  }
169
180
  }
170
181
  catch (error) {
171
- console.error(`❌ Error getting stat "${statName}":`, error.message);
182
+ console.error(`[Steamworks] Error getting stat "${statName}":`, error.message);
172
183
  return null;
173
184
  }
174
185
  }
@@ -188,7 +199,7 @@ class SteamStatsManager {
188
199
  * const currentKills = await statsManager.getStatInt('total_kills') || 0;
189
200
  * const success = await statsManager.setStatInt('total_kills', currentKills + 1);
190
201
  * if (success) {
191
- * console.log('Kill count updated!');
202
+ * console.log('[Steamworks] Kill count updated!');
192
203
  * }
193
204
  * ```
194
205
  *
@@ -205,7 +216,7 @@ class SteamStatsManager {
205
216
  */
206
217
  async setStatInt(statName, value) {
207
218
  if (!this.apiCore.isInitialized()) {
208
- console.warn('⚠️ Steam API not initialized');
219
+ console.warn('[Steamworks] Steam API not initialized');
209
220
  return false;
210
221
  }
211
222
  try {
@@ -215,23 +226,23 @@ class SteamStatsManager {
215
226
  // Store the stats to Steam servers
216
227
  const stored = this.libraryLoader.SteamAPI_ISteamUserStats_StoreStats(userStatsInterface);
217
228
  if (stored) {
218
- console.log(`✅ Set stat "${statName}" to ${value}`);
229
+ console.log(`[Steamworks] Set stat "${statName}" to ${value}`);
219
230
  // Process callbacks
220
231
  this.libraryLoader.SteamAPI_RunCallbacks();
221
232
  return true;
222
233
  }
223
234
  else {
224
- console.warn(`⚠️ Failed to store stat: ${statName}`);
235
+ console.warn(`[Steamworks] Failed to store stat: ${statName}`);
225
236
  return false;
226
237
  }
227
238
  }
228
239
  else {
229
- console.warn(`⚠️ Failed to set stat: ${statName}`);
240
+ console.warn(`[Steamworks] Failed to set stat: ${statName}`);
230
241
  return false;
231
242
  }
232
243
  }
233
244
  catch (error) {
234
- console.error(`❌ Error setting stat "${statName}":`, error.message);
245
+ console.error(`[Steamworks] Error setting stat "${statName}":`, error.message);
235
246
  return false;
236
247
  }
237
248
  }
@@ -266,7 +277,7 @@ class SteamStatsManager {
266
277
  */
267
278
  async setStatFloat(statName, value) {
268
279
  if (!this.apiCore.isInitialized()) {
269
- console.warn('⚠️ Steam API not initialized');
280
+ console.warn('[Steamworks] Steam API not initialized');
270
281
  return false;
271
282
  }
272
283
  try {
@@ -276,23 +287,23 @@ class SteamStatsManager {
276
287
  // Store the stats to Steam servers
277
288
  const stored = this.libraryLoader.SteamAPI_ISteamUserStats_StoreStats(userStatsInterface);
278
289
  if (stored) {
279
- console.log(`✅ Set stat "${statName}" to ${value}`);
290
+ console.log(`[Steamworks] Set stat "${statName}" to ${value}`);
280
291
  // Process callbacks
281
292
  this.libraryLoader.SteamAPI_RunCallbacks();
282
293
  return true;
283
294
  }
284
295
  else {
285
- console.warn(`⚠️ Failed to store stat: ${statName}`);
296
+ console.warn(`[Steamworks] Failed to store stat: ${statName}`);
286
297
  return false;
287
298
  }
288
299
  }
289
300
  else {
290
- console.warn(`⚠️ Failed to set stat: ${statName}`);
301
+ console.warn(`[Steamworks] Failed to set stat: ${statName}`);
291
302
  return false;
292
303
  }
293
304
  }
294
305
  catch (error) {
295
- console.error(`❌ Error setting stat "${statName}":`, error.message);
306
+ console.error(`[Steamworks] Error setting stat "${statName}":`, error.message);
296
307
  return false;
297
308
  }
298
309
  }
@@ -329,7 +340,7 @@ class SteamStatsManager {
329
340
  */
330
341
  async updateAvgRateStat(statName, countThisSession, sessionLength) {
331
342
  if (!this.apiCore.isInitialized()) {
332
- console.warn('⚠️ Steam API not initialized');
343
+ console.warn('[Steamworks] Steam API not initialized');
333
344
  return false;
334
345
  }
335
346
  try {
@@ -339,23 +350,23 @@ class SteamStatsManager {
339
350
  // Store the stats to Steam servers
340
351
  const stored = this.libraryLoader.SteamAPI_ISteamUserStats_StoreStats(userStatsInterface);
341
352
  if (stored) {
342
- console.log(`✅ Updated avg rate stat "${statName}": ${countThisSession} over ${sessionLength}s`);
353
+ console.log(`[Steamworks] Updated avg rate stat "${statName}": ${countThisSession} over ${sessionLength}s`);
343
354
  // Process callbacks
344
355
  this.libraryLoader.SteamAPI_RunCallbacks();
345
356
  return true;
346
357
  }
347
358
  else {
348
- console.warn(`⚠️ Failed to store stat: ${statName}`);
359
+ console.warn(`[Steamworks] Failed to store stat: ${statName}`);
349
360
  return false;
350
361
  }
351
362
  }
352
363
  else {
353
- console.warn(`⚠️ Failed to update avg rate stat: ${statName}`);
364
+ console.warn(`[Steamworks] Failed to update avg rate stat: ${statName}`);
354
365
  return false;
355
366
  }
356
367
  }
357
368
  catch (error) {
358
- console.error(`❌ Error updating avg rate stat "${statName}":`, error.message);
369
+ console.error(`[Steamworks] Error updating avg rate stat "${statName}":`, error.message);
359
370
  return false;
360
371
  }
361
372
  }
@@ -384,7 +395,7 @@ class SteamStatsManager {
384
395
  *
385
396
  * // Now get the friend's stats
386
397
  * const friendKills = await statsManager.getUserStatInt(friendSteamId, 'total_kills');
387
- * console.log(`Friend has ${friendKills} kills`);
398
+ * console.log(`[Steamworks] Friend has ${friendKills} kills`);
388
399
  * }
389
400
  * ```
390
401
  *
@@ -399,7 +410,7 @@ class SteamStatsManager {
399
410
  */
400
411
  async requestUserStats(steamId) {
401
412
  if (!this.apiCore.isInitialized()) {
402
- console.warn('⚠️ Steam API not initialized');
413
+ console.warn('[Steamworks] Steam API not initialized');
403
414
  return false;
404
415
  }
405
416
  try {
@@ -407,16 +418,16 @@ class SteamStatsManager {
407
418
  const steamIdBigInt = typeof steamId === 'string' ? BigInt(steamId) : steamId;
408
419
  const callHandle = this.libraryLoader.SteamAPI_ISteamUserStats_RequestUserStats(userStatsInterface, steamIdBigInt);
409
420
  if (callHandle !== BigInt(0)) {
410
- console.log(`📡 Requested stats for user: ${steamId}`);
421
+ console.log(`[Steamworks] Requested stats for user: ${steamId}`);
411
422
  return true;
412
423
  }
413
424
  else {
414
- console.warn(`⚠️ Failed to request user stats: ${steamId}`);
425
+ console.warn(`[Steamworks] Failed to request user stats: ${steamId}`);
415
426
  return false;
416
427
  }
417
428
  }
418
429
  catch (error) {
419
- console.error(`❌ Error requesting user stats:`, error.message);
430
+ console.error(`[Steamworks] Error requesting user stats:`, error.message);
420
431
  return false;
421
432
  }
422
433
  }
@@ -428,7 +439,7 @@ class SteamStatsManager {
428
439
  *
429
440
  * @param steamId - Steam ID of the user
430
441
  * @param statName - Name of the stat to retrieve
431
- * @returns The stat value, or null if not found or on error
442
+ * @returns UserStat object with steamId, name, value, and type, or null if not found or on error
432
443
  *
433
444
  * @example
434
445
  * ```typescript
@@ -437,23 +448,26 @@ class SteamStatsManager {
437
448
  * await statsManager.requestUserStats(friendId);
438
449
  * await new Promise(resolve => setTimeout(resolve, 100));
439
450
  *
440
- * const myKills = await statsManager.getStatInt('total_kills') || 0;
441
- * const friendKills = await statsManager.getUserStatInt(friendId, 'total_kills') || 0;
451
+ * const myStat = await statsManager.getStatInt('total_kills');
452
+ * const friendStat = await statsManager.getUserStatInt(friendId, 'total_kills');
442
453
  *
443
- * console.log(`You: ${myKills}, Friend: ${friendKills}`);
454
+ * if (myStat && friendStat) {
455
+ * console.log(`[Steamworks] You: ${myStat.value}, Friend: ${friendStat.value}`);
456
+ * }
444
457
  * ```
445
458
  *
446
459
  * @remarks
447
460
  * - Must call requestUserStats() first
448
461
  * - Wait 50-100ms after requesting before calling this
449
462
  * - Returns null if stats haven't arrived yet or user's stats are private
463
+ * - Returns structured UserStat object with full metadata including steamId
450
464
  *
451
465
  * Steamworks SDK Functions:
452
466
  * - `SteamAPI_ISteamUserStats_GetUserStatInt32()` - Get user's int32 stat value
453
467
  */
454
468
  async getUserStatInt(steamId, statName) {
455
469
  if (!this.apiCore.isInitialized()) {
456
- console.warn('⚠️ Steam API not initialized');
470
+ console.warn('[Steamworks] Steam API not initialized');
457
471
  return null;
458
472
  }
459
473
  try {
@@ -463,16 +477,21 @@ class SteamStatsManager {
463
477
  const success = this.libraryLoader.SteamAPI_ISteamUserStats_GetUserStatInt32(userStatsInterface, steamIdBigInt, statName, valueOut);
464
478
  if (success) {
465
479
  const value = koffi.decode(valueOut, 'int32');
466
- console.log(`📊 Got user stat "${statName}" for ${steamId}: ${value}`);
467
- return value;
480
+ console.log(`[Steamworks] Got user stat "${statName}" for ${steamId}: ${value}`);
481
+ return {
482
+ steamId: typeof steamId === 'string' ? steamId : steamId.toString(),
483
+ name: statName,
484
+ value,
485
+ type: 'int'
486
+ };
468
487
  }
469
488
  else {
470
- console.warn(`⚠️ Failed to get user stat: ${statName}`);
489
+ console.warn(`[Steamworks] Failed to get user stat: ${statName}`);
471
490
  return null;
472
491
  }
473
492
  }
474
493
  catch (error) {
475
- console.error(`❌ Error getting user stat "${statName}":`, error.message);
494
+ console.error(`[Steamworks] Error getting user stat "${statName}":`, error.message);
476
495
  return null;
477
496
  }
478
497
  }
@@ -484,7 +503,7 @@ class SteamStatsManager {
484
503
  *
485
504
  * @param steamId - Steam ID of the user
486
505
  * @param statName - Name of the stat to retrieve
487
- * @returns The stat value, or null if not found or on error
506
+ * @returns UserStat object with steamId, name, value, and type, or null if not found or on error
488
507
  *
489
508
  * @example
490
509
  * ```typescript
@@ -493,9 +512,9 @@ class SteamStatsManager {
493
512
  * await statsManager.requestUserStats(friendId);
494
513
  * await new Promise(resolve => setTimeout(resolve, 100));
495
514
  *
496
- * const friendAccuracy = await statsManager.getUserStatFloat(friendId, 'shooting_accuracy');
497
- * if (friendAccuracy !== null) {
498
- * console.log(`Friend accuracy: ${(friendAccuracy * 100).toFixed(2)}%`);
515
+ * const friendStat = await statsManager.getUserStatFloat(friendId, 'shooting_accuracy');
516
+ * if (friendStat) {
517
+ * console.log(`[Steamworks] Friend accuracy: ${(friendStat.value * 100).toFixed(2)}%`);
499
518
  * }
500
519
  * ```
501
520
  *
@@ -503,13 +522,14 @@ class SteamStatsManager {
503
522
  * - Must call requestUserStats() first
504
523
  * - Wait 50-100ms after requesting before calling this
505
524
  * - Returns null if stats haven't arrived yet or user's stats are private
525
+ * - Returns structured UserStat object with full metadata including steamId
506
526
  *
507
527
  * Steamworks SDK Functions:
508
528
  * - `SteamAPI_ISteamUserStats_GetUserStatFloat()` - Get user's float stat value
509
529
  */
510
530
  async getUserStatFloat(steamId, statName) {
511
531
  if (!this.apiCore.isInitialized()) {
512
- console.warn('⚠️ Steam API not initialized');
532
+ console.warn('[Steamworks] Steam API not initialized');
513
533
  return null;
514
534
  }
515
535
  try {
@@ -519,16 +539,21 @@ class SteamStatsManager {
519
539
  const success = this.libraryLoader.SteamAPI_ISteamUserStats_GetUserStatFloat(userStatsInterface, steamIdBigInt, statName, valueOut);
520
540
  if (success) {
521
541
  const value = koffi.decode(valueOut, 'float');
522
- console.log(`📊 Got user stat "${statName}" for ${steamId}: ${value}`);
523
- return value;
542
+ console.log(`[Steamworks] Got user stat "${statName}" for ${steamId}: ${value}`);
543
+ return {
544
+ steamId: typeof steamId === 'string' ? steamId : steamId.toString(),
545
+ name: statName,
546
+ value,
547
+ type: 'float'
548
+ };
524
549
  }
525
550
  else {
526
- console.warn(`⚠️ Failed to get user stat: ${statName}`);
551
+ console.warn(`[Steamworks] Failed to get user stat: ${statName}`);
527
552
  return null;
528
553
  }
529
554
  }
530
555
  catch (error) {
531
- console.error(`❌ Error getting user stat "${statName}":`, error.message);
556
+ console.error(`[Steamworks] Error getting user stat "${statName}":`, error.message);
532
557
  return null;
533
558
  }
534
559
  }
@@ -555,7 +580,7 @@ class SteamStatsManager {
555
580
  * await new Promise(resolve => setTimeout(resolve, 100));
556
581
  *
557
582
  * const totalKills = await statsManager.getGlobalStatInt('total_kills');
558
- * console.log(`All players combined: ${totalKills} kills`);
583
+ * console.log(`[Steamworks] All players combined: ${totalKills} kills`);
559
584
  * ```
560
585
  *
561
586
  * @remarks
@@ -570,7 +595,7 @@ class SteamStatsManager {
570
595
  */
571
596
  async requestGlobalStats(historyDays = 0) {
572
597
  if (!this.apiCore.isInitialized()) {
573
- console.warn('⚠️ Steam API not initialized');
598
+ console.warn('[Steamworks] Steam API not initialized');
574
599
  return false;
575
600
  }
576
601
  try {
@@ -579,16 +604,16 @@ class SteamStatsManager {
579
604
  const userStatsInterface = this.libraryLoader.SteamAPI_SteamUserStats_v013();
580
605
  const callHandle = this.libraryLoader.SteamAPI_ISteamUserStats_RequestGlobalStats(userStatsInterface, days);
581
606
  if (callHandle !== BigInt(0)) {
582
- console.log(`📡 Requested global stats with ${days} days of history`);
607
+ console.log(`[Steamworks] Requested global stats with ${days} days of history`);
583
608
  return true;
584
609
  }
585
610
  else {
586
- console.warn(`⚠️ Failed to request global stats`);
611
+ console.warn(`[Steamworks] Failed to request global stats`);
587
612
  return false;
588
613
  }
589
614
  }
590
615
  catch (error) {
591
- console.error(`❌ Error requesting global stats:`, error.message);
616
+ console.error(`[Steamworks] Error requesting global stats:`, error.message);
592
617
  return false;
593
618
  }
594
619
  }
@@ -599,7 +624,7 @@ class SteamStatsManager {
599
624
  * Must call requestGlobalStats() first and wait for the data to arrive.
600
625
  *
601
626
  * @param statName - Name of the global stat to retrieve
602
- * @returns The stat value as BigInt, or null if not found or on error
627
+ * @returns GlobalStat object with name, value, and type, or null if not found or on error
603
628
  *
604
629
  * @example
605
630
  * ```typescript
@@ -607,24 +632,25 @@ class SteamStatsManager {
607
632
  * await statsManager.requestGlobalStats();
608
633
  * await new Promise(resolve => setTimeout(resolve, 100));
609
634
  *
610
- * const globalKills = await statsManager.getGlobalStatInt('total_kills');
611
- * if (globalKills !== null) {
612
- * console.log(`All players have ${globalKills} total kills`);
635
+ * const globalStat = await statsManager.getGlobalStatInt('total_kills');
636
+ * if (globalStat) {
637
+ * console.log(`[Steamworks] ${globalStat.name}: ${globalStat.value}`);
613
638
  * }
614
639
  * ```
615
640
  *
616
641
  * @remarks
617
- * - Returns BigInt for large numbers (can exceed JavaScript's safe integer range)
618
642
  * - Must call requestGlobalStats() first
619
643
  * - Wait 50-100ms after requesting before calling this
620
644
  * - Useful for tracking game-wide statistics
645
+ * - Returns structured GlobalStat object with full metadata
646
+ * - Value is number (BigInt converted to number for consistency)
621
647
  *
622
648
  * Steamworks SDK Functions:
623
649
  * - `SteamAPI_ISteamUserStats_GetGlobalStatInt64()` - Get global int64 stat value
624
650
  */
625
651
  async getGlobalStatInt(statName) {
626
652
  if (!this.apiCore.isInitialized()) {
627
- console.warn('⚠️ Steam API not initialized');
653
+ console.warn('[Steamworks] Steam API not initialized');
628
654
  return null;
629
655
  }
630
656
  try {
@@ -633,16 +659,20 @@ class SteamStatsManager {
633
659
  const success = this.libraryLoader.SteamAPI_ISteamUserStats_GetGlobalStatInt64(userStatsInterface, statName, valueOut);
634
660
  if (success) {
635
661
  const value = koffi.decode(valueOut, 'int64');
636
- console.log(`🌍 Got global stat "${statName}": ${value}`);
637
- return value;
662
+ console.log(`[Steamworks] Got global stat "${statName}": ${value}`);
663
+ return {
664
+ name: statName,
665
+ value: Number(value),
666
+ type: 'int64'
667
+ };
638
668
  }
639
669
  else {
640
- console.warn(`⚠️ Failed to get global stat: ${statName}`);
670
+ console.warn(`[Steamworks] Failed to get global stat: ${statName}`);
641
671
  return null;
642
672
  }
643
673
  }
644
674
  catch (error) {
645
- console.error(`❌ Error getting global stat "${statName}":`, error.message);
675
+ console.error(`[Steamworks] Error getting global stat "${statName}":`, error.message);
646
676
  return null;
647
677
  }
648
678
  }
@@ -654,7 +684,7 @@ class SteamStatsManager {
654
684
  * Use this for averages or stats requiring decimal precision.
655
685
  *
656
686
  * @param statName - Name of the global stat to retrieve
657
- * @returns The stat value, or null if not found or on error
687
+ * @returns GlobalStat object with name, value, and type, or null if not found or on error
658
688
  *
659
689
  * @example
660
690
  * ```typescript
@@ -662,9 +692,9 @@ class SteamStatsManager {
662
692
  * await statsManager.requestGlobalStats();
663
693
  * await new Promise(resolve => setTimeout(resolve, 100));
664
694
  *
665
- * const avgAccuracy = await statsManager.getGlobalStatDouble('average_accuracy');
666
- * if (avgAccuracy !== null) {
667
- * console.log(`Global average accuracy: ${(avgAccuracy * 100).toFixed(2)}%`);
695
+ * const avgStat = await statsManager.getGlobalStatDouble('average_accuracy');
696
+ * if (avgStat) {
697
+ * console.log(`[Steamworks] ${avgStat.name}: ${(avgStat.value * 100).toFixed(2)}%`);
668
698
  * }
669
699
  * ```
670
700
  *
@@ -673,13 +703,14 @@ class SteamStatsManager {
673
703
  * - Must call requestGlobalStats() first
674
704
  * - Wait 50-100ms after requesting before calling this
675
705
  * - Perfect for calculating game-wide averages
706
+ * - Returns structured GlobalStat object with full metadata
676
707
  *
677
708
  * Steamworks SDK Functions:
678
709
  * - `SteamAPI_ISteamUserStats_GetGlobalStatDouble()` - Get global double stat value
679
710
  */
680
711
  async getGlobalStatDouble(statName) {
681
712
  if (!this.apiCore.isInitialized()) {
682
- console.warn('⚠️ Steam API not initialized');
713
+ console.warn('[Steamworks] Steam API not initialized');
683
714
  return null;
684
715
  }
685
716
  try {
@@ -688,16 +719,20 @@ class SteamStatsManager {
688
719
  const success = this.libraryLoader.SteamAPI_ISteamUserStats_GetGlobalStatDouble(userStatsInterface, statName, valueOut);
689
720
  if (success) {
690
721
  const value = koffi.decode(valueOut, 'double');
691
- console.log(`🌍 Got global stat "${statName}": ${value}`);
692
- return value;
722
+ console.log(`[Steamworks] Got global stat "${statName}": ${value}`);
723
+ return {
724
+ name: statName,
725
+ value,
726
+ type: 'double'
727
+ };
693
728
  }
694
729
  else {
695
- console.warn(`⚠️ Failed to get global stat: ${statName}`);
730
+ console.warn(`[Steamworks] Failed to get global stat: ${statName}`);
696
731
  return null;
697
732
  }
698
733
  }
699
734
  catch (error) {
700
- console.error(`❌ Error getting global stat "${statName}":`, error.message);
735
+ console.error(`[Steamworks] Error getting global stat "${statName}":`, error.message);
701
736
  return null;
702
737
  }
703
738
  }
@@ -709,7 +744,7 @@ class SteamStatsManager {
709
744
  *
710
745
  * @param statName - Name of the global stat
711
746
  * @param days - Number of days of history to retrieve (1-60, default: 7)
712
- * @returns Array of daily BigInt values, or null if error
747
+ * @returns GlobalStatHistory object with name, history array, and type, or null if error
713
748
  *
714
749
  * @example
715
750
  * ```typescript
@@ -719,10 +754,10 @@ class SteamStatsManager {
719
754
  *
720
755
  * const history = await statsManager.getGlobalStatHistoryInt('total_kills', 7);
721
756
  * if (history) {
722
- * console.log('Kill history (newest to oldest):');
723
- * history.forEach((kills, index) => {
757
+ * console.log(`[Steamworks] ${history.name} history (${history.type}):`);
758
+ * history.history.forEach((kills, index) => {
724
759
  * const daysAgo = index === 0 ? 'today' : `${index} days ago`;
725
- * console.log(` ${daysAgo}: ${kills} kills`);
760
+ * console.log(`[Steamworks] ${daysAgo}: ${kills} kills`);
726
761
  * });
727
762
  * }
728
763
  * ```
@@ -730,7 +765,8 @@ class SteamStatsManager {
730
765
  * @remarks
731
766
  * - Array index [0] = today, [1] = yesterday, etc.
732
767
  * - Must call requestGlobalStats(days) first with same or greater number of days
733
- * - Returns BigInt values for large numbers
768
+ * - Returns structured GlobalStatHistory object with full metadata
769
+ * - Values are numbers (BigInt converted to number for consistency)
734
770
  * - Maximum 60 days of history (automatically clamped)
735
771
  * - Perfect for trend analysis and visualizations
736
772
  *
@@ -739,7 +775,7 @@ class SteamStatsManager {
739
775
  */
740
776
  async getGlobalStatHistoryInt(statName, days = 7) {
741
777
  if (!this.apiCore.isInitialized()) {
742
- console.warn('⚠️ Steam API not initialized');
778
+ console.warn('[Steamworks] Steam API not initialized');
743
779
  return null;
744
780
  }
745
781
  try {
@@ -751,18 +787,22 @@ class SteamStatsManager {
751
787
  if (elementsReturned > 0) {
752
788
  const history = [];
753
789
  for (let i = 0; i < elementsReturned; i++) {
754
- history.push(koffi.decode(historyOut, 'int64', i));
790
+ history.push(Number(koffi.decode(historyOut, 'int64', i))); // Convert BigInt to number
755
791
  }
756
- console.log(`🌍 Got ${elementsReturned} days of history for "${statName}"`);
757
- return history;
792
+ console.log(`[Steamworks] Got ${elementsReturned} days of history for "${statName}"`);
793
+ return {
794
+ name: statName,
795
+ history,
796
+ type: 'int64'
797
+ };
758
798
  }
759
799
  else {
760
- console.warn(`⚠️ Failed to get global stat history: ${statName}`);
800
+ console.warn(`[Steamworks] Failed to get global stat history: ${statName}`);
761
801
  return null;
762
802
  }
763
803
  }
764
804
  catch (error) {
765
- console.error(`❌ Error getting global stat history "${statName}":`, error.message);
805
+ console.error(`[Steamworks] Error getting global stat history "${statName}":`, error.message);
766
806
  return null;
767
807
  }
768
808
  }
@@ -775,7 +815,7 @@ class SteamStatsManager {
775
815
  *
776
816
  * @param statName - Name of the global stat
777
817
  * @param days - Number of days of history to retrieve (1-60, default: 7)
778
- * @returns Array of daily float values, or null if error
818
+ * @returns GlobalStatHistory object with name, history array, and type, or null if error
779
819
  *
780
820
  * @example
781
821
  * ```typescript
@@ -785,10 +825,10 @@ class SteamStatsManager {
785
825
  *
786
826
  * const history = await statsManager.getGlobalStatHistoryDouble('average_accuracy', 30);
787
827
  * if (history) {
788
- * console.log('Accuracy trend:');
789
- * history.forEach((accuracy, index) => {
828
+ * console.log(`[Steamworks] ${history.name} trend (${history.type}):`);
829
+ * history.history.forEach((accuracy, index) => {
790
830
  * if (index % 7 === 0) { // Weekly intervals
791
- * console.log(` Week ${index/7}: ${(accuracy * 100).toFixed(2)}%`);
831
+ * console.log(`[Steamworks] Week ${index/7}: ${(accuracy * 100).toFixed(2)}%`);
792
832
  * }
793
833
  * });
794
834
  * }
@@ -797,6 +837,7 @@ class SteamStatsManager {
797
837
  * @remarks
798
838
  * - Array index [0] = today, [1] = yesterday, etc.
799
839
  * - Must call requestGlobalStats(days) first with same or greater number of days
840
+ * - Returns structured GlobalStatHistory object with full metadata
800
841
  * - Returns floating-point values for decimal precision
801
842
  * - Maximum 60 days of history (automatically clamped)
802
843
  * - Perfect for tracking averages, rates, and percentages over time
@@ -806,7 +847,7 @@ class SteamStatsManager {
806
847
  */
807
848
  async getGlobalStatHistoryDouble(statName, days = 7) {
808
849
  if (!this.apiCore.isInitialized()) {
809
- console.warn('⚠️ Steam API not initialized');
850
+ console.warn('[Steamworks] Steam API not initialized');
810
851
  return null;
811
852
  }
812
853
  try {
@@ -820,16 +861,20 @@ class SteamStatsManager {
820
861
  for (let i = 0; i < elementsReturned; i++) {
821
862
  history.push(koffi.decode(historyOut, 'double', i));
822
863
  }
823
- console.log(`🌍 Got ${elementsReturned} days of history for "${statName}"`);
824
- return history;
864
+ console.log(`[Steamworks] Got ${elementsReturned} days of history for "${statName}"`);
865
+ return {
866
+ name: statName,
867
+ history,
868
+ type: 'double'
869
+ };
825
870
  }
826
871
  else {
827
- console.warn(`⚠️ Failed to get global stat history: ${statName}`);
872
+ console.warn(`[Steamworks] Failed to get global stat history: ${statName}`);
828
873
  return null;
829
874
  }
830
875
  }
831
876
  catch (error) {
832
- console.error(`❌ Error getting global stat history "${statName}":`, error.message);
877
+ console.error(`[Steamworks] Error getting global stat history "${statName}":`, error.message);
833
878
  return null;
834
879
  }
835
880
  }