yolkbot 0.1.2-alpha.17 → 0.1.2-alpha.3
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/browser/build/global.js +1 -1
- package/browser/build/module.js +1 -1
- package/package.json +1 -1
- package/src/api.js +3 -3
- package/src/bot.js +125 -121
- package/src/dispatches/SaveLoadoutDispatch.js +2 -4
- package/src/types/bot.d.ts +2 -7
package/package.json
CHANGED
package/src/api.js
CHANGED
|
@@ -97,7 +97,7 @@ async function loginWithCredentials(email, password, proxy = '', instance = 'she
|
|
|
97
97
|
'x-client-version': 'Chrome/JsCore/9.17.2/FirebaseCore-web',
|
|
98
98
|
'x-firebase-locale': 'en'
|
|
99
99
|
},
|
|
100
|
-
dispatcher: proxy ? new globals.ProxyAgent(proxy
|
|
100
|
+
dispatcher: proxy ? new globals.ProxyAgent(proxy) : undefined
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
body = await request.json();
|
|
@@ -158,7 +158,7 @@ async function loginWithRefreshToken(refreshToken, proxy = '', instance = 'shell
|
|
|
158
158
|
'x-client-version': 'Chrome/JsCore/9.17.2/FirebaseCore-web',
|
|
159
159
|
'x-firebase-locale': 'en'
|
|
160
160
|
},
|
|
161
|
-
dispatcher: proxy ? new globals.ProxyAgent(proxy
|
|
161
|
+
dispatcher: proxy ? new globals.ProxyAgent(proxy) : undefined
|
|
162
162
|
});
|
|
163
163
|
|
|
164
164
|
body = await request.json();
|
|
@@ -206,7 +206,7 @@ async function loginAnonymously(proxy = '', instance = 'shellshock.io') {
|
|
|
206
206
|
'x-client-version': 'Chrome/JsCore/9.17.2/FirebaseCore-web',
|
|
207
207
|
'x-firebase-locale': 'en'
|
|
208
208
|
},
|
|
209
|
-
dispatcher: proxy ? new globals.ProxyAgent(proxy
|
|
209
|
+
dispatcher: proxy ? new globals.ProxyAgent(proxy) : undefined
|
|
210
210
|
});
|
|
211
211
|
|
|
212
212
|
const body = await req.json();
|
package/src/bot.js
CHANGED
|
@@ -43,8 +43,7 @@ const intents = {
|
|
|
43
43
|
PING: 5,
|
|
44
44
|
COSMETIC_DATA: 6,
|
|
45
45
|
PLAYER_HEALTH: 7,
|
|
46
|
-
PACKET_HOOK: 8
|
|
47
|
-
MONITOR: 9
|
|
46
|
+
PACKET_HOOK: 8
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
export class Bot {
|
|
@@ -69,9 +68,8 @@ export class Bot {
|
|
|
69
68
|
|
|
70
69
|
// private information NOT FOR OTHER PLAYERS!!
|
|
71
70
|
this.state = {
|
|
72
|
-
// kept for specifying
|
|
71
|
+
// kept for specifying socket open sequence
|
|
73
72
|
name: '',
|
|
74
|
-
weaponIdx: 0,
|
|
75
73
|
|
|
76
74
|
// tracking for dispatch checks
|
|
77
75
|
reloading: false,
|
|
@@ -79,10 +77,7 @@ export class Bot {
|
|
|
79
77
|
usingMelee: false,
|
|
80
78
|
|
|
81
79
|
// shots fired ezzz
|
|
82
|
-
shotsFired: 0
|
|
83
|
-
|
|
84
|
-
// holy glitch
|
|
85
|
-
quit: false
|
|
80
|
+
shotsFired: 0
|
|
86
81
|
}
|
|
87
82
|
|
|
88
83
|
this.players = {}
|
|
@@ -392,6 +387,97 @@ export class Bot {
|
|
|
392
387
|
});
|
|
393
388
|
}
|
|
394
389
|
|
|
390
|
+
async #onGameMesssage(msg) {
|
|
391
|
+
CommIn.init(msg.data);
|
|
392
|
+
|
|
393
|
+
let out;
|
|
394
|
+
const cmd = CommIn.unPackInt8U();
|
|
395
|
+
|
|
396
|
+
switch (cmd) {
|
|
397
|
+
case CommCode.socketReady:
|
|
398
|
+
out = CommOut.getBuffer();
|
|
399
|
+
out.packInt8(CommCode.joinGame);
|
|
400
|
+
|
|
401
|
+
out.packString(this.state.name); // name
|
|
402
|
+
out.packString(this.game.raw.uuid); // game id
|
|
403
|
+
|
|
404
|
+
out.packInt8(0); // hidebadge
|
|
405
|
+
out.packInt8(0); // weapon choice
|
|
406
|
+
|
|
407
|
+
out.packInt32(this.account.session); // session int
|
|
408
|
+
out.packString(this.account.firebaseId); // firebase id
|
|
409
|
+
out.packString(this.account.sessionId); // session id
|
|
410
|
+
|
|
411
|
+
out.send(this.game.socket);
|
|
412
|
+
break;
|
|
413
|
+
|
|
414
|
+
case CommCode.gameJoined: {
|
|
415
|
+
this.me.id = CommIn.unPackInt8U();
|
|
416
|
+
// console.log("My id is:", this.me.id);
|
|
417
|
+
this.me.team = CommIn.unPackInt8U();
|
|
418
|
+
// console.log("My team is:", this.me.team);
|
|
419
|
+
this.game.gameModeId = CommIn.unPackInt8U(); // aka gameType
|
|
420
|
+
this.game.gameMode = GameModesById[this.game.gameModeId];
|
|
421
|
+
// console.log("Gametype:", this.game.gameMode, this.game.gameModeId);
|
|
422
|
+
this.game.mapIdx = CommIn.unPackInt8U();
|
|
423
|
+
this.game.map = Maps[this.game.mapIdx];
|
|
424
|
+
if (this.intents.includes(this.Intents.PATHFINDING)) {
|
|
425
|
+
this.game.map.raw = await this.#fetchMap(this.game.map.filename, this.game.map.hash);
|
|
426
|
+
this.pathing.nodeList = new NodeList(this.game.map.raw);
|
|
427
|
+
if (this.game.gameModeId === GameModes.kotc) this.#initKotcZones();
|
|
428
|
+
}
|
|
429
|
+
// console.log("Map:", this.game.map);
|
|
430
|
+
this.game.playerLimit = CommIn.unPackInt8U();
|
|
431
|
+
// console.log("Player limit:", this.game.playerLimit);
|
|
432
|
+
this.game.isGameOwner = CommIn.unPackInt8U() == 1;
|
|
433
|
+
// console.log("Is game owner:", this.game.isGameOwner);
|
|
434
|
+
this.game.isPrivate = CommIn.unPackInt8U() == 1;
|
|
435
|
+
// console.log("Is private game:", this.game.isPrivate);
|
|
436
|
+
|
|
437
|
+
// console.log('Successfully joined game.');
|
|
438
|
+
this.state.joinedGame = true;
|
|
439
|
+
this.lastDeathTime = Date.now();
|
|
440
|
+
|
|
441
|
+
const out = CommOut.getBuffer();
|
|
442
|
+
out.packInt8(CommCode.clientReady);
|
|
443
|
+
out.send(this.game.socket);
|
|
444
|
+
|
|
445
|
+
this.game.socket.onmessage = (msg) => this._packetQueue.push(msg.data);
|
|
446
|
+
|
|
447
|
+
if (this.autoUpdate)
|
|
448
|
+
this.updateIntervalId = setInterval(() => this.update(), this.updateInterval);
|
|
449
|
+
|
|
450
|
+
if (this.intents.includes(this.Intents.PING)) {
|
|
451
|
+
const out = CommOut.getBuffer();
|
|
452
|
+
out.packInt8(CommCode.ping);
|
|
453
|
+
out.send(this.game.socket);
|
|
454
|
+
this.lastPingTime = Date.now();
|
|
455
|
+
}
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
case CommCode.eventModifier:
|
|
460
|
+
// console.log("Echoed eventModifier"); // why the fuck do you need to do this
|
|
461
|
+
out = CommOut.getBuffer();
|
|
462
|
+
out.packInt8(CommCode.eventModifier);
|
|
463
|
+
out.send(this.game.socket);
|
|
464
|
+
break;
|
|
465
|
+
|
|
466
|
+
case CommCode.requestGameOptions:
|
|
467
|
+
this.#processGameRequestOptionsPacket();
|
|
468
|
+
break;
|
|
469
|
+
|
|
470
|
+
default:
|
|
471
|
+
try {
|
|
472
|
+
const inferredCode = Object.entries(CommCode).filter(([, v]) => v == cmd)[0][0];
|
|
473
|
+
console.error('onGameMessage: Received but did not handle a:', inferredCode);
|
|
474
|
+
// packet could potentially not exist, then [0][0] will error
|
|
475
|
+
} catch {
|
|
476
|
+
console.error('onGameMessage: Unexpected packet received during startup: ' + cmd);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
395
481
|
// region - a region id ('useast', 'germany', etc)
|
|
396
482
|
// mode - a mode name that corresponds to a GameMode id
|
|
397
483
|
// map - the name of a map
|
|
@@ -485,7 +571,7 @@ export class Bot {
|
|
|
485
571
|
this.game.socket.onerror = null;
|
|
486
572
|
}
|
|
487
573
|
|
|
488
|
-
this.game.socket.onmessage =
|
|
574
|
+
this.game.socket.onmessage = this.#onGameMesssage.bind(this);
|
|
489
575
|
|
|
490
576
|
this.game.socket.onclose = (e) => {
|
|
491
577
|
// console.log('Game socket closed:', e.code, Object.entries(CloseCode).filter(([, v]) => v == e.code));
|
|
@@ -555,7 +641,6 @@ export class Bot {
|
|
|
555
641
|
|
|
556
642
|
update() {
|
|
557
643
|
if (!this.state.joinedGame) throw new Error('You cannot call update() if the bot is not in a game.');
|
|
558
|
-
if (this.state.quit) return;
|
|
559
644
|
|
|
560
645
|
// process pathfinding
|
|
561
646
|
if (this.pathing.followingPath && this.intents.includes(this.Intents.PATHFINDING)) this.#processPathfinding();
|
|
@@ -580,20 +665,19 @@ export class Bot {
|
|
|
580
665
|
if (now - this.lastUpdateTime >= 50) {
|
|
581
666
|
this.emit('tick');
|
|
582
667
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
}
|
|
595
|
-
out.send(this.game.socket);
|
|
668
|
+
// Send out update packet
|
|
669
|
+
const out = CommOut.getBuffer();
|
|
670
|
+
out.packInt8(CommCode.syncMe);
|
|
671
|
+
out.packInt8(Math.random() * 128 | 0); // stateIdx
|
|
672
|
+
out.packInt8(this.me.serverStateIdx); // serverStateIdx
|
|
673
|
+
for (let i = 0; i < 3; i++) {
|
|
674
|
+
out.packInt8(this.controlKeys); // controlkeys
|
|
675
|
+
out.packInt8(this.state.shotsFired); // shots fired
|
|
676
|
+
out.packRadU(this.me.view.yaw); // yaw
|
|
677
|
+
out.packRad(this.me.view.pitch); // pitch
|
|
678
|
+
out.packInt8(100); // fixes commcode issues, does nothing
|
|
596
679
|
}
|
|
680
|
+
out.send(this.game.socket);
|
|
597
681
|
|
|
598
682
|
this.lastUpdateTime = now;
|
|
599
683
|
this.state.shotsFired = 0;
|
|
@@ -618,8 +702,6 @@ export class Bot {
|
|
|
618
702
|
#mustBeInstant = ['authFail', 'banned'];
|
|
619
703
|
|
|
620
704
|
emit(event, ...args) {
|
|
621
|
-
if (this.state.quit) return;
|
|
622
|
-
|
|
623
705
|
if (this._hooks[event]) {
|
|
624
706
|
for (const cb of this._hooks[event]) {
|
|
625
707
|
if (this.#mustBeInstant.includes(event)) cb(...args);
|
|
@@ -1032,11 +1114,9 @@ export class Bot {
|
|
|
1032
1114
|
}
|
|
1033
1115
|
|
|
1034
1116
|
#processEventModifierPacket() {
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
out.send(this.game.socket);
|
|
1039
|
-
}
|
|
1117
|
+
const out = CommOut.getBuffer();
|
|
1118
|
+
out.packInt8(CommCode.eventModifier);
|
|
1119
|
+
out.send(this.game.socket);
|
|
1040
1120
|
}
|
|
1041
1121
|
|
|
1042
1122
|
#processRemovePlayerPacket() {
|
|
@@ -1270,7 +1350,7 @@ export class Bot {
|
|
|
1270
1350
|
|
|
1271
1351
|
this.emit('pingUpdate', oldPing, this.ping);
|
|
1272
1352
|
|
|
1273
|
-
|
|
1353
|
+
setTimeout(() => {
|
|
1274
1354
|
const out = CommOut.getBuffer();
|
|
1275
1355
|
out.packInt8(CommCode.ping);
|
|
1276
1356
|
out.send(this.game.socket);
|
|
@@ -1380,26 +1460,22 @@ export class Bot {
|
|
|
1380
1460
|
}
|
|
1381
1461
|
|
|
1382
1462
|
#processGameRequestOptionsPacket() {
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
out.packInt8(this.game.options.healthRegen * 4);
|
|
1389
|
-
|
|
1390
|
-
const flags =
|
|
1391
|
-
(this.game.options.locked ? 1 : 0) |
|
|
1392
|
-
(this.game.options.noTeamChange ? 2 : 0) |
|
|
1393
|
-
(this.game.options.noTeamShuffle ? 4 : 0);
|
|
1463
|
+
const out = CommOut.getBuffer();
|
|
1464
|
+
out.packInt8(CommCode.gameOptions);
|
|
1465
|
+
out.packInt8(this.game.options.gravity * 4);
|
|
1466
|
+
out.packInt8(this.game.options.damage * 4);
|
|
1467
|
+
out.packInt8(this.game.options.healthRegen * 4);
|
|
1394
1468
|
|
|
1395
|
-
|
|
1469
|
+
const flags =
|
|
1470
|
+
(this.game.options.locked ? 1 : 0) |
|
|
1471
|
+
(this.game.options.noTeamChange ? 2 : 0) |
|
|
1472
|
+
(this.game.options.noTeamShuffle ? 4 : 0);
|
|
1396
1473
|
|
|
1397
|
-
|
|
1398
|
-
out.packInt8(v ? 1 : 0);
|
|
1399
|
-
});
|
|
1474
|
+
out.packInt8(flags);
|
|
1400
1475
|
|
|
1401
|
-
|
|
1402
|
-
|
|
1476
|
+
this.game.options.weaponsDisabled.forEach((v) => {
|
|
1477
|
+
out.packInt8(v ? 1 : 0);
|
|
1478
|
+
});
|
|
1403
1479
|
}
|
|
1404
1480
|
|
|
1405
1481
|
#processExplodePacket() {
|
|
@@ -1471,68 +1547,6 @@ export class Bot {
|
|
|
1471
1547
|
}
|
|
1472
1548
|
}
|
|
1473
1549
|
|
|
1474
|
-
#processSocketReadyPacket() {
|
|
1475
|
-
if (!this.intents.includes(this.Intents.MONITOR)) {
|
|
1476
|
-
const out = CommOut.getBuffer();
|
|
1477
|
-
out.packInt8(CommCode.joinGame);
|
|
1478
|
-
|
|
1479
|
-
out.packString(this.state.name);
|
|
1480
|
-
out.packString(this.game.raw.uuid);
|
|
1481
|
-
|
|
1482
|
-
out.packInt8(0); // hidebadge
|
|
1483
|
-
out.packInt8(this.state.weaponIdx || 0); // weapon idx
|
|
1484
|
-
|
|
1485
|
-
out.packInt32(this.account.session);
|
|
1486
|
-
out.packString(this.account.firebaseId);
|
|
1487
|
-
out.packString(this.account.sessionId);
|
|
1488
|
-
|
|
1489
|
-
out.send(this.game.socket);
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
async #processGameJoinedPacket() {
|
|
1494
|
-
this.me.id = CommIn.unPackInt8U();
|
|
1495
|
-
this.me.team = CommIn.unPackInt8U();
|
|
1496
|
-
this.game.gameModeId = CommIn.unPackInt8U(); // aka gameType
|
|
1497
|
-
this.game.gameMode = GameModesById[this.game.gameModeId];
|
|
1498
|
-
this.game.mapIdx = CommIn.unPackInt8U();
|
|
1499
|
-
this.game.map = Maps[this.game.mapIdx];
|
|
1500
|
-
if (this.intents.includes(this.Intents.PATHFINDING)) {
|
|
1501
|
-
this.game.map.raw = await this.#fetchMap(this.game.map.filename, this.game.map.hash);
|
|
1502
|
-
this.pathing.nodeList = new NodeList(this.game.map.raw);
|
|
1503
|
-
if (this.game.gameModeId === GameModes.kotc) this.#initKotcZones();
|
|
1504
|
-
}
|
|
1505
|
-
this.game.playerLimit = CommIn.unPackInt8U();
|
|
1506
|
-
this.game.isGameOwner = CommIn.unPackInt8U() == 1;
|
|
1507
|
-
this.game.isPrivate = CommIn.unPackInt8U() == 1;
|
|
1508
|
-
|
|
1509
|
-
// console.log('Successfully joined game.');
|
|
1510
|
-
|
|
1511
|
-
this.state.joinedGame = true;
|
|
1512
|
-
this.lastDeathTime = Date.now();
|
|
1513
|
-
|
|
1514
|
-
if (!this.intents.includes(this.Intents.MONITOR)) {
|
|
1515
|
-
const out = CommOut.getBuffer();
|
|
1516
|
-
out.packInt8(CommCode.clientReady);
|
|
1517
|
-
out.send(this.game.socket);
|
|
1518
|
-
|
|
1519
|
-
this.game.socket.onmessage = (msg) => this._packetQueue.push(msg.data);
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
|
-
if (this.autoUpdate)
|
|
1523
|
-
this.updateIntervalId = setInterval(() => this.update(), this.updateInterval);
|
|
1524
|
-
|
|
1525
|
-
if (this.intents.includes(this.Intents.PING)) {
|
|
1526
|
-
this.lastPingTime = Date.now();
|
|
1527
|
-
|
|
1528
|
-
if (!this.intents.includes(this.Intents.MONITOR)) {
|
|
1529
|
-
const out = CommOut.getBuffer();
|
|
1530
|
-
out.packInt8(CommCode.ping);
|
|
1531
|
-
out.send(this.game.socket);
|
|
1532
|
-
}
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
1550
|
processPacket(packet) {
|
|
1537
1551
|
CommIn.init(packet);
|
|
1538
1552
|
|
|
@@ -1668,14 +1682,6 @@ export class Bot {
|
|
|
1668
1682
|
this.#processChallengeCompletePacket();
|
|
1669
1683
|
break;
|
|
1670
1684
|
|
|
1671
|
-
case CommCode.socketReady:
|
|
1672
|
-
this.#processSocketReadyPacket();
|
|
1673
|
-
break;
|
|
1674
|
-
|
|
1675
|
-
case CommCode.gameJoined:
|
|
1676
|
-
this.#processGameJoinedPacket();
|
|
1677
|
-
break;
|
|
1678
|
-
|
|
1679
1685
|
case CommCode.gameAction:
|
|
1680
1686
|
this.#processGameActionPacket();
|
|
1681
1687
|
break;
|
|
@@ -1749,7 +1755,7 @@ export class Bot {
|
|
|
1749
1755
|
if (typeof response === 'string') return response;
|
|
1750
1756
|
|
|
1751
1757
|
if (response.error) {
|
|
1752
|
-
if (response.error == 'RATELIMITED'
|
|
1758
|
+
if (response.error == 'RATELIMITED') {
|
|
1753
1759
|
await this.checkChiknWinner();
|
|
1754
1760
|
return 'on_cooldown';
|
|
1755
1761
|
} else if (response.error == 'SESSION_EXPIRED') {
|
|
@@ -1930,8 +1936,6 @@ export class Bot {
|
|
|
1930
1936
|
delete this.me;
|
|
1931
1937
|
delete this.players;
|
|
1932
1938
|
}
|
|
1933
|
-
|
|
1934
|
-
this.state.quit = true;
|
|
1935
1939
|
}
|
|
1936
1940
|
}
|
|
1937
1941
|
|
|
@@ -70,12 +70,10 @@ export class SaveLoadoutDispatch {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
execute(bot) {
|
|
73
|
-
if (
|
|
73
|
+
if (this.changes.classIdx && this.changes.classIdx !== bot.me.selectedGun) {
|
|
74
74
|
bot.me.weapons[0] = new GunList[this.changes.classIdx]();
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
bot.state.weaponIdx = this.changes.classIdx || bot.state.weaponIdx;
|
|
78
|
-
|
|
79
77
|
const loadout = {
|
|
80
78
|
...bot.account.loadout,
|
|
81
79
|
...this.changes
|
|
@@ -91,7 +89,7 @@ export class SaveLoadoutDispatch {
|
|
|
91
89
|
|
|
92
90
|
bot.account.loadout = loadout;
|
|
93
91
|
|
|
94
|
-
|
|
92
|
+
saveLoadout.then(() => {
|
|
95
93
|
if (bot.state.joinedGame) {
|
|
96
94
|
const out = CommOut.getBuffer();
|
|
97
95
|
out.packInt8(CommCode.changeCharacter);
|
package/src/types/bot.d.ts
CHANGED
|
@@ -66,8 +66,6 @@ export interface Account {
|
|
|
66
66
|
firebaseId: string;
|
|
67
67
|
sessionId: string;
|
|
68
68
|
session: string;
|
|
69
|
-
email: string;
|
|
70
|
-
password: string;
|
|
71
69
|
cw: ChiknWinnerStatus;
|
|
72
70
|
loadout: {
|
|
73
71
|
hatId: number | null;
|
|
@@ -172,12 +170,10 @@ export interface Pathing {
|
|
|
172
170
|
|
|
173
171
|
export interface BotState {
|
|
174
172
|
name: string;
|
|
175
|
-
weaponIdx: number;
|
|
176
173
|
reloading: boolean;
|
|
177
174
|
swappingGun: boolean;
|
|
178
175
|
usingMelee: boolean;
|
|
179
176
|
shotsFired: number;
|
|
180
|
-
quit: boolean;
|
|
181
177
|
}
|
|
182
178
|
|
|
183
179
|
export interface ChiknWinnerResponse {
|
|
@@ -194,8 +190,7 @@ type intents = {
|
|
|
194
190
|
PING: 5,
|
|
195
191
|
COSMETIC_DATA: 6,
|
|
196
192
|
PLAYER_HEALTH: 7,
|
|
197
|
-
PACKET_HOOK: 8
|
|
198
|
-
MONITOR: 9
|
|
193
|
+
PACKET_HOOK: 8
|
|
199
194
|
}
|
|
200
195
|
|
|
201
196
|
export class Bot {
|
|
@@ -236,7 +231,7 @@ export class Bot {
|
|
|
236
231
|
update(): void;
|
|
237
232
|
|
|
238
233
|
canSee(player: GamePlayer): boolean;
|
|
239
|
-
getBestTarget(customFilter
|
|
234
|
+
getBestTarget(customFilter: (player: GamePlayer) => boolean): GamePlayer | undefined;
|
|
240
235
|
|
|
241
236
|
onAny(cb: Function): void;
|
|
242
237
|
|