teeworlds 2.3.3 → 2.3.4
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/lib/MsgPacker.js +2 -1
- package/lib/MsgPacker.ts +3 -1
- package/lib/client.js +69 -65
- package/lib/client.ts +62 -53
- package/package.json +1 -1
package/lib/MsgPacker.js
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MsgPacker = void 0;
|
|
4
4
|
var MsgPacker = /** @class */ (function () {
|
|
5
|
-
function MsgPacker(msg, sys) {
|
|
5
|
+
function MsgPacker(msg, sys, flag) {
|
|
6
6
|
this.result = Buffer.from([2 * msg + (sys ? 1 : 0)]);
|
|
7
7
|
this.sys = sys;
|
|
8
|
+
this.flag = flag;
|
|
8
9
|
}
|
|
9
10
|
MsgPacker.prototype.AddString = function (str) {
|
|
10
11
|
this.result = Buffer.concat([this.result, Buffer.from(str), Buffer.from([0x00])]);
|
package/lib/MsgPacker.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export class MsgPacker {
|
|
2
2
|
result: Buffer;
|
|
3
3
|
sys: boolean;
|
|
4
|
-
|
|
4
|
+
flag: number;
|
|
5
|
+
constructor(msg: number, sys: boolean, flag: number) {
|
|
5
6
|
this.result = Buffer.from([2*msg + (sys ? 1 : 0)]);
|
|
6
7
|
this.sys = sys;
|
|
8
|
+
this.flag = flag;
|
|
7
9
|
}
|
|
8
10
|
AddString(str: string) {
|
|
9
11
|
this.result = Buffer.concat([this.result, Buffer.from(str), Buffer.from([0x00])])
|
package/lib/client.js
CHANGED
|
@@ -139,11 +139,12 @@ var Client = /** @class */ (function (_super) {
|
|
|
139
139
|
if (msg.ack > lastAck)
|
|
140
140
|
toResend.push(msg.msg);
|
|
141
141
|
});
|
|
142
|
-
|
|
142
|
+
toResend.forEach(function (a) { return a.flag = 1 | 2; });
|
|
143
|
+
this.SendMsgEx(toResend);
|
|
143
144
|
};
|
|
144
145
|
Client.prototype.Unpack = function (packet) {
|
|
145
146
|
var unpacked = { twprotocol: { flags: packet[0] >> 4, ack: ((packet[0] & 0xf) << 8) | packet[1], chunkAmount: packet[2], size: packet.byteLength - 3 }, chunks: [] };
|
|
146
|
-
if (packet.indexOf(Buffer.from([0xff, 0xff, 0xff, 0xff])) == 0
|
|
147
|
+
if (packet.indexOf(Buffer.from([0xff, 0xff, 0xff, 0xff])) == 0) // !(unpacked.twprotocol.flags & 8) || unpacked.twprotocol.flags == 255) // flags == 255 is connectionless (used for sending usernames)
|
|
147
148
|
return unpacked;
|
|
148
149
|
if (unpacked.twprotocol.flags & 4) { // resend flag
|
|
149
150
|
this.ResendAfter(unpacked.twprotocol.ack);
|
|
@@ -199,7 +200,7 @@ var Client = /** @class */ (function (_super) {
|
|
|
199
200
|
*/
|
|
200
201
|
});
|
|
201
202
|
};
|
|
202
|
-
Client.prototype.SendMsgEx = function (Msgs
|
|
203
|
+
Client.prototype.SendMsgEx = function (Msgs) {
|
|
203
204
|
var _this = this;
|
|
204
205
|
if (this.State == States.STATE_OFFLINE)
|
|
205
206
|
return;
|
|
@@ -219,20 +220,20 @@ var Client = /** @class */ (function (_super) {
|
|
|
219
220
|
if (this.clientAck == 0)
|
|
220
221
|
this.lastSentMessages = [];
|
|
221
222
|
_Msgs.forEach(function (Msg, index) {
|
|
222
|
-
header[index] = Buffer.alloc((
|
|
223
|
-
header[index][0] = ((
|
|
223
|
+
header[index] = Buffer.alloc((Msg.flag & 1 ? 3 : 2));
|
|
224
|
+
header[index][0] = ((Msg.flag & 3) << 6) | ((Msg.size >> 4) & 0x3f);
|
|
224
225
|
header[index][1] = (Msg.size & 0xf);
|
|
225
|
-
if (
|
|
226
|
+
if (Msg.flag & 1) {
|
|
226
227
|
_this.clientAck = (_this.clientAck + 1) % (1 << 10);
|
|
227
228
|
if (_this.clientAck == 0)
|
|
228
229
|
_this.lastSentMessages = [];
|
|
229
230
|
header[index][1] |= (_this.clientAck >> 2) & 0xf0;
|
|
230
231
|
header[index][2] = _this.clientAck & 0xff;
|
|
231
|
-
header[index][0] = (((
|
|
232
|
-
if ((
|
|
232
|
+
header[index][0] = (((Msg.flag | 2) & 3) << 6) | ((Msg.size >> 4) & 0x3f); // 2 is resend flag (ugly hack for queue)
|
|
233
|
+
if ((Msg.flag & 2) == 0)
|
|
233
234
|
_this.sentChunkQueue.push(Buffer.concat([header[index], Msg.buffer]));
|
|
234
|
-
header[index][0] = (((
|
|
235
|
-
if ((
|
|
235
|
+
header[index][0] = (((Msg.flag) & 3) << 6) | ((Msg.size >> 4) & 0x3f);
|
|
236
|
+
if ((Msg.flag & 2) == 0)
|
|
236
237
|
_this.lastSentMessages.push({ msg: Msg, ack: _this.clientAck });
|
|
237
238
|
}
|
|
238
239
|
});
|
|
@@ -249,11 +250,12 @@ var Client = /** @class */ (function (_super) {
|
|
|
249
250
|
chunks = Buffer.concat([chunks, Buffer.from(header[index]), Msg.buffer]);
|
|
250
251
|
else {
|
|
251
252
|
skip = true;
|
|
252
|
-
_this.SendMsgEx(_Msgs.slice(index)
|
|
253
|
+
_this.SendMsgEx(_Msgs.slice(index));
|
|
253
254
|
}
|
|
254
255
|
});
|
|
255
256
|
var packet = Buffer.concat([(packetHeader), chunks, this.TKEN]);
|
|
256
|
-
|
|
257
|
+
if (chunks.length < 0)
|
|
258
|
+
return;
|
|
257
259
|
this.socket.send(packet, 0, packet.length, this.port, this.host);
|
|
258
260
|
};
|
|
259
261
|
Client.prototype.QueueChunkEx = function (Msg) {
|
|
@@ -267,6 +269,8 @@ var Client = /** @class */ (function (_super) {
|
|
|
267
269
|
this.lastSendTime = new Date().getTime();
|
|
268
270
|
var packetHeader = Buffer.from([0x0 + (((16 << 4) & 0xf0) | ((this.ack >> 8) & 0xf)), this.ack & 0xff, chunks.length]);
|
|
269
271
|
var packet = Buffer.concat([(packetHeader), Buffer.concat(chunks), this.TKEN]);
|
|
272
|
+
if (chunks.length < 0)
|
|
273
|
+
return;
|
|
270
274
|
this.socket.send(packet, 0, packet.length, this.port, this.host);
|
|
271
275
|
};
|
|
272
276
|
Client.prototype.MsgToChunk = function (packet) {
|
|
@@ -351,10 +355,10 @@ var Client = /** @class */ (function (_super) {
|
|
|
351
355
|
_this.SendControlMsg(3);
|
|
352
356
|
_this.State = States.STATE_LOADING; // loading state
|
|
353
357
|
_this.receivedSnaps = 0;
|
|
354
|
-
var info = new MsgPacker_1.MsgPacker(1, true);
|
|
358
|
+
var info = new MsgPacker_1.MsgPacker(1, true, 1);
|
|
355
359
|
info.AddString(((_a = _this.options) === null || _a === void 0 ? void 0 : _a.NET_VERSION) ? _this.options.NET_VERSION : "0.6 626fce9a778df4d4");
|
|
356
360
|
info.AddString(((_b = _this.options) === null || _b === void 0 ? void 0 : _b.password) === undefined ? "" : (_c = _this.options) === null || _c === void 0 ? void 0 : _c.password); // password
|
|
357
|
-
var client_version = new MsgPacker_1.MsgPacker(0, true);
|
|
361
|
+
var client_version = new MsgPacker_1.MsgPacker(0, true, 1);
|
|
358
362
|
client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
|
|
359
363
|
var randomUuid = Buffer.alloc(16);
|
|
360
364
|
crypto_1.randomBytes(16).copy(randomUuid);
|
|
@@ -367,7 +371,7 @@ var Client = /** @class */ (function (_super) {
|
|
|
367
371
|
client_version.AddInt(16003);
|
|
368
372
|
client_version.AddString("DDNet 16.0.3");
|
|
369
373
|
}
|
|
370
|
-
_this.SendMsgEx([client_version, info]
|
|
374
|
+
_this.SendMsgEx([client_version, info]);
|
|
371
375
|
}
|
|
372
376
|
else if (a.toJSON().data[3] == 0x4) {
|
|
373
377
|
// disconnected
|
|
@@ -379,12 +383,13 @@ var Client = /** @class */ (function (_super) {
|
|
|
379
383
|
_this.lastRecvTime = new Date().getTime();
|
|
380
384
|
}
|
|
381
385
|
}
|
|
382
|
-
else
|
|
386
|
+
else {
|
|
383
387
|
_this.lastRecvTime = new Date().getTime();
|
|
388
|
+
}
|
|
384
389
|
var unpacked = _this.Unpack(a);
|
|
385
390
|
unpacked.chunks.forEach(function (a) {
|
|
386
|
-
if (a.flags & 1) { // vital
|
|
387
|
-
if (a.seq === (_this.ack + 1) % (1 << 10)) {
|
|
391
|
+
if (a.flags & 1 && (a.flags !== 15)) { // vital and not connless
|
|
392
|
+
if (a.seq === (_this.ack + 1) % (1 << 10)) { // https://github.com/nobody-mb/twchatonly/blob/master/chatonly.cpp#L237
|
|
388
393
|
_this.ack = a.seq;
|
|
389
394
|
_this.requestResend = false;
|
|
390
395
|
}
|
|
@@ -399,8 +404,6 @@ var Client = /** @class */ (function (_super) {
|
|
|
399
404
|
return;
|
|
400
405
|
}
|
|
401
406
|
_this.requestResend = true;
|
|
402
|
-
// c_flags |= 4; /* resend flag */
|
|
403
|
-
// continue; // take the next chunk in the packet
|
|
404
407
|
}
|
|
405
408
|
}
|
|
406
409
|
});
|
|
@@ -436,9 +439,7 @@ var Client = /** @class */ (function (_super) {
|
|
|
436
439
|
var num_parts_1 = 1;
|
|
437
440
|
var part_1 = 0;
|
|
438
441
|
if (chunk.msg === "SNAP") {
|
|
439
|
-
// chunk.raw = Buffer.from(unpackInt(chunk?.raw?.toJSON().data).remaining); // delta tick
|
|
440
442
|
num_parts_1 = unpacker.unpackInt();
|
|
441
|
-
// chunk.raw = Buffer.from(unpackInt(chunk?.raw?.toJSON().data).remaining); // num parts
|
|
442
443
|
part_1 = unpacker.unpackInt();
|
|
443
444
|
}
|
|
444
445
|
var crc = 0;
|
|
@@ -482,36 +483,39 @@ var Client = /** @class */ (function (_super) {
|
|
|
482
483
|
}
|
|
483
484
|
});
|
|
484
485
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
unpacked.victim = { ClientInfo: _this.client_info(unpacked.victim_id), PlayerInfo: _this.player_info(unpacked.victim_id) };
|
|
497
|
-
}
|
|
498
|
-
if (unpacked.killer_id != -1 && unpacked.killer_id < 64)
|
|
499
|
-
unpacked.killer = { ClientInfo: _this.client_info(unpacked.killer_id), PlayerInfo: _this.player_info(unpacked.killer_id) };
|
|
500
|
-
_this.emit("kill", unpacked);
|
|
486
|
+
var chat = unpacked.chunks.filter(function (a) { return a.msg == "SV_KILL_MSG" || a.msg == "SV_MOTD"; });
|
|
487
|
+
chat.forEach(function (a) {
|
|
488
|
+
if (a.msg == "SV_KILL_MSG") {
|
|
489
|
+
var unpacked = {};
|
|
490
|
+
var unpacker = new MsgUnpacker_1.MsgUnpacker(a.raw.toJSON().data);
|
|
491
|
+
unpacked.killer_id = unpacker.unpackInt();
|
|
492
|
+
unpacked.victim_id = unpacker.unpackInt();
|
|
493
|
+
unpacked.weapon = unpacker.unpackInt();
|
|
494
|
+
unpacked.special_mode = unpacker.unpackInt();
|
|
495
|
+
if (unpacked.victim_id != -1 && unpacked.victim_id < 64) {
|
|
496
|
+
unpacked.victim = { ClientInfo: _this.client_info(unpacked.victim_id), PlayerInfo: _this.player_info(unpacked.victim_id) };
|
|
501
497
|
}
|
|
502
|
-
|
|
503
|
-
|
|
498
|
+
if (unpacked.killer_id != -1 && unpacked.killer_id < 64)
|
|
499
|
+
unpacked.killer = { ClientInfo: _this.client_info(unpacked.killer_id), PlayerInfo: _this.player_info(unpacked.killer_id) };
|
|
500
|
+
_this.emit("kill", unpacked);
|
|
501
|
+
}
|
|
502
|
+
else if (a.msg == "SV_MOTD") {
|
|
503
|
+
var unpacker = new MsgUnpacker_1.MsgUnpacker(a.raw.toJSON().data);
|
|
504
|
+
var message = unpacker.unpackString();
|
|
505
|
+
_this.emit("motd", message);
|
|
506
|
+
}
|
|
507
|
+
});
|
|
504
508
|
if (unpacked.chunks[0] && chunkMessages.includes("SV_READY_TO_ENTER")) {
|
|
505
|
-
var Msg = new MsgPacker_1.MsgPacker(15, true); /* entergame */
|
|
506
|
-
_this.SendMsgEx(Msg
|
|
509
|
+
var Msg = new MsgPacker_1.MsgPacker(15, true, 1); /* entergame */
|
|
510
|
+
_this.SendMsgEx(Msg);
|
|
507
511
|
}
|
|
508
512
|
else if ((unpacked.chunks[0] && chunkMessages.includes("CAPABILITIES") || unpacked.chunks[0] && chunkMessages.includes("MAP_CHANGE"))) {
|
|
509
513
|
// send ready
|
|
510
|
-
var Msg = new MsgPacker_1.MsgPacker(14, true); /* ready */
|
|
511
|
-
_this.SendMsgEx(Msg
|
|
514
|
+
var Msg = new MsgPacker_1.MsgPacker(14, true, 1); /* ready */
|
|
515
|
+
_this.SendMsgEx(Msg);
|
|
512
516
|
}
|
|
513
|
-
else if ((unpacked.chunks[0] && chunkMessages.includes("CON_READY")
|
|
514
|
-
var info = new MsgPacker_1.MsgPacker(20, false);
|
|
517
|
+
else if ((unpacked.chunks[0] && chunkMessages.includes("CON_READY"))) {
|
|
518
|
+
var info = new MsgPacker_1.MsgPacker(20, false, 1);
|
|
515
519
|
if ((_g = _this.options) === null || _g === void 0 ? void 0 : _g.identity) {
|
|
516
520
|
info.AddString(_this.options.identity.name);
|
|
517
521
|
info.AddString(_this.options.identity.clan);
|
|
@@ -530,13 +534,13 @@ var Client = /** @class */ (function (_super) {
|
|
|
530
534
|
info.AddInt(10346103); /* color body */
|
|
531
535
|
info.AddInt(65535); /* color feet */
|
|
532
536
|
}
|
|
533
|
-
var crashmeplx = new MsgPacker_1.MsgPacker(17, true); // rcon
|
|
537
|
+
var crashmeplx = new MsgPacker_1.MsgPacker(17, true, 1); // rcon
|
|
534
538
|
crashmeplx.AddString("crashmeplx"); // 64 player support message
|
|
535
|
-
_this.SendMsgEx([info, crashmeplx]
|
|
539
|
+
_this.SendMsgEx([info, crashmeplx]);
|
|
536
540
|
}
|
|
537
541
|
else if (unpacked.chunks[0] && chunkMessages.includes("PING")) {
|
|
538
|
-
var info = new MsgPacker_1.MsgPacker(23, true);
|
|
539
|
-
_this.SendMsgEx(info
|
|
542
|
+
var info = new MsgPacker_1.MsgPacker(23, true, 1);
|
|
543
|
+
_this.SendMsgEx(info);
|
|
540
544
|
}
|
|
541
545
|
if (chunkMessages.includes("SNAP") || chunkMessages.includes("SNAP_EMPTY") || chunkMessages.includes("SNAP_SINGLE")) {
|
|
542
546
|
_this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
|
|
@@ -556,7 +560,7 @@ var Client = /** @class */ (function (_super) {
|
|
|
556
560
|
if (input === void 0) { input = this.movement.input; }
|
|
557
561
|
if (this.State != States.STATE_ONLINE)
|
|
558
562
|
return;
|
|
559
|
-
var inputMsg = new MsgPacker_1.MsgPacker(16, true);
|
|
563
|
+
var inputMsg = new MsgPacker_1.MsgPacker(16, true, 0);
|
|
560
564
|
inputMsg.AddInt(this.AckGameTick);
|
|
561
565
|
inputMsg.AddInt(this.PredGameTick);
|
|
562
566
|
inputMsg.AddInt(40);
|
|
@@ -575,7 +579,7 @@ var Client = /** @class */ (function (_super) {
|
|
|
575
579
|
input_data.forEach(function (a) {
|
|
576
580
|
inputMsg.AddInt(a);
|
|
577
581
|
});
|
|
578
|
-
this.SendMsgEx(inputMsg
|
|
582
|
+
this.SendMsgEx(inputMsg);
|
|
579
583
|
};
|
|
580
584
|
Object.defineProperty(Client.prototype, "input", {
|
|
581
585
|
get: function () {
|
|
@@ -598,18 +602,18 @@ var Client = /** @class */ (function (_super) {
|
|
|
598
602
|
};
|
|
599
603
|
Client.prototype.Say = function (message, team) {
|
|
600
604
|
if (team === void 0) { team = false; }
|
|
601
|
-
var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_SAY, false);
|
|
605
|
+
var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_SAY, false, 1);
|
|
602
606
|
packer.AddInt(team ? 1 : 0); // team
|
|
603
607
|
packer.AddString(message);
|
|
604
|
-
this.
|
|
608
|
+
this.QueueChunkEx(packer);
|
|
605
609
|
};
|
|
606
610
|
Client.prototype.Vote = function (vote) {
|
|
607
|
-
var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_VOTE, false);
|
|
608
|
-
packer.AddInt(vote ? 1 :
|
|
609
|
-
this.
|
|
611
|
+
var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_VOTE, false, 1);
|
|
612
|
+
packer.AddInt(vote ? 1 : -1);
|
|
613
|
+
this.QueueChunkEx(packer);
|
|
610
614
|
};
|
|
611
615
|
Client.prototype.ChangePlayerInfo = function (playerInfo) {
|
|
612
|
-
var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_CHANGEINFO, false);
|
|
616
|
+
var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_CHANGEINFO, false, 1);
|
|
613
617
|
packer.AddString(playerInfo.name); //m_pName);
|
|
614
618
|
packer.AddString(playerInfo.clan); //m_pClan);
|
|
615
619
|
packer.AddInt(playerInfo.country); //m_Country);
|
|
@@ -617,21 +621,21 @@ var Client = /** @class */ (function (_super) {
|
|
|
617
621
|
packer.AddInt(playerInfo.use_custom_color ? 1 : 0); //m_UseCustomColor);
|
|
618
622
|
packer.AddInt(playerInfo.color_body); //m_ColorBody);
|
|
619
623
|
packer.AddInt(playerInfo.color_feet); //m_ColorFeet);
|
|
620
|
-
this.
|
|
624
|
+
this.QueueChunkEx(packer);
|
|
621
625
|
};
|
|
622
626
|
Client.prototype.Kill = function () {
|
|
623
|
-
var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_KILL, false);
|
|
624
|
-
this.
|
|
627
|
+
var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_KILL, false, 1);
|
|
628
|
+
this.QueueChunkEx(packer);
|
|
625
629
|
};
|
|
626
630
|
Client.prototype.ChangeTeam = function (team) {
|
|
627
|
-
var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_SETTEAM, false);
|
|
631
|
+
var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_SETTEAM, false, 1);
|
|
628
632
|
packer.AddInt(team);
|
|
629
|
-
this.
|
|
633
|
+
this.QueueChunkEx(packer);
|
|
630
634
|
};
|
|
631
635
|
Client.prototype.Emote = function (emote) {
|
|
632
|
-
var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_EMOTICON, false);
|
|
636
|
+
var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_EMOTICON, false, 1);
|
|
633
637
|
packer.AddInt(emote);
|
|
634
|
-
this.
|
|
638
|
+
this.QueueChunkEx(packer);
|
|
635
639
|
};
|
|
636
640
|
Client.prototype.client_info = function (id) {
|
|
637
641
|
var delta = this.SnapUnpacker.deltas.filter(function (a) {
|
package/lib/client.ts
CHANGED
|
@@ -184,6 +184,8 @@ export declare interface Client {
|
|
|
184
184
|
on(event: 'message', listener: (message: iMessage) => void): this;
|
|
185
185
|
on(event: 'broadcast', listener: (message: string) => void): this;
|
|
186
186
|
on(event: 'kill', listener: (kill: iKillMsg) => void): this;
|
|
187
|
+
on(event: 'motd', listener: (message: string) => void): this;
|
|
188
|
+
|
|
187
189
|
requestResend: boolean;
|
|
188
190
|
}
|
|
189
191
|
|
|
@@ -235,19 +237,22 @@ export class Client extends EventEmitter {
|
|
|
235
237
|
|
|
236
238
|
ResendAfter(lastAck: number) {
|
|
237
239
|
this.clientAck = lastAck;
|
|
240
|
+
|
|
241
|
+
|
|
238
242
|
let toResend: MsgPacker[] = [];
|
|
239
243
|
this.lastSentMessages.forEach(msg => {
|
|
240
244
|
if (msg.ack > lastAck)
|
|
241
245
|
toResend.push(msg.msg);
|
|
242
246
|
});
|
|
243
|
-
|
|
247
|
+
toResend.forEach(a => a.flag = 1|2);
|
|
248
|
+
this.SendMsgEx(toResend);
|
|
244
249
|
}
|
|
245
250
|
|
|
246
251
|
Unpack(packet: Buffer): _packet {
|
|
247
252
|
var unpacked: _packet = { twprotocol: { flags: packet[0] >> 4, ack: ((packet[0]&0xf)<<8) | packet[1], chunkAmount: packet[2], size: packet.byteLength - 3 }, chunks: [] }
|
|
248
253
|
|
|
249
254
|
|
|
250
|
-
if (packet.indexOf(Buffer.from([0xff, 0xff, 0xff, 0xff])) == 0
|
|
255
|
+
if (packet.indexOf(Buffer.from([0xff, 0xff, 0xff, 0xff])) == 0 )// !(unpacked.twprotocol.flags & 8) || unpacked.twprotocol.flags == 255) // flags == 255 is connectionless (used for sending usernames)
|
|
251
256
|
return unpacked;
|
|
252
257
|
if (unpacked.twprotocol.flags & 4) { // resend flag
|
|
253
258
|
this.ResendAfter(unpacked.twprotocol.ack);
|
|
@@ -307,7 +312,7 @@ export class Client extends EventEmitter {
|
|
|
307
312
|
})
|
|
308
313
|
}
|
|
309
314
|
|
|
310
|
-
SendMsgEx(Msgs: MsgPacker[] | MsgPacker
|
|
315
|
+
SendMsgEx(Msgs: MsgPacker[] | MsgPacker) {
|
|
311
316
|
if (this.State == States.STATE_OFFLINE)
|
|
312
317
|
return;
|
|
313
318
|
if (!this.socket)
|
|
@@ -326,20 +331,20 @@ export class Client extends EventEmitter {
|
|
|
326
331
|
if (this.clientAck == 0)
|
|
327
332
|
this.lastSentMessages = [];
|
|
328
333
|
_Msgs.forEach((Msg: MsgPacker, index) => {
|
|
329
|
-
header[index] = Buffer.alloc((
|
|
330
|
-
header[index][0] = ((
|
|
334
|
+
header[index] = Buffer.alloc((Msg.flag & 1 ? 3 : 2));
|
|
335
|
+
header[index][0] = ((Msg.flag & 3) << 6) | ((Msg.size >> 4) & 0x3f);
|
|
331
336
|
header[index][1] = (Msg.size & 0xf);
|
|
332
|
-
if (
|
|
337
|
+
if (Msg.flag & 1) {
|
|
333
338
|
this.clientAck = (this.clientAck + 1) % (1 << 10);
|
|
334
339
|
if (this.clientAck == 0)
|
|
335
340
|
this.lastSentMessages = [];
|
|
336
341
|
header[index][1] |= (this.clientAck >> 2) & 0xf0;
|
|
337
342
|
header[index][2] = this.clientAck & 0xff;
|
|
338
|
-
header[index][0] = (((
|
|
339
|
-
if ((
|
|
343
|
+
header[index][0] = (((Msg.flag | 2)&3)<<6)|((Msg.size>>4)&0x3f); // 2 is resend flag (ugly hack for queue)
|
|
344
|
+
if ((Msg.flag & 2) == 0)
|
|
340
345
|
this.sentChunkQueue.push(Buffer.concat([header[index], Msg.buffer]));
|
|
341
|
-
header[index][0] = (((
|
|
342
|
-
if ((
|
|
346
|
+
header[index][0] = (((Msg.flag)&3)<<6)|((Msg.size>>4)&0x3f);
|
|
347
|
+
if ((Msg.flag & 2) == 0)
|
|
343
348
|
this.lastSentMessages.push({msg: Msg, ack: this.clientAck})
|
|
344
349
|
}
|
|
345
350
|
})
|
|
@@ -357,11 +362,12 @@ export class Client extends EventEmitter {
|
|
|
357
362
|
chunks = Buffer.concat([chunks, Buffer.from(header[index]), Msg.buffer]);
|
|
358
363
|
else {
|
|
359
364
|
skip = true;
|
|
360
|
-
this.SendMsgEx(_Msgs.slice(index)
|
|
365
|
+
this.SendMsgEx(_Msgs.slice(index));
|
|
361
366
|
}
|
|
362
367
|
})
|
|
363
368
|
var packet = Buffer.concat([(packetHeader), chunks, this.TKEN]);
|
|
364
|
-
|
|
369
|
+
if (chunks.length < 0)
|
|
370
|
+
return;
|
|
365
371
|
this.socket.send(packet, 0, packet.length, this.port, this.host)
|
|
366
372
|
}
|
|
367
373
|
|
|
@@ -380,7 +386,8 @@ export class Client extends EventEmitter {
|
|
|
380
386
|
var packetHeader = Buffer.from([0x0+(((16<<4)&0xf0)|((this.ack>>8)&0xf)), this.ack&0xff, chunks.length]);
|
|
381
387
|
|
|
382
388
|
var packet = Buffer.concat([(packetHeader), Buffer.concat(chunks), this.TKEN]);
|
|
383
|
-
|
|
389
|
+
if (chunks.length < 0)
|
|
390
|
+
return;
|
|
384
391
|
this.socket.send(packet, 0, packet.length, this.port, this.host)
|
|
385
392
|
}
|
|
386
393
|
|
|
@@ -471,11 +478,11 @@ export class Client extends EventEmitter {
|
|
|
471
478
|
this.State = States.STATE_LOADING; // loading state
|
|
472
479
|
this.receivedSnaps = 0;
|
|
473
480
|
|
|
474
|
-
var info = new MsgPacker(1, true);
|
|
481
|
+
var info = new MsgPacker(1, true, 1);
|
|
475
482
|
info.AddString(this.options?.NET_VERSION ? this.options.NET_VERSION : "0.6 626fce9a778df4d4");
|
|
476
483
|
info.AddString(this.options?.password === undefined ? "" : this.options?.password); // password
|
|
477
484
|
|
|
478
|
-
var client_version = new MsgPacker(0, true);
|
|
485
|
+
var client_version = new MsgPacker(0, true, 1);
|
|
479
486
|
client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
|
|
480
487
|
let randomUuid = Buffer.alloc(16);
|
|
481
488
|
|
|
@@ -490,7 +497,7 @@ export class Client extends EventEmitter {
|
|
|
490
497
|
client_version.AddString("DDNet 16.0.3");
|
|
491
498
|
}
|
|
492
499
|
|
|
493
|
-
this.SendMsgEx([client_version, info]
|
|
500
|
+
this.SendMsgEx([client_version, info])
|
|
494
501
|
} else if (a.toJSON().data[3] == 0x4) {
|
|
495
502
|
// disconnected
|
|
496
503
|
this.State = States.STATE_OFFLINE;
|
|
@@ -500,15 +507,18 @@ export class Client extends EventEmitter {
|
|
|
500
507
|
if (a.toJSON().data[3] !== 0x0) { // keepalive
|
|
501
508
|
this.lastRecvTime = new Date().getTime();
|
|
502
509
|
}
|
|
503
|
-
} else
|
|
510
|
+
} else {
|
|
504
511
|
this.lastRecvTime = new Date().getTime();
|
|
505
512
|
|
|
513
|
+
}
|
|
514
|
+
|
|
506
515
|
|
|
507
|
-
var unpacked: _packet = this.Unpack(a)
|
|
516
|
+
var unpacked: _packet = this.Unpack(a);
|
|
508
517
|
unpacked.chunks.forEach(a => {
|
|
509
|
-
if (a.flags & 1) { // vital
|
|
510
|
-
if (a.seq === (this.ack+1)%(1<<10)) {
|
|
511
|
-
this.ack = a.seq
|
|
518
|
+
if (a.flags & 1 && (a.flags !== 15)) { // vital and not connless
|
|
519
|
+
if (a.seq === (this.ack+1)%(1<<10)) { // https://github.com/nobody-mb/twchatonly/blob/master/chatonly.cpp#L237
|
|
520
|
+
this.ack = a.seq!;
|
|
521
|
+
|
|
512
522
|
this.requestResend = false;
|
|
513
523
|
}
|
|
514
524
|
else { //IsSeqInBackroom (old packet that we already got)
|
|
@@ -522,11 +532,10 @@ export class Client extends EventEmitter {
|
|
|
522
532
|
return;
|
|
523
533
|
}
|
|
524
534
|
this.requestResend = true;
|
|
525
|
-
// c_flags |= 4; /* resend flag */
|
|
526
|
-
// continue; // take the next chunk in the packet
|
|
527
535
|
|
|
528
536
|
}
|
|
529
537
|
}
|
|
538
|
+
|
|
530
539
|
})
|
|
531
540
|
unpacked.chunks.filter(a => a.msgid == NETMSGTYPE.SV_BROADCAST && a.type == 'game').forEach(a => {
|
|
532
541
|
let unpacker = new MsgUnpacker(a.raw.toJSON().data);
|
|
@@ -564,9 +573,7 @@ export class Client extends EventEmitter {
|
|
|
564
573
|
let part = 0;
|
|
565
574
|
|
|
566
575
|
if (chunk.msg === "SNAP") {
|
|
567
|
-
// chunk.raw = Buffer.from(unpackInt(chunk?.raw?.toJSON().data).remaining); // delta tick
|
|
568
576
|
num_parts = unpacker.unpackInt();
|
|
569
|
-
// chunk.raw = Buffer.from(unpackInt(chunk?.raw?.toJSON().data).remaining); // num parts
|
|
570
577
|
part = unpacker.unpackInt();
|
|
571
578
|
}
|
|
572
579
|
|
|
@@ -617,8 +624,7 @@ export class Client extends EventEmitter {
|
|
|
617
624
|
}
|
|
618
625
|
})
|
|
619
626
|
}
|
|
620
|
-
|
|
621
|
-
var chat = unpacked.chunks.filter(a => a.msg == "SV_KILL_MSG");
|
|
627
|
+
var chat = unpacked.chunks.filter(a => a.msg == "SV_KILL_MSG" || a.msg == "SV_MOTD");
|
|
622
628
|
chat.forEach(a => {
|
|
623
629
|
if (a.msg == "SV_KILL_MSG") {
|
|
624
630
|
var unpacked: iKillMsg = {} as iKillMsg;
|
|
@@ -634,19 +640,22 @@ export class Client extends EventEmitter {
|
|
|
634
640
|
if (unpacked.killer_id != -1 && unpacked.killer_id < 64)
|
|
635
641
|
unpacked.killer = { ClientInfo: this.client_info(unpacked.killer_id), PlayerInfo: this.player_info(unpacked.killer_id) }
|
|
636
642
|
this.emit("kill", unpacked)
|
|
643
|
+
} else if (a.msg == "SV_MOTD") {
|
|
644
|
+
let unpacker = new MsgUnpacker(a.raw.toJSON().data);
|
|
645
|
+
let message = unpacker.unpackString();
|
|
646
|
+
this.emit("motd", message);
|
|
637
647
|
}
|
|
638
648
|
})
|
|
639
|
-
}
|
|
640
649
|
|
|
641
650
|
if (unpacked.chunks[0] && chunkMessages.includes("SV_READY_TO_ENTER")) {
|
|
642
|
-
var Msg = new MsgPacker(15, true); /* entergame */
|
|
643
|
-
this.SendMsgEx(Msg
|
|
651
|
+
var Msg = new MsgPacker(15, true, 1); /* entergame */
|
|
652
|
+
this.SendMsgEx(Msg);
|
|
644
653
|
} else if ((unpacked.chunks[0] && chunkMessages.includes("CAPABILITIES") || unpacked.chunks[0] && chunkMessages.includes("MAP_CHANGE"))) {
|
|
645
654
|
// send ready
|
|
646
|
-
var Msg = new MsgPacker(14, true); /* ready */
|
|
647
|
-
this.SendMsgEx(Msg
|
|
648
|
-
} else if ((unpacked.chunks[0] && chunkMessages.includes("CON_READY")
|
|
649
|
-
var info = new MsgPacker(20, false);
|
|
655
|
+
var Msg = new MsgPacker(14, true, 1); /* ready */
|
|
656
|
+
this.SendMsgEx(Msg);
|
|
657
|
+
} else if ((unpacked.chunks[0] && chunkMessages.includes("CON_READY"))) {
|
|
658
|
+
var info = new MsgPacker(20, false, 1);
|
|
650
659
|
if (this.options?.identity) {
|
|
651
660
|
info.AddString(this.options.identity.name);
|
|
652
661
|
info.AddString(this.options.identity.clan);
|
|
@@ -665,15 +674,15 @@ export class Client extends EventEmitter {
|
|
|
665
674
|
info.AddInt(65535); /* color feet */
|
|
666
675
|
|
|
667
676
|
}
|
|
668
|
-
var crashmeplx = new MsgPacker(17, true); // rcon
|
|
677
|
+
var crashmeplx = new MsgPacker(17, true, 1); // rcon
|
|
669
678
|
crashmeplx.AddString("crashmeplx"); // 64 player support message
|
|
670
|
-
this.SendMsgEx([info, crashmeplx]
|
|
679
|
+
this.SendMsgEx([info, crashmeplx]);
|
|
671
680
|
|
|
672
681
|
|
|
673
682
|
|
|
674
683
|
} else if (unpacked.chunks[0] && chunkMessages.includes("PING")) {
|
|
675
|
-
var info = new MsgPacker(23, true);
|
|
676
|
-
this.SendMsgEx(info
|
|
684
|
+
var info = new MsgPacker(23, true, 1);
|
|
685
|
+
this.SendMsgEx(info)
|
|
677
686
|
}
|
|
678
687
|
if (chunkMessages.includes("SNAP") || chunkMessages.includes("SNAP_EMPTY") || chunkMessages.includes("SNAP_SINGLE")) {
|
|
679
688
|
this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
|
|
@@ -695,7 +704,7 @@ export class Client extends EventEmitter {
|
|
|
695
704
|
if (this.State != States.STATE_ONLINE)
|
|
696
705
|
return;
|
|
697
706
|
|
|
698
|
-
let inputMsg = new MsgPacker(16, true);
|
|
707
|
+
let inputMsg = new MsgPacker(16, true, 0);
|
|
699
708
|
inputMsg.AddInt(this.AckGameTick);
|
|
700
709
|
inputMsg.AddInt(this.PredGameTick);
|
|
701
710
|
inputMsg.AddInt(40);
|
|
@@ -716,7 +725,7 @@ export class Client extends EventEmitter {
|
|
|
716
725
|
input_data.forEach(a => {
|
|
717
726
|
inputMsg.AddInt(a);
|
|
718
727
|
});
|
|
719
|
-
this.SendMsgEx(inputMsg
|
|
728
|
+
this.SendMsgEx(inputMsg);
|
|
720
729
|
}
|
|
721
730
|
get input() {
|
|
722
731
|
return this.movement.input;
|
|
@@ -735,18 +744,18 @@ export class Client extends EventEmitter {
|
|
|
735
744
|
}
|
|
736
745
|
|
|
737
746
|
Say(message: string, team = false) {
|
|
738
|
-
var packer = new MsgPacker(NETMSGTYPE.CL_SAY, false);
|
|
747
|
+
var packer = new MsgPacker(NETMSGTYPE.CL_SAY, false, 1);
|
|
739
748
|
packer.AddInt(team ? 1 : 0); // team
|
|
740
749
|
packer.AddString(message);
|
|
741
|
-
this.
|
|
750
|
+
this.QueueChunkEx(packer);
|
|
742
751
|
}
|
|
743
752
|
Vote(vote: boolean) {
|
|
744
|
-
var packer = new MsgPacker(NETMSGTYPE.CL_VOTE, false);
|
|
745
|
-
packer.AddInt(vote ? 1 :
|
|
746
|
-
this.
|
|
753
|
+
var packer = new MsgPacker(NETMSGTYPE.CL_VOTE, false, 1);
|
|
754
|
+
packer.AddInt(vote ? 1 : -1);
|
|
755
|
+
this.QueueChunkEx(packer);
|
|
747
756
|
}
|
|
748
757
|
ChangePlayerInfo(playerInfo: ClientInfo) {
|
|
749
|
-
var packer = new MsgPacker(NETMSGTYPE.CL_CHANGEINFO, false);
|
|
758
|
+
var packer = new MsgPacker(NETMSGTYPE.CL_CHANGEINFO, false, 1);
|
|
750
759
|
packer.AddString(playerInfo.name); //m_pName);
|
|
751
760
|
packer.AddString(playerInfo.clan); //m_pClan);
|
|
752
761
|
packer.AddInt(playerInfo.country); //m_Country);
|
|
@@ -754,21 +763,21 @@ export class Client extends EventEmitter {
|
|
|
754
763
|
packer.AddInt(playerInfo.use_custom_color ? 1 : 0); //m_UseCustomColor);
|
|
755
764
|
packer.AddInt(playerInfo.color_body); //m_ColorBody);
|
|
756
765
|
packer.AddInt(playerInfo.color_feet); //m_ColorFeet);
|
|
757
|
-
this.
|
|
766
|
+
this.QueueChunkEx(packer);
|
|
758
767
|
}
|
|
759
768
|
Kill() {
|
|
760
|
-
var packer = new MsgPacker(NETMSGTYPE.CL_KILL, false);
|
|
761
|
-
this.
|
|
769
|
+
var packer = new MsgPacker(NETMSGTYPE.CL_KILL, false, 1);
|
|
770
|
+
this.QueueChunkEx(packer);
|
|
762
771
|
}
|
|
763
772
|
ChangeTeam(team: number) {
|
|
764
|
-
var packer = new MsgPacker(NETMSGTYPE.CL_SETTEAM, false);
|
|
773
|
+
var packer = new MsgPacker(NETMSGTYPE.CL_SETTEAM, false, 1);
|
|
765
774
|
packer.AddInt(team);
|
|
766
|
-
this.
|
|
775
|
+
this.QueueChunkEx(packer);
|
|
767
776
|
}
|
|
768
777
|
Emote(emote: number) {
|
|
769
|
-
var packer = new MsgPacker(NETMSGTYPE.CL_EMOTICON, false);
|
|
778
|
+
var packer = new MsgPacker(NETMSGTYPE.CL_EMOTICON, false, 1);
|
|
770
779
|
packer.AddInt(emote);
|
|
771
|
-
this.
|
|
780
|
+
this.QueueChunkEx(packer);
|
|
772
781
|
}
|
|
773
782
|
client_info(id: number) {
|
|
774
783
|
let delta = this.SnapUnpacker.deltas.filter(a =>
|