steamutils 1.4.10 → 1.4.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. package/SteamClient.js +2630 -2630
  2. package/package.json +1 -1
package/SteamClient.js CHANGED
@@ -1,2630 +1,2630 @@
1
- import NodeSteamUser from "steam-user";
2
- import _ from "lodash";
3
- import fs from "fs";
4
- import { protoDecode, protoEncode } from "./helpers/util.js";
5
- import SteamID from "steamid";
6
- import FriendCode from "csgo-friendcode";
7
- import axios from "axios";
8
- import helpers, { loadProfos } from "./helpers/protos.js";
9
- import { fileURLToPath } from "url";
10
- import path from "path";
11
- import SteamUser from "./index.js";
12
- import { v4 as uuidv4 } from "uuid";
13
- import EFriendRelationship from "steam-user/enums/EFriendRelationship.js";
14
- import SteamCommunity from "steamcommunity";
15
- import moment from "moment-timezone";
16
- import { encode, encodeUids } from "./bufferHelpers.js";
17
-
18
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
-
20
- const Protos = helpers([
21
- {
22
- name: "csgo",
23
- protos: loadProfos(`${__dirname}/protos/`),
24
- },
25
- ]);
26
-
27
- export const RANKS = {
28
- 0: "Unranked",
29
- 1: "Silver I",
30
- 2: "Silver II",
31
- 3: "Silver III",
32
- 4: "Silver IV",
33
- 5: "Silver Elite",
34
- 6: "Silver Elite Master",
35
- 7: "Gold Nova I",
36
- 8: "Gold Nova II",
37
- 9: "Gold Nova III",
38
- 10: "Gold Nova Master",
39
- 11: "Master Guardian I",
40
- 12: "Master Guardian II",
41
- 13: "Master Guardian Elite",
42
- 14: "Distinguished Master Guardian",
43
- 15: "Legendary Eagle",
44
- 16: "Legendary Eagle Master",
45
- 17: "Supreme Master First Class",
46
- 18: "The Global Elite",
47
- };
48
- export const LOCS = {
49
- 20054: "VN",
50
- 23115: "KZ",
51
- 20041: "IN",
52
- 20035: "CN",
53
- 17474: "BD",
54
- 17481: "ID",
55
- 22861: "MY",
56
- 18516: "TH",
57
- 22356: "TW",
58
- 21067: "KR",
59
- 19272: "HK",
60
- 18512: "PH",
61
- 21842: "RU",
62
- 16716: "LA",
63
- 20558: "NP",
64
- 18259: "SG",
65
- 19789: "MM",
66
- 20045: "MN",
67
- 18251: "KG",
68
- 18507: "KH",
69
- 22605: "MX",
70
- 19280: "PK",
71
- 20301: "HK/MO", //hongkong or macau
72
- 21333: "Unknown",
73
- 21825: "AU",
74
- 20034: "Unkown",
75
- };
76
-
77
- const AppID = 730;
78
- export let CSGO_VER = 13960;
79
- export const FreeAppList = JSON.parse(fs.readFileSync(path.join(__dirname, "free_packages.json"))).packages;
80
-
81
- SteamUser.getAppVersion(AppID).then(function (ver) {
82
- CSGO_VER = ver;
83
- });
84
-
85
- const PersonasCache = [];
86
- let isSendingFriendMessages = false;
87
-
88
- function SteamClient({ username, password, cookie, clientJsToken, isAutoRequestFreeLicense = true, isFakeGameScore = true, isPartyRegister = true, isAutoPlay = false, isInvisible = false, autoAcceptTradeRequest = false, autoReconnect = true, MAX_GAME_PLAY = 10, games = null }) {
89
- const steamClient = new NodeSteamUser();
90
- let prime = null;
91
- let state = "Offline"; //InGame, Online, Invisible
92
- let isLogOff = false;
93
- let playingBlocked = null;
94
- const richPresence = {};
95
- let sendMessageTimestamp = 0;
96
- let lastTimePartyRegister = 0;
97
- let lastTimePartySearch = 0;
98
- const ownedApps = [];
99
- let logOffEvent = null;
100
-
101
- let _clientWelcome = null;
102
- let _clientHello = null;
103
-
104
- const currentLobby = {
105
- lobbyID: null,
106
- timestamp: 0,
107
- };
108
-
109
- const onAnyCallbacks = [];
110
-
111
- const events = {
112
- user: [],
113
- loggedOn: [],
114
- csgoOnline: [],
115
- csgoClientHello: [],
116
- webSession: [],
117
- friendMessage: [],
118
- friendTyping: [],
119
- disconnected: [],
120
- error: [],
121
- playersProfile: [],
122
- fatalError: [],
123
- partyInvite: [],
124
- friendRelationship: [],
125
- tradeOffers: [],
126
- offlineMessages: [],
127
- friendsList: [],
128
- gifts: [],
129
- playingState: [],
130
- emailInfo: [],
131
- accountLimitations: [],
132
- };
133
-
134
- const gcCallback = {};
135
-
136
- function pushGCCallback(name, cb, timeout) {
137
- if (!gcCallback[name]) {
138
- gcCallback[name] = {};
139
- }
140
- let t = null;
141
- let id = uuidv4();
142
-
143
- function callback(...arg) {
144
- if (t) {
145
- clearTimeout(t);
146
- }
147
- delete gcCallback[name][id];
148
- cb?.apply(null, arg);
149
- }
150
-
151
- if (timeout) {
152
- t = setTimeout(callback, timeout);
153
- }
154
- gcCallback[name][id] = callback;
155
- }
156
-
157
- function callGCCallback(name, ...arg) {
158
- if (gcCallback[name]) {
159
- for (const id in gcCallback[name]) {
160
- gcCallback[name][id]?.(...arg);
161
- }
162
- }
163
- }
164
-
165
- function callEvent(_events, data) {
166
- const eventName = Object.keys(events).find((eventName) => events[eventName] === _events);
167
- eventName && onAnyCallbacks.forEach((cb) => cb?.({ eventName, data }));
168
-
169
- _events?.forEach?.((e) => {
170
- e.callback?.(data);
171
- e.timeout && clearTimeout(e.timeout);
172
- delete e.timeout;
173
- if (e.once) {
174
- delete e.callback;
175
- }
176
- });
177
- _.remove(_events, (e) => !e || e?.once);
178
- }
179
-
180
- function onEvent(name, callback, once, timeout) {
181
- if (!events[name]) {
182
- events[name] = [];
183
- }
184
- const t = timeout ? setTimeout(callback, timeout) : null;
185
- events[name].push({
186
- once,
187
- callback,
188
- timeout: t,
189
- });
190
- }
191
-
192
- function offEvent(name) {
193
- if (Array.isArray(events[name])) {
194
- for (const eventElement of events[name]) {
195
- if (eventElement.timeout) {
196
- clearTimeout(eventElement.timeout);
197
- }
198
- }
199
- }
200
-
201
- delete events[name];
202
- }
203
-
204
- function onAnyEvent(callback) {
205
- onAnyCallbacks.push(callback);
206
- }
207
-
208
- function offAllEvent() {
209
- for (const name in events) {
210
- for (const event of events[name]) {
211
- if (event.timeout) {
212
- try {
213
- clearTimeout(event.timeout);
214
- } catch (e) {}
215
- delete event.timeout;
216
- }
217
- }
218
- delete events[name];
219
- }
220
- onAnyCallbacks.length = 0;
221
- }
222
-
223
- const intervals = {};
224
- const intervalRandoms = {};
225
-
226
- function doSetInterval(cb, timeout, key) {
227
- const isRandom = Array.isArray(timeout);
228
- if (!key) {
229
- key = uuidv4();
230
- }
231
- if (isRandom) {
232
- if (intervalRandoms[key] !== undefined) {
233
- try {
234
- clearTimeout(intervalRandoms[key]);
235
- } catch (e) {}
236
- }
237
- intervalRandoms[key] = setTimeout(
238
- function () {
239
- doSetInterval(cb, timeout, key);
240
- if (state !== "Offline") {
241
- cb();
242
- }
243
- },
244
- _.random(timeout[0], timeout[1]),
245
- );
246
- } else {
247
- if (intervals[key] !== undefined) {
248
- try {
249
- clearInterval(intervals[key]);
250
- } catch (e) {}
251
- }
252
-
253
- intervals[key] = setInterval(function () {
254
- if (state !== "Offline") {
255
- cb();
256
- }
257
- }, timeout);
258
- }
259
-
260
- return key;
261
- }
262
-
263
- function doClearIntervals() {
264
- for (const key in intervals) {
265
- clearInterval(intervals[key]);
266
- delete intervals[key];
267
- }
268
- for (const key in intervalRandoms) {
269
- clearTimeout(intervalRandoms[key]);
270
- delete intervalRandoms[key];
271
- }
272
- }
273
-
274
- function doClearInterval(key) {
275
- try {
276
- clearInterval(intervals[key]);
277
- } catch (e) {}
278
- delete intervals[key];
279
-
280
- try {
281
- clearTimeout(intervalRandoms[key]);
282
- } catch (e) {}
283
- delete intervalRandoms[key];
284
- }
285
-
286
- function getAccountInfoName() {
287
- return [steamClient?.accountInfo?.name, steamClient?._logOnDetails?.account_name].filter(Boolean).join(" - ");
288
- }
289
-
290
- function getPersonaName() {
291
- return steamClient?.accountInfo?.name;
292
- }
293
-
294
- function log(...msg) {
295
- const now = moment().tz("Asia/Ho_Chi_Minh").format("DD/MM/YYYY HH:mm:ss");
296
- console.log(`[${now}] [${getAccountInfoName()}]`, ...msg);
297
- }
298
-
299
- async function getPersonas(steamIDs) {
300
- const idsToFetch = steamIDs.map((steamId) => (steamId instanceof SteamID ? steamId.getSteamID64() : steamId));
301
- const notCachedIDs = idsToFetch.filter((id) => !PersonasCache.some((p) => p.id == id));
302
- const cachedPersonas = PersonasCache.filter((p) => idsToFetch.includes(p.id));
303
-
304
- if (notCachedIDs.length) {
305
- let personas = null;
306
- try {
307
- personas = (await steamClient.getPersonas(notCachedIDs))?.personas;
308
- } catch (e) {}
309
- if (!personas || !Object.keys(personas).length) {
310
- try {
311
- personas = (await steamClient.getPersonas(notCachedIDs))?.personas;
312
- } catch (e) {}
313
- }
314
- if (!personas || !Object.keys(personas).length) {
315
- try {
316
- personas = (await steamClient.getPersonas(notCachedIDs))?.personas;
317
- } catch (e) {}
318
- }
319
- if (personas && Object.keys(personas).length) {
320
- for (let sid64 in personas) {
321
- personas[sid64].id = sid64;
322
- personas[sid64].avatar_hash = Buffer.from(personas[sid64].avatar_hash).toString("hex");
323
- PersonasCache.push(personas[sid64]);
324
- cachedPersonas.push(personas[sid64]);
325
- }
326
- }
327
- }
328
-
329
- while (PersonasCache.length > 500) {
330
- PersonasCache.shift();
331
- }
332
- return cachedPersonas;
333
- }
334
-
335
- function sleep(ms) {
336
- return new Promise((resolve) => {
337
- setTimeout(resolve, ms);
338
- });
339
- }
340
-
341
- function getCookies() {
342
- return cookie || steamClient?.webSession?.cookies?.join?.(";");
343
- }
344
-
345
- async function getCookiesWait() {
346
- return (
347
- getCookies() ||
348
- new Promise((resolve) => {
349
- onEvent(
350
- "webSession",
351
- function (webSession) {
352
- resolve(webSession?.cookies);
353
- },
354
- true,
355
- 30000,
356
- );
357
- })
358
- );
359
- }
360
-
361
- async function gamePlay() {
362
- return await gamesPlayed(730);
363
- }
364
-
365
- async function autoGamePlay() {
366
- await gamePlay();
367
- doSetInterval(gamePlay, [15 * 60000, 30 * 60000], "autoGamePlay");
368
- }
369
-
370
- async function offAutoGamePlay() {
371
- steamClient.gamesPlayed([]);
372
- doClearInterval("autoGamePlay");
373
- }
374
-
375
- async function updateAutoGamePlay() {
376
- if (isAutoPlay) {
377
- autoGamePlay();
378
- } else {
379
- offAutoGamePlay();
380
- }
381
- }
382
-
383
- /**
384
- * Get a list of lobbies (* = Unsure description could be wrong)
385
- * @param {Number} ver Game version we are searching for
386
- * @param {Boolean} apr Prime or not*
387
- * @param {Number} ark Rank multiplied by 10*
388
- * @param {Array.<Number>} grps *
389
- * @param {Number} launcher If we are using the China CSGO launcher or not*
390
- * @param {Number} game_type Game type, 8 Competitive, 10 Wingman
391
- * @returns {Promise.<Object>}
392
- */
393
- async function partySearch({ prime = false, game_type = "Competitive", rank = "Silver Elite", timeout = 5000 } = {}) {
394
- const players = await new Promise((resolve) => {
395
- steamClient.sendToGC(
396
- AppID,
397
- Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Party_Search,
398
- {},
399
- protoEncode(Protos.csgo.CMsgGCCStrike15_v2_Party_Search, {
400
- ver: CSGO_VER,
401
- apr: prime ? 1 : 0,
402
- ark: parseInt(Object.keys(RANKS).find((k) => RANKS[k] === rank)) * 10,
403
- grps: [],
404
- launcher: 0,
405
- game_type: game_type === "Competitive" ? 8 : 10,
406
- }),
407
- );
408
- lastTimePartySearch = new Date().getTime();
409
- pushGCCallback("partySearch", resolve, timeout);
410
- });
411
- if (Array.isArray(players) && players.length) {
412
- const personas = await getPersonas(players.map((p) => p.steamId));
413
- for (const player of players) {
414
- const persona = personas.find((p) => p.id == player.steamId);
415
- if (persona) {
416
- player.player_name = persona.player_name;
417
- player.avatar_hash = persona.avatar_hash;
418
- }
419
- }
420
- }
421
- return players;
422
- }
423
-
424
- async function createLobby() {
425
- if (!steamClient.steamID) {
426
- return;
427
- }
428
-
429
- return new Promise((resolve) => {
430
- const timeout = setTimeout(function () {
431
- resolve();
432
- }, 30000);
433
-
434
- steamClient._send(
435
- {
436
- msg: Protos.csgo.EMsg.k_EMsgClientMMSCreateLobby,
437
- proto: {
438
- steamid: steamClient.steamID.getSteamID64(),
439
- routing_appid: 730,
440
- },
441
- },
442
- protoEncode(Protos.csgo.CMsgClientMMSCreateLobby, {
443
- app_id: 730,
444
- max_members: 1,
445
- lobby_type: 1,
446
- lobby_flags: 1,
447
- }),
448
- function (payload) {
449
- clearTimeout(timeout);
450
- const result = protoDecode(Protos.csgo.CMsgClientMMSCreateLobbyResponse, payload.toBuffer());
451
- const steam_id_lobby = result.steam_id_lobby.toString();
452
- currentLobby.lobbyID = steam_id_lobby;
453
- currentLobby.timestamp = new Date().getTime();
454
- resolve(steam_id_lobby);
455
- },
456
- );
457
- });
458
-
459
- // return await getHandlerResult(Protos.csgo.EMsg.k_EMsgClientMMSCreateLobbyResponse, function (payload) {
460
- // const result = protoDecode(Protos.csgo.CMsgClientMMSCreateLobbyResponse, payload.toBuffer())
461
- // return result.steam_id_lobby.toString()
462
- // })
463
-
464
- // steamClient.sendToGC(730, Protos.csgo.EMsg.k_EMsgClientMMSCreateLobby, {
465
- // steamid: steamClient.steamID,
466
- // routing_appid: 730,
467
- // }, protoEncode(Protos.csgo.CMsgClientMMSCreateLobby, {
468
- // app_id: 730,
469
- // max_members: 1,
470
- // lobby_type: 1,
471
- // lobby_flags: 1
472
- // }))
473
- }
474
-
475
- async function updateLobby(lobbyID) {
476
- if (!steamClient.steamID) {
477
- return;
478
- }
479
-
480
- return new Promise((resolve) => {
481
- const timeout = setTimeout(function () {
482
- resolve();
483
- }, 30000);
484
-
485
- steamClient._send(
486
- {
487
- msg: Protos.csgo.EMsg.k_EMsgClientMMSSetLobbyData,
488
- proto: {
489
- steamid: steamClient.steamID.getSteamID64(),
490
- routing_appid: 730,
491
- },
492
- },
493
- protoEncode(Protos.csgo.CMsgClientMMSSetLobbyData, {
494
- app_id: 730,
495
- steam_id_lobby: lobbyID,
496
- steam_id_member: "0",
497
- max_members: 10,
498
- lobby_type: 1,
499
- lobby_flags: 1,
500
- metadata: encode(
501
- {
502
- "game:ark": "0",
503
- // Country/Message
504
- "game:loc": "",
505
- "game:mapgroupname": "mg_de_mirage",
506
- "game:mode": "competitive",
507
- "game:prime": "1",
508
- "game:type": "classic",
509
- "members:numPlayers": "1",
510
- "options:action": "custommatch",
511
- "options:anytypemode": "0",
512
- "system:access": "private",
513
- "system:network": "LIVE",
514
- uids: [steamClient.steamID],
515
- },
516
- [0x00, 0x00],
517
- [0x08],
518
- { uids: encodeUids },
519
- ).toBuffer(),
520
- }),
521
- function (payload) {
522
- clearTimeout(timeout);
523
- const result = protoDecode(Protos.csgo.CMsgClientMMSSetLobbyDataResponse, payload.toBuffer());
524
- const steam_id_lobby = result.steam_id_lobby.toString();
525
- currentLobby.lobbyID = steam_id_lobby;
526
- currentLobby.timestamp = new Date().getTime();
527
- resolve(steam_id_lobby);
528
- },
529
- );
530
- });
531
-
532
- // return await getHandlerResult(Protos.csgo.EMsg.k_EMsgClientMMSSetLobbyDataResponse, function (payload) {
533
- // const result = protoDecode(Protos.csgo.CMsgClientMMSSetLobbyDataResponse, payload.toBuffer())
534
- // return result.steam_id_lobby.toString()
535
- // })
536
- }
537
-
538
- async function invite2Lobby(lobbyID, steamId) {
539
- if (!steamClient.steamID) {
540
- return;
541
- }
542
-
543
- steamClient._send(
544
- {
545
- msg: Protos.csgo.EMsg.k_EMsgClientMMSInviteToLobby,
546
- proto: {
547
- steamid: steamClient.steamID.getSteamID64(),
548
- routing_appid: 730,
549
- },
550
- },
551
- protoEncode(Protos.csgo.CMsgClientMMSInviteToLobby, {
552
- app_id: 730,
553
- steam_id_lobby: lobbyID,
554
- steam_id_user_invited: steamId,
555
- }),
556
- );
557
-
558
- // lobbyID = new SteamID(lobbyID).accountid;
559
-
560
- // Protos.csgo.EMsg.k_EMsgGCHInviteUserToLobby
561
- // Protos.csgo.EMsg.k_EMsgClientMMSInviteToLobby
562
- // steamClient.sendToGC(730, Protos.csgo.EMsg.k_EMsgClientMMSInviteToLobby, {}, protoEncode(Protos.csgo.CMsgClientMMSInviteToLobby, {
563
- // app_id: 730,
564
- // steam_id_lobby: lobbyID,
565
- // steam_id_user_invited: accountid,
566
- // }), function (...args) {
567
- // console.log("invite2Lobby response", args)
568
- // })
569
- }
570
-
571
- async function createThenInvite2Lobby(steamIds, onInvite) {
572
- if (!steamClient.steamID) {
573
- return;
574
- }
575
-
576
- if (!Array.isArray(steamIds)) {
577
- steamIds = [steamIds];
578
- }
579
-
580
- let lobbyID = null;
581
- if (currentLobby.lobbyID && currentLobby.timestamp > new Date().getTime() - 30000) {
582
- //30 seconds
583
- lobbyID = currentLobby.lobbyID;
584
- } else {
585
- lobbyID = await createLobby();
586
- lobbyID = await updateLobby(lobbyID);
587
- }
588
-
589
- for (const steamId of steamIds) {
590
- onInvite?.(lobbyID, steamId);
591
- await invite2Lobby(lobbyID, steamId);
592
- }
593
-
594
- return lobbyID;
595
- }
596
-
597
- async function getLobbyData(lobbyID) {
598
- if (!steamClient.steamID) {
599
- return;
600
- }
601
-
602
- return new Promise((resolve) => {
603
- const timeout = setTimeout(function () {
604
- resolve();
605
- }, 30000);
606
-
607
- steamClient._send(
608
- {
609
- msg: Protos.csgo.EMsg.k_EMsgClientMMSGetLobbyData,
610
- proto: {
611
- steamid: steamClient.steamID.getSteamID64(),
612
- routing_appid: 730,
613
- },
614
- },
615
- protoEncode(Protos.csgo.CMsgClientMMSGetLobbyData, {
616
- app_id: 730,
617
- steam_id_lobby: lobbyID.toString(),
618
- }),
619
- function (payload) {
620
- clearTimeout(timeout);
621
- const result = protoDecode(Protos.csgo.CMsgClientMMSLobbyData, payload.toBuffer());
622
- result.steam_id_lobby = result.steam_id_lobby.toString();
623
- resolve(result);
624
- },
625
- );
626
- });
627
- }
628
-
629
- async function joinLobby(lobbyID) {
630
- log("joinLobby", lobbyID); //SteamID.fromIndividualAccountID(lobbyId).accountid
631
-
632
- steamClient._send(
633
- {
634
- msg: Protos.csgo.EMsg.k_EMsgClientMMSJoinLobby,
635
- proto: {
636
- steamid: steamClient.steamID.getSteamID64(),
637
- routing_appid: 730,
638
- },
639
- }, //CMsgClientMMSUserJoinedLobby CMsgClientMMSJoinLobby
640
- protoEncode(Protos.csgo.CMsgClientMMSJoinLobby, {
641
- app_id: 730,
642
- steam_id_lobby: lobbyID,
643
- persona_name: steamClient.accountInfo.name,
644
- }),
645
- function (payload) {
646
- const result = protoDecode(Protos.csgo.CMsgClientMMSJoinLobbyResponse, payload.toBuffer());
647
- result.steam_id_lobby = result.steam_id_lobby.toString();
648
- result.steam_id_owner = result.steam_id_owner.toString();
649
- console.log(result);
650
- const resultExample = {
651
- members: [],
652
- app_id: 730,
653
- steam_id_lobby: "3641224920",
654
- chat_room_enter_response: 2,
655
- max_members: 0,
656
- lobby_type: 0,
657
- lobby_flags: 0,
658
- steam_id_owner: "0",
659
- metadata: null, //Buffer
660
- };
661
- },
662
- );
663
- }
664
-
665
- async function sendHello() {
666
- steamClient.sendToGC(AppID, Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_MatchmakingClient2GCHello, {}, Buffer.alloc(0));
667
- // steamClient.sendToGC(AppID, Protos.csgo.EGCBaseClientMsg.k_EMsgGCClientHello, {}, Buffer.alloc(0));
668
-
669
- steamClient.sendToGC(
670
- AppID,
671
- Protos.csgo.EGCBaseClientMsg.k_EMsgGCClientHello,
672
- {},
673
- protoEncode(Protos.csgo.CMsgClientHello, {
674
- version: 2000258, //get from https://github.com/SteamDatabase/GameTracking-CS2/commits
675
- client_session_need: 0,
676
- client_launcher: 0,
677
- steam_launcher: 0,
678
- }),
679
- );
680
- }
681
-
682
- async function requestCoPlays() {
683
- return new Promise((resolve) => {
684
- steamClient.sendToGC(AppID, Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Account_RequestCoPlays, {}, Buffer.alloc(0));
685
- pushGCCallback("RequestCoPlays", resolve, 30000);
686
- });
687
- }
688
-
689
- function bindEvent() {
690
- const _events = {
691
- async disconnected(eresult, msg) {
692
- state = "Offline";
693
- log("disconnected", eresult, msg);
694
-
695
- callEvent(events.disconnected, { eresult, msg });
696
-
697
- if (["ServiceUnavailable", "NoConnection"].includes(msg) && autoReconnect && !isLogOff) {
698
- async function relogin(retry) {
699
- if (isLogOff) {
700
- console.error("Cannot relogin (logoff)");
701
- return false;
702
- } else if (retry <= 0) {
703
- console.error("Cannot relogin");
704
- return false;
705
- } else {
706
- const isSuccess = await login(true);
707
- if (isSuccess) {
708
- const loggedOnResponse = await new Promise((resolve) => {
709
- onEvent("loggedOn", resolve, true, 180000);
710
- });
711
- if (loggedOnResponse) {
712
- console.log("Relogin success");
713
- return true;
714
- } else {
715
- const isLogOff = await new Promise((resolve, reject) => {
716
- logOffEvent = resolve;
717
- setTimeout(resolve, 120000);
718
- });
719
- logOffEvent = null;
720
- if (isLogOff === true) {
721
- return false;
722
- }
723
- return await relogin(retry - 1);
724
- }
725
- } else {
726
- const isLogOff = await new Promise((resolve, reject) => {
727
- logOffEvent = resolve;
728
- setTimeout(resolve, 120000);
729
- });
730
- logOffEvent = null;
731
- if (isLogOff === true) {
732
- return false;
733
- }
734
- return await relogin(retry - 1);
735
- }
736
- }
737
- }
738
-
739
- const isLogOff = await new Promise((resolve, reject) => {
740
- logOffEvent = resolve;
741
- setTimeout(resolve, 60000);
742
- });
743
- logOffEvent = null;
744
- if (isLogOff === true) {
745
- offAllEvent();
746
- doClearIntervals();
747
- } else {
748
- const isSuccess = await relogin(50);
749
- if (!isSuccess) {
750
- offAllEvent();
751
- doClearIntervals();
752
- }
753
- }
754
- } else {
755
- offAllEvent();
756
- doClearIntervals();
757
- }
758
- },
759
- async error(e) {
760
- let errorStr = "";
761
- switch (e.eresult) {
762
- case 5:
763
- errorStr = "Invalid Password";
764
- break;
765
- case 6:
766
- case 34:
767
- errorStr = "Logged In Elsewhere";
768
- break;
769
- case 84:
770
- errorStr = "Rate Limit Exceeded";
771
- break;
772
- case 65:
773
- errorStr = "steam guard is invalid";
774
- break;
775
- default:
776
- errorStr = `Unknown: ${e.eresult}`;
777
- break;
778
- }
779
- log(`error [isLogOff: ${isLogOff}]`, e?.message);
780
- doClearIntervals();
781
- callEvent(events.error, { eresult: e.eresult, msg: e.message, error: errorStr });
782
- },
783
- async webSession(sessionID, cookies) {
784
- const webSession = { sessionID, cookies };
785
- steamClient.webSession = webSession;
786
- callEvent(events.webSession, webSession);
787
- },
788
- async receivedFromGC(appid, msgType, payload) {
789
- const key = getECsgoGCMsgKey(msgType);
790
- switch (msgType) {
791
- case Protos.csgo.EMsg.k_EMsgClientChatInvite: {
792
- log(payload);
793
- break;
794
- }
795
- case Protos.csgo.ECsgoGCMsg.k_EMsgClientMMSJoinLobbyResponse: {
796
- const msg = protoDecode(Protos.csgo.CMsgClientMMSJoinLobbyResponse, payload);
797
- log(msg);
798
- break;
799
- }
800
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Party_Invite: {
801
- const msg = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_Party_Invite, payload);
802
- const sid64 = SteamID.fromIndividualAccountID(msg.accountid).getSteamID64();
803
- if (events.partyInvite?.length) {
804
- const personas = await getPersonas([sid64]);
805
- const player_name = personas.find((p) => p.id == sid64)?.player_name;
806
- if (player_name === undefined) {
807
- log(sid64, personas);
808
- }
809
- callEvent(events.partyInvite, { player_name, steamId: sid64, lobbyId: msg.lobbyid });
810
- }
811
- // log(player_name, `https://steamcommunity.com/profiles/${sid64}`);
812
- // joinLobby(msg.lobbyid, msg.accountid)
813
- break;
814
- }
815
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Account_RequestCoPlays: {
816
- const msg = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_Account_RequestCoPlays, payload);
817
- const personas = msg.players.map((p) => SteamID.fromIndividualAccountID(p.accountid));
818
- callGCCallback("RequestCoPlays", personas);
819
- break;
820
- }
821
- case Protos.csgo.EGCBaseClientMsg.k_EMsgGCClientWelcome: {
822
- prime = false;
823
- const CMsgClientWelcome = protoDecode(Protos.csgo.CMsgClientWelcome, payload);
824
- const obj = {};
825
- for (const outofdate_cache of CMsgClientWelcome.outofdate_subscribed_caches) {
826
- for (const cache_object of outofdate_cache.objects) {
827
- for (const object_data of cache_object.object_data) {
828
- switch (cache_object.type_id) {
829
- case 1: {
830
- const result = protoDecode(Protos.csgo.CSOEconItem, object_data);
831
- result.id = result.id.toNumber();
832
- result.original_id = result.original_id.toNumber();
833
- if (!obj.items) {
834
- obj.items = {};
835
- }
836
- obj.items[result.id] = result;
837
- break;
838
- }
839
- case 2: {
840
- const result = protoDecode(Protos.csgo.CSOPersonaDataPublic, object_data);
841
- obj.PersonaDataPublic = result;
842
- const example = {
843
- player_level: 4, //CSGO_Profile_Rank
844
- commendation: {
845
- cmd_friendly: 149,
846
- cmd_teaching: 108,
847
- cmd_leader: 115,
848
- },
849
- elevated_state: true,
850
- };
851
- break;
852
- }
853
- case 5: {
854
- const result = protoDecode(Protos.csgo.CSOItemRecipe, object_data);
855
- break;
856
- }
857
- case 7: {
858
- const CSOEconGameAccountClient = protoDecode(Protos.csgo.CSOEconGameAccountClient, object_data);
859
- const CSOEconGameAccountClientExample = {
860
- additional_backpack_slots: 0,
861
- bonus_xp_timestamp_refresh: 1688518800, //Wednesday 1:00:00 AM every week
862
- bonus_xp_usedflags: 19,
863
- elevated_state: 5,
864
- elevated_timestamp: 5,
865
- }; //1688518800
866
- if ((CSOEconGameAccountClient.bonus_xp_usedflags & 16) != 0) {
867
- // EXPBonusFlag::PrestigeEarned
868
- prime = true;
869
- CSOEconGameAccountClient.prime = true;
870
- }
871
- if (CSOEconGameAccountClient.elevated_state === 5) {
872
- // bought prime
873
- prime = true;
874
- CSOEconGameAccountClient.prime = true;
875
- }
876
-
877
- CSOEconGameAccountClient.flags = XpBonuxFlagsHelper.ParseBonusXPFlags(CSOEconGameAccountClient.bonus_xp_usedflags);
878
- obj.GameAccountClient = CSOEconGameAccountClient;
879
- break;
880
- }
881
-
882
- case 35: {
883
- // const result =protoDecode(Protos.csgo.CSOSelectedItemPreset, object_data);
884
- break;
885
- }
886
-
887
- case 36: {
888
- // const result =protoDecode(Protos.csgo.CSOEconItemPresetInstance, object_data);
889
- break;
890
- }
891
- case 38: {
892
- const result = protoDecode(Protos.csgo.CSOEconItemDropRateBonus, object_data);
893
- break;
894
- }
895
- case 39: {
896
- const result = protoDecode(Protos.csgo.CSOEconItemLeagueViewPass, object_data);
897
- break;
898
- }
899
- case 40: {
900
- const result = protoDecode(Protos.csgo.CSOEconItemEventTicket, object_data);
901
- break;
902
- }
903
- case 41: {
904
- const result = protoDecode(Protos.csgo.CSOAccountSeasonalOperation, object_data);
905
- break;
906
- }
907
- case 42: {
908
- // const result =protoDecode(Protos.csgo.CSOEconItemTournamentPassport, object_data);
909
- break;
910
- }
911
- case 43: {
912
- const result = protoDecode(Protos.csgo.CSOEconDefaultEquippedDefinitionInstanceClient, object_data);
913
- const example = {
914
- account_id: 1080136620,
915
- item_definition: 61,
916
- class_id: 3,
917
- slot_id: 2,
918
- };
919
- break;
920
- }
921
- case 45: {
922
- const result = protoDecode(Protos.csgo.CSOEconCoupon, object_data);
923
- break;
924
- }
925
- case 46: {
926
- const result = protoDecode(Protos.csgo.CSOQuestProgress, object_data);
927
- break;
928
- }
929
- case 4: {
930
- const result = protoDecode(Protos.csgo.CSOAccountItemPersonalStore, object_data);
931
- result.generation_time = result.generation_time * 1000;
932
- if (Array.isArray(result.items)) {
933
- result.items = result.items.map((item) => item.toNumber());
934
- }
935
- obj.personalStore = result;
936
- const redeemable_balance = result.redeemable_balance; //2, 0
937
- //How many rewards they have available to redeem.
938
- //redeemable_balance 2: not yet claim
939
- //redeemable_balance 1: claim 1/2
940
- //redeemable_balance 0: claimed
941
- break;
942
- }
943
-
944
- default: {
945
- // log("cache_object.type_id", cache_object.type_id);
946
- }
947
- }
948
- }
949
- }
950
- }
951
- _clientWelcome = obj;
952
- callEvent(events.csgoOnline, obj);
953
-
954
- if (isPartyRegister) {
955
- partyRegister();
956
- doSetInterval(
957
- function () {
958
- partyRegister();
959
- },
960
- [60000, 120000],
961
- "autoPartyRegister",
962
- );
963
- }
964
- break;
965
- }
966
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_MatchmakingGC2ClientUpdate: {
967
- const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_MatchmakingGC2ClientUpdate, payload);
968
- break;
969
- }
970
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_GC2ClientGlobalStats: {
971
- const result = protoDecode(Protos.csgo.CMsgClientUGSGetGlobalStatsResponse, payload);
972
- break;
973
- }
974
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientReportPlayer: {
975
- const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientReportPlayer, payload);
976
- break;
977
- }
978
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_GC2ClientTextMsg: {
979
- const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_GC2ClientTextMsg, payload);
980
- break;
981
- }
982
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_MatchmakingGC2ClientHello: {
983
- const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_MatchmakingGC2ClientHello, payload);
984
- const example = {
985
- my_current_event_teams: [],
986
- my_current_event_stages: [],
987
- rankings: [],
988
- account_id: 1080136620,
989
- ongoingmatch: null,
990
- global_stats: {
991
- search_statistics: [
992
- {
993
- game_type: 520,
994
- search_time_avg: 0,
995
- players_searching: 5141,
996
- },
997
- {
998
- game_type: 32776,
999
- search_time_avg: 0,
1000
- players_searching: 6561,
1001
- },
1002
- ],
1003
- players_online: 617207,
1004
- servers_online: 230638,
1005
- players_searching: 13550,
1006
- servers_available: 126352,
1007
- ongoing_matches: 23264,
1008
- search_time_avg: 95993,
1009
- main_post_url: "xxx",
1010
- required_appid_version: 13879,
1011
- pricesheet_version: 1688084844,
1012
- twitch_streams_version: 2,
1013
- active_tournament_eventid: 21,
1014
- active_survey_id: 0,
1015
- rtime32_cur: 0,
1016
- rtime32_event_start: 0,
1017
- },
1018
- penalty_seconds: 0, //379243
1019
- penalty_reason: 0, //4 You did too much damage to your teammates at round start ,5: abandoned
1020
- vac_banned: 0,
1021
- ranking: {
1022
- account_id: 1080136620,
1023
- rank_id: 10,
1024
- wins: 209,
1025
- rank_change: 0,
1026
- rank_type_id: 6,
1027
- tv_control: 0,
1028
- },
1029
- commendation: {
1030
- cmd_friendly: 149,
1031
- cmd_teaching: 108,
1032
- cmd_leader: 115,
1033
- },
1034
- medals: null,
1035
- my_current_event: null,
1036
- my_current_team: null,
1037
- survey_vote: 0,
1038
- activity: null,
1039
- player_level: 4,
1040
- player_cur_xp: 327684501,
1041
- player_xp_bonus_flags: 0,
1042
- };
1043
- if (result?.global_stats?.required_appid_version && (!CSGO_VER || result.global_stats.required_appid_version > CSGO_VER)) {
1044
- CSGO_VER = result.global_stats.required_appid_version;
1045
- }
1046
- _clientHello = result;
1047
- callEvent(events.csgoClientHello, result);
1048
- break;
1049
- }
1050
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientReportResponse: {
1051
- const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientReportResponse, payload);
1052
- break;
1053
- }
1054
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientCommendPlayerQueryResponse: {
1055
- const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientCommendPlayer, payload);
1056
- break;
1057
- }
1058
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_PlayerOverwatchCaseAssignment: {
1059
- const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_PlayerOverwatchCaseAssignment, payload);
1060
- break;
1061
- }
1062
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_MatchList: {
1063
- const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_MatchList, payload);
1064
- break;
1065
- }
1066
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_GetEventFavorites_Response: {
1067
- const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_GetEventFavorites_Response, payload);
1068
- break;
1069
- }
1070
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_StartAgreementSessionInGame: {
1071
- break;
1072
- }
1073
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_ClientDeepStats: {
1074
- const result = protoDecode(Protos.csgo.CMsgGCCStrike15_ClientDeepStats, payload);
1075
- break;
1076
- }
1077
- case Protos.csgo.EGCBaseClientMsg.k_EMsgGCClientConnectionStatus: {
1078
- const result = protoDecode(Protos.csgo.CMsgConnectionStatus, payload);
1079
- break;
1080
- }
1081
- case Protos.csgo.EGCItemMsg.k_EMsgGCStoreGetUserDataResponse: {
1082
- const result = protoDecode(Protos.csgo.CMsgStoreGetUserDataResponse, payload);
1083
- break;
1084
- }
1085
- case Protos.csgo.EGCItemMsg.k_EMsgGCStorePurchaseFinalizeResponse: {
1086
- const result = protoDecode(Protos.csgo.CMsgGCStorePurchaseFinalizeResponse, payload);
1087
- break;
1088
- }
1089
- case Protos.csgo.EGCItemMsg.k_EMsgGCStorePurchaseCancelResponse: {
1090
- const result = protoDecode(Protos.csgo.CMsgGCStorePurchaseCancelResponse, payload);
1091
- break;
1092
- }
1093
- case Protos.csgo.EGCItemMsg.k_EMsgGCStorePurchaseInitResponse: {
1094
- const result = protoDecode(Protos.csgo.CMsgGCStorePurchaseInitResponse, payload);
1095
- break;
1096
- }
1097
- case Protos.csgo.EMsg.k_EMsgClientMMSCreateLobbyResponse: {
1098
- const result = protoDecode(Protos.csgo.CMsgClientMMSCreateLobbyResponse, payload);
1099
- console.log("k_EMsgClientMMSCreateLobbyResponse", result);
1100
- break;
1101
- }
1102
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientGCRankUpdate: {
1103
- const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientGCRankUpdate, payload);
1104
- break;
1105
- }
1106
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Party_Search: {
1107
- const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_Party_SearchResults, payload);
1108
- const entries = _.uniqBy(result.entries, "id");
1109
- //{
1110
- // id: 144900402,
1111
- // grp: 0,
1112
- // game_type: 8,
1113
- // apr: 1,
1114
- // ark: 17,
1115
- // loc: 20041,
1116
- // accountid: 0
1117
- // }
1118
-
1119
- //{
1120
- // id: "76561199265943339",
1121
- // rich_presence: [],
1122
- // persona_state: null,
1123
- // game_played_app_id: null,
1124
- // game_server_ip: null,
1125
- // game_server_port: null,
1126
- // persona_state_flags: null,
1127
- // online_session_instances: null,
1128
- // persona_set_by_user: null,
1129
- // player_name: "杀人不见血",
1130
- // query_port: null,
1131
- // steamid_source: null,
1132
- // avatar_hash: "33994e26f1fe7e2093f8c7dee66c1ac91531050d",
1133
- // last_logoff: null,
1134
- // last_logon: null,
1135
- // last_seen_online: null,
1136
- // clan_rank: null,
1137
- // game_name: null,
1138
- // gameid: null,
1139
- // game_data_blob: null,
1140
- // clan_data: null,
1141
- // clan_tag: null,
1142
- // broadcast_id: null,
1143
- // game_lobby_id: null,
1144
- // watching_broadcast_accountid: null,
1145
- // watching_broadcast_appid: null,
1146
- // watching_broadcast_viewers: null,
1147
- // watching_broadcast_title: null,
1148
- // is_community_banned: null,
1149
- // player_name_pending_review: null,
1150
- // avatar_pending_review: null,
1151
- // avatar_url_icon: "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/33/33994e26f1fe7e2093f8c7dee66c1ac91531050d.jpg",
1152
- // avatar_url_medium: "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/33/33994e26f1fe7e2093f8c7dee66c1ac91531050d_medium.jpg",
1153
- // avatar_url_full: "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/33/33994e26f1fe7e2093f8c7dee66c1ac91531050d_full.jpg"
1154
- // }
1155
-
1156
- const players = [];
1157
- for (const player of entries) {
1158
- try {
1159
- const prime = player.apr === 1 ? "PRIME" : "NON-PRIME";
1160
- const loc = LOCS[player.loc] || player.loc;
1161
- const steamId = SteamID.fromIndividualAccountID(player.id).getSteamID64();
1162
- const friendCode = FriendCode.encode(steamId);
1163
-
1164
- // if ((LOCS[player.loc] == 'VN' || !LOCS[player.loc])) {
1165
- players.push({
1166
- prime,
1167
- rank: RANKS[player.ark] !== undefined ? RANKS[player.ark] : player.ark,
1168
- loc,
1169
- steamId,
1170
- friendCode,
1171
- });
1172
- // }
1173
- } catch (e) {}
1174
- }
1175
-
1176
- callGCCallback("partySearch", players);
1177
- break;
1178
- }
1179
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_PlayersProfile: {
1180
- let data = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_PlayersProfile, payload)?.account_profiles;
1181
- const dataExample = [
1182
- {
1183
- my_current_event_teams: [],
1184
- my_current_event_stages: [],
1185
- rankings: [
1186
- {
1187
- account_id: 1225887169,
1188
- rank_id: 0,
1189
- wins: 6,
1190
- rank_change: 0,
1191
- rank_type_id: 7,
1192
- tv_control: 0,
1193
- },
1194
- {
1195
- account_id: 1225887169,
1196
- rank_id: 0,
1197
- wins: 0,
1198
- rank_change: 0,
1199
- rank_type_id: 10,
1200
- tv_control: 0,
1201
- },
1202
- ],
1203
- account_id: 1225887169,
1204
- ongoingmatch: null,
1205
- global_stats: null,
1206
- penalty_seconds: 0,
1207
- penalty_reason: 0,
1208
- vac_banned: 0,
1209
- ranking: {
1210
- account_id: 1225887169,
1211
- rank_id: 8,
1212
- wins: 469,
1213
- rank_change: 0,
1214
- rank_type_id: 6,
1215
- tv_control: 0,
1216
- },
1217
- commendation: {
1218
- cmd_friendly: 51,
1219
- cmd_teaching: 40,
1220
- cmd_leader: 40,
1221
- },
1222
- medals: {
1223
- display_items_defidx: [4819, 4737],
1224
- featured_display_item_defidx: 4819,
1225
- },
1226
- my_current_event: null,
1227
- my_current_team: null,
1228
- survey_vote: 0,
1229
- activity: null,
1230
- player_level: 32,
1231
- player_cur_xp: 327682846,
1232
- player_xp_bonus_flags: 0,
1233
- },
1234
- ];
1235
-
1236
- const player = data?.[0];
1237
- if (player) {
1238
- player.prime = !!(player.ranking?.account_id || player.player_level || player.player_cur_xp);
1239
- player.steamId = SteamID.fromIndividualAccountID(player.account_id).getSteamID64();
1240
- callGCCallback(`PlayersProfile_${player.account_id}`, player);
1241
- }
1242
- callEvent(events.playersProfile, player);
1243
- break;
1244
- }
1245
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientLogonFatalError: {
1246
- const data = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientLogonFatalError, payload);
1247
- const dataExample = {
1248
- errorcode: 4,
1249
- message: "",
1250
- country: "VN",
1251
- };
1252
- callEvent(events.fatalError, data);
1253
- break;
1254
- }
1255
- case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientRequestJoinFriendData: {
1256
- const data = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientRequestJoinFriendData, payload);
1257
- if (!data?.account_id) {
1258
- return;
1259
- }
1260
- const dataExample = {
1261
- version: 14009,
1262
- account_id: 1594592618,
1263
- join_token: 1431405434,
1264
- join_ipp: 1318239032,
1265
- res: null,
1266
- errormsg: "Game is full",
1267
- };
1268
- callGCCallback(`requestJoinFriendData_${data.account_id}`, data);
1269
- break;
1270
- }
1271
- default:
1272
- log(`receivedFromGC ${msgType} ${key}`);
1273
- const results = Object.values(Protos.csgo)
1274
- .map(function (p) {
1275
- try {
1276
- return protoDecode(p, payload);
1277
- } catch (e) {}
1278
- })
1279
- .filter(function (result) {
1280
- return result && Object.keys(result).length;
1281
- });
1282
- log(key, results);
1283
- }
1284
- },
1285
- async loggedOn(loggedOnResponse) {
1286
- callEvent(events.loggedOn, loggedOnResponse);
1287
- updateInvisible();
1288
- updateAutoRequestFreeLicense();
1289
- updateAutoGamePlay();
1290
- },
1291
- async user(steamId, data) {
1292
- callEvent(events.user, { steamId: steamId.getSteamID64(), data });
1293
- const dataExample = {
1294
- rich_presence: [
1295
- {
1296
- key: "status",
1297
- value: "Competitive Mirage [ 3 : 6 ]",
1298
- },
1299
- {
1300
- key: "version",
1301
- value: "13875",
1302
- },
1303
- {
1304
- key: "game:state",
1305
- value: "game",
1306
- },
1307
- {
1308
- key: "steam_display",
1309
- value: "#display_GameKnownMapScore",
1310
- },
1311
- {
1312
- key: "game:mode",
1313
- value: "competitive",
1314
- },
1315
- {
1316
- key: "game:mapgroupname",
1317
- value: "mg_de_mirage",
1318
- },
1319
- {
1320
- key: "game:map",
1321
- value: "de_mirage",
1322
- },
1323
- {
1324
- key: "game:server",
1325
- value: "kv",
1326
- },
1327
- {
1328
- key: "watch",
1329
- value: "1",
1330
- },
1331
- {
1332
- key: "steam_player_group",
1333
- value: "2134948645",
1334
- },
1335
- {
1336
- key: "game:score",
1337
- value: "[ 3 : 6 ]",
1338
- },
1339
- ],
1340
- friendid: "76561199405834425",
1341
- persona_state: 1,
1342
- game_played_app_id: 730,
1343
- game_server_ip: null,
1344
- game_server_port: null,
1345
- persona_state_flags: 1,
1346
- online_session_instances: 1,
1347
- persona_set_by_user: null,
1348
- player_name: "quỷ súng",
1349
- query_port: null,
1350
- steamid_source: "0",
1351
- avatar_hash: {
1352
- type: "Buffer",
1353
- data: [23, 163, 216, 209, 236, 179, 73, 228, 225, 30, 48, 190, 192, 170, 177, 246, 139, 71, 122, 205],
1354
- },
1355
- last_logoff: 1683950268,
1356
- last_logon: 1683950281,
1357
- last_seen_online: 1683950268,
1358
- clan_rank: null,
1359
- game_name: "",
1360
- gameid: "730",
1361
- game_data_blob: {
1362
- type: "Buffer",
1363
- data: [],
1364
- },
1365
- clan_data: null,
1366
- clan_tag: null,
1367
- broadcast_id: "0",
1368
- game_lobby_id: "0",
1369
- watching_broadcast_accountid: null,
1370
- watching_broadcast_appid: null,
1371
- watching_broadcast_viewers: null,
1372
- watching_broadcast_title: null,
1373
- is_community_banned: null,
1374
- player_name_pending_review: null,
1375
- avatar_pending_review: null,
1376
- };
1377
- },
1378
- async playingState(playing_blocked, playing_app) {
1379
- playingBlocked = playing_blocked;
1380
- if (playing_app === 0) {
1381
- playing_app = null;
1382
- }
1383
- if (playing_blocked) {
1384
- //true, false
1385
- console.log("Playing else where");
1386
- }
1387
- log("playingState", playing_blocked, playing_app);
1388
- callEvent(events.playingState, { playing_blocked, playing_app });
1389
- },
1390
- async friendRelationship(sid, relationship, previousRelationship) {
1391
- callEvent(events.friendRelationship, {
1392
- steamId: sid.getSteamID64(),
1393
- relationship,
1394
- previousRelationship,
1395
- });
1396
- switch (relationship) {
1397
- case EFriendRelationship.None: {
1398
- //we got unfriended.
1399
- break;
1400
- }
1401
- case EFriendRelationship.RequestRecipient: {
1402
- //we got invited as a friend
1403
- break;
1404
- }
1405
- case EFriendRelationship.Friend: {
1406
- //we got added as a friend
1407
- break;
1408
- }
1409
- }
1410
- },
1411
- async tradeOffers(count) {
1412
- callEvent(events.tradeOffers, count);
1413
- },
1414
- async offlineMessages(count, friends) {
1415
- callEvent(events.offlineMessages, { count, steamIdList: friends });
1416
- },
1417
- async tradeRequest(steamID, respond) {
1418
- if (autoAcceptTradeRequest) {
1419
- log(`Incoming trade request from ${steamID.getSteam3RenderedID()}, accepting`);
1420
- respond(true);
1421
- } else {
1422
- log(`Incoming trade request from ${steamID.getSteam3RenderedID()}, wating`);
1423
- }
1424
- },
1425
- async friendsList() {
1426
- callEvent(events.friendsList, getFriendList());
1427
- },
1428
- async gifts(gid, packageid, TimeCreated, TimeExpiration, TimeSent, TimeAcked, TimeRedeemed, RecipientAddress, SenderAddress, SenderName) {
1429
- callEvent(events.gifts, {
1430
- gid,
1431
- packageid,
1432
- TimeCreated,
1433
- TimeExpiration,
1434
- TimeSent,
1435
- TimeAcked,
1436
- TimeRedeemed,
1437
- RecipientAddress,
1438
- SenderAddress,
1439
- SenderName,
1440
- });
1441
- },
1442
- async emailInfo(address, validated) {
1443
- callEvent(events.emailInfo, { address, validated });
1444
- },
1445
- async appLaunched() {
1446
- setTimeout(function () {
1447
- state = getPlayingAppIds().length ? "InGame" : isInvisible ? "Invisible" : "Online";
1448
- }, 1000);
1449
- },
1450
- async appQuit() {
1451
- setTimeout(function () {
1452
- state = getPlayingAppIds().length ? "InGame" : isInvisible ? "Invisible" : "Online";
1453
- }, 1000);
1454
- },
1455
- async accountLimitations(bis_limited_account, bis_community_banned, bis_locked_account, bis_limited_account_allowed_to_invite_friends) {
1456
- callEvent(events.accountLimitations, {
1457
- limited: bis_limited_account,
1458
- communityBanned: bis_community_banned,
1459
- locked: bis_locked_account,
1460
- canInviteFriends: bis_limited_account_allowed_to_invite_friends,
1461
- });
1462
- },
1463
- };
1464
-
1465
- const _chatEvents = {
1466
- async friendMessage(data) {
1467
- if (!data) return;
1468
- data.message_no_bbcode = data.message_no_bbcode?.replaceAll("ː", ":");
1469
- data.message = data.message?.replaceAll("ː", ":");
1470
- const example = {
1471
- steamid_friend: {
1472
- universe: 1,
1473
- type: 1,
1474
- instance: 1,
1475
- accountid: 1080136620,
1476
- },
1477
- chat_entry_type: 1,
1478
- from_limited_account: false,
1479
- message: "xxx",
1480
- ordinal: 0,
1481
- local_echo: false,
1482
- message_no_bbcode: "xxx",
1483
- low_priority: false,
1484
- server_timestamp: "2023-05-14T09:26:25.000Z",
1485
- message_bbcode_parsed: ["xxx"],
1486
- };
1487
- const timestamp = new Date(data.server_timestamp).getTime();
1488
- const steamId = data.steamid_friend.getSteamID64();
1489
- const invite = ["Invited you to play a game!", "Đã mời bạn chơi một trò chơi!"].includes(data.message_no_bbcode || data.message);
1490
- const emotion = (data.message_no_bbcode || "").split(" ").find((m) => m.startsWith(":") && m.endsWith(":"));
1491
-
1492
- callEvent(events.friendMessage, {
1493
- ...data,
1494
- message: data.message_no_bbcode,
1495
- invite,
1496
- steamId,
1497
- timestamp,
1498
- emotion,
1499
- });
1500
- },
1501
- async friendTyping(steamId, message) {
1502
- callEvent(events.friendTyping, {
1503
- steamId,
1504
- message,
1505
- });
1506
- },
1507
- };
1508
-
1509
- // steamClient.on('lobbyInvite', (inviterID, lobbyID ) => {
1510
- // joinLobby(lobbyID)
1511
- // })
1512
-
1513
- // steamClient.on("debug", (msg) => {
1514
- // if (!["ClientPersonaState", "ClientClanState"].some((c) => msg.includes(c))) {
1515
- // if (msg.startsWith("Received")) {
1516
- // console.log(`------- ${msg}`);
1517
- // } else {
1518
- // console.log(msg);
1519
- // }
1520
- // }
1521
- // });
1522
-
1523
- function getECsgoGCMsgKey(_key) {
1524
- for (let key in Protos.csgo.ECsgoGCMsg) {
1525
- if (Protos.csgo.ECsgoGCMsg[key] == _key) {
1526
- return key;
1527
- }
1528
- }
1529
- for (let key in Protos.csgo.EGCBaseClientMsg) {
1530
- if (Protos.csgo.EGCBaseClientMsg[key] == _key) {
1531
- return key;
1532
- }
1533
- }
1534
- for (let key in Protos.csgo.EMsg) {
1535
- if (Protos.csgo.EMsg[key] == _key) {
1536
- return key;
1537
- }
1538
- }
1539
- for (let key in Protos.csgo.EGCItemMsg) {
1540
- if (Protos.csgo.EGCItemMsg[key] == _key) {
1541
- return key;
1542
- }
1543
- }
1544
- }
1545
-
1546
- for (const [name, _event] of Object.entries(_events)) {
1547
- steamClient.on(name, _event);
1548
- }
1549
-
1550
- for (const [name, _event] of Object.entries(_chatEvents)) {
1551
- steamClient.chat.on(name, _event);
1552
- }
1553
- }
1554
-
1555
- function getHandlerResult(msg, handler) {
1556
- const timeout = { current: null };
1557
- return new Promise((resolve) => {
1558
- function myhandler(...args) {
1559
- timeout.current && clearTimeout(timeout.current);
1560
- removeHandler();
1561
- resolve(handler?.(...args));
1562
- }
1563
-
1564
- function removeHandler() {
1565
- if (Array.isArray(steamClient._handlerManager._handlers[msg])) {
1566
- const index = steamClient._handlerManager._handlers[msg].findIndex((_handler) => _handler === myhandler);
1567
- if (index > -1) {
1568
- steamClient._handlerManager._handlers[msg].splice(index, 1);
1569
- }
1570
- }
1571
- }
1572
-
1573
- timeout.current = setTimeout(function () {
1574
- removeHandler();
1575
- resolve();
1576
- }, 60000);
1577
- steamClient._handlerManager.add(msg, myhandler);
1578
- });
1579
- }
1580
-
1581
- function getFriendList() {
1582
- return Object.keys(steamClient.myFriends).filter((steamId) => steamClient.myFriends[steamId] === NodeSteamUser.EFriendRelationship.Friend);
1583
- }
1584
-
1585
- function sendFriendTyping(steamId, callback) {
1586
- steamClient.chat.sendFriendTyping(steamId, callback);
1587
- }
1588
-
1589
- /*
1590
- * usually take 400 -> 800 miliseconds
1591
- * */
1592
- function getPlayersProfile(steamId) {
1593
- const accountid = new SteamID(steamId).accountid;
1594
- steamClient.sendToGC(
1595
- 730,
1596
- Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientRequestPlayersProfile,
1597
- {},
1598
- protoEncode(Protos.csgo.CMsgGCCStrike15_v2_ClientRequestPlayersProfile, {
1599
- account_id: accountid, // account_id: new SteamID('76561199184696945').accountid,
1600
- request_level: 32,
1601
- }),
1602
- );
1603
- return new Promise((resolve) => {
1604
- pushGCCallback(`PlayersProfile_${accountid}`, resolve, 2000);
1605
- });
1606
- }
1607
-
1608
- async function checkPlayerPrimeStatus(steamId) {
1609
- const profile = await getPlayersProfile(steamId);
1610
- if (!profile) return false;
1611
-
1612
- if (profile.ranking?.account_id) {
1613
- return true;
1614
- }
1615
-
1616
- if (profile.player_level || profile.player_cur_xp) {
1617
- return true;
1618
- }
1619
- return false;
1620
- }
1621
-
1622
- async function _getStoreSteamPoweredResponse(cookie) {
1623
- let response = null;
1624
- for (let i = 0; i < 50; i++) {
1625
- if (!response) {
1626
- try {
1627
- response = await axios.request({
1628
- url: "https://store.steampowered.com/",
1629
- headers: {
1630
- cookie,
1631
- accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.75",
1632
- },
1633
- });
1634
- } catch (e) {
1635
- await sleep(1000);
1636
- }
1637
- }
1638
- }
1639
- return response;
1640
- }
1641
-
1642
- async function getNewCookie(cookie) {
1643
- if (!cookie) {
1644
- return;
1645
- }
1646
- let response = await _getStoreSteamPoweredResponse(cookie);
1647
- if (!response) {
1648
- return;
1649
- }
1650
- while (Array.isArray(response?.headers?.["set-cookie"])) {
1651
- console.log(cookie);
1652
- const cookieObj = cookie.split(";").reduce(function (accumulator, currentValue) {
1653
- accumulator[currentValue.trim().split("=")[0].trim()] = currentValue.trim().split("=")[1].trim();
1654
- return accumulator;
1655
- }, {});
1656
- for (const mcookie of response.headers["set-cookie"]) {
1657
- const name = mcookie.split("=")[0].trim();
1658
- const value = mcookie.split("=")[1].split(";")[0].trim();
1659
- cookieObj[name] = value;
1660
- }
1661
- cookie = Object.keys(cookieObj)
1662
- .map((name) => `${name}=${cookieObj[name]}`)
1663
- .join(";");
1664
- response = await _getStoreSteamPoweredResponse(cookie);
1665
- }
1666
- return cookie;
1667
- }
1668
-
1669
- async function loginWithCookie(cookie, tryNewCookie = false) {
1670
- let response;
1671
- for (let i = 0; i < 20; i++) {
1672
- try {
1673
- response = await axios.request({
1674
- url: "https://steamcommunity.com/chat/clientjstoken",
1675
- headers: {
1676
- cookie,
1677
- },
1678
- });
1679
- } catch (e) {
1680
- await sleep(1000);
1681
- }
1682
- if (response) {
1683
- break;
1684
- }
1685
- }
1686
-
1687
- const result = response?.data;
1688
- if (result?.logged_in) {
1689
- Object.assign(result, {
1690
- steamID: new SteamID(result.steamid),
1691
- accountName: result.account_name,
1692
- webLogonToken: result.token,
1693
- });
1694
- steamClient.logOn(result);
1695
- return cookie;
1696
- } else {
1697
- if (tryNewCookie) {
1698
- log("You are not logged in", cookie);
1699
- return null;
1700
- } else {
1701
- const newCookie = await getNewCookie(cookie);
1702
- if (!newCookie) {
1703
- console.error("Cannot get new cookie");
1704
- return null;
1705
- } else {
1706
- return await loginWithCookie(newCookie, true);
1707
- }
1708
- }
1709
- }
1710
- }
1711
-
1712
- async function login(reconnect = false) {
1713
- function logOn(clientJsToken) {
1714
- try {
1715
- steamClient.logOn({
1716
- ...clientJsToken,
1717
- steamId: new SteamID(clientJsToken.steamid),
1718
- steamID: new SteamID(clientJsToken.steamid),
1719
- accountName: clientJsToken.account_name,
1720
- webLogonToken: clientJsToken.token,
1721
- });
1722
- return true;
1723
- } catch (e) {
1724
- console.error(e);
1725
- return false;
1726
- }
1727
- }
1728
-
1729
- if (clientJsToken?.logged_in === true) {
1730
- log(reconnect ? "reconnect with clientJsToken" : "login with clientJsToken");
1731
- setTimeout(function () {
1732
- clientJsToken = null;
1733
- }, 1000);
1734
- return logOn(clientJsToken);
1735
- } else if (cookie) {
1736
- log(reconnect ? "reconnect with cookie" : "login with cookie");
1737
- const steamUser = new SteamUser(typeof cookie === "function" ? await cookie() : cookie);
1738
- const _clientJsToken = await steamUser.getClientJsToken();
1739
- if (_clientJsToken?.logged_in === true) {
1740
- return logOn(_clientJsToken);
1741
- } else {
1742
- log(`Account not logged in ${clientJsToken?.account_name || steamUser.getSteamIdUser() || ""}`);
1743
- console.log(clientJsToken);
1744
- return false;
1745
- }
1746
- } else if (username && password) {
1747
- log(reconnect ? `reconnect with username ${username}` : `login with username ${username}`);
1748
- steamClient.logOn({
1749
- accountName: username,
1750
- password: password,
1751
- rememberPassword: true,
1752
- machineName: "Natri",
1753
- });
1754
- return true;
1755
- } else {
1756
- log(`Account not logged in ${clientJsToken?.account_name || ""}`);
1757
- return false;
1758
- }
1759
- }
1760
-
1761
- function logOff() {
1762
- isLogOff = true;
1763
- logOffEvent?.(true);
1764
- steamClient.logOff();
1765
- }
1766
-
1767
- function onCookie(callback) {
1768
- if (getCookies()) {
1769
- callback(getCookies());
1770
- } else {
1771
- onEvent(
1772
- "webSession",
1773
- function (webSession) {
1774
- callback(webSession?.cookies?.join?.(";"));
1775
- },
1776
- true,
1777
- );
1778
- }
1779
- }
1780
-
1781
- async function init() {
1782
- bindEvent();
1783
- if (await login()) {
1784
- steamClient._handlerManager.add(Protos.csgo.EMsg.k_EMsgClientRequestedClientStats, function (payload) {
1785
- const result = protoDecode(Protos.csgo.CMsgClientRequestedClientStats, payload.toBuffer());
1786
- // console.log("CMsgClientRequestedClientStats", result);
1787
- });
1788
- steamClient._handlerManager.add(Protos.csgo.EMsg.k_EMsgClientMMSLobbyData, function (payload) {
1789
- const result = protoDecode(Protos.csgo.CMsgClientMMSLobbyData, payload.toBuffer());
1790
- // console.log("CMsgClientMMSLobbyData", result, result.metadata);
1791
- });
1792
- }
1793
- }
1794
-
1795
- function partyRegister() {
1796
- if (prime === null) {
1797
- _partyRegister(true);
1798
- _partyRegister(false);
1799
- } else {
1800
- _partyRegister(prime);
1801
- }
1802
- }
1803
-
1804
- function _partyRegister(prime) {
1805
- log("partyRegister", prime);
1806
- lastTimePartyRegister = new Date().getTime();
1807
- steamClient.sendToGC(
1808
- 730,
1809
- Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Party_Register,
1810
- {},
1811
- protoEncode(Protos.csgo.CMsgGCCStrike15_v2_Party_Register, {
1812
- // id : 0,
1813
- ver: CSGO_VER,
1814
- apr: prime ? 1 : 0, //prime
1815
- ark: prime ? 180 : 0,
1816
- grps: [],
1817
- launcher: 0,
1818
- game_type: 8,
1819
- }),
1820
- );
1821
- }
1822
-
1823
- async function sendFriendMessage(steamId, message) {
1824
- while (sendMessageTimestamp && new Date().getTime() - sendMessageTimestamp < 2000) {
1825
- await sleep(1000);
1826
- }
1827
-
1828
- while (isSendingFriendMessages) {
1829
- await sleep(5000);
1830
- }
1831
-
1832
- isSendingFriendMessages = true;
1833
- const now = new Date().getTime();
1834
- while (new Date().getTime() - now < 2 * 60000) {
1835
- //2 minutes
1836
- const result = await new Promise((resolve) => {
1837
- steamClient.chat.sendFriendMessage(steamId, message, undefined, function (...arg) {
1838
- sendMessageTimestamp = new Date().getTime();
1839
- resolve(arg);
1840
- });
1841
- });
1842
-
1843
- if (result?.[1]?.server_timestamp) {
1844
- isSendingFriendMessages = false;
1845
- return result?.[1];
1846
- } else if (result?.[0]?.message?.includes?.("RateLimitExceeded")) {
1847
- await sleep(5000);
1848
- } else {
1849
- isSendingFriendMessages = false;
1850
- return result;
1851
- }
1852
- }
1853
- isSendingFriendMessages = false;
1854
- }
1855
-
1856
- async function autoRequestFreeLicense(shouldLog = false, max = 10) {
1857
- return;
1858
- // const mCookies = await getCookiesWait()
1859
- // if (!mCookies) return
1860
- // let freeAppList = Array.isArray(steamClient.licenses) ? FreeAppList.filter(appId => steamClient.licenses.every(({package_id}) => package_id !== appId)) : FreeAppList;
1861
- const freeAppList = freeAppList.filter((appId) => ownedApps.some((app) => app.appid == appId));
1862
- const recommendedApps = _.shuffle(freeAppList);
1863
- if (max) {
1864
- recommendedApps.length = Math.min(recommendedApps.length, max);
1865
- }
1866
- try {
1867
- const response = await steamClient.requestFreeLicense(recommendedApps);
1868
- if (shouldLog) {
1869
- log(response);
1870
- }
1871
- } catch (e) {
1872
- log(e);
1873
- }
1874
- // if (Math.random() > 0.7) {
1875
- // for (const recommendedApp of recommendedApps) {
1876
- // try {
1877
- // await steamUtils.requestFreeLicense(recommendedApp)
1878
- // } catch (e) {
1879
- // }
1880
- // await sleep(2000)
1881
- // }
1882
- // } else {
1883
- // try {
1884
- // await steamClient.requestFreeLicense(recommendedApps)
1885
- // } catch (e) {
1886
- // log(e);
1887
- // }
1888
- // }
1889
-
1890
- // if (shouldLog) {
1891
- // await sleep(20000)
1892
- // const ownedAppsCount2 = (await steamUtils.getDynamicStoreUserData())?.rgOwnedApps?.length || 0
1893
- // const increaseNumber = ownedAppsCount2 - ownedAppsCount;
1894
- // log(`OwnedApps length ${ownedAppsCount2}, increase ${increaseNumber}`)
1895
- // }
1896
- }
1897
-
1898
- async function playCSGO() {
1899
- try {
1900
- await steamClient.requestFreeLicense(AppID);
1901
- await sleep(5000);
1902
- } catch (e) {}
1903
- gamesPlayed(AppID);
1904
- }
1905
-
1906
- function doFakeGameScore() {
1907
- const maxRound = Math.random() > 0.7 ? 16 : 12;
1908
- const maps = [
1909
- "ar_baggage",
1910
- "ar_dizzy",
1911
- "ar_monastery",
1912
- "ar_shoots",
1913
- "cs_agency",
1914
- "cs_assault",
1915
- "cs_italy",
1916
- "cs_militia",
1917
- "cs_office",
1918
- "de_ancient",
1919
- "de_anubis",
1920
- "de_bank",
1921
- "de_boyard",
1922
- "de_cache",
1923
- "de_canals",
1924
- "de_cbble",
1925
- "de_chalice",
1926
- "de_dust2",
1927
- "de_inferno",
1928
- "de_lake",
1929
- "de_mirage",
1930
- "de_nuke",
1931
- "de_overpass",
1932
- "de_safehouse",
1933
- // "de_shortnuke",
1934
- "de_stmarc",
1935
- "de_sugarcane",
1936
- "de_train",
1937
- "de_tuscan",
1938
- "de_vertigo",
1939
- "dz_ember",
1940
- "dz_vineyard",
1941
- "gd_cbble",
1942
- "training1",
1943
- ];
1944
-
1945
- if (richPresence.myScore === undefined) {
1946
- richPresence.myScore = _.random(0, maxRound);
1947
- }
1948
- if (richPresence.theirScore === undefined) {
1949
- richPresence.theirScore = _.random(0, maxRound);
1950
- }
1951
- if (richPresence.map === undefined) {
1952
- richPresence.map = maps[Math.floor(Math.random() * maps.length)];
1953
- }
1954
- if (richPresence.myScore === maxRound || richPresence.theirScore === maxRound) {
1955
- richPresence.myScore = 0;
1956
- richPresence.theirScore = 0;
1957
- richPresence.map = maps[Math.floor(Math.random() * maps.length)];
1958
- } else {
1959
- const isMyTeamWin = Math.random() > 0.5;
1960
- if (isMyTeamWin) {
1961
- richPresence.myScore++;
1962
- } else {
1963
- richPresence.theirScore++;
1964
- }
1965
- }
1966
-
1967
- const score = richPresence.myScore === 0 && richPresence.theirScore === 0 ? "" : `[ ${richPresence.myScore} : ${richPresence.theirScore} ]`;
1968
- steamClient.uploadRichPresence(730, {
1969
- "game:state": "game",
1970
- steam_display: "#display_GameKnownMapScore",
1971
- connect: "+gcconnectG082AA752",
1972
- version: CSGO_VER.toString(),
1973
- "game:mode": "competitive",
1974
- "game:map": richPresence.map,
1975
- "game:server": "kv",
1976
- watch: _.random(1, 5).toString(),
1977
- "game:score": score,
1978
- });
1979
- }
1980
-
1981
- function updateFakeGameScore() {
1982
- if (isFakeGameScore && getPlayingAppIds().some((a) => a == 730)) {
1983
- doSetInterval(doFakeGameScore, [60000, 180000], "uploadRichPresenceCSGO");
1984
- } else {
1985
- doClearInterval("uploadRichPresenceCSGO");
1986
- }
1987
- }
1988
-
1989
- function updateAutoRequestFreeLicense() {
1990
- if (isAutoRequestFreeLicense) {
1991
- doSetInterval(
1992
- function () {
1993
- autoRequestFreeLicense(false, 50);
1994
- },
1995
- [5 * 60000, 10 * 60000],
1996
- "autoRequestFreeLicense",
1997
- );
1998
- } else {
1999
- doClearInterval("autoRequestFreeLicense");
2000
- }
2001
- }
2002
-
2003
- function updateInvisible() {
2004
- if (isInvisible) {
2005
- steamClient.setPersona(NodeSteamUser.EPersonaState.Invisible);
2006
- state = "Invisible";
2007
- } else {
2008
- steamClient.setPersona(NodeSteamUser.EPersonaState.Online);
2009
- state = "Online";
2010
- }
2011
- }
2012
-
2013
- async function gamesPlayed(apps) {
2014
- if (!Array.isArray(apps)) {
2015
- apps = [apps];
2016
- }
2017
-
2018
- const processedApps = apps.map((app) => {
2019
- if (typeof app == "string") {
2020
- app = { game_id: "15190414816125648896", game_extra_info: app };
2021
- } else if (typeof app === "number" || typeof app != "object") {
2022
- app = { game_id: app };
2023
- }
2024
-
2025
- if (typeof app.game_ip_address == "number") {
2026
- app.game_ip_address = { v4: app.game_ip_address };
2027
- }
2028
-
2029
- return app;
2030
- });
2031
-
2032
- steamClient.gamesPlayed(processedApps);
2033
- if (processedApps.some((app) => parseInt(app.game_id) === 730)) {
2034
- await sleep(500);
2035
- await sendHello();
2036
- }
2037
- updateFakeGameScore();
2038
-
2039
- // await sleep(10000)
2040
- // self.steamUser.uploadRichPresence(730, {
2041
- // status: 'bussssss',
2042
- // 'game:state': 'lobby',
2043
- // steam_display: '#display_watch',
2044
- // currentmap: '#gamemap_de_empire',
2045
- // connect: '+gcconnectG082AA752',
2046
- // 'game:mode': 'competitive'
2047
- // })
2048
- }
2049
-
2050
- function getFriendsList() {
2051
- const methodName = "FriendsList.GetFriendsList#1";
2052
- const { users, myFriends } = steamClient; //object
2053
- /*
2054
- users
2055
- * {
2056
- rich_presence: [],
2057
- player_name: "Kei #SkinsMonkey",
2058
- avatar_hash: [123,4543],
2059
- last_logoff: "2023-05-20T05:00:42.000Z",
2060
- last_logon: "2023-05-20T05:02:16.000Z",
2061
- last_seen_online: "2023-05-20T05:00:42.000Z",
2062
- avatar_url_icon: "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/3e/3e9da0b107ac2ec384759544368a8a977359537a.jpg",
2063
- avatar_url_medium: "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/3e/3e9da0b107ac2ec384759544368a8a977359537a_medium.jpg",
2064
- avatar_url_full: "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/3e/3e9da0b107ac2ec384759544368a8a977359537a_full.jpg"
2065
- }
2066
- *
2067
-
2068
- myFriends
2069
- {
2070
- 76561198365087582: 3,
2071
- 76561199490395123: 3
2072
- }
2073
- * */
2074
- /*steamClient._send({
2075
- msg: 151,
2076
- proto: {
2077
- target_job_name: methodName
2078
- }
2079
- }, Buffer.alloc(0), function (body, hdr) {
2080
- const result = hdr.proto.eresult
2081
- const errorMessage = hdr.proto.error_message
2082
- const responseData = body.toBuffer()
2083
- console.log(`xxx`, result)
2084
- })*/
2085
-
2086
- steamClient.sendToGC(730, 767, {}, Buffer.alloc(0));
2087
- }
2088
-
2089
- async function getUserOwnedApps(steamId = steamClient.steamID) {
2090
- if (!steamId) {
2091
- return [];
2092
- }
2093
- if (typeof steamId?.getSteamID64 === "function") {
2094
- steamId = steamId.getSteamID64();
2095
- }
2096
- const isMe = steamId === steamClient.steamID.getSteamID64();
2097
- if (isMe && ownedApps.length) {
2098
- return ownedApps;
2099
- }
2100
- let result = {};
2101
- try {
2102
- result = await steamClient.getUserOwnedApps(steamId);
2103
- } catch (e) {
2104
- try {
2105
- result = await steamClient.getUserOwnedApps(steamId);
2106
- } catch (e) {
2107
- result = {};
2108
- }
2109
- }
2110
- if (isMe && Array.isArray(result.apps)) {
2111
- ownedApps.length = 0;
2112
- ownedApps.push(...result.apps);
2113
- }
2114
- return result.apps || [];
2115
- const resultExample = {
2116
- app_count: 22,
2117
- apps: [
2118
- {
2119
- content_descriptorids: [],
2120
- appid: 208030,
2121
- name: "Moon Breakers",
2122
- playtime_2weeks: null,
2123
- playtime_forever: 0,
2124
- img_icon_url: "",
2125
- has_community_visible_stats: null,
2126
- playtime_windows_forever: 0,
2127
- playtime_mac_forever: 0,
2128
- playtime_linux_forever: 0,
2129
- rtime_last_played: 0,
2130
- capsule_filename: null,
2131
- sort_as: null,
2132
- has_workshop: null,
2133
- has_market: null,
2134
- has_dlc: null,
2135
- has_leaderboards: null,
2136
- },
2137
- ],
2138
- };
2139
- }
2140
-
2141
- function getPlayingAppIds() {
2142
- return steamClient._playingAppIds || [];
2143
- }
2144
-
2145
- function requestJoinFriendData(token, version) {
2146
- if (!steamClient.steamID) {
2147
- return;
2148
- }
2149
-
2150
- // Parse tokens
2151
- let conBuf = Buffer.from(token.replace(/^\+gcconnect/, "").replace(/^G/, ""), "hex");
2152
- if (conBuf.length !== 12) {
2153
- return;
2154
- }
2155
-
2156
- let joinToken = conBuf.readInt32BE(0);
2157
- let accountID = conBuf.readInt32BE(4);
2158
- let joinIpp = conBuf.readInt32BE(8);
2159
-
2160
- return new Promise((resolve) => {
2161
- pushGCCallback(`requestJoinFriendData_${accountID}`, resolve, 30000);
2162
- steamClient.sendToGC(
2163
- AppID,
2164
- Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientRequestJoinFriendData,
2165
- {},
2166
- protoEncode(Protos.csgo.CMsgGCCStrike15_v2_ClientRequestJoinFriendData, {
2167
- version: version || CSGO_VER,
2168
- account_id: accountID,
2169
- join_token: joinToken,
2170
- join_ipp: joinIpp,
2171
- }),
2172
- );
2173
- });
2174
- }
2175
-
2176
- function redeemFreeReward(itemIds, generation_time) {
2177
- console.log(`Sent message to GC: AppID ${AppID}, MessageType ${Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientRedeemFreeReward}`);
2178
-
2179
- const encodedMessages = protoEncode(Protos.csgo.CMsgGCCstrike15_v2_ClientRedeemFreeReward, {
2180
- items: itemIds,
2181
- redeemable_balance: 0,
2182
- generation_time: generation_time,
2183
- });
2184
- steamClient.sendToGC(730, Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientRedeemFreeReward, {}, encodedMessages, function (payload) {
2185
- console.log(payload);
2186
- });
2187
-
2188
- setTimeout(function () {
2189
- steamClient._send(
2190
- {
2191
- msg: Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientRedeemFreeReward,
2192
- proto: {
2193
- steamid: steamClient.steamID.getSteamID64(),
2194
- routing_appid: 730,
2195
- },
2196
- },
2197
- encodedMessages,
2198
- function (payload) {
2199
- console.log(payload);
2200
- },
2201
- );
2202
- }, 30000);
2203
- }
2204
-
2205
- function requestRankingInfo() {
2206
- return new Promise((resolve) => {
2207
- const timeout = setTimeout(function () {
2208
- resolve();
2209
- }, 30000);
2210
-
2211
- steamClient._send(
2212
- {
2213
- msg: Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientGCRankUpdate,
2214
- proto: {
2215
- steamid: steamClient.steamID.getSteamID64(),
2216
- routing_appid: 730,
2217
- },
2218
- },
2219
- protoEncode(Protos.csgo.CMsgGCCStrike15_v2_ClientGCRankUpdate, {
2220
- rankings: [
2221
- {
2222
- rank_type_id: 7, //wing man
2223
- },
2224
- {
2225
- rank_type_id: 10, //dangerzone
2226
- },
2227
- {
2228
- rank_type_id: 11, //premier elo
2229
- },
2230
- ],
2231
- }),
2232
- function (payload) {
2233
- clearTimeout(timeout);
2234
- resolve(payload);
2235
- },
2236
- );
2237
- });
2238
- }
2239
-
2240
- return {
2241
- init,
2242
- partySearch,
2243
- invite2Lobby,
2244
- createLobby,
2245
- updateLobby,
2246
- createThenInvite2Lobby,
2247
- joinLobby,
2248
- getLobbyData,
2249
- partyRegister,
2250
- requestCoPlays,
2251
- getPersonas,
2252
- getUsername() {
2253
- return username;
2254
- },
2255
- getCookies,
2256
- getCookiesWait,
2257
- getLogOnDetails() {
2258
- return steamClient?._logOnDetails;
2259
- },
2260
- onEvent,
2261
- offEvent,
2262
- offAllEvent,
2263
- setPersona(state, name) {
2264
- steamClient.setPersona(state, name);
2265
- },
2266
- sendFriendMessage,
2267
- sendFriendTyping,
2268
- getSteamClient() {
2269
- return steamClient;
2270
- },
2271
- getAccountInfoName,
2272
- getPersonaName,
2273
- async getPlayersProfile(steamId, retry = 3) {
2274
- for (let i = 0; i < retry; i++) {
2275
- const profile = await getPlayersProfile(steamId);
2276
- if (profile) {
2277
- return profile;
2278
- }
2279
- }
2280
- return null;
2281
- },
2282
- autoRequestFreeLicense,
2283
- playCSGO,
2284
- doSetInterval,
2285
- doClearIntervals,
2286
- gamesPlayed,
2287
- sendHello,
2288
- checkPlayerPrimeStatus,
2289
- doClearInterval,
2290
- gamePlay,
2291
- autoGamePlay,
2292
- offAutoGamePlay,
2293
- updateAutoGamePlay,
2294
- getFriendsList,
2295
- setIsPartyRegister(change) {
2296
- change = !!change;
2297
- if (isPartyRegister !== change) {
2298
- isPartyRegister = change;
2299
- if (!isPartyRegister) {
2300
- doClearInterval("autoPartyRegister");
2301
- } else {
2302
- sendHello();
2303
- }
2304
- }
2305
- },
2306
- setAutoPlay(change) {
2307
- change = !!change;
2308
- if (isAutoPlay !== change) {
2309
- isAutoPlay = change;
2310
- updateAutoGamePlay();
2311
- }
2312
- },
2313
- setIsInvisible(change) {
2314
- change = !!change;
2315
- if (isInvisible !== change) {
2316
- isInvisible = change;
2317
- updateInvisible();
2318
- }
2319
- },
2320
- setFakeGameScore(change) {
2321
- change = !!change;
2322
- if (isFakeGameScore !== change) {
2323
- isFakeGameScore = change;
2324
- updateFakeGameScore();
2325
- }
2326
- },
2327
- setAutoRequestFreeLicense(change) {
2328
- change = !!change;
2329
- if (isAutoRequestFreeLicense !== change) {
2330
- isAutoRequestFreeLicense = change;
2331
- updateAutoRequestFreeLicense();
2332
- }
2333
- },
2334
- getState() {
2335
- return state;
2336
- },
2337
- log,
2338
- isPrime() {
2339
- return prime === true;
2340
- },
2341
- getFriendList,
2342
- logOff,
2343
- isPlayingBlocked() {
2344
- return playingBlocked;
2345
- },
2346
- async getChatHistory(steamId) {
2347
- if (!steamClient.steamID) return [];
2348
- const mySteamId = typeof steamClient.steamID.getSteamID64 === "function" ? steamClient.steamID.getSteamID64() : steamClient.steamID;
2349
- return new Promise((resolve) => {
2350
- setTimeout(resolve, 90000);
2351
- steamClient.getChatHistory(steamId, async function (error, result) {
2352
- const messages = (result || []).map(function (msg) {
2353
- const fromSteamId = typeof msg.steamID?.getSteamID64 === "function" ? msg.steamID.getSteamID64() : msg.steamID;
2354
- return {
2355
- message: msg.message,
2356
- from: fromSteamId,
2357
- to: fromSteamId == mySteamId ? steamId : mySteamId,
2358
- _id: new Date(msg.timestamp).getTime().toString(),
2359
- timestamp: new Date(msg.timestamp).getTime(),
2360
- isMe: fromSteamId !== steamId,
2361
- };
2362
- });
2363
- resolve(messages);
2364
- });
2365
- });
2366
- },
2367
- onAnyEvent,
2368
- async redeemGift(gid) {
2369
- try {
2370
- const community = new SteamCommunity();
2371
- let cookies = await getCookiesWait();
2372
- community.setCookies(typeof cookies === "string" ? cookies.split(";") : cookies);
2373
- community.redeemGift(gid);
2374
- } catch (e) {}
2375
- },
2376
- async requestFreeLicense(...args) {
2377
- try {
2378
- return await steamClient.requestFreeLicense(...args);
2379
- } catch (e) {}
2380
- },
2381
- getSteamId() {
2382
- try {
2383
- return steamClient.steamID.getSteamID64();
2384
- } catch (e) {}
2385
- },
2386
- getLastTimePartyRegister() {
2387
- return lastTimePartyRegister;
2388
- },
2389
- getLastTimePartySearch() {
2390
- return lastTimePartySearch;
2391
- },
2392
- getLicenses() {
2393
- return steamClient.licenses;
2394
- const exampleLicenses = [
2395
- {
2396
- package_id: 303386,
2397
- time_created: 1680491335,
2398
- time_next_process: 0,
2399
- minute_limit: 0,
2400
- minutes_used: 0,
2401
- payment_method: 1024,
2402
- flags: 512,
2403
- purchase_country_code: "VN",
2404
- license_type: 1,
2405
- territory_code: 0,
2406
- change_number: 20615891,
2407
- owner_id: 1530068060,
2408
- initial_period: 0,
2409
- initial_time_unit: 0,
2410
- renewal_period: 0,
2411
- renewal_time_unit: 0,
2412
- access_token: "8049398090486337961",
2413
- master_package_id: null,
2414
- },
2415
- ];
2416
- },
2417
- uploadRichPresence(appid, richPresence) {
2418
- const _richPresence = Array.isArray(richPresence)
2419
- ? richPresence.reduce(function (previousValue, currentValue, currentIndex, array) {
2420
- if (currentValue.key) {
2421
- previousValue[currentValue.key] = currentValue.value?.toString() || "";
2422
- }
2423
- return previousValue;
2424
- }, {})
2425
- : richPresence;
2426
- steamClient.uploadRichPresence(appid, _richPresence);
2427
- },
2428
- getUserOwnedApps,
2429
- getPlayingAppIds,
2430
- getCurrentLobby() {
2431
- return currentLobby;
2432
- },
2433
- setGame(_games) {
2434
- games = _games;
2435
- },
2436
- getClientHello() {
2437
- return _clientHello;
2438
- },
2439
- getClientWelcome() {
2440
- return _clientWelcome;
2441
- },
2442
- redeemFreeReward,
2443
- requestJoinFriendData,
2444
- };
2445
- }
2446
-
2447
- export default SteamClient;
2448
-
2449
- export function increaseCSGO_VER() {
2450
- return ++CSGO_VER;
2451
- }
2452
-
2453
- SteamClient.isAccountPlayable = async function isAccountPlayable({ cookie, clientJsToken, timeoutMs, onPlayable, onNotPlayable, ...rest }) {
2454
- if (!clientJsToken && cookie) {
2455
- clientJsToken = await new SteamUser(typeof cookie === "function" ? await cookie() : cookie).getClientJsToken();
2456
- }
2457
- if (clientJsToken?.logged_in !== true) {
2458
- if (typeof onNotPlayable === "function") {
2459
- await onNotPlayable(null);
2460
- }
2461
- return { invalidClientJsToken: true };
2462
- }
2463
- return await new Promise((resolve) => {
2464
- const timeouts = [
2465
- setTimeout(() => {
2466
- doResolve({ timedOut: true });
2467
- }, timeoutMs || 30000),
2468
- ];
2469
-
2470
- const steamClient = new SteamClient({
2471
- isFakeGameScore: false,
2472
- isAutoPlay: true,
2473
- isPartyRegister: false,
2474
- isInvisible: true,
2475
- MAX_GAME_PLAY: 10,
2476
- games: 730,
2477
- clientJsToken,
2478
- ...rest,
2479
- });
2480
-
2481
- steamClient.onEvent("error", ({ eresult, msg, error }) => {
2482
- doResolve({ eresult, msg, error });
2483
- });
2484
-
2485
- steamClient.onEvent("csgoOnline", (ClientWelcome) => {
2486
- doResolve({ playable: true });
2487
- });
2488
-
2489
- steamClient.onEvent("csgoClientHello", (ClientHello) => {
2490
- doResolve({ playable: true });
2491
- });
2492
-
2493
- steamClient.onEvent("playingState", ({ playing_blocked, playing_app }) => {
2494
- if (playing_blocked) {
2495
- doResolve({ playable: false });
2496
- } else {
2497
- timeouts.push(
2498
- setTimeout(function () {
2499
- const isBlocked = steamClient.isPlayingBlocked();
2500
- doResolve({ playable: !isBlocked });
2501
- }, 5000),
2502
- );
2503
- }
2504
- });
2505
-
2506
- // steamClient.onEvent("fatalError", () => {
2507
- // doResolve();
2508
- // });
2509
-
2510
- steamClient.init();
2511
-
2512
- async function doResolve(data) {
2513
- timeouts.forEach((timeout) => clearTimeout(timeout));
2514
- steamClient.doClearIntervals();
2515
- steamClient.offAllEvent();
2516
-
2517
- if (data?.playable === true) {
2518
- if (typeof onPlayable === "function") {
2519
- try {
2520
- await onPlayable(steamClient);
2521
- } catch (e) {}
2522
- }
2523
- } else {
2524
- if (typeof onNotPlayable === "function") {
2525
- try {
2526
- await onNotPlayable(steamClient);
2527
- } catch (e) {}
2528
- }
2529
- }
2530
-
2531
- steamClient.logOff();
2532
- return resolve(data);
2533
- }
2534
- });
2535
- };
2536
-
2537
- class XpBonuxFlagsHelper {
2538
- static kCSXpBonusFlags_EarnedXpThisPeriod = 1 << 0;
2539
- static kCSXpBonusFlags_FirstReward = 1 << 1;
2540
- static kCSXpBonusFlags_Msg_YourReportGotConvicted = 1 << 2; // Player Reports
2541
- static kCSXpBonusFlags_Msg_YouPartiedWithCheaters = 1 << 3; // Party Member Banned
2542
- static kCSXpBonusFlags_PrestigeEarned = 1 << 4;
2543
- // ===$CHINAGOVERNMENTCERT$===
2544
- static kCSXpBonusFlags_ChinaGovernmentCert = 1 << 5;
2545
- // ===$CHINAGOVERNMENTCERT$===
2546
-
2547
- // Client-facing bits not backed by SQL
2548
- static kCSXpBonusFlags_OverwatchBonus = 1 << 28; // Overwatch XP Reward
2549
- static kCSXpBonusFlags_BonusBoostConsumed = 1 << 29;
2550
- static kCSXpBonusFlags_ReducedGain = 1 << 30;
2551
-
2552
- static kCSXpBonusFlagsMask_SQLBacked_TimeBased = this.kCSXpBonusFlags_EarnedXpThisPeriod | this.kCSXpBonusFlags_FirstReward;
2553
- static kCSXpBonusFlagsMask_SQLBacked_Notifications = this.kCSXpBonusFlags_Msg_YourReportGotConvicted | this.kCSXpBonusFlags_Msg_YouPartiedWithCheaters;
2554
- static kCSXpBonusFlagsMask_SQLBacked_Permanent = this.kCSXpBonusFlagsMask_SQLBacked_Notifications | this.kCSXpBonusFlags_PrestigeEarned | this.kCSXpBonusFlags_ChinaGovernmentCert;
2555
- static kCSXpBonusFlagsMask_SQLBacked = this.kCSXpBonusFlagsMask_SQLBacked_TimeBased | this.kCSXpBonusFlagsMask_SQLBacked_Permanent;
2556
- static kCSXpBonusFlagsMask_Client_Permanent = this.kCSXpBonusFlags_OverwatchBonus;
2557
- static kCSXpBonusFlagsMask_Client_TimeBased = this.kCSXpBonusFlags_BonusBoostConsumed | this.kCSXpBonusFlags_ReducedGain;
2558
- // TODO: Find "Communication Abuse Reports" flag
2559
-
2560
- static flags = {
2561
- kCSXpBonusFlags_EarnedXpThisPeriod: this.kCSXpBonusFlags_EarnedXpThisPeriod,
2562
- kCSXpBonusFlags_FirstReward: this.kCSXpBonusFlags_FirstReward,
2563
- kCSXpBonusFlags_Msg_YourReportGotConvicted: this.kCSXpBonusFlags_Msg_YourReportGotConvicted,
2564
- kCSXpBonusFlags_Msg_YouPartiedWithCheaters: this.kCSXpBonusFlags_Msg_YouPartiedWithCheaters,
2565
- kCSXpBonusFlags_PrestigeEarned: this.kCSXpBonusFlags_PrestigeEarned,
2566
- kCSXpBonusFlags_ChinaGovernmentCert: this.kCSXpBonusFlags_ChinaGovernmentCert,
2567
- kCSXpBonusFlags_OverwatchBonus: this.kCSXpBonusFlags_OverwatchBonus,
2568
- kCSXpBonusFlags_BonusBoostConsumed: this.kCSXpBonusFlags_BonusBoostConsumed,
2569
- kCSXpBonusFlags_ReducedGain: this.kCSXpBonusFlags_ReducedGain,
2570
- kCSXpBonusFlagsMask_SQLBacked_TimeBased: this.kCSXpBonusFlagsMask_SQLBacked_TimeBased,
2571
- kCSXpBonusFlagsMask_SQLBacked_Notifications: this.kCSXpBonusFlagsMask_SQLBacked_Notifications,
2572
- kCSXpBonusFlagsMask_SQLBacked_Permanent: this.kCSXpBonusFlagsMask_SQLBacked_Permanent,
2573
- kCSXpBonusFlagsMask_SQLBacked: this.kCSXpBonusFlagsMask_SQLBacked,
2574
- kCSXpBonusFlagsMask_Client_Permanent: this.kCSXpBonusFlagsMask_Client_Permanent,
2575
- kCSXpBonusFlagsMask_Client_TimeBased: this.kCSXpBonusFlagsMask_Client_TimeBased,
2576
- };
2577
-
2578
- static stringFlags = {
2579
- kCSXpBonusFlags_EarnedXpThisPeriod: undefined,
2580
- kCSXpBonusFlags_FirstReward: undefined,
2581
- kCSXpBonusFlags_Msg_YourReportGotConvicted: {
2582
- title: "Player Reports",
2583
- description: "A player you reported has been convicted for cheating",
2584
- },
2585
- kCSXpBonusFlags_Msg_YouPartiedWithCheaters: {
2586
- title: "Party Member Banned",
2587
- description: "You partied with a player who has been convicted for cheating. Your skill group and XP have been adjusted",
2588
- },
2589
- kCSXpBonusFlags_PrestigeEarned: undefined,
2590
- kCSXpBonusFlags_ChinaGovernmentCert: undefined,
2591
- kCSXpBonusFlags_OverwatchBonus: {
2592
- title: "Overwatch XP Reward",
2593
- description: "You have submitted accurate verdicts and qualified for an Overwatch Investigator XP reward",
2594
- },
2595
- kCSXpBonusFlags_BonusBoostConsumed: undefined,
2596
- kCSXpBonusFlags_ReducedGain: undefined,
2597
- kCSXpBonusFlagsMask_SQLBacked_TimeBased: undefined,
2598
- kCSXpBonusFlagsMask_SQLBacked_Notifications: undefined,
2599
- kCSXpBonusFlagsMask_SQLBacked_Permanent: undefined,
2600
- kCSXpBonusFlagsMask_SQLBacked: undefined,
2601
- kCSXpBonusFlagsMask_Client_Permanent: undefined,
2602
- kCSXpBonusFlagsMask_Client_TimeBased: undefined,
2603
- };
2604
-
2605
- // To be fair this whole thing is way over the top for just trying to print to console if you have bonus Overwatch XP waiting to be picked up
2606
- // But who cares, doing this for completion. Easier copy pasting for future projects.
2607
-
2608
- static ParseBonusXPFlags(xpFlags) {
2609
- let masks = [];
2610
- for (let flag in this.flags) {
2611
- if ((xpFlags & this.flags[flag]) !== this.flags[flag]) {
2612
- continue;
2613
- }
2614
-
2615
- masks.push(flag);
2616
- }
2617
-
2618
- return masks;
2619
- }
2620
-
2621
- static StringifyFlags(masks) {
2622
- return masks
2623
- .map((mask) => {
2624
- return this.stringFlags[mask];
2625
- })
2626
- .filter((str) => {
2627
- return typeof str === "object";
2628
- });
2629
- }
2630
- }
1
+ import NodeSteamUser from "steam-user";
2
+ import _ from "lodash";
3
+ import fs from "fs";
4
+ import { protoDecode, protoEncode } from "./helpers/util.js";
5
+ import SteamID from "steamid";
6
+ import FriendCode from "csgo-friendcode";
7
+ import axios from "axios";
8
+ import helpers, { loadProfos } from "./helpers/protos.js";
9
+ import { fileURLToPath } from "url";
10
+ import path from "path";
11
+ import SteamUser from "./index.js";
12
+ import { v4 as uuidv4 } from "uuid";
13
+ import EFriendRelationship from "steam-user/enums/EFriendRelationship.js";
14
+ import SteamCommunity from "steamcommunity";
15
+ import moment from "moment-timezone";
16
+ import { encode, encodeUids } from "./bufferHelpers.js";
17
+
18
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
+
20
+ const Protos = helpers([
21
+ {
22
+ name: "csgo",
23
+ protos: loadProfos(`${__dirname}/protos/`),
24
+ },
25
+ ]);
26
+
27
+ export const RANKS = {
28
+ 0: "Unranked",
29
+ 1: "Silver I",
30
+ 2: "Silver II",
31
+ 3: "Silver III",
32
+ 4: "Silver IV",
33
+ 5: "Silver Elite",
34
+ 6: "Silver Elite Master",
35
+ 7: "Gold Nova I",
36
+ 8: "Gold Nova II",
37
+ 9: "Gold Nova III",
38
+ 10: "Gold Nova Master",
39
+ 11: "Master Guardian I",
40
+ 12: "Master Guardian II",
41
+ 13: "Master Guardian Elite",
42
+ 14: "Distinguished Master Guardian",
43
+ 15: "Legendary Eagle",
44
+ 16: "Legendary Eagle Master",
45
+ 17: "Supreme Master First Class",
46
+ 18: "The Global Elite",
47
+ };
48
+ export const LOCS = {
49
+ 20054: "VN",
50
+ 23115: "KZ",
51
+ 20041: "IN",
52
+ 20035: "CN",
53
+ 17474: "BD",
54
+ 17481: "ID",
55
+ 22861: "MY",
56
+ 18516: "TH",
57
+ 22356: "TW",
58
+ 21067: "KR",
59
+ 19272: "HK",
60
+ 18512: "PH",
61
+ 21842: "RU",
62
+ 16716: "LA",
63
+ 20558: "NP",
64
+ 18259: "SG",
65
+ 19789: "MM",
66
+ 20045: "MN",
67
+ 18251: "KG",
68
+ 18507: "KH",
69
+ 22605: "MX",
70
+ 19280: "PK",
71
+ 20301: "HK/MO", //hongkong or macau
72
+ 21333: "Unknown",
73
+ 21825: "AU",
74
+ 20034: "Unkown",
75
+ };
76
+
77
+ const AppID = 730;
78
+ export let CSGO_VER = 13960;
79
+ export const FreeAppList = JSON.parse(fs.readFileSync(path.join(__dirname, "free_packages.json"))).packages;
80
+
81
+ SteamUser.getAppVersion(AppID).then(function (ver) {
82
+ CSGO_VER = ver;
83
+ });
84
+
85
+ const PersonasCache = [];
86
+ let isSendingFriendMessages = false;
87
+
88
+ function SteamClient({ username, password, cookie, clientJsToken, isAutoRequestFreeLicense = true, isFakeGameScore = true, isPartyRegister = true, isAutoPlay = false, isInvisible = false, autoAcceptTradeRequest = false, autoReconnect = true, MAX_GAME_PLAY = 10, games = null }) {
89
+ const steamClient = new NodeSteamUser();
90
+ let prime = null;
91
+ let state = "Offline"; //InGame, Online, Invisible
92
+ let isLogOff = false;
93
+ let playingBlocked = null;
94
+ const richPresence = {};
95
+ let sendMessageTimestamp = 0;
96
+ let lastTimePartyRegister = 0;
97
+ let lastTimePartySearch = 0;
98
+ const ownedApps = [];
99
+ let logOffEvent = null;
100
+
101
+ let _clientWelcome = null;
102
+ let _clientHello = null;
103
+
104
+ const currentLobby = {
105
+ lobbyID: null,
106
+ timestamp: 0,
107
+ };
108
+
109
+ const onAnyCallbacks = [];
110
+
111
+ const events = {
112
+ user: [],
113
+ loggedOn: [],
114
+ csgoOnline: [],
115
+ csgoClientHello: [],
116
+ webSession: [],
117
+ friendMessage: [],
118
+ friendTyping: [],
119
+ disconnected: [],
120
+ error: [],
121
+ playersProfile: [],
122
+ fatalError: [],
123
+ partyInvite: [],
124
+ friendRelationship: [],
125
+ tradeOffers: [],
126
+ offlineMessages: [],
127
+ friendsList: [],
128
+ gifts: [],
129
+ playingState: [],
130
+ emailInfo: [],
131
+ accountLimitations: [],
132
+ };
133
+
134
+ const gcCallback = {};
135
+
136
+ function pushGCCallback(name, cb, timeout) {
137
+ if (!gcCallback[name]) {
138
+ gcCallback[name] = {};
139
+ }
140
+ let t = null;
141
+ let id = uuidv4();
142
+
143
+ function callback(...arg) {
144
+ if (t) {
145
+ clearTimeout(t);
146
+ }
147
+ delete gcCallback[name][id];
148
+ cb?.apply(null, arg);
149
+ }
150
+
151
+ if (timeout) {
152
+ t = setTimeout(callback, timeout);
153
+ }
154
+ gcCallback[name][id] = callback;
155
+ }
156
+
157
+ function callGCCallback(name, ...arg) {
158
+ if (gcCallback[name]) {
159
+ for (const id in gcCallback[name]) {
160
+ gcCallback[name][id]?.(...arg);
161
+ }
162
+ }
163
+ }
164
+
165
+ function callEvent(_events, data) {
166
+ const eventName = Object.keys(events).find((eventName) => events[eventName] === _events);
167
+ eventName && onAnyCallbacks.forEach((cb) => cb?.({ eventName, data }));
168
+
169
+ _events?.forEach?.((e) => {
170
+ e.callback?.(data);
171
+ e.timeout && clearTimeout(e.timeout);
172
+ delete e.timeout;
173
+ if (e.once) {
174
+ delete e.callback;
175
+ }
176
+ });
177
+ _.remove(_events, (e) => !e || e?.once);
178
+ }
179
+
180
+ function onEvent(name, callback, once, timeout) {
181
+ if (!events[name]) {
182
+ events[name] = [];
183
+ }
184
+ const t = timeout ? setTimeout(callback, timeout) : null;
185
+ events[name].push({
186
+ once,
187
+ callback,
188
+ timeout: t,
189
+ });
190
+ }
191
+
192
+ function offEvent(name) {
193
+ if (Array.isArray(events[name])) {
194
+ for (const eventElement of events[name]) {
195
+ if (eventElement.timeout) {
196
+ clearTimeout(eventElement.timeout);
197
+ }
198
+ }
199
+ }
200
+
201
+ delete events[name];
202
+ }
203
+
204
+ function onAnyEvent(callback) {
205
+ onAnyCallbacks.push(callback);
206
+ }
207
+
208
+ function offAllEvent() {
209
+ for (const name in events) {
210
+ for (const event of events[name]) {
211
+ if (event.timeout) {
212
+ try {
213
+ clearTimeout(event.timeout);
214
+ } catch (e) {}
215
+ delete event.timeout;
216
+ }
217
+ }
218
+ delete events[name];
219
+ }
220
+ onAnyCallbacks.length = 0;
221
+ }
222
+
223
+ const intervals = {};
224
+ const intervalRandoms = {};
225
+
226
+ function doSetInterval(cb, timeout, key) {
227
+ const isRandom = Array.isArray(timeout);
228
+ if (!key) {
229
+ key = uuidv4();
230
+ }
231
+ if (isRandom) {
232
+ if (intervalRandoms[key] !== undefined) {
233
+ try {
234
+ clearTimeout(intervalRandoms[key]);
235
+ } catch (e) {}
236
+ }
237
+ intervalRandoms[key] = setTimeout(
238
+ function () {
239
+ doSetInterval(cb, timeout, key);
240
+ if (state !== "Offline") {
241
+ cb();
242
+ }
243
+ },
244
+ _.random(timeout[0], timeout[1]),
245
+ );
246
+ } else {
247
+ if (intervals[key] !== undefined) {
248
+ try {
249
+ clearInterval(intervals[key]);
250
+ } catch (e) {}
251
+ }
252
+
253
+ intervals[key] = setInterval(function () {
254
+ if (state !== "Offline") {
255
+ cb();
256
+ }
257
+ }, timeout);
258
+ }
259
+
260
+ return key;
261
+ }
262
+
263
+ function doClearIntervals() {
264
+ for (const key in intervals) {
265
+ clearInterval(intervals[key]);
266
+ delete intervals[key];
267
+ }
268
+ for (const key in intervalRandoms) {
269
+ clearTimeout(intervalRandoms[key]);
270
+ delete intervalRandoms[key];
271
+ }
272
+ }
273
+
274
+ function doClearInterval(key) {
275
+ try {
276
+ clearInterval(intervals[key]);
277
+ } catch (e) {}
278
+ delete intervals[key];
279
+
280
+ try {
281
+ clearTimeout(intervalRandoms[key]);
282
+ } catch (e) {}
283
+ delete intervalRandoms[key];
284
+ }
285
+
286
+ function getAccountInfoName() {
287
+ return [steamClient?.accountInfo?.name, steamClient?._logOnDetails?.account_name].filter(Boolean).join(" - ");
288
+ }
289
+
290
+ function getPersonaName() {
291
+ return steamClient?.accountInfo?.name;
292
+ }
293
+
294
+ function log(...msg) {
295
+ const now = moment().tz("Asia/Ho_Chi_Minh").format("DD/MM/YYYY HH:mm:ss");
296
+ console.log(`[${now}] [${getAccountInfoName()}]`, ...msg);
297
+ }
298
+
299
+ async function getPersonas(steamIDs) {
300
+ const idsToFetch = steamIDs.map((steamId) => (steamId instanceof SteamID ? steamId.getSteamID64() : steamId));
301
+ const notCachedIDs = idsToFetch.filter((id) => !PersonasCache.some((p) => p.id == id));
302
+ const cachedPersonas = PersonasCache.filter((p) => idsToFetch.includes(p.id));
303
+
304
+ if (notCachedIDs.length) {
305
+ let personas = null;
306
+ try {
307
+ personas = (await steamClient.getPersonas(notCachedIDs))?.personas;
308
+ } catch (e) {}
309
+ if (!personas || !Object.keys(personas).length) {
310
+ try {
311
+ personas = (await steamClient.getPersonas(notCachedIDs))?.personas;
312
+ } catch (e) {}
313
+ }
314
+ if (!personas || !Object.keys(personas).length) {
315
+ try {
316
+ personas = (await steamClient.getPersonas(notCachedIDs))?.personas;
317
+ } catch (e) {}
318
+ }
319
+ if (personas && Object.keys(personas).length) {
320
+ for (let sid64 in personas) {
321
+ personas[sid64].id = sid64;
322
+ personas[sid64].avatar_hash = Buffer.from(personas[sid64].avatar_hash).toString("hex");
323
+ PersonasCache.push(personas[sid64]);
324
+ cachedPersonas.push(personas[sid64]);
325
+ }
326
+ }
327
+ }
328
+
329
+ while (PersonasCache.length > 500) {
330
+ PersonasCache.shift();
331
+ }
332
+ return cachedPersonas;
333
+ }
334
+
335
+ function sleep(ms) {
336
+ return new Promise((resolve) => {
337
+ setTimeout(resolve, ms);
338
+ });
339
+ }
340
+
341
+ function getCookies() {
342
+ return cookie || steamClient?.webSession?.cookies?.join?.(";");
343
+ }
344
+
345
+ async function getCookiesWait() {
346
+ return (
347
+ getCookies() ||
348
+ new Promise((resolve) => {
349
+ onEvent(
350
+ "webSession",
351
+ function (webSession) {
352
+ resolve(webSession?.cookies);
353
+ },
354
+ true,
355
+ 30000,
356
+ );
357
+ })
358
+ );
359
+ }
360
+
361
+ async function gamePlay() {
362
+ return await gamesPlayed(730);
363
+ }
364
+
365
+ async function autoGamePlay() {
366
+ await gamePlay();
367
+ doSetInterval(gamePlay, [15 * 60000, 30 * 60000], "autoGamePlay");
368
+ }
369
+
370
+ async function offAutoGamePlay() {
371
+ steamClient.gamesPlayed([]);
372
+ doClearInterval("autoGamePlay");
373
+ }
374
+
375
+ async function updateAutoGamePlay() {
376
+ if (isAutoPlay) {
377
+ autoGamePlay();
378
+ } else {
379
+ offAutoGamePlay();
380
+ }
381
+ }
382
+
383
+ /**
384
+ * Get a list of lobbies (* = Unsure description could be wrong)
385
+ * @param {Number} ver Game version we are searching for
386
+ * @param {Boolean} apr Prime or not*
387
+ * @param {Number} ark Rank multiplied by 10*
388
+ * @param {Array.<Number>} grps *
389
+ * @param {Number} launcher If we are using the China CSGO launcher or not*
390
+ * @param {Number} game_type Game type, 8 Competitive, 10 Wingman
391
+ * @returns {Promise.<Object>}
392
+ */
393
+ async function partySearch({ prime = false, game_type = "Competitive", rank = "Silver Elite", timeout = 5000 } = {}) {
394
+ const players = await new Promise((resolve) => {
395
+ steamClient.sendToGC(
396
+ AppID,
397
+ Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Party_Search,
398
+ {},
399
+ protoEncode(Protos.csgo.CMsgGCCStrike15_v2_Party_Search, {
400
+ ver: CSGO_VER,
401
+ apr: prime ? 1 : 0,
402
+ ark: parseInt(Object.keys(RANKS).find((k) => RANKS[k] === rank)) * 10,
403
+ grps: [],
404
+ launcher: 0,
405
+ game_type: game_type === "Competitive" ? 8 : 10,
406
+ }),
407
+ );
408
+ lastTimePartySearch = new Date().getTime();
409
+ pushGCCallback("partySearch", resolve, timeout);
410
+ });
411
+ if (Array.isArray(players) && players.length) {
412
+ const personas = await getPersonas(players.map((p) => p.steamId));
413
+ for (const player of players) {
414
+ const persona = personas.find((p) => p.id == player.steamId);
415
+ if (persona) {
416
+ player.player_name = persona.player_name;
417
+ player.avatar_hash = persona.avatar_hash;
418
+ }
419
+ }
420
+ }
421
+ return players;
422
+ }
423
+
424
+ async function createLobby() {
425
+ if (!steamClient.steamID) {
426
+ return;
427
+ }
428
+
429
+ return new Promise((resolve) => {
430
+ const timeout = setTimeout(function () {
431
+ resolve();
432
+ }, 30000);
433
+
434
+ steamClient._send(
435
+ {
436
+ msg: Protos.csgo.EMsg.k_EMsgClientMMSCreateLobby,
437
+ proto: {
438
+ steamid: steamClient.steamID.getSteamID64(),
439
+ routing_appid: 730,
440
+ },
441
+ },
442
+ protoEncode(Protos.csgo.CMsgClientMMSCreateLobby, {
443
+ app_id: 730,
444
+ max_members: 1,
445
+ lobby_type: 1,
446
+ lobby_flags: 1,
447
+ }),
448
+ function (payload) {
449
+ clearTimeout(timeout);
450
+ const result = protoDecode(Protos.csgo.CMsgClientMMSCreateLobbyResponse, payload.toBuffer());
451
+ const steam_id_lobby = result.steam_id_lobby.toString();
452
+ currentLobby.lobbyID = steam_id_lobby;
453
+ currentLobby.timestamp = new Date().getTime();
454
+ resolve(steam_id_lobby);
455
+ },
456
+ );
457
+ });
458
+
459
+ // return await getHandlerResult(Protos.csgo.EMsg.k_EMsgClientMMSCreateLobbyResponse, function (payload) {
460
+ // const result = protoDecode(Protos.csgo.CMsgClientMMSCreateLobbyResponse, payload.toBuffer())
461
+ // return result.steam_id_lobby.toString()
462
+ // })
463
+
464
+ // steamClient.sendToGC(730, Protos.csgo.EMsg.k_EMsgClientMMSCreateLobby, {
465
+ // steamid: steamClient.steamID,
466
+ // routing_appid: 730,
467
+ // }, protoEncode(Protos.csgo.CMsgClientMMSCreateLobby, {
468
+ // app_id: 730,
469
+ // max_members: 1,
470
+ // lobby_type: 1,
471
+ // lobby_flags: 1
472
+ // }))
473
+ }
474
+
475
+ async function updateLobby(lobbyID) {
476
+ if (!steamClient.steamID) {
477
+ return;
478
+ }
479
+
480
+ return new Promise((resolve) => {
481
+ const timeout = setTimeout(function () {
482
+ resolve();
483
+ }, 30000);
484
+
485
+ steamClient._send(
486
+ {
487
+ msg: Protos.csgo.EMsg.k_EMsgClientMMSSetLobbyData,
488
+ proto: {
489
+ steamid: steamClient.steamID.getSteamID64(),
490
+ routing_appid: 730,
491
+ },
492
+ },
493
+ protoEncode(Protos.csgo.CMsgClientMMSSetLobbyData, {
494
+ app_id: 730,
495
+ steam_id_lobby: lobbyID,
496
+ steam_id_member: "0",
497
+ max_members: 10,
498
+ lobby_type: 1,
499
+ lobby_flags: 1,
500
+ metadata: encode(
501
+ {
502
+ "game:ark": "0",
503
+ // Country/Message
504
+ "game:loc": "",
505
+ "game:mapgroupname": "mg_de_mirage",
506
+ "game:mode": "competitive",
507
+ "game:prime": "1",
508
+ "game:type": "classic",
509
+ "members:numPlayers": "1",
510
+ "options:action": "custommatch",
511
+ "options:anytypemode": "0",
512
+ "system:access": "private",
513
+ "system:network": "LIVE",
514
+ uids: [steamClient.steamID],
515
+ },
516
+ [0x00, 0x00],
517
+ [0x08],
518
+ { uids: encodeUids },
519
+ ).toBuffer(),
520
+ }),
521
+ function (payload) {
522
+ clearTimeout(timeout);
523
+ const result = protoDecode(Protos.csgo.CMsgClientMMSSetLobbyDataResponse, payload.toBuffer());
524
+ const steam_id_lobby = result.steam_id_lobby.toString();
525
+ currentLobby.lobbyID = steam_id_lobby;
526
+ currentLobby.timestamp = new Date().getTime();
527
+ resolve(steam_id_lobby);
528
+ },
529
+ );
530
+ });
531
+
532
+ // return await getHandlerResult(Protos.csgo.EMsg.k_EMsgClientMMSSetLobbyDataResponse, function (payload) {
533
+ // const result = protoDecode(Protos.csgo.CMsgClientMMSSetLobbyDataResponse, payload.toBuffer())
534
+ // return result.steam_id_lobby.toString()
535
+ // })
536
+ }
537
+
538
+ async function invite2Lobby(lobbyID, steamId) {
539
+ if (!steamClient.steamID) {
540
+ return;
541
+ }
542
+
543
+ steamClient._send(
544
+ {
545
+ msg: Protos.csgo.EMsg.k_EMsgClientMMSInviteToLobby,
546
+ proto: {
547
+ steamid: steamClient.steamID.getSteamID64(),
548
+ routing_appid: 730,
549
+ },
550
+ },
551
+ protoEncode(Protos.csgo.CMsgClientMMSInviteToLobby, {
552
+ app_id: 730,
553
+ steam_id_lobby: lobbyID,
554
+ steam_id_user_invited: steamId,
555
+ }),
556
+ );
557
+
558
+ // lobbyID = new SteamID(lobbyID).accountid;
559
+
560
+ // Protos.csgo.EMsg.k_EMsgGCHInviteUserToLobby
561
+ // Protos.csgo.EMsg.k_EMsgClientMMSInviteToLobby
562
+ // steamClient.sendToGC(730, Protos.csgo.EMsg.k_EMsgClientMMSInviteToLobby, {}, protoEncode(Protos.csgo.CMsgClientMMSInviteToLobby, {
563
+ // app_id: 730,
564
+ // steam_id_lobby: lobbyID,
565
+ // steam_id_user_invited: accountid,
566
+ // }), function (...args) {
567
+ // console.log("invite2Lobby response", args)
568
+ // })
569
+ }
570
+
571
+ async function createThenInvite2Lobby(steamIds, onInvite) {
572
+ if (!steamClient.steamID) {
573
+ return;
574
+ }
575
+
576
+ if (!Array.isArray(steamIds)) {
577
+ steamIds = [steamIds];
578
+ }
579
+
580
+ let lobbyID = null;
581
+ if (currentLobby.lobbyID && currentLobby.timestamp > new Date().getTime() - 30000) {
582
+ //30 seconds
583
+ lobbyID = currentLobby.lobbyID;
584
+ } else {
585
+ lobbyID = await createLobby();
586
+ lobbyID = await updateLobby(lobbyID);
587
+ }
588
+
589
+ for (const steamId of steamIds) {
590
+ onInvite?.(lobbyID, steamId);
591
+ await invite2Lobby(lobbyID, steamId);
592
+ }
593
+
594
+ return lobbyID;
595
+ }
596
+
597
+ async function getLobbyData(lobbyID) {
598
+ if (!steamClient.steamID) {
599
+ return;
600
+ }
601
+
602
+ return new Promise((resolve) => {
603
+ const timeout = setTimeout(function () {
604
+ resolve();
605
+ }, 30000);
606
+
607
+ steamClient._send(
608
+ {
609
+ msg: Protos.csgo.EMsg.k_EMsgClientMMSGetLobbyData,
610
+ proto: {
611
+ steamid: steamClient.steamID.getSteamID64(),
612
+ routing_appid: 730,
613
+ },
614
+ },
615
+ protoEncode(Protos.csgo.CMsgClientMMSGetLobbyData, {
616
+ app_id: 730,
617
+ steam_id_lobby: lobbyID.toString(),
618
+ }),
619
+ function (payload) {
620
+ clearTimeout(timeout);
621
+ const result = protoDecode(Protos.csgo.CMsgClientMMSLobbyData, payload.toBuffer());
622
+ result.steam_id_lobby = result.steam_id_lobby.toString();
623
+ resolve(result);
624
+ },
625
+ );
626
+ });
627
+ }
628
+
629
+ async function joinLobby(lobbyID) {
630
+ log("joinLobby", lobbyID); //SteamID.fromIndividualAccountID(lobbyId).accountid
631
+
632
+ steamClient._send(
633
+ {
634
+ msg: Protos.csgo.EMsg.k_EMsgClientMMSJoinLobby,
635
+ proto: {
636
+ steamid: steamClient.steamID.getSteamID64(),
637
+ routing_appid: 730,
638
+ },
639
+ }, //CMsgClientMMSUserJoinedLobby CMsgClientMMSJoinLobby
640
+ protoEncode(Protos.csgo.CMsgClientMMSJoinLobby, {
641
+ app_id: 730,
642
+ steam_id_lobby: lobbyID,
643
+ persona_name: steamClient.accountInfo.name,
644
+ }),
645
+ function (payload) {
646
+ const result = protoDecode(Protos.csgo.CMsgClientMMSJoinLobbyResponse, payload.toBuffer());
647
+ result.steam_id_lobby = result.steam_id_lobby.toString();
648
+ result.steam_id_owner = result.steam_id_owner.toString();
649
+ console.log(result);
650
+ const resultExample = {
651
+ members: [],
652
+ app_id: 730,
653
+ steam_id_lobby: "3641224920",
654
+ chat_room_enter_response: 2,
655
+ max_members: 0,
656
+ lobby_type: 0,
657
+ lobby_flags: 0,
658
+ steam_id_owner: "0",
659
+ metadata: null, //Buffer
660
+ };
661
+ },
662
+ );
663
+ }
664
+
665
+ async function sendHello() {
666
+ steamClient.sendToGC(AppID, Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_MatchmakingClient2GCHello, {}, Buffer.alloc(0));
667
+ // steamClient.sendToGC(AppID, Protos.csgo.EGCBaseClientMsg.k_EMsgGCClientHello, {}, Buffer.alloc(0));
668
+
669
+ steamClient.sendToGC(
670
+ AppID,
671
+ Protos.csgo.EGCBaseClientMsg.k_EMsgGCClientHello,
672
+ {},
673
+ protoEncode(Protos.csgo.CMsgClientHello, {
674
+ version: 2000258, //get from https://github.com/SteamDatabase/GameTracking-CS2/commits
675
+ client_session_need: 0,
676
+ client_launcher: 0,
677
+ steam_launcher: 0,
678
+ }),
679
+ );
680
+ }
681
+
682
+ async function requestCoPlays() {
683
+ return new Promise((resolve) => {
684
+ steamClient.sendToGC(AppID, Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Account_RequestCoPlays, {}, Buffer.alloc(0));
685
+ pushGCCallback("RequestCoPlays", resolve, 30000);
686
+ });
687
+ }
688
+
689
+ function bindEvent() {
690
+ const _events = {
691
+ async disconnected(eresult, msg) {
692
+ state = "Offline";
693
+ log("disconnected", eresult, msg);
694
+
695
+ callEvent(events.disconnected, { eresult, msg });
696
+
697
+ if (["ServiceUnavailable", "NoConnection"].includes(msg) && autoReconnect && !isLogOff) {
698
+ async function relogin(retry) {
699
+ if (isLogOff) {
700
+ console.error("Cannot relogin (logoff)");
701
+ return false;
702
+ } else if (retry <= 0) {
703
+ console.error("Cannot relogin");
704
+ return false;
705
+ } else {
706
+ const isSuccess = await login(true);
707
+ if (isSuccess) {
708
+ const loggedOnResponse = await new Promise((resolve) => {
709
+ onEvent("loggedOn", resolve, true, 180000);
710
+ });
711
+ if (loggedOnResponse) {
712
+ console.log("Relogin success");
713
+ return true;
714
+ } else {
715
+ const isLogOff = await new Promise((resolve, reject) => {
716
+ logOffEvent = resolve;
717
+ setTimeout(resolve, 120000);
718
+ });
719
+ logOffEvent = null;
720
+ if (isLogOff === true) {
721
+ return false;
722
+ }
723
+ return await relogin(retry - 1);
724
+ }
725
+ } else {
726
+ const isLogOff = await new Promise((resolve, reject) => {
727
+ logOffEvent = resolve;
728
+ setTimeout(resolve, 120000);
729
+ });
730
+ logOffEvent = null;
731
+ if (isLogOff === true) {
732
+ return false;
733
+ }
734
+ return await relogin(retry - 1);
735
+ }
736
+ }
737
+ }
738
+
739
+ const isLogOff = await new Promise((resolve, reject) => {
740
+ logOffEvent = resolve;
741
+ setTimeout(resolve, 60000);
742
+ });
743
+ logOffEvent = null;
744
+ if (isLogOff === true) {
745
+ offAllEvent();
746
+ doClearIntervals();
747
+ } else {
748
+ const isSuccess = await relogin(50);
749
+ if (!isSuccess) {
750
+ offAllEvent();
751
+ doClearIntervals();
752
+ }
753
+ }
754
+ } else {
755
+ offAllEvent();
756
+ doClearIntervals();
757
+ }
758
+ },
759
+ async error(e) {
760
+ let errorStr = "";
761
+ switch (e.eresult) {
762
+ case 5:
763
+ errorStr = "Invalid Password";
764
+ break;
765
+ case 6:
766
+ case 34:
767
+ errorStr = "Logged In Elsewhere";
768
+ break;
769
+ case 84:
770
+ errorStr = "Rate Limit Exceeded";
771
+ break;
772
+ case 65:
773
+ errorStr = "steam guard is invalid";
774
+ break;
775
+ default:
776
+ errorStr = `Unknown: ${e.eresult}`;
777
+ break;
778
+ }
779
+ log(`error [isLogOff: ${isLogOff}]`, e?.message);
780
+ doClearIntervals();
781
+ callEvent(events.error, { eresult: e.eresult, msg: e.message, error: errorStr });
782
+ },
783
+ async webSession(sessionID, cookies) {
784
+ const webSession = { sessionID, cookies };
785
+ steamClient.webSession = webSession;
786
+ callEvent(events.webSession, webSession);
787
+ },
788
+ async receivedFromGC(appid, msgType, payload) {
789
+ const key = getECsgoGCMsgKey(msgType);
790
+ switch (msgType) {
791
+ case Protos.csgo.EMsg.k_EMsgClientChatInvite: {
792
+ log(payload);
793
+ break;
794
+ }
795
+ case Protos.csgo.ECsgoGCMsg.k_EMsgClientMMSJoinLobbyResponse: {
796
+ const msg = protoDecode(Protos.csgo.CMsgClientMMSJoinLobbyResponse, payload);
797
+ log(msg);
798
+ break;
799
+ }
800
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Party_Invite: {
801
+ const msg = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_Party_Invite, payload);
802
+ const sid64 = SteamID.fromIndividualAccountID(msg.accountid).getSteamID64();
803
+ if (events.partyInvite?.length) {
804
+ const personas = await getPersonas([sid64]);
805
+ const player_name = personas.find((p) => p.id == sid64)?.player_name;
806
+ if (player_name === undefined) {
807
+ log(sid64, personas);
808
+ }
809
+ callEvent(events.partyInvite, { player_name, steamId: sid64, lobbyId: msg.lobbyid });
810
+ }
811
+ // log(player_name, `https://steamcommunity.com/profiles/${sid64}`);
812
+ // joinLobby(msg.lobbyid, msg.accountid)
813
+ break;
814
+ }
815
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Account_RequestCoPlays: {
816
+ const msg = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_Account_RequestCoPlays, payload);
817
+ const personas = msg.players.map((p) => SteamID.fromIndividualAccountID(p.accountid));
818
+ callGCCallback("RequestCoPlays", personas);
819
+ break;
820
+ }
821
+ case Protos.csgo.EGCBaseClientMsg.k_EMsgGCClientWelcome: {
822
+ prime = false;
823
+ const CMsgClientWelcome = protoDecode(Protos.csgo.CMsgClientWelcome, payload);
824
+ const obj = {};
825
+ for (const outofdate_cache of CMsgClientWelcome.outofdate_subscribed_caches) {
826
+ for (const cache_object of outofdate_cache.objects) {
827
+ for (const object_data of cache_object.object_data) {
828
+ switch (cache_object.type_id) {
829
+ case 1: {
830
+ const result = protoDecode(Protos.csgo.CSOEconItem, object_data);
831
+ result.id = result.id.toNumber();
832
+ result.original_id = result.original_id.toNumber();
833
+ if (!obj.items) {
834
+ obj.items = {};
835
+ }
836
+ obj.items[result.id] = result;
837
+ break;
838
+ }
839
+ case 2: {
840
+ const result = protoDecode(Protos.csgo.CSOPersonaDataPublic, object_data);
841
+ obj.PersonaDataPublic = result;
842
+ const example = {
843
+ player_level: 4, //CSGO_Profile_Rank
844
+ commendation: {
845
+ cmd_friendly: 149,
846
+ cmd_teaching: 108,
847
+ cmd_leader: 115,
848
+ },
849
+ elevated_state: true,
850
+ };
851
+ break;
852
+ }
853
+ case 5: {
854
+ const result = protoDecode(Protos.csgo.CSOItemRecipe, object_data);
855
+ break;
856
+ }
857
+ case 7: {
858
+ const CSOEconGameAccountClient = protoDecode(Protos.csgo.CSOEconGameAccountClient, object_data);
859
+ const CSOEconGameAccountClientExample = {
860
+ additional_backpack_slots: 0,
861
+ bonus_xp_timestamp_refresh: 1688518800, //Wednesday 1:00:00 AM every week
862
+ bonus_xp_usedflags: 19,
863
+ elevated_state: 5,
864
+ elevated_timestamp: 5,
865
+ }; //1688518800
866
+ if ((CSOEconGameAccountClient.bonus_xp_usedflags & 16) != 0) {
867
+ // EXPBonusFlag::PrestigeEarned
868
+ prime = true;
869
+ CSOEconGameAccountClient.prime = true;
870
+ }
871
+ if (CSOEconGameAccountClient.elevated_state === 5) {
872
+ // bought prime
873
+ prime = true;
874
+ CSOEconGameAccountClient.prime = true;
875
+ }
876
+
877
+ CSOEconGameAccountClient.flags = XpBonuxFlagsHelper.ParseBonusXPFlags(CSOEconGameAccountClient.bonus_xp_usedflags);
878
+ obj.GameAccountClient = CSOEconGameAccountClient;
879
+ break;
880
+ }
881
+
882
+ case 35: {
883
+ // const result =protoDecode(Protos.csgo.CSOSelectedItemPreset, object_data);
884
+ break;
885
+ }
886
+
887
+ case 36: {
888
+ // const result =protoDecode(Protos.csgo.CSOEconItemPresetInstance, object_data);
889
+ break;
890
+ }
891
+ case 38: {
892
+ const result = protoDecode(Protos.csgo.CSOEconItemDropRateBonus, object_data);
893
+ break;
894
+ }
895
+ case 39: {
896
+ const result = protoDecode(Protos.csgo.CSOEconItemLeagueViewPass, object_data);
897
+ break;
898
+ }
899
+ case 40: {
900
+ const result = protoDecode(Protos.csgo.CSOEconItemEventTicket, object_data);
901
+ break;
902
+ }
903
+ case 41: {
904
+ const result = protoDecode(Protos.csgo.CSOAccountSeasonalOperation, object_data);
905
+ break;
906
+ }
907
+ case 42: {
908
+ // const result =protoDecode(Protos.csgo.CSOEconItemTournamentPassport, object_data);
909
+ break;
910
+ }
911
+ case 43: {
912
+ const result = protoDecode(Protos.csgo.CSOEconDefaultEquippedDefinitionInstanceClient, object_data);
913
+ const example = {
914
+ account_id: 1080136620,
915
+ item_definition: 61,
916
+ class_id: 3,
917
+ slot_id: 2,
918
+ };
919
+ break;
920
+ }
921
+ case 45: {
922
+ const result = protoDecode(Protos.csgo.CSOEconCoupon, object_data);
923
+ break;
924
+ }
925
+ case 46: {
926
+ const result = protoDecode(Protos.csgo.CSOQuestProgress, object_data);
927
+ break;
928
+ }
929
+ case 4: {
930
+ const result = protoDecode(Protos.csgo.CSOAccountItemPersonalStore, object_data);
931
+ result.generation_time = result.generation_time * 1000;
932
+ if (Array.isArray(result.items)) {
933
+ result.items = result.items.map((item) => item.toNumber());
934
+ }
935
+ obj.personalStore = result;
936
+ const redeemable_balance = result.redeemable_balance; //2, 0
937
+ //How many rewards they have available to redeem.
938
+ //redeemable_balance 2: not yet claim
939
+ //redeemable_balance 1: claim 1/2
940
+ //redeemable_balance 0: claimed
941
+ break;
942
+ }
943
+
944
+ default: {
945
+ // log("cache_object.type_id", cache_object.type_id);
946
+ }
947
+ }
948
+ }
949
+ }
950
+ }
951
+ _clientWelcome = obj;
952
+ callEvent(events.csgoOnline, obj);
953
+
954
+ if (isPartyRegister) {
955
+ partyRegister();
956
+ doSetInterval(
957
+ function () {
958
+ partyRegister();
959
+ },
960
+ [60000, 120000],
961
+ "autoPartyRegister",
962
+ );
963
+ }
964
+ break;
965
+ }
966
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_MatchmakingGC2ClientUpdate: {
967
+ const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_MatchmakingGC2ClientUpdate, payload);
968
+ break;
969
+ }
970
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_GC2ClientGlobalStats: {
971
+ const result = protoDecode(Protos.csgo.CMsgClientUGSGetGlobalStatsResponse, payload);
972
+ break;
973
+ }
974
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientReportPlayer: {
975
+ const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientReportPlayer, payload);
976
+ break;
977
+ }
978
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_GC2ClientTextMsg: {
979
+ const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_GC2ClientTextMsg, payload);
980
+ break;
981
+ }
982
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_MatchmakingGC2ClientHello: {
983
+ const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_MatchmakingGC2ClientHello, payload);
984
+ const example = {
985
+ my_current_event_teams: [],
986
+ my_current_event_stages: [],
987
+ rankings: [],
988
+ account_id: 1080136620,
989
+ ongoingmatch: null,
990
+ global_stats: {
991
+ search_statistics: [
992
+ {
993
+ game_type: 520,
994
+ search_time_avg: 0,
995
+ players_searching: 5141,
996
+ },
997
+ {
998
+ game_type: 32776,
999
+ search_time_avg: 0,
1000
+ players_searching: 6561,
1001
+ },
1002
+ ],
1003
+ players_online: 617207,
1004
+ servers_online: 230638,
1005
+ players_searching: 13550,
1006
+ servers_available: 126352,
1007
+ ongoing_matches: 23264,
1008
+ search_time_avg: 95993,
1009
+ main_post_url: "xxx",
1010
+ required_appid_version: 13879,
1011
+ pricesheet_version: 1688084844,
1012
+ twitch_streams_version: 2,
1013
+ active_tournament_eventid: 21,
1014
+ active_survey_id: 0,
1015
+ rtime32_cur: 0,
1016
+ rtime32_event_start: 0,
1017
+ },
1018
+ penalty_seconds: 0, //379243
1019
+ penalty_reason: 0, //4 You did too much damage to your teammates at round start ,5: abandoned
1020
+ vac_banned: 0,
1021
+ ranking: {
1022
+ account_id: 1080136620,
1023
+ rank_id: 10,
1024
+ wins: 209,
1025
+ rank_change: 0,
1026
+ rank_type_id: 6,
1027
+ tv_control: 0,
1028
+ },
1029
+ commendation: {
1030
+ cmd_friendly: 149,
1031
+ cmd_teaching: 108,
1032
+ cmd_leader: 115,
1033
+ },
1034
+ medals: null,
1035
+ my_current_event: null,
1036
+ my_current_team: null,
1037
+ survey_vote: 0,
1038
+ activity: null,
1039
+ player_level: 4,
1040
+ player_cur_xp: 327684501,
1041
+ player_xp_bonus_flags: 0,
1042
+ };
1043
+ if (result?.global_stats?.required_appid_version && (!CSGO_VER || result.global_stats.required_appid_version > CSGO_VER)) {
1044
+ CSGO_VER = result.global_stats.required_appid_version;
1045
+ }
1046
+ _clientHello = result;
1047
+ callEvent(events.csgoClientHello, result);
1048
+ break;
1049
+ }
1050
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientReportResponse: {
1051
+ const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientReportResponse, payload);
1052
+ break;
1053
+ }
1054
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientCommendPlayerQueryResponse: {
1055
+ const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientCommendPlayer, payload);
1056
+ break;
1057
+ }
1058
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_PlayerOverwatchCaseAssignment: {
1059
+ const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_PlayerOverwatchCaseAssignment, payload);
1060
+ break;
1061
+ }
1062
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_MatchList: {
1063
+ const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_MatchList, payload);
1064
+ break;
1065
+ }
1066
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_GetEventFavorites_Response: {
1067
+ const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_GetEventFavorites_Response, payload);
1068
+ break;
1069
+ }
1070
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_StartAgreementSessionInGame: {
1071
+ break;
1072
+ }
1073
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_ClientDeepStats: {
1074
+ const result = protoDecode(Protos.csgo.CMsgGCCStrike15_ClientDeepStats, payload);
1075
+ break;
1076
+ }
1077
+ case Protos.csgo.EGCBaseClientMsg.k_EMsgGCClientConnectionStatus: {
1078
+ const result = protoDecode(Protos.csgo.CMsgConnectionStatus, payload);
1079
+ break;
1080
+ }
1081
+ case Protos.csgo.EGCItemMsg.k_EMsgGCStoreGetUserDataResponse: {
1082
+ const result = protoDecode(Protos.csgo.CMsgStoreGetUserDataResponse, payload);
1083
+ break;
1084
+ }
1085
+ case Protos.csgo.EGCItemMsg.k_EMsgGCStorePurchaseFinalizeResponse: {
1086
+ const result = protoDecode(Protos.csgo.CMsgGCStorePurchaseFinalizeResponse, payload);
1087
+ break;
1088
+ }
1089
+ case Protos.csgo.EGCItemMsg.k_EMsgGCStorePurchaseCancelResponse: {
1090
+ const result = protoDecode(Protos.csgo.CMsgGCStorePurchaseCancelResponse, payload);
1091
+ break;
1092
+ }
1093
+ case Protos.csgo.EGCItemMsg.k_EMsgGCStorePurchaseInitResponse: {
1094
+ const result = protoDecode(Protos.csgo.CMsgGCStorePurchaseInitResponse, payload);
1095
+ break;
1096
+ }
1097
+ case Protos.csgo.EMsg.k_EMsgClientMMSCreateLobbyResponse: {
1098
+ const result = protoDecode(Protos.csgo.CMsgClientMMSCreateLobbyResponse, payload);
1099
+ console.log("k_EMsgClientMMSCreateLobbyResponse", result);
1100
+ break;
1101
+ }
1102
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientGCRankUpdate: {
1103
+ const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientGCRankUpdate, payload);
1104
+ break;
1105
+ }
1106
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Party_Search: {
1107
+ const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_Party_SearchResults, payload);
1108
+ const entries = _.uniqBy(result.entries, "id");
1109
+ //{
1110
+ // id: 144900402,
1111
+ // grp: 0,
1112
+ // game_type: 8,
1113
+ // apr: 1,
1114
+ // ark: 17,
1115
+ // loc: 20041,
1116
+ // accountid: 0
1117
+ // }
1118
+
1119
+ //{
1120
+ // id: "76561199265943339",
1121
+ // rich_presence: [],
1122
+ // persona_state: null,
1123
+ // game_played_app_id: null,
1124
+ // game_server_ip: null,
1125
+ // game_server_port: null,
1126
+ // persona_state_flags: null,
1127
+ // online_session_instances: null,
1128
+ // persona_set_by_user: null,
1129
+ // player_name: "杀人不见血",
1130
+ // query_port: null,
1131
+ // steamid_source: null,
1132
+ // avatar_hash: "33994e26f1fe7e2093f8c7dee66c1ac91531050d",
1133
+ // last_logoff: null,
1134
+ // last_logon: null,
1135
+ // last_seen_online: null,
1136
+ // clan_rank: null,
1137
+ // game_name: null,
1138
+ // gameid: null,
1139
+ // game_data_blob: null,
1140
+ // clan_data: null,
1141
+ // clan_tag: null,
1142
+ // broadcast_id: null,
1143
+ // game_lobby_id: null,
1144
+ // watching_broadcast_accountid: null,
1145
+ // watching_broadcast_appid: null,
1146
+ // watching_broadcast_viewers: null,
1147
+ // watching_broadcast_title: null,
1148
+ // is_community_banned: null,
1149
+ // player_name_pending_review: null,
1150
+ // avatar_pending_review: null,
1151
+ // avatar_url_icon: "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/33/33994e26f1fe7e2093f8c7dee66c1ac91531050d.jpg",
1152
+ // avatar_url_medium: "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/33/33994e26f1fe7e2093f8c7dee66c1ac91531050d_medium.jpg",
1153
+ // avatar_url_full: "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/33/33994e26f1fe7e2093f8c7dee66c1ac91531050d_full.jpg"
1154
+ // }
1155
+
1156
+ const players = [];
1157
+ for (const player of entries) {
1158
+ try {
1159
+ const prime = player.apr === 1 ? "PRIME" : "NON-PRIME";
1160
+ const loc = LOCS[player.loc] || player.loc;
1161
+ const steamId = SteamID.fromIndividualAccountID(player.id).getSteamID64();
1162
+ const friendCode = FriendCode.encode(steamId);
1163
+
1164
+ // if ((LOCS[player.loc] == 'VN' || !LOCS[player.loc])) {
1165
+ players.push({
1166
+ prime,
1167
+ rank: RANKS[player.ark] !== undefined ? RANKS[player.ark] : player.ark,
1168
+ loc,
1169
+ steamId,
1170
+ friendCode,
1171
+ });
1172
+ // }
1173
+ } catch (e) {}
1174
+ }
1175
+
1176
+ callGCCallback("partySearch", players);
1177
+ break;
1178
+ }
1179
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_PlayersProfile: {
1180
+ let data = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_PlayersProfile, payload)?.account_profiles;
1181
+ const dataExample = [
1182
+ {
1183
+ my_current_event_teams: [],
1184
+ my_current_event_stages: [],
1185
+ rankings: [
1186
+ {
1187
+ account_id: 1225887169,
1188
+ rank_id: 0,
1189
+ wins: 6,
1190
+ rank_change: 0,
1191
+ rank_type_id: 7,
1192
+ tv_control: 0,
1193
+ },
1194
+ {
1195
+ account_id: 1225887169,
1196
+ rank_id: 0,
1197
+ wins: 0,
1198
+ rank_change: 0,
1199
+ rank_type_id: 10,
1200
+ tv_control: 0,
1201
+ },
1202
+ ],
1203
+ account_id: 1225887169,
1204
+ ongoingmatch: null,
1205
+ global_stats: null,
1206
+ penalty_seconds: 0,
1207
+ penalty_reason: 0,
1208
+ vac_banned: 0,
1209
+ ranking: {
1210
+ account_id: 1225887169,
1211
+ rank_id: 8,
1212
+ wins: 469,
1213
+ rank_change: 0,
1214
+ rank_type_id: 6,
1215
+ tv_control: 0,
1216
+ },
1217
+ commendation: {
1218
+ cmd_friendly: 51,
1219
+ cmd_teaching: 40,
1220
+ cmd_leader: 40,
1221
+ },
1222
+ medals: {
1223
+ display_items_defidx: [4819, 4737],
1224
+ featured_display_item_defidx: 4819,
1225
+ },
1226
+ my_current_event: null,
1227
+ my_current_team: null,
1228
+ survey_vote: 0,
1229
+ activity: null,
1230
+ player_level: 32,
1231
+ player_cur_xp: 327682846,
1232
+ player_xp_bonus_flags: 0,
1233
+ },
1234
+ ];
1235
+
1236
+ const player = data?.[0];
1237
+ if (player) {
1238
+ player.prime = !!(player.ranking?.account_id || player.player_level || player.player_cur_xp);
1239
+ player.steamId = SteamID.fromIndividualAccountID(player.account_id).getSteamID64();
1240
+ callGCCallback(`PlayersProfile_${player.account_id}`, player);
1241
+ }
1242
+ callEvent(events.playersProfile, player);
1243
+ break;
1244
+ }
1245
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientLogonFatalError: {
1246
+ const data = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientLogonFatalError, payload);
1247
+ const dataExample = {
1248
+ errorcode: 4,
1249
+ message: "",
1250
+ country: "VN",
1251
+ };
1252
+ callEvent(events.fatalError, data);
1253
+ break;
1254
+ }
1255
+ case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientRequestJoinFriendData: {
1256
+ const data = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientRequestJoinFriendData, payload);
1257
+ if (!data?.account_id) {
1258
+ return;
1259
+ }
1260
+ const dataExample = {
1261
+ version: 14009,
1262
+ account_id: 1594592618,
1263
+ join_token: 1431405434,
1264
+ join_ipp: 1318239032,
1265
+ res: null,
1266
+ errormsg: "Game is full",
1267
+ };
1268
+ callGCCallback(`requestJoinFriendData_${data.account_id}`, data);
1269
+ break;
1270
+ }
1271
+ default:
1272
+ log(`receivedFromGC ${msgType} ${key}`);
1273
+ const results = Object.values(Protos.csgo)
1274
+ .map(function (p) {
1275
+ try {
1276
+ return protoDecode(p, payload);
1277
+ } catch (e) {}
1278
+ })
1279
+ .filter(function (result) {
1280
+ return result && Object.keys(result).length;
1281
+ });
1282
+ log(key, results);
1283
+ }
1284
+ },
1285
+ async loggedOn(loggedOnResponse) {
1286
+ callEvent(events.loggedOn, loggedOnResponse);
1287
+ updateInvisible();
1288
+ updateAutoRequestFreeLicense();
1289
+ updateAutoGamePlay();
1290
+ },
1291
+ async user(steamId, data) {
1292
+ callEvent(events.user, { steamId: steamId.getSteamID64(), data });
1293
+ const dataExample = {
1294
+ rich_presence: [
1295
+ {
1296
+ key: "status",
1297
+ value: "Competitive Mirage [ 3 : 6 ]",
1298
+ },
1299
+ {
1300
+ key: "version",
1301
+ value: "13875",
1302
+ },
1303
+ {
1304
+ key: "game:state",
1305
+ value: "game",
1306
+ },
1307
+ {
1308
+ key: "steam_display",
1309
+ value: "#display_GameKnownMapScore",
1310
+ },
1311
+ {
1312
+ key: "game:mode",
1313
+ value: "competitive",
1314
+ },
1315
+ {
1316
+ key: "game:mapgroupname",
1317
+ value: "mg_de_mirage",
1318
+ },
1319
+ {
1320
+ key: "game:map",
1321
+ value: "de_mirage",
1322
+ },
1323
+ {
1324
+ key: "game:server",
1325
+ value: "kv",
1326
+ },
1327
+ {
1328
+ key: "watch",
1329
+ value: "1",
1330
+ },
1331
+ {
1332
+ key: "steam_player_group",
1333
+ value: "2134948645",
1334
+ },
1335
+ {
1336
+ key: "game:score",
1337
+ value: "[ 3 : 6 ]",
1338
+ },
1339
+ ],
1340
+ friendid: "76561199405834425",
1341
+ persona_state: 1,
1342
+ game_played_app_id: 730,
1343
+ game_server_ip: null,
1344
+ game_server_port: null,
1345
+ persona_state_flags: 1,
1346
+ online_session_instances: 1,
1347
+ persona_set_by_user: null,
1348
+ player_name: "quỷ súng",
1349
+ query_port: null,
1350
+ steamid_source: "0",
1351
+ avatar_hash: {
1352
+ type: "Buffer",
1353
+ data: [23, 163, 216, 209, 236, 179, 73, 228, 225, 30, 48, 190, 192, 170, 177, 246, 139, 71, 122, 205],
1354
+ },
1355
+ last_logoff: 1683950268,
1356
+ last_logon: 1683950281,
1357
+ last_seen_online: 1683950268,
1358
+ clan_rank: null,
1359
+ game_name: "",
1360
+ gameid: "730",
1361
+ game_data_blob: {
1362
+ type: "Buffer",
1363
+ data: [],
1364
+ },
1365
+ clan_data: null,
1366
+ clan_tag: null,
1367
+ broadcast_id: "0",
1368
+ game_lobby_id: "0",
1369
+ watching_broadcast_accountid: null,
1370
+ watching_broadcast_appid: null,
1371
+ watching_broadcast_viewers: null,
1372
+ watching_broadcast_title: null,
1373
+ is_community_banned: null,
1374
+ player_name_pending_review: null,
1375
+ avatar_pending_review: null,
1376
+ };
1377
+ },
1378
+ async playingState(playing_blocked, playing_app) {
1379
+ playingBlocked = playing_blocked;
1380
+ if (playing_app === 0) {
1381
+ playing_app = null;
1382
+ }
1383
+ if (playing_blocked) {
1384
+ //true, false
1385
+ console.log("Playing else where");
1386
+ }
1387
+ log("playingState", playing_blocked, playing_app);
1388
+ callEvent(events.playingState, { playing_blocked, playing_app });
1389
+ },
1390
+ async friendRelationship(sid, relationship, previousRelationship) {
1391
+ callEvent(events.friendRelationship, {
1392
+ steamId: sid.getSteamID64(),
1393
+ relationship,
1394
+ previousRelationship,
1395
+ });
1396
+ switch (relationship) {
1397
+ case EFriendRelationship.None: {
1398
+ //we got unfriended.
1399
+ break;
1400
+ }
1401
+ case EFriendRelationship.RequestRecipient: {
1402
+ //we got invited as a friend
1403
+ break;
1404
+ }
1405
+ case EFriendRelationship.Friend: {
1406
+ //we got added as a friend
1407
+ break;
1408
+ }
1409
+ }
1410
+ },
1411
+ async tradeOffers(count) {
1412
+ callEvent(events.tradeOffers, count);
1413
+ },
1414
+ async offlineMessages(count, friends) {
1415
+ callEvent(events.offlineMessages, { count, steamIdList: friends });
1416
+ },
1417
+ async tradeRequest(steamID, respond) {
1418
+ if (autoAcceptTradeRequest) {
1419
+ log(`Incoming trade request from ${steamID.getSteam3RenderedID()}, accepting`);
1420
+ respond(true);
1421
+ } else {
1422
+ log(`Incoming trade request from ${steamID.getSteam3RenderedID()}, wating`);
1423
+ }
1424
+ },
1425
+ async friendsList() {
1426
+ callEvent(events.friendsList, getFriendList());
1427
+ },
1428
+ async gifts(gid, packageid, TimeCreated, TimeExpiration, TimeSent, TimeAcked, TimeRedeemed, RecipientAddress, SenderAddress, SenderName) {
1429
+ callEvent(events.gifts, {
1430
+ gid,
1431
+ packageid,
1432
+ TimeCreated,
1433
+ TimeExpiration,
1434
+ TimeSent,
1435
+ TimeAcked,
1436
+ TimeRedeemed,
1437
+ RecipientAddress,
1438
+ SenderAddress,
1439
+ SenderName,
1440
+ });
1441
+ },
1442
+ async emailInfo(address, validated) {
1443
+ callEvent(events.emailInfo, { address, validated });
1444
+ },
1445
+ async appLaunched() {
1446
+ setTimeout(function () {
1447
+ state = getPlayingAppIds().length ? "InGame" : isInvisible ? "Invisible" : "Online";
1448
+ }, 1000);
1449
+ },
1450
+ async appQuit() {
1451
+ setTimeout(function () {
1452
+ state = getPlayingAppIds().length ? "InGame" : isInvisible ? "Invisible" : "Online";
1453
+ }, 1000);
1454
+ },
1455
+ async accountLimitations(bis_limited_account, bis_community_banned, bis_locked_account, bis_limited_account_allowed_to_invite_friends) {
1456
+ callEvent(events.accountLimitations, {
1457
+ limited: bis_limited_account,
1458
+ communityBanned: bis_community_banned,
1459
+ locked: bis_locked_account,
1460
+ canInviteFriends: bis_limited_account_allowed_to_invite_friends,
1461
+ });
1462
+ },
1463
+ };
1464
+
1465
+ const _chatEvents = {
1466
+ async friendMessage(data) {
1467
+ if (!data) return;
1468
+ data.message_no_bbcode = data.message_no_bbcode?.replaceAll("ː", ":");
1469
+ data.message = data.message?.replaceAll("ː", ":");
1470
+ const example = {
1471
+ steamid_friend: {
1472
+ universe: 1,
1473
+ type: 1,
1474
+ instance: 1,
1475
+ accountid: 1080136620,
1476
+ },
1477
+ chat_entry_type: 1,
1478
+ from_limited_account: false,
1479
+ message: "xxx",
1480
+ ordinal: 0,
1481
+ local_echo: false,
1482
+ message_no_bbcode: "xxx",
1483
+ low_priority: false,
1484
+ server_timestamp: "2023-05-14T09:26:25.000Z",
1485
+ message_bbcode_parsed: ["xxx"],
1486
+ };
1487
+ const timestamp = new Date(data.server_timestamp).getTime();
1488
+ const steamId = data.steamid_friend.getSteamID64();
1489
+ const invite = ["Invited you to play a game!", "Đã mời bạn chơi một trò chơi!"].includes(data.message_no_bbcode || data.message);
1490
+ const emotion = (data.message_no_bbcode || "").split(" ").find((m) => m.startsWith(":") && m.endsWith(":"));
1491
+
1492
+ callEvent(events.friendMessage, {
1493
+ ...data,
1494
+ message: data.message_no_bbcode,
1495
+ invite,
1496
+ steamId,
1497
+ timestamp,
1498
+ emotion,
1499
+ });
1500
+ },
1501
+ async friendTyping(steamId, message) {
1502
+ callEvent(events.friendTyping, {
1503
+ steamId,
1504
+ message,
1505
+ });
1506
+ },
1507
+ };
1508
+
1509
+ // steamClient.on('lobbyInvite', (inviterID, lobbyID ) => {
1510
+ // joinLobby(lobbyID)
1511
+ // })
1512
+
1513
+ // steamClient.on("debug", (msg) => {
1514
+ // if (!["ClientPersonaState", "ClientClanState"].some((c) => msg.includes(c))) {
1515
+ // if (msg.startsWith("Received")) {
1516
+ // console.log(`------- ${msg}`);
1517
+ // } else {
1518
+ // console.log(msg);
1519
+ // }
1520
+ // }
1521
+ // });
1522
+
1523
+ function getECsgoGCMsgKey(_key) {
1524
+ for (let key in Protos.csgo.ECsgoGCMsg) {
1525
+ if (Protos.csgo.ECsgoGCMsg[key] == _key) {
1526
+ return key;
1527
+ }
1528
+ }
1529
+ for (let key in Protos.csgo.EGCBaseClientMsg) {
1530
+ if (Protos.csgo.EGCBaseClientMsg[key] == _key) {
1531
+ return key;
1532
+ }
1533
+ }
1534
+ for (let key in Protos.csgo.EMsg) {
1535
+ if (Protos.csgo.EMsg[key] == _key) {
1536
+ return key;
1537
+ }
1538
+ }
1539
+ for (let key in Protos.csgo.EGCItemMsg) {
1540
+ if (Protos.csgo.EGCItemMsg[key] == _key) {
1541
+ return key;
1542
+ }
1543
+ }
1544
+ }
1545
+
1546
+ for (const [name, _event] of Object.entries(_events)) {
1547
+ steamClient.on(name, _event);
1548
+ }
1549
+
1550
+ for (const [name, _event] of Object.entries(_chatEvents)) {
1551
+ steamClient.chat.on(name, _event);
1552
+ }
1553
+ }
1554
+
1555
+ function getHandlerResult(msg, handler) {
1556
+ const timeout = { current: null };
1557
+ return new Promise((resolve) => {
1558
+ function myhandler(...args) {
1559
+ timeout.current && clearTimeout(timeout.current);
1560
+ removeHandler();
1561
+ resolve(handler?.(...args));
1562
+ }
1563
+
1564
+ function removeHandler() {
1565
+ if (Array.isArray(steamClient._handlerManager._handlers[msg])) {
1566
+ const index = steamClient._handlerManager._handlers[msg].findIndex((_handler) => _handler === myhandler);
1567
+ if (index > -1) {
1568
+ steamClient._handlerManager._handlers[msg].splice(index, 1);
1569
+ }
1570
+ }
1571
+ }
1572
+
1573
+ timeout.current = setTimeout(function () {
1574
+ removeHandler();
1575
+ resolve();
1576
+ }, 60000);
1577
+ steamClient._handlerManager.add(msg, myhandler);
1578
+ });
1579
+ }
1580
+
1581
+ function getFriendList() {
1582
+ return Object.keys(steamClient.myFriends).filter((steamId) => steamClient.myFriends[steamId] === NodeSteamUser.EFriendRelationship.Friend);
1583
+ }
1584
+
1585
+ function sendFriendTyping(steamId, callback) {
1586
+ steamClient.chat.sendFriendTyping(steamId, callback);
1587
+ }
1588
+
1589
+ /*
1590
+ * usually take 400 -> 800 miliseconds
1591
+ * */
1592
+ function getPlayersProfile(steamId) {
1593
+ const accountid = new SteamID(steamId).accountid;
1594
+ steamClient.sendToGC(
1595
+ 730,
1596
+ Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientRequestPlayersProfile,
1597
+ {},
1598
+ protoEncode(Protos.csgo.CMsgGCCStrike15_v2_ClientRequestPlayersProfile, {
1599
+ account_id: accountid, // account_id: new SteamID('76561199184696945').accountid,
1600
+ request_level: 32,
1601
+ }),
1602
+ );
1603
+ return new Promise((resolve) => {
1604
+ pushGCCallback(`PlayersProfile_${accountid}`, resolve, 2000);
1605
+ });
1606
+ }
1607
+
1608
+ async function checkPlayerPrimeStatus(steamId) {
1609
+ const profile = await getPlayersProfile(steamId);
1610
+ if (!profile) return false;
1611
+
1612
+ if (profile.ranking?.account_id) {
1613
+ return true;
1614
+ }
1615
+
1616
+ if (profile.player_level || profile.player_cur_xp) {
1617
+ return true;
1618
+ }
1619
+ return false;
1620
+ }
1621
+
1622
+ async function _getStoreSteamPoweredResponse(cookie) {
1623
+ let response = null;
1624
+ for (let i = 0; i < 50; i++) {
1625
+ if (!response) {
1626
+ try {
1627
+ response = await axios.request({
1628
+ url: "https://store.steampowered.com/",
1629
+ headers: {
1630
+ cookie,
1631
+ accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.75",
1632
+ },
1633
+ });
1634
+ } catch (e) {
1635
+ await sleep(1000);
1636
+ }
1637
+ }
1638
+ }
1639
+ return response;
1640
+ }
1641
+
1642
+ async function getNewCookie(cookie) {
1643
+ if (!cookie) {
1644
+ return;
1645
+ }
1646
+ let response = await _getStoreSteamPoweredResponse(cookie);
1647
+ if (!response) {
1648
+ return;
1649
+ }
1650
+ while (Array.isArray(response?.headers?.["set-cookie"])) {
1651
+ console.log(cookie);
1652
+ const cookieObj = cookie.split(";").reduce(function (accumulator, currentValue) {
1653
+ accumulator[currentValue.trim().split("=")[0].trim()] = currentValue.trim().split("=")[1].trim();
1654
+ return accumulator;
1655
+ }, {});
1656
+ for (const mcookie of response.headers["set-cookie"]) {
1657
+ const name = mcookie.split("=")[0].trim();
1658
+ const value = mcookie.split("=")[1].split(";")[0].trim();
1659
+ cookieObj[name] = value;
1660
+ }
1661
+ cookie = Object.keys(cookieObj)
1662
+ .map((name) => `${name}=${cookieObj[name]}`)
1663
+ .join(";");
1664
+ response = await _getStoreSteamPoweredResponse(cookie);
1665
+ }
1666
+ return cookie;
1667
+ }
1668
+
1669
+ async function loginWithCookie(cookie, tryNewCookie = false) {
1670
+ let response;
1671
+ for (let i = 0; i < 20; i++) {
1672
+ try {
1673
+ response = await axios.request({
1674
+ url: "https://steamcommunity.com/chat/clientjstoken",
1675
+ headers: {
1676
+ cookie,
1677
+ },
1678
+ });
1679
+ } catch (e) {
1680
+ await sleep(1000);
1681
+ }
1682
+ if (response) {
1683
+ break;
1684
+ }
1685
+ }
1686
+
1687
+ const result = response?.data;
1688
+ if (result?.logged_in) {
1689
+ Object.assign(result, {
1690
+ steamID: new SteamID(result.steamid),
1691
+ accountName: result.account_name,
1692
+ webLogonToken: result.token,
1693
+ });
1694
+ steamClient.logOn(result);
1695
+ return cookie;
1696
+ } else {
1697
+ if (tryNewCookie) {
1698
+ log("You are not logged in", cookie);
1699
+ return null;
1700
+ } else {
1701
+ const newCookie = await getNewCookie(cookie);
1702
+ if (!newCookie) {
1703
+ console.error("Cannot get new cookie");
1704
+ return null;
1705
+ } else {
1706
+ return await loginWithCookie(newCookie, true);
1707
+ }
1708
+ }
1709
+ }
1710
+ }
1711
+
1712
+ async function login(reconnect = false) {
1713
+ function logOn(clientJsToken) {
1714
+ try {
1715
+ steamClient.logOn({
1716
+ ...clientJsToken,
1717
+ steamId: new SteamID(clientJsToken.steamid),
1718
+ steamID: new SteamID(clientJsToken.steamid),
1719
+ accountName: clientJsToken.account_name,
1720
+ webLogonToken: clientJsToken.token,
1721
+ });
1722
+ return true;
1723
+ } catch (e) {
1724
+ console.error(e);
1725
+ return false;
1726
+ }
1727
+ }
1728
+
1729
+ if (clientJsToken?.logged_in === true) {
1730
+ log(reconnect ? "reconnect with clientJsToken" : "login with clientJsToken");
1731
+ setTimeout(function () {
1732
+ clientJsToken = null;
1733
+ }, 1000);
1734
+ return logOn(clientJsToken);
1735
+ } else if (cookie) {
1736
+ log(reconnect ? "reconnect with cookie" : "login with cookie");
1737
+ const steamUser = new SteamUser(typeof cookie === "function" ? await cookie() : cookie);
1738
+ const _clientJsToken = await steamUser.getClientJsToken();
1739
+ if (_clientJsToken?.logged_in === true) {
1740
+ return logOn(_clientJsToken);
1741
+ } else {
1742
+ log(`Account not logged in ${clientJsToken?.account_name || steamUser.getSteamIdUser() || ""}`);
1743
+ console.log(clientJsToken);
1744
+ return false;
1745
+ }
1746
+ } else if (username && password) {
1747
+ log(reconnect ? `reconnect with username ${username}` : `login with username ${username}`);
1748
+ steamClient.logOn({
1749
+ accountName: username,
1750
+ password: password,
1751
+ rememberPassword: true,
1752
+ machineName: "Natri",
1753
+ });
1754
+ return true;
1755
+ } else {
1756
+ log(`Account not logged in ${clientJsToken?.account_name || ""}`);
1757
+ return false;
1758
+ }
1759
+ }
1760
+
1761
+ function logOff() {
1762
+ isLogOff = true;
1763
+ logOffEvent?.(true);
1764
+ steamClient.logOff();
1765
+ }
1766
+
1767
+ function onCookie(callback) {
1768
+ if (getCookies()) {
1769
+ callback(getCookies());
1770
+ } else {
1771
+ onEvent(
1772
+ "webSession",
1773
+ function (webSession) {
1774
+ callback(webSession?.cookies?.join?.(";"));
1775
+ },
1776
+ true,
1777
+ );
1778
+ }
1779
+ }
1780
+
1781
+ async function init() {
1782
+ bindEvent();
1783
+ if (await login()) {
1784
+ steamClient._handlerManager.add(Protos.csgo.EMsg.k_EMsgClientRequestedClientStats, function (payload) {
1785
+ const result = protoDecode(Protos.csgo.CMsgClientRequestedClientStats, payload.toBuffer());
1786
+ // console.log("CMsgClientRequestedClientStats", result);
1787
+ });
1788
+ steamClient._handlerManager.add(Protos.csgo.EMsg.k_EMsgClientMMSLobbyData, function (payload) {
1789
+ const result = protoDecode(Protos.csgo.CMsgClientMMSLobbyData, payload.toBuffer());
1790
+ // console.log("CMsgClientMMSLobbyData", result, result.metadata);
1791
+ });
1792
+ }
1793
+ }
1794
+
1795
+ function partyRegister() {
1796
+ if (prime === null) {
1797
+ _partyRegister(true);
1798
+ _partyRegister(false);
1799
+ } else {
1800
+ _partyRegister(prime);
1801
+ }
1802
+ }
1803
+
1804
+ function _partyRegister(prime) {
1805
+ log("partyRegister", prime);
1806
+ lastTimePartyRegister = new Date().getTime();
1807
+ steamClient.sendToGC(
1808
+ 730,
1809
+ Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Party_Register,
1810
+ {},
1811
+ protoEncode(Protos.csgo.CMsgGCCStrike15_v2_Party_Register, {
1812
+ // id : 0,
1813
+ ver: CSGO_VER,
1814
+ apr: prime ? 1 : 0, //prime
1815
+ ark: prime ? 180 : 0,
1816
+ grps: [],
1817
+ launcher: 0,
1818
+ game_type: 8,
1819
+ }),
1820
+ );
1821
+ }
1822
+
1823
+ async function sendFriendMessage(steamId, message) {
1824
+ while (sendMessageTimestamp && new Date().getTime() - sendMessageTimestamp < 2000) {
1825
+ await sleep(1000);
1826
+ }
1827
+
1828
+ while (isSendingFriendMessages) {
1829
+ await sleep(5000);
1830
+ }
1831
+
1832
+ isSendingFriendMessages = true;
1833
+ const now = new Date().getTime();
1834
+ while (new Date().getTime() - now < 2 * 60000) {
1835
+ //2 minutes
1836
+ const result = await new Promise((resolve) => {
1837
+ steamClient.chat.sendFriendMessage(steamId, message, undefined, function (...arg) {
1838
+ sendMessageTimestamp = new Date().getTime();
1839
+ resolve(arg);
1840
+ });
1841
+ });
1842
+
1843
+ if (result?.[1]?.server_timestamp) {
1844
+ isSendingFriendMessages = false;
1845
+ return result?.[1];
1846
+ } else if (result?.[0]?.message?.includes?.("RateLimitExceeded")) {
1847
+ await sleep(5000);
1848
+ } else {
1849
+ isSendingFriendMessages = false;
1850
+ return result;
1851
+ }
1852
+ }
1853
+ isSendingFriendMessages = false;
1854
+ }
1855
+
1856
+ async function autoRequestFreeLicense(shouldLog = false, max = 10) {
1857
+ return;
1858
+ // const mCookies = await getCookiesWait()
1859
+ // if (!mCookies) return
1860
+ // let freeAppList = Array.isArray(steamClient.licenses) ? FreeAppList.filter(appId => steamClient.licenses.every(({package_id}) => package_id !== appId)) : FreeAppList;
1861
+ const freeAppList = freeAppList.filter((appId) => ownedApps.some((app) => app.appid == appId));
1862
+ const recommendedApps = _.shuffle(freeAppList);
1863
+ if (max) {
1864
+ recommendedApps.length = Math.min(recommendedApps.length, max);
1865
+ }
1866
+ try {
1867
+ const response = await steamClient.requestFreeLicense(recommendedApps);
1868
+ if (shouldLog) {
1869
+ log(response);
1870
+ }
1871
+ } catch (e) {
1872
+ log(e);
1873
+ }
1874
+ // if (Math.random() > 0.7) {
1875
+ // for (const recommendedApp of recommendedApps) {
1876
+ // try {
1877
+ // await steamUtils.requestFreeLicense(recommendedApp)
1878
+ // } catch (e) {
1879
+ // }
1880
+ // await sleep(2000)
1881
+ // }
1882
+ // } else {
1883
+ // try {
1884
+ // await steamClient.requestFreeLicense(recommendedApps)
1885
+ // } catch (e) {
1886
+ // log(e);
1887
+ // }
1888
+ // }
1889
+
1890
+ // if (shouldLog) {
1891
+ // await sleep(20000)
1892
+ // const ownedAppsCount2 = (await steamUtils.getDynamicStoreUserData())?.rgOwnedApps?.length || 0
1893
+ // const increaseNumber = ownedAppsCount2 - ownedAppsCount;
1894
+ // log(`OwnedApps length ${ownedAppsCount2}, increase ${increaseNumber}`)
1895
+ // }
1896
+ }
1897
+
1898
+ async function playCSGO() {
1899
+ try {
1900
+ await steamClient.requestFreeLicense(AppID);
1901
+ await sleep(5000);
1902
+ } catch (e) {}
1903
+ gamesPlayed(AppID);
1904
+ }
1905
+
1906
+ function doFakeGameScore() {
1907
+ const maxRound = Math.random() > 0.7 ? 16 : 12;
1908
+ const maps = [
1909
+ "ar_baggage",
1910
+ "ar_dizzy",
1911
+ "ar_monastery",
1912
+ "ar_shoots",
1913
+ "cs_agency",
1914
+ "cs_assault",
1915
+ "cs_italy",
1916
+ "cs_militia",
1917
+ "cs_office",
1918
+ "de_ancient",
1919
+ "de_anubis",
1920
+ "de_bank",
1921
+ "de_boyard",
1922
+ "de_cache",
1923
+ "de_canals",
1924
+ "de_cbble",
1925
+ "de_chalice",
1926
+ "de_dust2",
1927
+ "de_inferno",
1928
+ "de_lake",
1929
+ "de_mirage",
1930
+ "de_nuke",
1931
+ "de_overpass",
1932
+ "de_safehouse",
1933
+ // "de_shortnuke",
1934
+ "de_stmarc",
1935
+ "de_sugarcane",
1936
+ "de_train",
1937
+ "de_tuscan",
1938
+ "de_vertigo",
1939
+ "dz_ember",
1940
+ "dz_vineyard",
1941
+ "gd_cbble",
1942
+ "training1",
1943
+ ];
1944
+
1945
+ if (richPresence.myScore === undefined) {
1946
+ richPresence.myScore = _.random(0, maxRound);
1947
+ }
1948
+ if (richPresence.theirScore === undefined) {
1949
+ richPresence.theirScore = _.random(0, maxRound);
1950
+ }
1951
+ if (richPresence.map === undefined) {
1952
+ richPresence.map = maps[Math.floor(Math.random() * maps.length)];
1953
+ }
1954
+ if (richPresence.myScore === maxRound || richPresence.theirScore === maxRound) {
1955
+ richPresence.myScore = 0;
1956
+ richPresence.theirScore = 0;
1957
+ richPresence.map = maps[Math.floor(Math.random() * maps.length)];
1958
+ } else {
1959
+ const isMyTeamWin = Math.random() > 0.5;
1960
+ if (isMyTeamWin) {
1961
+ richPresence.myScore++;
1962
+ } else {
1963
+ richPresence.theirScore++;
1964
+ }
1965
+ }
1966
+
1967
+ const score = richPresence.myScore === 0 && richPresence.theirScore === 0 ? "" : `[ ${richPresence.myScore} : ${richPresence.theirScore} ]`;
1968
+ steamClient.uploadRichPresence(730, {
1969
+ "game:state": "game",
1970
+ steam_display: "#display_GameKnownMapScore",
1971
+ // connect: "+gcconnectG082AA752",
1972
+ version: CSGO_VER.toString(),
1973
+ "game:mode": "competitive",
1974
+ "game:map": richPresence.map,
1975
+ "game:server": "kv",
1976
+ // watch: Math.random() > 0.95 ? _.random(1, 5).toString() : null,
1977
+ "game:score": score,
1978
+ });
1979
+ }
1980
+
1981
+ function updateFakeGameScore() {
1982
+ if (isFakeGameScore && getPlayingAppIds().some((a) => a == 730)) {
1983
+ doSetInterval(doFakeGameScore, [60000, 180000], "uploadRichPresenceCSGO");
1984
+ } else {
1985
+ doClearInterval("uploadRichPresenceCSGO");
1986
+ }
1987
+ }
1988
+
1989
+ function updateAutoRequestFreeLicense() {
1990
+ if (isAutoRequestFreeLicense) {
1991
+ doSetInterval(
1992
+ function () {
1993
+ autoRequestFreeLicense(false, 50);
1994
+ },
1995
+ [5 * 60000, 10 * 60000],
1996
+ "autoRequestFreeLicense",
1997
+ );
1998
+ } else {
1999
+ doClearInterval("autoRequestFreeLicense");
2000
+ }
2001
+ }
2002
+
2003
+ function updateInvisible() {
2004
+ if (isInvisible) {
2005
+ steamClient.setPersona(NodeSteamUser.EPersonaState.Invisible);
2006
+ state = "Invisible";
2007
+ } else {
2008
+ steamClient.setPersona(NodeSteamUser.EPersonaState.Online);
2009
+ state = "Online";
2010
+ }
2011
+ }
2012
+
2013
+ async function gamesPlayed(apps) {
2014
+ if (!Array.isArray(apps)) {
2015
+ apps = [apps];
2016
+ }
2017
+
2018
+ const processedApps = apps.map((app) => {
2019
+ if (typeof app == "string") {
2020
+ app = { game_id: "15190414816125648896", game_extra_info: app };
2021
+ } else if (typeof app === "number" || typeof app != "object") {
2022
+ app = { game_id: app };
2023
+ }
2024
+
2025
+ if (typeof app.game_ip_address == "number") {
2026
+ app.game_ip_address = { v4: app.game_ip_address };
2027
+ }
2028
+
2029
+ return app;
2030
+ });
2031
+
2032
+ steamClient.gamesPlayed(processedApps);
2033
+ if (processedApps.some((app) => parseInt(app.game_id) === 730)) {
2034
+ await sleep(500);
2035
+ await sendHello();
2036
+ }
2037
+ updateFakeGameScore();
2038
+
2039
+ // await sleep(10000)
2040
+ // self.steamUser.uploadRichPresence(730, {
2041
+ // status: 'bussssss',
2042
+ // 'game:state': 'lobby',
2043
+ // steam_display: '#display_watch',
2044
+ // currentmap: '#gamemap_de_empire',
2045
+ // connect: '+gcconnectG082AA752',
2046
+ // 'game:mode': 'competitive'
2047
+ // })
2048
+ }
2049
+
2050
+ function getFriendsList() {
2051
+ const methodName = "FriendsList.GetFriendsList#1";
2052
+ const { users, myFriends } = steamClient; //object
2053
+ /*
2054
+ users
2055
+ * {
2056
+ rich_presence: [],
2057
+ player_name: "Kei #SkinsMonkey",
2058
+ avatar_hash: [123,4543],
2059
+ last_logoff: "2023-05-20T05:00:42.000Z",
2060
+ last_logon: "2023-05-20T05:02:16.000Z",
2061
+ last_seen_online: "2023-05-20T05:00:42.000Z",
2062
+ avatar_url_icon: "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/3e/3e9da0b107ac2ec384759544368a8a977359537a.jpg",
2063
+ avatar_url_medium: "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/3e/3e9da0b107ac2ec384759544368a8a977359537a_medium.jpg",
2064
+ avatar_url_full: "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/3e/3e9da0b107ac2ec384759544368a8a977359537a_full.jpg"
2065
+ }
2066
+ *
2067
+
2068
+ myFriends
2069
+ {
2070
+ 76561198365087582: 3,
2071
+ 76561199490395123: 3
2072
+ }
2073
+ * */
2074
+ /*steamClient._send({
2075
+ msg: 151,
2076
+ proto: {
2077
+ target_job_name: methodName
2078
+ }
2079
+ }, Buffer.alloc(0), function (body, hdr) {
2080
+ const result = hdr.proto.eresult
2081
+ const errorMessage = hdr.proto.error_message
2082
+ const responseData = body.toBuffer()
2083
+ console.log(`xxx`, result)
2084
+ })*/
2085
+
2086
+ steamClient.sendToGC(730, 767, {}, Buffer.alloc(0));
2087
+ }
2088
+
2089
+ async function getUserOwnedApps(steamId = steamClient.steamID) {
2090
+ if (!steamId) {
2091
+ return [];
2092
+ }
2093
+ if (typeof steamId?.getSteamID64 === "function") {
2094
+ steamId = steamId.getSteamID64();
2095
+ }
2096
+ const isMe = steamId === steamClient.steamID.getSteamID64();
2097
+ if (isMe && ownedApps.length) {
2098
+ return ownedApps;
2099
+ }
2100
+ let result = {};
2101
+ try {
2102
+ result = await steamClient.getUserOwnedApps(steamId);
2103
+ } catch (e) {
2104
+ try {
2105
+ result = await steamClient.getUserOwnedApps(steamId);
2106
+ } catch (e) {
2107
+ result = {};
2108
+ }
2109
+ }
2110
+ if (isMe && Array.isArray(result.apps)) {
2111
+ ownedApps.length = 0;
2112
+ ownedApps.push(...result.apps);
2113
+ }
2114
+ return result.apps || [];
2115
+ const resultExample = {
2116
+ app_count: 22,
2117
+ apps: [
2118
+ {
2119
+ content_descriptorids: [],
2120
+ appid: 208030,
2121
+ name: "Moon Breakers",
2122
+ playtime_2weeks: null,
2123
+ playtime_forever: 0,
2124
+ img_icon_url: "",
2125
+ has_community_visible_stats: null,
2126
+ playtime_windows_forever: 0,
2127
+ playtime_mac_forever: 0,
2128
+ playtime_linux_forever: 0,
2129
+ rtime_last_played: 0,
2130
+ capsule_filename: null,
2131
+ sort_as: null,
2132
+ has_workshop: null,
2133
+ has_market: null,
2134
+ has_dlc: null,
2135
+ has_leaderboards: null,
2136
+ },
2137
+ ],
2138
+ };
2139
+ }
2140
+
2141
+ function getPlayingAppIds() {
2142
+ return steamClient._playingAppIds || [];
2143
+ }
2144
+
2145
+ function requestJoinFriendData(token, version) {
2146
+ if (!steamClient.steamID) {
2147
+ return;
2148
+ }
2149
+
2150
+ // Parse tokens
2151
+ let conBuf = Buffer.from(token.replace(/^\+gcconnect/, "").replace(/^G/, ""), "hex");
2152
+ if (conBuf.length !== 12) {
2153
+ return;
2154
+ }
2155
+
2156
+ let joinToken = conBuf.readInt32BE(0);
2157
+ let accountID = conBuf.readInt32BE(4);
2158
+ let joinIpp = conBuf.readInt32BE(8);
2159
+
2160
+ return new Promise((resolve) => {
2161
+ pushGCCallback(`requestJoinFriendData_${accountID}`, resolve, 30000);
2162
+ steamClient.sendToGC(
2163
+ AppID,
2164
+ Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientRequestJoinFriendData,
2165
+ {},
2166
+ protoEncode(Protos.csgo.CMsgGCCStrike15_v2_ClientRequestJoinFriendData, {
2167
+ version: version || CSGO_VER,
2168
+ account_id: accountID,
2169
+ join_token: joinToken,
2170
+ join_ipp: joinIpp,
2171
+ }),
2172
+ );
2173
+ });
2174
+ }
2175
+
2176
+ function redeemFreeReward(itemIds, generation_time) {
2177
+ console.log(`Sent message to GC: AppID ${AppID}, MessageType ${Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientRedeemFreeReward}`);
2178
+
2179
+ const encodedMessages = protoEncode(Protos.csgo.CMsgGCCstrike15_v2_ClientRedeemFreeReward, {
2180
+ items: itemIds,
2181
+ redeemable_balance: 0,
2182
+ generation_time: generation_time,
2183
+ });
2184
+ steamClient.sendToGC(730, Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientRedeemFreeReward, {}, encodedMessages, function (payload) {
2185
+ console.log(payload);
2186
+ });
2187
+
2188
+ setTimeout(function () {
2189
+ steamClient._send(
2190
+ {
2191
+ msg: Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientRedeemFreeReward,
2192
+ proto: {
2193
+ steamid: steamClient.steamID.getSteamID64(),
2194
+ routing_appid: 730,
2195
+ },
2196
+ },
2197
+ encodedMessages,
2198
+ function (payload) {
2199
+ console.log(payload);
2200
+ },
2201
+ );
2202
+ }, 30000);
2203
+ }
2204
+
2205
+ function requestRankingInfo() {
2206
+ return new Promise((resolve) => {
2207
+ const timeout = setTimeout(function () {
2208
+ resolve();
2209
+ }, 30000);
2210
+
2211
+ steamClient._send(
2212
+ {
2213
+ msg: Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientGCRankUpdate,
2214
+ proto: {
2215
+ steamid: steamClient.steamID.getSteamID64(),
2216
+ routing_appid: 730,
2217
+ },
2218
+ },
2219
+ protoEncode(Protos.csgo.CMsgGCCStrike15_v2_ClientGCRankUpdate, {
2220
+ rankings: [
2221
+ {
2222
+ rank_type_id: 7, //wing man
2223
+ },
2224
+ {
2225
+ rank_type_id: 10, //dangerzone
2226
+ },
2227
+ {
2228
+ rank_type_id: 11, //premier elo
2229
+ },
2230
+ ],
2231
+ }),
2232
+ function (payload) {
2233
+ clearTimeout(timeout);
2234
+ resolve(payload);
2235
+ },
2236
+ );
2237
+ });
2238
+ }
2239
+
2240
+ return {
2241
+ init,
2242
+ partySearch,
2243
+ invite2Lobby,
2244
+ createLobby,
2245
+ updateLobby,
2246
+ createThenInvite2Lobby,
2247
+ joinLobby,
2248
+ getLobbyData,
2249
+ partyRegister,
2250
+ requestCoPlays,
2251
+ getPersonas,
2252
+ getUsername() {
2253
+ return username;
2254
+ },
2255
+ getCookies,
2256
+ getCookiesWait,
2257
+ getLogOnDetails() {
2258
+ return steamClient?._logOnDetails;
2259
+ },
2260
+ onEvent,
2261
+ offEvent,
2262
+ offAllEvent,
2263
+ setPersona(state, name) {
2264
+ steamClient.setPersona(state, name);
2265
+ },
2266
+ sendFriendMessage,
2267
+ sendFriendTyping,
2268
+ getSteamClient() {
2269
+ return steamClient;
2270
+ },
2271
+ getAccountInfoName,
2272
+ getPersonaName,
2273
+ async getPlayersProfile(steamId, retry = 3) {
2274
+ for (let i = 0; i < retry; i++) {
2275
+ const profile = await getPlayersProfile(steamId);
2276
+ if (profile) {
2277
+ return profile;
2278
+ }
2279
+ }
2280
+ return null;
2281
+ },
2282
+ autoRequestFreeLicense,
2283
+ playCSGO,
2284
+ doSetInterval,
2285
+ doClearIntervals,
2286
+ gamesPlayed,
2287
+ sendHello,
2288
+ checkPlayerPrimeStatus,
2289
+ doClearInterval,
2290
+ gamePlay,
2291
+ autoGamePlay,
2292
+ offAutoGamePlay,
2293
+ updateAutoGamePlay,
2294
+ getFriendsList,
2295
+ setIsPartyRegister(change) {
2296
+ change = !!change;
2297
+ if (isPartyRegister !== change) {
2298
+ isPartyRegister = change;
2299
+ if (!isPartyRegister) {
2300
+ doClearInterval("autoPartyRegister");
2301
+ } else {
2302
+ sendHello();
2303
+ }
2304
+ }
2305
+ },
2306
+ setAutoPlay(change) {
2307
+ change = !!change;
2308
+ if (isAutoPlay !== change) {
2309
+ isAutoPlay = change;
2310
+ updateAutoGamePlay();
2311
+ }
2312
+ },
2313
+ setIsInvisible(change) {
2314
+ change = !!change;
2315
+ if (isInvisible !== change) {
2316
+ isInvisible = change;
2317
+ updateInvisible();
2318
+ }
2319
+ },
2320
+ setFakeGameScore(change) {
2321
+ change = !!change;
2322
+ if (isFakeGameScore !== change) {
2323
+ isFakeGameScore = change;
2324
+ updateFakeGameScore();
2325
+ }
2326
+ },
2327
+ setAutoRequestFreeLicense(change) {
2328
+ change = !!change;
2329
+ if (isAutoRequestFreeLicense !== change) {
2330
+ isAutoRequestFreeLicense = change;
2331
+ updateAutoRequestFreeLicense();
2332
+ }
2333
+ },
2334
+ getState() {
2335
+ return state;
2336
+ },
2337
+ log,
2338
+ isPrime() {
2339
+ return prime === true;
2340
+ },
2341
+ getFriendList,
2342
+ logOff,
2343
+ isPlayingBlocked() {
2344
+ return playingBlocked;
2345
+ },
2346
+ async getChatHistory(steamId) {
2347
+ if (!steamClient.steamID) return [];
2348
+ const mySteamId = typeof steamClient.steamID.getSteamID64 === "function" ? steamClient.steamID.getSteamID64() : steamClient.steamID;
2349
+ return new Promise((resolve) => {
2350
+ setTimeout(resolve, 90000);
2351
+ steamClient.getChatHistory(steamId, async function (error, result) {
2352
+ const messages = (result || []).map(function (msg) {
2353
+ const fromSteamId = typeof msg.steamID?.getSteamID64 === "function" ? msg.steamID.getSteamID64() : msg.steamID;
2354
+ return {
2355
+ message: msg.message,
2356
+ from: fromSteamId,
2357
+ to: fromSteamId == mySteamId ? steamId : mySteamId,
2358
+ _id: new Date(msg.timestamp).getTime().toString(),
2359
+ timestamp: new Date(msg.timestamp).getTime(),
2360
+ isMe: fromSteamId !== steamId,
2361
+ };
2362
+ });
2363
+ resolve(messages);
2364
+ });
2365
+ });
2366
+ },
2367
+ onAnyEvent,
2368
+ async redeemGift(gid) {
2369
+ try {
2370
+ const community = new SteamCommunity();
2371
+ let cookies = await getCookiesWait();
2372
+ community.setCookies(typeof cookies === "string" ? cookies.split(";") : cookies);
2373
+ community.redeemGift(gid);
2374
+ } catch (e) {}
2375
+ },
2376
+ async requestFreeLicense(...args) {
2377
+ try {
2378
+ return await steamClient.requestFreeLicense(...args);
2379
+ } catch (e) {}
2380
+ },
2381
+ getSteamId() {
2382
+ try {
2383
+ return steamClient.steamID.getSteamID64();
2384
+ } catch (e) {}
2385
+ },
2386
+ getLastTimePartyRegister() {
2387
+ return lastTimePartyRegister;
2388
+ },
2389
+ getLastTimePartySearch() {
2390
+ return lastTimePartySearch;
2391
+ },
2392
+ getLicenses() {
2393
+ return steamClient.licenses;
2394
+ const exampleLicenses = [
2395
+ {
2396
+ package_id: 303386,
2397
+ time_created: 1680491335,
2398
+ time_next_process: 0,
2399
+ minute_limit: 0,
2400
+ minutes_used: 0,
2401
+ payment_method: 1024,
2402
+ flags: 512,
2403
+ purchase_country_code: "VN",
2404
+ license_type: 1,
2405
+ territory_code: 0,
2406
+ change_number: 20615891,
2407
+ owner_id: 1530068060,
2408
+ initial_period: 0,
2409
+ initial_time_unit: 0,
2410
+ renewal_period: 0,
2411
+ renewal_time_unit: 0,
2412
+ access_token: "8049398090486337961",
2413
+ master_package_id: null,
2414
+ },
2415
+ ];
2416
+ },
2417
+ uploadRichPresence(appid, richPresence) {
2418
+ const _richPresence = Array.isArray(richPresence)
2419
+ ? richPresence.reduce(function (previousValue, currentValue, currentIndex, array) {
2420
+ if (currentValue.key) {
2421
+ previousValue[currentValue.key] = currentValue.value?.toString() || "";
2422
+ }
2423
+ return previousValue;
2424
+ }, {})
2425
+ : richPresence;
2426
+ steamClient.uploadRichPresence(appid, _richPresence);
2427
+ },
2428
+ getUserOwnedApps,
2429
+ getPlayingAppIds,
2430
+ getCurrentLobby() {
2431
+ return currentLobby;
2432
+ },
2433
+ setGame(_games) {
2434
+ games = _games;
2435
+ },
2436
+ getClientHello() {
2437
+ return _clientHello;
2438
+ },
2439
+ getClientWelcome() {
2440
+ return _clientWelcome;
2441
+ },
2442
+ redeemFreeReward,
2443
+ requestJoinFriendData,
2444
+ };
2445
+ }
2446
+
2447
+ export default SteamClient;
2448
+
2449
+ export function increaseCSGO_VER() {
2450
+ return ++CSGO_VER;
2451
+ }
2452
+
2453
+ SteamClient.isAccountPlayable = async function isAccountPlayable({ cookie, clientJsToken, timeoutMs, onPlayable, onNotPlayable, ...rest }) {
2454
+ if (!clientJsToken && cookie) {
2455
+ clientJsToken = await new SteamUser(typeof cookie === "function" ? await cookie() : cookie).getClientJsToken();
2456
+ }
2457
+ if (clientJsToken?.logged_in !== true) {
2458
+ if (typeof onNotPlayable === "function") {
2459
+ await onNotPlayable(null);
2460
+ }
2461
+ return { invalidClientJsToken: true };
2462
+ }
2463
+ return await new Promise((resolve) => {
2464
+ const timeouts = [
2465
+ setTimeout(() => {
2466
+ doResolve({ timedOut: true });
2467
+ }, timeoutMs || 30000),
2468
+ ];
2469
+
2470
+ const steamClient = new SteamClient({
2471
+ isFakeGameScore: false,
2472
+ isAutoPlay: true,
2473
+ isPartyRegister: false,
2474
+ isInvisible: true,
2475
+ MAX_GAME_PLAY: 10,
2476
+ games: 730,
2477
+ clientJsToken,
2478
+ ...rest,
2479
+ });
2480
+
2481
+ steamClient.onEvent("error", ({ eresult, msg, error }) => {
2482
+ doResolve({ eresult, msg, error });
2483
+ });
2484
+
2485
+ steamClient.onEvent("csgoOnline", (ClientWelcome) => {
2486
+ doResolve({ playable: true });
2487
+ });
2488
+
2489
+ steamClient.onEvent("csgoClientHello", (ClientHello) => {
2490
+ doResolve({ playable: true });
2491
+ });
2492
+
2493
+ steamClient.onEvent("playingState", ({ playing_blocked, playing_app }) => {
2494
+ if (playing_blocked) {
2495
+ doResolve({ playable: false });
2496
+ } else {
2497
+ timeouts.push(
2498
+ setTimeout(function () {
2499
+ const isBlocked = steamClient.isPlayingBlocked();
2500
+ doResolve({ playable: !isBlocked });
2501
+ }, 5000),
2502
+ );
2503
+ }
2504
+ });
2505
+
2506
+ // steamClient.onEvent("fatalError", () => {
2507
+ // doResolve();
2508
+ // });
2509
+
2510
+ steamClient.init();
2511
+
2512
+ async function doResolve(data) {
2513
+ timeouts.forEach((timeout) => clearTimeout(timeout));
2514
+ steamClient.doClearIntervals();
2515
+ steamClient.offAllEvent();
2516
+
2517
+ if (data?.playable === true) {
2518
+ if (typeof onPlayable === "function") {
2519
+ try {
2520
+ await onPlayable(steamClient);
2521
+ } catch (e) {}
2522
+ }
2523
+ } else {
2524
+ if (typeof onNotPlayable === "function") {
2525
+ try {
2526
+ await onNotPlayable(steamClient);
2527
+ } catch (e) {}
2528
+ }
2529
+ }
2530
+
2531
+ steamClient.logOff();
2532
+ return resolve(data);
2533
+ }
2534
+ });
2535
+ };
2536
+
2537
+ class XpBonuxFlagsHelper {
2538
+ static kCSXpBonusFlags_EarnedXpThisPeriod = 1 << 0;
2539
+ static kCSXpBonusFlags_FirstReward = 1 << 1;
2540
+ static kCSXpBonusFlags_Msg_YourReportGotConvicted = 1 << 2; // Player Reports
2541
+ static kCSXpBonusFlags_Msg_YouPartiedWithCheaters = 1 << 3; // Party Member Banned
2542
+ static kCSXpBonusFlags_PrestigeEarned = 1 << 4;
2543
+ // ===$CHINAGOVERNMENTCERT$===
2544
+ static kCSXpBonusFlags_ChinaGovernmentCert = 1 << 5;
2545
+ // ===$CHINAGOVERNMENTCERT$===
2546
+
2547
+ // Client-facing bits not backed by SQL
2548
+ static kCSXpBonusFlags_OverwatchBonus = 1 << 28; // Overwatch XP Reward
2549
+ static kCSXpBonusFlags_BonusBoostConsumed = 1 << 29;
2550
+ static kCSXpBonusFlags_ReducedGain = 1 << 30;
2551
+
2552
+ static kCSXpBonusFlagsMask_SQLBacked_TimeBased = this.kCSXpBonusFlags_EarnedXpThisPeriod | this.kCSXpBonusFlags_FirstReward;
2553
+ static kCSXpBonusFlagsMask_SQLBacked_Notifications = this.kCSXpBonusFlags_Msg_YourReportGotConvicted | this.kCSXpBonusFlags_Msg_YouPartiedWithCheaters;
2554
+ static kCSXpBonusFlagsMask_SQLBacked_Permanent = this.kCSXpBonusFlagsMask_SQLBacked_Notifications | this.kCSXpBonusFlags_PrestigeEarned | this.kCSXpBonusFlags_ChinaGovernmentCert;
2555
+ static kCSXpBonusFlagsMask_SQLBacked = this.kCSXpBonusFlagsMask_SQLBacked_TimeBased | this.kCSXpBonusFlagsMask_SQLBacked_Permanent;
2556
+ static kCSXpBonusFlagsMask_Client_Permanent = this.kCSXpBonusFlags_OverwatchBonus;
2557
+ static kCSXpBonusFlagsMask_Client_TimeBased = this.kCSXpBonusFlags_BonusBoostConsumed | this.kCSXpBonusFlags_ReducedGain;
2558
+ // TODO: Find "Communication Abuse Reports" flag
2559
+
2560
+ static flags = {
2561
+ kCSXpBonusFlags_EarnedXpThisPeriod: this.kCSXpBonusFlags_EarnedXpThisPeriod,
2562
+ kCSXpBonusFlags_FirstReward: this.kCSXpBonusFlags_FirstReward,
2563
+ kCSXpBonusFlags_Msg_YourReportGotConvicted: this.kCSXpBonusFlags_Msg_YourReportGotConvicted,
2564
+ kCSXpBonusFlags_Msg_YouPartiedWithCheaters: this.kCSXpBonusFlags_Msg_YouPartiedWithCheaters,
2565
+ kCSXpBonusFlags_PrestigeEarned: this.kCSXpBonusFlags_PrestigeEarned,
2566
+ kCSXpBonusFlags_ChinaGovernmentCert: this.kCSXpBonusFlags_ChinaGovernmentCert,
2567
+ kCSXpBonusFlags_OverwatchBonus: this.kCSXpBonusFlags_OverwatchBonus,
2568
+ kCSXpBonusFlags_BonusBoostConsumed: this.kCSXpBonusFlags_BonusBoostConsumed,
2569
+ kCSXpBonusFlags_ReducedGain: this.kCSXpBonusFlags_ReducedGain,
2570
+ kCSXpBonusFlagsMask_SQLBacked_TimeBased: this.kCSXpBonusFlagsMask_SQLBacked_TimeBased,
2571
+ kCSXpBonusFlagsMask_SQLBacked_Notifications: this.kCSXpBonusFlagsMask_SQLBacked_Notifications,
2572
+ kCSXpBonusFlagsMask_SQLBacked_Permanent: this.kCSXpBonusFlagsMask_SQLBacked_Permanent,
2573
+ kCSXpBonusFlagsMask_SQLBacked: this.kCSXpBonusFlagsMask_SQLBacked,
2574
+ kCSXpBonusFlagsMask_Client_Permanent: this.kCSXpBonusFlagsMask_Client_Permanent,
2575
+ kCSXpBonusFlagsMask_Client_TimeBased: this.kCSXpBonusFlagsMask_Client_TimeBased,
2576
+ };
2577
+
2578
+ static stringFlags = {
2579
+ kCSXpBonusFlags_EarnedXpThisPeriod: undefined,
2580
+ kCSXpBonusFlags_FirstReward: undefined,
2581
+ kCSXpBonusFlags_Msg_YourReportGotConvicted: {
2582
+ title: "Player Reports",
2583
+ description: "A player you reported has been convicted for cheating",
2584
+ },
2585
+ kCSXpBonusFlags_Msg_YouPartiedWithCheaters: {
2586
+ title: "Party Member Banned",
2587
+ description: "You partied with a player who has been convicted for cheating. Your skill group and XP have been adjusted",
2588
+ },
2589
+ kCSXpBonusFlags_PrestigeEarned: undefined,
2590
+ kCSXpBonusFlags_ChinaGovernmentCert: undefined,
2591
+ kCSXpBonusFlags_OverwatchBonus: {
2592
+ title: "Overwatch XP Reward",
2593
+ description: "You have submitted accurate verdicts and qualified for an Overwatch Investigator XP reward",
2594
+ },
2595
+ kCSXpBonusFlags_BonusBoostConsumed: undefined,
2596
+ kCSXpBonusFlags_ReducedGain: undefined,
2597
+ kCSXpBonusFlagsMask_SQLBacked_TimeBased: undefined,
2598
+ kCSXpBonusFlagsMask_SQLBacked_Notifications: undefined,
2599
+ kCSXpBonusFlagsMask_SQLBacked_Permanent: undefined,
2600
+ kCSXpBonusFlagsMask_SQLBacked: undefined,
2601
+ kCSXpBonusFlagsMask_Client_Permanent: undefined,
2602
+ kCSXpBonusFlagsMask_Client_TimeBased: undefined,
2603
+ };
2604
+
2605
+ // To be fair this whole thing is way over the top for just trying to print to console if you have bonus Overwatch XP waiting to be picked up
2606
+ // But who cares, doing this for completion. Easier copy pasting for future projects.
2607
+
2608
+ static ParseBonusXPFlags(xpFlags) {
2609
+ let masks = [];
2610
+ for (let flag in this.flags) {
2611
+ if ((xpFlags & this.flags[flag]) !== this.flags[flag]) {
2612
+ continue;
2613
+ }
2614
+
2615
+ masks.push(flag);
2616
+ }
2617
+
2618
+ return masks;
2619
+ }
2620
+
2621
+ static StringifyFlags(masks) {
2622
+ return masks
2623
+ .map((mask) => {
2624
+ return this.stringFlags[mask];
2625
+ })
2626
+ .filter((str) => {
2627
+ return typeof str === "object";
2628
+ });
2629
+ }
2630
+ }