steamutils 1.4.20 → 1.4.22

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