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