teeworlds 2.4.0 → 2.4.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/index.js +7 -2
- package/lib/client.js +256 -169
- package/lib/client.ts +191 -83
- package/lib/snapshot.js +31 -16
- package/lib/snapshot.ts +34 -18
- package/package.json +1 -1
- package/test.js +32 -0
package/index.js
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
8
12
|
}));
|
|
9
13
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
-
for (var p in m) if (p !== "default" && !
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
15
|
};
|
|
12
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.Client = void 0;
|
|
13
18
|
var client_1 = require("./lib/client");
|
|
14
19
|
Object.defineProperty(exports, "Client", { enumerable: true, get: function () { return client_1.Client; } });
|
|
15
20
|
__exportStar(require("./lib/MsgPacker"), exports);
|
package/lib/client.js
CHANGED
|
@@ -3,10 +3,12 @@ var __extends = (this && this.__extends) || (function () {
|
|
|
3
3
|
var extendStatics = function (d, b) {
|
|
4
4
|
extendStatics = Object.setPrototypeOf ||
|
|
5
5
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
-
function (d, b) { for (var p in b) if (
|
|
6
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
7
7
|
return extendStatics(d, b);
|
|
8
8
|
};
|
|
9
9
|
return function (d, b) {
|
|
10
|
+
if (typeof b !== "function" && b !== null)
|
|
11
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
10
12
|
extendStatics(d, b);
|
|
11
13
|
function __() { this.constructor = d; }
|
|
12
14
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
@@ -37,42 +39,79 @@ var States;
|
|
|
37
39
|
States[States["STATE_QUITTING"] = 5] = "STATE_QUITTING";
|
|
38
40
|
States[States["STATE_RESTARTING"] = 6] = "STATE_RESTARTING";
|
|
39
41
|
})(States || (States = {}));
|
|
40
|
-
var
|
|
41
|
-
(function (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
})(
|
|
42
|
+
var NETMSG_Game;
|
|
43
|
+
(function (NETMSG_Game) {
|
|
44
|
+
NETMSG_Game[NETMSG_Game["EX"] = 0] = "EX";
|
|
45
|
+
NETMSG_Game[NETMSG_Game["SV_MOTD"] = 1] = "SV_MOTD";
|
|
46
|
+
NETMSG_Game[NETMSG_Game["SV_BROADCAST"] = 2] = "SV_BROADCAST";
|
|
47
|
+
NETMSG_Game[NETMSG_Game["SV_CHAT"] = 3] = "SV_CHAT";
|
|
48
|
+
NETMSG_Game[NETMSG_Game["SV_KILLMSG"] = 4] = "SV_KILLMSG";
|
|
49
|
+
NETMSG_Game[NETMSG_Game["SV_SOUNDGLOBAL"] = 5] = "SV_SOUNDGLOBAL";
|
|
50
|
+
NETMSG_Game[NETMSG_Game["SV_TUNEPARAMS"] = 6] = "SV_TUNEPARAMS";
|
|
51
|
+
NETMSG_Game[NETMSG_Game["SV_EXTRAPROJECTILE"] = 7] = "SV_EXTRAPROJECTILE";
|
|
52
|
+
NETMSG_Game[NETMSG_Game["SV_READYTOENTER"] = 8] = "SV_READYTOENTER";
|
|
53
|
+
NETMSG_Game[NETMSG_Game["SV_WEAPONPICKUP"] = 9] = "SV_WEAPONPICKUP";
|
|
54
|
+
NETMSG_Game[NETMSG_Game["SV_EMOTICON"] = 10] = "SV_EMOTICON";
|
|
55
|
+
NETMSG_Game[NETMSG_Game["SV_VOTECLEAROPTIONS"] = 11] = "SV_VOTECLEAROPTIONS";
|
|
56
|
+
NETMSG_Game[NETMSG_Game["SV_VOTEOPTIONLISTADD"] = 12] = "SV_VOTEOPTIONLISTADD";
|
|
57
|
+
NETMSG_Game[NETMSG_Game["SV_VOTEOPTIONADD"] = 13] = "SV_VOTEOPTIONADD";
|
|
58
|
+
NETMSG_Game[NETMSG_Game["SV_VOTEOPTIONREMOVE"] = 14] = "SV_VOTEOPTIONREMOVE";
|
|
59
|
+
NETMSG_Game[NETMSG_Game["SV_VOTESET"] = 15] = "SV_VOTESET";
|
|
60
|
+
NETMSG_Game[NETMSG_Game["SV_VOTESTATUS"] = 16] = "SV_VOTESTATUS";
|
|
61
|
+
NETMSG_Game[NETMSG_Game["CL_SAY"] = 17] = "CL_SAY";
|
|
62
|
+
NETMSG_Game[NETMSG_Game["CL_SETTEAM"] = 18] = "CL_SETTEAM";
|
|
63
|
+
NETMSG_Game[NETMSG_Game["CL_SETSPECTATORMODE"] = 19] = "CL_SETSPECTATORMODE";
|
|
64
|
+
NETMSG_Game[NETMSG_Game["CL_STARTINFO"] = 20] = "CL_STARTINFO";
|
|
65
|
+
NETMSG_Game[NETMSG_Game["CL_CHANGEINFO"] = 21] = "CL_CHANGEINFO";
|
|
66
|
+
NETMSG_Game[NETMSG_Game["CL_KILL"] = 22] = "CL_KILL";
|
|
67
|
+
NETMSG_Game[NETMSG_Game["CL_EMOTICON"] = 23] = "CL_EMOTICON";
|
|
68
|
+
NETMSG_Game[NETMSG_Game["CL_VOTE"] = 24] = "CL_VOTE";
|
|
69
|
+
NETMSG_Game[NETMSG_Game["CL_CALLVOTE"] = 25] = "CL_CALLVOTE";
|
|
70
|
+
NETMSG_Game[NETMSG_Game["CL_ISDDNETLEGACY"] = 26] = "CL_ISDDNETLEGACY";
|
|
71
|
+
NETMSG_Game[NETMSG_Game["SV_DDRACETIMELEGACY"] = 27] = "SV_DDRACETIMELEGACY";
|
|
72
|
+
NETMSG_Game[NETMSG_Game["SV_RECORDLEGACY"] = 28] = "SV_RECORDLEGACY";
|
|
73
|
+
NETMSG_Game[NETMSG_Game["UNUSED"] = 29] = "UNUSED";
|
|
74
|
+
NETMSG_Game[NETMSG_Game["SV_TEAMSSTATELEGACY"] = 30] = "SV_TEAMSSTATELEGACY";
|
|
75
|
+
NETMSG_Game[NETMSG_Game["CL_SHOWOTHERSLEGACY"] = 31] = "CL_SHOWOTHERSLEGACY";
|
|
76
|
+
NETMSG_Game[NETMSG_Game["NUM"] = 32] = "NUM";
|
|
77
|
+
})(NETMSG_Game || (NETMSG_Game = {}));
|
|
78
|
+
var NETMSG_Sys;
|
|
79
|
+
(function (NETMSG_Sys) {
|
|
80
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_EX"] = 0] = "NETMSG_EX";
|
|
81
|
+
// the first thing sent by the client
|
|
82
|
+
// contains the version info for the client
|
|
83
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_INFO"] = 1] = "NETMSG_INFO";
|
|
84
|
+
// sent by server
|
|
85
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_MAP_CHANGE"] = 2] = "NETMSG_MAP_CHANGE";
|
|
86
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_MAP_DATA"] = 3] = "NETMSG_MAP_DATA";
|
|
87
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_CON_READY"] = 4] = "NETMSG_CON_READY";
|
|
88
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_SNAP"] = 5] = "NETMSG_SNAP";
|
|
89
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_SNAPEMPTY"] = 6] = "NETMSG_SNAPEMPTY";
|
|
90
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_SNAPSINGLE"] = 7] = "NETMSG_SNAPSINGLE";
|
|
91
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_SNAPSMALL"] = 8] = "NETMSG_SNAPSMALL";
|
|
92
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_INPUTTIMING"] = 9] = "NETMSG_INPUTTIMING";
|
|
93
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_RCON_AUTH_STATUS"] = 10] = "NETMSG_RCON_AUTH_STATUS";
|
|
94
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_RCON_LINE"] = 11] = "NETMSG_RCON_LINE";
|
|
95
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_AUTH_CHALLANGE"] = 12] = "NETMSG_AUTH_CHALLANGE";
|
|
96
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_AUTH_RESULT"] = 13] = "NETMSG_AUTH_RESULT";
|
|
97
|
+
// sent by client
|
|
98
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_READY"] = 14] = "NETMSG_READY";
|
|
99
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_ENTERGAME"] = 15] = "NETMSG_ENTERGAME";
|
|
100
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_INPUT"] = 16] = "NETMSG_INPUT";
|
|
101
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_RCON_CMD"] = 17] = "NETMSG_RCON_CMD";
|
|
102
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_RCON_AUTH"] = 18] = "NETMSG_RCON_AUTH";
|
|
103
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_REQUEST_MAP_DATA"] = 19] = "NETMSG_REQUEST_MAP_DATA";
|
|
104
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_AUTH_START"] = 20] = "NETMSG_AUTH_START";
|
|
105
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_AUTH_RESPONSE"] = 21] = "NETMSG_AUTH_RESPONSE";
|
|
106
|
+
// sent by both
|
|
107
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_PING"] = 22] = "NETMSG_PING";
|
|
108
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_PING_REPLY"] = 23] = "NETMSG_PING_REPLY";
|
|
109
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_ERROR"] = 24] = "NETMSG_ERROR";
|
|
110
|
+
// sent by server (todo: move it up)
|
|
111
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_RCON_CMD_ADD"] = 25] = "NETMSG_RCON_CMD_ADD";
|
|
112
|
+
NETMSG_Sys[NETMSG_Sys["NETMSG_RCON_CMD_REM"] = 26] = "NETMSG_RCON_CMD_REM";
|
|
113
|
+
NETMSG_Sys[NETMSG_Sys["NUM_NETMSGS"] = 27] = "NUM_NETMSGS";
|
|
114
|
+
})(NETMSG_Sys || (NETMSG_Sys = {}));
|
|
76
115
|
function toHexStream(buff) {
|
|
77
116
|
return buff.toJSON().data.map(function (a) { return ('0' + (a & 0xff).toString(16)).slice(-2); }).join("");
|
|
78
117
|
}
|
|
@@ -114,6 +153,7 @@ var Client = /** @class */ (function (_super) {
|
|
|
114
153
|
_this.SnapUnpacker = new snapshot_1.Snapshot();
|
|
115
154
|
// this.eSnapHolder = [];
|
|
116
155
|
_this.requestResend = false;
|
|
156
|
+
_this.VoteList = [];
|
|
117
157
|
if (options)
|
|
118
158
|
_this.options = options;
|
|
119
159
|
_this.snaps = [];
|
|
@@ -168,7 +208,8 @@ var Client = /** @class */ (function (_super) {
|
|
|
168
208
|
}
|
|
169
209
|
else
|
|
170
210
|
packet = packet.slice(2);
|
|
171
|
-
chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
|
|
211
|
+
// chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
|
|
212
|
+
chunk.sys = Boolean(packet[0] & 1); // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
|
|
172
213
|
chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
|
|
173
214
|
chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
|
|
174
215
|
chunk.raw = packet.slice(1, chunk.bytes);
|
|
@@ -290,7 +331,8 @@ var Client = /** @class */ (function (_super) {
|
|
|
290
331
|
}
|
|
291
332
|
else
|
|
292
333
|
packet = packet.slice(2);
|
|
293
|
-
chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
|
|
334
|
+
// chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
|
|
335
|
+
chunk.sys = Boolean(packet[0] & 1); // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
|
|
294
336
|
chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
|
|
295
337
|
chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
|
|
296
338
|
chunk.raw = packet.slice(1, chunk.bytes);
|
|
@@ -354,7 +396,7 @@ var Client = /** @class */ (function (_super) {
|
|
|
354
396
|
this.time = new Date().getTime() + 2000; // start sending keepalives after 2s
|
|
355
397
|
if (this.socket)
|
|
356
398
|
this.socket.on("message", function (packet, rinfo) {
|
|
357
|
-
var _a, _b, _c, _d, _e, _f
|
|
399
|
+
var _a, _b, _c, _d, _e, _f;
|
|
358
400
|
if (_this.State == 0 || rinfo.address != _this.host || rinfo.port != _this.port)
|
|
359
401
|
return;
|
|
360
402
|
clearInterval(connectInterval);
|
|
@@ -371,7 +413,7 @@ var Client = /** @class */ (function (_super) {
|
|
|
371
413
|
var client_version = new MsgPacker_1.MsgPacker(0, true, 1);
|
|
372
414
|
client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
|
|
373
415
|
var randomUuid = Buffer.alloc(16);
|
|
374
|
-
crypto_1.randomBytes(16).copy(randomUuid);
|
|
416
|
+
(0, crypto_1.randomBytes)(16).copy(randomUuid);
|
|
375
417
|
client_version.AddBuffer(randomUuid);
|
|
376
418
|
if (((_d = _this.options) === null || _d === void 0 ? void 0 : _d.ddnet_version) !== undefined) {
|
|
377
419
|
client_version.AddInt((_e = _this.options) === null || _e === void 0 ? void 0 : _e.ddnet_version.version);
|
|
@@ -386,7 +428,7 @@ var Client = /** @class */ (function (_super) {
|
|
|
386
428
|
else if (packet.toJSON().data[3] == 0x4) {
|
|
387
429
|
// disconnected
|
|
388
430
|
_this.State = States.STATE_OFFLINE;
|
|
389
|
-
var reason = (MsgUnpacker_1.unpackString(packet.toJSON().data.slice(4)).result);
|
|
431
|
+
var reason = ((0, MsgUnpacker_1.unpackString)(packet.toJSON().data.slice(4)).result);
|
|
390
432
|
_this.emit("disconnect", reason);
|
|
391
433
|
}
|
|
392
434
|
if (packet.toJSON().data[3] !== 0x0) { // keepalive
|
|
@@ -418,10 +460,6 @@ var Client = /** @class */ (function (_super) {
|
|
|
418
460
|
}
|
|
419
461
|
}
|
|
420
462
|
});
|
|
421
|
-
unpacked.chunks.filter(function (chunk) { return chunk.msgid == NETMSGTYPE.SV_BROADCAST && chunk.type == 'game'; }).forEach(function (a) {
|
|
422
|
-
var unpacker = new MsgUnpacker_1.MsgUnpacker(a.raw.toJSON().data);
|
|
423
|
-
_this.emit("broadcast", unpacker.unpackString());
|
|
424
|
-
});
|
|
425
463
|
_this.sentChunkQueue.forEach(function (buff, i) {
|
|
426
464
|
var chunk = _this.MsgToChunk(buff);
|
|
427
465
|
if (chunk.flags & 1) {
|
|
@@ -429,144 +467,186 @@ var Client = /** @class */ (function (_super) {
|
|
|
429
467
|
_this.sentChunkQueue.splice(i, 1);
|
|
430
468
|
}
|
|
431
469
|
});
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
var DeltaTick = GameTick - unpacker.unpackInt();
|
|
444
|
-
var PartSize = 0;
|
|
445
|
-
var Crc = 0;
|
|
446
|
-
var CompleteSize = 0;
|
|
447
|
-
if (chunk.msg == "SNAP") {
|
|
448
|
-
NumParts = unpacker.unpackInt();
|
|
449
|
-
Part = unpacker.unpackInt();
|
|
470
|
+
unpacked.chunks.forEach(function (chunk, index) {
|
|
471
|
+
var _a;
|
|
472
|
+
var _b;
|
|
473
|
+
if (chunk.sys) {
|
|
474
|
+
// system messages
|
|
475
|
+
if (chunk.msgid == NETMSG_Sys.NETMSG_PING) { // ping
|
|
476
|
+
var packer = new MsgPacker_1.MsgPacker(NETMSG_Sys.NETMSG_PING_REPLY, true, 0);
|
|
477
|
+
_this.SendMsgEx(packer); // send ping reply
|
|
478
|
+
}
|
|
479
|
+
else if (chunk.msgid == NETMSG_Sys.NETMSG_PING_REPLY) { // Ping reply
|
|
480
|
+
_this.game._ping_resolve(new Date().getTime());
|
|
450
481
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
482
|
+
// packets neccessary for connection
|
|
483
|
+
// https://ddnet.org/docs/libtw2/connection/
|
|
484
|
+
if (chunk.msgid == NETMSG_Sys.NETMSG_MAP_CHANGE) {
|
|
485
|
+
var Msg = new MsgPacker_1.MsgPacker(NETMSG_Sys.NETMSG_READY, true, 1); /* ready */
|
|
486
|
+
_this.SendMsgEx(Msg);
|
|
454
487
|
}
|
|
455
|
-
if (
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
_this.
|
|
460
|
-
_this.
|
|
461
|
-
_this.
|
|
488
|
+
else if (chunk.msgid == NETMSG_Sys.NETMSG_CON_READY) {
|
|
489
|
+
var info = new MsgPacker_1.MsgPacker(NETMSG_Game.CL_STARTINFO, false, 1);
|
|
490
|
+
if ((_b = _this.options) === null || _b === void 0 ? void 0 : _b.identity) {
|
|
491
|
+
info.AddString(_this.options.identity.name);
|
|
492
|
+
info.AddString(_this.options.identity.clan);
|
|
493
|
+
info.AddInt(_this.options.identity.country);
|
|
494
|
+
info.AddString(_this.options.identity.skin);
|
|
495
|
+
info.AddInt(_this.options.identity.use_custom_color);
|
|
496
|
+
info.AddInt(_this.options.identity.color_body);
|
|
497
|
+
info.AddInt(_this.options.identity.color_feet);
|
|
462
498
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
_this.AckGameTick = snapUnpacked.recvTick;
|
|
472
|
-
if (Math.abs(_this.PredGameTick - _this.AckGameTick) > 10)
|
|
473
|
-
_this.PredGameTick = _this.AckGameTick + 1;
|
|
474
|
-
_this.sendInput();
|
|
499
|
+
else {
|
|
500
|
+
info.AddString(_this.name); /* name */
|
|
501
|
+
info.AddString(""); /* clan */
|
|
502
|
+
info.AddInt(-1); /* country */
|
|
503
|
+
info.AddString("greyfox"); /* skin */
|
|
504
|
+
info.AddInt(1); /* use custom color */
|
|
505
|
+
info.AddInt(10346103); /* color body */
|
|
506
|
+
info.AddInt(65535); /* color feet */
|
|
475
507
|
}
|
|
508
|
+
var crashmeplx = new MsgPacker_1.MsgPacker(17, true, 1); // rcon
|
|
509
|
+
crashmeplx.AddString("crashmeplx"); // 64 player support message
|
|
510
|
+
_this.SendMsgEx([info, crashmeplx]);
|
|
476
511
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
var unpacker = new MsgUnpacker_1.MsgUnpacker(
|
|
488
|
-
var
|
|
512
|
+
if (chunk.msgid >= NETMSG_Sys.NETMSG_SNAP && chunk.msgid <= NETMSG_Sys.NETMSG_SNAPSINGLE) {
|
|
513
|
+
_this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
|
|
514
|
+
if (_this.receivedSnaps == 2) {
|
|
515
|
+
if (_this.State != States.STATE_ONLINE)
|
|
516
|
+
_this.emit('connected');
|
|
517
|
+
_this.State = States.STATE_ONLINE;
|
|
518
|
+
}
|
|
519
|
+
if (Math.abs(_this.PredGameTick - _this.AckGameTick) > 10)
|
|
520
|
+
_this.PredGameTick = _this.AckGameTick + 1;
|
|
521
|
+
// snapChunks.forEach(chunk => {
|
|
522
|
+
var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw.toJSON().data);
|
|
523
|
+
var NumParts = 1;
|
|
524
|
+
var Part = 0;
|
|
525
|
+
var GameTick = unpacker.unpackInt();
|
|
526
|
+
var DeltaTick = GameTick - unpacker.unpackInt();
|
|
527
|
+
var PartSize = 0;
|
|
528
|
+
var Crc = 0;
|
|
529
|
+
var CompleteSize = 0;
|
|
530
|
+
if (chunk.msg == "SNAP") {
|
|
531
|
+
NumParts = unpacker.unpackInt();
|
|
532
|
+
Part = unpacker.unpackInt();
|
|
533
|
+
}
|
|
534
|
+
if (chunk.msg != "SNAP_EMPTY") {
|
|
535
|
+
Crc = unpacker.unpackInt();
|
|
536
|
+
PartSize = unpacker.unpackInt();
|
|
537
|
+
}
|
|
538
|
+
if (PartSize < 1 || NumParts > 64 || Part < 0 || Part >= NumParts || PartSize <= 0 || PartSize > 900)
|
|
539
|
+
return;
|
|
540
|
+
if (GameTick >= _this.currentSnapshotGameTick) {
|
|
541
|
+
if (GameTick != _this.currentSnapshotGameTick) {
|
|
542
|
+
_this.snaps = [];
|
|
543
|
+
_this.SnapshotParts = 0;
|
|
544
|
+
_this.currentSnapshotGameTick = GameTick;
|
|
545
|
+
}
|
|
546
|
+
// chunk.raw = Buffer.from(unpacker.remaining);
|
|
547
|
+
_this.snaps[Part] = Buffer.from(unpacker.remaining);
|
|
548
|
+
_this.SnapshotParts |= 1 << Part;
|
|
549
|
+
if (_this.SnapshotParts == ((1 << NumParts) - 1)) {
|
|
550
|
+
var mergedSnaps = Buffer.concat(_this.snaps);
|
|
551
|
+
_this.SnapshotParts = 0;
|
|
552
|
+
var snapUnpacked = _this.SnapUnpacker.unpackSnapshot(mergedSnaps.toJSON().data, DeltaTick, GameTick, Crc);
|
|
553
|
+
_this.emit("snapshot");
|
|
554
|
+
_this.AckGameTick = snapUnpacked.recvTick;
|
|
555
|
+
if (Math.abs(_this.PredGameTick - _this.AckGameTick) > 10)
|
|
556
|
+
_this.PredGameTick = _this.AckGameTick + 1;
|
|
557
|
+
_this.sendInput();
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
// })
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
// game messages
|
|
565
|
+
// vote list:
|
|
566
|
+
if (chunk.msgid == NETMSG_Game.SV_VOTECLEAROPTIONS) {
|
|
567
|
+
_this.VoteList = [];
|
|
568
|
+
}
|
|
569
|
+
else if (chunk.msgid == NETMSG_Game.SV_VOTEOPTIONLISTADD) {
|
|
570
|
+
var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw.toJSON().data);
|
|
571
|
+
var NumOptions = unpacker.unpackInt();
|
|
572
|
+
var list = [];
|
|
573
|
+
for (var i = 0; i < 15; i++) {
|
|
574
|
+
list.push(unpacker.unpackString());
|
|
575
|
+
}
|
|
576
|
+
list = list.slice(NumOptions);
|
|
577
|
+
(_a = _this.VoteList).push.apply(_a, list);
|
|
578
|
+
}
|
|
579
|
+
else if (chunk.msgid == NETMSG_Game.SV_VOTEOPTIONADD) {
|
|
580
|
+
var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw.toJSON().data);
|
|
581
|
+
_this.VoteList.push(unpacker.unpackString());
|
|
582
|
+
}
|
|
583
|
+
else if (chunk.msgid == NETMSG_Game.SV_VOTEOPTIONREMOVE) {
|
|
584
|
+
var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw.toJSON().data);
|
|
585
|
+
var index_1 = _this.VoteList.indexOf(unpacker.unpackString());
|
|
586
|
+
if (index_1 > -1)
|
|
587
|
+
_this.VoteList = _this.VoteList.splice(index_1, 1);
|
|
588
|
+
}
|
|
589
|
+
// events
|
|
590
|
+
if (chunk.msgid == NETMSG_Game.SV_EMOTICON) {
|
|
591
|
+
var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw.toJSON().data);
|
|
592
|
+
var unpacked_1 = {
|
|
593
|
+
client_id: unpacker.unpackInt(),
|
|
594
|
+
emoticon: unpacker.unpackInt()
|
|
595
|
+
};
|
|
596
|
+
if (unpacked_1.client_id != -1) {
|
|
597
|
+
unpacked_1.author = {
|
|
598
|
+
ClientInfo: _this.client_info(unpacked_1.client_id),
|
|
599
|
+
PlayerInfo: _this.player_info(unpacked_1.client_id)
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
_this.emit("emote", unpacked_1);
|
|
603
|
+
}
|
|
604
|
+
else if (chunk.msgid == NETMSG_Game.SV_BROADCAST) {
|
|
605
|
+
var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw.toJSON().data);
|
|
606
|
+
_this.emit("broadcast", unpacker.unpackString());
|
|
607
|
+
}
|
|
608
|
+
if (chunk.msgid == NETMSG_Game.SV_CHAT) {
|
|
609
|
+
var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw.toJSON().data);
|
|
610
|
+
var unpacked_2 = {
|
|
489
611
|
team: unpacker.unpackInt(),
|
|
490
612
|
client_id: unpacker.unpackInt(),
|
|
491
613
|
message: unpacker.unpackString()
|
|
492
614
|
};
|
|
493
|
-
if (
|
|
494
|
-
|
|
495
|
-
ClientInfo: _this.client_info(
|
|
496
|
-
PlayerInfo: _this.player_info(
|
|
615
|
+
if (unpacked_2.client_id != -1) {
|
|
616
|
+
unpacked_2.author = {
|
|
617
|
+
ClientInfo: _this.client_info(unpacked_2.client_id),
|
|
618
|
+
PlayerInfo: _this.player_info(unpacked_2.client_id)
|
|
497
619
|
};
|
|
498
620
|
}
|
|
499
|
-
_this.emit("message",
|
|
621
|
+
_this.emit("message", unpacked_2);
|
|
500
622
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
623
|
+
else if (chunk.msgid == NETMSG_Game.SV_KILLMSG) {
|
|
624
|
+
var unpacked_3 = {};
|
|
625
|
+
var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw.toJSON().data);
|
|
626
|
+
unpacked_3.killer_id = unpacker.unpackInt();
|
|
627
|
+
unpacked_3.victim_id = unpacker.unpackInt();
|
|
628
|
+
unpacked_3.weapon = unpacker.unpackInt();
|
|
629
|
+
unpacked_3.special_mode = unpacker.unpackInt();
|
|
630
|
+
if (unpacked_3.victim_id != -1 && unpacked_3.victim_id < 64) {
|
|
631
|
+
unpacked_3.victim = { ClientInfo: _this.client_info(unpacked_3.victim_id), PlayerInfo: _this.player_info(unpacked_3.victim_id) };
|
|
632
|
+
}
|
|
633
|
+
if (unpacked_3.killer_id != -1 && unpacked_3.killer_id < 64)
|
|
634
|
+
unpacked_3.killer = { ClientInfo: _this.client_info(unpacked_3.killer_id), PlayerInfo: _this.player_info(unpacked_3.killer_id) };
|
|
635
|
+
_this.emit("kill", unpacked_3);
|
|
636
|
+
}
|
|
637
|
+
else if (chunk.msgid == NETMSG_Game.SV_MOTD) {
|
|
638
|
+
var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw.toJSON().data);
|
|
639
|
+
var message = unpacker.unpackString();
|
|
640
|
+
_this.emit("motd", message);
|
|
641
|
+
}
|
|
642
|
+
// packets neccessary for connection
|
|
643
|
+
// https://ddnet.org/docs/libtw2/connection/
|
|
644
|
+
if (chunk.msgid == NETMSG_Game.SV_READYTOENTER) {
|
|
645
|
+
var Msg = new MsgPacker_1.MsgPacker(15, true, 1); /* entergame */
|
|
646
|
+
_this.SendMsgEx(Msg);
|
|
514
647
|
}
|
|
515
|
-
if (unpacked.killer_id != -1 && unpacked.killer_id < 64)
|
|
516
|
-
unpacked.killer = { ClientInfo: _this.client_info(unpacked.killer_id), PlayerInfo: _this.player_info(unpacked.killer_id) };
|
|
517
|
-
_this.emit("kill", unpacked);
|
|
518
|
-
}
|
|
519
|
-
else if (a.msg == "SV_MOTD") {
|
|
520
|
-
var unpacker = new MsgUnpacker_1.MsgUnpacker(a.raw.toJSON().data);
|
|
521
|
-
var message = unpacker.unpackString();
|
|
522
|
-
_this.emit("motd", message);
|
|
523
648
|
}
|
|
524
649
|
});
|
|
525
|
-
if (unpacked.chunks[0] && chunkMessages.includes("SV_READY_TO_ENTER")) {
|
|
526
|
-
var Msg = new MsgPacker_1.MsgPacker(15, true, 1); /* entergame */
|
|
527
|
-
_this.SendMsgEx(Msg);
|
|
528
|
-
}
|
|
529
|
-
else if ((unpacked.chunks[0] && chunkMessages.includes("CAPABILITIES") || unpacked.chunks[0] && chunkMessages.includes("MAP_CHANGE"))) {
|
|
530
|
-
// send ready
|
|
531
|
-
var Msg = new MsgPacker_1.MsgPacker(14, true, 1); /* ready */
|
|
532
|
-
_this.SendMsgEx(Msg);
|
|
533
|
-
}
|
|
534
|
-
else if ((unpacked.chunks[0] && chunkMessages.includes("CON_READY"))) {
|
|
535
|
-
var info = new MsgPacker_1.MsgPacker(20, false, 1);
|
|
536
|
-
if ((_h = _this.options) === null || _h === void 0 ? void 0 : _h.identity) {
|
|
537
|
-
info.AddString(_this.options.identity.name);
|
|
538
|
-
info.AddString(_this.options.identity.clan);
|
|
539
|
-
info.AddInt(_this.options.identity.country);
|
|
540
|
-
info.AddString(_this.options.identity.skin);
|
|
541
|
-
info.AddInt(_this.options.identity.use_custom_color);
|
|
542
|
-
info.AddInt(_this.options.identity.color_body);
|
|
543
|
-
info.AddInt(_this.options.identity.color_feet);
|
|
544
|
-
}
|
|
545
|
-
else {
|
|
546
|
-
info.AddString(_this.name); /* name */
|
|
547
|
-
info.AddString(""); /* clan */
|
|
548
|
-
info.AddInt(-1); /* country */
|
|
549
|
-
info.AddString("greyfox"); /* skin */
|
|
550
|
-
info.AddInt(1); /* use custom color */
|
|
551
|
-
info.AddInt(10346103); /* color body */
|
|
552
|
-
info.AddInt(65535); /* color feet */
|
|
553
|
-
}
|
|
554
|
-
var crashmeplx = new MsgPacker_1.MsgPacker(17, true, 1); // rcon
|
|
555
|
-
crashmeplx.AddString("crashmeplx"); // 64 player support message
|
|
556
|
-
_this.SendMsgEx([info, crashmeplx]);
|
|
557
|
-
}
|
|
558
|
-
else if (unpacked.chunks[0] && chunkMessages.includes("PING")) {
|
|
559
|
-
var info = new MsgPacker_1.MsgPacker(23, true, 1);
|
|
560
|
-
_this.SendMsgEx(info);
|
|
561
|
-
}
|
|
562
|
-
if (chunkMessages.includes("SNAP") || chunkMessages.includes("SNAP_EMPTY") || chunkMessages.includes("SNAP_SINGLE")) {
|
|
563
|
-
_this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
|
|
564
|
-
if (_this.receivedSnaps == 2) {
|
|
565
|
-
if (_this.State != States.STATE_ONLINE)
|
|
566
|
-
_this.emit('connected');
|
|
567
|
-
_this.State = States.STATE_ONLINE;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
650
|
if (new Date().getTime() - _this.time >= 1000 && _this.State == States.STATE_ONLINE) {
|
|
571
651
|
_this.time = new Date().getTime();
|
|
572
652
|
_this.SendControlMsg(0);
|
|
@@ -661,6 +741,13 @@ var Client = /** @class */ (function (_super) {
|
|
|
661
741
|
enumerable: false,
|
|
662
742
|
configurable: true
|
|
663
743
|
});
|
|
744
|
+
Object.defineProperty(Client.prototype, "VoteOptionList", {
|
|
745
|
+
get: function () {
|
|
746
|
+
return this.VoteList;
|
|
747
|
+
},
|
|
748
|
+
enumerable: false,
|
|
749
|
+
configurable: true
|
|
750
|
+
});
|
|
664
751
|
return Client;
|
|
665
752
|
}(stream_1.EventEmitter));
|
|
666
753
|
exports.Client = Client;
|
package/lib/client.ts
CHANGED
|
@@ -25,7 +25,7 @@ enum States {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
enum
|
|
28
|
+
enum NETMSG_Game {
|
|
29
29
|
EX,
|
|
30
30
|
SV_MOTD,
|
|
31
31
|
SV_BROADCAST,
|
|
@@ -61,12 +61,58 @@ enum NETMSGTYPE {
|
|
|
61
61
|
NUM
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
enum NETMSG_Sys {
|
|
65
|
+
NETMSG_EX = 0,
|
|
66
|
+
|
|
67
|
+
// the first thing sent by the client
|
|
68
|
+
// contains the version info for the client
|
|
69
|
+
NETMSG_INFO = 1,
|
|
70
|
+
|
|
71
|
+
// sent by server
|
|
72
|
+
NETMSG_MAP_CHANGE, // sent when client should switch map
|
|
73
|
+
NETMSG_MAP_DATA, // map transfer, contains a chunk of the map file
|
|
74
|
+
NETMSG_CON_READY, // connection is ready, client should send start info
|
|
75
|
+
NETMSG_SNAP, // normal snapshot, multiple parts
|
|
76
|
+
NETMSG_SNAPEMPTY, // empty snapshot
|
|
77
|
+
NETMSG_SNAPSINGLE, // ?
|
|
78
|
+
NETMSG_SNAPSMALL, //
|
|
79
|
+
NETMSG_INPUTTIMING, // reports how off the input was
|
|
80
|
+
NETMSG_RCON_AUTH_STATUS, // result of the authentication
|
|
81
|
+
NETMSG_RCON_LINE, // line that should be printed to the remote console
|
|
82
|
+
|
|
83
|
+
NETMSG_AUTH_CHALLANGE, //
|
|
84
|
+
NETMSG_AUTH_RESULT, //
|
|
85
|
+
|
|
86
|
+
// sent by client
|
|
87
|
+
NETMSG_READY, //
|
|
88
|
+
NETMSG_ENTERGAME,
|
|
89
|
+
NETMSG_INPUT, // contains the inputdata from the client
|
|
90
|
+
NETMSG_RCON_CMD, //
|
|
91
|
+
NETMSG_RCON_AUTH, //
|
|
92
|
+
NETMSG_REQUEST_MAP_DATA, //
|
|
93
|
+
|
|
94
|
+
NETMSG_AUTH_START, //
|
|
95
|
+
NETMSG_AUTH_RESPONSE, //
|
|
96
|
+
|
|
97
|
+
// sent by both
|
|
98
|
+
NETMSG_PING,
|
|
99
|
+
NETMSG_PING_REPLY,
|
|
100
|
+
NETMSG_ERROR,
|
|
101
|
+
|
|
102
|
+
// sent by server (todo: move it up)
|
|
103
|
+
NETMSG_RCON_CMD_ADD,
|
|
104
|
+
NETMSG_RCON_CMD_REM,
|
|
105
|
+
|
|
106
|
+
NUM_NETMSGS,
|
|
107
|
+
}
|
|
108
|
+
|
|
64
109
|
interface chunk {
|
|
65
110
|
bytes: number,
|
|
66
111
|
flags: number,
|
|
67
112
|
sequence?: number,
|
|
68
113
|
seq?: number,
|
|
69
|
-
type: 'sys' | 'game',
|
|
114
|
+
// type: 'sys' | 'game',
|
|
115
|
+
sys: Boolean,
|
|
70
116
|
msgid: number,
|
|
71
117
|
msg: string,
|
|
72
118
|
raw: Buffer,
|
|
@@ -128,6 +174,12 @@ declare interface iMessage {
|
|
|
128
174
|
message: string
|
|
129
175
|
}
|
|
130
176
|
|
|
177
|
+
declare interface iEmoticon {
|
|
178
|
+
client_id: number,
|
|
179
|
+
emoticon: number,
|
|
180
|
+
author?: { ClientInfo?: ClientInfo, PlayerInfo?: PlayerInfo }
|
|
181
|
+
}
|
|
182
|
+
|
|
131
183
|
declare interface iKillMsg {
|
|
132
184
|
killer_id: number,
|
|
133
185
|
killer?: { ClientInfo?: ClientInfo, PlayerInfo?: PlayerInfo },
|
|
@@ -152,6 +204,7 @@ export declare interface Client {
|
|
|
152
204
|
on(event: 'connected', listener: () => void): this;
|
|
153
205
|
on(event: 'disconnect', listener: (reason: string) => void): this;
|
|
154
206
|
|
|
207
|
+
on(event: 'emote', listener: (message: iEmoticon) => void): this;
|
|
155
208
|
on(event: 'message', listener: (message: iMessage) => void): this;
|
|
156
209
|
on(event: 'broadcast', listener: (message: string) => void): this;
|
|
157
210
|
on(event: 'kill', listener: (kill: iKillMsg) => void): this;
|
|
@@ -193,6 +246,7 @@ export class Client extends EventEmitter {
|
|
|
193
246
|
public movement: Movement;
|
|
194
247
|
public game: Game;
|
|
195
248
|
|
|
249
|
+
private VoteList: string[];
|
|
196
250
|
// eSnapHolder: eSnap[];
|
|
197
251
|
|
|
198
252
|
|
|
@@ -215,6 +269,8 @@ export class Client extends EventEmitter {
|
|
|
215
269
|
// this.eSnapHolder = [];
|
|
216
270
|
this.requestResend = false;
|
|
217
271
|
|
|
272
|
+
this.VoteList = [];
|
|
273
|
+
|
|
218
274
|
if (options)
|
|
219
275
|
this.options = options;
|
|
220
276
|
|
|
@@ -286,7 +342,8 @@ export class Client extends EventEmitter {
|
|
|
286
342
|
packet = packet.slice(3) // remove flags & size
|
|
287
343
|
} else
|
|
288
344
|
packet = packet.slice(2)
|
|
289
|
-
chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
|
|
345
|
+
// chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
|
|
346
|
+
chunk.sys = Boolean(packet[0] & 1); // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
|
|
290
347
|
chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
|
|
291
348
|
chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
|
|
292
349
|
chunk.raw = packet.slice(1, chunk.bytes)
|
|
@@ -414,7 +471,8 @@ export class Client extends EventEmitter {
|
|
|
414
471
|
packet = packet.slice(3) // remove flags & size
|
|
415
472
|
} else
|
|
416
473
|
packet = packet.slice(2)
|
|
417
|
-
chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
|
|
474
|
+
// chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
|
|
475
|
+
chunk.sys = Boolean(packet[0] & 1); // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
|
|
418
476
|
chunk.msgid = (packet[0]-(packet[0]&1))/2;
|
|
419
477
|
chunk.msg = messageTypes[packet[0]&1][chunk.msgid];
|
|
420
478
|
chunk.raw = packet.slice(1, chunk.bytes)
|
|
@@ -552,11 +610,6 @@ export class Client extends EventEmitter {
|
|
|
552
610
|
}
|
|
553
611
|
|
|
554
612
|
})
|
|
555
|
-
unpacked.chunks.filter(chunk => chunk.msgid == NETMSGTYPE.SV_BROADCAST && chunk.type == 'game').forEach(a => {
|
|
556
|
-
let unpacker = new MsgUnpacker(a.raw.toJSON().data);
|
|
557
|
-
|
|
558
|
-
this.emit("broadcast", unpacker.unpackString());
|
|
559
|
-
})
|
|
560
613
|
this.sentChunkQueue.forEach((buff, i) => {
|
|
561
614
|
let chunk = this.MsgToChunk(buff);
|
|
562
615
|
if (chunk.flags & 1) {
|
|
@@ -564,14 +617,61 @@ export class Client extends EventEmitter {
|
|
|
564
617
|
this.sentChunkQueue.splice(i, 1);
|
|
565
618
|
}
|
|
566
619
|
})
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
unpacked.chunks.forEach((chunk, index) => {
|
|
623
|
+
if (chunk.sys) {
|
|
624
|
+
// system messages
|
|
625
|
+
if (chunk.msgid == NETMSG_Sys.NETMSG_PING) { // ping
|
|
626
|
+
let packer = new MsgPacker(NETMSG_Sys.NETMSG_PING_REPLY, true, 0);
|
|
627
|
+
|
|
628
|
+
this.SendMsgEx(packer); // send ping reply
|
|
629
|
+
} else if (chunk.msgid == NETMSG_Sys.NETMSG_PING_REPLY) { // Ping reply
|
|
630
|
+
this.game._ping_resolve(new Date().getTime())
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// packets neccessary for connection
|
|
634
|
+
// https://ddnet.org/docs/libtw2/connection/
|
|
635
|
+
|
|
636
|
+
if (chunk.msgid == NETMSG_Sys.NETMSG_MAP_CHANGE) {
|
|
637
|
+
var Msg = new MsgPacker(NETMSG_Sys.NETMSG_READY, true, 1); /* ready */
|
|
638
|
+
this.SendMsgEx(Msg);
|
|
639
|
+
} else if (chunk.msgid == NETMSG_Sys.NETMSG_CON_READY) {
|
|
640
|
+
var info = new MsgPacker(NETMSG_Game.CL_STARTINFO, false, 1);
|
|
641
|
+
if (this.options?.identity) {
|
|
642
|
+
info.AddString(this.options.identity.name);
|
|
643
|
+
info.AddString(this.options.identity.clan);
|
|
644
|
+
info.AddInt(this.options.identity.country);
|
|
645
|
+
info.AddString(this.options.identity.skin);
|
|
646
|
+
info.AddInt(this.options.identity.use_custom_color);
|
|
647
|
+
info.AddInt(this.options.identity.color_body);
|
|
648
|
+
info.AddInt(this.options.identity.color_feet);
|
|
649
|
+
} else {
|
|
650
|
+
info.AddString(this.name); /* name */
|
|
651
|
+
info.AddString(""); /* clan */
|
|
652
|
+
info.AddInt(-1); /* country */
|
|
653
|
+
info.AddString("greyfox"); /* skin */
|
|
654
|
+
info.AddInt(1); /* use custom color */
|
|
655
|
+
info.AddInt(10346103); /* color body */
|
|
656
|
+
info.AddInt(65535); /* color feet */
|
|
657
|
+
|
|
658
|
+
}
|
|
659
|
+
var crashmeplx = new MsgPacker(17, true, 1); // rcon
|
|
660
|
+
crashmeplx.AddString("crashmeplx"); // 64 player support message
|
|
661
|
+
this.SendMsgEx([info, crashmeplx]);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
if (chunk.msgid >= NETMSG_Sys.NETMSG_SNAP && chunk.msgid <= NETMSG_Sys.NETMSG_SNAPSINGLE) {
|
|
665
|
+
this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
|
|
666
|
+
if (this.receivedSnaps == 2) {
|
|
667
|
+
if (this.State != States.STATE_ONLINE)
|
|
668
|
+
this.emit('connected')
|
|
669
|
+
this.State = States.STATE_ONLINE;
|
|
670
|
+
}
|
|
671
|
+
if (Math.abs(this.PredGameTick - this.AckGameTick) > 10)
|
|
572
672
|
this.PredGameTick = this.AckGameTick + 1;
|
|
573
673
|
|
|
574
|
-
snapChunks.forEach(chunk => {
|
|
674
|
+
// snapChunks.forEach(chunk => {
|
|
575
675
|
let unpacker = new MsgUnpacker(chunk.raw.toJSON().data);
|
|
576
676
|
|
|
577
677
|
let NumParts = 1;
|
|
@@ -611,7 +711,7 @@ export class Client extends EventEmitter {
|
|
|
611
711
|
let mergedSnaps = Buffer.concat(this.snaps);
|
|
612
712
|
this.SnapshotParts = 0;
|
|
613
713
|
|
|
614
|
-
let snapUnpacked = this.SnapUnpacker.unpackSnapshot(mergedSnaps.toJSON().data, DeltaTick, GameTick);
|
|
714
|
+
let snapUnpacked = this.SnapUnpacker.unpackSnapshot(mergedSnaps.toJSON().data, DeltaTick, GameTick, Crc);
|
|
615
715
|
|
|
616
716
|
this.emit("snapshot");
|
|
617
717
|
this.AckGameTick = snapUnpacked.recvTick;
|
|
@@ -625,19 +725,65 @@ export class Client extends EventEmitter {
|
|
|
625
725
|
}
|
|
626
726
|
|
|
627
727
|
|
|
628
|
-
})
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
var chunkMessages = unpacked.chunks.map(a => a.msg)
|
|
632
|
-
if (unpacked.chunks.findIndex(chunk => chunk.msgid == 23 && chunk.type == "sys") !== -1) {
|
|
633
|
-
this.game._ping_resolve(new Date().getTime())
|
|
728
|
+
// })
|
|
729
|
+
|
|
730
|
+
|
|
634
731
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
732
|
+
} else {
|
|
733
|
+
// game messages
|
|
734
|
+
|
|
735
|
+
// vote list:
|
|
736
|
+
if (chunk.msgid == NETMSG_Game.SV_VOTECLEAROPTIONS) {
|
|
737
|
+
this.VoteList = [];
|
|
738
|
+
} else if (chunk.msgid == NETMSG_Game.SV_VOTEOPTIONLISTADD) {
|
|
739
|
+
let unpacker = new MsgUnpacker(chunk.raw.toJSON().data)
|
|
740
|
+
let NumOptions = unpacker.unpackInt()
|
|
741
|
+
let list: string[] = [];
|
|
742
|
+
for (let i = 0; i < 15; i++) {
|
|
743
|
+
list.push(unpacker.unpackString());
|
|
744
|
+
}
|
|
745
|
+
list = list.slice(NumOptions);
|
|
746
|
+
|
|
747
|
+
this.VoteList.push(...list);
|
|
748
|
+
} else if (chunk.msgid == NETMSG_Game.SV_VOTEOPTIONADD) {
|
|
749
|
+
let unpacker = new MsgUnpacker(chunk.raw.toJSON().data)
|
|
750
|
+
|
|
751
|
+
this.VoteList.push(unpacker.unpackString());
|
|
752
|
+
} else if (chunk.msgid == NETMSG_Game.SV_VOTEOPTIONREMOVE) {
|
|
753
|
+
let unpacker = new MsgUnpacker(chunk.raw.toJSON().data)
|
|
754
|
+
|
|
755
|
+
let index = this.VoteList.indexOf(unpacker.unpackString());
|
|
756
|
+
|
|
757
|
+
if (index > -1)
|
|
758
|
+
this.VoteList = this.VoteList.splice(index, 1);
|
|
759
|
+
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// events
|
|
763
|
+
if (chunk.msgid == NETMSG_Game.SV_EMOTICON) {
|
|
764
|
+
let unpacker = new MsgUnpacker(chunk.raw.toJSON().data);
|
|
765
|
+
let unpacked = {
|
|
766
|
+
client_id: unpacker.unpackInt(),
|
|
767
|
+
emoticon: unpacker.unpackInt()
|
|
768
|
+
} as iEmoticon;
|
|
769
|
+
|
|
770
|
+
if (unpacked.client_id != -1) {
|
|
771
|
+
unpacked.author = {
|
|
772
|
+
ClientInfo: this.client_info(unpacked.client_id),
|
|
773
|
+
PlayerInfo: this.player_info(unpacked.client_id)
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
this.emit("emote", unpacked)
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
} else if (chunk.msgid == NETMSG_Game.SV_BROADCAST) {
|
|
781
|
+
let unpacker = new MsgUnpacker(chunk.raw.toJSON().data);
|
|
782
|
+
|
|
783
|
+
this.emit("broadcast", unpacker.unpackString());
|
|
784
|
+
} if (chunk.msgid == NETMSG_Game.SV_CHAT) {
|
|
785
|
+
let unpacker = new MsgUnpacker(chunk.raw.toJSON().data);
|
|
786
|
+
let unpacked: iMessage = {
|
|
641
787
|
team: unpacker.unpackInt(),
|
|
642
788
|
client_id: unpacker.unpackInt(),
|
|
643
789
|
message: unpacker.unpackString()
|
|
@@ -650,14 +796,9 @@ export class Client extends EventEmitter {
|
|
|
650
796
|
}
|
|
651
797
|
}
|
|
652
798
|
this.emit("message", unpacked)
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
var chat = unpacked.chunks.filter(chunk => chunk.msg == "SV_KILL_MSG" || chunk.msg == "SV_MOTD");
|
|
657
|
-
chat.forEach(a => {
|
|
658
|
-
if (a.msg == "SV_KILL_MSG") {
|
|
659
|
-
var unpacked: iKillMsg = {} as iKillMsg;
|
|
660
|
-
let unpacker = new MsgUnpacker(a.raw.toJSON().data);
|
|
799
|
+
} else if (chunk.msgid == NETMSG_Game.SV_KILLMSG) {
|
|
800
|
+
let unpacked: iKillMsg = {} as iKillMsg;
|
|
801
|
+
let unpacker = new MsgUnpacker(chunk.raw.toJSON().data);
|
|
661
802
|
unpacked.killer_id = unpacker.unpackInt();
|
|
662
803
|
unpacked.victim_id = unpacker.unpackInt();
|
|
663
804
|
unpacked.weapon = unpacker.unpackInt();
|
|
@@ -669,59 +810,22 @@ export class Client extends EventEmitter {
|
|
|
669
810
|
if (unpacked.killer_id != -1 && unpacked.killer_id < 64)
|
|
670
811
|
unpacked.killer = { ClientInfo: this.client_info(unpacked.killer_id), PlayerInfo: this.player_info(unpacked.killer_id) }
|
|
671
812
|
this.emit("kill", unpacked)
|
|
672
|
-
} else if (
|
|
673
|
-
let unpacker = new MsgUnpacker(
|
|
813
|
+
} else if (chunk.msgid == NETMSG_Game.SV_MOTD) {
|
|
814
|
+
let unpacker = new MsgUnpacker(chunk.raw.toJSON().data);
|
|
674
815
|
let message = unpacker.unpackString();
|
|
675
816
|
this.emit("motd", message);
|
|
676
817
|
}
|
|
677
|
-
})
|
|
678
|
-
|
|
679
|
-
if (unpacked.chunks[0] && chunkMessages.includes("SV_READY_TO_ENTER")) {
|
|
680
|
-
var Msg = new MsgPacker(15, true, 1); /* entergame */
|
|
681
|
-
this.SendMsgEx(Msg);
|
|
682
|
-
} else if ((unpacked.chunks[0] && chunkMessages.includes("CAPABILITIES") || unpacked.chunks[0] && chunkMessages.includes("MAP_CHANGE"))) {
|
|
683
|
-
// send ready
|
|
684
|
-
var Msg = new MsgPacker(14, true, 1); /* ready */
|
|
685
|
-
this.SendMsgEx(Msg);
|
|
686
|
-
} else if ((unpacked.chunks[0] && chunkMessages.includes("CON_READY"))) {
|
|
687
|
-
var info = new MsgPacker(20, false, 1);
|
|
688
|
-
if (this.options?.identity) {
|
|
689
|
-
info.AddString(this.options.identity.name);
|
|
690
|
-
info.AddString(this.options.identity.clan);
|
|
691
|
-
info.AddInt(this.options.identity.country);
|
|
692
|
-
info.AddString(this.options.identity.skin);
|
|
693
|
-
info.AddInt(this.options.identity.use_custom_color);
|
|
694
|
-
info.AddInt(this.options.identity.color_body);
|
|
695
|
-
info.AddInt(this.options.identity.color_feet);
|
|
696
|
-
} else {
|
|
697
|
-
info.AddString(this.name); /* name */
|
|
698
|
-
info.AddString(""); /* clan */
|
|
699
|
-
info.AddInt(-1); /* country */
|
|
700
|
-
info.AddString("greyfox"); /* skin */
|
|
701
|
-
info.AddInt(1); /* use custom color */
|
|
702
|
-
info.AddInt(10346103); /* color body */
|
|
703
|
-
info.AddInt(65535); /* color feet */
|
|
704
|
-
|
|
705
|
-
}
|
|
706
|
-
var crashmeplx = new MsgPacker(17, true, 1); // rcon
|
|
707
|
-
crashmeplx.AddString("crashmeplx"); // 64 player support message
|
|
708
|
-
this.SendMsgEx([info, crashmeplx]);
|
|
709
818
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
if (chunkMessages.includes("SNAP") || chunkMessages.includes("SNAP_EMPTY") || chunkMessages.includes("SNAP_SINGLE")) {
|
|
717
|
-
this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
|
|
718
|
-
if (this.receivedSnaps == 2) {
|
|
719
|
-
if (this.State != States.STATE_ONLINE)
|
|
720
|
-
this.emit('connected')
|
|
721
|
-
this.State = States.STATE_ONLINE;
|
|
819
|
+
// packets neccessary for connection
|
|
820
|
+
// https://ddnet.org/docs/libtw2/connection/
|
|
821
|
+
if (chunk.msgid == NETMSG_Game.SV_READYTOENTER) {
|
|
822
|
+
var Msg = new MsgPacker(15, true, 1); /* entergame */
|
|
823
|
+
this.SendMsgEx(Msg);
|
|
824
|
+
}
|
|
722
825
|
}
|
|
826
|
+
})
|
|
723
827
|
|
|
724
|
-
|
|
828
|
+
|
|
725
829
|
if (new Date().getTime() - this.time >= 1000 && this.State == States.STATE_ONLINE) {
|
|
726
830
|
this.time = new Date().getTime();
|
|
727
831
|
this.SendControlMsg(0);
|
|
@@ -812,4 +916,8 @@ export class Client extends EventEmitter {
|
|
|
812
916
|
.sort((a, b) => a.id - b.id)
|
|
813
917
|
.map(player => player.parsed as PlayerInfo);
|
|
814
918
|
}
|
|
919
|
+
|
|
920
|
+
get VoteOptionList(): string[] {
|
|
921
|
+
return this.VoteList;
|
|
922
|
+
}
|
|
815
923
|
}
|
package/lib/snapshot.js
CHANGED
|
@@ -54,6 +54,7 @@ var Snapshot = /** @class */ (function () {
|
|
|
54
54
|
function Snapshot() {
|
|
55
55
|
this.deltas = [];
|
|
56
56
|
this.eSnapHolder = [];
|
|
57
|
+
this.crc_errors = 0;
|
|
57
58
|
}
|
|
58
59
|
Snapshot.prototype.IntsToStr = function (pInts) {
|
|
59
60
|
var pIntz = [];
|
|
@@ -291,7 +292,15 @@ var Snapshot = /** @class */ (function () {
|
|
|
291
292
|
}
|
|
292
293
|
return _item;
|
|
293
294
|
};
|
|
294
|
-
Snapshot.prototype.
|
|
295
|
+
Snapshot.prototype.crc = function (tick) {
|
|
296
|
+
var checksum = 0;
|
|
297
|
+
this.eSnapHolder.forEach(function (snap) {
|
|
298
|
+
if (snap.ack == tick)
|
|
299
|
+
snap.Snapshot.Data.forEach(function (el) { return checksum += el; });
|
|
300
|
+
});
|
|
301
|
+
return checksum & 0xffffffff;
|
|
302
|
+
};
|
|
303
|
+
Snapshot.prototype.unpackSnapshot = function (snap, deltatick, recvTick, WantedCrc) {
|
|
295
304
|
var _this = this;
|
|
296
305
|
var unpacker = new MsgUnpacker_1.MsgUnpacker(snap);
|
|
297
306
|
if (deltatick == -1) {
|
|
@@ -330,7 +339,6 @@ var Snapshot = /** @class */ (function () {
|
|
|
330
339
|
var deleted_key = unpacker.unpackInt(); // removed_item_keys
|
|
331
340
|
// let index = this.deltas.map(delta => delta.key).indexOf(deleted_key);
|
|
332
341
|
var index = this_1.deltas.findIndex(function (delta) { return delta.key === deleted_key; });
|
|
333
|
-
// console.log("deleting ", deleted_key, index)
|
|
334
342
|
if (index > -1)
|
|
335
343
|
this_1.deltas.splice(index, 1);
|
|
336
344
|
deleted.push(deleted_key);
|
|
@@ -349,13 +357,8 @@ var Snapshot = /** @class */ (function () {
|
|
|
349
357
|
var items = { items: [], /* client_infos: client_infos, player_infos: player_infos,*/ lost: 0 };
|
|
350
358
|
var deltaSnaps = this.eSnapHolder.filter(function (a) { return a.ack === deltatick; });
|
|
351
359
|
if (deltaSnaps.length == 0 && deltatick >= 0) {
|
|
352
|
-
// console.log("RESET recvtick")
|
|
353
360
|
return { items: [], recvTick: -1 };
|
|
354
361
|
}
|
|
355
|
-
var newSnaps = [];
|
|
356
|
-
deltaSnaps.forEach(function (a) {
|
|
357
|
-
newSnaps.push({ Snapshot: a.Snapshot, ack: recvTick });
|
|
358
|
-
});
|
|
359
362
|
var _loop_2 = function (i) {
|
|
360
363
|
var type_id = unpacker.unpackInt();
|
|
361
364
|
var id = unpacker.unpackInt();
|
|
@@ -370,10 +373,7 @@ var Snapshot = /** @class */ (function () {
|
|
|
370
373
|
for (var j = 0; j < _size; j++) {
|
|
371
374
|
if (unpacker.remaining.length > 0)
|
|
372
375
|
data.push(unpacker.unpackInt());
|
|
373
|
-
// else
|
|
374
|
-
// console.log("wrong size")
|
|
375
376
|
}
|
|
376
|
-
// console.log(index, deltatick)
|
|
377
377
|
if (deltatick >= 0) {
|
|
378
378
|
// let index = deltaSnaps.map(delta => delta.Snapshot.Key).indexOf(key)
|
|
379
379
|
var index = deltaSnaps.findIndex(function (delta) { return delta.Snapshot.Key === key; });
|
|
@@ -391,7 +391,7 @@ var Snapshot = /** @class */ (function () {
|
|
|
391
391
|
_loop_2(i);
|
|
392
392
|
}
|
|
393
393
|
var _loop_3 = function (newSnap) {
|
|
394
|
-
if (this_3.eSnapHolder.findIndex(function (a) { return a.ack ==
|
|
394
|
+
if (this_3.eSnapHolder.findIndex(function (a) { return a.ack == recvTick && a.Snapshot.Key == newSnap.Snapshot.Key; }) === -1) { // ugly copy new snap to eSnapHolder (if it isnt pushed already)
|
|
395
395
|
this_3.eSnapHolder.push({ Snapshot: { Data: newSnap.Snapshot.Data, Key: newSnap.Snapshot.Key }, ack: recvTick });
|
|
396
396
|
}
|
|
397
397
|
if (deltatick > -1) {
|
|
@@ -404,10 +404,24 @@ var Snapshot = /** @class */ (function () {
|
|
|
404
404
|
this_3.deltas.push({ data: newSnap.Snapshot.Data, key: newSnap.Snapshot.Key, id: newSnap.Snapshot.Key & 0xffff, type_id: ((newSnap.Snapshot.Key >> 16) & 0xffff), parsed: this_3.parseItem(newSnap.Snapshot.Data, ((newSnap.Snapshot.Key >> 16) & 0xffff), ((newSnap.Snapshot.Key) & 0xffff)) });
|
|
405
405
|
};
|
|
406
406
|
var this_3 = this;
|
|
407
|
-
for (var _i = 0,
|
|
408
|
-
var newSnap =
|
|
407
|
+
for (var _i = 0, deltaSnaps_1 = deltaSnaps; _i < deltaSnaps_1.length; _i++) {
|
|
408
|
+
var newSnap = deltaSnaps_1[_i];
|
|
409
409
|
_loop_3(newSnap);
|
|
410
410
|
}
|
|
411
|
+
if (this.crc(recvTick) !== WantedCrc) {
|
|
412
|
+
this.crc_errors++;
|
|
413
|
+
if (this.crc_errors > 5) {
|
|
414
|
+
recvTick = -1;
|
|
415
|
+
this.crc_errors = 0;
|
|
416
|
+
this.eSnapHolder = [];
|
|
417
|
+
this.deltas = [];
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
recvTick = deltatick;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
else if (this.crc_errors > 0)
|
|
424
|
+
this.crc_errors--;
|
|
411
425
|
return { items: items, recvTick: recvTick };
|
|
412
426
|
};
|
|
413
427
|
return Snapshot;
|
|
@@ -415,14 +429,15 @@ var Snapshot = /** @class */ (function () {
|
|
|
415
429
|
exports.Snapshot = Snapshot;
|
|
416
430
|
function UndiffItem(oldItem, newItem) {
|
|
417
431
|
var out = newItem;
|
|
418
|
-
if (JSON.stringify(newItem) === JSON.stringify(oldItem))
|
|
419
|
-
|
|
432
|
+
// if (JSON.stringify(newItem) === JSON.stringify(oldItem))
|
|
433
|
+
// return newItem;
|
|
420
434
|
oldItem.forEach(function (a, i) {
|
|
421
435
|
if (a !== undefined && out[i] !== undefined) {
|
|
422
436
|
out[i] += a;
|
|
423
437
|
}
|
|
424
|
-
else
|
|
438
|
+
else {
|
|
425
439
|
out[i] = 0;
|
|
440
|
+
}
|
|
426
441
|
});
|
|
427
442
|
return out;
|
|
428
443
|
}
|
package/lib/snapshot.ts
CHANGED
|
@@ -57,6 +57,7 @@ interface eSnap {
|
|
|
57
57
|
export class Snapshot {
|
|
58
58
|
deltas: {'data': number[], 'parsed': Item, 'type_id': number, 'id': number, 'key': number}[] = [];
|
|
59
59
|
eSnapHolder: eSnap[] = [];
|
|
60
|
+
crc_errors: number = 0;
|
|
60
61
|
|
|
61
62
|
private IntsToStr(pInts: number[]): string {
|
|
62
63
|
var pIntz: number[] = [];
|
|
@@ -297,7 +298,18 @@ export class Snapshot {
|
|
|
297
298
|
|
|
298
299
|
return _item;
|
|
299
300
|
}
|
|
300
|
-
|
|
301
|
+
|
|
302
|
+
crc(tick: number) {
|
|
303
|
+
var checksum = 0;
|
|
304
|
+
this.eSnapHolder.forEach(snap => {
|
|
305
|
+
if (snap.ack == tick)
|
|
306
|
+
snap.Snapshot.Data.forEach(el => checksum += el);
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
return checksum & 0xffffffff;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
unpackSnapshot(snap: number[], deltatick: number, recvTick: number, WantedCrc: number) {
|
|
301
313
|
let unpacker = new MsgUnpacker(snap);
|
|
302
314
|
if (deltatick == -1) {
|
|
303
315
|
this.eSnapHolder = [];
|
|
@@ -309,7 +321,7 @@ export class Snapshot {
|
|
|
309
321
|
// empty snap, copy old one into new ack
|
|
310
322
|
this.eSnapHolder.forEach(snap => {
|
|
311
323
|
if (snap.ack == deltatick)
|
|
312
|
-
|
|
324
|
+
this.eSnapHolder.push({Snapshot: snap.Snapshot, ack: recvTick});
|
|
313
325
|
|
|
314
326
|
})
|
|
315
327
|
return {items: [], recvTick: recvTick};
|
|
@@ -337,12 +349,11 @@ export class Snapshot {
|
|
|
337
349
|
let deleted_key = unpacker.unpackInt(); // removed_item_keys
|
|
338
350
|
// let index = this.deltas.map(delta => delta.key).indexOf(deleted_key);
|
|
339
351
|
let index = this.deltas.findIndex(delta => delta.key === deleted_key);
|
|
340
|
-
// console.log("deleting ", deleted_key, index)
|
|
341
352
|
if (index > -1)
|
|
342
353
|
this.deltas.splice(index, 1);
|
|
343
354
|
deleted.push(deleted_key)
|
|
344
355
|
}
|
|
345
|
-
if (deleted.length)
|
|
356
|
+
if (deleted.length)
|
|
346
357
|
this.eSnapHolder = this.eSnapHolder.filter(a => !deleted.includes(a.Snapshot.Key));
|
|
347
358
|
|
|
348
359
|
/*item_delta:
|
|
@@ -355,14 +366,8 @@ export class Snapshot {
|
|
|
355
366
|
let deltaSnaps = this.eSnapHolder.filter(a => a.ack === deltatick);
|
|
356
367
|
|
|
357
368
|
if (deltaSnaps.length == 0 && deltatick >= 0) {
|
|
358
|
-
// console.log("RESET recvtick")
|
|
359
369
|
return {items: [], recvTick: -1};
|
|
360
370
|
}
|
|
361
|
-
let newSnaps: eSnap[] = [];
|
|
362
|
-
deltaSnaps.forEach((a) => {
|
|
363
|
-
|
|
364
|
-
newSnaps.push({Snapshot: a.Snapshot, ack: recvTick});
|
|
365
|
-
})
|
|
366
371
|
|
|
367
372
|
|
|
368
373
|
for (let i = 0; i < num_item_deltas; i++) {
|
|
@@ -380,10 +385,7 @@ export class Snapshot {
|
|
|
380
385
|
for (let j = 0; j < _size; j++) {
|
|
381
386
|
if (unpacker.remaining.length > 0)
|
|
382
387
|
data.push(unpacker.unpackInt());
|
|
383
|
-
// else
|
|
384
|
-
// console.log("wrong size")
|
|
385
388
|
}
|
|
386
|
-
// console.log(index, deltatick)
|
|
387
389
|
if (deltatick >= 0) {
|
|
388
390
|
// let index = deltaSnaps.map(delta => delta.Snapshot.Key).indexOf(key)
|
|
389
391
|
let index = deltaSnaps.findIndex(delta => delta.Snapshot.Key === key);
|
|
@@ -402,8 +404,8 @@ export class Snapshot {
|
|
|
402
404
|
|
|
403
405
|
|
|
404
406
|
}
|
|
405
|
-
for (let newSnap of
|
|
406
|
-
if (this.eSnapHolder.findIndex(a => a.ack ==
|
|
407
|
+
for (let newSnap of deltaSnaps) {
|
|
408
|
+
if (this.eSnapHolder.findIndex(a => a.ack == recvTick && a.Snapshot.Key == newSnap.Snapshot.Key) === -1) { // ugly copy new snap to eSnapHolder (if it isnt pushed already)
|
|
407
409
|
this.eSnapHolder.push({Snapshot: {Data: newSnap.Snapshot.Data, Key: newSnap.Snapshot.Key}, ack: recvTick});
|
|
408
410
|
}
|
|
409
411
|
if (deltatick > -1) {
|
|
@@ -417,6 +419,19 @@ export class Snapshot {
|
|
|
417
419
|
this.deltas.push({data: newSnap.Snapshot.Data, key: newSnap.Snapshot.Key, id: newSnap.Snapshot.Key & 0xffff, type_id: ((newSnap.Snapshot.Key >> 16) & 0xffff), parsed: this.parseItem(newSnap.Snapshot.Data, ((newSnap.Snapshot.Key >> 16) & 0xffff), ((newSnap.Snapshot.Key) & 0xffff))});
|
|
418
420
|
}
|
|
419
421
|
|
|
422
|
+
if (this.crc(recvTick) !== WantedCrc) {
|
|
423
|
+
this.crc_errors++;
|
|
424
|
+
if (this.crc_errors > 5) {
|
|
425
|
+
recvTick = -1;
|
|
426
|
+
this.crc_errors = 0;
|
|
427
|
+
this.eSnapHolder = [];
|
|
428
|
+
this.deltas = [];
|
|
429
|
+
} else {
|
|
430
|
+
recvTick = deltatick;
|
|
431
|
+
|
|
432
|
+
}
|
|
433
|
+
} else if (this.crc_errors > 0)
|
|
434
|
+
this.crc_errors--;
|
|
420
435
|
|
|
421
436
|
return {items, recvTick};
|
|
422
437
|
}
|
|
@@ -424,13 +439,14 @@ export class Snapshot {
|
|
|
424
439
|
|
|
425
440
|
function UndiffItem(oldItem: number[], newItem: number[]): number[] {
|
|
426
441
|
let out: number[] = newItem;
|
|
427
|
-
if (JSON.stringify(newItem) === JSON.stringify(oldItem))
|
|
428
|
-
return newItem;
|
|
442
|
+
// if (JSON.stringify(newItem) === JSON.stringify(oldItem))
|
|
443
|
+
// return newItem;
|
|
429
444
|
oldItem.forEach((a, i) => {
|
|
430
445
|
if (a !== undefined && out[i] !== undefined) {
|
|
431
446
|
out[i] += a;
|
|
432
|
-
} else
|
|
447
|
+
} else {
|
|
433
448
|
out[i] = 0;
|
|
449
|
+
}
|
|
434
450
|
})
|
|
435
451
|
return out;
|
|
436
452
|
}
|
package/package.json
CHANGED
package/test.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const { Snapshot } = require("./lib/snapshot")
|
|
2
|
+
|
|
3
|
+
let test_snap1 = [0,18,0,4,18,1744,1072,2,3,4,17,1840,912,1,0,4,16,880,880,0,0,4,15,1840,848,1,0,4,14,912,848,0,0,4,13,880,848,1,0,4,12,848,848,0,0,4,11,880,816,0,0,4,9,1264,656,0,0,4,8,1104,656,0,0,4,7,912,656,0,0,4,6,1712,624,2,2,4,5,1840,432,1,0,4,3,1840,336,1,0,9,0,292,1584,305,0,128,0,0,0,-1,0,0,1584,304,0,0,0,10,0,10,1,0,0,6,0,0,0,0,0,20,0,0,1,11,0,-287183387,-320474125,-1594563099,-2139062272,-2139062144,-2139062144,-2139062272,-1,-454695199,-169020288,-2139062144,-2139062144,-2139062144,-2139062272,0,65408,65408,10,0,1,0,0,0,0]
|
|
4
|
+
let first_crc = 0x5b96263a;
|
|
5
|
+
let test_snap2 = [0,1,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,];
|
|
6
|
+
let second_crc = 0x5b96263b;
|
|
7
|
+
let snapunpacker = new Snapshot();
|
|
8
|
+
|
|
9
|
+
let sum = (nums) => {
|
|
10
|
+
var sum = 0;
|
|
11
|
+
nums.forEach(a => {
|
|
12
|
+
// if (a < 0)
|
|
13
|
+
sum += a
|
|
14
|
+
})
|
|
15
|
+
console.log(sum, master_sum)
|
|
16
|
+
return sum;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let master_sum = 0;
|
|
20
|
+
|
|
21
|
+
// test_snap.forEach(a => master_sum += sum(...a));
|
|
22
|
+
// master_sum = sum(...test_snap)
|
|
23
|
+
// test_snap.forEach(a => {master_sum += a; console.log(master_sum)})
|
|
24
|
+
// console.log(snapunpacker.unpackSnapshot(test_snap).items.items);
|
|
25
|
+
|
|
26
|
+
snapunpacker = new Snapshot();
|
|
27
|
+
console.log(snapunpacker.unpackSnapshot(test_snap1, -1, 1, first_crc));
|
|
28
|
+
console.log(snapunpacker.unpackSnapshot(test_snap2, 1, 2, second_crc));
|
|
29
|
+
// console.log(snapunpacker.eSnapHolder)
|
|
30
|
+
// snapunpacker.eSnapHolder.forEach(a => console.log(a.Snapshot.Data))
|
|
31
|
+
snapunpacker.eSnapHolder.forEach(a => master_sum += sum(a.Snapshot.Data))
|
|
32
|
+
console.log(master_sum & 0xffffffff, 0x5b96263a)
|