teeworlds 2.4.5 → 2.4.8

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/client.js CHANGED
@@ -23,12 +23,14 @@ var crypto_1 = require("crypto");
23
23
  var dgram_1 = __importDefault(require("dgram"));
24
24
  var stream_1 = require("stream");
25
25
  var MsgUnpacker_1 = require("./MsgUnpacker");
26
+ var version = require('../package.json').version;
26
27
  var movement_1 = __importDefault(require("./components/movement"));
27
28
  var MsgPacker_1 = require("./MsgPacker");
28
29
  var snapshot_1 = require("./snapshot");
29
30
  var huffman_1 = __importDefault(require("./huffman"));
30
31
  var game_1 = require("./components/game");
31
32
  var snapshot_2 = require("./components/snapshot");
33
+ var UUIDManager_1 = require("./UUIDManager");
32
34
  var huff = new huffman_1.default();
33
35
  var States;
34
36
  (function (States) {
@@ -112,20 +114,23 @@ var NETMSG_Sys;
112
114
  NETMSG_Sys[NETMSG_Sys["NETMSG_RCON_CMD_ADD"] = 25] = "NETMSG_RCON_CMD_ADD";
113
115
  NETMSG_Sys[NETMSG_Sys["NETMSG_RCON_CMD_REM"] = 26] = "NETMSG_RCON_CMD_REM";
114
116
  NETMSG_Sys[NETMSG_Sys["NUM_NETMSGS"] = 27] = "NUM_NETMSGS";
117
+ NETMSG_Sys[NETMSG_Sys["NETMSG_WHATIS"] = 65536] = "NETMSG_WHATIS";
118
+ NETMSG_Sys[NETMSG_Sys["NETMSG_ITIS"] = 65537] = "NETMSG_ITIS";
119
+ NETMSG_Sys[NETMSG_Sys["NETMSG_IDONTKNOW"] = 65538] = "NETMSG_IDONTKNOW";
120
+ NETMSG_Sys[NETMSG_Sys["NETMSG_RCONTYPE"] = 65539] = "NETMSG_RCONTYPE";
121
+ NETMSG_Sys[NETMSG_Sys["NETMSG_MAP_DETAILS"] = 65540] = "NETMSG_MAP_DETAILS";
122
+ NETMSG_Sys[NETMSG_Sys["NETMSG_CAPABILITIES"] = 65541] = "NETMSG_CAPABILITIES";
123
+ NETMSG_Sys[NETMSG_Sys["NETMSG_CLIENTVER"] = 65542] = "NETMSG_CLIENTVER";
124
+ NETMSG_Sys[NETMSG_Sys["NETMSG_PINGEX"] = 65543] = "NETMSG_PINGEX";
125
+ NETMSG_Sys[NETMSG_Sys["NETMSG_PONGEX"] = 65544] = "NETMSG_PONGEX";
126
+ NETMSG_Sys[NETMSG_Sys["NETMSG_CHECKSUM_REQUEST"] = 65545] = "NETMSG_CHECKSUM_REQUEST";
127
+ NETMSG_Sys[NETMSG_Sys["NETMSG_CHECKSUM_RESPONSE"] = 65546] = "NETMSG_CHECKSUM_RESPONSE";
128
+ NETMSG_Sys[NETMSG_Sys["NETMSG_CHECKSUM_ERROR"] = 65547] = "NETMSG_CHECKSUM_ERROR";
115
129
  })(NETMSG_Sys || (NETMSG_Sys = {}));
116
130
  var messageTypes = [
117
131
  ["none, starts at 1", "SV_MOTD", "SV_BROADCAST", "SV_CHAT", "SV_KILL_MSG", "SV_SOUND_GLOBAL", "SV_TUNE_PARAMS", "SV_EXTRA_PROJECTILE", "SV_READY_TO_ENTER", "SV_WEAPON_PICKUP", "SV_EMOTICON", "SV_VOTE_CLEAR_OPTIONS", "SV_VOTE_OPTION_LIST_ADD", "SV_VOTE_OPTION_ADD", "SV_VOTE_OPTION_REMOVE", "SV_VOTE_SET", "SV_VOTE_STATUS", "CL_SAY", "CL_SET_TEAM", "CL_SET_SPECTATOR_MODE", "CL_START_INFO", "CL_CHANGE_INFO", "CL_KILL", "CL_EMOTICON", "CL_VOTE", "CL_CALL_VOTE", "CL_IS_DDNET", "SV_DDRACE_TIME", "SV_RECORD", "UNUSED", "SV_TEAMS_STATE", "CL_SHOW_OTHERS_LEGACY"],
118
132
  ["none, starts at 1", "INFO", "MAP_CHANGE", "MAP_DATA", "CON_READY", "SNAP", "SNAP_EMPTY", "SNAP_SINGLE", "INPUT_TIMING", "RCON_AUTH_STATUS", "RCON_LINE", "READY", "ENTER_GAME", "INPUT", "RCON_CMD", "RCON_AUTH", "REQUEST_MAP_DATA", "PING", "PING_REPLY", "RCON_CMD_ADD", "RCON_CMD_REMOVE"]
119
133
  ];
