teeworlds 2.4.5 → 2.4.7

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
@@ -29,6 +29,7 @@ var snapshot_1 = require("./snapshot");
29
29
  var huffman_1 = __importDefault(require("./huffman"));
30
30
  var game_1 = require("./components/game");
31
31
  var snapshot_2 = require("./components/snapshot");
32
+ var UUIDManager_1 = require("./UUIDManager");
32
33
  var huff = new huffman_1.default();
33
34
  var States;
34
35
  (function (States) {
@@ -112,20 +113,23 @@ var NETMSG_Sys;
112
113
  NETMSG_Sys[NETMSG_Sys["NETMSG_RCON_CMD_ADD"] = 25] = "NETMSG_RCON_CMD_ADD";
113
114
  NETMSG_Sys[NETMSG_Sys["NETMSG_RCON_CMD_REM"] = 26] = "NETMSG_RCON_CMD_REM";
114
115
  NETMSG_Sys[NETMSG_Sys["NUM_NETMSGS"] = 27] = "NUM_NETMSGS";
116
+ NETMSG_Sys[NETMSG_Sys["NETMSG_WHATIS"] = 65536] = "NETMSG_WHATIS";
117
+ NETMSG_Sys[NETMSG_Sys["NETMSG_ITIS"] = 65537] = "NETMSG_ITIS";
118
+ NETMSG_Sys[NETMSG_Sys["NETMSG_IDONTKNOW"] = 65538] = "NETMSG_IDONTKNOW";
119
+ NETMSG_Sys[NETMSG_Sys["NETMSG_RCONTYPE"] = 65539] = "NETMSG_RCONTYPE";
120
+ NETMSG_Sys[NETMSG_Sys["NETMSG_MAP_DETAILS"] = 65540] = "NETMSG_MAP_DETAILS";
121
+ NETMSG_Sys[NETMSG_Sys["NETMSG_CAPABILITIES"] = 65541] = "NETMSG_CAPABILITIES";
122
+ NETMSG_Sys[NETMSG_Sys["NETMSG_CLIENTVER"] = 65542] = "NETMSG_CLIENTVER";
123
+ NETMSG_Sys[NETMSG_Sys["NETMSG_PINGEX"] = 65543] = "NETMSG_PINGEX";
124
+ NETMSG_Sys[NETMSG_Sys["NETMSG_PONGEX"] = 65544] = "NETMSG_PONGEX";
125
+ NETMSG_Sys[NETMSG_Sys["NETMSG_CHECKSUM_REQUEST"] = 65545] = "NETMSG_CHECKSUM_REQUEST";
126
+ NETMSG_Sys[NETMSG_Sys["NETMSG_CHECKSUM_RESPONSE"] = 65546] = "NETMSG_CHECKSUM_RESPONSE";
127
+ NETMSG_Sys[NETMSG_Sys["NETMSG_CHECKSUM_ERROR"] = 65547] = "NETMSG_CHECKSUM_ERROR";
115
128
  })(NETMSG_Sys || (NETMSG_Sys = {}));
