steamworks-ffi-node 0.3.0 → 0.4.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/README.md +86 -10
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/SteamAPICore.d.ts +221 -8
- package/dist/internal/SteamAPICore.d.ts.map +1 -1
- package/dist/internal/SteamAPICore.js +234 -14
- package/dist/internal/SteamAPICore.js.map +1 -1
- package/dist/internal/SteamAchievementManager.d.ts +602 -31
- package/dist/internal/SteamAchievementManager.d.ts.map +1 -1
- package/dist/internal/SteamAchievementManager.js +601 -32
- package/dist/internal/SteamAchievementManager.js.map +1 -1
- package/dist/internal/SteamCallbackPoller.d.ts +68 -0
- package/dist/internal/SteamCallbackPoller.d.ts.map +1 -0
- package/dist/internal/SteamCallbackPoller.js +134 -0
- package/dist/internal/SteamCallbackPoller.js.map +1 -0
- package/dist/internal/SteamLeaderboardManager.d.ts +338 -0
- package/dist/internal/SteamLeaderboardManager.d.ts.map +1 -0
- package/dist/internal/SteamLeaderboardManager.js +734 -0
- package/dist/internal/SteamLeaderboardManager.js.map +1 -0
- package/dist/internal/SteamLibraryLoader.d.ts +15 -0
- package/dist/internal/SteamLibraryLoader.d.ts.map +1 -1
- package/dist/internal/SteamLibraryLoader.js +42 -5
- package/dist/internal/SteamLibraryLoader.js.map +1 -1
- package/dist/internal/SteamStatsManager.d.ts +357 -50
- package/dist/internal/SteamStatsManager.d.ts.map +1 -1
- package/dist/internal/SteamStatsManager.js +444 -106
- package/dist/internal/SteamStatsManager.js.map +1 -1
- package/dist/steam.d.ts +169 -9
- package/dist/steam.d.ts.map +1 -1
- package/dist/steam.js +178 -0
- package/dist/steam.js.map +1 -1
- package/dist/types.d.ts +91 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +34 -0
- package/dist/types.js.map +1 -1
- package/package.json +4 -3
|
@@ -36,10 +36,38 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.SteamStatsManager = void 0;
|
|
37
37
|
const koffi = __importStar(require("koffi"));
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
39
|
+
* SteamStatsManager
|
|
40
|
+
*
|
|
41
|
+
* Manages all Steam user statistics operations including:
|
|
42
|
+
* - User stats (get/set integer and float values)
|
|
43
|
+
* - Average rate stats (for tracking rates over time)
|
|
44
|
+
* - Friend/user stats (view stats of other players)
|
|
45
|
+
* - Global stats (aggregate statistics across all players)
|
|
46
|
+
* - Global stat history (historical data over time)
|
|
47
|
+
*
|
|
48
|
+
* Stats are different from achievements - they are numeric values that can increase/decrease
|
|
49
|
+
* and are used for leaderboards, progress tracking, and game analytics.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const statsManager = new SteamStatsManager(libraryLoader, apiCore);
|
|
54
|
+
*
|
|
55
|
+
* // Set and get player stats
|
|
56
|
+
* await statsManager.setStatInt('total_kills', 100);
|
|
57
|
+
* const kills = await statsManager.getStatInt('total_kills');
|
|
58
|
+
*
|
|
59
|
+
* // Get global stats
|
|
60
|
+
* await statsManager.requestGlobalStats(7);
|
|
61
|
+
* const globalKills = await statsManager.getGlobalStatInt('total_kills');
|
|
62
|
+
* ```
|
|
41
63
|
*/
|
|
42
64
|
class SteamStatsManager {
|
|
65
|
+
/**
|
|
66
|
+
* Creates a new SteamStatsManager instance
|
|
67
|
+
*
|
|
68
|
+
* @param libraryLoader - The Steam library loader for FFI calls
|
|
69
|
+
* @param apiCore - The Steam API core for lifecycle management
|
|
70
|
+
*/
|
|
43
71
|
constructor(libraryLoader, apiCore) {
|
|
44
72
|
this.libraryLoader = libraryLoader;
|
|
45
73
|
this.apiCore = apiCore;
|
|
@@ -48,17 +76,35 @@ class SteamStatsManager {
|
|
|
48
76
|
// User Stats Operations (Get/Set)
|
|
49
77
|
// ========================================
|
|
50
78
|
/**
|
|
51
|
-
* Get an integer stat value
|
|
79
|
+
* Get an integer stat value for the current user
|
|
52
80
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
81
|
+
* Retrieves a 32-bit integer stat value from Steam. Stats are numeric values
|
|
82
|
+
* that track player progress and can be used for leaderboards and analytics.
|
|
83
|
+
*
|
|
84
|
+
* @param statName - Name of the stat to retrieve (as defined in Steamworks Partner site)
|
|
85
|
+
* @returns SteamStat object with name, value, and type, or null if not found or on error
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
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
|
|
93
|
+
* }
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* @remarks
|
|
97
|
+
* - Returns null if Steam API is not initialized
|
|
98
|
+
* - Stat names are case-sensitive and must match Steamworks configuration
|
|
99
|
+
* - Use getStatFloat() for decimal values
|
|
100
|
+
* - Returns structured SteamStat object with full metadata
|
|
55
101
|
*
|
|
56
102
|
* Steamworks SDK Functions:
|
|
57
103
|
* - `SteamAPI_ISteamUserStats_GetStatInt32()` - Get int32 stat value
|
|
58
104
|
*/
|
|
59
105
|
async getStatInt(statName) {
|
|
60
106
|
if (!this.apiCore.isInitialized()) {
|
|
61
|
-
console.warn('
|
|
107
|
+
console.warn('[Steamworks] Steam API not initialized');
|
|
62
108
|
return null;
|
|
63
109
|
}
|
|
64
110
|
try {
|
|
@@ -67,31 +113,51 @@ class SteamStatsManager {
|
|
|
67
113
|
const success = this.libraryLoader.SteamAPI_ISteamUserStats_GetStatInt32(userStatsInterface, statName, valueOut);
|
|
68
114
|
if (success) {
|
|
69
115
|
const value = koffi.decode(valueOut, 'int32');
|
|
70
|
-
console.log(
|
|
71
|
-
return
|
|
116
|
+
console.log(`[Steamworks] Got stat "${statName}": ${value}`);
|
|
117
|
+
return {
|
|
118
|
+
name: statName,
|
|
119
|
+
value,
|
|
120
|
+
type: 'int'
|
|
121
|
+
};
|
|
72
122
|
}
|
|
73
123
|
else {
|
|
74
|
-
console.warn(
|
|
124
|
+
console.warn(`[Steamworks] Failed to get stat: ${statName}`);
|
|
75
125
|
return null;
|
|
76
126
|
}
|
|
77
127
|
}
|
|
78
128
|
catch (error) {
|
|
79
|
-
console.error(
|
|
129
|
+
console.error(`[Steamworks] Error getting stat "${statName}":`, error.message);
|
|
80
130
|
return null;
|
|
81
131
|
}
|
|
82
132
|
}
|
|
83
133
|
/**
|
|
84
|
-
* Get a float stat value
|
|
134
|
+
* Get a float stat value for the current user
|
|
85
135
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
136
|
+
* Retrieves a floating-point stat value from Steam. Use this for stats that
|
|
137
|
+
* require decimal precision (e.g., average accuracy, distance traveled).
|
|
138
|
+
*
|
|
139
|
+
* @param statName - Name of the stat to retrieve (as defined in Steamworks Partner site)
|
|
140
|
+
* @returns SteamStat object with name, value, and type, or null if not found or on error
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* const accuracyStat = await statsManager.getStatFloat('shooting_accuracy');
|
|
145
|
+
* if (accuracyStat) {
|
|
146
|
+
* console.log(`[Steamworks] ${accuracyStat.name}: ${(accuracyStat.value * 100).toFixed(2)}%`);
|
|
147
|
+
* }
|
|
148
|
+
* ```
|
|
149
|
+
*
|
|
150
|
+
* @remarks
|
|
151
|
+
* - Returns null if Steam API is not initialized
|
|
152
|
+
* - Use getStatInt() for whole number values
|
|
153
|
+
* - Returns structured SteamStat object with full metadata
|
|
88
154
|
*
|
|
89
155
|
* Steamworks SDK Functions:
|
|
90
156
|
* - `SteamAPI_ISteamUserStats_GetStatFloat()` - Get float stat value
|
|
91
157
|
*/
|
|
92
158
|
async getStatFloat(statName) {
|
|
93
159
|
if (!this.apiCore.isInitialized()) {
|
|
94
|
-
console.warn('
|
|
160
|
+
console.warn('[Steamworks] Steam API not initialized');
|
|
95
161
|
return null;
|
|
96
162
|
}
|
|
97
163
|
try {
|
|
@@ -100,26 +166,49 @@ class SteamStatsManager {
|
|
|
100
166
|
const success = this.libraryLoader.SteamAPI_ISteamUserStats_GetStatFloat(userStatsInterface, statName, valueOut);
|
|
101
167
|
if (success) {
|
|
102
168
|
const value = koffi.decode(valueOut, 'float');
|
|
103
|
-
console.log(
|
|
104
|
-
return
|
|
169
|
+
console.log(`[Steamworks] Got stat "${statName}": ${value}`);
|
|
170
|
+
return {
|
|
171
|
+
name: statName,
|
|
172
|
+
value,
|
|
173
|
+
type: 'float'
|
|
174
|
+
};
|
|
105
175
|
}
|
|
106
176
|
else {
|
|
107
|
-
console.warn(
|
|
177
|
+
console.warn(`[Steamworks] Failed to get stat: ${statName}`);
|
|
108
178
|
return null;
|
|
109
179
|
}
|
|
110
180
|
}
|
|
111
181
|
catch (error) {
|
|
112
|
-
console.error(
|
|
182
|
+
console.error(`[Steamworks] Error getting stat "${statName}":`, error.message);
|
|
113
183
|
return null;
|
|
114
184
|
}
|
|
115
185
|
}
|
|
116
186
|
/**
|
|
117
|
-
* Set an integer stat value
|
|
187
|
+
* Set an integer stat value for the current user
|
|
118
188
|
*
|
|
119
|
-
*
|
|
189
|
+
* Updates a 32-bit integer stat value and immediately stores it to Steam servers.
|
|
190
|
+
* The new value will be visible in your Steam profile and can trigger achievements.
|
|
191
|
+
*
|
|
192
|
+
* @param statName - Name of the stat to set (as defined in Steamworks Partner site)
|
|
120
193
|
* @param value - Integer value to set
|
|
121
194
|
* @returns true if successful, false otherwise
|
|
122
195
|
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* // Increment kill count
|
|
199
|
+
* const currentKills = await statsManager.getStatInt('total_kills') || 0;
|
|
200
|
+
* const success = await statsManager.setStatInt('total_kills', currentKills + 1);
|
|
201
|
+
* if (success) {
|
|
202
|
+
* console.log('[Steamworks] Kill count updated!');
|
|
203
|
+
* }
|
|
204
|
+
* ```
|
|
205
|
+
*
|
|
206
|
+
* @remarks
|
|
207
|
+
* - Automatically calls StoreStats() to save to Steam servers
|
|
208
|
+
* - Runs callbacks to process the store operation
|
|
209
|
+
* - Can trigger stat-based achievements
|
|
210
|
+
* - Use setStatFloat() for decimal values
|
|
211
|
+
*
|
|
123
212
|
* Steamworks SDK Functions:
|
|
124
213
|
* - `SteamAPI_ISteamUserStats_SetStatInt32()` - Set int32 stat value
|
|
125
214
|
* - `SteamAPI_ISteamUserStats_StoreStats()` - Store stats to Steam servers
|
|
@@ -127,7 +216,7 @@ class SteamStatsManager {
|
|
|
127
216
|
*/
|
|
128
217
|
async setStatInt(statName, value) {
|
|
129
218
|
if (!this.apiCore.isInitialized()) {
|
|
130
|
-
console.warn('
|
|
219
|
+
console.warn('[Steamworks] Steam API not initialized');
|
|
131
220
|
return false;
|
|
132
221
|
}
|
|
133
222
|
try {
|
|
@@ -137,33 +226,50 @@ class SteamStatsManager {
|
|
|
137
226
|
// Store the stats to Steam servers
|
|
138
227
|
const stored = this.libraryLoader.SteamAPI_ISteamUserStats_StoreStats(userStatsInterface);
|
|
139
228
|
if (stored) {
|
|
140
|
-
console.log(
|
|
229
|
+
console.log(`[Steamworks] Set stat "${statName}" to ${value}`);
|
|
141
230
|
// Process callbacks
|
|
142
231
|
this.libraryLoader.SteamAPI_RunCallbacks();
|
|
143
232
|
return true;
|
|
144
233
|
}
|
|
145
234
|
else {
|
|
146
|
-
console.warn(
|
|
235
|
+
console.warn(`[Steamworks] Failed to store stat: ${statName}`);
|
|
147
236
|
return false;
|
|
148
237
|
}
|
|
149
238
|
}
|
|
150
239
|
else {
|
|
151
|
-
console.warn(
|
|
240
|
+
console.warn(`[Steamworks] Failed to set stat: ${statName}`);
|
|
152
241
|
return false;
|
|
153
242
|
}
|
|
154
243
|
}
|
|
155
244
|
catch (error) {
|
|
156
|
-
console.error(
|
|
245
|
+
console.error(`[Steamworks] Error setting stat "${statName}":`, error.message);
|
|
157
246
|
return false;
|
|
158
247
|
}
|
|
159
248
|
}
|
|
160
249
|
/**
|
|
161
|
-
* Set a float stat value
|
|
250
|
+
* Set a float stat value for the current user
|
|
162
251
|
*
|
|
163
|
-
*
|
|
252
|
+
* Updates a floating-point stat value and immediately stores it to Steam servers.
|
|
253
|
+
* Use this for stats requiring decimal precision.
|
|
254
|
+
*
|
|
255
|
+
* @param statName - Name of the stat to set (as defined in Steamworks Partner site)
|
|
164
256
|
* @param value - Float value to set
|
|
165
257
|
* @returns true if successful, false otherwise
|
|
166
258
|
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```typescript
|
|
261
|
+
* // Update accuracy based on hits/shots
|
|
262
|
+
* const hits = 85;
|
|
263
|
+
* const shots = 100;
|
|
264
|
+
* const accuracy = hits / shots; // 0.85
|
|
265
|
+
* await statsManager.setStatFloat('shooting_accuracy', accuracy);
|
|
266
|
+
* ```
|
|
267
|
+
*
|
|
268
|
+
* @remarks
|
|
269
|
+
* - Automatically calls StoreStats() to save to Steam servers
|
|
270
|
+
* - Runs callbacks to process the store operation
|
|
271
|
+
* - Use setStatInt() for whole number values
|
|
272
|
+
*
|
|
167
273
|
* Steamworks SDK Functions:
|
|
168
274
|
* - `SteamAPI_ISteamUserStats_SetStatFloat()` - Set float stat value
|
|
169
275
|
* - `SteamAPI_ISteamUserStats_StoreStats()` - Store stats to Steam servers
|
|
@@ -171,7 +277,7 @@ class SteamStatsManager {
|
|
|
171
277
|
*/
|
|
172
278
|
async setStatFloat(statName, value) {
|
|
173
279
|
if (!this.apiCore.isInitialized()) {
|
|
174
|
-
console.warn('
|
|
280
|
+
console.warn('[Steamworks] Steam API not initialized');
|
|
175
281
|
return false;
|
|
176
282
|
}
|
|
177
283
|
try {
|
|
@@ -181,35 +287,52 @@ class SteamStatsManager {
|
|
|
181
287
|
// Store the stats to Steam servers
|
|
182
288
|
const stored = this.libraryLoader.SteamAPI_ISteamUserStats_StoreStats(userStatsInterface);
|
|
183
289
|
if (stored) {
|
|
184
|
-
console.log(
|
|
290
|
+
console.log(`[Steamworks] Set stat "${statName}" to ${value}`);
|
|
185
291
|
// Process callbacks
|
|
186
292
|
this.libraryLoader.SteamAPI_RunCallbacks();
|
|
187
293
|
return true;
|
|
188
294
|
}
|
|
189
295
|
else {
|
|
190
|
-
console.warn(
|
|
296
|
+
console.warn(`[Steamworks] Failed to store stat: ${statName}`);
|
|
191
297
|
return false;
|
|
192
298
|
}
|
|
193
299
|
}
|
|
194
300
|
else {
|
|
195
|
-
console.warn(
|
|
301
|
+
console.warn(`[Steamworks] Failed to set stat: ${statName}`);
|
|
196
302
|
return false;
|
|
197
303
|
}
|
|
198
304
|
}
|
|
199
305
|
catch (error) {
|
|
200
|
-
console.error(
|
|
306
|
+
console.error(`[Steamworks] Error setting stat "${statName}":`, error.message);
|
|
201
307
|
return false;
|
|
202
308
|
}
|
|
203
309
|
}
|
|
204
310
|
/**
|
|
205
311
|
* Update an average rate stat
|
|
206
|
-
* This is used for stats like "average speed" or "kills per hour"
|
|
207
312
|
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
313
|
+
* Updates stats that represent rates or averages over time (e.g., "kills per hour",
|
|
314
|
+
* "average speed"). Steam automatically maintains the average calculation.
|
|
315
|
+
*
|
|
316
|
+
* @param statName - Name of the stat to update (as defined in Steamworks Partner site)
|
|
317
|
+
* @param countThisSession - Count/value for this session (e.g., kills this session)
|
|
210
318
|
* @param sessionLength - Length of session in seconds
|
|
211
319
|
* @returns true if successful, false otherwise
|
|
212
320
|
*
|
|
321
|
+
* @example
|
|
322
|
+
* ```typescript
|
|
323
|
+
* // Update kills per hour stat
|
|
324
|
+
* const sessionKills = 25;
|
|
325
|
+
* const sessionSeconds = 1800; // 30 minutes
|
|
326
|
+
* await statsManager.updateAvgRateStat('kills_per_hour', sessionKills, sessionSeconds);
|
|
327
|
+
* // Steam calculates: (25 / 1800) * 3600 = 50 kills/hour
|
|
328
|
+
* ```
|
|
329
|
+
*
|
|
330
|
+
* @remarks
|
|
331
|
+
* - Automatically calls StoreStats() to save to Steam servers
|
|
332
|
+
* - Steam maintains the running average across all sessions
|
|
333
|
+
* - sessionLength should be in seconds
|
|
334
|
+
* - Used for "per hour" or "per game" statistics
|
|
335
|
+
*
|
|
213
336
|
* Steamworks SDK Functions:
|
|
214
337
|
* - `SteamAPI_ISteamUserStats_UpdateAvgRateStat()` - Update average rate stat
|
|
215
338
|
* - `SteamAPI_ISteamUserStats_StoreStats()` - Store stats to Steam servers
|
|
@@ -217,7 +340,7 @@ class SteamStatsManager {
|
|
|
217
340
|
*/
|
|
218
341
|
async updateAvgRateStat(statName, countThisSession, sessionLength) {
|
|
219
342
|
if (!this.apiCore.isInitialized()) {
|
|
220
|
-
console.warn('
|
|
343
|
+
console.warn('[Steamworks] Steam API not initialized');
|
|
221
344
|
return false;
|
|
222
345
|
}
|
|
223
346
|
try {
|
|
@@ -227,23 +350,23 @@ class SteamStatsManager {
|
|
|
227
350
|
// Store the stats to Steam servers
|
|
228
351
|
const stored = this.libraryLoader.SteamAPI_ISteamUserStats_StoreStats(userStatsInterface);
|
|
229
352
|
if (stored) {
|
|
230
|
-
console.log(
|
|
353
|
+
console.log(`[Steamworks] Updated avg rate stat "${statName}": ${countThisSession} over ${sessionLength}s`);
|
|
231
354
|
// Process callbacks
|
|
232
355
|
this.libraryLoader.SteamAPI_RunCallbacks();
|
|
233
356
|
return true;
|
|
234
357
|
}
|
|
235
358
|
else {
|
|
236
|
-
console.warn(
|
|
359
|
+
console.warn(`[Steamworks] Failed to store stat: ${statName}`);
|
|
237
360
|
return false;
|
|
238
361
|
}
|
|
239
362
|
}
|
|
240
363
|
else {
|
|
241
|
-
console.warn(
|
|
364
|
+
console.warn(`[Steamworks] Failed to update avg rate stat: ${statName}`);
|
|
242
365
|
return false;
|
|
243
366
|
}
|
|
244
367
|
}
|
|
245
368
|
catch (error) {
|
|
246
|
-
console.error(
|
|
369
|
+
console.error(`[Steamworks] Error updating avg rate stat "${statName}":`, error.message);
|
|
247
370
|
return false;
|
|
248
371
|
}
|
|
249
372
|
}
|
|
@@ -252,17 +375,42 @@ class SteamStatsManager {
|
|
|
252
375
|
// ========================================
|
|
253
376
|
/**
|
|
254
377
|
* Request stats for another user (friend)
|
|
255
|
-
*
|
|
378
|
+
*
|
|
379
|
+
* Requests stat data from Steam servers for a specific user. Must be called
|
|
380
|
+
* before getting user stats with getUserStatInt() or getUserStatFloat().
|
|
381
|
+
* This is an asynchronous operation - wait a moment before reading the stats.
|
|
256
382
|
*
|
|
257
383
|
* @param steamId - Steam ID of the user (as string or BigInt)
|
|
258
|
-
* @returns true if request was sent, false otherwise
|
|
384
|
+
* @returns true if request was sent successfully, false otherwise
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* ```typescript
|
|
388
|
+
* const friendSteamId = '76561198012345678';
|
|
389
|
+
*
|
|
390
|
+
* // Request the friend's stats
|
|
391
|
+
* const success = await statsManager.requestUserStats(friendSteamId);
|
|
392
|
+
* if (success) {
|
|
393
|
+
* // Wait a moment for Steam to fetch the data
|
|
394
|
+
* await new Promise(resolve => setTimeout(resolve, 100));
|
|
395
|
+
*
|
|
396
|
+
* // Now get the friend's stats
|
|
397
|
+
* const friendKills = await statsManager.getUserStatInt(friendSteamId, 'total_kills');
|
|
398
|
+
* console.log(`[Steamworks] Friend has ${friendKills} kills`);
|
|
399
|
+
* }
|
|
400
|
+
* ```
|
|
401
|
+
*
|
|
402
|
+
* @remarks
|
|
403
|
+
* - Must be called before getting user stats
|
|
404
|
+
* - Returns true immediately if request was sent (not when data arrives)
|
|
405
|
+
* - Wait 50-100ms after requesting before reading stats
|
|
406
|
+
* - User's stats must be public for this to work
|
|
259
407
|
*
|
|
260
408
|
* Steamworks SDK Functions:
|
|
261
|
-
* - `SteamAPI_ISteamUserStats_RequestUserStats()` - Request user stats from Steam
|
|
409
|
+
* - `SteamAPI_ISteamUserStats_RequestUserStats()` - Request user stats from Steam servers
|
|
262
410
|
*/
|
|
263
411
|
async requestUserStats(steamId) {
|
|
264
412
|
if (!this.apiCore.isInitialized()) {
|
|
265
|
-
console.warn('
|
|
413
|
+
console.warn('[Steamworks] Steam API not initialized');
|
|
266
414
|
return false;
|
|
267
415
|
}
|
|
268
416
|
try {
|
|
@@ -270,33 +418,56 @@ class SteamStatsManager {
|
|
|
270
418
|
const steamIdBigInt = typeof steamId === 'string' ? BigInt(steamId) : steamId;
|
|
271
419
|
const callHandle = this.libraryLoader.SteamAPI_ISteamUserStats_RequestUserStats(userStatsInterface, steamIdBigInt);
|
|
272
420
|
if (callHandle !== BigInt(0)) {
|
|
273
|
-
console.log(
|
|
421
|
+
console.log(`[Steamworks] Requested stats for user: ${steamId}`);
|
|
274
422
|
return true;
|
|
275
423
|
}
|
|
276
424
|
else {
|
|
277
|
-
console.warn(
|
|
425
|
+
console.warn(`[Steamworks] Failed to request user stats: ${steamId}`);
|
|
278
426
|
return false;
|
|
279
427
|
}
|
|
280
428
|
}
|
|
281
429
|
catch (error) {
|
|
282
|
-
console.error(
|
|
430
|
+
console.error(`[Steamworks] Error requesting user stats:`, error.message);
|
|
283
431
|
return false;
|
|
284
432
|
}
|
|
285
433
|
}
|
|
286
434
|
/**
|
|
287
435
|
* Get an integer stat value for another user (friend)
|
|
288
|
-
*
|
|
436
|
+
*
|
|
437
|
+
* Retrieves a 32-bit integer stat value for a specific user. Must call
|
|
438
|
+
* requestUserStats() first and wait for the data to arrive.
|
|
289
439
|
*
|
|
290
440
|
* @param steamId - Steam ID of the user
|
|
291
441
|
* @param statName - Name of the stat to retrieve
|
|
292
|
-
* @returns
|
|
442
|
+
* @returns UserStat object with steamId, name, value, and type, or null if not found or on error
|
|
443
|
+
*
|
|
444
|
+
* @example
|
|
445
|
+
* ```typescript
|
|
446
|
+
* // Compare your kills to a friend's
|
|
447
|
+
* const friendId = '76561198012345678';
|
|
448
|
+
* await statsManager.requestUserStats(friendId);
|
|
449
|
+
* await new Promise(resolve => setTimeout(resolve, 100));
|
|
450
|
+
*
|
|
451
|
+
* const myStat = await statsManager.getStatInt('total_kills');
|
|
452
|
+
* const friendStat = await statsManager.getUserStatInt(friendId, 'total_kills');
|
|
453
|
+
*
|
|
454
|
+
* if (myStat && friendStat) {
|
|
455
|
+
* console.log(`[Steamworks] You: ${myStat.value}, Friend: ${friendStat.value}`);
|
|
456
|
+
* }
|
|
457
|
+
* ```
|
|
458
|
+
*
|
|
459
|
+
* @remarks
|
|
460
|
+
* - Must call requestUserStats() first
|
|
461
|
+
* - Wait 50-100ms after requesting before calling this
|
|
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
|
|
293
464
|
*
|
|
294
465
|
* Steamworks SDK Functions:
|
|
295
466
|
* - `SteamAPI_ISteamUserStats_GetUserStatInt32()` - Get user's int32 stat value
|
|
296
467
|
*/
|
|
297
468
|
async getUserStatInt(steamId, statName) {
|
|
298
469
|
if (!this.apiCore.isInitialized()) {
|
|
299
|
-
console.warn('
|
|
470
|
+
console.warn('[Steamworks] Steam API not initialized');
|
|
300
471
|
return null;
|
|
301
472
|
}
|
|
302
473
|
try {
|
|
@@ -306,33 +477,59 @@ class SteamStatsManager {
|
|
|
306
477
|
const success = this.libraryLoader.SteamAPI_ISteamUserStats_GetUserStatInt32(userStatsInterface, steamIdBigInt, statName, valueOut);
|
|
307
478
|
if (success) {
|
|
308
479
|
const value = koffi.decode(valueOut, 'int32');
|
|
309
|
-
console.log(
|
|
310
|
-
return
|
|
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
|
+
};
|
|
311
487
|
}
|
|
312
488
|
else {
|
|
313
|
-
console.warn(
|
|
489
|
+
console.warn(`[Steamworks] Failed to get user stat: ${statName}`);
|
|
314
490
|
return null;
|
|
315
491
|
}
|
|
316
492
|
}
|
|
317
493
|
catch (error) {
|
|
318
|
-
console.error(
|
|
494
|
+
console.error(`[Steamworks] Error getting user stat "${statName}":`, error.message);
|
|
319
495
|
return null;
|
|
320
496
|
}
|
|
321
497
|
}
|
|
322
498
|
/**
|
|
323
499
|
* Get a float stat value for another user (friend)
|
|
324
|
-
*
|
|
500
|
+
*
|
|
501
|
+
* Retrieves a floating-point stat value for a specific user. Must call
|
|
502
|
+
* requestUserStats() first and wait for the data to arrive.
|
|
325
503
|
*
|
|
326
504
|
* @param steamId - Steam ID of the user
|
|
327
505
|
* @param statName - Name of the stat to retrieve
|
|
328
|
-
* @returns
|
|
506
|
+
* @returns UserStat object with steamId, name, value, and type, or null if not found or on error
|
|
507
|
+
*
|
|
508
|
+
* @example
|
|
509
|
+
* ```typescript
|
|
510
|
+
* // Compare accuracy with a friend
|
|
511
|
+
* const friendId = '76561198012345678';
|
|
512
|
+
* await statsManager.requestUserStats(friendId);
|
|
513
|
+
* await new Promise(resolve => setTimeout(resolve, 100));
|
|
514
|
+
*
|
|
515
|
+
* const friendStat = await statsManager.getUserStatFloat(friendId, 'shooting_accuracy');
|
|
516
|
+
* if (friendStat) {
|
|
517
|
+
* console.log(`[Steamworks] Friend accuracy: ${(friendStat.value * 100).toFixed(2)}%`);
|
|
518
|
+
* }
|
|
519
|
+
* ```
|
|
520
|
+
*
|
|
521
|
+
* @remarks
|
|
522
|
+
* - Must call requestUserStats() first
|
|
523
|
+
* - Wait 50-100ms after requesting before calling this
|
|
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
|
|
329
526
|
*
|
|
330
527
|
* Steamworks SDK Functions:
|
|
331
528
|
* - `SteamAPI_ISteamUserStats_GetUserStatFloat()` - Get user's float stat value
|
|
332
529
|
*/
|
|
333
530
|
async getUserStatFloat(steamId, statName) {
|
|
334
531
|
if (!this.apiCore.isInitialized()) {
|
|
335
|
-
console.warn('
|
|
532
|
+
console.warn('[Steamworks] Steam API not initialized');
|
|
336
533
|
return null;
|
|
337
534
|
}
|
|
338
535
|
try {
|
|
@@ -342,16 +539,21 @@ class SteamStatsManager {
|
|
|
342
539
|
const success = this.libraryLoader.SteamAPI_ISteamUserStats_GetUserStatFloat(userStatsInterface, steamIdBigInt, statName, valueOut);
|
|
343
540
|
if (success) {
|
|
344
541
|
const value = koffi.decode(valueOut, 'float');
|
|
345
|
-
console.log(
|
|
346
|
-
return
|
|
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
|
+
};
|
|
347
549
|
}
|
|
348
550
|
else {
|
|
349
|
-
console.warn(
|
|
551
|
+
console.warn(`[Steamworks] Failed to get user stat: ${statName}`);
|
|
350
552
|
return null;
|
|
351
553
|
}
|
|
352
554
|
}
|
|
353
555
|
catch (error) {
|
|
354
|
-
console.error(
|
|
556
|
+
console.error(`[Steamworks] Error getting user stat "${statName}":`, error.message);
|
|
355
557
|
return null;
|
|
356
558
|
}
|
|
357
559
|
}
|
|
@@ -360,17 +562,40 @@ class SteamStatsManager {
|
|
|
360
562
|
// ========================================
|
|
361
563
|
/**
|
|
362
564
|
* Request global stats data from Steam
|
|
363
|
-
* Must be called before getting global stats
|
|
364
565
|
*
|
|
365
|
-
*
|
|
366
|
-
*
|
|
566
|
+
* Requests aggregated statistics across all players from Steam servers.
|
|
567
|
+
* Optionally includes historical data for trend analysis.
|
|
568
|
+
* Must be called before getting global stats.
|
|
569
|
+
*
|
|
570
|
+
* @param historyDays - Number of days of history to retrieve (0-60, default: 0)
|
|
571
|
+
* @returns true if request was sent successfully, false otherwise
|
|
572
|
+
*
|
|
573
|
+
* @example
|
|
574
|
+
* ```typescript
|
|
575
|
+
* // Request current global stats (no history)
|
|
576
|
+
* await statsManager.requestGlobalStats(0);
|
|
577
|
+
*
|
|
578
|
+
* // Request with 7 days of history for trends
|
|
579
|
+
* await statsManager.requestGlobalStats(7);
|
|
580
|
+
* await new Promise(resolve => setTimeout(resolve, 100));
|
|
581
|
+
*
|
|
582
|
+
* const totalKills = await statsManager.getGlobalStatInt('total_kills');
|
|
583
|
+
* console.log(`[Steamworks] All players combined: ${totalKills} kills`);
|
|
584
|
+
* ```
|
|
585
|
+
*
|
|
586
|
+
* @remarks
|
|
587
|
+
* - Must be called before getting global stats
|
|
588
|
+
* - Returns true immediately if request was sent (not when data arrives)
|
|
589
|
+
* - Wait 50-100ms after requesting before reading stats
|
|
590
|
+
* - historyDays is automatically clamped to 0-60 range
|
|
591
|
+
* - Historical data allows tracking trends over time
|
|
367
592
|
*
|
|
368
593
|
* Steamworks SDK Functions:
|
|
369
|
-
* - `SteamAPI_ISteamUserStats_RequestGlobalStats()` - Request global stats from Steam
|
|
594
|
+
* - `SteamAPI_ISteamUserStats_RequestGlobalStats()` - Request global stats from Steam servers
|
|
370
595
|
*/
|
|
371
596
|
async requestGlobalStats(historyDays = 0) {
|
|
372
597
|
if (!this.apiCore.isInitialized()) {
|
|
373
|
-
console.warn('
|
|
598
|
+
console.warn('[Steamworks] Steam API not initialized');
|
|
374
599
|
return false;
|
|
375
600
|
}
|
|
376
601
|
try {
|
|
@@ -379,32 +604,53 @@ class SteamStatsManager {
|
|
|
379
604
|
const userStatsInterface = this.libraryLoader.SteamAPI_SteamUserStats_v013();
|
|
380
605
|
const callHandle = this.libraryLoader.SteamAPI_ISteamUserStats_RequestGlobalStats(userStatsInterface, days);
|
|
381
606
|
if (callHandle !== BigInt(0)) {
|
|
382
|
-
console.log(
|
|
607
|
+
console.log(`[Steamworks] Requested global stats with ${days} days of history`);
|
|
383
608
|
return true;
|
|
384
609
|
}
|
|
385
610
|
else {
|
|
386
|
-
console.warn(
|
|
611
|
+
console.warn(`[Steamworks] Failed to request global stats`);
|
|
387
612
|
return false;
|
|
388
613
|
}
|
|
389
614
|
}
|
|
390
615
|
catch (error) {
|
|
391
|
-
console.error(
|
|
616
|
+
console.error(`[Steamworks] Error requesting global stats:`, error.message);
|
|
392
617
|
return false;
|
|
393
618
|
}
|
|
394
619
|
}
|
|
395
620
|
/**
|
|
396
|
-
* Get a global stat value (
|
|
397
|
-
*
|
|
621
|
+
* Get a global stat value (64-bit integer)
|
|
622
|
+
*
|
|
623
|
+
* Retrieves an aggregated integer stat value across all players.
|
|
624
|
+
* Must call requestGlobalStats() first and wait for the data to arrive.
|
|
398
625
|
*
|
|
399
626
|
* @param statName - Name of the global stat to retrieve
|
|
400
|
-
* @returns
|
|
627
|
+
* @returns GlobalStat object with name, value, and type, or null if not found or on error
|
|
628
|
+
*
|
|
629
|
+
* @example
|
|
630
|
+
* ```typescript
|
|
631
|
+
* // Get total kills across all players
|
|
632
|
+
* await statsManager.requestGlobalStats();
|
|
633
|
+
* await new Promise(resolve => setTimeout(resolve, 100));
|
|
634
|
+
*
|
|
635
|
+
* const globalStat = await statsManager.getGlobalStatInt('total_kills');
|
|
636
|
+
* if (globalStat) {
|
|
637
|
+
* console.log(`[Steamworks] ${globalStat.name}: ${globalStat.value}`);
|
|
638
|
+
* }
|
|
639
|
+
* ```
|
|
640
|
+
*
|
|
641
|
+
* @remarks
|
|
642
|
+
* - Must call requestGlobalStats() first
|
|
643
|
+
* - Wait 50-100ms after requesting before calling this
|
|
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)
|
|
401
647
|
*
|
|
402
648
|
* Steamworks SDK Functions:
|
|
403
649
|
* - `SteamAPI_ISteamUserStats_GetGlobalStatInt64()` - Get global int64 stat value
|
|
404
650
|
*/
|
|
405
651
|
async getGlobalStatInt(statName) {
|
|
406
652
|
if (!this.apiCore.isInitialized()) {
|
|
407
|
-
console.warn('
|
|
653
|
+
console.warn('[Steamworks] Steam API not initialized');
|
|
408
654
|
return null;
|
|
409
655
|
}
|
|
410
656
|
try {
|
|
@@ -413,32 +659,58 @@ class SteamStatsManager {
|
|
|
413
659
|
const success = this.libraryLoader.SteamAPI_ISteamUserStats_GetGlobalStatInt64(userStatsInterface, statName, valueOut);
|
|
414
660
|
if (success) {
|
|
415
661
|
const value = koffi.decode(valueOut, 'int64');
|
|
416
|
-
console.log(
|
|
417
|
-
return
|
|
662
|
+
console.log(`[Steamworks] Got global stat "${statName}": ${value}`);
|
|
663
|
+
return {
|
|
664
|
+
name: statName,
|
|
665
|
+
value: Number(value),
|
|
666
|
+
type: 'int64'
|
|
667
|
+
};
|
|
418
668
|
}
|
|
419
669
|
else {
|
|
420
|
-
console.warn(
|
|
670
|
+
console.warn(`[Steamworks] Failed to get global stat: ${statName}`);
|
|
421
671
|
return null;
|
|
422
672
|
}
|
|
423
673
|
}
|
|
424
674
|
catch (error) {
|
|
425
|
-
console.error(
|
|
675
|
+
console.error(`[Steamworks] Error getting global stat "${statName}":`, error.message);
|
|
426
676
|
return null;
|
|
427
677
|
}
|
|
428
678
|
}
|
|
429
679
|
/**
|
|
430
|
-
* Get a global stat value (double)
|
|
431
|
-
*
|
|
680
|
+
* Get a global stat value (double-precision float)
|
|
681
|
+
*
|
|
682
|
+
* Retrieves an aggregated floating-point stat value across all players.
|
|
683
|
+
* Must call requestGlobalStats() first and wait for the data to arrive.
|
|
684
|
+
* Use this for averages or stats requiring decimal precision.
|
|
432
685
|
*
|
|
433
686
|
* @param statName - Name of the global stat to retrieve
|
|
434
|
-
* @returns
|
|
687
|
+
* @returns GlobalStat object with name, value, and type, or null if not found or on error
|
|
688
|
+
*
|
|
689
|
+
* @example
|
|
690
|
+
* ```typescript
|
|
691
|
+
* // Get average accuracy across all players
|
|
692
|
+
* await statsManager.requestGlobalStats();
|
|
693
|
+
* await new Promise(resolve => setTimeout(resolve, 100));
|
|
694
|
+
*
|
|
695
|
+
* const avgStat = await statsManager.getGlobalStatDouble('average_accuracy');
|
|
696
|
+
* if (avgStat) {
|
|
697
|
+
* console.log(`[Steamworks] ${avgStat.name}: ${(avgStat.value * 100).toFixed(2)}%`);
|
|
698
|
+
* }
|
|
699
|
+
* ```
|
|
700
|
+
*
|
|
701
|
+
* @remarks
|
|
702
|
+
* - Use for stats requiring decimal precision
|
|
703
|
+
* - Must call requestGlobalStats() first
|
|
704
|
+
* - Wait 50-100ms after requesting before calling this
|
|
705
|
+
* - Perfect for calculating game-wide averages
|
|
706
|
+
* - Returns structured GlobalStat object with full metadata
|
|
435
707
|
*
|
|
436
708
|
* Steamworks SDK Functions:
|
|
437
709
|
* - `SteamAPI_ISteamUserStats_GetGlobalStatDouble()` - Get global double stat value
|
|
438
710
|
*/
|
|
439
711
|
async getGlobalStatDouble(statName) {
|
|
440
712
|
if (!this.apiCore.isInitialized()) {
|
|
441
|
-
console.warn('
|
|
713
|
+
console.warn('[Steamworks] Steam API not initialized');
|
|
442
714
|
return null;
|
|
443
715
|
}
|
|
444
716
|
try {
|
|
@@ -447,33 +719,63 @@ class SteamStatsManager {
|
|
|
447
719
|
const success = this.libraryLoader.SteamAPI_ISteamUserStats_GetGlobalStatDouble(userStatsInterface, statName, valueOut);
|
|
448
720
|
if (success) {
|
|
449
721
|
const value = koffi.decode(valueOut, 'double');
|
|
450
|
-
console.log(
|
|
451
|
-
return
|
|
722
|
+
console.log(`[Steamworks] Got global stat "${statName}": ${value}`);
|
|
723
|
+
return {
|
|
724
|
+
name: statName,
|
|
725
|
+
value,
|
|
726
|
+
type: 'double'
|
|
727
|
+
};
|
|
452
728
|
}
|
|
453
729
|
else {
|
|
454
|
-
console.warn(
|
|
730
|
+
console.warn(`[Steamworks] Failed to get global stat: ${statName}`);
|
|
455
731
|
return null;
|
|
456
732
|
}
|
|
457
733
|
}
|
|
458
734
|
catch (error) {
|
|
459
|
-
console.error(
|
|
735
|
+
console.error(`[Steamworks] Error getting global stat "${statName}":`, error.message);
|
|
460
736
|
return null;
|
|
461
737
|
}
|
|
462
738
|
}
|
|
463
739
|
/**
|
|
464
|
-
* Get global stat history
|
|
465
|
-
*
|
|
740
|
+
* Get global stat history for an integer stat
|
|
741
|
+
*
|
|
742
|
+
* Retrieves historical daily values for a global stat. Array index [0] is today,
|
|
743
|
+
* [1] is yesterday, etc. Useful for tracking trends and creating graphs.
|
|
466
744
|
*
|
|
467
745
|
* @param statName - Name of the global stat
|
|
468
|
-
* @param days - Number of days of history to retrieve (
|
|
469
|
-
* @returns
|
|
746
|
+
* @param days - Number of days of history to retrieve (1-60, default: 7)
|
|
747
|
+
* @returns GlobalStatHistory object with name, history array, and type, or null if error
|
|
748
|
+
*
|
|
749
|
+
* @example
|
|
750
|
+
* ```typescript
|
|
751
|
+
* // Get 7 days of global kill history
|
|
752
|
+
* await statsManager.requestGlobalStats(7);
|
|
753
|
+
* await new Promise(resolve => setTimeout(resolve, 100));
|
|
754
|
+
*
|
|
755
|
+
* const history = await statsManager.getGlobalStatHistoryInt('total_kills', 7);
|
|
756
|
+
* if (history) {
|
|
757
|
+
* console.log(`[Steamworks] ${history.name} history (${history.type}):`);
|
|
758
|
+
* history.history.forEach((kills, index) => {
|
|
759
|
+
* const daysAgo = index === 0 ? 'today' : `${index} days ago`;
|
|
760
|
+
* console.log(`[Steamworks] ${daysAgo}: ${kills} kills`);
|
|
761
|
+
* });
|
|
762
|
+
* }
|
|
763
|
+
* ```
|
|
764
|
+
*
|
|
765
|
+
* @remarks
|
|
766
|
+
* - Array index [0] = today, [1] = yesterday, etc.
|
|
767
|
+
* - Must call requestGlobalStats(days) first with same or greater number of days
|
|
768
|
+
* - Returns structured GlobalStatHistory object with full metadata
|
|
769
|
+
* - Values are numbers (BigInt converted to number for consistency)
|
|
770
|
+
* - Maximum 60 days of history (automatically clamped)
|
|
771
|
+
* - Perfect for trend analysis and visualizations
|
|
470
772
|
*
|
|
471
773
|
* Steamworks SDK Functions:
|
|
472
|
-
* - `SteamAPI_ISteamUserStats_GetGlobalStatHistoryInt64()` - Get
|
|
774
|
+
* - `SteamAPI_ISteamUserStats_GetGlobalStatHistoryInt64()` - Get historical int64 values
|
|
473
775
|
*/
|
|
474
776
|
async getGlobalStatHistoryInt(statName, days = 7) {
|
|
475
777
|
if (!this.apiCore.isInitialized()) {
|
|
476
|
-
console.warn('
|
|
778
|
+
console.warn('[Steamworks] Steam API not initialized');
|
|
477
779
|
return null;
|
|
478
780
|
}
|
|
479
781
|
try {
|
|
@@ -485,35 +787,67 @@ class SteamStatsManager {
|
|
|
485
787
|
if (elementsReturned > 0) {
|
|
486
788
|
const history = [];
|
|
487
789
|
for (let i = 0; i < elementsReturned; i++) {
|
|
488
|
-
history.push(koffi.decode(historyOut, 'int64', i));
|
|
790
|
+
history.push(Number(koffi.decode(historyOut, 'int64', i))); // Convert BigInt to number
|
|
489
791
|
}
|
|
490
|
-
console.log(
|
|
491
|
-
return
|
|
792
|
+
console.log(`[Steamworks] Got ${elementsReturned} days of history for "${statName}"`);
|
|
793
|
+
return {
|
|
794
|
+
name: statName,
|
|
795
|
+
history,
|
|
796
|
+
type: 'int64'
|
|
797
|
+
};
|
|
492
798
|
}
|
|
493
799
|
else {
|
|
494
|
-
console.warn(
|
|
800
|
+
console.warn(`[Steamworks] Failed to get global stat history: ${statName}`);
|
|
495
801
|
return null;
|
|
496
802
|
}
|
|
497
803
|
}
|
|
498
804
|
catch (error) {
|
|
499
|
-
console.error(
|
|
805
|
+
console.error(`[Steamworks] Error getting global stat history "${statName}":`, error.message);
|
|
500
806
|
return null;
|
|
501
807
|
}
|
|
502
808
|
}
|
|
503
809
|
/**
|
|
504
|
-
* Get global stat history
|
|
505
|
-
*
|
|
810
|
+
* Get global stat history for a floating-point stat
|
|
811
|
+
*
|
|
812
|
+
* Retrieves historical daily values for a global stat with decimal precision.
|
|
813
|
+
* Array index [0] is today, [1] is yesterday, etc. Ideal for tracking averages
|
|
814
|
+
* and rates over time.
|
|
506
815
|
*
|
|
507
816
|
* @param statName - Name of the global stat
|
|
508
|
-
* @param days - Number of days of history to retrieve (
|
|
509
|
-
* @returns
|
|
817
|
+
* @param days - Number of days of history to retrieve (1-60, default: 7)
|
|
818
|
+
* @returns GlobalStatHistory object with name, history array, and type, or null if error
|
|
819
|
+
*
|
|
820
|
+
* @example
|
|
821
|
+
* ```typescript
|
|
822
|
+
* // Track average accuracy trend over 30 days
|
|
823
|
+
* await statsManager.requestGlobalStats(30);
|
|
824
|
+
* await new Promise(resolve => setTimeout(resolve, 100));
|
|
825
|
+
*
|
|
826
|
+
* const history = await statsManager.getGlobalStatHistoryDouble('average_accuracy', 30);
|
|
827
|
+
* if (history) {
|
|
828
|
+
* console.log(`[Steamworks] ${history.name} trend (${history.type}):`);
|
|
829
|
+
* history.history.forEach((accuracy, index) => {
|
|
830
|
+
* if (index % 7 === 0) { // Weekly intervals
|
|
831
|
+
* console.log(`[Steamworks] Week ${index/7}: ${(accuracy * 100).toFixed(2)}%`);
|
|
832
|
+
* }
|
|
833
|
+
* });
|
|
834
|
+
* }
|
|
835
|
+
* ```
|
|
836
|
+
*
|
|
837
|
+
* @remarks
|
|
838
|
+
* - Array index [0] = today, [1] = yesterday, etc.
|
|
839
|
+
* - Must call requestGlobalStats(days) first with same or greater number of days
|
|
840
|
+
* - Returns structured GlobalStatHistory object with full metadata
|
|
841
|
+
* - Returns floating-point values for decimal precision
|
|
842
|
+
* - Maximum 60 days of history (automatically clamped)
|
|
843
|
+
* - Perfect for tracking averages, rates, and percentages over time
|
|
510
844
|
*
|
|
511
845
|
* Steamworks SDK Functions:
|
|
512
|
-
* - `SteamAPI_ISteamUserStats_GetGlobalStatHistoryDouble()` - Get
|
|
846
|
+
* - `SteamAPI_ISteamUserStats_GetGlobalStatHistoryDouble()` - Get historical double values
|
|
513
847
|
*/
|
|
514
848
|
async getGlobalStatHistoryDouble(statName, days = 7) {
|
|
515
849
|
if (!this.apiCore.isInitialized()) {
|
|
516
|
-
console.warn('
|
|
850
|
+
console.warn('[Steamworks] Steam API not initialized');
|
|
517
851
|
return null;
|
|
518
852
|
}
|
|
519
853
|
try {
|
|
@@ -527,16 +861,20 @@ class SteamStatsManager {
|
|
|
527
861
|
for (let i = 0; i < elementsReturned; i++) {
|
|
528
862
|
history.push(koffi.decode(historyOut, 'double', i));
|
|
529
863
|
}
|
|
530
|
-
console.log(
|
|
531
|
-
return
|
|
864
|
+
console.log(`[Steamworks] Got ${elementsReturned} days of history for "${statName}"`);
|
|
865
|
+
return {
|
|
866
|
+
name: statName,
|
|
867
|
+
history,
|
|
868
|
+
type: 'double'
|
|
869
|
+
};
|
|
532
870
|
}
|
|
533
871
|
else {
|
|
534
|
-
console.warn(
|
|
872
|
+
console.warn(`[Steamworks] Failed to get global stat history: ${statName}`);
|
|
535
873
|
return null;
|
|
536
874
|
}
|
|
537
875
|
}
|
|
538
876
|
catch (error) {
|
|
539
|
-
console.error(
|
|
877
|
+
console.error(`[Steamworks] Error getting global stat history "${statName}":`, error.message);
|
|
540
878
|
return null;
|
|
541
879
|
}
|
|
542
880
|
}
|