teeworlds 2.0.3 → 2.0.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/client.js CHANGED
@@ -308,184 +308,187 @@ var Client = /** @class */ (function (_super) {
308
308
  clearInterval(connectInterval);
309
309
  }, 500);
310
310
  this.time = new Date().getTime() + 2000; // start sending keepalives after 2s
311
- this.socket.on("message", function (a) { return __awaiter(_this, void 0, void 0, function () {
312
- var unpacked, chunkMessages, chat, chat, info, client_version, randomUuid, reason, Msg, Msg, info, info, chunks, part_1, num_parts_1;
313
- var _this = this;
314
- return __generator(this, function (_a) {
315
- switch (_a.label) {
316
- case 0: return [4 /*yield*/, this.Unpack(a)];
317
- case 1:
318
- unpacked = _a.sent();
319
- if (unpacked.twprotocol.flags != 128 && unpacked.twprotocol.ack) {
320
- unpacked.chunks.forEach(function (a) {
321
- if (a.msg && !a.msg.startsWith("SNAP")) {
322
- if (a.seq != undefined && a.seq != -1)
323
- _this.ack = a.seq;
324
- }
325
- });
326
- }
327
- chunkMessages = unpacked.chunks.map(function (a) { return a.msg; });
328
- if (chunkMessages.includes("SV_CHAT")) {
329
- chat = unpacked.chunks.filter(function (a) { return a.msg == "SV_CHAT"; });
330
- chat.forEach(function (a) {
331
- if (a.msg == "SV_CHAT") {
332
- var unpacked = {};
333
- unpacked.team = MsgUnpacker_1.default.unpackInt(a.raw.toJSON().data).result;
334
- var remaining = MsgUnpacker_1.default.unpackInt(a.raw.toJSON().data).remaining;
335
- unpacked.client_id = MsgUnpacker_1.default.unpackInt(remaining).result;
336
- remaining = MsgUnpacker_1.default.unpackInt(remaining).remaining;
337
- unpacked.message = MsgUnpacker_1.default.unpackString(remaining).result;
338
- if (unpacked.client_id != -1)
339
- unpacked.author = { ClientInfo: _this.client_infos[unpacked.client_id], PlayerInfo: _this.player_infos[unpacked.client_id] };
340
- // console.log(unpacked)
341
- _this.emit("message", unpacked);
311
+ if (this.socket)
312
+ this.socket.on("message", function (a) { return __awaiter(_this, void 0, void 0, function () {
313
+ var unpacked, chunkMessages, chat, chat, info, client_version, randomUuid, reason, Msg, Msg, info, info, chunks, part_1, num_parts_1;
314
+ var _this = this;
315
+ return __generator(this, function (_a) {
316
+ switch (_a.label) {
317
+ case 0: return [4 /*yield*/, this.Unpack(a)];
318
+ case 1:
319
+ unpacked = _a.sent();
320
+ if (unpacked.twprotocol.flags != 128 && unpacked.twprotocol.ack) {
321
+ unpacked.chunks.forEach(function (a) {
322
+ if (a.msg && !a.msg.startsWith("SNAP")) {
323
+ if (a.seq != undefined && a.seq != -1)
324
+ _this.ack = a.seq;
325
+ }
326
+ });
327
+ }
328
+ chunkMessages = unpacked.chunks.map(function (a) { return a.msg; });
329
+ if (chunkMessages.includes("SV_CHAT")) {
330
+ chat = unpacked.chunks.filter(function (a) { return a.msg == "SV_CHAT"; });
331
+ chat.forEach(function (a) {
332
+ if (a.msg == "SV_CHAT") {
333
+ var unpacked = {};
334
+ unpacked.team = MsgUnpacker_1.default.unpackInt(a.raw.toJSON().data).result;
335
+ var remaining = MsgUnpacker_1.default.unpackInt(a.raw.toJSON().data).remaining;
336
+ unpacked.client_id = MsgUnpacker_1.default.unpackInt(remaining).result;
337
+ remaining = MsgUnpacker_1.default.unpackInt(remaining).remaining;
338
+ unpacked.message = MsgUnpacker_1.default.unpackString(remaining).result;
339
+ if (unpacked.client_id != -1)
340
+ unpacked.author = { ClientInfo: _this.client_infos[unpacked.client_id], PlayerInfo: _this.player_infos[unpacked.client_id] };
341
+ // console.log(unpacked)
342
+ _this.emit("message", unpacked);
343
+ }
344
+ });
345
+ }
346
+ if (chunkMessages.includes("SV_KILL_MSG")) {
347
+ chat = unpacked.chunks.filter(function (a) { return a.msg == "SV_KILL_MSG"; });
348
+ chat.forEach(function (a) {
349
+ if (a.msg == "SV_KILL_MSG") {
350
+ var unpacked = {};
351
+ unpacked.killer_id = MsgUnpacker_1.default.unpackInt(a.raw.toJSON().data).result;
352
+ var remaining = MsgUnpacker_1.default.unpackInt(a.raw.toJSON().data).remaining;
353
+ unpacked.victim_id = MsgUnpacker_1.default.unpackInt(remaining).result;
354
+ remaining = MsgUnpacker_1.default.unpackInt(remaining).remaining;
355
+ unpacked.weapon = MsgUnpacker_1.default.unpackInt(remaining).result;
356
+ remaining = MsgUnpacker_1.default.unpackInt(remaining).remaining;
357
+ unpacked.special_mode = MsgUnpacker_1.default.unpackInt(remaining).result;
358
+ if (unpacked.victim_id != -1)
359
+ unpacked.victim = { ClientInfo: _this.client_infos[unpacked.victim_id], PlayerInfo: _this.player_infos[unpacked.victim_id] };
360
+ if (unpacked.killer_id != -1)
361
+ unpacked.killer = { ClientInfo: _this.client_infos[unpacked.killer_id], PlayerInfo: _this.player_infos[unpacked.killer_id] };
362
+ // console.log(unpacked)
363
+ _this.emit("kill", unpacked);
364
+ }
365
+ });
366
+ }
367
+ if (a.toJSON().data[0] == 0x10) {
368
+ if (a.toString().includes("TKEN") || arrStartsWith(a.toJSON().data, [0x10, 0x0, 0x0, 0x0])) {
369
+ clearInterval(connectInterval);
370
+ this.TKEN = Buffer.from(a.toJSON().data.slice(a.toJSON().data.length - 4, a.toJSON().data.length));
371
+ this.SendControlMsg(3);
372
+ this.State = 2; // loading state
373
+ info = new MsgPacker_1.default(1, true);
374
+ info.AddString("0.6 626fce9a778df4d4");
375
+ info.AddString(""); // password
376
+ client_version = new MsgPacker_1.default(0, true);
377
+ client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
378
+ randomUuid = new Uint8Array(16);
379
+ crypto_1.randomBytes(16).copy(randomUuid);
380
+ client_version.AddBuffer(Buffer.from(randomUuid));
381
+ client_version.AddInt(15091);
382
+ client_version.AddString("DDNet 15.9.1");
383
+ this.SendMsgExWithChunks([client_version, info], 1);
342
384
  }
343
- });
344
- }
345
- if (chunkMessages.includes("SV_KILL_MSG")) {
346
- chat = unpacked.chunks.filter(function (a) { return a.msg == "SV_KILL_MSG"; });
347
- chat.forEach(function (a) {
348
- if (a.msg == "SV_KILL_MSG") {
349
- var unpacked = {};
350
- unpacked.killer_id = MsgUnpacker_1.default.unpackInt(a.raw.toJSON().data).result;
351
- var remaining = MsgUnpacker_1.default.unpackInt(a.raw.toJSON().data).remaining;
352
- unpacked.victim_id = MsgUnpacker_1.default.unpackInt(remaining).result;
353
- remaining = MsgUnpacker_1.default.unpackInt(remaining).remaining;
354
- unpacked.weapon = MsgUnpacker_1.default.unpackInt(remaining).result;
355
- remaining = MsgUnpacker_1.default.unpackInt(remaining).remaining;
356
- unpacked.special_mode = MsgUnpacker_1.default.unpackInt(remaining).result;
357
- if (unpacked.victim_id != -1)
358
- unpacked.victim = { ClientInfo: _this.client_infos[unpacked.victim_id], PlayerInfo: _this.player_infos[unpacked.victim_id] };
359
- if (unpacked.killer_id != -1)
360
- unpacked.killer = { ClientInfo: _this.client_infos[unpacked.killer_id], PlayerInfo: _this.player_infos[unpacked.killer_id] };
361
- // console.log(unpacked)
362
- _this.emit("kill", unpacked);
385
+ else if (a.toJSON().data[3] == 0x4) {
386
+ // disconnected
387
+ this.State = 0;
388
+ reason = (MsgUnpacker_1.default.unpackString(a.toJSON().data.slice(4)).result);
389
+ this.State = -1;
390
+ this.emit("disconnect", reason);
363
391
  }
364
- });
365
- }
366
- if (a.toJSON().data[0] == 0x10) {
367
- if (a.toString().includes("TKEN") || arrStartsWith(a.toJSON().data, [0x10, 0x0, 0x0, 0x0])) {
368
- clearInterval(connectInterval);
369
- this.TKEN = Buffer.from(a.toJSON().data.slice(a.toJSON().data.length - 4, a.toJSON().data.length));
370
- this.SendControlMsg(3);
371
- this.State = 2; // loading state
372
- info = new MsgPacker_1.default(1, true);
373
- info.AddString("0.6 626fce9a778df4d4");
374
- info.AddString(""); // password
375
- client_version = new MsgPacker_1.default(0, true);
376
- client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
377
- randomUuid = new Uint8Array(16);
378
- crypto_1.randomBytes(16).copy(randomUuid);
379
- client_version.AddBuffer(Buffer.from(randomUuid));
380
- client_version.AddInt(15091);
381
- client_version.AddString("DDNet 15.9.1");
382
- this.SendMsgExWithChunks([client_version, info], 1);
383
392
  }
384
- else if (a.toJSON().data[3] == 0x4) {
385
- // disconnected
386
- this.State = 0;
387
- reason = (MsgUnpacker_1.default.unpackString(a.toJSON().data.slice(4)).result);
388
- this.State = -1;
389
- this.emit("disconnect", reason);
393
+ if (unpacked.chunks[0] && chunkMessages.includes("SV_READY_TO_ENTER")) {
394
+ Msg = new MsgPacker_1.default(15, true);
395
+ this.SendMsgEx(Msg, 1);
390
396
  }
391
- }
392
- if (unpacked.chunks[0] && chunkMessages.includes("SV_READY_TO_ENTER")) {
393
- Msg = new MsgPacker_1.default(15, true);
394
- this.SendMsgEx(Msg, 1);
395
- }
396
- else if ((unpacked.chunks[0] && chunkMessages.includes("CAPABILITIES") || unpacked.chunks[0] && chunkMessages.includes("MAP_CHANGE"))) {
397
- Msg = new MsgPacker_1.default(14, true);
398
- this.SendMsgEx(Msg, 1);
399
- }
400
- else if ((unpacked.chunks[0] && chunkMessages.includes("CON_READY") || unpacked.chunks[0] && chunkMessages.includes("SV_MOTD"))) {
401
- info = new MsgPacker_1.default(20, false);
402
- info.AddString(this.name); /* name */
403
- info.AddString(""); /* clan */
404
- info.AddInt(-1); /* country */
405
- info.AddString("greyfox"); /* skin */
406
- info.AddInt(1); /* use custom color */
407
- info.AddInt(10346103); /* color body */
408
- info.AddInt(65535); /* color feet */
409
- this.SendMsgEx(info, 1);
410
- }
411
- else if (unpacked.chunks[0] && chunkMessages.includes("SV_READY_TO_ENTER")) {
412
- if (this.State != 3) {
413
- this.emit('connected');
397
+ else if ((unpacked.chunks[0] && chunkMessages.includes("CAPABILITIES") || unpacked.chunks[0] && chunkMessages.includes("MAP_CHANGE"))) {
398
+ Msg = new MsgPacker_1.default(14, true);
399
+ this.SendMsgEx(Msg, 1);
414
400
  }
415
- this.State = 3;
416
- }
417
- else if (unpacked.chunks[0] && chunkMessages.includes("PING")) {
418
- info = new MsgPacker_1.default(23, true);
419
- this.SendMsgEx(info, 1);
420
- }
421
- if (chunkMessages.includes("SNAP") || chunkMessages.includes("SNAP_EMPTY") || chunkMessages.includes("SNAP_SINGLE")) {
422
- this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
423
- if (this.receivedSnaps >= 2) {
424
- if (this.State != 3)
401
+ else if ((unpacked.chunks[0] && chunkMessages.includes("CON_READY") || unpacked.chunks[0] && chunkMessages.includes("SV_MOTD"))) {
402
+ info = new MsgPacker_1.default(20, false);
403
+ info.AddString(this.name); /* name */
404
+ info.AddString(""); /* clan */
405
+ info.AddInt(-1); /* country */
406
+ info.AddString("greyfox"); /* skin */
407
+ info.AddInt(1); /* use custom color */
408
+ info.AddInt(10346103); /* color body */
409
+ info.AddInt(65535); /* color feet */
410
+ this.SendMsgEx(info, 1);
411
+ }
412
+ else if (unpacked.chunks[0] && chunkMessages.includes("SV_READY_TO_ENTER")) {
413
+ if (this.State != 3) {
425
414
  this.emit('connected');
415
+ }
426
416
  this.State = 3;
427
417
  }
428
- chunks = unpacked.chunks.filter(function (a) { return a.msg == "SNAP" || a.msg == "SNAP_SINGLE" || a.msg == "SNAP_EMPTY"; });
429
- if (chunks.length > 0) {
430
- part_1 = 0;
431
- num_parts_1 = 1;
432
- chunks.forEach(function (chunk) {
433
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
434
- var AckGameTick = (MsgUnpacker_1.default.unpackInt(chunk.raw.toJSON().data).result);
435
- chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_a = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _a === void 0 ? void 0 : _a.toJSON().data).remaining);
436
- var DeltaTick = MsgUnpacker_1.default.unpackInt((_b = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _b === void 0 ? void 0 : _b.toJSON().data).result;
437
- if (chunk.msg == "SNAP") {
438
- chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_c = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _c === void 0 ? void 0 : _c.toJSON().data).remaining); // delta tick
439
- num_parts_1 = (MsgUnpacker_1.default.unpackInt((_d = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _d === void 0 ? void 0 : _d.toJSON().data).result);
440
- chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_e = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _e === void 0 ? void 0 : _e.toJSON().data).remaining); // num parts
441
- part_1 = (MsgUnpacker_1.default.unpackInt((_f = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _f === void 0 ? void 0 : _f.toJSON().data).result);
442
- }
443
- chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_g = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _g === void 0 ? void 0 : _g.toJSON().data).remaining); // part
444
- if (chunk.msg != "SNAP_EMPTY")
445
- chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_h = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _h === void 0 ? void 0 : _h.toJSON().data).remaining); // crc
446
- chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_j = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _j === void 0 ? void 0 : _j.toJSON().data).remaining); // crc
447
- if (part_1 == 0 || _this.snaps.length > 30) {
448
- _this.snaps = [];
449
- }
450
- _this.snaps.push(chunk.raw);
451
- if ((num_parts_1 - 1) == part_1 && _this.snaps.length == num_parts_1) {
452
- var mergedSnaps = Buffer.concat(_this.snaps);
453
- var snapUnpacked = SnapUnpacker.unpackSnapshot(mergedSnaps.toJSON().data, 1);
454
- snapUnpacked.items.forEach(function (a, i) {
455
- if (a.type_id == items.OBJ_CLIENT_INFO) {
456
- _this.client_infos[a.id] = a.parsed;
457
- // console.log(a.parsed, i)
458
- // console.log(this.client_infos[a.id])
459
- }
460
- else if (a.type_id == items.OBJ_PLAYER_INFO) {
461
- _this.player_infos[i] = a.parsed;
462
- }
463
- else if (a.type_id == items.OBJ_EX || a.type_id > 0x4000) {
464
- if (a.data.length == 5 && (a.parsed.freeze_end > 0 || a.parsed.freeze_end == -1)) {
465
- // var packer = new MsgPacker(22, false)
466
- // this.SendMsgEx(packer, 1)
418
+ else if (unpacked.chunks[0] && chunkMessages.includes("PING")) {
419
+ info = new MsgPacker_1.default(23, true);
420
+ this.SendMsgEx(info, 1);
421
+ }
422
+ if (chunkMessages.includes("SNAP") || chunkMessages.includes("SNAP_EMPTY") || chunkMessages.includes("SNAP_SINGLE")) {
423
+ this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
424
+ if (this.receivedSnaps >= 2) {
425
+ if (this.State != 3)
426
+ this.emit('connected');
427
+ this.State = 3;
428
+ }
429
+ chunks = unpacked.chunks.filter(function (a) { return a.msg == "SNAP" || a.msg == "SNAP_SINGLE" || a.msg == "SNAP_EMPTY"; });
430
+ if (chunks.length > 0) {
431
+ part_1 = 0;
432
+ num_parts_1 = 1;
433
+ chunks.forEach(function (chunk) {
434
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
435
+ var AckGameTick = (MsgUnpacker_1.default.unpackInt(chunk.raw.toJSON().data).result);
436
+ chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_a = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _a === void 0 ? void 0 : _a.toJSON().data).remaining);
437
+ var DeltaTick = MsgUnpacker_1.default.unpackInt((_b = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _b === void 0 ? void 0 : _b.toJSON().data).result;
438
+ if (chunk.msg == "SNAP") {
439
+ chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_c = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _c === void 0 ? void 0 : _c.toJSON().data).remaining); // delta tick
440
+ num_parts_1 = (MsgUnpacker_1.default.unpackInt((_d = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _d === void 0 ? void 0 : _d.toJSON().data).result);
441
+ chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_e = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _e === void 0 ? void 0 : _e.toJSON().data).remaining); // num parts
442
+ part_1 = (MsgUnpacker_1.default.unpackInt((_f = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _f === void 0 ? void 0 : _f.toJSON().data).result);
443
+ }
444
+ chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_g = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _g === void 0 ? void 0 : _g.toJSON().data).remaining); // part
445
+ if (chunk.msg != "SNAP_EMPTY")
446
+ chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_h = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _h === void 0 ? void 0 : _h.toJSON().data).remaining); // crc
447
+ chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_j = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _j === void 0 ? void 0 : _j.toJSON().data).remaining); // crc
448
+ if (part_1 == 0 || _this.snaps.length > 30) {
449
+ _this.snaps = [];
450
+ }
451
+ _this.snaps.push(chunk.raw);
452
+ if ((num_parts_1 - 1) == part_1 && _this.snaps.length == num_parts_1) {
453
+ var mergedSnaps = Buffer.concat(_this.snaps);
454
+ var snapUnpacked = SnapUnpacker.unpackSnapshot(mergedSnaps.toJSON().data, 1);
455
+ snapUnpacked.items.forEach(function (a, i) {
456
+ if (a.type_id == items.OBJ_CLIENT_INFO) {
457
+ _this.client_infos[a.id] = a.parsed;
458
+ // console.log(a.parsed, i)
459
+ // console.log(this.client_infos[a.id])
467
460
  }
468
- }
469
- });
470
- }
471
- });
461
+ else if (a.type_id == items.OBJ_PLAYER_INFO) {
462
+ _this.player_infos[i] = a.parsed;
463
+ }
464
+ else if (a.type_id == items.OBJ_EX || a.type_id > 0x4000) {
465
+ if (a.data.length == 5 && (a.parsed.freeze_end > 0 || a.parsed.freeze_end == -1)) {
466
+ // var packer = new MsgPacker(22, false)
467
+ // this.SendMsgEx(packer, 1)
468
+ }
469
+ }
470
+ });
471
+ }
472
+ });
473
+ }
472
474
  }
473
- }
474
- if (new Date().getTime() - this.time >= 1000) {
475
- this.time = new Date().getTime();
476
- this.SendControlMsg(0);
477
- }
478
- return [2 /*return*/];
479
- }
480
- });
481
- }); });
475
+ if (new Date().getTime() - this.time >= 1000) {
476
+ this.time = new Date().getTime();
477
+ this.SendControlMsg(0);
478
+ }
479
+ return [2 /*return*/];
480
+ }
481
+ });
482
+ }); });
482
483
  };
