steamutils 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SteamClient.js +534 -0
- package/helpers/protos.js +33 -0
- package/helpers/util.js +60 -0
- package/index.js +1 -0
- package/package.json +3 -1
package/SteamClient.js
ADDED
@@ -0,0 +1,534 @@
|
|
1
|
+
import SteamUser 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 from "./helpers/protos.js";
|
9
|
+
|
10
|
+
const Protos = helpers([{
|
11
|
+
name: 'csgo',
|
12
|
+
protos: fs.readdirSync(__dirname + '/protos/').filter(s => s.endsWith('.proto')).map(s => __dirname + '/protos/' + s)
|
13
|
+
}])
|
14
|
+
|
15
|
+
export const RANKS = {
|
16
|
+
0: 'Unranked',
|
17
|
+
1: 'Silver I',
|
18
|
+
2: 'Silver II',
|
19
|
+
3: 'Silver III',
|
20
|
+
4: 'Silver IV',
|
21
|
+
5: 'Silver Elite',
|
22
|
+
6: 'Silver Elite Master',
|
23
|
+
7: 'Gold Nova I',
|
24
|
+
8: 'Gold Nova II',
|
25
|
+
9: 'Gold Nova III',
|
26
|
+
10: 'Gold Nova Master',
|
27
|
+
11: 'Master Guardian I',
|
28
|
+
12: 'Master Guardian II',
|
29
|
+
13: 'Master Guardian Elite',
|
30
|
+
14: 'Distinguished Master Guardian',
|
31
|
+
15: 'Legendary Eagle',
|
32
|
+
16: 'Legendary Eagle Master',
|
33
|
+
17: 'Supreme Master First Class',
|
34
|
+
18: 'The Global Elite'
|
35
|
+
}
|
36
|
+
export const LOCS = {
|
37
|
+
20054: 'VN',
|
38
|
+
23115: 'KZ',
|
39
|
+
20041: 'IN',
|
40
|
+
20035: 'CN',
|
41
|
+
17474: 'BD',
|
42
|
+
17481: 'ID',
|
43
|
+
22861: 'MY',
|
44
|
+
18516: 'TH',
|
45
|
+
22356: 'TW',
|
46
|
+
21067: 'KR',
|
47
|
+
19272: 'HK',
|
48
|
+
18512: 'PH',
|
49
|
+
21842: 'RU',
|
50
|
+
16716: 'LA',
|
51
|
+
20558: 'NP',
|
52
|
+
18259: 'SG',
|
53
|
+
19789: 'MM',
|
54
|
+
20045: 'MN',
|
55
|
+
18251: 'KG',
|
56
|
+
18507: 'KH',
|
57
|
+
22605: 'MX',
|
58
|
+
19280: 'PK',
|
59
|
+
20301: 'HK/MO',//hongkong or macau
|
60
|
+
21333: 'Unknown',
|
61
|
+
21825: 'AU',
|
62
|
+
}
|
63
|
+
|
64
|
+
|
65
|
+
const appid = 730
|
66
|
+
let CSGO_VER = null
|
67
|
+
GetCurrentVersion(appid).then(function (ver) {
|
68
|
+
CSGO_VER = ver
|
69
|
+
})
|
70
|
+
|
71
|
+
async function GetCurrentVersion(appid) {
|
72
|
+
const result = await axios.request({
|
73
|
+
url: 'https://api.steampowered.com/ISteamApps/UpToDateCheck/v1/?format=json&appid=' + appid + '&version=0'
|
74
|
+
})
|
75
|
+
return result.data.response.required_version
|
76
|
+
}
|
77
|
+
|
78
|
+
function SteamClient({
|
79
|
+
username,
|
80
|
+
password,
|
81
|
+
cookie,
|
82
|
+
}) {
|
83
|
+
const steamClient = new SteamUser()
|
84
|
+
let prime = false
|
85
|
+
let gamename = null;
|
86
|
+
|
87
|
+
const events = {
|
88
|
+
loggedOn: []
|
89
|
+
}
|
90
|
+
|
91
|
+
const personasCache = []
|
92
|
+
|
93
|
+
async function getPersonas(steamIDs) {
|
94
|
+
const notCachesteamIDs = steamIDs.filter(id => !personasCache.some(p => p.id == id))
|
95
|
+
const cachedPersonas = personasCache.filter(p => steamIDs.includes(p.id))
|
96
|
+
|
97
|
+
if (notCachesteamIDs.length) {
|
98
|
+
let personas = null
|
99
|
+
try {
|
100
|
+
personas = (await steamClient.getPersonas(steamIDs))?.personas
|
101
|
+
} catch (e) {
|
102
|
+
}
|
103
|
+
if (!personas) {
|
104
|
+
try {
|
105
|
+
personas = (await steamClient.getPersonas(steamIDs))?.personas
|
106
|
+
} catch (e) {
|
107
|
+
}
|
108
|
+
}
|
109
|
+
if (!personas) {
|
110
|
+
return {}
|
111
|
+
} else {
|
112
|
+
for (let sid64 in personas) {
|
113
|
+
personas[sid64].avatar_hash = Buffer.from(personas[sid64].avatar_hash).toString("hex")
|
114
|
+
personasCache.push(personas[sid64])
|
115
|
+
cachedPersonas.push(personas[sid64])
|
116
|
+
}
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
while (personasCache.length > 500) {
|
121
|
+
personasCache.shift()
|
122
|
+
}
|
123
|
+
return cachedPersonas
|
124
|
+
}
|
125
|
+
|
126
|
+
const sleep = (ms) => {
|
127
|
+
return new Promise(resolve => {
|
128
|
+
setTimeout(resolve, ms)
|
129
|
+
})
|
130
|
+
}
|
131
|
+
|
132
|
+
const partySearchCallback = []
|
133
|
+
|
134
|
+
/**
|
135
|
+
* Get a list of lobbies (* = Unsure description could be wrong)
|
136
|
+
* @param {Number} ver Game version we are searching for
|
137
|
+
* @param {Boolean} apr Prime or not*
|
138
|
+
* @param {Number} ark Rank multiplied by 10*
|
139
|
+
* @param {Array.<Number>} grps *
|
140
|
+
* @param {Number} launcher If we are using the China CSGO launcher or not*
|
141
|
+
* @param {Number} game_type Game type, 8 Competitive, 10 Wingman
|
142
|
+
* @returns {Promise.<Object>}
|
143
|
+
*/
|
144
|
+
async function partySearch({
|
145
|
+
prime = false, game_type = 'Competitive', rank = 'Silver Elite',
|
146
|
+
}) {
|
147
|
+
|
148
|
+
return new Promise(resolve => {
|
149
|
+
steamClient.sendToGC(appid, Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Party_Search, {}, protoEncode(Protos.csgo.CMsgGCCStrike15_v2_Party_Search, {
|
150
|
+
ver: CSGO_VER,
|
151
|
+
apr: prime ? 1 : 0,
|
152
|
+
ark: Object.keys(RANKS).find(k => RANKS[k] === rank) * 10,
|
153
|
+
grps: [],
|
154
|
+
launcher: 0,
|
155
|
+
game_type: game_type === 'Competitive' ? 8 : 10
|
156
|
+
}))
|
157
|
+
partySearchCallback.push(resolve)
|
158
|
+
setTimeout(resolve, 10000)
|
159
|
+
})
|
160
|
+
}
|
161
|
+
|
162
|
+
async function sendHello() {
|
163
|
+
console.log('sendHello')
|
164
|
+
steamClient.sendToGC(appid, Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_MatchmakingClient2GCHello, {}, Buffer.alloc(0))
|
165
|
+
steamClient.sendToGC(appid, Protos.csgo.EGCBaseClientMsg.k_EMsgGCClientHello, {}, Buffer.alloc(0))
|
166
|
+
console.log('sendHello done')
|
167
|
+
}
|
168
|
+
|
169
|
+
const requestCoPlaysCallback = []
|
170
|
+
|
171
|
+
async function requestCoPlays() {
|
172
|
+
console.log('sendMessageAccount_RequestCoPlays')
|
173
|
+
return new Promise(resolve => {
|
174
|
+
steamClient.sendToGC(appid, Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Account_RequestCoPlays, {}, Buffer.alloc(0))
|
175
|
+
requestCoPlaysCallback.push(resolve)
|
176
|
+
setTimeout(resolve, 10000)
|
177
|
+
})
|
178
|
+
}
|
179
|
+
|
180
|
+
|
181
|
+
function bindEvent() {
|
182
|
+
steamClient.on('disconnected', async (eresult, msg) => {
|
183
|
+
console.log('disconnected')
|
184
|
+
})
|
185
|
+
steamClient.on('error', async (e) => {
|
186
|
+
let errorStr = ``
|
187
|
+
switch (e.eresult) {
|
188
|
+
case 5:
|
189
|
+
errorStr = `Invalid Password`
|
190
|
+
break
|
191
|
+
case 6:
|
192
|
+
case 34:
|
193
|
+
errorStr = `Logged In Elsewhere`
|
194
|
+
break
|
195
|
+
case 84:
|
196
|
+
errorStr = `Rate Limit Exceeded`
|
197
|
+
break
|
198
|
+
case 65:
|
199
|
+
errorStr = `steam guard is invalid`
|
200
|
+
break
|
201
|
+
default:
|
202
|
+
errorStr = `Unknown: ${e.eresult}`
|
203
|
+
break
|
204
|
+
}
|
205
|
+
console.log('error', e?.message)
|
206
|
+
})
|
207
|
+
|
208
|
+
steamClient.on('webSession', (sessionID, cookies) => {
|
209
|
+
// console.log('webSession', sessionID, cookies);
|
210
|
+
})
|
211
|
+
|
212
|
+
steamClient.on('receivedFromGC', async (appid, msgType, payload) => {
|
213
|
+
const key = getECsgoGCMsgKey(msgType)
|
214
|
+
switch (msgType) {
|
215
|
+
case Protos.csgo.EMsg.k_EMsgClientChatInvite: {
|
216
|
+
console.log(payload)
|
217
|
+
break
|
218
|
+
}
|
219
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgClientMMSJoinLobbyResponse: {
|
220
|
+
let msg = protoDecode(Protos.csgo.CMsgClientMMSJoinLobbyResponse, payload)
|
221
|
+
console.log(msg)
|
222
|
+
break
|
223
|
+
}
|
224
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Party_Invite: {
|
225
|
+
let msg = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_Party_Invite, payload)
|
226
|
+
let sid = SteamID.fromIndividualAccountID(msg.accountid);
|
227
|
+
// console.log(msg)
|
228
|
+
let personas = await getPersonas([sid])
|
229
|
+
console.log(personas?.[sid]?.player_name, `https://steamcommunity.com/profiles/${sid.getSteamID64()}`);
|
230
|
+
// joinLobby(msg.lobbyid, msg.accountid)
|
231
|
+
break
|
232
|
+
}
|
233
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Account_RequestCoPlays: {
|
234
|
+
const msg = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_Account_RequestCoPlays, payload);
|
235
|
+
const personas = msg.players.map(p => SteamID.fromIndividualAccountID(p.accountid));
|
236
|
+
requestCoPlaysCallback?.shift()?.(personas)
|
237
|
+
break
|
238
|
+
}
|
239
|
+
case Protos.csgo.EGCBaseClientMsg.k_EMsgGCClientWelcome: {
|
240
|
+
const CMsgClientWelcome = protoDecode(Protos.csgo.CMsgClientWelcome, payload);
|
241
|
+
for (const outofdate_cache of CMsgClientWelcome.outofdate_subscribed_caches) {
|
242
|
+
for (const cache_object of outofdate_cache.objects) {
|
243
|
+
if (cache_object.object_data.length === 0) {
|
244
|
+
continue
|
245
|
+
}
|
246
|
+
switch (cache_object.type_id) {
|
247
|
+
case 7: {
|
248
|
+
let CSOEconGameAccountClient = protoDecode(Protos.csgo.CSOEconGameAccountClient, cache_object.object_data[0])
|
249
|
+
if ((CSOEconGameAccountClient.bonus_xp_usedflags & 16) != 0) { // EXPBonusFlag::PrestigeEarned
|
250
|
+
prime = true
|
251
|
+
}
|
252
|
+
if (CSOEconGameAccountClient.elevated_state == 5) { // bought prime
|
253
|
+
prime = true
|
254
|
+
}
|
255
|
+
break
|
256
|
+
}
|
257
|
+
}
|
258
|
+
}
|
259
|
+
}
|
260
|
+
break
|
261
|
+
}
|
262
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_MatchmakingGC2ClientUpdate: {
|
263
|
+
const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_MatchmakingGC2ClientUpdate, payload)
|
264
|
+
break
|
265
|
+
}
|
266
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_GC2ClientGlobalStats: {
|
267
|
+
const result = protoDecode(Protos.csgo.CMsgClientUGSGetGlobalStatsResponse, payload)
|
268
|
+
break
|
269
|
+
}
|
270
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_GC2ClientTextMsg: {
|
271
|
+
const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_GC2ClientTextMsg, payload)
|
272
|
+
break
|
273
|
+
}
|
274
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_MatchmakingGC2ClientHello: {
|
275
|
+
const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_MatchmakingGC2ClientHello, payload)
|
276
|
+
break
|
277
|
+
}
|
278
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientReportResponse: {
|
279
|
+
const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientReportResponse, payload)
|
280
|
+
break
|
281
|
+
}
|
282
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientCommendPlayerQueryResponse: {
|
283
|
+
const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientCommendPlayer, payload)
|
284
|
+
break
|
285
|
+
}
|
286
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_PlayerOverwatchCaseAssignment: {
|
287
|
+
const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_PlayerOverwatchCaseAssignment, payload)
|
288
|
+
break
|
289
|
+
}
|
290
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_MatchList: {
|
291
|
+
const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_MatchList, payload)
|
292
|
+
break
|
293
|
+
}
|
294
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_GetEventFavorites_Response: {
|
295
|
+
const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_GetEventFavorites_Response, payload)
|
296
|
+
break
|
297
|
+
}
|
298
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_StartAgreementSessionInGame: {
|
299
|
+
|
300
|
+
break
|
301
|
+
}
|
302
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_ClientDeepStats: {
|
303
|
+
const result = protoDecode(Protos.csgo.CMsgGCCStrike15_ClientDeepStats, payload)
|
304
|
+
break
|
305
|
+
}
|
306
|
+
case Protos.csgo.EGCBaseClientMsg.k_EMsgGCClientConnectionStatus: {
|
307
|
+
const result = protoDecode(Protos.csgo.CMsgConnectionStatus, payload)
|
308
|
+
break
|
309
|
+
}
|
310
|
+
case Protos.csgo.EGCItemMsg.k_EMsgGCStoreGetUserDataResponse: {
|
311
|
+
const result = protoDecode(Protos.csgo.CMsgStoreGetUserDataResponse, payload)
|
312
|
+
break
|
313
|
+
}
|
314
|
+
case Protos.csgo.EGCItemMsg.k_EMsgGCStorePurchaseFinalizeResponse: {
|
315
|
+
const result = protoDecode(Protos.csgo.CMsgGCStorePurchaseFinalizeResponse, payload)
|
316
|
+
break
|
317
|
+
}
|
318
|
+
case Protos.csgo.EGCItemMsg.k_EMsgGCStorePurchaseCancelResponse: {
|
319
|
+
const result = protoDecode(Protos.csgo.CMsgGCStorePurchaseCancelResponse, payload)
|
320
|
+
break
|
321
|
+
}
|
322
|
+
case Protos.csgo.EGCItemMsg.k_EMsgGCStorePurchaseInitResponse: {
|
323
|
+
const result = protoDecode(Protos.csgo.CMsgGCStorePurchaseInitResponse, payload)
|
324
|
+
break
|
325
|
+
}
|
326
|
+
case Protos.csgo.EMsg.k_EMsgClientMMSCreateLobbyResponse: {
|
327
|
+
const result = protoDecode(Protos.csgo.CMsgClientMMSCreateLobbyResponse, payload)
|
328
|
+
break
|
329
|
+
}
|
330
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientGCRankUpdate: {
|
331
|
+
const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_ClientGCRankUpdate, payload)
|
332
|
+
break
|
333
|
+
}
|
334
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Party_Search: {
|
335
|
+
const result = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_Party_SearchResults, payload)
|
336
|
+
const entries = _.uniqBy(result.entries, 'id')
|
337
|
+
|
338
|
+
const players = []
|
339
|
+
|
340
|
+
const steamIDs = entries
|
341
|
+
.map(p => SteamID.fromIndividualAccountID(p.id).getSteamID64())
|
342
|
+
const personas = await getPersonas(steamIDs)
|
343
|
+
|
344
|
+
for (const player of entries) {
|
345
|
+
try {
|
346
|
+
const prime = player.apr === 1 ? 'PRIME' : 'NON-PRIME'
|
347
|
+
const loc = LOCS[player.loc] || player.loc
|
348
|
+
const steamID = SteamID.fromIndividualAccountID(player.id).getSteamID64()
|
349
|
+
const persona = personas.find(p => p.id == player.id)
|
350
|
+
const player_name = persona.player_name
|
351
|
+
const friendCode = FriendCode.encode(steamID)
|
352
|
+
|
353
|
+
if ((LOCS[player.loc] == 'VN' || !LOCS[player.loc])) {
|
354
|
+
players.push({
|
355
|
+
prime,
|
356
|
+
player_name: player_name,
|
357
|
+
rank: RANKS[player.ark],
|
358
|
+
loc: loc,
|
359
|
+
steamID,
|
360
|
+
friendCode,
|
361
|
+
avatar_hash: persona.avatar_hash,
|
362
|
+
})
|
363
|
+
}
|
364
|
+
} catch (e) {
|
365
|
+
}
|
366
|
+
}
|
367
|
+
|
368
|
+
partySearchCallback.shift()?.(players)
|
369
|
+
break
|
370
|
+
}
|
371
|
+
case Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_PlayersProfile: {
|
372
|
+
let data = protoDecode(Protos.csgo.CMsgGCCStrike15_v2_PlayersProfile, payload)?.account_profiles
|
373
|
+
const dataExample = [{
|
374
|
+
my_current_event_teams: [],
|
375
|
+
my_current_event_stages: [],
|
376
|
+
rankings: [{
|
377
|
+
account_id: 1225887169, rank_id: 0, wins: 6, rank_change: 0, rank_type_id: 7, tv_control: 0
|
378
|
+
}, {
|
379
|
+
account_id: 1225887169, rank_id: 0, wins: 0, rank_change: 0, rank_type_id: 10, tv_control: 0
|
380
|
+
}],
|
381
|
+
account_id: 1225887169,
|
382
|
+
ongoingmatch: null,
|
383
|
+
global_stats: null,
|
384
|
+
penalty_seconds: 0,
|
385
|
+
penalty_reason: 0,
|
386
|
+
vac_banned: 0,
|
387
|
+
ranking: {
|
388
|
+
account_id: 1225887169,
|
389
|
+
rank_id: 8,
|
390
|
+
wins: 469,
|
391
|
+
rank_change: 0,
|
392
|
+
rank_type_id: 6,
|
393
|
+
tv_control: 0
|
394
|
+
},
|
395
|
+
commendation: {
|
396
|
+
cmd_friendly: 51, cmd_teaching: 40, cmd_leader: 40
|
397
|
+
},
|
398
|
+
medals: {
|
399
|
+
display_items_defidx: [4819, 4737], featured_display_item_defidx: 4819
|
400
|
+
},
|
401
|
+
my_current_event: null,
|
402
|
+
my_current_team: null,
|
403
|
+
survey_vote: 0,
|
404
|
+
activity: null,
|
405
|
+
player_level: 32,
|
406
|
+
player_cur_xp: 327682846,
|
407
|
+
player_xp_bonus_flags: 0
|
408
|
+
}]
|
409
|
+
console.log(data);
|
410
|
+
break
|
411
|
+
}
|
412
|
+
default:
|
413
|
+
console.log(`receivedFromGC ${msgType} ${key}`)
|
414
|
+
const results = Object.values(Protos.csgo).map(function (p) {
|
415
|
+
try {
|
416
|
+
return protoDecode(p, payload)
|
417
|
+
} catch (e) {
|
418
|
+
}
|
419
|
+
}).filter(function (result) {
|
420
|
+
return result && Object.keys(result).length
|
421
|
+
})
|
422
|
+
console.log(key, results)
|
423
|
+
}
|
424
|
+
})
|
425
|
+
|
426
|
+
function getECsgoGCMsgKey(_key) {
|
427
|
+
for (let key in Protos.csgo.ECsgoGCMsg) {
|
428
|
+
if (Protos.csgo.ECsgoGCMsg[key] == _key) {
|
429
|
+
return key
|
430
|
+
}
|
431
|
+
}
|
432
|
+
for (let key in Protos.csgo.EGCBaseClientMsg) {
|
433
|
+
if (Protos.csgo.EGCBaseClientMsg[key] == _key) {
|
434
|
+
return key
|
435
|
+
}
|
436
|
+
}
|
437
|
+
for (let key in Protos.csgo.EMsg) {
|
438
|
+
if (Protos.csgo.EMsg[key] == _key) {
|
439
|
+
return key
|
440
|
+
}
|
441
|
+
}
|
442
|
+
for (let key in Protos.csgo.EGCItemMsg) {
|
443
|
+
if (Protos.csgo.EGCItemMsg[key] == _key) {
|
444
|
+
return key
|
445
|
+
}
|
446
|
+
}
|
447
|
+
}
|
448
|
+
|
449
|
+
steamClient.on('loggedOn', async (loggedOnResponse) => {
|
450
|
+
await steamClient.requestFreeLicense(appid)
|
451
|
+
await sleep(5000)
|
452
|
+
|
453
|
+
if (gamename) {
|
454
|
+
steamClient.gamesPlayed([{
|
455
|
+
game_id: appid, game_extra_info: gamename
|
456
|
+
}], true);
|
457
|
+
} else {
|
458
|
+
steamClient.gamesPlayed(appid, true)
|
459
|
+
}
|
460
|
+
|
461
|
+
steamClient.setPersona(SteamUser.EPersonaState.LookingToPlay)
|
462
|
+
|
463
|
+
while (!steamClient.accountInfo) {
|
464
|
+
await sleep(500)
|
465
|
+
}
|
466
|
+
|
467
|
+
console.log(`app ${appid} launched on account ${steamClient.accountInfo.name}`)
|
468
|
+
await sendHello()
|
469
|
+
|
470
|
+
events.loggedOn.forEach(e => e?.invoke?.())
|
471
|
+
})
|
472
|
+
}
|
473
|
+
|
474
|
+
function getPlayersProfile(accountid) {
|
475
|
+
steamClient.sendToGC(730, Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_ClientRequestPlayersProfile, {}, protoEncode(Protos.csgo.CMsgGCCStrike15_v2_ClientRequestPlayersProfile, {
|
476
|
+
account_id: accountid, // account_id: new SteamID('76561199184696945').accountid,
|
477
|
+
request_level: 32
|
478
|
+
}))
|
479
|
+
}
|
480
|
+
|
481
|
+
async function login() {
|
482
|
+
if (cookie) {
|
483
|
+
console.log('login with cookie')
|
484
|
+
const result = (await axios.request({
|
485
|
+
url: 'https://steamcommunity.com/chat/clientjstoken', headers: {
|
486
|
+
cookie,
|
487
|
+
}
|
488
|
+
}))?.data
|
489
|
+
if (result) {
|
490
|
+
Object.assign(result, {
|
491
|
+
steamID: new SteamID(result.steamid), accountName: result.account_name, webLogonToken: result.token
|
492
|
+
})
|
493
|
+
steamClient.logOn(result)
|
494
|
+
}
|
495
|
+
} else if (username && password) {
|
496
|
+
console.log(`login with username ${username}`)
|
497
|
+
steamClient.logOn({
|
498
|
+
accountName: username, password: password, rememberPassword: true, machineName: 'Natri',
|
499
|
+
})
|
500
|
+
}
|
501
|
+
}
|
502
|
+
|
503
|
+
function init() {
|
504
|
+
bindEvent()
|
505
|
+
login()
|
506
|
+
}
|
507
|
+
|
508
|
+
|
509
|
+
function partyRegister() {
|
510
|
+
console.log("partyRegister", steamClient?.accountInfo?.name || username, prime);
|
511
|
+
steamClient.sendToGC(730, Protos.csgo.ECsgoGCMsg.k_EMsgGCCStrike15_v2_Party_Register, {}, protoEncode(Protos.csgo.CMsgGCCStrike15_v2_Party_Register, {
|
512
|
+
// id : 0,
|
513
|
+
ver: CSGO_VER, apr: prime ? 1 : 0,//prime
|
514
|
+
ark: prime ? 180 : 0, grps: [], launcher: 0, game_type: 8
|
515
|
+
}))
|
516
|
+
}
|
517
|
+
|
518
|
+
return {
|
519
|
+
init, partySearch, partyRegister, requestCoPlays, getPersonas, getUsername: function () {
|
520
|
+
return username
|
521
|
+
}, onEvent: function (name, cb) {
|
522
|
+
if (!events[name]) {
|
523
|
+
events[name] = []
|
524
|
+
}
|
525
|
+
events[name].push(cb)
|
526
|
+
}, setPersona: function (state, name) {
|
527
|
+
steamClient.setPersona(state, name)
|
528
|
+
}, setGameName: function (name) {
|
529
|
+
gamename = name
|
530
|
+
},
|
531
|
+
}
|
532
|
+
}
|
533
|
+
|
534
|
+
export default SteamClient
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import Protobuf from "protobufjs";
|
2
|
+
import fs from "fs";
|
3
|
+
import path from "path";
|
4
|
+
|
5
|
+
export default function Protos(protos, ignoreErrors = true) {
|
6
|
+
const protobufs = {};
|
7
|
+
|
8
|
+
for (let proto of protos) {
|
9
|
+
let root = new Protobuf.Root();
|
10
|
+
let files = Array.isArray(proto.protos) ? proto.protos : fs.readdirSync(proto.protos).map(file => path.join(proto.protos, file));
|
11
|
+
|
12
|
+
for (let file of files) {
|
13
|
+
if (!file.endsWith(".proto") || !fs.existsSync(file)) {
|
14
|
+
continue;
|
15
|
+
}
|
16
|
+
|
17
|
+
try {
|
18
|
+
root = root.loadSync(file, {
|
19
|
+
keepCase: true
|
20
|
+
});
|
21
|
+
} catch (err) {
|
22
|
+
if (!ignoreErrors) {
|
23
|
+
throw err;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
;
|
27
|
+
}
|
28
|
+
|
29
|
+
protobufs[proto.name] = root;
|
30
|
+
}
|
31
|
+
|
32
|
+
return protobufs;
|
33
|
+
}
|
package/helpers/util.js
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
export function penalty_reason_string(id) {
|
2
|
+
switch (id) {
|
3
|
+
case 0:
|
4
|
+
return 0;
|
5
|
+
case 1:
|
6
|
+
return "Kicked";
|
7
|
+
case 2:
|
8
|
+
return "TK Limit";
|
9
|
+
case 3:
|
10
|
+
return "TK Spawn";
|
11
|
+
case 4:
|
12
|
+
return "Disconnected Too Long";
|
13
|
+
case 5:
|
14
|
+
return "Abandon";
|
15
|
+
case 6:
|
16
|
+
return "TD Limit";
|
17
|
+
case 7:
|
18
|
+
return "TD Spawn";
|
19
|
+
case 8:
|
20
|
+
case 14:
|
21
|
+
return "Untrusted";
|
22
|
+
case 9:
|
23
|
+
return "Kicked Too Much";
|
24
|
+
case 10:
|
25
|
+
return "Overwatch (Cheat)";
|
26
|
+
case 11:
|
27
|
+
return "Overwatch (Grief)";
|
28
|
+
case 16:
|
29
|
+
return "Failed To Connect";
|
30
|
+
case 17:
|
31
|
+
return "Kick Abuse";
|
32
|
+
case 18:
|
33
|
+
case 19:
|
34
|
+
case 20:
|
35
|
+
return "Rank Calibration";
|
36
|
+
case 21:
|
37
|
+
return "Reports (Grief)"
|
38
|
+
default:
|
39
|
+
return `Unknown(${id})`;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
export function penalty_reason_permanent(id) {
|
44
|
+
switch (id) {
|
45
|
+
case 8:
|
46
|
+
case 14:
|
47
|
+
case 10:
|
48
|
+
return true;
|
49
|
+
default:
|
50
|
+
return false;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
export function protoDecode(proto, obj) {
|
55
|
+
return proto.toObject(proto.decode(obj), {defaults: true});
|
56
|
+
}
|
57
|
+
|
58
|
+
export function protoEncode(proto, obj) {
|
59
|
+
return proto.encode(proto.create(obj)).finish();
|
60
|
+
}
|
package/index.js
CHANGED
@@ -1864,6 +1864,7 @@ class SteamUser {
|
|
1864
1864
|
let result = (await this._httpRequest('chat/clientjstoken'))?.data
|
1865
1865
|
if (!result?.steamid) {
|
1866
1866
|
if (retry !== null && retry !== undefined && retry >= 0) {
|
1867
|
+
await sleep(2000)
|
1867
1868
|
return await this.getClientJsToken(retry - 1)
|
1868
1869
|
} else {
|
1869
1870
|
return null
|
package/package.json
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
{
|
2
2
|
"name": "steamutils",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.4",
|
4
4
|
"dependencies": {
|
5
5
|
"axios": "^1.3.4",
|
6
6
|
"cheerio": "^1.0.0-rc.12",
|
7
7
|
"crypto-js": "^4.1.1",
|
8
|
+
"csgo-friendcode": "^3.0.3",
|
8
9
|
"lodash": "^4.17.21",
|
9
10
|
"moment": "^2.29.4",
|
10
11
|
"node-bignumber": "^1.2.2",
|
12
|
+
"steam-user": "^4.28.1",
|
11
13
|
"steamid": "^2.0.0",
|
12
14
|
"url-parse": "^1.5.10",
|
13
15
|
"xml-js": "^1.6.11",
|