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