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/README.md +7 -7
- package/docs/events.md +367 -0
- package/docs/examples/chat_bot.js +25 -0
- package/docs/examples/kill_on_freeze.js +20 -0
- package/lib/MsgUnpacker.js +6 -0
- package/lib/MsgUnpacker.ts +7 -0
- package/lib/UUIDManager.js +50 -0
- package/lib/UUIDManager.ts +45 -0
- package/lib/client.js +125 -30
- package/lib/client.ts +154 -34
- package/lib/components/movement.js +28 -0
- package/lib/components/movement.ts +25 -0
- package/lib/components/snapshot.js +58 -0
- package/lib/components/snapshot.ts +47 -2
- package/lib/snapshot.js +114 -20
- package/lib/snapshot.ts +130 -32
- package/lib/snapshots.d.ts +57 -9
- package/package.json +1 -1
- package/test.js +57 -0
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
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
chunk.
|
|
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
|
-
|
|
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
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
chunk.
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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 =
|
|
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(
|
|
412
|
-
client_version.AddString("DDNet 16.0
|
|
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
|
-
|
|
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
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
chunk.
|
|
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
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
chunk.
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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 =
|
|
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(
|
|
553
|
-
client_version.AddString("DDNet 16.0
|
|
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
|
-
|
|
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;
|