483
484
  Client.prototype.Disconnect = function () {
484
485
  var _this = this;
485
486
  return new Promise(function (resolve) {
486
487
  _this.SendControlMsg(4).then(function () {
487
488
  resolve(true);
488
- _this.socket.close();
489
+ if (_this.socket)
490
+ _this.socket.close();
491
+ _this.socket = undefined;
489
492
  _this.State = -1;
490
493
  });
491
494
  });
package/lib/client.ts CHANGED
@@ -156,7 +156,7 @@ declare interface Client {
156
156
  receivedSnaps: number; /* wait for 2 ss before seeing self as connected */
157
157
  lastMsg: string;
158
158
  _port: number;
159
- socket: net.Socket;
159
+ socket: net.Socket | undefined;
160
160
  TKEN: Buffer;
161
161
  time: number;
162
162
 
@@ -310,6 +310,7 @@ class Client extends EventEmitter {
310
310
  clearInterval(connectInterval)
311
311
  }, 500)
312
312
  this.time = new Date().getTime() + 2000; // start sending keepalives after 2s
313
+ if (this.socket)
313
314
  this.socket.on("message", async (a) => {
314
315
  var unpacked: _packet = await this.Unpack(a)
315
316
  if (unpacked.twprotocol.flags != 128 && unpacked.twprotocol.ack) {
@@ -485,7 +486,9 @@ class Client extends EventEmitter {
485
486
  return new Promise((resolve) => {
486
487
  this.SendControlMsg(4).then(() => {
487
488
  resolve(true);
488
- this.socket.close();
489
+ if (this.socket)
490
+ this.socket.close();
491
+ this.socket = undefined
489
492
  this.State = -1;
490
493
  })
491
494
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teeworlds",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
4
4
  "description": "Library for (ingame) teeworlds bots.",
5
5
  "license": "MIT",
6
6
  "main": "index.js",