120
- var messageUUIDs = {
121
- "WHAT_IS": Buffer.from([0x24, 0x5e, 0x50, 0x97, 0x9f, 0xe0, 0x39, 0xd6, 0xbf, 0x7d, 0x9a, 0x29, 0xe1, 0x69, 0x1e, 0x4c]),
122
- "IT_IS": Buffer.from([0x69, 0x54, 0x84, 0x7e, 0x2e, 0x87, 0x36, 0x03, 0xb5, 0x62, 0x36, 0xda, 0x29, 0xed, 0x1a, 0xca]),
123
- "I_DONT_KNOW": Buffer.from([0x41, 0x69, 0x11, 0xb5, 0x79, 0x73, 0x33, 0xbf, 0x8d, 0x52, 0x7b, 0xf0, 0x1e, 0x51, 0x9c, 0xf0]),
124
- "RCON_TYPE": Buffer.from([0x12, 0x81, 0x0e, 0x1f, 0xa1, 0xdb, 0x33, 0x78, 0xb4, 0xfb, 0x16, 0x4e, 0xd6, 0x50, 0x59, 0x26]),
125
- "MAP_DETAILS": Buffer.from([0xf9, 0x11, 0x7b, 0x3c, 0x80, 0x39, 0x34, 0x16, 0x9f, 0xc0, 0xae, 0xf2, 0xbc, 0xb7, 0x5c, 0x03]),
126
- "CLIENT_VERSION": Buffer.from([0x8c, 0x00, 0x13, 0x04, 0x84, 0x61, 0x3e, 0x47, 0x87, 0x87, 0xf6, 0x72, 0xb3, 0x83, 0x5b, 0xd4]),
127
- "CAPABILITIES": Buffer.from([0xf6, 0x21, 0xa5, 0xa1, 0xf5, 0x85, 0x37, 0x75, 0x8e, 0x73, 0x41, 0xbe, 0xee, 0x79, 0xf2, 0xb2]),
128
- };
129
134
  var Client = /** @class */ (function (_super) {
130
135
  __extends(Client, _super);
131
136
  function Client(ip, port, nickname, options) {
@@ -160,6 +165,19 @@ var Client = /** @class */ (function (_super) {
160
165
  _this.movement = new movement_1.default();
161
166
  _this.game = new game_1.Game(_this);
162
167
  _this.SnapshotUnpacker = new snapshot_2.SnapshotWrapper(_this);
168
+ _this.UUIDManager = new UUIDManager_1.UUIDManager();
169
+ _this.UUIDManager.RegisterName("what-is@ddnet.tw", NETMSG_Sys.NETMSG_WHATIS);
170
+ _this.UUIDManager.RegisterName("it-is@ddnet.tw", NETMSG_Sys.NETMSG_ITIS);
171
+ _this.UUIDManager.RegisterName("i-dont-know@ddnet.tw", NETMSG_Sys.NETMSG_IDONTKNOW);
172
+ _this.UUIDManager.RegisterName("rcon-type@ddnet.tw", NETMSG_Sys.NETMSG_RCONTYPE);
173
+ _this.UUIDManager.RegisterName("map-details@ddnet.tw", NETMSG_Sys.NETMSG_MAP_DETAILS);
174
+ _this.UUIDManager.RegisterName("capabilities@ddnet.tw", NETMSG_Sys.NETMSG_CAPABILITIES);
175
+ _this.UUIDManager.RegisterName("clientver@ddnet.tw", NETMSG_Sys.NETMSG_CLIENTVER);
176
+ _this.UUIDManager.RegisterName("ping@ddnet.tw", NETMSG_Sys.NETMSG_PING);
177
+ _this.UUIDManager.RegisterName("pong@ddnet.tw", NETMSG_Sys.NETMSG_PONGEX);
178
+ _this.UUIDManager.RegisterName("checksum-request@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_REQUEST);
179
+ _this.UUIDManager.RegisterName("checksum-response@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_RESPONSE);
180
+ _this.UUIDManager.RegisterName("checksum-error@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_ERROR);
163
181
  return _this;
164
182
  }
165
183
  Client.prototype.ResendAfter = function (lastAck) {
@@ -201,12 +219,15 @@ var Client = /** @class */ (function (_super) {
201
219
  chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
202
220
  chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
203
221
  chunk.raw = packet.slice(1, chunk.bytes);
204
- Object.values(messageUUIDs).forEach(function (a, i) {
205
- if (a.byteLength >= 16 && a.compare(packet.slice(0, 16)) == 0) {
206
- chunk.extended_msgid = a;
207
- chunk.msg = Object.keys(messageUUIDs)[i];
222
+ if (chunk.msgid == 0 && chunk.raw.byteLength >= 16) {
223
+ var uuid = this.UUIDManager.LookupUUID(chunk.raw.slice(0, 16));
224
+ if (uuid !== undefined) {
225
+ chunk.extended_msgid = uuid.hash;
226
+ chunk.msg = uuid.name;
227
+ chunk.raw = chunk.raw.slice(16);
228
+ chunk.msgid = uuid.type_id;
208
229
  }
209
- });
230
+ }
210
231
  packet = packet.slice(chunk.bytes);
211
232
  unpacked.chunks.push(chunk);
212
233
  }
@@ -233,8 +254,9 @@ var Client = /** @class */ (function (_super) {
233
254
  });
234
255
  };
235
256
  /** Send a Msg (or Msg[]) to the server.*/
236
- Client.prototype.SendMsgEx = function (Msgs) {
257
+ Client.prototype.SendMsgEx = function (Msgs, flags) {
237
258
  var _this = this;
259
+ if (flags === void 0) { flags = 0; }
238
260
  if (this.State == States.STATE_OFFLINE)
239
261
  return;
240
262
  if (!this.socket)
@@ -270,7 +292,7 @@ var Client = /** @class */ (function (_super) {
270
292
  _this.lastSentMessages.push({ msg: Msg, ack: _this.clientAck });
271
293
  }
272
294
  });
273
- var flags = 0;
295
+ // let flags = 0;
274
296
  if (this.requestResend)
275
297
  flags |= 4;
276
298
  var packetHeader = Buffer.from([((flags << 4) & 0xf0) | ((this.ack >> 8) & 0xf), this.ack & 0xff, _Msgs.length]);
@@ -324,12 +346,15 @@ var Client = /** @class */ (function (_super) {
324
346
  chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
325
347
  chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
326
348
  chunk.raw = packet.slice(1, chunk.bytes);
327
- Object.values(messageUUIDs).forEach(function (a, i) {
328
- if (a.byteLength >= 16 && a.compare(packet.slice(0, 16)) === 0) {
329
- chunk.extended_msgid = a;
330
- chunk.msg = Object.keys(messageUUIDs)[i];
349
+ if (chunk.msgid == 0) {
350
+ var uuid = this.UUIDManager.LookupUUID(chunk.raw.slice(0, 16));
351
+ if (uuid !== undefined) {
352
+ chunk.extended_msgid = uuid.hash;
353
+ chunk.msgid = uuid.type_id;
354
+ chunk.msg = uuid.name;
355
+ chunk.raw = chunk.raw.slice(16);
331
356
  }
332
- });
357
+ }
333
358
  return chunk;
334
359
  };
335
360
  /** Connect the client to the server. */
@@ -344,7 +369,7 @@ var Client = /** @class */ (function (_super) {
344
369
  }
345
370
  else if (_this.State == States.STATE_OFFLINE)
346
371
  clearInterval(predTimer);
347
- }, 20);
372
+ }, 1000 / 50); // 50 ticks per second
348
373
  this.SendControlMsg(1, "TKEN");
349
374
  var connectInterval = setInterval(function () {
350
375
  if (_this.State == States.STATE_CONNECTING)
@@ -360,7 +385,7 @@ var Client = /** @class */ (function (_super) {
360
385
  return;
361
386
  _this.time = new Date().getTime();
362
387
  _this.sendInput();
363
- }, 500);
388
+ }, 50);
364
389
  }
365
390
  var resendTimeout = setInterval(function () {
366
391
  if (_this.State != States.STATE_OFFLINE) {
@@ -400,16 +425,15 @@ var Client = /** @class */ (function (_super) {
400
425
  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
401
426
  var client_version = new MsgPacker_1.MsgPacker(0, true, 1);
402
427
  client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
403
- var randomUuid = Buffer.allocUnsafe(16);
404
- (0, crypto_1.randomBytes)(16).copy(randomUuid);
428
+ var randomUuid = (0, crypto_1.randomBytes)(16);
405
429
  client_version.AddBuffer(randomUuid);
406
430
  if (((_d = _this.options) === null || _d === void 0 ? void 0 : _d.ddnet_version) !== undefined) {
407
431
  client_version.AddInt((_e = _this.options) === null || _e === void 0 ? void 0 : _e.ddnet_version.version);
408
- client_version.AddString("DDNet " + ((_f = _this.options) === null || _f === void 0 ? void 0 : _f.ddnet_version.release_version));
432
+ client_version.AddString("DDNet ".concat((_f = _this.options) === null || _f === void 0 ? void 0 : _f.ddnet_version.release_version, "; https://www.npmjs.com/package/teeworlds/v/").concat(version));
409
433
  }
410
434
  else {
411
- client_version.AddInt(16003);
412
- client_version.AddString("DDNet 16.0.3");
435
+ client_version.AddInt(16050);
436
+ client_version.AddString("DDNet 16.5.0; https://www.npmjs.com/package/teeworlds/v/".concat(version));
413
437
  }
414
438
  _this.SendMsgEx([client_version, info]);
415
439
  }
@@ -541,13 +565,85 @@ var Client = /** @class */ (function (_super) {
541
565
  var snapUnpacked = _this.SnapUnpacker.unpackSnapshot(mergedSnaps, DeltaTick, GameTick, Crc);
542
566
  _this.emit("snapshot", snapUnpacked.items);
543
567
  _this.AckGameTick = snapUnpacked.recvTick;
544
- if (Math.abs(_this.PredGameTick - _this.AckGameTick) > 10)
568
+ if (Math.abs(_this.PredGameTick - _this.AckGameTick) > 10) {
545
569
  _this.PredGameTick = _this.AckGameTick + 1;
546
- _this.sendInput();
570
+ _this.sendInput();
571
+ }
547
572
  }
548
573
  }
549
574
  // })
550
575
  }
576
+ if (chunk.msgid >= NETMSG_Sys.NETMSG_WHATIS && chunk.msgid <= NETMSG_Sys.NETMSG_CHECKSUM_ERROR) {
577
+ if (chunk.msgid == NETMSG_Sys.NETMSG_WHATIS) {
578
+ var Uuid = chunk.raw.slice(0, 16);
579
+ var uuid = _this.UUIDManager.LookupUUID(Uuid);
580
+ var packer = new MsgPacker_1.MsgPacker(0, true, 1);
581
+ if (uuid !== undefined) {
582
+ // IT_IS msg
583
+ packer.AddBuffer(_this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_ITIS).hash);
584
+ packer.AddBuffer(Uuid);
585
+ packer.AddString(uuid.name);
586
+ }
587
+ else {
588
+ // dont_know msg
589
+ packer.AddBuffer(_this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_IDONTKNOW).hash);
590
+ packer.AddBuffer(Uuid);
591
+ }
592
+ _this.QueueChunkEx(packer);
593
+ }
594
+ if (chunk.msgid == NETMSG_Sys.NETMSG_MAP_DETAILS) { // TODO: option for downloading maps
595
+ var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
596
+ var map_name = unpacker.unpackString();
597
+ var map_sha256 = Buffer.alloc(32);
598
+ if (unpacker.remaining.length >= 32)
599
+ map_sha256 = unpacker.unpackRaw(32);
600
+ var map_crc = unpacker.unpackInt();
601
+ var map_size = unpacker.unpackInt();
602
+ var map_url = "";
603
+ if (unpacker.remaining.length)
604
+ map_url = unpacker.unpackString();
605
+ _this.emit("map_details", { map_name: map_name, map_sha256: map_sha256, map_crc: map_crc, map_size: map_size, map_url: map_url });
606
+ // unpacker.unpack
607
+ }
608
+ else if (chunk.msgid == NETMSG_Sys.NETMSG_CAPABILITIES) {
609
+ var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
610
+ var Version = unpacker.unpackInt();
611
+ var Flags = unpacker.unpackInt();
612
+ if (Version <= 0)
613
+ return;
614
+ var DDNet = false;
615
+ if (Version >= 1) {
616
+ DDNet = Boolean(Flags & 1);
617
+ }
618
+ var ChatTimeoutCode = DDNet;
619
+ var AnyPlayerFlag = DDNet;
620
+ var PingEx = false;
621
+ var AllowDummy = true;
622
+ var SyncWeaponInput = false;
623
+ if (Version >= 1) {
624
+ ChatTimeoutCode = Boolean(Flags & 2);
625
+ }
626
+ if (Version >= 2) {
627
+ AnyPlayerFlag = Boolean(Flags & 4);
628
+ }
629
+ if (Version >= 3) {
630
+ PingEx = Boolean(Flags & 8);
631
+ }
632
+ if (Version >= 4) {
633
+ AllowDummy = Boolean(Flags & 16);
634
+ }
635
+ if (Version >= 5) {
636
+ SyncWeaponInput = Boolean(Flags & 32);
637
+ }
638
+ _this.emit("capabilities", { ChatTimeoutCode: ChatTimeoutCode, AnyPlayerFlag: AnyPlayerFlag, PingEx: PingEx, AllowDummy: AllowDummy, SyncWeaponInput: SyncWeaponInput });
639
+ // https://github.com/ddnet/ddnet/blob/06e3eb564150e9ab81b3a5595c48e9fe5952ed32/src/engine/client/client.cpp#L1565
640
+ }
641
+ else if (chunk.msgid == NETMSG_Sys.NETMSG_PINGEX) {
642
+ var packer = new MsgPacker_1.MsgPacker(0, true, 2);
643
+ packer.AddBuffer(_this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_PONGEX).hash);
644
+ _this.SendMsgEx(packer, 2);
645
+ }
646
+ }
551
647
  }
552
648
  else {
553
649
  // game messages
@@ -562,7 +658,7 @@ var Client = /** @class */ (function (_super) {
562
658
  for (var i = 0; i < 15; i++) {
563
659
  list.push(unpacker.unpackString());
564
660
  }
565
- list = list.slice(NumOptions);
661
+ list = list.slice(0, NumOptions);
566
662
  (_a = _this.VoteList).push.apply(_a, list);
567
663
  }
568
664
  else if (chunk.msgid == NETMSG_Game.SV_VOTEOPTIONADD) {
package/lib/client.ts CHANGED
@@ -4,6 +4,7 @@ import net from 'dgram';
4
4
  import { EventEmitter } from 'stream';
5
5
 
6
6
  import { unpackString, MsgUnpacker } from "./MsgUnpacker";
7
+ let { version } = require('../package.json');
7
8
 
8
9
  import Movement from './components/movement';
9
10
  import { PlayerInput, PlayerInfo, Projectile, Laser, Pickup, Flag, GameInfo, GameData, CharacterCore, Character, ClientInfo, SpectatorInfo, Common, Explosion, Spawn, HammerHit, Death, SoundGlobal, SoundWorld, DamageInd } from "./snapshots";
@@ -14,6 +15,8 @@ import Huffman from "./huffman";
14
15
  import { Game } from "./components/game";
15
16
  import { SnapshotWrapper } from "./components/snapshot";
16
17
 
18
+ import { UUIDManager } from "./UUIDManager";
19
+
17
20
  const huff = new Huffman();
18
21
 
19
22
  enum States {
@@ -106,6 +109,21 @@ enum NETMSG_Sys {
106
109
  NETMSG_RCON_CMD_REM,
107
110
 
108
111
  NUM_NETMSGS,
112
+
113
+ NETMSG_WHATIS = 65536,
114
+ NETMSG_ITIS,
115
+ NETMSG_IDONTKNOW,
116
+
117
+ NETMSG_RCONTYPE,
118
+ NETMSG_MAP_DETAILS,
119
+ NETMSG_CAPABILITIES,
120
+ NETMSG_CLIENTVER,
121
+ NETMSG_PINGEX,
122
+ NETMSG_PONGEX,
123
+ NETMSG_CHECKSUM_REQUEST,
124
+ NETMSG_CHECKSUM_RESPONSE,
125
+ NETMSG_CHECKSUM_ERROR
126
+
109
127
  }
110
128
 
111
129
  interface chunk {
@@ -131,15 +149,6 @@ var messageTypes = [
131
149
  ["none, starts at 1", "INFO", "MAP_CHANGE", "MAP_DATA", "CON_READY", "SNAP", "SNAP_EMPTY", "SNAP_SINGLE", "INPUT_TIMING", "RCON_AUTH_STATUS", "RCON_LINE", "READY", "ENTER_GAME", "INPUT", "RCON_CMD", "RCON_AUTH", "REQUEST_MAP_DATA", "PING", "PING_REPLY", "RCON_CMD_ADD", "RCON_CMD_REMOVE"]
132
150
  ]
133
151
 
134
- var messageUUIDs = {
135
- "WHAT_IS": Buffer.from([0x24, 0x5e, 0x50, 0x97, 0x9f, 0xe0, 0x39, 0xd6, 0xbf, 0x7d, 0x9a, 0x29, 0xe1, 0x69, 0x1e, 0x4c]),
136
- "IT_IS": Buffer.from([0x69, 0x54, 0x84, 0x7e, 0x2e, 0x87, 0x36, 0x03, 0xb5, 0x62, 0x36, 0xda, 0x29, 0xed, 0x1a, 0xca]),
137
- "I_DONT_KNOW": Buffer.from([0x41, 0x69, 0x11, 0xb5, 0x79, 0x73, 0x33, 0xbf, 0x8d, 0x52, 0x7b, 0xf0, 0x1e, 0x51, 0x9c, 0xf0]),
138
- "RCON_TYPE": Buffer.from([0x12, 0x81, 0x0e, 0x1f, 0xa1, 0xdb, 0x33, 0x78, 0xb4, 0xfb, 0x16, 0x4e, 0xd6, 0x50, 0x59, 0x26]),
139
- "MAP_DETAILS": Buffer.from([0xf9, 0x11, 0x7b, 0x3c, 0x80, 0x39, 0x34, 0x16, 0x9f, 0xc0, 0xae, 0xf2, 0xbc, 0xb7, 0x5c, 0x03]),
140
- "CLIENT_VERSION": Buffer.from([0x8c, 0x00, 0x13, 0x04, 0x84, 0x61, 0x3e, 0x47, 0x87, 0x87, 0xf6, 0x72, 0xb3, 0x83, 0x5b, 0xd4]),
141
- "CAPABILITIES": Buffer.from([0xf6, 0x21, 0xa5, 0xa1, 0xf5, 0x85, 0x37, 0x75, 0x8e, 0x73, 0x41, 0xbe, 0xee, 0x79, 0xf2, 0xb2]),
142
- }
143
152
 
144
153
  declare interface iMessage {
145
154
  team: number,
@@ -184,6 +193,9 @@ export declare interface Client {
184
193
  on(event: 'kill', listener: (kill: iKillMsg) => void): this;
185
194
  on(event: 'motd', listener: (message: string) => void): this;
186
195
 
196
+ on(event: 'map_details', listener: (message: {map_name: string, map_sha256: Buffer, map_crc: number, map_size: number, map_url: string}) => void): this;
197
+ on(event: 'capabilities', listener: (message: {ChatTimeoutCode: boolean, AnyPlayerFlag: boolean, PingEx: boolean, AllowDummy: boolean, SyncWeaponInput: boolean}) => void): this;
198
+
187
199
  on(event: 'snapshot', listener: (items: Item[]) => void): this;
188
200
  }
189
201
 
@@ -230,6 +242,7 @@ export class Client extends EventEmitter {
230
242
  public readonly options?: iOptions;
231
243
  private requestResend: boolean;
232
244
 
245
+ private UUIDManager: UUIDManager;
233
246
 
234
247
  constructor(ip: string, port: number, nickname: string, options?: iOptions) {
235
248
  super();
@@ -270,11 +283,28 @@ export class Client extends EventEmitter {
270
283
  this.lastRecvTime = new Date().getTime();
271
284
 
272
285
  this.lastSentMessages = [];
286
+
273
287
  this.movement = new Movement();
274
288
 
275
289
  this.game = new Game(this);
276
290
  this.SnapshotUnpacker = new SnapshotWrapper(this);
277
291
 
292
+ this.UUIDManager = new UUIDManager();
293
+
294
+
295
+ this.UUIDManager.RegisterName("what-is@ddnet.tw", NETMSG_Sys.NETMSG_WHATIS);
296
+ this.UUIDManager.RegisterName("it-is@ddnet.tw", NETMSG_Sys.NETMSG_ITIS);
297
+ this.UUIDManager.RegisterName("i-dont-know@ddnet.tw", NETMSG_Sys.NETMSG_IDONTKNOW);
298
+
299
+ this.UUIDManager.RegisterName("rcon-type@ddnet.tw", NETMSG_Sys.NETMSG_RCONTYPE);
300
+ this.UUIDManager.RegisterName("map-details@ddnet.tw", NETMSG_Sys.NETMSG_MAP_DETAILS);
301
+ this.UUIDManager.RegisterName("capabilities@ddnet.tw", NETMSG_Sys.NETMSG_CAPABILITIES);
302
+ this.UUIDManager.RegisterName("clientver@ddnet.tw", NETMSG_Sys.NETMSG_CLIENTVER);
303
+ this.UUIDManager.RegisterName("ping@ddnet.tw", NETMSG_Sys.NETMSG_PING);
304
+ this.UUIDManager.RegisterName("pong@ddnet.tw", NETMSG_Sys.NETMSG_PONGEX);
305
+ this.UUIDManager.RegisterName("checksum-request@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_REQUEST);
306
+ this.UUIDManager.RegisterName("checksum-response@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_RESPONSE);
307
+ this.UUIDManager.RegisterName("checksum-error@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_ERROR);
278
308
 
279
309
  }
280
310
 
@@ -325,12 +355,15 @@ export class Client extends EventEmitter {
325
355
  chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
326
356
  chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
327
357
  chunk.raw = packet.slice(1, chunk.bytes)
328
- Object.values(messageUUIDs).forEach((a, i) => {
329
- if (a.byteLength >= 16 && a.compare(packet.slice(0, 16)) == 0) {
330
- chunk.extended_msgid = a;
331
- chunk.msg = Object.keys(messageUUIDs)[i];
358
+ if (chunk.msgid == 0 && chunk.raw.byteLength >= 16) {
359
+ let uuid = this.UUIDManager.LookupUUID(chunk.raw.slice(0, 16));
360
+ if (uuid !== undefined) {
361
+ chunk.extended_msgid = uuid.hash;
362
+ chunk.msg = uuid.name;
363
+ chunk.raw = chunk.raw.slice(16);
364
+ chunk.msgid = uuid.type_id;
332
365
  }
333
- })
366
+ }
334
367
 
335
368
  packet = packet.slice(chunk.bytes)
336
369
  unpacked.chunks.push(chunk)
@@ -361,7 +394,7 @@ export class Client extends EventEmitter {
361
394
 
362
395
 
363
396
  /** Send a Msg (or Msg[]) to the server.*/
364
- SendMsgEx(Msgs: MsgPacker[] | MsgPacker) {
397
+ SendMsgEx(Msgs: MsgPacker[] | MsgPacker, flags = 0) {
365
398
  if (this.State == States.STATE_OFFLINE)
366
399
  return;
367
400
  if (!this.socket)
@@ -397,7 +430,7 @@ export class Client extends EventEmitter {
397
430
  this.lastSentMessages.push({msg: Msg, ack: this.clientAck})
398
431
  }
399
432
  })
400
- let flags = 0;
433
+ // let flags = 0;
401
434
  if (this.requestResend)
402
435
  flags |= 4;
403
436
 
@@ -458,12 +491,16 @@ export class Client extends EventEmitter {
458
491
  chunk.msgid = (packet[0]-(packet[0]&1))/2;
459
492
  chunk.msg = messageTypes[packet[0]&1][chunk.msgid];
460
493
  chunk.raw = packet.slice(1, chunk.bytes)
461
- Object.values(messageUUIDs).forEach((a, i) => {
462
- if (a.byteLength >= 16 && a.compare(packet.slice(0, 16)) === 0) {
463
- chunk.extended_msgid = a;
464
- chunk.msg = Object.keys(messageUUIDs)[i];
465
- }
466
- })
494
+ if (chunk.msgid == 0) {
495
+ let uuid = this.UUIDManager.LookupUUID(chunk.raw.slice(0,16));
496
+ if (uuid !== undefined) {
497
+ chunk.extended_msgid = uuid.hash;
498
+ chunk.msgid = uuid.type_id;
499
+ chunk.msg = uuid.name;
500
+ chunk.raw = chunk.raw.slice(16);
501
+ }
502
+
503
+ }
467
504
  return chunk;
468
505
  }
469
506
 
@@ -479,7 +516,7 @@ export class Client extends EventEmitter {
479
516
  } else if (this.State == States.STATE_OFFLINE)
480
517
  clearInterval(predTimer);
481
518
 
482
- }, 20);
519
+ }, 1000/50); // 50 ticks per second
483
520
 
484
521
  this.SendControlMsg(1, "TKEN")
485
522
  let connectInterval = setInterval(() => {
@@ -496,7 +533,7 @@ export class Client extends EventEmitter {
496
533
  return;
497
534
  this.time = new Date().getTime();
498
535
  this.sendInput();
499
- }, 500)
536
+ }, 50)
500
537
  }
501
538
 
502
539
  let resendTimeout = setInterval(() => {
@@ -540,17 +577,15 @@ export class Client extends EventEmitter {
540
577
 
541
578
  var client_version = new MsgPacker(0, true, 1);
542
579
  client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
543
- let randomUuid = Buffer.allocUnsafe(16);
544
-
545
- randomBytes(16).copy(randomUuid);
580
+ let randomUuid = randomBytes(16);
546
581
 
547
582
  client_version.AddBuffer(randomUuid);
548
583
  if (this.options?.ddnet_version !== undefined) {
549
584
  client_version.AddInt(this.options?.ddnet_version.version);
550
- client_version.AddString("DDNet " + this.options?.ddnet_version.release_version);
585
+ client_version.AddString(`DDNet ${this.options?.ddnet_version.release_version}; https://www.npmjs.com/package/teeworlds/v/${version}`);
551
586
  } else {
552
- client_version.AddInt(16003);
553
- client_version.AddString("DDNet 16.0.3");
587
+ client_version.AddInt(16050);
588
+ client_version.AddString(`DDNet 16.5.0; https://www.npmjs.com/package/teeworlds/v/${version}`);
554
589
  }
555
590
 
556
591
  this.SendMsgEx([client_version, info])
@@ -699,10 +734,10 @@ export class Client extends EventEmitter {
699
734
 
700
735
  this.emit("snapshot", snapUnpacked.items);
701
736
  this.AckGameTick = snapUnpacked.recvTick;
702
- if (Math.abs(this.PredGameTick - this.AckGameTick) > 10)
737
+ if (Math.abs(this.PredGameTick - this.AckGameTick) > 10) {
703
738
  this.PredGameTick = this.AckGameTick + 1;
704
-
705
- this.sendInput();
739
+ this.sendInput();
740
+ }
706
741
  }
707
742
 
708
743
 
@@ -712,7 +747,93 @@ export class Client extends EventEmitter {
712
747
  // })
713
748
 
714
749
 
715
- }
750
+ }
751
+
752
+ if (chunk.msgid >= NETMSG_Sys.NETMSG_WHATIS && chunk.msgid <= NETMSG_Sys.NETMSG_CHECKSUM_ERROR) {
753
+ if (chunk.msgid == NETMSG_Sys.NETMSG_WHATIS) {
754
+ let Uuid = chunk.raw.slice(0, 16);
755
+
756
+ let uuid = this.UUIDManager.LookupUUID(Uuid);
757
+ let packer = new MsgPacker(0, true, 1);
758
+ if (uuid !== undefined) {
759
+ // IT_IS msg
760
+ packer.AddBuffer(this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_ITIS)!.hash);
761
+
762
+ packer.AddBuffer(Uuid);
763
+ packer.AddString(uuid.name);
764
+ } else {
765
+ // dont_know msg
766
+ packer.AddBuffer(this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_IDONTKNOW)!.hash);
767
+
768
+ packer.AddBuffer(Uuid);
769
+ }
770
+ this.QueueChunkEx(packer)
771
+ }
772
+
773
+ if (chunk.msgid == NETMSG_Sys.NETMSG_MAP_DETAILS) { // TODO: option for downloading maps
774
+ let unpacker = new MsgUnpacker(chunk.raw);
775
+
776
+ let map_name = unpacker.unpackString();
777
+ let map_sha256: Buffer = Buffer.alloc(32);
778
+ if (unpacker.remaining.length >= 32)
779
+ map_sha256 = unpacker.unpackRaw(32);
780
+ let map_crc = unpacker.unpackInt();
781
+ let map_size = unpacker.unpackInt();
782
+
783
+ let map_url = "";
784
+ if (unpacker.remaining.length)
785
+ map_url = unpacker.unpackString();
786
+
787
+ this.emit("map_details", {map_name, map_sha256, map_crc, map_size, map_url})
788
+ // unpacker.unpack
789
+
790
+ } else if (chunk.msgid == NETMSG_Sys.NETMSG_CAPABILITIES) {
791
+ let unpacker = new MsgUnpacker(chunk.raw);
792
+ let Version = unpacker.unpackInt();
793
+ let Flags = unpacker.unpackInt();
794
+ if (Version <= 0)
795
+ return;
796
+ let DDNet = false;
797
+ if (Version >= 1) {
798
+ DDNet = Boolean(Flags & 1);
799
+
800
+ }
801
+ let ChatTimeoutCode = DDNet;
802
+ let AnyPlayerFlag = DDNet;
803
+ let PingEx = false;
804
+ let AllowDummy = true;
805
+ let SyncWeaponInput = false;
806
+ if(Version >= 1)
807
+ {
808
+ ChatTimeoutCode = Boolean(Flags & 2);
809
+ }
810
+ if(Version >= 2)
811
+ {
812
+ AnyPlayerFlag = Boolean(Flags & 4);
813
+ }
814
+ if(Version >= 3)
815
+ {
816
+ PingEx = Boolean(Flags & 8);
817
+ }
818
+ if(Version >= 4)
819
+ {
820
+ AllowDummy = Boolean(Flags & 16);
821
+ }
822
+ if(Version >= 5)
823
+ {
824
+ SyncWeaponInput = Boolean(Flags & 32);
825
+ }
826
+ this.emit("capabilities", {ChatTimeoutCode, AnyPlayerFlag, PingEx, AllowDummy, SyncWeaponInput});
827
+ // https://github.com/ddnet/ddnet/blob/06e3eb564150e9ab81b3a5595c48e9fe5952ed32/src/engine/client/client.cpp#L1565
828
+ } else if (chunk.msgid == NETMSG_Sys.NETMSG_PINGEX) {
829
+ let packer = new MsgPacker(0, true, 2);
830
+ packer.AddBuffer(this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_PONGEX)!.hash);
831
+
832
+ this.SendMsgEx(packer, 2);
833
+ }
834
+
835
+ }
836
+
716
837
  } else {
717
838
  // game messages
718
839
 
@@ -726,7 +847,7 @@ export class Client extends EventEmitter {
726
847
  for (let i = 0; i < 15; i++) {
727
848
  list.push(unpacker.unpackString());
728
849
  }
729
- list = list.slice(NumOptions);
850
+ list = list.slice(0, NumOptions);
730
851
 
731
852
  this.VoteList.push(...list);
732
853
  } else if (chunk.msgid == NETMSG_Game.SV_VOTEOPTIONADD) {
@@ -40,6 +40,34 @@ var Movement = /** @class */ (function () {
40
40
  this.input.m_TargetX = x;
41
41
  this.input.m_TargetY = y;
42
42
  };
43
+ Movement.prototype.Flag = function (toggle, num) {
44
+ if (toggle) {
45
+ this.input.m_PlayerFlags |= num;
46
+ }
47
+ else {
48
+ this.input.m_PlayerFlags &= ~num;
49
+ }
50
+ };
51
+ Movement.prototype.FlagPlaying = function (toggle) {
52
+ if (toggle === void 0) { toggle = true; }
53
+ this.Flag(toggle, 1);
54
+ };
55
+ Movement.prototype.FlagInMenu = function (toggle) {
56
+ if (toggle === void 0) { toggle = true; }
57
+ this.Flag(toggle, 2);
58
+ };
59
+ Movement.prototype.FlagChatting = function (toggle) {
60
+ if (toggle === void 0) { toggle = true; }
61
+ this.Flag(toggle, 4);
62
+ };
63
+ Movement.prototype.FlagScoreboard = function (toggle) {
64
+ if (toggle === void 0) { toggle = true; }
65
+ this.Flag(toggle, 8);
66
+ };
67
+ Movement.prototype.FlagHookline = function (toggle) {
68
+ if (toggle === void 0) { toggle = true; }
69
+ this.Flag(toggle, 16);
70
+ };
43
71
  Movement.prototype.Reset = function () {
44
72
  this.input.m_Direction = 0;
45
73
  this.input.m_Jump = 0;
@@ -50,6 +50,31 @@ class Movement {
50
50
  this.input.m_TargetX = x;
51
51
  this.input.m_TargetY = y;
52
52
  }
53
+
54
+ private Flag(toggle: boolean, num: number) {
55
+ if (toggle) {
56
+ this.input.m_PlayerFlags |= num;
57
+ } else {
58
+ this.input.m_PlayerFlags &= ~num;
59
+
60
+ }
61
+ }
62
+ FlagPlaying(toggle = true) {
63
+ this.Flag(toggle, 1);
64
+ }
65
+ FlagInMenu(toggle = true) {
66
+ this.Flag(toggle, 2);
67
+ }
68
+ FlagChatting(toggle = true) {
69
+ this.Flag(toggle, 4);
70
+ }
71
+ FlagScoreboard(toggle = true) {
72
+ this.Flag(toggle, 8);
73
+ }
74
+ FlagHookline(toggle = true) {
75
+ this.Flag(toggle, 16);
76
+ }
77
+
53
78
  Reset() {
54
79
  this.input.m_Direction = 0;
55
80
  this.input.m_Jump = 0;