steamutils 1.3.69 → 1.3.70

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