116
129
  var messageTypes = [
117
130
  ["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
131
  ["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
132
  ];
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
133
  var Client = /** @class */ (function (_super) {
130
134
  __extends(Client, _super);
131
135
  function Client(ip, port, nickname, options) {
@@ -160,6 +164,19 @@ var Client = /** @class */ (function (_super) {
160
164
  _this.movement = new movement_1.default();
161
165
  _this.game = new game_1.Game(_this);
162
166
  _this.SnapshotUnpacker = new snapshot_2.SnapshotWrapper(_this);
167
+ _this.UUIDManager = new UUIDManager_1.UUIDManager();
168
+ _this.UUIDManager.RegisterName("what-is@ddnet.tw", NETMSG_Sys.NETMSG_WHATIS);
169
+ _this.UUIDManager.RegisterName("it-is@ddnet.tw", NETMSG_Sys.NETMSG_ITIS);
170
+ _this.UUIDManager.RegisterName("i-dont-know@ddnet.tw", NETMSG_Sys.NETMSG_IDONTKNOW);
171
+ _this.UUIDManager.RegisterName("rcon-type@ddnet.tw", NETMSG_Sys.NETMSG_RCONTYPE);
172
+ _this.UUIDManager.RegisterName("map-details@ddnet.tw", NETMSG_Sys.NETMSG_MAP_DETAILS);
173
+ _this.UUIDManager.RegisterName("capabilities@ddnet.tw", NETMSG_Sys.NETMSG_CAPABILITIES);
174
+ _this.UUIDManager.RegisterName("clientver@ddnet.tw", NETMSG_Sys.NETMSG_CLIENTVER);
175
+ _this.UUIDManager.RegisterName("ping@ddnet.tw", NETMSG_Sys.NETMSG_PING);
176
+ _this.UUIDManager.RegisterName("pong@ddnet.tw", NETMSG_Sys.NETMSG_PONGEX);
177
+ _this.UUIDManager.RegisterName("checksum-request@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_REQUEST);
178
+ _this.UUIDManager.RegisterName("checksum-response@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_RESPONSE);
179
+ _this.UUIDManager.RegisterName("checksum-error@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_ERROR);
163
180
  return _this;
164
181
  }
165
182
  Client.prototype.ResendAfter = function (lastAck) {
@@ -201,12 +218,15 @@ var Client = /** @class */ (function (_super) {
201
218
  chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
202
219
  chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
203
220
  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];
221
+ if (chunk.msgid == 0 && chunk.raw.byteLength >= 16) {
222
+ var uuid = this.UUIDManager.LookupUUID(chunk.raw.slice(0, 16));
223
+ if (uuid !== undefined) {
224
+ chunk.extended_msgid = uuid.hash;
225
+ chunk.msg = uuid.name;
226
+ chunk.raw = chunk.raw.slice(16);
227
+ chunk.msgid = uuid.type_id;
208
228
  }
209
- });
229
+ }
210
230
  packet = packet.slice(chunk.bytes);
211
231
  unpacked.chunks.push(chunk);
212
232
  }
@@ -233,8 +253,9 @@ var Client = /** @class */ (function (_super) {
233
253
  });
234
254
  };
235
255
  /** Send a Msg (or Msg[]) to the server.*/
236
- Client.prototype.SendMsgEx = function (Msgs) {
256
+ Client.prototype.SendMsgEx = function (Msgs, flags) {
237
257
  var _this = this;
258
+ if (flags === void 0) { flags = 0; }
238
259
  if (this.State == States.STATE_OFFLINE)
239
260
  return;
240
261
  if (!this.socket)
@@ -270,7 +291,7 @@ var Client = /** @class */ (function (_super) {
270
291
  _this.lastSentMessages.push({ msg: Msg, ack: _this.clientAck });
271
292
  }
272
293
  });
273
- var flags = 0;
294
+ // let flags = 0;
274
295
  if (this.requestResend)
275
296
  flags |= 4;
276
297
  var packetHeader = Buffer.from([((flags << 4) & 0xf0) | ((this.ack >> 8) & 0xf), this.ack & 0xff, _Msgs.length]);
@@ -324,12 +345,15 @@ var Client = /** @class */ (function (_super) {
324
345
  chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
325
346
  chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
326
347
  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];
348
+ if (chunk.msgid == 0) {
349
+ var uuid = this.UUIDManager.LookupUUID(chunk.raw.slice(0, 16));
350
+ if (uuid !== undefined) {
351
+ chunk.extended_msgid = uuid.hash;
352
+ chunk.msgid = uuid.type_id;
353
+ chunk.msg = uuid.name;
354
+ chunk.raw = chunk.raw.slice(16);
331
355
  }
332
- });
356
+ }
333
357
  return chunk;
334
358
  };
335
359
  /** Connect the client to the server. */
@@ -344,7 +368,7 @@ var Client = /** @class */ (function (_super) {
344
368
  }
345
369
  else if (_this.State == States.STATE_OFFLINE)
346
370
  clearInterval(predTimer);
347
- }, 20);
371
+ }, 1000 / 50); // 50 ticks per second
348
372
  this.SendControlMsg(1, "TKEN");
349
373
  var connectInterval = setInterval(function () {
350
374
  if (_this.State == States.STATE_CONNECTING)
@@ -360,7 +384,7 @@ var Client = /** @class */ (function (_super) {
360
384
  return;
361
385
  _this.time = new Date().getTime();
362
386
  _this.sendInput();
363
- }, 500);
387
+ }, 50);
364
388
  }
365
389
  var resendTimeout = setInterval(function () {
366
390
  if (_this.State != States.STATE_OFFLINE) {
@@ -400,16 +424,15 @@ var Client = /** @class */ (function (_super) {
400
424
  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
425
  var client_version = new MsgPacker_1.MsgPacker(0, true, 1);
402
426
  client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
403
- var randomUuid = Buffer.allocUnsafe(16);
404
- (0, crypto_1.randomBytes)(16).copy(randomUuid);
427
+ var randomUuid = (0, crypto_1.randomBytes)(16);
405
428
  client_version.AddBuffer(randomUuid);
406
429
  if (((_d = _this.options) === null || _d === void 0 ? void 0 : _d.ddnet_version) !== undefined) {
407
430
  client_version.AddInt((_e = _this.options) === null || _e === void 0 ? void 0 : _e.ddnet_version.version);
408
431
  client_version.AddString("DDNet " + ((_f = _this.options) === null || _f === void 0 ? void 0 : _f.ddnet_version.release_version));
409
432
  }
410
433
  else {
411
- client_version.AddInt(16003);
412
- client_version.AddString("DDNet 16.0.3");
434
+ client_version.AddInt(16050);
435
+ client_version.AddString("DDNet 16.5.0");
413
436
  }
414
437
  _this.SendMsgEx([client_version, info]);
415
438
  }
@@ -541,13 +564,85 @@ var Client = /** @class */ (function (_super) {
541
564
  var snapUnpacked = _this.SnapUnpacker.unpackSnapshot(mergedSnaps, DeltaTick, GameTick, Crc);
542
565
  _this.emit("snapshot", snapUnpacked.items);
543
566
  _this.AckGameTick = snapUnpacked.recvTick;
544
- if (Math.abs(_this.PredGameTick - _this.AckGameTick) > 10)
567
+ if (Math.abs(_this.PredGameTick - _this.AckGameTick) > 10) {
545
568
  _this.PredGameTick = _this.AckGameTick + 1;
546
- _this.sendInput();
569
+ _this.sendInput();
570
+ }
547
571
  }
548
572
  }
549
573
  // })
550
574
  }
575
+ if (chunk.msgid >= NETMSG_Sys.NETMSG_WHATIS && chunk.msgid <= NETMSG_Sys.NETMSG_CHECKSUM_ERROR) {
576
+ if (chunk.msgid == NETMSG_Sys.NETMSG_WHATIS) {
577
+ var Uuid = chunk.raw.slice(0, 16);
578
+ var uuid = _this.UUIDManager.LookupUUID(Uuid);
579
+ var packer = new MsgPacker_1.MsgPacker(0, true, 1);
580
+ if (uuid !== undefined) {
581
+ // IT_IS msg
582
+ packer.AddBuffer(_this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_ITIS).hash);
583
+ packer.AddBuffer(Uuid);
584
+ packer.AddString(uuid.name);
585
+ }
586
+ else {
587
+ // dont_know msg
588
+ packer.AddBuffer(_this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_IDONTKNOW).hash);
589
+ packer.AddBuffer(Uuid);
590
+ }
591
+ _this.QueueChunkEx(packer);
592
+ }
593
+ if (chunk.msgid == NETMSG_Sys.NETMSG_MAP_DETAILS) { // TODO: option for downloading maps
594
+ var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
595
+ var map_name = unpacker.unpackString();
596
+ var map_sha256 = Buffer.alloc(32);
597
+ if (unpacker.remaining.length >= 32)
598
+ map_sha256 = unpacker.unpackRaw(32);
599
+ var map_crc = unpacker.unpackInt();
600
+ var map_size = unpacker.unpackInt();
601
+ var map_url = "";
602
+ if (unpacker.remaining.length)
603
+ map_url = unpacker.unpackString();
604
+ _this.emit("map_details", { map_name: map_name, map_sha256: map_sha256, map_crc: map_crc, map_size: map_size, map_url: map_url });
605
+ // unpacker.unpack
606
+ }
607
+ else if (chunk.msgid == NETMSG_Sys.NETMSG_CAPABILITIES) {
608
+ var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
609
+ var Version = unpacker.unpackInt();
610
+ var Flags = unpacker.unpackInt();
611
+ if (Version <= 0)
612
+ return;
613
+ var DDNet = false;
614
+ if (Version >= 1) {
615
+ DDNet = Boolean(Flags & 1);
616
+ }
617
+ var ChatTimeoutCode = DDNet;
618
+ var AnyPlayerFlag = DDNet;
619
+ var PingEx = false;
620
+ var AllowDummy = true;
621
+ var SyncWeaponInput = false;
622
+ if (Version >= 1) {
623
+ ChatTimeoutCode = Boolean(Flags & 2);
624
+ }
625
+ if (Version >= 2) {
626
+ AnyPlayerFlag = Boolean(Flags & 4);
627
+ }
628
+ if (Version >= 3) {
629
+ PingEx = Boolean(Flags & 8);
630
+ }
631
+ if (Version >= 4) {
632
+ AllowDummy = Boolean(Flags & 16);
633
+ }
634
+ if (Version >= 5) {
635
+ SyncWeaponInput = Boolean(Flags & 32);
636
+ }
637
+ _this.emit("capabilities", { ChatTimeoutCode: ChatTimeoutCode, AnyPlayerFlag: AnyPlayerFlag, PingEx: PingEx, AllowDummy: AllowDummy, SyncWeaponInput: SyncWeaponInput });
638
+ // https://github.com/ddnet/ddnet/blob/06e3eb564150e9ab81b3a5595c48e9fe5952ed32/src/engine/client/client.cpp#L1565
639
+ }
640
+ else if (chunk.msgid == NETMSG_Sys.NETMSG_PINGEX) {
641
+ var packer = new MsgPacker_1.MsgPacker(0, true, 2);
642
+ packer.AddBuffer(_this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_PONGEX).hash);
643
+ _this.SendMsgEx(packer, 2);
644
+ }
645
+ }
551
646
  }
552
647
  else {
553
648
  // game messages
@@ -562,7 +657,7 @@ var Client = /** @class */ (function (_super) {
562
657
  for (var i = 0; i < 15; i++) {
563
658
  list.push(unpacker.unpackString());
564
659
  }
565
- list = list.slice(NumOptions);
660
+ list = list.slice(0, NumOptions);
566
661
  (_a = _this.VoteList).push.apply(_a, list);
567
662
  }
568
663
  else if (chunk.msgid == NETMSG_Game.SV_VOTEOPTIONADD) {
package/lib/client.ts CHANGED
@@ -14,6 +14,8 @@ import Huffman from "./huffman";
14
14
  import { Game } from "./components/game";
15
15
  import { SnapshotWrapper } from "./components/snapshot";
16
16
 
17
+ import { UUIDManager } from "./UUIDManager";
18
+
17
19
  const huff = new Huffman();
18
20
 
19
21
  enum States {
@@ -106,6 +108,21 @@ enum NETMSG_Sys {
106
108
  NETMSG_RCON_CMD_REM,
107
109
 
108
110
  NUM_NETMSGS,
111
+
112
+ NETMSG_WHATIS = 65536,
113
+ NETMSG_ITIS,
114
+ NETMSG_IDONTKNOW,
115
+
116
+ NETMSG_RCONTYPE,
117
+ NETMSG_MAP_DETAILS,
118
+ NETMSG_CAPABILITIES,
119
+ NETMSG_CLIENTVER,
120
+ NETMSG_PINGEX,
121
+ NETMSG_PONGEX,
122
+ NETMSG_CHECKSUM_REQUEST,
123
+ NETMSG_CHECKSUM_RESPONSE,
124
+ NETMSG_CHECKSUM_ERROR
125
+
109
126
  }
110
127
 
111
128
  interface chunk {
@@ -131,15 +148,6 @@ var messageTypes = [
131
148
  ["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
149
  ]
133
150
 
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
151
 
144
152
  declare interface iMessage {
145
153
  team: number,
@@ -184,6 +192,9 @@ export declare interface Client {
184
192
  on(event: 'kill', listener: (kill: iKillMsg) => void): this;
185
193
  on(event: 'motd', listener: (message: string) => void): this;
186
194
 
195
+ on(event: 'map_details', listener: (message: {map_name: string, map_sha256: Buffer, map_crc: number, map_size: number, map_url: string}) => void): this;
196
+ on(event: 'capabilities', listener: (message: {ChatTimeoutCode: boolean, AnyPlayerFlag: boolean, PingEx: boolean, AllowDummy: boolean, SyncWeaponInput: boolean}) => void): this;
197
+
187
198
  on(event: 'snapshot', listener: (items: Item[]) => void): this;
188
199
  }
189
200
 
@@ -230,6 +241,7 @@ export class Client extends EventEmitter {
230
241
  public readonly options?: iOptions;
231
242
  private requestResend: boolean;
232
243
 
244
+ private UUIDManager: UUIDManager;
233
245
 
234
246
  constructor(ip: string, port: number, nickname: string, options?: iOptions) {
235
247
  super();
@@ -270,11 +282,28 @@ export class Client extends EventEmitter {
270
282
  this.lastRecvTime = new Date().getTime();
271
283
 
272
284
  this.lastSentMessages = [];
285
+
273
286
  this.movement = new Movement();
274
287
 
275
288
  this.game = new Game(this);
276
289
  this.SnapshotUnpacker = new SnapshotWrapper(this);
277
290
 
291
+ this.UUIDManager = new UUIDManager();
292
+
293
+
294
+ this.UUIDManager.RegisterName("what-is@ddnet.tw", NETMSG_Sys.NETMSG_WHATIS);
295
+ this.UUIDManager.RegisterName("it-is@ddnet.tw", NETMSG_Sys.NETMSG_ITIS);
296
+ this.UUIDManager.RegisterName("i-dont-know@ddnet.tw", NETMSG_Sys.NETMSG_IDONTKNOW);
297
+
298
+ this.UUIDManager.RegisterName("rcon-type@ddnet.tw", NETMSG_Sys.NETMSG_RCONTYPE);
299
+ this.UUIDManager.RegisterName("map-details@ddnet.tw", NETMSG_Sys.NETMSG_MAP_DETAILS);
300
+ this.UUIDManager.RegisterName("capabilities@ddnet.tw", NETMSG_Sys.NETMSG_CAPABILITIES);
301
+ this.UUIDManager.RegisterName("clientver@ddnet.tw", NETMSG_Sys.NETMSG_CLIENTVER);
302
+ this.UUIDManager.RegisterName("ping@ddnet.tw", NETMSG_Sys.NETMSG_PING);
303
+ this.UUIDManager.RegisterName("pong@ddnet.tw", NETMSG_Sys.NETMSG_PONGEX);
304
+ this.UUIDManager.RegisterName("checksum-request@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_REQUEST);
305
+ this.UUIDManager.RegisterName("checksum-response@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_RESPONSE);
306
+ this.UUIDManager.RegisterName("checksum-error@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_ERROR);
278
307
 
279
308
  }
280
309
 
@@ -325,12 +354,15 @@ export class Client extends EventEmitter {
325
354
  chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
326
355
  chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
327
356
  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];
357
+ if (chunk.msgid == 0 && chunk.raw.byteLength >= 16) {
358
+ let uuid = this.UUIDManager.LookupUUID(chunk.raw.slice(0, 16));
359
+ if (uuid !== undefined) {
360
+ chunk.extended_msgid = uuid.hash;
361
+ chunk.msg = uuid.name;
362
+ chunk.raw = chunk.raw.slice(16);
363
+ chunk.msgid = uuid.type_id;
332
364
  }
333
- })
365
+ }
334
366
 
335
367
  packet = packet.slice(chunk.bytes)
336
368
  unpacked.chunks.push(chunk)
@@ -361,7 +393,7 @@ export class Client extends EventEmitter {
361
393
 
362
394
 
363
395
  /** Send a Msg (or Msg[]) to the server.*/
364
- SendMsgEx(Msgs: MsgPacker[] | MsgPacker) {
396
+ SendMsgEx(Msgs: MsgPacker[] | MsgPacker, flags = 0) {
365
397
  if (this.State == States.STATE_OFFLINE)
366
398
  return;
367
399
  if (!this.socket)
@@ -397,7 +429,7 @@ export class Client extends EventEmitter {
397
429
  this.lastSentMessages.push({msg: Msg, ack: this.clientAck})
398
430
  }
399
431
  })
400
- let flags = 0;
432
+ // let flags = 0;
401
433
  if (this.requestResend)
402
434
  flags |= 4;
403
435
 
@@ -458,12 +490,16 @@ export class Client extends EventEmitter {
458
490
  chunk.msgid = (packet[0]-(packet[0]&1))/2;
459
491
  chunk.msg = messageTypes[packet[0]&1][chunk.msgid];
460
492
  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
- })
493
+ if (chunk.msgid == 0) {
494
+ let uuid = this.UUIDManager.LookupUUID(chunk.raw.slice(0,16));
495
+ if (uuid !== undefined) {
496
+ chunk.extended_msgid = uuid.hash;
497
+ chunk.msgid = uuid.type_id;
498
+ chunk.msg = uuid.name;
499
+ chunk.raw = chunk.raw.slice(16);
500
+ }
501
+
502
+ }
467
503
  return chunk;
468
504
  }
469
505
 
@@ -479,7 +515,7 @@ export class Client extends EventEmitter {
479
515
  } else if (this.State == States.STATE_OFFLINE)
480
516
  clearInterval(predTimer);
481
517
 
482
- }, 20);
518
+ }, 1000/50); // 50 ticks per second
483
519
 
484
520
  this.SendControlMsg(1, "TKEN")
485
521
  let connectInterval = setInterval(() => {
@@ -496,7 +532,7 @@ export class Client extends EventEmitter {
496
532
  return;
497
533
  this.time = new Date().getTime();
498
534
  this.sendInput();
499
- }, 500)
535
+ }, 50)
500
536
  }
501
537
 
502
538
  let resendTimeout = setInterval(() => {
@@ -540,17 +576,15 @@ export class Client extends EventEmitter {
540
576
 
541
577
  var client_version = new MsgPacker(0, true, 1);
542
578
  client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
543
- let randomUuid = Buffer.allocUnsafe(16);
544
-
545
- randomBytes(16).copy(randomUuid);
579
+ let randomUuid = randomBytes(16);
546
580
 
547
581
  client_version.AddBuffer(randomUuid);
548
582
  if (this.options?.ddnet_version !== undefined) {
549
583
  client_version.AddInt(this.options?.ddnet_version.version);
550
584
  client_version.AddString("DDNet " + this.options?.ddnet_version.release_version);
551
585
  } else {
552
- client_version.AddInt(16003);
553
- client_version.AddString("DDNet 16.0.3");
586
+ client_version.AddInt(16050);
587
+ client_version.AddString("DDNet 16.5.0");
554
588
  }
555
589
 
556
590
  this.SendMsgEx([client_version, info])
@@ -699,10 +733,10 @@ export class Client extends EventEmitter {
699
733
 
700
734
  this.emit("snapshot", snapUnpacked.items);
701
735
  this.AckGameTick = snapUnpacked.recvTick;
702
- if (Math.abs(this.PredGameTick - this.AckGameTick) > 10)
736
+ if (Math.abs(this.PredGameTick - this.AckGameTick) > 10) {
703
737
  this.PredGameTick = this.AckGameTick + 1;
704
-
705
- this.sendInput();
738
+ this.sendInput();
739
+ }
706
740
  }
707
741
 
708
742
 
@@ -712,7 +746,93 @@ export class Client extends EventEmitter {
712
746
  // })
713
747
 
714
748
 
715
- }
749
+ }
750
+
751
+ if (chunk.msgid >= NETMSG_Sys.NETMSG_WHATIS && chunk.msgid <= NETMSG_Sys.NETMSG_CHECKSUM_ERROR) {
752
+ if (chunk.msgid == NETMSG_Sys.NETMSG_WHATIS) {
753
+ let Uuid = chunk.raw.slice(0, 16);
754
+
755
+ let uuid = this.UUIDManager.LookupUUID(Uuid);
756
+ let packer = new MsgPacker(0, true, 1);
757
+ if (uuid !== undefined) {
758
+ // IT_IS msg
759
+ packer.AddBuffer(this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_ITIS)!.hash);
760
+
761
+ packer.AddBuffer(Uuid);
762
+ packer.AddString(uuid.name);
763
+ } else {
764
+ // dont_know msg
765
+ packer.AddBuffer(this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_IDONTKNOW)!.hash);
766
+
767
+ packer.AddBuffer(Uuid);
768
+ }
769
+ this.QueueChunkEx(packer)
770
+ }
771
+
772
+ if (chunk.msgid == NETMSG_Sys.NETMSG_MAP_DETAILS) { // TODO: option for downloading maps
773
+ let unpacker = new MsgUnpacker(chunk.raw);
774
+
775
+ let map_name = unpacker.unpackString();
776
+ let map_sha256: Buffer = Buffer.alloc(32);
777
+ if (unpacker.remaining.length >= 32)
778
+ map_sha256 = unpacker.unpackRaw(32);
779
+ let map_crc = unpacker.unpackInt();
780
+ let map_size = unpacker.unpackInt();
781
+
782
+ let map_url = "";
783
+ if (unpacker.remaining.length)
784
+ map_url = unpacker.unpackString();
785
+
786
+ this.emit("map_details", {map_name, map_sha256, map_crc, map_size, map_url})
787
+ // unpacker.unpack
788
+
789
+ } else if (chunk.msgid == NETMSG_Sys.NETMSG_CAPABILITIES) {
790
+ let unpacker = new MsgUnpacker(chunk.raw);
791
+ let Version = unpacker.unpackInt();
792
+ let Flags = unpacker.unpackInt();
793
+ if (Version <= 0)
794
+ return;
795
+ let DDNet = false;
796
+ if (Version >= 1) {
797
+ DDNet = Boolean(Flags & 1);
798
+
799
+ }
800
+ let ChatTimeoutCode = DDNet;
801
+ let AnyPlayerFlag = DDNet;
802
+ let PingEx = false;
803
+ let AllowDummy = true;
804
+ let SyncWeaponInput = false;
805
+ if(Version >= 1)
806
+ {
807
+ ChatTimeoutCode = Boolean(Flags & 2);
808
+ }
809
+ if(Version >= 2)
810
+ {
811
+ AnyPlayerFlag = Boolean(Flags & 4);
812
+ }
813
+ if(Version >= 3)
814
+ {
815
+ PingEx = Boolean(Flags & 8);
816
+ }
817
+ if(Version >= 4)
818
+ {
819
+ AllowDummy = Boolean(Flags & 16);
820
+ }
821
+ if(Version >= 5)
822
+ {
823
+ SyncWeaponInput = Boolean(Flags & 32);
824
+ }
825
+ this.emit("capabilities", {ChatTimeoutCode, AnyPlayerFlag, PingEx, AllowDummy, SyncWeaponInput});
826
+ // https://github.com/ddnet/ddnet/blob/06e3eb564150e9ab81b3a5595c48e9fe5952ed32/src/engine/client/client.cpp#L1565
827
+ } else if (chunk.msgid == NETMSG_Sys.NETMSG_PINGEX) {
828
+ let packer = new MsgPacker(0, true, 2);
829
+ packer.AddBuffer(this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_PONGEX)!.hash);
830
+
831
+ this.SendMsgEx(packer, 2);
832
+ }
833
+
834
+ }
835
+
716
836
  } else {
717
837
  // game messages
718
838
 
@@ -726,7 +846,7 @@ export class Client extends EventEmitter {
726
846
  for (let i = 0; i < 15; i++) {
727
847
  list.push(unpacker.unpackString());
728
848
  }
729
- list = list.slice(NumOptions);
849
+ list = list.slice(0, NumOptions);
730
850
 
731
851
  this.VoteList.push(...list);
732
852
  } 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;