yolkbot 0.1.0-alpha.9 → 0.1.1-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/browser.js +6 -6
- package/package.json +17 -5
- package/src/api.js +97 -23
- package/src/bot/GamePlayer.js +2 -2
- package/src/bot.js +892 -483
- package/src/comm/Codes.js +73 -0
- package/src/constants/challenges.js +1822 -0
- package/src/constants/index.js +23 -1
- package/src/constants/items.js +663 -264
- package/src/constants/maps.js +57 -18
- package/src/dispatches/BootPlayerDispatch.js +1 -1
- package/src/dispatches/ChatDispatch.js +1 -1
- package/src/dispatches/GameOptionsDispatch.js +1 -1
- package/src/dispatches/GoToAmmoDispatch.js +44 -0
- package/src/dispatches/GoToCoopDispatch.js +44 -0
- package/src/dispatches/GoToGrenadeDispatch.js +44 -0
- package/src/dispatches/GoToPlayerDispatch.js +5 -1
- package/src/dispatches/GoToSpatulaDispatch.js +5 -1
- package/src/dispatches/LookAtPosDispatch.js +0 -2
- package/src/dispatches/LookDispatch2.js +18 -0
- package/src/dispatches/MeleeDispatch.js +1 -1
- package/src/dispatches/PauseDispatch.js +1 -1
- package/src/dispatches/ReloadDispatch.js +14 -2
- package/src/dispatches/ReportPlayerDispatch.js +1 -1
- package/src/dispatches/SaveLoadoutDispatch.js +11 -34
- package/src/dispatches/SpawnDispatch.js +1 -1
- package/src/dispatches/SwapWeaponDispatch.js +1 -1
- package/src/dispatches/SwitchTeamDispatch.js +1 -1
- package/src/dispatches/ThrowGrenadeDispatch.js +1 -1
- package/src/dispatches/index.js +9 -0
- package/src/matchmaker.js +11 -2
- package/src/pathing/mapnode.js +83 -250
- package/src/socket.js +1 -1
- package/src/types/api.d.ts +2 -16
- package/src/types/bot/GamePlayer.d.ts +25 -21
- package/src/types/bot.d.ts +122 -54
- package/src/types/constants/challenges.d.ts +19 -0
- package/src/types/constants/guns.d.ts +240 -0
- package/src/types/constants/index.d.ts +100 -0
- package/src/types/constants/items.d.ts +21 -0
- package/src/types/constants/maps.d.ts +15 -0
- package/src/types/dispatches/GoToAmmoDispatch.d.ts +8 -0
- package/src/types/dispatches/GoToCoopDispatch.d.ts +8 -0
- package/src/types/dispatches/GoToGrenadeDispatch.d.ts +8 -0
- package/src/types/dispatches/MovementDispatch.d.ts +2 -0
- package/src/types/dispatches/index.d.ts +45 -1
- package/src/types/matchmaker.d.ts +19 -14
- package/src/types/socket.d.ts +7 -0
- package/src/types/gun.d.ts +0 -131
package/src/bot.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { loginAnonymously, loginWithCredentials } from '#api';
|
|
1
|
+
import { createAccount, loginAnonymously, loginWithCredentials, loginWithRefreshToken, queryServices } from '#api';
|
|
2
2
|
|
|
3
3
|
import CommIn from './comm/CommIn.js';
|
|
4
4
|
import CommOut from './comm/CommOut.js';
|
|
@@ -9,6 +9,7 @@ import Matchmaker from './matchmaker.js';
|
|
|
9
9
|
import yolkws from './socket.js';
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
|
+
ChiknWinnerDailyLimit,
|
|
12
13
|
CollectTypes,
|
|
13
14
|
CoopStates,
|
|
14
15
|
findItemById,
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
GameOptionFlags,
|
|
18
19
|
GunList,
|
|
19
20
|
IsBrowser,
|
|
21
|
+
ItemTypes,
|
|
20
22
|
Movements,
|
|
21
23
|
PlayTypes,
|
|
22
24
|
ShellStreaks
|
|
@@ -32,30 +34,32 @@ import { Maps } from './constants/maps.js';
|
|
|
32
34
|
const CoopStagesById = Object.fromEntries(Object.entries(CoopStates).map(([key, value]) => [value, key]));
|
|
33
35
|
const GameModesById = Object.fromEntries(Object.entries(GameModes).map(([key, value]) => [value, key]));
|
|
34
36
|
|
|
37
|
+
const intents = {
|
|
38
|
+
CHALLENGES: 1,
|
|
39
|
+
STATS: 2,
|
|
40
|
+
PATHFINDING: 3,
|
|
41
|
+
BUFFERS: 4,
|
|
42
|
+
PING: 5,
|
|
43
|
+
COSMETIC_DATA: 6,
|
|
44
|
+
PLAYER_HEALTH: 7,
|
|
45
|
+
PACKET_HOOK: 8
|
|
46
|
+
}
|
|
47
|
+
|
|
35
48
|
export class Bot {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// params.updateInterval - the auto update interval
|
|
40
|
-
// params.doPing - whether to auto ping (for bot.<ping>)
|
|
41
|
-
// params.pingInterval - the ping interval
|
|
42
|
-
// params.doPathing - whether to run pathfinding logic
|
|
43
|
-
// params.instance - a custom shell URL to run requests through
|
|
49
|
+
static Intents = intents;
|
|
50
|
+
Intents = intents;
|
|
51
|
+
|
|
44
52
|
constructor(params = {}) {
|
|
45
53
|
if (params.proxy && IsBrowser)
|
|
46
54
|
throw new Error('proxies do not work and hence are not supported in the browser');
|
|
47
55
|
|
|
56
|
+
this.intents = params.intents || [];
|
|
57
|
+
|
|
58
|
+
this.instance = params.instance || 'shellshock.io';
|
|
48
59
|
this.proxy = params.proxy || '';
|
|
49
|
-
this.name = params.name || Math.random().toString(36).substring(8);
|
|
50
60
|
|
|
51
|
-
this.autoPing = params.doPing || true;
|
|
52
61
|
this.autoUpdate = params.doUpdate || true;
|
|
53
|
-
this.
|
|
54
|
-
|
|
55
|
-
this.pingInterval = params.pingInterval || 1000;
|
|
56
|
-
this.updateInterval = params.updateInterval || 5;
|
|
57
|
-
|
|
58
|
-
this.instance = params.instance || 'shellshock.io';
|
|
62
|
+
this.updateInterval = params.updateInterval || 16.5;
|
|
59
63
|
|
|
60
64
|
this._hooks = {};
|
|
61
65
|
this._globalHooks = [];
|
|
@@ -63,10 +67,10 @@ export class Bot {
|
|
|
63
67
|
|
|
64
68
|
// private information NOT FOR OTHER PLAYERS!!
|
|
65
69
|
this.state = {
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
// kept for specifying socket open sequence
|
|
71
|
+
name: '',
|
|
68
72
|
|
|
69
|
-
//
|
|
73
|
+
// tracking for dispatch checks
|
|
70
74
|
reloading: false,
|
|
71
75
|
swappingGun: false,
|
|
72
76
|
usingMelee: false,
|
|
@@ -81,6 +85,7 @@ export class Bot {
|
|
|
81
85
|
this.game = {
|
|
82
86
|
raw: {}, // matchmaker response
|
|
83
87
|
code: '',
|
|
88
|
+
socket: null,
|
|
84
89
|
|
|
85
90
|
// data given on sign in
|
|
86
91
|
gameModeId: 0, // assume ffa
|
|
@@ -98,8 +103,10 @@ export class Bot {
|
|
|
98
103
|
},
|
|
99
104
|
availability: 'both',
|
|
100
105
|
numPlayers: '18',
|
|
106
|
+
|
|
101
107
|
raw: {},
|
|
102
|
-
nodes: {}
|
|
108
|
+
nodes: {},
|
|
109
|
+
zones: []
|
|
103
110
|
},
|
|
104
111
|
playerLimit: 0,
|
|
105
112
|
isGameOwner: false,
|
|
@@ -135,7 +142,8 @@ export class Bot {
|
|
|
135
142
|
|
|
136
143
|
// data from kotc
|
|
137
144
|
stage: CoopStates.capturing,
|
|
138
|
-
|
|
145
|
+
zoneNumber: 0,
|
|
146
|
+
activeZone: [],
|
|
139
147
|
capturing: 0,
|
|
140
148
|
captureProgress: 0,
|
|
141
149
|
numCapturing: 0,
|
|
@@ -145,10 +153,23 @@ export class Bot {
|
|
|
145
153
|
|
|
146
154
|
this.account = {
|
|
147
155
|
// used for auth
|
|
156
|
+
id: 0,
|
|
148
157
|
firebaseId: '',
|
|
149
158
|
sessionId: '',
|
|
150
159
|
session: '',
|
|
151
160
|
|
|
161
|
+
// raw login params
|
|
162
|
+
email: '',
|
|
163
|
+
password: '',
|
|
164
|
+
|
|
165
|
+
// chikn winner related info
|
|
166
|
+
cw: {
|
|
167
|
+
atLimit: false,
|
|
168
|
+
limit: 0,
|
|
169
|
+
secondsUntilPlay: 0, // short cooldown, in seconds
|
|
170
|
+
canPlayAgain: Date.now()
|
|
171
|
+
},
|
|
172
|
+
|
|
152
173
|
// used for skin changing
|
|
153
174
|
loadout: {
|
|
154
175
|
hatId: null,
|
|
@@ -184,21 +205,17 @@ export class Bot {
|
|
|
184
205
|
this._dispatches = [];
|
|
185
206
|
this._packetQueue = [];
|
|
186
207
|
|
|
187
|
-
this.
|
|
208
|
+
this.matchmaker = null;
|
|
188
209
|
|
|
189
210
|
this.ping = 0;
|
|
190
211
|
this.lastPingTime = -1;
|
|
191
212
|
|
|
192
213
|
this.lastDeathTime = -1;
|
|
193
214
|
this.lastChatTime = -1;
|
|
194
|
-
|
|
195
215
|
this.lastUpdateTime = -1;
|
|
196
|
-
this.nUpdates = 0;
|
|
197
216
|
|
|
198
217
|
this.controlKeys = 0;
|
|
199
218
|
|
|
200
|
-
this.initTime = Date.now();
|
|
201
|
-
|
|
202
219
|
this.pathing = {
|
|
203
220
|
nodeList: null,
|
|
204
221
|
followingPath: false,
|
|
@@ -206,90 +223,111 @@ export class Bot {
|
|
|
206
223
|
activeNode: null,
|
|
207
224
|
activeNodeIdx: 0
|
|
208
225
|
}
|
|
226
|
+
|
|
227
|
+
if (this.intents.includes(this.Intents.PLAYER_HEALTH)) this.healthIntervalId = setInterval(() => {
|
|
228
|
+
if (!this.players) return;
|
|
229
|
+
|
|
230
|
+
for (const player of Object.values(this.players)) {
|
|
231
|
+
if (player.playing && player.hp > 0) {
|
|
232
|
+
const regenSpeed = 0.1 * (this.game.isPrivate ? this.game.options.healthRegen : 1);
|
|
233
|
+
|
|
234
|
+
if (player.streakRewards.includes(ShellStreaks.OverHeal)) {
|
|
235
|
+
player.hp = Math.max(100, player.hp - regenSpeed);
|
|
236
|
+
} else {
|
|
237
|
+
player.hp = Math.min(100, player.hp + regenSpeed);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}, 33);
|
|
209
242
|
}
|
|
210
243
|
|
|
211
|
-
|
|
212
|
-
|
|
244
|
+
dispatch(disp) {
|
|
245
|
+
this._dispatches.push(disp);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async createAccount(email, pass) {
|
|
249
|
+
this.account.email = email;
|
|
250
|
+
this.account.password = pass;
|
|
213
251
|
|
|
214
|
-
|
|
215
|
-
|
|
252
|
+
const loginData = await createAccount(email, pass, this.proxy, this.instance);
|
|
253
|
+
return await this.#processLoginData(loginData);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async login(email, pass) {
|
|
257
|
+
this.account.email = email;
|
|
258
|
+
this.account.password = pass;
|
|
216
259
|
|
|
217
260
|
const loginData = await loginWithCredentials(email, pass, this.proxy, this.instance);
|
|
261
|
+
return await this.#processLoginData(loginData);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async loginWithRefreshToken(refreshToken) {
|
|
265
|
+
const loginData = await loginWithRefreshToken(refreshToken, this.proxy, this.instance);
|
|
266
|
+
return await this.#processLoginData(loginData);
|
|
267
|
+
}
|
|
218
268
|
|
|
269
|
+
async loginAnonymously() {
|
|
270
|
+
delete this.account.email;
|
|
271
|
+
delete this.account.password;
|
|
272
|
+
|
|
273
|
+
const loginData = await loginAnonymously(this.proxy, this.instance);
|
|
274
|
+
return await this.#processLoginData(loginData);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
async #processLoginData(loginData) {
|
|
219
278
|
if (typeof loginData == 'string') {
|
|
220
|
-
this
|
|
279
|
+
this.emit('authFail', loginData);
|
|
221
280
|
return false;
|
|
222
281
|
}
|
|
223
282
|
|
|
224
283
|
if (loginData.banRemaining) {
|
|
225
|
-
this
|
|
284
|
+
this.emit('banned', loginData.banRemaining);
|
|
226
285
|
return false;
|
|
227
286
|
}
|
|
228
287
|
|
|
229
|
-
this.state.loggedIn = true;
|
|
230
|
-
|
|
231
288
|
this.account.rawLoginData = loginData;
|
|
232
289
|
|
|
233
290
|
this.account.accountAge = loginData.accountAge;
|
|
234
291
|
this.account.eggBalance = loginData.currentBalance;
|
|
235
292
|
this.account.emailVerified = loginData.emailVerified;
|
|
236
293
|
this.account.firebaseId = loginData.firebaseId;
|
|
294
|
+
this.account.id = loginData.id;
|
|
237
295
|
this.account.loadout = loginData.loadout;
|
|
238
296
|
this.account.ownedItemIds = loginData.ownedItemIds;
|
|
297
|
+
this.account.session = loginData.session;
|
|
239
298
|
this.account.sessionId = loginData.sessionId;
|
|
240
299
|
this.account.vip = loginData.upgradeProductId && !loginData.upgradeIsExpired;
|
|
241
300
|
|
|
242
|
-
|
|
301
|
+
if (this.intents.includes(this.Intents.STATS)) this.account.stats = {
|
|
302
|
+
lifetime: loginData.statsLifetime,
|
|
303
|
+
monthly: loginData.statsCurrent
|
|
304
|
+
};
|
|
243
305
|
|
|
244
|
-
|
|
245
|
-
|
|
306
|
+
if (this.intents.includes(this.Intents.CHALLENGES)) {
|
|
307
|
+
this.account.challenges = [];
|
|
246
308
|
|
|
247
|
-
|
|
248
|
-
this._dispatches.push(disp);
|
|
249
|
-
}
|
|
309
|
+
const { Challenges } = await import('./constants/challenges.js');
|
|
250
310
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
if (disp.check(this)) {
|
|
255
|
-
disp.execute(this);
|
|
256
|
-
this._dispatches.splice(i, 1);
|
|
257
|
-
return; // only 1 dispatch per update
|
|
258
|
-
} else {
|
|
259
|
-
// console.log("Dispatch failed", this.state.joinedGame, this.lastChatTime)
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
311
|
+
for (const challenge of loginData.challenges) {
|
|
312
|
+
const challengeData = Challenges.find(c => c.id == challenge.challengeId);
|
|
313
|
+
if (!challengeData) continue;
|
|
263
314
|
|
|
264
|
-
|
|
265
|
-
const loginData = await loginAnonymously(this.proxy, this.instance);
|
|
315
|
+
delete challenge.playerId;
|
|
266
316
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
317
|
+
this.account.challenges.push({
|
|
318
|
+
...challengeData,
|
|
319
|
+
...challenge
|
|
320
|
+
});
|
|
321
|
+
}
|
|
270
322
|
}
|
|
271
323
|
|
|
272
|
-
this.state.loggedIn = true;
|
|
273
|
-
|
|
274
|
-
this.account.rawLoginData = loginData;
|
|
275
|
-
|
|
276
|
-
this.account.accountAge = loginData.accountAge;
|
|
277
|
-
this.account.eggBalance = loginData.currentBalance;
|
|
278
|
-
this.account.emailVerified = loginData.emailVerified;
|
|
279
|
-
this.account.firebaseId = loginData.firebaseId;
|
|
280
|
-
this.account.loadout = loginData.loadout;
|
|
281
|
-
this.account.ownedItemIds = loginData.ownedItemIds;
|
|
282
|
-
this.account.session = loginData.session;
|
|
283
|
-
this.account.sessionId = loginData.sessionId;
|
|
284
|
-
this.account.vip = false;
|
|
285
|
-
|
|
286
324
|
return this.account;
|
|
287
325
|
}
|
|
288
326
|
|
|
289
327
|
async initMatchmaker() {
|
|
290
|
-
if (
|
|
328
|
+
if (this.account.id == 0) {
|
|
291
329
|
// console.log('Not logged in, attempting to create anonymous user...');
|
|
292
|
-
const anonLogin = await this
|
|
330
|
+
const anonLogin = await this.loginAnonymously();
|
|
293
331
|
if (!anonLogin) return false;
|
|
294
332
|
}
|
|
295
333
|
|
|
@@ -301,7 +339,7 @@ export class Bot {
|
|
|
301
339
|
instance: this.instance
|
|
302
340
|
});
|
|
303
341
|
|
|
304
|
-
this.matchmaker.on('authFail', (data) => this
|
|
342
|
+
this.matchmaker.on('authFail', (data) => this.emit('authFail', data));
|
|
305
343
|
|
|
306
344
|
await this.matchmaker.getRegions();
|
|
307
345
|
}
|
|
@@ -312,34 +350,33 @@ export class Bot {
|
|
|
312
350
|
async #joinGameWithCode(code) {
|
|
313
351
|
if (!await this.initMatchmaker()) return false;
|
|
314
352
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
delete this.game.raw.command; // pissed me off
|
|
353
|
+
return await new Promise((resolve) => {
|
|
354
|
+
const listener = (mes) => {
|
|
355
|
+
if (mes.command == 'gameFound') {
|
|
356
|
+
this.matchmaker.off('msg', listener);
|
|
320
357
|
|
|
321
|
-
|
|
322
|
-
|
|
358
|
+
this.game.raw = mes;
|
|
359
|
+
this.game.code = code;
|
|
323
360
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
this.matchmaker.on('msg', listener);
|
|
361
|
+
resolve();
|
|
362
|
+
}
|
|
329
363
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
observe: false,
|
|
334
|
-
sessionId: this.account.sessionId
|
|
335
|
-
})
|
|
364
|
+
if (mes.error && mes.error == 'gameNotFound')
|
|
365
|
+
throw new Error(`Game ${code} not found (likely expired).`)
|
|
366
|
+
};
|
|
336
367
|
|
|
337
|
-
|
|
368
|
+
this.matchmaker.on('msg', listener);
|
|
338
369
|
|
|
339
|
-
|
|
370
|
+
this.matchmaker.send({
|
|
371
|
+
command: 'joinGame',
|
|
372
|
+
id: code,
|
|
373
|
+
observe: false,
|
|
374
|
+
sessionId: this.account.sessionId
|
|
375
|
+
})
|
|
376
|
+
});
|
|
340
377
|
}
|
|
341
378
|
|
|
342
|
-
async #onGameMesssage(msg) {
|
|
379
|
+
async #onGameMesssage(msg) {
|
|
343
380
|
CommIn.init(msg.data);
|
|
344
381
|
|
|
345
382
|
let out;
|
|
@@ -350,7 +387,7 @@ export class Bot {
|
|
|
350
387
|
out = CommOut.getBuffer();
|
|
351
388
|
out.packInt8(CommCode.joinGame);
|
|
352
389
|
|
|
353
|
-
out.packString(this.name); // name
|
|
390
|
+
out.packString(this.state.name); // name
|
|
354
391
|
out.packString(this.game.raw.uuid); // game id
|
|
355
392
|
|
|
356
393
|
out.packInt8(0); // hidebadge
|
|
@@ -360,10 +397,10 @@ export class Bot {
|
|
|
360
397
|
out.packString(this.account.firebaseId); // firebase id
|
|
361
398
|
out.packString(this.account.sessionId); // session id
|
|
362
399
|
|
|
363
|
-
out.send(this.
|
|
400
|
+
out.send(this.game.socket);
|
|
364
401
|
break;
|
|
365
402
|
|
|
366
|
-
case CommCode.gameJoined:
|
|
403
|
+
case CommCode.gameJoined: {
|
|
367
404
|
this.me.id = CommIn.unPackInt8U();
|
|
368
405
|
// console.log("My id is:", this.me.id);
|
|
369
406
|
this.me.team = CommIn.unPackInt8U();
|
|
@@ -373,9 +410,10 @@ export class Bot {
|
|
|
373
410
|
// console.log("Gametype:", this.game.gameMode, this.game.gameModeId);
|
|
374
411
|
this.game.mapIdx = CommIn.unPackInt8U();
|
|
375
412
|
this.game.map = Maps[this.game.mapIdx];
|
|
376
|
-
if (
|
|
413
|
+
if (this.intents.includes(this.Intents.PATHFINDING)) {
|
|
377
414
|
this.game.map.raw = await this.#fetchMap(this.game.map.filename, this.game.map.hash);
|
|
378
415
|
this.pathing.nodeList = new NodeList(this.game.map.raw);
|
|
416
|
+
if (this.game.gameModeId === GameModes.kotc) this.#initKotcZones();
|
|
379
417
|
}
|
|
380
418
|
// console.log("Map:", this.game.map);
|
|
381
419
|
this.game.playerLimit = CommIn.unPackInt8U();
|
|
@@ -389,34 +427,34 @@ export class Bot {
|
|
|
389
427
|
this.state.joinedGame = true;
|
|
390
428
|
this.lastDeathTime = Date.now();
|
|
391
429
|
|
|
430
|
+
const out = CommOut.getBuffer();
|
|
431
|
+
out.packInt8(CommCode.clientReady);
|
|
432
|
+
out.send(this.game.socket);
|
|
433
|
+
|
|
434
|
+
this.game.socket.onmessage = (msg) => this._packetQueue.push(msg.data);
|
|
435
|
+
|
|
436
|
+
if (this.autoUpdate)
|
|
437
|
+
setInterval(() => this.update(), this.updateInterval);
|
|
438
|
+
|
|
439
|
+
if (this.intents.includes(this.Intents.PING)) {
|
|
440
|
+
const out = CommOut.getBuffer();
|
|
441
|
+
out.packInt8(CommCode.ping);
|
|
442
|
+
out.send(this.game.socket);
|
|
443
|
+
this.lastPingTime = Date.now();
|
|
444
|
+
}
|
|
392
445
|
break;
|
|
446
|
+
}
|
|
393
447
|
|
|
394
448
|
case CommCode.eventModifier:
|
|
395
449
|
// console.log("Echoed eventModifier"); // why the fuck do you need to do this
|
|
396
450
|
out = CommOut.getBuffer();
|
|
397
451
|
out.packInt8(CommCode.eventModifier);
|
|
398
|
-
out.send(this.
|
|
452
|
+
out.send(this.game.socket);
|
|
399
453
|
break;
|
|
400
454
|
|
|
401
|
-
case CommCode.requestGameOptions:
|
|
402
|
-
|
|
403
|
-
out.packInt8(CommCode.gameOptions);
|
|
404
|
-
out.packInt8(this.game.options.gravity * 4);
|
|
405
|
-
out.packInt8(this.game.options.damage * 4);
|
|
406
|
-
out.packInt8(this.game.options.healthRegen * 4);
|
|
407
|
-
|
|
408
|
-
const flags =
|
|
409
|
-
(this.game.options.locked ? 1 : 0) |
|
|
410
|
-
(this.game.options.noTeamChange ? 2 : 0) |
|
|
411
|
-
(this.game.options.noTeamShuffle ? 4 : 0);
|
|
412
|
-
|
|
413
|
-
out.packInt8(flags);
|
|
414
|
-
|
|
415
|
-
this.game.options.weaponsDisabled.forEach((v) => {
|
|
416
|
-
out.packInt8(v ? 1 : 0);
|
|
417
|
-
});
|
|
455
|
+
case CommCode.requestGameOptions:
|
|
456
|
+
this.#processGameRequestOptionsPacket();
|
|
418
457
|
break;
|
|
419
|
-
}
|
|
420
458
|
|
|
421
459
|
default:
|
|
422
460
|
try {
|
|
@@ -449,52 +487,50 @@ export class Bot {
|
|
|
449
487
|
|
|
450
488
|
if (mapIdx == -1) throw new Error('invalid map, see the Maps constant for a list')
|
|
451
489
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
delete this.game.raw.command;
|
|
457
|
-
|
|
458
|
-
this.gameFound = true;
|
|
459
|
-
}
|
|
460
|
-
};
|
|
490
|
+
await new Promise((resolve) => {
|
|
491
|
+
const listener = (msg) => {
|
|
492
|
+
if (msg.command == 'gameFound') {
|
|
493
|
+
this.matchmaker.off('msg', listener);
|
|
461
494
|
|
|
462
|
-
|
|
495
|
+
this.game.raw = msg;
|
|
496
|
+
this.game.code = this.game.raw.id;
|
|
463
497
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
playType: PlayTypes.createPrivate,
|
|
468
|
-
gameType: GameModes[opts.mode],
|
|
469
|
-
sessionId: this.account.sessionId,
|
|
470
|
-
noobLobby: false,
|
|
471
|
-
map: mapIdx
|
|
472
|
-
});
|
|
498
|
+
resolve();
|
|
499
|
+
}
|
|
500
|
+
};
|
|
473
501
|
|
|
474
|
-
|
|
502
|
+
this.matchmaker.on('msg', listener);
|
|
475
503
|
|
|
476
|
-
|
|
504
|
+
this.matchmaker.send({
|
|
505
|
+
command: 'findGame',
|
|
506
|
+
region: opts.region,
|
|
507
|
+
playType: PlayTypes.createPrivate,
|
|
508
|
+
gameType: GameModes[opts.mode],
|
|
509
|
+
sessionId: this.account.sessionId,
|
|
510
|
+
noobLobby: false,
|
|
511
|
+
map: mapIdx
|
|
512
|
+
});
|
|
513
|
+
});
|
|
477
514
|
|
|
478
515
|
return this.game.raw;
|
|
479
516
|
}
|
|
480
517
|
|
|
481
|
-
async join(data) {
|
|
518
|
+
async join(name, data) {
|
|
519
|
+
this.state.name = name || 'yolkbot';
|
|
520
|
+
|
|
482
521
|
if (typeof data == 'string') {
|
|
483
522
|
if (data.includes('#')) data = data.split('#')[1]; // stupid shell kids put in full links
|
|
484
523
|
// this is a string code that we can pass and get the needed info from
|
|
485
524
|
await this.#joinGameWithCode(data);
|
|
486
525
|
} else if (typeof data == 'object') {
|
|
487
|
-
if (
|
|
526
|
+
if (this.account.id == 0) {
|
|
488
527
|
// console.log('passed an object but you still need to be logged in!!')
|
|
489
|
-
await this
|
|
528
|
+
await this.loginAnonymously();
|
|
490
529
|
}
|
|
491
530
|
|
|
492
531
|
// this is a game object that we can pass and get the needed info from
|
|
493
532
|
this.game.raw = data;
|
|
494
533
|
this.game.code = this.game.raw.id;
|
|
495
|
-
delete this.game.raw.command;
|
|
496
|
-
|
|
497
|
-
this.gameFound = true;
|
|
498
534
|
}
|
|
499
535
|
|
|
500
536
|
if (!this.game.raw.id || !this.game.raw.subdomain)
|
|
@@ -502,115 +538,115 @@ export class Bot {
|
|
|
502
538
|
|
|
503
539
|
// console.log(`Joining ${this.game.raw.id} using proxy ${this.proxy || 'none'}`);
|
|
504
540
|
|
|
505
|
-
|
|
541
|
+
const attempt = async () => {
|
|
542
|
+
try {
|
|
543
|
+
this.game.socket = new yolkws(`wss://${this.game.raw.subdomain}.${this.instance}/game/${this.game.raw.id}`, this.proxy);
|
|
544
|
+
} catch {
|
|
545
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
546
|
+
await attempt();
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
await attempt();
|
|
506
551
|
|
|
507
|
-
this.
|
|
552
|
+
this.game.socket.binaryType = 'arraybuffer';
|
|
508
553
|
|
|
509
|
-
this.
|
|
554
|
+
this.game.socket.onopen = () => {
|
|
510
555
|
// console.log('Successfully connected to game server.');
|
|
511
556
|
}
|
|
512
557
|
|
|
513
|
-
this.
|
|
558
|
+
this.game.socket.onmessage = this.#onGameMesssage.bind(this);
|
|
514
559
|
|
|
515
|
-
this.
|
|
560
|
+
this.game.socket.onclose = (e) => {
|
|
516
561
|
// console.log('Game socket closed:', e.code, Object.entries(CloseCode).filter(([, v]) => v == e.code));
|
|
517
|
-
this
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
while (!this.state.joinedGame) await new Promise(r => setTimeout(r, 5));
|
|
521
|
-
|
|
522
|
-
const out = CommOut.getBuffer();
|
|
523
|
-
out.packInt8(CommCode.clientReady);
|
|
524
|
-
out.send(this.gameSocket);
|
|
525
|
-
|
|
526
|
-
this.gameSocket.onmessage = (msg) => this._packetQueue.push(msg.data);
|
|
527
|
-
|
|
528
|
-
// console.log(`Successfully joined ${this.game.code}. Startup to join time: ${Date.now() - this.initTime} ms`);
|
|
529
|
-
|
|
530
|
-
if (this.autoUpdate)
|
|
531
|
-
setInterval(() => this.update(), this.updateInterval);
|
|
532
|
-
|
|
533
|
-
if (this.autoPing) {
|
|
534
|
-
const out = CommOut.getBuffer();
|
|
535
|
-
out.packInt8(CommCode.ping);
|
|
536
|
-
out.send(this.gameSocket);
|
|
537
|
-
this.lastPingTime = Date.now();
|
|
562
|
+
this.emit('close', e.code);
|
|
538
563
|
}
|
|
539
564
|
}
|
|
540
565
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
this.nUpdates++;
|
|
566
|
+
#processPathfinding() {
|
|
567
|
+
const myPositionStr = Object.entries(this.me.position).map(entry => Math.floor(entry[1])).join(',');
|
|
545
568
|
|
|
546
|
-
if (this.
|
|
569
|
+
if (myPositionStr == this.pathing.activePath[this.pathing.activePath.length - 1].positionStr()) {
|
|
570
|
+
// console.log('Completed path to', this.pathing.activePath[this.pathing.activePath.length - 1].position);
|
|
571
|
+
this.pathing.followingPath = false;
|
|
572
|
+
this.pathing.activePath = null;
|
|
573
|
+
this.pathing.activeNode = null;
|
|
574
|
+
this.pathing.activeNodeIdx = 0;
|
|
547
575
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
const myPositionStr = Object.entries(this.me.position).map(entry => Math.floor(entry[1])).join(',');
|
|
555
|
-
|
|
556
|
-
if (myPositionStr == this.pathing.activePath[this.pathing.activePath.length - 1].positionStr()) {
|
|
557
|
-
// console.log('Completed path to', this.pathing.activePath[this.pathing.activePath.length - 1].position);
|
|
558
|
-
this.pathing.followingPath = false;
|
|
559
|
-
this.pathing.activePath = null;
|
|
560
|
-
this.pathing.activeNode = null;
|
|
561
|
-
this.pathing.activeNodeIdx = 0;
|
|
562
|
-
|
|
563
|
-
this.dispatch(new MovementDispatch(0));
|
|
576
|
+
this.dispatch(new MovementDispatch(0));
|
|
577
|
+
} else {
|
|
578
|
+
let positionTarget;
|
|
579
|
+
if (this.pathing.activeNodeIdx < this.pathing.activePath.length - 1) {
|
|
580
|
+
positionTarget = this.pathing.activePath[this.pathing.activeNodeIdx + 1].flatCenter();
|
|
581
|
+
this.dispatch(new LookAtPosDispatch(positionTarget));
|
|
564
582
|
} else {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
this.dispatch(new LookAtPosDispatch(positionTarget));
|
|
569
|
-
} else {
|
|
570
|
-
positionTarget = this.pathing.activePath[this.pathing.activeNodeIdx].flatCenter();
|
|
571
|
-
this.dispatch(new LookAtPosDispatch(positionTarget));
|
|
572
|
-
}
|
|
583
|
+
positionTarget = this.pathing.activePath[this.pathing.activeNodeIdx].flatCenter();
|
|
584
|
+
this.dispatch(new LookAtPosDispatch(positionTarget));
|
|
585
|
+
}
|
|
573
586
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
} else {
|
|
581
|
-
// console.log('Close to node that\'s before, idx:',
|
|
582
|
-
// this.pathing.activePath.indexOf(node), 'current:', this.pathing.activeNodeIdx);
|
|
583
|
-
}
|
|
587
|
+
for (const node of this.pathing.activePath) {
|
|
588
|
+
if (node.flatRadialDistance(this.me.position) < 0.1 && node.position.y == Math.floor(this.me.position.y)) {
|
|
589
|
+
if (this.pathing.activePath.indexOf(node) >= this.pathing.activeNodeIdx) {
|
|
590
|
+
this.pathing.activeNodeIdx = this.pathing.activePath.indexOf(node) + 1;
|
|
591
|
+
this.pathing.activeNode = this.pathing.activePath[this.pathing.activeNodeIdx];
|
|
592
|
+
break;
|
|
584
593
|
} else {
|
|
585
|
-
// console.log('
|
|
594
|
+
// console.log('Close to node that\'s before, idx:',
|
|
595
|
+
// this.pathing.activePath.indexOf(node), 'current:', this.pathing.activeNodeIdx);
|
|
586
596
|
}
|
|
587
|
-
|
|
597
|
+
} else {
|
|
598
|
+
// console.log('Node at', node.position, 'is', node.flatRadialDistance(this.me.position), 'away.')
|
|
588
599
|
}
|
|
600
|
+
// console.log('activeNode is ', this.pathing.activeNode.flatRadialDistance(this.me.position), 'away');
|
|
601
|
+
}
|
|
589
602
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
}
|
|
603
|
+
if (!(this.controlKeys & Movements.FORWARD)) {
|
|
604
|
+
this.dispatch(new MovementDispatch(Movements.FORWARD));
|
|
593
605
|
}
|
|
606
|
+
}
|
|
594
607
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
608
|
+
/*let onPath = false;
|
|
609
|
+
for (const node of this.pathing.activePath) {
|
|
610
|
+
if (node.positionStr() == myPositionStr) {
|
|
611
|
+
onPath = true;
|
|
612
|
+
break;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
if (!onPath) {
|
|
616
|
+
console.log('Got off-path somehow');
|
|
617
|
+
this.dispatch(new PathfindDispatch(this.pathing.activePath[this.pathing.activePath.length - 1]));
|
|
618
|
+
this.pathing.followingPath = false;
|
|
619
|
+
this.pathing.activePath = null;
|
|
620
|
+
this.pathing.activeNode = null;
|
|
621
|
+
this.pathing.activeNodeIdx = 0;
|
|
622
|
+
}*/
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
update() {
|
|
626
|
+
if (!this.state.joinedGame) throw new Error('Not playing, can\'t update. ');
|
|
627
|
+
|
|
628
|
+
// process pathfinding
|
|
629
|
+
if (this.pathing.followingPath && this.intents.includes(this.Intents.PATHFINDING)) this.#processPathfinding();
|
|
630
|
+
|
|
631
|
+
// process incoming packets
|
|
632
|
+
while (this._packetQueue.length > 0) this.#handlePacket(this._packetQueue.shift());
|
|
633
|
+
|
|
634
|
+
// process dispatches
|
|
635
|
+
if (this._dispatches.length > 0) {
|
|
636
|
+
for (let i = 0; i < this._dispatches.length; i++) {
|
|
637
|
+
const disp = this._dispatches[i];
|
|
638
|
+
if (disp.check(this)) {
|
|
639
|
+
disp.execute(this);
|
|
640
|
+
this._dispatches.splice(i, 1);
|
|
641
|
+
break; // only 1 dispatch per update
|
|
600
642
|
}
|
|
601
643
|
}
|
|
602
|
-
if (!onPath) {
|
|
603
|
-
console.log('Got off-path somehow');
|
|
604
|
-
this.dispatch(new PathfindDispatch(this.pathing.activePath[this.pathing.activePath.length - 1]));
|
|
605
|
-
this.pathing.followingPath = false;
|
|
606
|
-
this.pathing.activePath = null;
|
|
607
|
-
this.pathing.activeNode = null;
|
|
608
|
-
this.pathing.activeNodeIdx = 0;
|
|
609
|
-
}*/
|
|
610
644
|
}
|
|
611
645
|
|
|
612
|
-
|
|
613
|
-
|
|
646
|
+
// process syncMe
|
|
647
|
+
const now = Date.now();
|
|
648
|
+
if (now - this.lastUpdateTime >= 50) {
|
|
649
|
+
this.emit('tick');
|
|
614
650
|
|
|
615
651
|
// Send out update packet
|
|
616
652
|
const out = CommOut.getBuffer();
|
|
@@ -624,14 +660,16 @@ export class Bot {
|
|
|
624
660
|
out.packRad(this.me.view.pitch); // pitch
|
|
625
661
|
out.packInt8(100); // fixes commcode issues, does nothing
|
|
626
662
|
}
|
|
627
|
-
out.send(this.
|
|
663
|
+
out.send(this.game.socket);
|
|
628
664
|
|
|
629
|
-
this.lastUpdateTime =
|
|
665
|
+
this.lastUpdateTime = now;
|
|
630
666
|
this.state.shotsFired = 0;
|
|
631
667
|
}
|
|
632
668
|
|
|
633
|
-
|
|
634
|
-
|
|
669
|
+
while (this._liveCallbacks.length > 0) {
|
|
670
|
+
const cb = this._liveCallbacks.shift();
|
|
671
|
+
cb();
|
|
672
|
+
}
|
|
635
673
|
}
|
|
636
674
|
|
|
637
675
|
on(event, cb) {
|
|
@@ -646,7 +684,7 @@ export class Bot {
|
|
|
646
684
|
// these are auth-related codes (liveCallbacks doesn't run during auth)
|
|
647
685
|
#mustBeInstant = ['authFail', 'banned'];
|
|
648
686
|
|
|
649
|
-
|
|
687
|
+
emit(event, ...args) {
|
|
650
688
|
if (this._hooks[event]) {
|
|
651
689
|
for (const cb of this._hooks[event]) {
|
|
652
690
|
if (this.#mustBeInstant.includes(event)) cb(...args);
|
|
@@ -664,23 +702,25 @@ export class Bot {
|
|
|
664
702
|
if (!IsBrowser) {
|
|
665
703
|
const { existsSync, mkdirSync, readFileSync, writeFileSync } = await import('node:fs');
|
|
666
704
|
const { join } = await import('node:path');
|
|
705
|
+
const { homedir } = await import('node:os');
|
|
667
706
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
707
|
+
const yolkbotCache = join(homedir(), '.yolkbot');
|
|
708
|
+
const mapCache = join(yolkbotCache, 'maps');
|
|
709
|
+
|
|
710
|
+
if (!existsSync(yolkbotCache)) mkdirSync(yolkbotCache);
|
|
711
|
+
if (!existsSync(mapCache)) mkdirSync(mapCache);
|
|
712
|
+
|
|
713
|
+
const mapFile = join(mapCache, `${name}-${hash}.json`);
|
|
671
714
|
|
|
672
|
-
|
|
715
|
+
if (existsSync(mapFile))
|
|
716
|
+
return JSON.parse(readFileSync(mapFile, 'utf-8'));
|
|
717
|
+
|
|
718
|
+
console.log('map not in cache, IMPORT!!', name, hash);
|
|
673
719
|
|
|
674
720
|
const data = await (await fetch(`https://${this.instance}/maps/${name}.json?${hash}`)).json();
|
|
675
721
|
|
|
676
|
-
|
|
677
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
722
|
+
writeFileSync(mapFile, JSON.stringify(data, null, 4), { flag: 'w+' });
|
|
678
723
|
|
|
679
|
-
writeFileSync(
|
|
680
|
-
join(dir, `${name}-${hash}.json`),
|
|
681
|
-
JSON.stringify(data, null, 4),
|
|
682
|
-
{ flag: 'w+' }
|
|
683
|
-
);
|
|
684
724
|
return data;
|
|
685
725
|
} else {
|
|
686
726
|
const data = await (await fetch(`https://${this.instance}/maps/${name}.json?${hash}`)).json();
|
|
@@ -688,6 +728,64 @@ export class Bot {
|
|
|
688
728
|
}
|
|
689
729
|
}
|
|
690
730
|
|
|
731
|
+
#initKotcZones() {
|
|
732
|
+
const meshData = this.game.map.raw.data['DYNAMIC.capture-zone.none'];
|
|
733
|
+
if (!meshData) return delete this.game.map.zones;
|
|
734
|
+
|
|
735
|
+
let numCaptureZones = 0;
|
|
736
|
+
const mapData = {};
|
|
737
|
+
const zones = [];
|
|
738
|
+
|
|
739
|
+
for (const cell of meshData) {
|
|
740
|
+
if (!mapData[cell.x]) mapData[cell.x] = {};
|
|
741
|
+
if (!mapData[cell.x][cell.y]) mapData[cell.x][cell.y] = {};
|
|
742
|
+
mapData[cell.x][cell.y][cell.z] = { zone: null };
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
const offsets = [
|
|
746
|
+
{ x: -1, z: 0 },
|
|
747
|
+
{ x: 1, z: 0 },
|
|
748
|
+
{ x: 0, z: -1 },
|
|
749
|
+
{ x: 0, z: 1 }
|
|
750
|
+
];
|
|
751
|
+
|
|
752
|
+
function getMapCellAt(x, y, z) {
|
|
753
|
+
return mapData[x] && mapData[x][y] && mapData[x][y][z] ? mapData[x][y][z] : null;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
for (const cellA of meshData) {
|
|
757
|
+
if (!mapData[cellA.x][cellA.y][cellA.z].zone) {
|
|
758
|
+
cellA.zone = ++numCaptureZones;
|
|
759
|
+
mapData[cellA.x][cellA.y][cellA.z].zone = cellA.zone;
|
|
760
|
+
|
|
761
|
+
const currentZone = [cellA];
|
|
762
|
+
let hits;
|
|
763
|
+
|
|
764
|
+
do {
|
|
765
|
+
hits = 0;
|
|
766
|
+
for (const cellB of meshData) {
|
|
767
|
+
if (!mapData[cellB.x][cellB.y][cellB.z].zone) {
|
|
768
|
+
for (const o of offsets) {
|
|
769
|
+
const cell = getMapCellAt(cellB.x + o.x, cellB.y, cellB.z + o.z);
|
|
770
|
+
if (cell && cell.zone == cellA.zone) {
|
|
771
|
+
hits++;
|
|
772
|
+
cellB.zone = cellA.zone;
|
|
773
|
+
mapData[cellB.x][cellB.y][cellB.z].zone = cellA.zone;
|
|
774
|
+
currentZone.push(cellB);
|
|
775
|
+
break;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
} while (hits > 0);
|
|
781
|
+
|
|
782
|
+
zones.push(currentZone);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
this.game.map.zones = zones;
|
|
787
|
+
}
|
|
788
|
+
|
|
691
789
|
#processChatPacket() {
|
|
692
790
|
const id = CommIn.unPackInt8U();
|
|
693
791
|
const msgFlags = CommIn.unPackInt8U();
|
|
@@ -695,7 +793,7 @@ export class Bot {
|
|
|
695
793
|
const player = this.players[Object.keys(this.players).find(p => this.players[p].id == id)];
|
|
696
794
|
// console.log(`Player ${player.name}: ${text} (flags: ${msgFlags})`);
|
|
697
795
|
// console.log(`Their position: ${player.position.x}, ${player.position.y}, ${player.position.z}`);
|
|
698
|
-
this
|
|
796
|
+
this.emit('chat', player, text, msgFlags);
|
|
699
797
|
}
|
|
700
798
|
|
|
701
799
|
#processAddPlayerPacket() {
|
|
@@ -704,6 +802,7 @@ export class Bot {
|
|
|
704
802
|
const name = CommIn.unPackString();
|
|
705
803
|
const safename = CommIn.unPackString(); // ??? (a)
|
|
706
804
|
const charClass = CommIn.unPackInt8U();
|
|
805
|
+
const findCosmetics = this.intents.includes(this.Intents.COSMETIC_DATA);
|
|
707
806
|
const playerData = {
|
|
708
807
|
id_: id_,
|
|
709
808
|
uniqueId_: uniqueId,
|
|
@@ -712,14 +811,14 @@ export class Bot {
|
|
|
712
811
|
charClass_: charClass,
|
|
713
812
|
team_: CommIn.unPackInt8U(),
|
|
714
813
|
primaryWeaponItem_: findItemById(CommIn.unPackInt16U()),
|
|
715
|
-
secondaryWeaponItem_: findItemById(CommIn.unPackInt16U())
|
|
814
|
+
secondaryWeaponItem_: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
|
|
716
815
|
shellColor_: CommIn.unPackInt8U(),
|
|
717
|
-
hatItem_: findItemById(CommIn.unPackInt16U()),
|
|
718
|
-
stampItem_: findItemById(CommIn.unPackInt16U()),
|
|
816
|
+
hatItem_: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
|
|
817
|
+
stampItem_: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
|
|
719
818
|
unknownInt8: CommIn.unPackInt8(), // c
|
|
720
819
|
otherUnknownInt8: CommIn.unPackInt8(),
|
|
721
|
-
grenadeItem_: findItemById(CommIn.unPackInt16U()),
|
|
722
|
-
meleeItem_: findItemById(CommIn.unPackInt16U()),
|
|
820
|
+
grenadeItem_: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
|
|
821
|
+
meleeItem_: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
|
|
723
822
|
x_: CommIn.unPackFloat(),
|
|
724
823
|
y_: CommIn.unPackFloat(),
|
|
725
824
|
z_: CommIn.unPackFloat(),
|
|
@@ -752,36 +851,14 @@ export class Bot {
|
|
|
752
851
|
playerData.gameData_.private = CommIn.unPackInt8U();
|
|
753
852
|
playerData.gameData_.gameType = CommIn.unPackInt8U();
|
|
754
853
|
|
|
755
|
-
if (!this.players[playerData.id_])
|
|
854
|
+
if (!this.players[playerData.id_])
|
|
756
855
|
this.players[playerData.id_] = new GamePlayer(playerData.id_, playerData.team_, playerData);
|
|
757
856
|
|
|
758
|
-
const player = this.players[playerData.id_];
|
|
759
|
-
|
|
760
|
-
if (player.playing) {
|
|
761
|
-
player.healthInterval = setInterval(() => {
|
|
762
|
-
if (player.hp < 1) return;
|
|
763
|
-
|
|
764
|
-
const regenSpeed = 0.1 * (this.game.isPrivate ? this.game.options.healthRegen : 1);
|
|
765
|
-
|
|
766
|
-
if (player.streakRewards.includes(ShellStreaks.OverHeal)) {
|
|
767
|
-
player.hp = Math.max(100, player.hp - regenSpeed);
|
|
768
|
-
} else {
|
|
769
|
-
player.hp = Math.min(100, player.hp + regenSpeed);
|
|
770
|
-
}
|
|
771
|
-
}, 33);
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
|
|
775
857
|
if (this.me.id == playerData.id_) {
|
|
776
858
|
this.me = this.players[playerData.id_];
|
|
777
859
|
}
|
|
778
860
|
|
|
779
|
-
this
|
|
780
|
-
|
|
781
|
-
const unp = CommIn.unPackInt8U();
|
|
782
|
-
if (unp == CommCode.addPlayer) { // there is another player stacked
|
|
783
|
-
this.#processAddPlayerPacket();
|
|
784
|
-
}
|
|
861
|
+
this.emit('playerJoin', this.players[playerData.id_]);
|
|
785
862
|
}
|
|
786
863
|
|
|
787
864
|
#processRespawnPacket() {
|
|
@@ -808,29 +885,13 @@ export class Bot {
|
|
|
808
885
|
player.grenades = grenades;
|
|
809
886
|
player.position = { x: x, y: y, z: z };
|
|
810
887
|
// console.log(`Player ${player.name} respawned at ${x}, ${y}, ${z}`);
|
|
811
|
-
this
|
|
812
|
-
|
|
813
|
-
if (player.healthInterval) {
|
|
814
|
-
clearInterval(player.healthInterval);
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
player.healthInterval = setInterval(() => {
|
|
818
|
-
if (player.hp < 1) return;
|
|
819
|
-
|
|
820
|
-
const regenSpeed = 0.1 * (this.game.isPrivate ? this.game.options[GameOptionFlags.healthRegen] : 1);
|
|
821
|
-
|
|
822
|
-
if (player.streakRewards.includes(ShellStreaks.OverHeal)) {
|
|
823
|
-
player.hp = Math.max(100, player.hp - regenSpeed);
|
|
824
|
-
} else {
|
|
825
|
-
player.hp = Math.min(100, player.hp + regenSpeed);
|
|
826
|
-
}
|
|
827
|
-
}, 33);
|
|
888
|
+
this.emit('playerRespawn', player);
|
|
828
889
|
} else {
|
|
829
890
|
// console.log(`Player ${id} not found. (me: ${this.me.id}) (respawn)`);
|
|
830
891
|
}
|
|
831
892
|
}
|
|
832
893
|
|
|
833
|
-
#
|
|
894
|
+
#processSyncThemPacket() {
|
|
834
895
|
const id = CommIn.unPackInt8U();
|
|
835
896
|
const x = CommIn.unPackFloat();
|
|
836
897
|
const y = CommIn.unPackFloat();
|
|
@@ -838,37 +899,53 @@ export class Bot {
|
|
|
838
899
|
const climbing = CommIn.unPackInt8U();
|
|
839
900
|
|
|
840
901
|
const player = this.players[id];
|
|
841
|
-
if (!player
|
|
902
|
+
if (!player) return;
|
|
842
903
|
|
|
843
|
-
if (player.
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
904
|
+
if (player.position.x !== x) player.position.x = x;
|
|
905
|
+
if (player.position.z !== z) player.position.z = z;
|
|
906
|
+
|
|
907
|
+
if (!player.jumping || Math.abs(player.position.y - y) > 0.5 && player.position.y !== y)
|
|
908
|
+
player.position.y = y;
|
|
909
|
+
|
|
910
|
+
if (player.climbing !== climbing) player.climbing = climbing;
|
|
911
|
+
|
|
912
|
+
if (this.intents.includes(this.Intents.BUFFERS)) {
|
|
913
|
+
if (!player.buffer) return;
|
|
914
|
+
|
|
915
|
+
if (player.id == this.me.id) {
|
|
916
|
+
for (let i2 = 0; i2 < 3 /* FramesBetweenSyncs */; i2++) {
|
|
917
|
+
CommIn.unPackInt8U();
|
|
918
|
+
CommIn.unPackRadU();
|
|
919
|
+
CommIn.unPackRad();
|
|
920
|
+
CommIn.unPackInt8U();
|
|
921
|
+
}
|
|
922
|
+
return;
|
|
848
923
|
}
|
|
849
|
-
}
|
|
850
924
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
yaw = CommIn.unPackRadU();
|
|
855
|
-
if (!isNaN(yaw)) { player.buffer[i2].yaw_ = yaw }
|
|
856
|
-
pitch = CommIn.unPackRad();
|
|
857
|
-
if (!isNaN(pitch)) { player.buffer[i2].pitch_ = pitch }
|
|
858
|
-
}
|
|
925
|
+
let yaw, pitch;
|
|
926
|
+
for (let i2 = 0; i2 < 3; i2++) {
|
|
927
|
+
player.buffer[i2].controlKeys = CommIn.unPackInt8U();
|
|
859
928
|
|
|
860
|
-
|
|
929
|
+
yaw = CommIn.unPackRadU();
|
|
930
|
+
if (!isNaN(yaw)) player.buffer[i2].yaw_ = yaw
|
|
861
931
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
932
|
+
pitch = CommIn.unPackRad();
|
|
933
|
+
if (!isNaN(pitch)) player.buffer[i2].pitch_ = pitch
|
|
934
|
+
|
|
935
|
+
CommIn.unPackInt8U();
|
|
936
|
+
}
|
|
865
937
|
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
938
|
+
player.buffer[0].x = x;
|
|
939
|
+
player.buffer[0].y = y;
|
|
940
|
+
player.buffer[0].z = z;
|
|
941
|
+
} else {
|
|
942
|
+
for (let i2 = 0; i2 < 3; i2++) {
|
|
943
|
+
CommIn.unPackInt8U();
|
|
944
|
+
CommIn.unPackRadU();
|
|
945
|
+
CommIn.unPackRad();
|
|
946
|
+
CommIn.unPackInt8U();
|
|
947
|
+
}
|
|
948
|
+
}
|
|
872
949
|
}
|
|
873
950
|
|
|
874
951
|
#processPausePacket() {
|
|
@@ -876,7 +953,7 @@ export class Bot {
|
|
|
876
953
|
const player = this.players[id];
|
|
877
954
|
if (player) {
|
|
878
955
|
player.playing = false;
|
|
879
|
-
this
|
|
956
|
+
this.emit('playerPause', player);
|
|
880
957
|
}
|
|
881
958
|
}
|
|
882
959
|
|
|
@@ -887,23 +964,21 @@ export class Bot {
|
|
|
887
964
|
const player = this.players[id];
|
|
888
965
|
if (player) {
|
|
889
966
|
player.activeGun = newWeaponId;
|
|
890
|
-
this
|
|
967
|
+
this.emit('playerSwapWeapon', player, newWeaponId);
|
|
891
968
|
}
|
|
892
969
|
}
|
|
893
970
|
|
|
894
971
|
#processDeathPacket() {
|
|
895
972
|
const killedId = CommIn.unPackInt8U();
|
|
896
973
|
const byId = CommIn.unPackInt8U();
|
|
897
|
-
|
|
974
|
+
|
|
975
|
+
CommIn.unPackInt8U();
|
|
976
|
+
CommIn.unPackInt8U();
|
|
977
|
+
CommIn.unPackInt8U();
|
|
898
978
|
|
|
899
979
|
const killed = this.players[killedId];
|
|
900
980
|
const killer = this.players[byId];
|
|
901
981
|
|
|
902
|
-
/*
|
|
903
|
-
const killerLastDmg = CommIn.unPackInt8U();
|
|
904
|
-
const killedLastDmg = CommIn.unPackInt8U();
|
|
905
|
-
*/
|
|
906
|
-
|
|
907
982
|
if (killed) {
|
|
908
983
|
killed.playing = false;
|
|
909
984
|
killed.kills = 0;
|
|
@@ -914,18 +989,21 @@ export class Bot {
|
|
|
914
989
|
if (killer) { killer.kills++; }
|
|
915
990
|
// console.log(`Player ${killer.name} is on a streak of ${killer.kills} kills.`);
|
|
916
991
|
|
|
917
|
-
this
|
|
992
|
+
this.emit('playerDeath', killed, killer); // killed, killer
|
|
918
993
|
}
|
|
919
994
|
|
|
920
995
|
#processFirePacket() {
|
|
921
996
|
const id = CommIn.unPackInt8U();
|
|
922
997
|
|
|
998
|
+
for (let i = 0; i < 6; i++)
|
|
999
|
+
CommIn.unPackFloat();
|
|
1000
|
+
|
|
923
1001
|
const player = this.players[id];
|
|
924
1002
|
const playerWeapon = player.weapons[player.activeGun];
|
|
925
1003
|
|
|
926
1004
|
if (playerWeapon && playerWeapon.ammo) {
|
|
927
1005
|
playerWeapon.ammo.rounds--;
|
|
928
|
-
this
|
|
1006
|
+
this.emit('playerFire', player, playerWeapon);
|
|
929
1007
|
}
|
|
930
1008
|
}
|
|
931
1009
|
|
|
@@ -938,7 +1016,7 @@ export class Bot {
|
|
|
938
1016
|
|
|
939
1017
|
this.game.collectables[type].push({ id, x, y, z });
|
|
940
1018
|
|
|
941
|
-
this
|
|
1019
|
+
this.emit('spawnItem', type, id, { x, y, z });
|
|
942
1020
|
}
|
|
943
1021
|
|
|
944
1022
|
#processCollectPacket() {
|
|
@@ -955,13 +1033,15 @@ export class Bot {
|
|
|
955
1033
|
const playerWeapon = player.weapons[applyToWeaponIdx];
|
|
956
1034
|
if (playerWeapon && playerWeapon.ammo) {
|
|
957
1035
|
playerWeapon.ammo.store = Math.min(playerWeapon.ammo.storeMax, playerWeapon.ammo.store + playerWeapon.ammo.pickup);
|
|
958
|
-
this
|
|
1036
|
+
this.emit('collectAmmo', player, playerWeapon);
|
|
959
1037
|
}
|
|
960
1038
|
}
|
|
961
1039
|
|
|
962
1040
|
if (type == CollectTypes.GRENADE) {
|
|
963
|
-
player.grenades
|
|
964
|
-
|
|
1041
|
+
player.grenades++;
|
|
1042
|
+
if (player.grenades > 3) player.grenades = 3
|
|
1043
|
+
|
|
1044
|
+
this.emit('collectGrenade', player);
|
|
965
1045
|
}
|
|
966
1046
|
}
|
|
967
1047
|
|
|
@@ -975,16 +1055,19 @@ export class Bot {
|
|
|
975
1055
|
const oldHP = player.hp;
|
|
976
1056
|
player.hp = hp;
|
|
977
1057
|
|
|
978
|
-
this
|
|
1058
|
+
this.emit('playerDamaged', player, oldHP, player.hp);
|
|
979
1059
|
}
|
|
980
1060
|
|
|
981
1061
|
#processHitMePacket() {
|
|
982
1062
|
const hp = CommIn.unPackInt8U();
|
|
983
|
-
const oldHp = this.me.hp;
|
|
984
1063
|
|
|
1064
|
+
CommIn.unPackFloat();
|
|
1065
|
+
CommIn.unPackFloat();
|
|
1066
|
+
|
|
1067
|
+
const oldHp = this.me.hp;
|
|
985
1068
|
this.me.hp = hp;
|
|
986
1069
|
|
|
987
|
-
this
|
|
1070
|
+
this.emit('selfDamaged', oldHp, this.me.hp);
|
|
988
1071
|
}
|
|
989
1072
|
|
|
990
1073
|
#processSyncMePacket() {
|
|
@@ -1001,6 +1084,10 @@ export class Bot {
|
|
|
1001
1084
|
const newY = CommIn.unPackFloat();
|
|
1002
1085
|
const newZ = CommIn.unPackFloat();
|
|
1003
1086
|
|
|
1087
|
+
CommIn.unPackInt8U();
|
|
1088
|
+
CommIn.unPackInt8U();
|
|
1089
|
+
CommIn.unPackInt8U();
|
|
1090
|
+
|
|
1004
1091
|
const oldX = player.position.x;
|
|
1005
1092
|
const oldY = player.position.y;
|
|
1006
1093
|
const oldZ = player.position.z;
|
|
@@ -1010,14 +1097,14 @@ export class Bot {
|
|
|
1010
1097
|
player.position.z = newZ;
|
|
1011
1098
|
|
|
1012
1099
|
if (oldX != newX || oldY != newY || oldZ != newZ) {
|
|
1013
|
-
this
|
|
1100
|
+
this.emit('selfMoved', player, { x: oldX, y: oldY, z: oldZ }, { x: newX, y: newY, z: newZ });
|
|
1014
1101
|
}
|
|
1015
1102
|
}
|
|
1016
1103
|
|
|
1017
1104
|
#processEventModifierPacket() {
|
|
1018
1105
|
const out = CommOut.getBuffer();
|
|
1019
1106
|
out.packInt8(CommCode.eventModifier);
|
|
1020
|
-
out.send(this.
|
|
1107
|
+
out.send(this.game.socket);
|
|
1021
1108
|
}
|
|
1022
1109
|
|
|
1023
1110
|
#processRemovePlayerPacket() {
|
|
@@ -1026,7 +1113,7 @@ export class Bot {
|
|
|
1026
1113
|
|
|
1027
1114
|
delete this.players[id.toString()];
|
|
1028
1115
|
|
|
1029
|
-
this
|
|
1116
|
+
this.emit('playerLeave', removedPlayer);
|
|
1030
1117
|
}
|
|
1031
1118
|
|
|
1032
1119
|
#processGameStatePacket() {
|
|
@@ -1049,10 +1136,10 @@ export class Bot {
|
|
|
1049
1136
|
controlledByTeam: controlledByTeam
|
|
1050
1137
|
};
|
|
1051
1138
|
|
|
1052
|
-
this
|
|
1139
|
+
this.emit('gameStateChange', this.game);
|
|
1053
1140
|
} else if (this.game.gameModeId == GameModes.kotc) {
|
|
1054
1141
|
this.game.stage = CommIn.unPackInt8U(); // constants.CoopStates
|
|
1055
|
-
this.game.
|
|
1142
|
+
this.game.zoneNumber = CommIn.unPackInt8U(); // a number to represent which 'active zone' kotc is using
|
|
1056
1143
|
this.game.capturing = CommIn.unPackInt8U(); // the team capturing, named "teams" in shell src
|
|
1057
1144
|
this.game.captureProgress = CommIn.unPackInt16U(); // progress of the coop capture
|
|
1058
1145
|
this.game.numCapturing = CommIn.unPackInt8U(); // number of players capturing - number/1000
|
|
@@ -1062,8 +1149,12 @@ export class Bot {
|
|
|
1062
1149
|
// not in shell, for utility purposes =D
|
|
1063
1150
|
this.game.stageName = CoopStagesById[this.game.stage]; // name of the stage ('start' / 'capturing' / 'etc')
|
|
1064
1151
|
this.game.capturePercent = this.game.captureProgress / 1000; // progress of the capture as a percentage
|
|
1152
|
+
this.game.activeZone = this.game.map.zones ? this.game.map.zones[this.game.zoneNumber - 1] : null;
|
|
1065
1153
|
|
|
1066
|
-
this
|
|
1154
|
+
this.emit('gameStateChange', this.game);
|
|
1155
|
+
} else if (this.game.gameModeId == GameModes.team) {
|
|
1156
|
+
this.game.teamScore[1] = CommIn.unPackInt16U();
|
|
1157
|
+
this.game.teamScore[2] = CommIn.unPackInt16U();
|
|
1067
1158
|
}
|
|
1068
1159
|
|
|
1069
1160
|
if (this.game.gameModeId !== GameModes.spatula) {
|
|
@@ -1072,13 +1163,16 @@ export class Bot {
|
|
|
1072
1163
|
|
|
1073
1164
|
if (this.game.gameModeId !== GameModes.kotc) {
|
|
1074
1165
|
delete this.game.stage;
|
|
1075
|
-
delete this.game.
|
|
1166
|
+
delete this.game.zoneNumber;
|
|
1076
1167
|
delete this.game.capturing;
|
|
1077
1168
|
delete this.game.captureProgress;
|
|
1078
|
-
delete this.game.numCapturing
|
|
1169
|
+
delete this.game.numCapturing;
|
|
1170
|
+
delete this.game.stageName;
|
|
1171
|
+
delete this.game.numCapturing;
|
|
1172
|
+
delete this.game.activeZone;
|
|
1079
1173
|
}
|
|
1080
1174
|
|
|
1081
|
-
if (this.game.gameModeId
|
|
1175
|
+
if (this.game.gameModeId == GameModes.ffa) {
|
|
1082
1176
|
delete this.game.teamScore;
|
|
1083
1177
|
}
|
|
1084
1178
|
}
|
|
@@ -1129,7 +1223,7 @@ export class Bot {
|
|
|
1129
1223
|
break;
|
|
1130
1224
|
}
|
|
1131
1225
|
|
|
1132
|
-
this
|
|
1226
|
+
this.emit('playerBeginStreak', player, ksType);
|
|
1133
1227
|
}
|
|
1134
1228
|
|
|
1135
1229
|
#processEndStreakPacket() {
|
|
@@ -1148,21 +1242,24 @@ export class Bot {
|
|
|
1148
1242
|
player.streakRewards = player.streakRewards.filter((r) => r != ksType);
|
|
1149
1243
|
}
|
|
1150
1244
|
|
|
1151
|
-
this
|
|
1245
|
+
this.emit('playerEndStreak', ksType, player);
|
|
1152
1246
|
}
|
|
1153
1247
|
|
|
1154
1248
|
#processHitShieldPacket() {
|
|
1155
1249
|
const hb = CommIn.unPackInt8U();
|
|
1156
1250
|
const hp = CommIn.unPackInt8U();
|
|
1157
1251
|
|
|
1252
|
+
CommIn.unPackFloat();
|
|
1253
|
+
CommIn.unPackFloat();
|
|
1254
|
+
|
|
1158
1255
|
this.me.hpShield = hb;
|
|
1159
1256
|
this.me.hp = hp;
|
|
1160
1257
|
|
|
1161
1258
|
if (this.me.hpShield <= 0) {
|
|
1162
1259
|
this.me.streakRewards = this.me.streakRewards.filter((r) => r != ShellStreaks.HardBoiled);
|
|
1163
|
-
this
|
|
1260
|
+
this.emit('selfShieldLost');
|
|
1164
1261
|
} else {
|
|
1165
|
-
this
|
|
1262
|
+
this.emit('selfShieldHit', this.me.hpShield);
|
|
1166
1263
|
}
|
|
1167
1264
|
}
|
|
1168
1265
|
|
|
@@ -1191,7 +1288,7 @@ export class Bot {
|
|
|
1191
1288
|
this.game.options.weaponsDisabled = Array.from({ length: 7 }, () => CommIn.unPackInt8U() === 1);
|
|
1192
1289
|
this.game.options.mustUseSecondary = this.game.options.weaponsDisabled.every((v) => v);
|
|
1193
1290
|
|
|
1194
|
-
this
|
|
1291
|
+
this.emit('gameOptionsChange', oldOptions, this.game.options);
|
|
1195
1292
|
return false;
|
|
1196
1293
|
}
|
|
1197
1294
|
|
|
@@ -1200,7 +1297,7 @@ export class Bot {
|
|
|
1200
1297
|
|
|
1201
1298
|
if (action == GameActions.pause) {
|
|
1202
1299
|
// console.log('settings changed, gameOwner changed game settings, force paused');
|
|
1203
|
-
this
|
|
1300
|
+
this.emit('gameForcePause');
|
|
1204
1301
|
setTimeout(() => this.me.playing = false, 3000);
|
|
1205
1302
|
}
|
|
1206
1303
|
|
|
@@ -1208,35 +1305,43 @@ export class Bot {
|
|
|
1208
1305
|
// console.log('owner reset game');
|
|
1209
1306
|
|
|
1210
1307
|
this.me.kills = 0;
|
|
1211
|
-
this.game.teamScore = [0, 0, 0];
|
|
1212
1308
|
|
|
1213
|
-
this.game.
|
|
1214
|
-
this.game.spatula.controlledByTeam = 0;
|
|
1215
|
-
this.game.spatula.coords = { x: 0, y: 0, z: 0 };
|
|
1309
|
+
if (this.game.gameModeId !== GameModes.ffa) this.game.teamScore = [0, 0, 0];
|
|
1216
1310
|
|
|
1217
|
-
this.game.
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
this.game.
|
|
1311
|
+
if (this.game.gameModeId === GameModes.spatula) {
|
|
1312
|
+
this.game.spatula.controlledBy = 0;
|
|
1313
|
+
this.game.spatula.controlledByTeam = 0;
|
|
1314
|
+
this.game.spatula.coords = { x: 0, y: 0, z: 0 };
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
if (this.game.gameModeId === GameModes.kotc) {
|
|
1318
|
+
this.game.stage = CoopStates.capturing;
|
|
1319
|
+
this.game.zoneNumber = 0;
|
|
1320
|
+
this.game.activeZone = null;
|
|
1321
|
+
this.game.capturing = 0;
|
|
1322
|
+
this.game.captureProgress = 0;
|
|
1323
|
+
this.game.numCapturing = 0;
|
|
1324
|
+
this.game.stageName = CoopStagesById[CoopStates.capturing];
|
|
1325
|
+
this.game.capturePercent = 0.0;
|
|
1326
|
+
}
|
|
1224
1327
|
|
|
1225
|
-
this
|
|
1328
|
+
this.emit('gameReset');
|
|
1226
1329
|
}
|
|
1227
1330
|
}
|
|
1228
1331
|
|
|
1229
1332
|
#processPingPacket() {
|
|
1333
|
+
if (!this.intents.includes(this.Intents.PING)) return;
|
|
1334
|
+
|
|
1230
1335
|
const oldPing = this.ping;
|
|
1231
1336
|
|
|
1232
1337
|
this.ping = Date.now() - this.lastPingTime;
|
|
1233
1338
|
|
|
1234
|
-
this
|
|
1339
|
+
this.emit('pingUpdate', oldPing, this.ping);
|
|
1235
1340
|
|
|
1236
1341
|
setTimeout(() => {
|
|
1237
1342
|
const out = CommOut.getBuffer();
|
|
1238
1343
|
out.packInt8(CommCode.ping);
|
|
1239
|
-
out.send(this.
|
|
1344
|
+
out.send(this.game.socket);
|
|
1240
1345
|
this.lastPingTime = Date.now();
|
|
1241
1346
|
}, this.pingInterval);
|
|
1242
1347
|
}
|
|
@@ -1253,7 +1358,7 @@ export class Bot {
|
|
|
1253
1358
|
player.team = toTeam;
|
|
1254
1359
|
player.kills = 0;
|
|
1255
1360
|
|
|
1256
|
-
this
|
|
1361
|
+
this.emit('playerSwitchTeam', player, oldTeam, toTeam);
|
|
1257
1362
|
}
|
|
1258
1363
|
|
|
1259
1364
|
#processChangeCharacterPacket() {
|
|
@@ -1268,12 +1373,18 @@ export class Bot {
|
|
|
1268
1373
|
const grenadeIdx = CommIn.unPackInt16U();
|
|
1269
1374
|
const meleeIdx = CommIn.unPackInt16U();
|
|
1270
1375
|
|
|
1376
|
+
CommIn.unPackInt8();
|
|
1377
|
+
CommIn.unPackInt8();
|
|
1378
|
+
|
|
1379
|
+
const findCosmetics = this.intents.includes(this.Intents.COSMETIC_DATA);
|
|
1380
|
+
|
|
1271
1381
|
const primaryWeaponItem = findItemById(primaryWeaponIdx);
|
|
1272
|
-
|
|
1273
|
-
const
|
|
1274
|
-
const
|
|
1275
|
-
const
|
|
1276
|
-
const
|
|
1382
|
+
|
|
1383
|
+
const secondaryWeaponItem = findCosmetics ? findItemById(secondaryWeaponIdx) : secondaryWeaponIdx;
|
|
1384
|
+
const hatItem = findCosmetics ? findItemById(hatIdx) : hatIdx;
|
|
1385
|
+
const stampItem = findCosmetics ? findItemById(stampIdx) : stampIdx;
|
|
1386
|
+
const grenadeItem = findCosmetics ? findItemById(grenadeIdx) : grenadeIdx;
|
|
1387
|
+
const meleeItem = findCosmetics ? findItemById(meleeIdx) : meleeIdx;
|
|
1277
1388
|
|
|
1278
1389
|
const player = this.players[id];
|
|
1279
1390
|
if (player) {
|
|
@@ -1291,8 +1402,8 @@ export class Bot {
|
|
|
1291
1402
|
player.selectedGun = weaponIndex;
|
|
1292
1403
|
player.weapons[0] = new GunList[weaponIndex]();
|
|
1293
1404
|
|
|
1294
|
-
if (oldWeaponIdx !== player.selectedGun) this
|
|
1295
|
-
if (oldCharacter !== player.character) this
|
|
1405
|
+
if (oldWeaponIdx !== player.selectedGun) this.emit('playerChangeGun', player, oldWeaponIdx, player.selectedGun);
|
|
1406
|
+
if (oldCharacter !== player.character) this.emit('playerChangeCharacter', player, oldCharacter, player.character);
|
|
1296
1407
|
}
|
|
1297
1408
|
}
|
|
1298
1409
|
|
|
@@ -1301,27 +1412,23 @@ export class Bot {
|
|
|
1301
1412
|
const oldBalance = this.account.eggBalance;
|
|
1302
1413
|
|
|
1303
1414
|
this.account.eggBalance = newBalance;
|
|
1304
|
-
this
|
|
1415
|
+
this.emit('balanceUpdate', newBalance - oldBalance, newBalance);
|
|
1305
1416
|
}
|
|
1306
1417
|
|
|
1307
1418
|
#processRespawnDeniedPacket() {
|
|
1308
1419
|
this.me.playing = false;
|
|
1309
|
-
this
|
|
1420
|
+
this.emit('selfRespawnFail');
|
|
1310
1421
|
}
|
|
1311
1422
|
|
|
1312
1423
|
#processMeleePacket() {
|
|
1313
1424
|
const id = CommIn.unPackInt8U();
|
|
1314
1425
|
const player = this.players[id];
|
|
1315
1426
|
|
|
1316
|
-
if (player) this
|
|
1427
|
+
if (player) this.emit('playerMelee', player);
|
|
1317
1428
|
}
|
|
1318
1429
|
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
if (!iUnderstandThisIsForInternalUseOnlyAndIShouldNotBeCallingThis)
|
|
1322
|
-
throw new Error('processReloadPacket is exposed for internal use only. do not call it.');
|
|
1323
|
-
|
|
1324
|
-
const id = customPlayer || CommIn.unPackInt8U();
|
|
1430
|
+
#processReloadPacket() {
|
|
1431
|
+
const id = CommIn.unPackInt8U();
|
|
1325
1432
|
const player = this.players[id];
|
|
1326
1433
|
|
|
1327
1434
|
if (!player) return;
|
|
@@ -1338,142 +1445,444 @@ export class Bot {
|
|
|
1338
1445
|
playerActiveWeapon.ammo.store -= newRounds;
|
|
1339
1446
|
}
|
|
1340
1447
|
|
|
1341
|
-
this
|
|
1448
|
+
this.emit('playerReload', player, playerActiveWeapon);
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
#processGameRequestOptionsPacket() {
|
|
1452
|
+
const out = CommOut.getBuffer();
|
|
1453
|
+
out.packInt8(CommCode.gameOptions);
|
|
1454
|
+
out.packInt8(this.game.options.gravity * 4);
|
|
1455
|
+
out.packInt8(this.game.options.damage * 4);
|
|
1456
|
+
out.packInt8(this.game.options.healthRegen * 4);
|
|
1457
|
+
|
|
1458
|
+
const flags =
|
|
1459
|
+
(this.game.options.locked ? 1 : 0) |
|
|
1460
|
+
(this.game.options.noTeamChange ? 2 : 0) |
|
|
1461
|
+
(this.game.options.noTeamShuffle ? 4 : 0);
|
|
1462
|
+
|
|
1463
|
+
out.packInt8(flags);
|
|
1464
|
+
|
|
1465
|
+
this.game.options.weaponsDisabled.forEach((v) => {
|
|
1466
|
+
out.packInt8(v ? 1 : 0);
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
#processExplodePacket() {
|
|
1471
|
+
const itemType = CommIn.unPackInt8U();
|
|
1472
|
+
let item = CommIn.unPackInt16U();
|
|
1473
|
+
const x = CommIn.unPackFloat();
|
|
1474
|
+
const y = CommIn.unPackFloat();
|
|
1475
|
+
const z = CommIn.unPackFloat();
|
|
1476
|
+
const damage = CommIn.unPackInt8U();
|
|
1477
|
+
const radius = CommIn.unPackFloat();
|
|
1478
|
+
|
|
1479
|
+
if (this.intents.includes(this.Intents.COSMETIC_DATA))
|
|
1480
|
+
item = findItemById(item);
|
|
1481
|
+
|
|
1482
|
+
if (itemType == ItemTypes.Grenade) this.emit('grenadeExploded', item, { x, y, z }, damage, radius);
|
|
1483
|
+
else this.emit('rocketHit', { x, y, z }, damage, radius);
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
#processThrowGrenadePacket() {
|
|
1487
|
+
const id = CommIn.unPackInt8U();
|
|
1488
|
+
const x = CommIn.unPackFloat();
|
|
1489
|
+
const y = CommIn.unPackFloat();
|
|
1490
|
+
const z = CommIn.unPackFloat();
|
|
1491
|
+
const dx = CommIn.unPackFloat();
|
|
1492
|
+
const dy = CommIn.unPackFloat();
|
|
1493
|
+
const dz = CommIn.unPackFloat();
|
|
1494
|
+
|
|
1495
|
+
const player = this.players[id];
|
|
1496
|
+
|
|
1497
|
+
if (player) {
|
|
1498
|
+
player.grenades--;
|
|
1499
|
+
this.emit('playerThrowGrenade', player, { x, y, z }, { x: dx, y: dy, z: dz });
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
#processChallengeCompletePacket() {
|
|
1504
|
+
const id = CommIn.unPackInt8U();
|
|
1505
|
+
const challengeId = CommIn.unPackInt8U();
|
|
1506
|
+
|
|
1507
|
+
const player = this.players[id];
|
|
1508
|
+
if (!player) return;
|
|
1509
|
+
|
|
1510
|
+
if (!this.intents.includes(this.Intents.CHALLENGES))
|
|
1511
|
+
return this.emit('challengeComplete', player, challengeId);
|
|
1512
|
+
|
|
1513
|
+
const challenge = this.account.challenges.find(c => c.id == challengeId);
|
|
1514
|
+
this.emit('challengeComplete', player, challenge);
|
|
1515
|
+
|
|
1516
|
+
if (player.id == this.me.id) this.refreshChallenges();
|
|
1342
1517
|
}
|
|
1343
1518
|
|
|
1344
1519
|
#handlePacket(packet) {
|
|
1345
1520
|
CommIn.init(packet);
|
|
1346
|
-
this.#emit('packet', packet);
|
|
1347
|
-
const cmd = CommIn.unPackInt8U();
|
|
1348
|
-
switch (cmd) {
|
|
1349
|
-
case CommCode.chat:
|
|
1350
|
-
this.#processChatPacket(packet);
|
|
1351
|
-
break;
|
|
1352
1521
|
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
break;
|
|
1522
|
+
if (this.intents.includes(this.Intents.PACKET_HOOK))
|
|
1523
|
+
this.emit('packet', packet);
|
|
1356
1524
|
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
break;
|
|
1525
|
+
let lastCommand = 0;
|
|
1526
|
+
let abort = false;
|
|
1360
1527
|
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
break;
|
|
1528
|
+
while (CommIn.isMoreDataAvailable() && !abort) {
|
|
1529
|
+
const cmd = CommIn.unPackInt8U();
|
|
1364
1530
|
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1531
|
+
switch (cmd) {
|
|
1532
|
+
case CommCode.syncThem:
|
|
1533
|
+
this.#processSyncThemPacket();
|
|
1534
|
+
break;
|
|
1368
1535
|
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1536
|
+
case CommCode.fire:
|
|
1537
|
+
this.#processFirePacket();
|
|
1538
|
+
break;
|
|
1372
1539
|
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1540
|
+
case CommCode.hitThem:
|
|
1541
|
+
this.#processHitThemPacket();
|
|
1542
|
+
break;
|
|
1376
1543
|
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1544
|
+
case CommCode.syncMe:
|
|
1545
|
+
this.#processSyncMePacket();
|
|
1546
|
+
break;
|
|
1380
1547
|
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1548
|
+
case CommCode.hitMe:
|
|
1549
|
+
this.#processHitMePacket();
|
|
1550
|
+
break;
|
|
1384
1551
|
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1552
|
+
case CommCode.swapWeapon:
|
|
1553
|
+
this.#processSwapWeaponPacket();
|
|
1554
|
+
break;
|
|
1388
1555
|
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1556
|
+
case CommCode.collectItem:
|
|
1557
|
+
this.#processCollectPacket();
|
|
1558
|
+
break;
|
|
1392
1559
|
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1560
|
+
case CommCode.respawn:
|
|
1561
|
+
this.#processRespawnPacket();
|
|
1562
|
+
break;
|
|
1396
1563
|
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1564
|
+
case CommCode.die:
|
|
1565
|
+
this.#processDeathPacket();
|
|
1566
|
+
break;
|
|
1400
1567
|
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1568
|
+
case CommCode.pause:
|
|
1569
|
+
this.#processPausePacket();
|
|
1570
|
+
break;
|
|
1404
1571
|
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1572
|
+
case CommCode.chat:
|
|
1573
|
+
this.#processChatPacket();
|
|
1574
|
+
break;
|
|
1408
1575
|
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1576
|
+
case CommCode.addPlayer:
|
|
1577
|
+
this.#processAddPlayerPacket();
|
|
1578
|
+
break;
|
|
1412
1579
|
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1580
|
+
case CommCode.removePlayer:
|
|
1581
|
+
this.#processRemovePlayerPacket();
|
|
1582
|
+
break;
|
|
1416
1583
|
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1584
|
+
case CommCode.eventModifier:
|
|
1585
|
+
this.#processEventModifierPacket();
|
|
1586
|
+
break;
|
|
1420
1587
|
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1588
|
+
case CommCode.metaGameState:
|
|
1589
|
+
this.#processGameStatePacket();
|
|
1590
|
+
break;
|
|
1424
1591
|
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1592
|
+
case CommCode.beginShellStreak:
|
|
1593
|
+
this.#processBeginStreakPacket();
|
|
1594
|
+
break;
|
|
1428
1595
|
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1596
|
+
case CommCode.endShellStreak:
|
|
1597
|
+
this.#processEndStreakPacket();
|
|
1598
|
+
break;
|
|
1432
1599
|
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1600
|
+
case CommCode.hitMeHardBoiled:
|
|
1601
|
+
this.#processHitShieldPacket();
|
|
1602
|
+
break;
|
|
1436
1603
|
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1604
|
+
case CommCode.gameOptions:
|
|
1605
|
+
this.#processGameOptionsPacket();
|
|
1606
|
+
break;
|
|
1440
1607
|
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1608
|
+
case CommCode.ping:
|
|
1609
|
+
this.#processPingPacket();
|
|
1610
|
+
break;
|
|
1444
1611
|
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1612
|
+
case CommCode.switchTeam:
|
|
1613
|
+
this.#processSwitchTeamPacket();
|
|
1614
|
+
break;
|
|
1448
1615
|
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1616
|
+
case CommCode.changeCharacter:
|
|
1617
|
+
this.#processChangeCharacterPacket();
|
|
1618
|
+
break;
|
|
1452
1619
|
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1620
|
+
case CommCode.reload:
|
|
1621
|
+
this.#processReloadPacket();
|
|
1622
|
+
break;
|
|
1456
1623
|
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1624
|
+
case CommCode.explode:
|
|
1625
|
+
this.#processExplodePacket();
|
|
1626
|
+
break;
|
|
1627
|
+
|
|
1628
|
+
case CommCode.throwGrenade:
|
|
1629
|
+
this.#processThrowGrenadePacket();
|
|
1630
|
+
break;
|
|
1631
|
+
|
|
1632
|
+
case CommCode.spawnItem:
|
|
1633
|
+
this.#processSpawnItemPacket();
|
|
1634
|
+
break;
|
|
1635
|
+
|
|
1636
|
+
case CommCode.melee:
|
|
1637
|
+
this.#processMeleePacket();
|
|
1638
|
+
break;
|
|
1639
|
+
|
|
1640
|
+
case CommCode.updateBalance:
|
|
1641
|
+
this.#processUpdateBalancePacket();
|
|
1642
|
+
break;
|
|
1643
|
+
|
|
1644
|
+
case CommCode.challengeCompleted:
|
|
1645
|
+
this.#processChallengeCompletePacket();
|
|
1646
|
+
break;
|
|
1647
|
+
|
|
1648
|
+
case CommCode.gameAction:
|
|
1649
|
+
this.#processGameActionPacket();
|
|
1650
|
+
break;
|
|
1651
|
+
|
|
1652
|
+
case CommCode.requestGameOptions:
|
|
1653
|
+
this.#processGameRequestOptionsPacket();
|
|
1654
|
+
break;
|
|
1655
|
+
|
|
1656
|
+
case CommCode.respawnDenied:
|
|
1657
|
+
this.#processRespawnDeniedPacket();
|
|
1658
|
+
break;
|
|
1460
1659
|
|
|
1461
|
-
case CommCode.clientReady:
|
|
1462
|
-
case CommCode.expireUpgrade:
|
|
1463
|
-
case CommCode.musicInfo:
|
|
1464
|
-
case CommCode.challengeCompleted:
|
|
1465
1660
|
// we do not plan to implement these
|
|
1466
1661
|
// for more info, see comm/codes.js
|
|
1467
|
-
|
|
1662
|
+
case CommCode.clientReady:
|
|
1663
|
+
case CommCode.expireUpgrade:
|
|
1664
|
+
break;
|
|
1468
1665
|
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
break;
|
|
1666
|
+
case CommCode.musicInfo:
|
|
1667
|
+
CommIn.unPackLongString();
|
|
1668
|
+
break;
|
|
1473
1669
|
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1670
|
+
default:
|
|
1671
|
+
console.error(`handlePacket: I got but did not handle a: ${Object.keys(CommCode).find(k => CommCode[k] === cmd)}`);
|
|
1672
|
+
if (lastCommand) console.error(`handlePacket: It may be a result of the ${lastCommand} command.`);
|
|
1673
|
+
abort = true
|
|
1674
|
+
break;
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
lastCommand = Object.keys(CommCode).find(k => CommCode[k] === cmd);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
async checkChiknWinner() {
|
|
1682
|
+
const response = await queryServices({
|
|
1683
|
+
cmd: 'chicknWinnerReady',
|
|
1684
|
+
id: this.account.id,
|
|
1685
|
+
sessionId: this.account.sessionId
|
|
1686
|
+
});
|
|
1687
|
+
|
|
1688
|
+
this.account.cw.limit = response.limit;
|
|
1689
|
+
this.account.cw.atLimit = response.limit > 3;
|
|
1690
|
+
|
|
1691
|
+
// if there is a "span", that means that it's under the daily limit and you can play again soon
|
|
1692
|
+
// if there is a "period", that means that the account is done for the day and must wait a long time
|
|
1693
|
+
this.account.cw.secondsUntilPlay = response.span || response.period || 0;
|
|
1694
|
+
this.account.cw.canPlayAgain = Date.now() + (this.account.cw.secondsUntilPlay * 1000);
|
|
1695
|
+
|
|
1696
|
+
return this.account.cw;
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
async playChiknWinner() {
|
|
1700
|
+
if (this.account.cw.atLimit || this.account.cw.limit > ChiknWinnerDailyLimit) return 'hit_daily_limit';
|
|
1701
|
+
if (this.account.cw.canPlayAgain > Date.now()) return 'on_cooldown';
|
|
1702
|
+
|
|
1703
|
+
const response = await queryServices({
|
|
1704
|
+
cmd: 'incentivizedVideoReward',
|
|
1705
|
+
firebaseId: this.account.firebaseId,
|
|
1706
|
+
id: this.account.id,
|
|
1707
|
+
sessionId: this.account.sessionId,
|
|
1708
|
+
token: null
|
|
1709
|
+
}, this.proxy, this.instance);
|
|
1710
|
+
|
|
1711
|
+
if (response.error) {
|
|
1712
|
+
if (response.error == 'RATELIMITED') {
|
|
1713
|
+
await this.checkChiknWinner();
|
|
1714
|
+
return 'on_cooldown';
|
|
1715
|
+
} else if (response.error == 'SESSION_EXPIRED') {
|
|
1716
|
+
return 'session_expired';
|
|
1717
|
+
} else {
|
|
1718
|
+
console.error('Unknown Chikn Winner response', response);
|
|
1719
|
+
return 'unknown_error';
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
if (response.reward) {
|
|
1724
|
+
this.account.eggBalance += response.reward.eggsGiven;
|
|
1725
|
+
response.reward.itemIds.forEach((id) => this.account.ownedItemIds.push(id));
|
|
1726
|
+
|
|
1727
|
+
await this.checkChiknWinner();
|
|
1728
|
+
|
|
1729
|
+
return response.reward;
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
console.error('Unknown Chikn Winner response', response);
|
|
1733
|
+
return 'unknown_error';
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
async resetChiknWinner() {
|
|
1737
|
+
if (this.account.eggBalance < 200) return 'not_enough_eggs';
|
|
1738
|
+
if (!this.account.cw.atLimit) return 'not_at_limit';
|
|
1739
|
+
|
|
1740
|
+
const response = await queryServices({
|
|
1741
|
+
cmd: 'chwReset',
|
|
1742
|
+
sessionId: this.account.sessionId
|
|
1743
|
+
});
|
|
1744
|
+
|
|
1745
|
+
if (response.result !== 'SUCCESS') {
|
|
1746
|
+
console.error('Unknown Chikn Winner reset response', response);
|
|
1747
|
+
return 'unknown_error';
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
this.account.eggBalance -= 200;
|
|
1751
|
+
await this.checkChiknWinner();
|
|
1752
|
+
|
|
1753
|
+
return this.account.cw;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
canSee(target) {
|
|
1757
|
+
if (!this.intents.includes(this.Intents.PATHFINDING)) throw new Error('You must have the PATHFINDING intent to use this method.');
|
|
1758
|
+
return this.pathing.nodeList.hasLineOfSight(this.me.position, target.position);
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
getBestTarget() {
|
|
1762
|
+
const options = Object.values(this.players)
|
|
1763
|
+
.filter((player) => player)
|
|
1764
|
+
.filter((player) => player !== this.me)
|
|
1765
|
+
.filter((player) => player.playing)
|
|
1766
|
+
.filter((player) => player.hp > 0)
|
|
1767
|
+
.filter((player) => player.name !== this.me.name)
|
|
1768
|
+
.filter((player) => this.me.team === 0 || player.team !== this.me.team)
|
|
1769
|
+
.filter((player) => this.canSee(player));
|
|
1770
|
+
|
|
1771
|
+
let minDistance = 200;
|
|
1772
|
+
let targetPlayer = null;
|
|
1773
|
+
|
|
1774
|
+
for (const player of options) {
|
|
1775
|
+
const dx = player.position.x - this.me.position.x;
|
|
1776
|
+
const dy = player.position.y - this.me.position.y;
|
|
1777
|
+
const dz = player.position.z - this.me.position.z;
|
|
1778
|
+
|
|
1779
|
+
const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
1780
|
+
|
|
1781
|
+
if (distance < minDistance) {
|
|
1782
|
+
minDistance = distance;
|
|
1783
|
+
targetPlayer = player;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
return targetPlayer;
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
async refreshBalance() {
|
|
1791
|
+
const result = await queryServices({
|
|
1792
|
+
cmd: 'checkBalance',
|
|
1793
|
+
firebaseId: this.account.firebaseId,
|
|
1794
|
+
sessionId: this.account.sessionId
|
|
1795
|
+
}, this.proxy, this.instance);
|
|
1796
|
+
|
|
1797
|
+
this.account.eggBalance = result.currentBalance;
|
|
1798
|
+
|
|
1799
|
+
return result.currentBalance;
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
async redeemCode(code) {
|
|
1803
|
+
const result = await queryServices({
|
|
1804
|
+
cmd: 'redeem',
|
|
1805
|
+
firebaseId: this.account.firebaseId,
|
|
1806
|
+
sessionId: this.account.sessionId,
|
|
1807
|
+
id: this.account.id,
|
|
1808
|
+
code
|
|
1809
|
+
}, this.proxy, this.instance);
|
|
1810
|
+
|
|
1811
|
+
if (result.result === 'SUCCESS') {
|
|
1812
|
+
this.account.eggBalance = result.eggs_given;
|
|
1813
|
+
result.item_ids.forEach((id) => this.account.ownedItemIds.push(id));
|
|
1814
|
+
|
|
1815
|
+
return {
|
|
1816
|
+
result,
|
|
1817
|
+
eggsGiven: result.eggs_given,
|
|
1818
|
+
itemIds: result.item_ids
|
|
1819
|
+
};
|
|
1820
|
+
} else return result;
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
async claimURLReward(reward) {
|
|
1824
|
+
const result = await queryServices({
|
|
1825
|
+
cmd: 'urlRewardParams',
|
|
1826
|
+
firebaseId: this.account.firebaseId,
|
|
1827
|
+
sessionId: this.account.sessionId,
|
|
1828
|
+
reward
|
|
1829
|
+
}, this.proxy, this.instance);
|
|
1830
|
+
|
|
1831
|
+
if (result.result === 'SUCCESS') {
|
|
1832
|
+
this.account.eggBalance += result.eggsGiven;
|
|
1833
|
+
result.itemIds.forEach((id) => this.account.ownedItemIds.push(id));
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
return result;
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
async claimSocialReward(rewardTag) {
|
|
1840
|
+
const result = await queryServices({
|
|
1841
|
+
cmd: 'reward',
|
|
1842
|
+
firebaseId: this.account.firebaseId,
|
|
1843
|
+
sessionId: this.account.sessionId,
|
|
1844
|
+
rewardTag
|
|
1845
|
+
}, this.proxy, this.instance);
|
|
1846
|
+
|
|
1847
|
+
if (result.result === 'SUCCESS') {
|
|
1848
|
+
this.account.eggBalance += result.eggsGiven;
|
|
1849
|
+
result.itemIds.forEach((id) => this.account.ownedItemIds.push(id));
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
return result;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
async buyItem(itemId) {
|
|
1856
|
+
const result = await queryServices({
|
|
1857
|
+
cmd: 'buy',
|
|
1858
|
+
firebaseId: this.account.firebaseId,
|
|
1859
|
+
sessionId: this.account.sessionId,
|
|
1860
|
+
itemId,
|
|
1861
|
+
save: true
|
|
1862
|
+
}, this.proxy, this.instance);
|
|
1863
|
+
|
|
1864
|
+
if (result.result === 'SUCCESS') {
|
|
1865
|
+
this.account.eggBalance = result.currentBalance;
|
|
1866
|
+
this.account.ownedItemIds.push(result.itemId);
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
return result;
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
quit(noCleanup = false) {
|
|
1873
|
+
if (this.intents.includes(this.Intents.PLAYER_HEALTH))
|
|
1874
|
+
clearInterval(this.healthIntervalId);
|
|
1875
|
+
|
|
1876
|
+
clearInterval(this.updateInterval);
|
|
1877
|
+
|
|
1878
|
+
this.game.socket.close();
|
|
1879
|
+
this.matchmaker.close();
|
|
1880
|
+
|
|
1881
|
+
if (!noCleanup) {
|
|
1882
|
+
delete this.account;
|
|
1883
|
+
delete this.game;
|
|
1884
|
+
delete this.me;
|
|
1885
|
+
delete this.players;
|
|
1477
1886
|
}
|
|
1478
1887
|
}
|
|
1479
1888
|
}
|