steamutils 1.4.21 → 1.4.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) 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 -2658
  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 +284 -3
  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
  239. package/.idea/git_toolbox_prj.xml +0 -15
package/SteamClient.js CHANGED
@@ -1,2658 +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.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
- }
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
+ }