teeworlds 2.5.4 → 2.5.6

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.
Files changed (54) hide show
  1. package/README.md +4 -3
  2. package/{index.ts → index.d.ts} +6 -6
  3. package/index.js +25 -24
  4. package/index.js.map +1 -0
  5. package/lib/MsgPacker.d.ts +11 -0
  6. package/lib/MsgPacker.js +47 -55
  7. package/lib/MsgPacker.js.map +1 -0
  8. package/lib/MsgUnpacker.d.ts +16 -0
  9. package/lib/MsgUnpacker.js +53 -53
  10. package/lib/MsgUnpacker.js.map +1 -0
  11. package/lib/UUIDManager.d.ts +27 -0
  12. package/lib/UUIDManager.js +45 -50
  13. package/lib/UUIDManager.js.map +1 -0
  14. package/lib/client.d.ts +135 -0
  15. package/lib/client.js +762 -830
  16. package/lib/client.js.map +1 -0
  17. package/lib/components/game.d.ts +32 -0
  18. package/lib/components/game.js +104 -106
  19. package/lib/components/game.js.map +1 -0
  20. package/lib/components/movement.d.ts +34 -0
  21. package/lib/components/movement.js +75 -82
  22. package/lib/components/movement.js.map +1 -0
  23. package/lib/components/rcon.d.ts +33 -0
  24. package/lib/components/rcon.js +92 -122
  25. package/lib/components/rcon.js.map +1 -0
  26. package/lib/components/snapshot.d.ts +59 -0
  27. package/lib/components/snapshot.js +144 -234
  28. package/lib/components/snapshot.js.map +1 -0
  29. package/lib/enums_types/protocol.d.ts +120 -0
  30. package/lib/enums_types/protocol.js +14 -13
  31. package/lib/enums_types/protocol.js.map +1 -0
  32. package/lib/huffman.d.ts +24 -0
  33. package/lib/huffman.js +187 -192
  34. package/lib/huffman.js.map +1 -0
  35. package/lib/snapshot.d.ts +49 -0
  36. package/lib/snapshot.js +599 -610
  37. package/lib/snapshot.js.map +1 -0
  38. package/package.json +21 -24
  39. package/docs/documentation.md +0 -368
  40. package/docs/examples/chat_bot.js +0 -25
  41. package/docs/examples/kill_on_freeze.js +0 -20
  42. package/lib/MsgPacker.ts +0 -45
  43. package/lib/MsgUnpacker.ts +0 -58
  44. package/lib/UUIDManager.ts +0 -45
  45. package/lib/client.ts +0 -926
  46. package/lib/components/game.ts +0 -133
  47. package/lib/components/movement.ts +0 -88
  48. package/lib/components/rcon.ts +0 -114
  49. package/lib/components/snapshot.ts +0 -187
  50. package/lib/enums_types/protocol.ts +0 -137
  51. package/lib/enums_types/types.d.ts +0 -236
  52. package/lib/huffman.ts +0 -226
  53. package/lib/snapshot.ts +0 -632
  54. package/tsconfig.json +0 -69
package/lib/client.js CHANGED
@@ -1,830 +1,762 @@
1
- "use strict";
2
- var __extends = (this && this.__extends) || (function () {
3
- var extendStatics = function (d, b) {
4
- extendStatics = Object.setPrototypeOf ||
5
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
- function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
- return extendStatics(d, b);
8
- };
9
- return function (d, b) {
10
- if (typeof b !== "function" && b !== null)
11
- throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
- extendStatics(d, b);
13
- function __() { this.constructor = d; }
14
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
- };
16
- })();
17
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
- return new (P || (P = Promise))(function (resolve, reject) {
20
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
21
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
22
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
23
- step((generator = generator.apply(thisArg, _arguments || [])).next());
24
- });
25
- };
26
- var __generator = (this && this.__generator) || function (thisArg, body) {
27
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
28
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
29
- function verb(n) { return function (v) { return step([n, v]); }; }
30
- function step(op) {
31
- if (f) throw new TypeError("Generator is already executing.");
32
- while (_) try {
33
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
34
- if (y = 0, t) op = [op[0] & 2, t.value];
35
- switch (op[0]) {
36
- case 0: case 1: t = op; break;
37
- case 4: _.label++; return { value: op[1], done: false };
38
- case 5: _.label++; y = op[1]; op = [0]; continue;
39
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
40
- default:
41
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
42
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
43
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
44
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
45
- if (t[2]) _.ops.pop();
46
- _.trys.pop(); continue;
47
- }
48
- op = body.call(thisArg, _);
49
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
50
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
51
- }
52
- };
53
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
54
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
55
- if (ar || !(i in from)) {
56
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
57
- ar[i] = from[i];
58
- }
59
- }
60
- return to.concat(ar || Array.prototype.slice.call(from));
61
- };
62
- var __importDefault = (this && this.__importDefault) || function (mod) {
63
- return (mod && mod.__esModule) ? mod : { "default": mod };
64
- };
65
- Object.defineProperty(exports, "__esModule", { value: true });
66
- exports.Client = void 0;
67
- var crypto_1 = require("crypto");
68
- var dns_1 = require("dns");
69
- var dgram_1 = __importDefault(require("dgram"));
70
- var stream_1 = require("stream");
71
- var MsgUnpacker_1 = require("./MsgUnpacker");
72
- var version = require('../package.json').version;
73
- var movement_1 = __importDefault(require("./components/movement"));
74
- var MsgPacker_1 = require("./MsgPacker");
75
- var snapshot_1 = require("./snapshot");
76
- var huffman_1 = require("./huffman");
77
- var game_1 = require("./components/game");
78
- var snapshot_2 = require("./components/snapshot");
79
- var UUIDManager_1 = require("./UUIDManager");
80
- var protocol_1 = require("./enums_types/protocol");
81
- var rcon_1 = require("./components/rcon");
82
- var huff = new huffman_1.Huffman();
83
- var messageTypes = [
84
- ["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"],
85
- ["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"]
86
- ];
87
- var Client = /** @class */ (function (_super) {
88
- __extends(Client, _super);
89
- function Client(ip, port, nickname, options) {
90
- var _this = _super.call(this) || this;
91
- _this.host = ip;
92
- _this.port = port;
93
- _this.name = nickname;
94
- _this.AckGameTick = 0;
95
- _this.PredGameTick = 0;
96
- _this.currentSnapshotGameTick = 0;
97
- _this.SnapshotParts = 0;
98
- _this.rcon = new rcon_1.Rcon(_this);
99
- _this.SnapUnpacker = new snapshot_1.Snapshot(_this);
100
- // this.eSnapHolder = [];
101
- _this.requestResend = false;
102
- _this.VoteList = [];
103
- if (options)
104
- _this.options = options;
105
- _this.snaps = [];
106
- _this.sentChunkQueue = [];
107
- _this.queueChunkEx = [];
108
- _this.State = protocol_1.States.STATE_OFFLINE; // 0 = offline; 1 = STATE_CONNECTING = 1, STATE_LOADING = 2, STATE_ONLINE = 3
109
- _this.ack = 0; // ack of messages the client has received
110
- _this.clientAck = 0; // ack of messages the client has sent
111
- _this.lastCheckedChunkAck = 0; // this.ack gets reset to this when flushing - used for resetting tick on e.g. map change
112
- _this.receivedSnaps = 0; /* wait for 2 snaps before seeing self as connected */
113
- _this.socket = dgram_1.default.createSocket("udp4");
114
- _this.socket.bind();
115
- _this.TKEN = Buffer.from([255, 255, 255, 255]);
116
- _this.time = new Date().getTime() + 2000; // time (used for keepalives, start to send keepalives after 2 seconds)
117
- _this.lastSendTime = new Date().getTime();
118
- _this.lastRecvTime = new Date().getTime();
119
- _this.lastSentMessages = [];
120
- _this.movement = new movement_1.default();
121
- _this.game = new game_1.Game(_this);
122
- _this.SnapshotUnpacker = new snapshot_2.SnapshotWrapper(_this);
123
- _this.UUIDManager = new UUIDManager_1.UUIDManager();
124
- _this.UUIDManager.RegisterName("what-is@ddnet.tw", 65536 /* NETMSG.System.NETMSG_WHATIS */);
125
- _this.UUIDManager.RegisterName("it-is@ddnet.tw", 65537 /* NETMSG.System.NETMSG_ITIS */);
126
- _this.UUIDManager.RegisterName("i-dont-know@ddnet.tw", 65538 /* NETMSG.System.NETMSG_IDONTKNOW */);
127
- _this.UUIDManager.RegisterName("rcon-type@ddnet.tw", 65539 /* NETMSG.System.NETMSG_RCONTYPE */);
128
- _this.UUIDManager.RegisterName("map-details@ddnet.tw", 65540 /* NETMSG.System.NETMSG_MAP_DETAILS */);
129
- _this.UUIDManager.RegisterName("capabilities@ddnet.tw", 65541 /* NETMSG.System.NETMSG_CAPABILITIES */);
130
- _this.UUIDManager.RegisterName("clientver@ddnet.tw", 65542 /* NETMSG.System.NETMSG_CLIENTVER */);
131
- _this.UUIDManager.RegisterName("ping@ddnet.tw", 22 /* NETMSG.System.NETMSG_PING */);
132
- _this.UUIDManager.RegisterName("pong@ddnet.tw", 65544 /* NETMSG.System.NETMSG_PONGEX */);
133
- _this.UUIDManager.RegisterName("checksum-request@ddnet.tw", 65545 /* NETMSG.System.NETMSG_CHECKSUM_REQUEST */);
134
- _this.UUIDManager.RegisterName("checksum-response@ddnet.tw", 65546 /* NETMSG.System.NETMSG_CHECKSUM_RESPONSE */);
135
- _this.UUIDManager.RegisterName("checksum-error@ddnet.tw", 65547 /* NETMSG.System.NETMSG_CHECKSUM_ERROR */);
136
- _this.UUIDManager.RegisterName("redirect@ddnet.org", 65548 /* NETMSG.System.NETMSG_REDIRECT */);
137
- _this.UUIDManager.RegisterName("i-am-npm-package@swarfey.gitlab.io", 65549 /* NETMSG.System.NETMSG_I_AM_NPM_PACKAGE */);
138
- return _this;
139
- }
140
- Client.prototype.on = function (event, listener) {
141
- return _super.prototype.on.call(this, event, listener);
142
- };
143
- Client.prototype.emit = function (event) {
144
- var args = [];
145
- for (var _i = 1; _i < arguments.length; _i++) {
146
- args[_i - 1] = arguments[_i];
147
- }
148
- return _super.prototype.emit.apply(this, __spreadArray([event], args, false));
149
- };
150
- Client.prototype.OnEnterGame = function () {
151
- this.snaps = [];
152
- this.SnapUnpacker = new snapshot_1.Snapshot(this);
153
- this.SnapshotParts = 0;
154
- this.receivedSnaps = 0;
155
- this.SnapshotUnpacker = new snapshot_2.SnapshotWrapper(this);
156
- this.currentSnapshotGameTick = 0;
157
- this.AckGameTick = -1;
158
- this.PredGameTick = 0;
159
- };
160
- Client.prototype.ResendAfter = function (lastAck) {
161
- this.clientAck = lastAck;
162
- var toResend = [];
163
- this.lastSentMessages.forEach(function (msg) {
164
- if (msg.ack > lastAck)
165
- toResend.push(msg.msg);
166
- });
167
- toResend.forEach(function (a) { return a.flag = 1 | 2; });
168
- this.SendMsgEx(toResend);
169
- };
170
- Client.prototype.Unpack = function (packet) {
171
- var unpacked = { twprotocol: { flags: packet[0] >> 4, ack: ((packet[0] & 0xf) << 8) | packet[1], chunkAmount: packet[2], size: packet.byteLength - 3 }, chunks: [] };
172
- if (packet.indexOf(Buffer.from([0xff, 0xff, 0xff, 0xff])) == 0) // !(unpacked.twprotocol.flags & 8) || unpacked.twprotocol.flags == 255) // flags == 255 is connectionless (used for sending usernames)
173
- return unpacked;
174
- if (unpacked.twprotocol.flags & 4) { // resend flag
175
- this.ResendAfter(unpacked.twprotocol.ack);
176
- }
177
- packet = packet.slice(3);
178
- if (unpacked.twprotocol.flags & 8 && !(unpacked.twprotocol.flags & 1)) { // compression flag
179
- packet = huff.decompress(packet);
180
- if (packet.length == 1 && packet[0] == -1)
181
- return unpacked;
182
- }
183
- for (var i = 0; i < unpacked.twprotocol.chunkAmount; i++) {
184
- var chunk = {};
185
- chunk.bytes = ((packet[0] & 0x3f) << 4) | (packet[1] & ((1 << 4) - 1));
186
- chunk.flags = (packet[0] >> 6) & 3;
187
- if (chunk.flags & 1) {
188
- chunk.seq = ((packet[1] & 0xf0) << 2) | packet[2];
189
- packet = packet.slice(3); // remove flags & size
190
- }
191
- else
192
- packet = packet.slice(2);
193
- // chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
194
- chunk.sys = Boolean(packet[0] & 1); // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
195
- chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
196
- chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
197
- chunk.raw = packet.slice(1, chunk.bytes);
198
- if (chunk.msgid == 0 && chunk.raw.byteLength >= 16) {
199
- var uuid = this.UUIDManager.LookupUUID(chunk.raw.slice(0, 16));
200
- if (uuid !== undefined) {
201
- chunk.extended_msgid = uuid.hash;
202
- chunk.msg = uuid.name;
203
- chunk.raw = chunk.raw.slice(16);
204
- chunk.msgid = uuid.type_id;
205
- }
206
- }
207
- packet = packet.slice(chunk.bytes);
208
- unpacked.chunks.push(chunk);
209
- }
210
- return unpacked;
211
- };
212
- /** Send a Control Msg to the server. (used for disconnect)*/
213
- Client.prototype.SendControlMsg = function (msg, ExtraMsg) {
214
- var _this = this;
215
- if (ExtraMsg === void 0) { ExtraMsg = ""; }
216
- this.lastSendTime = new Date().getTime();
217
- return new Promise(function (resolve, reject) {
218
- if (_this.socket) {
219
- var latestBuf = Buffer.from([0x10 + (((16 << 4) & 0xf0) | ((_this.ack >> 8) & 0xf)), _this.ack & 0xff, 0x00, msg]);
220
- latestBuf = Buffer.concat([latestBuf, Buffer.from(ExtraMsg), _this.TKEN]); // move header (latestBuf), optional extraMsg & TKEN into 1 buffer
221
- _this.socket.send(latestBuf, 0, latestBuf.length, _this.port, _this.host, function (err, bytes) {
222
- resolve(bytes);
223
- });
224
- }
225
- setTimeout(function () { resolve("failed, rip"); }, 2000);
226
- /* after 2 seconds it was probably not able to send,
227
- so when sending a quit message the user doesnt
228
- stay stuck not being able to ctrl + c
229
- */
230
- });
231
- };
232
- /** Send a Msg (or Msg[]) to the server.*/
233
- Client.prototype.SendMsgEx = function (Msgs, flags) {
234
- var _this = this;
235
- if (flags === void 0) { flags = 0; }
236
- if (this.State == protocol_1.States.STATE_OFFLINE)
237
- return;
238
- if (!this.socket)
239
- return;
240
- var _Msgs;
241
- if (Msgs instanceof Array)
242
- _Msgs = Msgs;
243
- else
244
- _Msgs = [Msgs];
245
- if (this.queueChunkEx.length > 0) {
246
- _Msgs.push.apply(_Msgs, this.queueChunkEx);
247
- this.queueChunkEx = [];
248
- }
249
- this.lastSendTime = new Date().getTime();
250
- var header = [];
251
- if (this.clientAck == 0)
252
- this.lastSentMessages = [];
253
- _Msgs.forEach(function (Msg, index) {
254
- header[index] = Buffer.alloc((Msg.flag & 1 ? 3 : 2));
255
- header[index][0] = ((Msg.flag & 3) << 6) | ((Msg.size >> 4) & 0x3f);
256
- header[index][1] = (Msg.size & 0xf);
257
- if (Msg.flag & 1) {
258
- _this.clientAck = (_this.clientAck + 1) % (1 << 10);
259
- if (_this.clientAck == 0)
260
- _this.lastSentMessages = [];
261
- header[index][1] |= (_this.clientAck >> 2) & 0xf0;
262
- header[index][2] = _this.clientAck & 0xff;
263
- header[index][0] = (((Msg.flag | 2) & 3) << 6) | ((Msg.size >> 4) & 0x3f); // 2 is resend flag (ugly hack for queue)
264
- if ((Msg.flag & 2) == 0)
265
- _this.sentChunkQueue.push(Buffer.concat([header[index], Msg.buffer]));
266
- header[index][0] = (((Msg.flag) & 3) << 6) | ((Msg.size >> 4) & 0x3f);
267
- if ((Msg.flag & 2) == 0)
268
- _this.lastSentMessages.push({ msg: Msg, ack: _this.clientAck });
269
- }
270
- });
271
- // let flags = 0;
272
- if (this.requestResend)
273
- flags |= 4;
274
- var packetHeader = Buffer.from([((flags << 4) & 0xf0) | ((this.ack >> 8) & 0xf), this.ack & 0xff, _Msgs.length]);
275
- var chunks = Buffer.from([]);
276
- var skip = false;
277
- _Msgs.forEach(function (Msg, index) {
278
- if (skip)
279
- return;
280
- if (chunks.byteLength < 1300)
281
- chunks = Buffer.concat([chunks, Buffer.from(header[index]), Msg.buffer]);
282
- else {
283
- skip = true;
284
- _this.SendMsgEx(_Msgs.slice(index));
285
- }
286
- });
287
- var packet = Buffer.concat([(packetHeader), chunks, this.TKEN]);
288
- if (chunks.length < 0)
289
- return;
290
- this.socket.send(packet, 0, packet.length, this.port, this.host);
291
- };
292
- /** Queue a chunk (instantly sent if flush flag is set - otherwise it will be sent in the next packet). */
293
- Client.prototype.QueueChunkEx = function (Msg) {
294
- if (Msg instanceof Array) {
295
- for (var _i = 0, Msg_1 = Msg; _i < Msg_1.length; _i++) {
296
- var chunk = Msg_1[_i];
297
- this.QueueChunkEx(chunk);
298
- }
299
- return;
300
- }
301
- if (this.queueChunkEx.length > 0) {
302
- var total_size = 0;
303
- for (var _a = 0, _b = this.queueChunkEx; _a < _b.length; _a++) {
304
- var chunk = _b[_a];
305
- total_size += chunk.size;
306
- }
307
- if (total_size + Msg.size + 3 > 1394 - 4)
308
- this.Flush();
309
- }
310
- this.queueChunkEx.push(Msg);
311
- if (Msg.flag & 4)
312
- this.Flush();
313
- };
314
- /** Send a Raw Buffer (as chunk) to the server. */
315
- Client.prototype.SendMsgRaw = function (chunks) {
316
- if (this.State == protocol_1.States.STATE_OFFLINE)
317
- return;
318
- if (!this.socket)
319
- return;
320
- this.lastSendTime = new Date().getTime();
321
- var packetHeader = Buffer.from([0x0 + (((16 << 4) & 0xf0) | ((this.ack >> 8) & 0xf)), this.ack & 0xff, chunks.length]);
322
- var packet = Buffer.concat([(packetHeader), Buffer.concat(chunks), this.TKEN]);
323
- if (chunks.length < 0)
324
- return;
325
- this.socket.send(packet, 0, packet.length, this.port, this.host);
326
- };
327
- Client.prototype.MsgToChunk = function (packet) {
328
- var chunk = {};
329
- chunk.bytes = ((packet[0] & 0x3f) << 4) | (packet[1] & ((1 << 4) - 1));
330
- chunk.flags = (packet[0] >> 6) & 3;
331
- if (chunk.flags & 1) {
332
- chunk.seq = ((packet[1] & 0xf0) << 2) | packet[2];
333
- packet = packet.slice(3); // remove flags & size
334
- }
335
- else
336
- packet = packet.slice(2);
337
- // chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
338
- chunk.sys = Boolean(packet[0] & 1); // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
339
- chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
340
- chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
341
- chunk.raw = packet.slice(1, chunk.bytes);
342
- if (chunk.msgid == 0) {
343
- var uuid = this.UUIDManager.LookupUUID(chunk.raw.slice(0, 16));
344
- if (uuid !== undefined) {
345
- chunk.extended_msgid = uuid.hash;
346
- chunk.msgid = uuid.type_id;
347
- chunk.msg = uuid.name;
348
- chunk.raw = chunk.raw.slice(16);
349
- }
350
- }
351
- return chunk;
352
- };
353
- Client.prototype.Flush = function () {
354
- // if (this.queueChunkEx.length == 0)
355
- console.log("flushing");
356
- this.SendMsgEx(this.queueChunkEx);
357
- this.queueChunkEx = [];
358
- this.ack = this.lastCheckedChunkAck;
359
- };
360
- /** Connect the client to the server. */
361
- Client.prototype.connect = function () {
362
- var _a;
363
- return __awaiter(this, void 0, void 0, function () {
364
- var predTimer, connectInterval, inputInterval_1, resendTimeout, Timeout;
365
- var _this = this;
366
- return __generator(this, function (_b) {
367
- // test via regex whether or not this.host is a domain or an ip
368
- // if not, resolve it
369
- if (!this.host.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)) {
370
- (0, dns_1.lookup)(this.host, 4, function (err, address, family) {
371
- if (err)
372
- throw err;
373
- _this.host = address;
374
- console.log(err, address, family);
375
- });
376
- }
377
- this.State = protocol_1.States.STATE_CONNECTING;
378
- predTimer = setInterval(function () {
379
- if (_this.State == protocol_1.States.STATE_ONLINE) {
380
- if (_this.AckGameTick > 0)
381
- _this.PredGameTick++;
382
- }
383
- else if (_this.State == protocol_1.States.STATE_OFFLINE)
384
- clearInterval(predTimer);
385
- }, 1000 / 50);
386
- this.SendControlMsg(1, "TKEN");
387
- connectInterval = setInterval(function () {
388
- if (_this.State == protocol_1.States.STATE_CONNECTING)
389
- _this.SendControlMsg(1, "TKEN");
390
- else
391
- clearInterval(connectInterval);
392
- }, 500);
393
- if (!((_a = this.options) === null || _a === void 0 ? void 0 : _a.lightweight)) {
394
- inputInterval_1 = setInterval(function () {
395
- if (_this.State == protocol_1.States.STATE_OFFLINE) {
396
- clearInterval(inputInterval_1);
397
- // console.log("???");
398
- }
399
- if (_this.State != protocol_1.States.STATE_ONLINE)
400
- return;
401
- _this.time = new Date().getTime();
402
- _this.sendInput();
403
- }, 50);
404
- }
405
- resendTimeout = setInterval(function () {
406
- if (_this.State != protocol_1.States.STATE_OFFLINE) {
407
- if (((new Date().getTime()) - _this.lastSendTime) > 900 && _this.sentChunkQueue.length > 0) {
408
- _this.SendMsgRaw([_this.sentChunkQueue[0]]);
409
- }
410
- }
411
- else
412
- clearInterval(resendTimeout);
413
- }, 1000);
414
- Timeout = setInterval(function () {
415
- var _a;
416
- var timeoutTime = ((_a = _this.options) === null || _a === void 0 ? void 0 : _a.timeout) ? _this.options.timeout : 15000;
417
- if ((new Date().getTime() - _this.lastRecvTime) > timeoutTime) {
418
- _this.State = protocol_1.States.STATE_OFFLINE;
419
- _this.emit("disconnect", "Timed Out. (no packets received for " + (new Date().getTime() - _this.lastRecvTime) + "ms)");
420
- clearInterval(Timeout);
421
- }
422
- }, 5000);
423
- this.time = new Date().getTime() + 2000; // start sending keepalives after 2s
424
- if (this.socket)
425
- this.socket.on("message", function (packet, rinfo) {
426
- var _a, _b, _c, _d, _e, _f;
427
- if (_this.State == 0 || rinfo.address != _this.host || rinfo.port != _this.port)
428
- return;
429
- clearInterval(connectInterval);
430
- if (packet[0] == 0x10) {
431
- if (packet.toString().includes("TKEN") || packet[3] == 0x2) {
432
- clearInterval(connectInterval);
433
- _this.TKEN = packet.slice(-4);
434
- _this.SendControlMsg(3);
435
- _this.State = protocol_1.States.STATE_LOADING; // loading state
436
- _this.receivedSnaps = 0;
437
- var info = new MsgPacker_1.MsgPacker(1, true, 1);
438
- info.AddString(((_a = _this.options) === null || _a === void 0 ? void 0 : _a.NET_VERSION) ? _this.options.NET_VERSION : "0.6 626fce9a778df4d4");
439
- 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
440
- var client_version = new MsgPacker_1.MsgPacker(0, true, 1);
441
- client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
442
- var randomUuid = (0, crypto_1.randomBytes)(16);
443
- client_version.AddBuffer(randomUuid);
444
- if (((_d = _this.options) === null || _d === void 0 ? void 0 : _d.ddnet_version) !== undefined) {
445
- client_version.AddInt((_e = _this.options) === null || _e === void 0 ? void 0 : _e.ddnet_version.version);
446
- 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));
447
- }
448
- else {
449
- client_version.AddInt(16050);
450
- client_version.AddString("DDNet 16.5.0; https://www.npmjs.com/package/teeworlds/v/".concat(version));
451
- }
452
- var i_am_npm_package = new MsgPacker_1.MsgPacker(0, true, 1);
453
- i_am_npm_package.AddBuffer(_this.UUIDManager.LookupType(65549 /* NETMSG.System.NETMSG_I_AM_NPM_PACKAGE */).hash);
454
- i_am_npm_package.AddString("https://www.npmjs.com/package/teeworlds/v/".concat(version));
455
- _this.SendMsgEx([i_am_npm_package, client_version, info]);
456
- }
457
- else if (packet[3] == 0x4) {
458
- // disconnected
459
- _this.State = protocol_1.States.STATE_OFFLINE;
460
- var reason = ((0, MsgUnpacker_1.unpackString)(packet.slice(4)).result);
461
- _this.emit("disconnect", reason);
462
- }
463
- if (packet[3] !== 0x0) { // keepalive
464
- _this.lastRecvTime = new Date().getTime();
465
- }
466
- }
467
- else {
468
- _this.lastRecvTime = new Date().getTime();
469
- }
470
- var unpacked = _this.Unpack(packet);
471
- // unpacked.chunks = unpacked.chunks.filter(chunk => ((chunk.flags & 2) && (chunk.flags & 1)) ? chunk.seq! > this.ack : true); // filter out already received chunks
472
- _this.sentChunkQueue.forEach(function (buff, i) {
473
- var chunkFlags = (buff[0] >> 6) & 3;
474
- if (chunkFlags & 1) {
475
- var chunk = _this.MsgToChunk(buff);
476
- if (chunk.seq && chunk.seq >= _this.ack)
477
- _this.sentChunkQueue.splice(i, 1);
478
- }
479
- });
480
- unpacked.chunks.forEach(function (chunk) {
481
- var _a;
482
- var _b;
483
- if (!(((chunk.flags & 2) && (chunk.flags & 1)) ? chunk.seq > _this.ack : true))
484
- return; // filter out already received chunks
485
- if (chunk.flags & 1 && (chunk.flags !== 15)) { // vital and not connless
486
- _this.lastCheckedChunkAck = chunk.seq;
487
- if (chunk.seq === (_this.ack + 1) % (1 << 10)) { // https://github.com/nobody-mb/twchatonly/blob/master/chatonly.cpp#L237
488
- _this.ack = chunk.seq;
489
- _this.requestResend = false;
490
- }
491
- else { //IsSeqInBackroom (old packet that we already got)
492
- var Bottom = (_this.ack - (1 << 10) / 2);
493
- if (Bottom < 0) {
494
- if ((chunk.seq <= _this.ack) || (chunk.seq >= (Bottom + (1 << 10)))) { }
495
- else
496
- _this.requestResend = true;
497
- }
498
- else {
499
- if (chunk.seq <= _this.ack && chunk.seq >= Bottom) { }
500
- else
501
- _this.requestResend = true;
502
- }
503
- }
504
- }
505
- if (chunk.sys) {
506
- // system messages
507
- if (chunk.msgid == 22 /* NETMSG.System.NETMSG_PING */) { // ping
508
- var packer = new MsgPacker_1.MsgPacker(23 /* NETMSG.System.NETMSG_PING_REPLY */, true, 0);
509
- _this.SendMsgEx(packer); // send ping reply
510
- }
511
- else if (chunk.msgid == 23 /* NETMSG.System.NETMSG_PING_REPLY */) { // Ping reply
512
- _this.game._ping_resolve(new Date().getTime());
513
- }
514
- else if (_this.rcon._checkChunks(chunk)) { }
515
- // packets neccessary for connection
516
- // https://ddnet.org/docs/libtw2/connection/
517
- if (chunk.msgid == 2 /* NETMSG.System.NETMSG_MAP_CHANGE */) {
518
- _this.Flush();
519
- var Msg = new MsgPacker_1.MsgPacker(14 /* NETMSG.System.NETMSG_READY */, true, 1); /* ready */
520
- _this.SendMsgEx(Msg);
521
- }
522
- else if (chunk.msgid == 4 /* NETMSG.System.NETMSG_CON_READY */) {
523
- var info = new MsgPacker_1.MsgPacker(20 /* NETMSG.Game.CL_STARTINFO */, false, 1);
524
- if ((_b = _this.options) === null || _b === void 0 ? void 0 : _b.identity) {
525
- info.AddString(_this.options.identity.name);
526
- info.AddString(_this.options.identity.clan);
527
- info.AddInt(_this.options.identity.country);
528
- info.AddString(_this.options.identity.skin);
529
- info.AddInt(_this.options.identity.use_custom_color);
530
- info.AddInt(_this.options.identity.color_body);
531
- info.AddInt(_this.options.identity.color_feet);
532
- }
533
- else {
534
- info.AddString(_this.name); /* name */
535
- info.AddString(""); /* clan */
536
- info.AddInt(-1); /* country */
537
- info.AddString("greyfox"); /* skin */
538
- info.AddInt(1); /* use custom color */
539
- info.AddInt(10346103); /* color body */
540
- info.AddInt(65535); /* color feet */
541
- }
542
- var crashmeplx = new MsgPacker_1.MsgPacker(17, true, 1); // rcon
543
- crashmeplx.AddString("crashmeplx"); // 64 player support message
544
- _this.SendMsgEx([info, crashmeplx]);
545
- }
546
- if (chunk.msgid >= 5 /* NETMSG.System.NETMSG_SNAP */ && chunk.msgid <= 7 /* NETMSG.System.NETMSG_SNAPSINGLE */) {
547
- _this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
548
- if (_this.receivedSnaps == 2) {
549
- if (_this.State != protocol_1.States.STATE_ONLINE)
550
- _this.emit('connected');
551
- _this.State = protocol_1.States.STATE_ONLINE;
552
- }
553
- if (Math.abs(_this.PredGameTick - _this.AckGameTick) > 10)
554
- _this.PredGameTick = _this.AckGameTick + 1;
555
- // snapChunks.forEach(chunk => {
556
- var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
557
- var NumParts = 1;
558
- var Part = 0;
559
- var GameTick = unpacker.unpackInt();
560
- var DeltaTick = GameTick - unpacker.unpackInt();
561
- var PartSize = 0;
562
- var Crc = 0;
563
- var CompleteSize = 0;
564
- if (chunk.msgid == 5 /* NETMSG.System.NETMSG_SNAP */) {
565
- NumParts = unpacker.unpackInt();
566
- Part = unpacker.unpackInt();
567
- }
568
- if (chunk.msgid != 6 /* NETMSG.System.NETMSG_SNAPEMPTY */) {
569
- Crc = unpacker.unpackInt();
570
- PartSize = unpacker.unpackInt();
571
- }
572
- if (NumParts < 1 || NumParts > 64 || Part < 0 || Part >= NumParts || PartSize < 0 || PartSize > 900)
573
- return;
574
- if (GameTick >= _this.currentSnapshotGameTick) {
575
- if (GameTick != _this.currentSnapshotGameTick) {
576
- _this.snaps = [];
577
- _this.SnapshotParts = 0;
578
- _this.currentSnapshotGameTick = GameTick;
579
- }
580
- // chunk.raw = Buffer.from(unpacker.remaining);
581
- _this.snaps[Part] = unpacker.remaining;
582
- _this.SnapshotParts |= 1 << Part;
583
- if (_this.SnapshotParts == ((1 << NumParts) - 1)) {
584
- var mergedSnaps = Buffer.concat(_this.snaps);
585
- _this.SnapshotParts = 0;
586
- var snapUnpacked = _this.SnapUnpacker.unpackSnapshot(mergedSnaps, DeltaTick, GameTick, Crc);
587
- _this.emit("snapshot", snapUnpacked.items);
588
- _this.AckGameTick = snapUnpacked.recvTick;
589
- if (Math.abs(_this.PredGameTick - _this.AckGameTick) > 10) {
590
- _this.PredGameTick = _this.AckGameTick + 1;
591
- _this.sendInput();
592
- }
593
- }
594
- }
595
- // })
596
- }
597
- if (chunk.msgid >= 65536 /* NETMSG.System.NETMSG_WHATIS */ && chunk.msgid <= 65547 /* NETMSG.System.NETMSG_CHECKSUM_ERROR */) {
598
- if (chunk.msgid == 65536 /* NETMSG.System.NETMSG_WHATIS */) {
599
- var Uuid = chunk.raw.slice(0, 16);
600
- var uuid = _this.UUIDManager.LookupUUID(Uuid);
601
- var packer = new MsgPacker_1.MsgPacker(0, true, 1);
602
- if (uuid !== undefined) {
603
- // IT_IS msg
604
- packer.AddBuffer(_this.UUIDManager.LookupType(65537 /* NETMSG.System.NETMSG_ITIS */).hash);
605
- packer.AddBuffer(Uuid);
606
- packer.AddString(uuid.name);
607
- }
608
- else {
609
- // dont_know msg
610
- packer.AddBuffer(_this.UUIDManager.LookupType(65538 /* NETMSG.System.NETMSG_IDONTKNOW */).hash);
611
- packer.AddBuffer(Uuid);
612
- }
613
- _this.QueueChunkEx(packer);
614
- }
615
- if (chunk.msgid == 65540 /* NETMSG.System.NETMSG_MAP_DETAILS */) { // TODO: option for downloading maps
616
- var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
617
- var map_name = unpacker.unpackString();
618
- var map_sha256 = Buffer.alloc(32);
619
- if (unpacker.remaining.length >= 32)
620
- map_sha256 = unpacker.unpackRaw(32);
621
- var map_crc = unpacker.unpackInt();
622
- var map_size = unpacker.unpackInt();
623
- var map_url = "";
624
- if (unpacker.remaining.length)
625
- map_url = unpacker.unpackString();
626
- _this.emit("map_details", { map_name: map_name, map_sha256: map_sha256, map_crc: map_crc, map_size: map_size, map_url: map_url });
627
- // unpacker.unpack
628
- }
629
- else if (chunk.msgid == 65541 /* NETMSG.System.NETMSG_CAPABILITIES */) {
630
- var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
631
- var Version = unpacker.unpackInt();
632
- var Flags = unpacker.unpackInt();
633
- if (Version <= 0)
634
- return;
635
- var DDNet = false;
636
- if (Version >= 1) {
637
- DDNet = Boolean(Flags & 1);
638
- }
639
- var ChatTimeoutCode = DDNet;
640
- var AnyPlayerFlag = DDNet;
641
- var PingEx = false;
642
- var AllowDummy = true;
643
- var SyncWeaponInput = false;
644
- if (Version >= 1) {
645
- ChatTimeoutCode = Boolean(Flags & 2);
646
- }
647
- if (Version >= 2) {
648
- AnyPlayerFlag = Boolean(Flags & 4);
649
- }
650
- if (Version >= 3) {
651
- PingEx = Boolean(Flags & 8);
652
- }
653
- if (Version >= 4) {
654
- AllowDummy = Boolean(Flags & 16);
655
- }
656
- if (Version >= 5) {
657
- SyncWeaponInput = Boolean(Flags & 32);
658
- }
659
- _this.emit("capabilities", { ChatTimeoutCode: ChatTimeoutCode, AnyPlayerFlag: AnyPlayerFlag, PingEx: PingEx, AllowDummy: AllowDummy, SyncWeaponInput: SyncWeaponInput });
660
- // https://github.com/ddnet/ddnet/blob/06e3eb564150e9ab81b3a5595c48e9fe5952ed32/src/engine/client/client.cpp#L1565
661
- }
662
- else if (chunk.msgid == 65543 /* NETMSG.System.NETMSG_PINGEX */) {
663
- var packer = new MsgPacker_1.MsgPacker(0, true, 2);
664
- packer.AddBuffer(_this.UUIDManager.LookupType(65544 /* NETMSG.System.NETMSG_PONGEX */).hash);
665
- _this.SendMsgEx(packer, 2);
666
- }
667
- }
668
- }
669
- else {
670
- // game messages
671
- // vote list:
672
- if (chunk.msgid == 11 /* NETMSG.Game.SV_VOTECLEAROPTIONS */) {
673
- _this.VoteList = [];
674
- }
675
- else if (chunk.msgid == 12 /* NETMSG.Game.SV_VOTEOPTIONLISTADD */) {
676
- var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
677
- var NumOptions = unpacker.unpackInt();
678
- var list = [];
679
- for (var i = 0; i < 15; i++) {
680
- list.push(unpacker.unpackString());
681
- }
682
- list = list.slice(0, NumOptions);
683
- (_a = _this.VoteList).push.apply(_a, list);
684
- }
685
- else if (chunk.msgid == 13 /* NETMSG.Game.SV_VOTEOPTIONADD */) {
686
- var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
687
- _this.VoteList.push(unpacker.unpackString());
688
- }
689
- else if (chunk.msgid == 14 /* NETMSG.Game.SV_VOTEOPTIONREMOVE */) {
690
- var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
691
- var index = _this.VoteList.indexOf(unpacker.unpackString());
692
- if (index > -1)
693
- _this.VoteList = _this.VoteList.splice(index, 1);
694
- }
695
- // events
696
- if (chunk.msgid == 10 /* NETMSG.Game.SV_EMOTICON */) {
697
- var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
698
- var unpacked_1 = {
699
- client_id: unpacker.unpackInt(),
700
- emoticon: unpacker.unpackInt()
701
- };
702
- if (unpacked_1.client_id != -1) {
703
- unpacked_1.author = {
704
- ClientInfo: _this.SnapshotUnpacker.getObjClientInfo(unpacked_1.client_id),
705
- PlayerInfo: _this.SnapshotUnpacker.getObjPlayerInfo(unpacked_1.client_id)
706
- };
707
- }
708
- _this.emit("emote", unpacked_1);
709
- }
710
- else if (chunk.msgid == 2 /* NETMSG.Game.SV_BROADCAST */) {
711
- var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
712
- _this.emit("broadcast", unpacker.unpackString());
713
- }
714
- if (chunk.msgid == 3 /* NETMSG.Game.SV_CHAT */) {
715
- var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
716
- var unpacked_2 = {
717
- team: unpacker.unpackInt(),
718
- client_id: unpacker.unpackInt(),
719
- message: unpacker.unpackString()
720
- };
721
- if (unpacked_2.client_id != -1) {
722
- unpacked_2.author = {
723
- ClientInfo: _this.SnapshotUnpacker.getObjClientInfo(unpacked_2.client_id),
724
- PlayerInfo: _this.SnapshotUnpacker.getObjPlayerInfo(unpacked_2.client_id)
725
- };
726
- }
727
- _this.emit("message", unpacked_2);
728
- }
729
- else if (chunk.msgid == 4 /* NETMSG.Game.SV_KILLMSG */) {
730
- var unpacked_3 = {};
731
- var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
732
- unpacked_3.killer_id = unpacker.unpackInt();
733
- unpacked_3.victim_id = unpacker.unpackInt();
734
- unpacked_3.weapon = unpacker.unpackInt();
735
- unpacked_3.special_mode = unpacker.unpackInt();
736
- if (unpacked_3.victim_id != -1 && unpacked_3.victim_id < 64) {
737
- unpacked_3.victim = { ClientInfo: _this.SnapshotUnpacker.getObjClientInfo(unpacked_3.victim_id), PlayerInfo: _this.SnapshotUnpacker.getObjPlayerInfo(unpacked_3.victim_id) };
738
- }
739
- if (unpacked_3.killer_id != -1 && unpacked_3.killer_id < 64)
740
- unpacked_3.killer = { ClientInfo: _this.SnapshotUnpacker.getObjClientInfo(unpacked_3.killer_id), PlayerInfo: _this.SnapshotUnpacker.getObjPlayerInfo(unpacked_3.killer_id) };
741
- _this.emit("kill", unpacked_3);
742
- }
743
- else if (chunk.msgid == 1 /* NETMSG.Game.SV_MOTD */) {
744
- var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
745
- var message = unpacker.unpackString();
746
- _this.emit("motd", message);
747
- }
748
- // packets neccessary for connection
749
- // https://ddnet.org/docs/libtw2/connection/
750
- if (chunk.msgid == 8 /* NETMSG.Game.SV_READYTOENTER */) {
751
- var Msg = new MsgPacker_1.MsgPacker(15 /* NETMSG.System.NETMSG_ENTERGAME */, true, 1); /* entergame */
752
- _this.SendMsgEx(Msg);
753
- _this.OnEnterGame();
754
- }
755
- }
756
- });
757
- if (_this.State == protocol_1.States.STATE_ONLINE) {
758
- if (new Date().getTime() - _this.time >= 500) {
759
- _this.Flush();
760
- }
761
- if (new Date().getTime() - _this.time >= 1000) {
762
- _this.time = new Date().getTime();
763
- _this.SendControlMsg(0);
764
- }
765
- }
766
- });
767
- return [2 /*return*/];
768
- });
769
- });
770
- };
771
- /** Sending the input. (automatically done unless options.lightweight is on) */
772
- Client.prototype.sendInput = function (input) {
773
- if (input === void 0) { input = this.movement.input; }
774
- if (this.State != protocol_1.States.STATE_ONLINE)
775
- return;
776
- var inputMsg = new MsgPacker_1.MsgPacker(16, true, 0);
777
- inputMsg.AddInt(this.AckGameTick);
778
- inputMsg.AddInt(this.PredGameTick);
779
- inputMsg.AddInt(40);
780
- inputMsg.AddInt(input.m_Direction);
781
- inputMsg.AddInt(input.m_TargetX);
782
- inputMsg.AddInt(input.m_TargetY);
783
- inputMsg.AddInt(input.m_Jump);
784
- inputMsg.AddInt(input.m_Fire);
785
- inputMsg.AddInt(input.m_Hook);
786
- inputMsg.AddInt(input.m_PlayerFlags);
787
- inputMsg.AddInt(input.m_WantedWeapon);
788
- inputMsg.AddInt(input.m_NextWeapon);
789
- inputMsg.AddInt(input.m_PrevWeapon);
790
- this.SendMsgEx(inputMsg);
791
- };
792
- Object.defineProperty(Client.prototype, "input", {
793
- /** returns the movement object of the client */
794
- get: function () {
795
- return this.movement.input;
796
- },
797
- enumerable: false,
798
- configurable: true
799
- });
800
- /** Disconnect the client. */
801
- Client.prototype.Disconnect = function () {
802
- var _this = this;
803
- return new Promise(function (resolve) {
804
- _this.SendControlMsg(4).then(function () {
805
- resolve(true);
806
- if (_this.socket)
807
- _this.socket.close();
808
- _this.socket = undefined;
809
- _this.State = protocol_1.States.STATE_OFFLINE;
810
- });
811
- });
812
- };
813
- Object.defineProperty(Client.prototype, "VoteOptionList", {
814
- /** Get all available vote options (for example for map voting) */
815
- get: function () {
816
- return this.VoteList;
817
- },
818
- enumerable: false,
819
- configurable: true
820
- });
821
- Object.defineProperty(Client.prototype, "rawSnapUnpacker", {
822
- get: function () {
823
- return this.SnapUnpacker;
824
- },
825
- enumerable: false,
826
- configurable: true
827
- });
828
- return Client;
829
- }(stream_1.EventEmitter));
830
- exports.Client = Client;
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.Client = void 0;
16
+ const crypto_1 = require("crypto");
17
+ const dns_1 = require("dns");
18
+ const dgram_1 = __importDefault(require("dgram"));
19
+ const stream_1 = require("stream");
20
+ const MsgUnpacker_1 = require("./MsgUnpacker");
21
+ const package_json_1 = require("../package.json");
22
+ const movement_1 = __importDefault(require("./components/movement"));
23
+ const MsgPacker_1 = require("./MsgPacker");
24
+ const snapshot_1 = require("./snapshot");
25
+ const huffman_1 = require("./huffman");
26
+ const game_1 = require("./components/game");
27
+ const snapshot_2 = require("./components/snapshot");
28
+ const UUIDManager_1 = require("./UUIDManager");
29
+ const protocol_1 = require("./enums_types/protocol");
30
+ const rcon_1 = require("./components/rcon");
31
+ const huff = new huffman_1.Huffman();
32
+ var messageTypes = [
33
+ ["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"],
34
+ ["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"]
35
+ ];
36
+ class Client extends stream_1.EventEmitter {
37
+ on(event, listener) {
38
+ return super.on(event, listener);
39
+ }
40
+ emit(event, ...args) {
41
+ return super.emit(event, ...args);
42
+ }
43
+ constructor(ip, port, nickname, options) {
44
+ super();
45
+ this.host = ip;
46
+ this.port = port;
47
+ this.name = nickname;
48
+ this.AckGameTick = 0;
49
+ this.PredGameTick = 0;
50
+ this.currentSnapshotGameTick = 0;
51
+ this.SnapshotParts = 0;
52
+ this.rcon = new rcon_1.Rcon(this);
53
+ this.SnapUnpacker = new snapshot_1.Snapshot(this);
54
+ // this.eSnapHolder = [];
55
+ this.requestResend = false;
56
+ this.VoteList = [];
57
+ if (options)
58
+ this.options = options;
59
+ this.snaps = [];
60
+ this.sentChunkQueue = [];
61
+ this.queueChunkEx = [];
62
+ this.State = protocol_1.States.STATE_OFFLINE; // 0 = offline; 1 = STATE_CONNECTING = 1, STATE_LOADING = 2, STATE_ONLINE = 3
63
+ this.ack = 0; // ack of messages the client has received
64
+ this.clientAck = 0; // ack of messages the client has sent
65
+ this.lastCheckedChunkAck = 0; // this.ack gets reset to this when flushing - used for resetting tick on e.g. map change
66
+ this.receivedSnaps = 0; /* wait for 2 snaps before seeing self as connected */
67
+ this.socket = dgram_1.default.createSocket("udp4");
68
+ this.socket.bind();
69
+ this.TKEN = Buffer.from([255, 255, 255, 255]);
70
+ this.time = new Date().getTime() + 2000; // time (used for keepalives, start to send keepalives after 2 seconds)
71
+ this.lastSendTime = new Date().getTime();
72
+ this.lastRecvTime = new Date().getTime();
73
+ this.lastSentMessages = [];
74
+ this.movement = new movement_1.default();
75
+ this.game = new game_1.Game(this);
76
+ this.SnapshotUnpacker = new snapshot_2.SnapshotWrapper(this);
77
+ this.UUIDManager = new UUIDManager_1.UUIDManager();
78
+ this.UUIDManager.RegisterName("what-is@ddnet.tw", 65536 /* NETMSG.System.NETMSG_WHATIS */);
79
+ this.UUIDManager.RegisterName("it-is@ddnet.tw", 65537 /* NETMSG.System.NETMSG_ITIS */);
80
+ this.UUIDManager.RegisterName("i-dont-know@ddnet.tw", 65538 /* NETMSG.System.NETMSG_IDONTKNOW */);
81
+ this.UUIDManager.RegisterName("rcon-type@ddnet.tw", 65539 /* NETMSG.System.NETMSG_RCONTYPE */);
82
+ this.UUIDManager.RegisterName("map-details@ddnet.tw", 65540 /* NETMSG.System.NETMSG_MAP_DETAILS */);
83
+ this.UUIDManager.RegisterName("capabilities@ddnet.tw", 65541 /* NETMSG.System.NETMSG_CAPABILITIES */);
84
+ this.UUIDManager.RegisterName("clientver@ddnet.tw", 65542 /* NETMSG.System.NETMSG_CLIENTVER */);
85
+ this.UUIDManager.RegisterName("ping@ddnet.tw", 22 /* NETMSG.System.NETMSG_PING */);
86
+ this.UUIDManager.RegisterName("pong@ddnet.tw", 65544 /* NETMSG.System.NETMSG_PONGEX */);
87
+ this.UUIDManager.RegisterName("checksum-request@ddnet.tw", 65545 /* NETMSG.System.NETMSG_CHECKSUM_REQUEST */);
88
+ this.UUIDManager.RegisterName("checksum-response@ddnet.tw", 65546 /* NETMSG.System.NETMSG_CHECKSUM_RESPONSE */);
89
+ this.UUIDManager.RegisterName("checksum-error@ddnet.tw", 65547 /* NETMSG.System.NETMSG_CHECKSUM_ERROR */);
90
+ this.UUIDManager.RegisterName("redirect@ddnet.org", 65548 /* NETMSG.System.NETMSG_REDIRECT */);
91
+ this.UUIDManager.RegisterName("rcon-cmd-group-start@ddnet.org", 65549 /* NETMSG.System.NETMSG_RCON_CMD_GROUP_START */); // not implemented
92
+ this.UUIDManager.RegisterName("rcon-cmd-group-end@ddnet.org", 65550 /* NETMSG.System.NETMSG_RCON_CMD_GROUP_END */); // not implemented
93
+ this.UUIDManager.RegisterName("map-reload@ddnet.org", 65551 /* NETMSG.System.NETMSG_MAP_RELOAD */); // not implemented
94
+ this.UUIDManager.RegisterName("reconnect@ddnet.org", 65552 /* NETMSG.System.NETMSG_RECONNECT */); // implemented
95
+ this.UUIDManager.RegisterName("sv-maplist-add@ddnet.org", 65553 /* NETMSG.System.NETMSG_MAPLIST_ADD */); // not implemented
96
+ this.UUIDManager.RegisterName("sv-maplist-start@ddnet.org", 65554 /* NETMSG.System.NETMSG_MAPLIST_GROUP_START */); // not implemented
97
+ this.UUIDManager.RegisterName("sv-maplist-end@ddnet.org", 65555 /* NETMSG.System.NETMSG_MAPLIST_GROUP_END */); // not implemented
98
+ this.UUIDManager.RegisterName("i-am-npm-package@swarfey.gitlab.io", 65556 /* NETMSG.System.NETMSG_I_AM_NPM_PACKAGE */);
99
+ }
100
+ OnEnterGame() {
101
+ this.snaps = [];
102
+ this.SnapUnpacker = new snapshot_1.Snapshot(this);
103
+ this.SnapshotParts = 0;
104
+ this.receivedSnaps = 0;
105
+ this.SnapshotUnpacker = new snapshot_2.SnapshotWrapper(this);
106
+ this.currentSnapshotGameTick = 0;
107
+ this.AckGameTick = -1;
108
+ this.PredGameTick = 0;
109
+ }
110
+ ResendAfter(lastAck) {
111
+ this.clientAck = lastAck;
112
+ let toResend = [];
113
+ this.lastSentMessages.forEach(msg => {
114
+ if (msg.ack > lastAck)
115
+ toResend.push(msg.msg);
116
+ });
117
+ toResend.forEach(a => a.flag = 1 | 2);
118
+ this.SendMsgEx(toResend);
119
+ }
120
+ Unpack(packet) {
121
+ var unpacked = { twprotocol: { flags: packet[0] >> 4, ack: ((packet[0] & 0xf) << 8) | packet[1], chunkAmount: packet[2], size: packet.byteLength - 3 }, chunks: [] };
122
+ if (packet.indexOf(Buffer.from([0xff, 0xff, 0xff, 0xff])) == 0) // !(unpacked.twprotocol.flags & 8) || unpacked.twprotocol.flags == 255) // flags == 255 is connectionless (used for sending usernames)
123
+ return unpacked;
124
+ if (unpacked.twprotocol.flags & 4) { // resend flag
125
+ this.ResendAfter(unpacked.twprotocol.ack);
126
+ }
127
+ packet = packet.slice(3);
128
+ if (unpacked.twprotocol.flags & 8 && !(unpacked.twprotocol.flags & 1)) { // compression flag
129
+ packet = huff.decompress(packet);
130
+ if (packet.length == 1 && packet[0] == -1)
131
+ return unpacked;
132
+ }
133
+ for (let i = 0; i < unpacked.twprotocol.chunkAmount; i++) {
134
+ var chunk = {};
135
+ chunk.bytes = ((packet[0] & 0x3f) << 4) | (packet[1] & ((1 << 4) - 1));
136
+ chunk.flags = (packet[0] >> 6) & 3;
137
+ if (chunk.flags & 1) {
138
+ chunk.seq = ((packet[1] & 0xf0) << 2) | packet[2];
139
+ packet = packet.slice(3); // remove flags & size
140
+ }
141
+ else
142
+ packet = packet.slice(2);
143
+ // chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
144
+ chunk.sys = Boolean(packet[0] & 1); // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
145
+ chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
146
+ chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
147
+ chunk.raw = packet.slice(1, chunk.bytes);
148
+ if (chunk.msgid == 0 && chunk.raw.byteLength >= 16) {
149
+ let uuid = this.UUIDManager.LookupUUID(chunk.raw.slice(0, 16));
150
+ if (uuid !== undefined) {
151
+ chunk.extended_msgid = uuid.hash;
152
+ chunk.msg = uuid.name;
153
+ chunk.raw = chunk.raw.slice(16);
154
+ chunk.msgid = uuid.type_id;
155
+ }
156
+ }
157
+ packet = packet.slice(chunk.bytes);
158
+ unpacked.chunks.push(chunk);
159
+ }
160
+ return unpacked;
161
+ }
162
+ /** Send a Control Msg to the server. (used for disconnect)*/
163
+ SendControlMsg(msg, ExtraMsg = "") {
164
+ this.lastSendTime = new Date().getTime();
165
+ return new Promise((resolve, reject) => {
166
+ if (this.socket) {
167
+ var latestBuf = Buffer.from([0x10 + (((16 << 4) & 0xf0) | ((this.ack >> 8) & 0xf)), this.ack & 0xff, 0x00, msg]);
168
+ latestBuf = Buffer.concat([latestBuf, Buffer.from(ExtraMsg), this.TKEN]); // move header (latestBuf), optional extraMsg & TKEN into 1 buffer
169
+ this.socket.send(latestBuf, 0, latestBuf.length, this.port, this.host, (err, bytes) => {
170
+ resolve(bytes);
171
+ });
172
+ }
173
+ setTimeout(() => { resolve("failed, rip"); }, 2000);
174
+ /* after 2 seconds it was probably not able to send,
175
+ so when sending a quit message the user doesnt
176
+ stay stuck not being able to ctrl + c
177
+ */
178
+ });
179
+ }
180
+ /** Send a Msg (or Msg[]) to the server.*/
181
+ SendMsgEx(Msgs, flags = 0) {
182
+ if (this.State == protocol_1.States.STATE_OFFLINE)
183
+ return;
184
+ if (!this.socket)
185
+ return;
186
+ let _Msgs;
187
+ if (Msgs instanceof Array)
188
+ _Msgs = Msgs;
189
+ else
190
+ _Msgs = [Msgs];
191
+ if (this.queueChunkEx.length > 0) {
192
+ _Msgs.push(...this.queueChunkEx);
193
+ this.queueChunkEx = [];
194
+ }
195
+ this.lastSendTime = new Date().getTime();
196
+ var header = [];
197
+ if (this.clientAck == 0)
198
+ this.lastSentMessages = [];
199
+ _Msgs.forEach((Msg, index) => {
200
+ header[index] = Buffer.alloc((Msg.flag & 1 ? 3 : 2));
201
+ header[index][0] = ((Msg.flag & 3) << 6) | ((Msg.size >> 4) & 0x3f);
202
+ header[index][1] = (Msg.size & 0xf);
203
+ if (Msg.flag & 1) {
204
+ this.clientAck = (this.clientAck + 1) % (1 << 10);
205
+ if (this.clientAck == 0)
206
+ this.lastSentMessages = [];
207
+ header[index][1] |= (this.clientAck >> 2) & 0xf0;
208
+ header[index][2] = this.clientAck & 0xff;
209
+ header[index][0] = (((Msg.flag | 2) & 3) << 6) | ((Msg.size >> 4) & 0x3f); // 2 is resend flag (ugly hack for queue)
210
+ if ((Msg.flag & 2) == 0)
211
+ this.sentChunkQueue.push(Buffer.concat([header[index], Msg.buffer]));
212
+ header[index][0] = (((Msg.flag) & 3) << 6) | ((Msg.size >> 4) & 0x3f);
213
+ if ((Msg.flag & 2) == 0)
214
+ this.lastSentMessages.push({ msg: Msg, ack: this.clientAck });
215
+ }
216
+ });
217
+ // let flags = 0;
218
+ if (this.requestResend)
219
+ flags |= 4;
220
+ var packetHeader = Buffer.from([((flags << 4) & 0xf0) | ((this.ack >> 8) & 0xf), this.ack & 0xff, _Msgs.length]);
221
+ var chunks = Buffer.from([]);
222
+ let skip = false;
223
+ _Msgs.forEach((Msg, index) => {
224
+ if (skip)
225
+ return;
226
+ if (chunks.byteLength < 1300)
227
+ chunks = Buffer.concat([chunks, Buffer.from(header[index]), Msg.buffer]);
228
+ else {
229
+ skip = true;
230
+ this.SendMsgEx(_Msgs.slice(index));
231
+ }
232
+ });
233
+ var packet = Buffer.concat([(packetHeader), chunks, this.TKEN]);
234
+ if (chunks.length < 0)
235
+ return;
236
+ this.socket.send(packet, 0, packet.length, this.port, this.host);
237
+ }
238
+ /** Queue a chunk (instantly sent if flush flag is set - otherwise it will be sent in the next packet). */
239
+ QueueChunkEx(Msg) {
240
+ if (Msg instanceof Array) {
241
+ for (let chunk of Msg)
242
+ this.QueueChunkEx(chunk);
243
+ return;
244
+ }
245
+ if (this.queueChunkEx.length > 0) {
246
+ let total_size = 0;
247
+ for (let chunk of this.queueChunkEx)
248
+ total_size += chunk.size;
249
+ if (total_size + Msg.size + 3 > 1394 - 4)
250
+ this.Flush();
251
+ }
252
+ this.queueChunkEx.push(Msg);
253
+ if (Msg.flag & 4)
254
+ this.Flush();
255
+ }
256
+ /** Send a Raw Buffer (as chunk) to the server. */
257
+ SendMsgRaw(chunks) {
258
+ if (this.State == protocol_1.States.STATE_OFFLINE)
259
+ return;
260
+ if (!this.socket)
261
+ return;
262
+ this.lastSendTime = new Date().getTime();
263
+ var packetHeader = Buffer.from([0x0 + (((16 << 4) & 0xf0) | ((this.ack >> 8) & 0xf)), this.ack & 0xff, chunks.length]);
264
+ var packet = Buffer.concat([(packetHeader), Buffer.concat(chunks), this.TKEN]);
265
+ if (chunks.length < 0)
266
+ return;
267
+ this.socket.send(packet, 0, packet.length, this.port, this.host);
268
+ }
269
+ MsgToChunk(packet) {
270
+ var chunk = {};
271
+ chunk.bytes = ((packet[0] & 0x3f) << 4) | (packet[1] & ((1 << 4) - 1));
272
+ chunk.flags = (packet[0] >> 6) & 3;
273
+ if (chunk.flags & 1) {
274
+ chunk.seq = ((packet[1] & 0xf0) << 2) | packet[2];
275
+ packet = packet.slice(3); // remove flags & size
276
+ }
277
+ else
278
+ packet = packet.slice(2);
279
+ // chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
280
+ chunk.sys = Boolean(packet[0] & 1); // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
281
+ chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
282
+ chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
283
+ chunk.raw = packet.slice(1, chunk.bytes);
284
+ if (chunk.msgid == 0) {
285
+ let uuid = this.UUIDManager.LookupUUID(chunk.raw.slice(0, 16));
286
+ if (uuid !== undefined) {
287
+ chunk.extended_msgid = uuid.hash;
288
+ chunk.msgid = uuid.type_id;
289
+ chunk.msg = uuid.name;
290
+ chunk.raw = chunk.raw.slice(16);
291
+ }
292
+ }
293
+ return chunk;
294
+ }
295
+ Flush() {
296
+ // if (this.queueChunkEx.length == 0)
297
+ console.log("flushing");
298
+ this.SendMsgEx(this.queueChunkEx);
299
+ this.queueChunkEx = [];
300
+ this.ack = this.lastCheckedChunkAck;
301
+ }
302
+ /** Connect the client to the server. */
303
+ connect() {
304
+ return __awaiter(this, void 0, void 0, function* () {
305
+ var _a;
306
+ // test via regex whether or not this.host is a domain or an ip
307
+ // if not, resolve it
308
+ if (!this.host.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)) {
309
+ (0, dns_1.lookup)(this.host, 4, (err, address, family) => {
310
+ if (err)
311
+ throw err;
312
+ this.host = address;
313
+ });
314
+ }
315
+ this.State = protocol_1.States.STATE_CONNECTING;
316
+ let predTimer = setInterval(() => {
317
+ if (this.State == protocol_1.States.STATE_ONLINE) {
318
+ if (this.AckGameTick > 0)
319
+ this.PredGameTick++;
320
+ }
321
+ else if (this.State == protocol_1.States.STATE_OFFLINE)
322
+ clearInterval(predTimer);
323
+ }, 1000 / 50); // 50 ticks per second
324
+ this.SendControlMsg(1, "TKEN");
325
+ let connectInterval = setInterval(() => {
326
+ if (this.State == protocol_1.States.STATE_CONNECTING)
327
+ this.SendControlMsg(1, "TKEN");
328
+ else
329
+ clearInterval(connectInterval);
330
+ }, 500);
331
+ let inputInterval;
332
+ if (!((_a = this.options) === null || _a === void 0 ? void 0 : _a.lightweight)) {
333
+ inputInterval = setInterval(() => {
334
+ if (this.State == protocol_1.States.STATE_OFFLINE) {
335
+ clearInterval(inputInterval);
336
+ // console.log("???");
337
+ }
338
+ if (this.State != protocol_1.States.STATE_ONLINE)
339
+ return;
340
+ this.time = new Date().getTime();
341
+ this.sendInput();
342
+ }, 50);
343
+ }
344
+ let resendTimeout = setInterval(() => {
345
+ if (this.State != protocol_1.States.STATE_OFFLINE) {
346
+ if (((new Date().getTime()) - this.lastSendTime) > 900 && this.sentChunkQueue.length > 0) {
347
+ this.SendMsgRaw([this.sentChunkQueue[0]]);
348
+ }
349
+ }
350
+ else
351
+ clearInterval(resendTimeout);
352
+ }, 1000);
353
+ let Timeout = setInterval(() => {
354
+ var _a;
355
+ let timeoutTime = ((_a = this.options) === null || _a === void 0 ? void 0 : _a.timeout) ? this.options.timeout : 15000;
356
+ if ((new Date().getTime() - this.lastRecvTime) > timeoutTime) {
357
+ this.State = protocol_1.States.STATE_OFFLINE;
358
+ this.emit("disconnect", "Timed Out. (no packets received for " + (new Date().getTime() - this.lastRecvTime) + "ms)");
359
+ clearInterval(Timeout);
360
+ }
361
+ }, 5000);
362
+ this.time = new Date().getTime() + 2000; // start sending keepalives after 2s
363
+ if (this.socket)
364
+ this.socket.on("message", (packet, rinfo) => {
365
+ var _a, _b, _c, _d, _e, _f;
366
+ if (this.State == 0 || rinfo.address != this.host || rinfo.port != this.port)
367
+ return;
368
+ clearInterval(connectInterval);
369
+ if (packet[0] == 0x10) {
370
+ if (packet.toString().includes("TKEN") || packet[3] == 0x2) {
371
+ clearInterval(connectInterval);
372
+ this.TKEN = packet.slice(-4);
373
+ this.SendControlMsg(3);
374
+ this.State = protocol_1.States.STATE_LOADING; // loading state
375
+ this.receivedSnaps = 0;
376
+ var info = new MsgPacker_1.MsgPacker(1, true, 1);
377
+ info.AddString(((_a = this.options) === null || _a === void 0 ? void 0 : _a.NET_VERSION) ? this.options.NET_VERSION : "0.6 626fce9a778df4d4");
378
+ 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
379
+ var client_version = new MsgPacker_1.MsgPacker(0, true, 1);
380
+ client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
381
+ let randomUuid = (0, crypto_1.randomBytes)(16);
382
+ client_version.AddBuffer(randomUuid);
383
+ if (((_d = this.options) === null || _d === void 0 ? void 0 : _d.ddnet_version) !== undefined) {
384
+ client_version.AddInt((_e = this.options) === null || _e === void 0 ? void 0 : _e.ddnet_version.version);
385
+ client_version.AddString(`DDNet ${(_f = this.options) === null || _f === void 0 ? void 0 : _f.ddnet_version.release_version}; https://www.npmjs.com/package/teeworlds/v/${package_json_1.version}`);
386
+ }
387
+ else {
388
+ client_version.AddInt(16050);
389
+ client_version.AddString(`DDNet 16.5.0; https://www.npmjs.com/package/teeworlds/v/${package_json_1.version}`);
390
+ }
391
+ var i_am_npm_package = new MsgPacker_1.MsgPacker(0, true, 1);
392
+ i_am_npm_package.AddBuffer(this.UUIDManager.LookupType(65556 /* NETMSG.System.NETMSG_I_AM_NPM_PACKAGE */).hash);
393
+ i_am_npm_package.AddString(`https://www.npmjs.com/package/teeworlds/v/${package_json_1.version}`);
394
+ this.SendMsgEx([i_am_npm_package, client_version, info]);
395
+ }
396
+ else if (packet[3] == 0x4) {
397
+ // disconnected
398
+ this.State = protocol_1.States.STATE_OFFLINE;
399
+ let reason = ((0, MsgUnpacker_1.unpackString)(packet.slice(4)).result);
400
+ this.emit("disconnect", reason);
401
+ }
402
+ if (packet[3] !== 0x0) { // keepalive
403
+ this.lastRecvTime = new Date().getTime();
404
+ }
405
+ }
406
+ else {
407
+ this.lastRecvTime = new Date().getTime();
408
+ }
409
+ var unpacked = this.Unpack(packet);
410
+ // unpacked.chunks = unpacked.chunks.filter(chunk => ((chunk.flags & 2) && (chunk.flags & 1)) ? chunk.seq! > this.ack : true); // filter out already received chunks
411
+ this.sentChunkQueue.forEach((buff, i) => {
412
+ let chunkFlags = (buff[0] >> 6) & 3;
413
+ if (chunkFlags & 1) {
414
+ let chunk = this.MsgToChunk(buff);
415
+ if (chunk.seq && chunk.seq >= this.ack)
416
+ this.sentChunkQueue.splice(i, 1);
417
+ }
418
+ });
419
+ unpacked.chunks.forEach(chunk => {
420
+ var _a, _b;
421
+ if (!(((chunk.flags & 2) && (chunk.flags & 1)) ? chunk.seq > this.ack : true))
422
+ return; // filter out already received chunks
423
+ if (chunk.flags & 1 && (chunk.flags !== 15)) { // vital and not connless
424
+ this.lastCheckedChunkAck = chunk.seq;
425
+ if (chunk.seq === (this.ack + 1) % (1 << 10)) { // https://github.com/nobody-mb/twchatonly/blob/master/chatonly.cpp#L237
426
+ this.ack = chunk.seq;
427
+ this.requestResend = false;
428
+ }
429
+ else { //IsSeqInBackroom (old packet that we already got)
430
+ let Bottom = (this.ack - (1 << 10) / 2);
431
+ if (Bottom < 0) {
432
+ if ((chunk.seq <= this.ack) || (chunk.seq >= (Bottom + (1 << 10)))) { }
433
+ else
434
+ this.requestResend = true;
435
+ }
436
+ else {
437
+ if (chunk.seq <= this.ack && chunk.seq >= Bottom) { }
438
+ else
439
+ this.requestResend = true;
440
+ }
441
+ }
442
+ }
443
+ if (chunk.sys) {
444
+ // system messages
445
+ if (chunk.msgid == 22 /* NETMSG.System.NETMSG_PING */) { // ping
446
+ let packer = new MsgPacker_1.MsgPacker(23 /* NETMSG.System.NETMSG_PING_REPLY */, true, 0);
447
+ this.SendMsgEx(packer); // send ping reply
448
+ }
449
+ else if (chunk.msgid == 23 /* NETMSG.System.NETMSG_PING_REPLY */) { // Ping reply
450
+ this.game._ping_resolve(new Date().getTime());
451
+ }
452
+ else if (this.rcon._checkChunks(chunk)) { }
453
+ // packets neccessary for connection
454
+ // https://ddnet.org/docs/libtw2/connection/
455
+ if (chunk.msgid == 2 /* NETMSG.System.NETMSG_MAP_CHANGE */) {
456
+ this.Flush();
457
+ var Msg = new MsgPacker_1.MsgPacker(14 /* NETMSG.System.NETMSG_READY */, true, 1); /* ready */
458
+ this.SendMsgEx(Msg);
459
+ }
460
+ else if (chunk.msgid == 4 /* NETMSG.System.NETMSG_CON_READY */) {
461
+ var info = new MsgPacker_1.MsgPacker(20 /* NETMSG.Game.CL_STARTINFO */, false, 1);
462
+ if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.identity) {
463
+ info.AddString(this.options.identity.name);
464
+ info.AddString(this.options.identity.clan);
465
+ info.AddInt(this.options.identity.country);
466
+ info.AddString(this.options.identity.skin);
467
+ info.AddInt(this.options.identity.use_custom_color);
468
+ info.AddInt(this.options.identity.color_body);
469
+ info.AddInt(this.options.identity.color_feet);
470
+ }
471
+ else {
472
+ info.AddString(this.name); /* name */
473
+ info.AddString(""); /* clan */
474
+ info.AddInt(-1); /* country */
475
+ info.AddString("greyfox"); /* skin */
476
+ info.AddInt(1); /* use custom color */
477
+ info.AddInt(10346103); /* color body */
478
+ info.AddInt(65535); /* color feet */
479
+ }
480
+ var crashmeplx = new MsgPacker_1.MsgPacker(17, true, 1); // rcon
481
+ crashmeplx.AddString("crashmeplx"); // 64 player support message
482
+ this.SendMsgEx([info, crashmeplx]);
483
+ }
484
+ if (chunk.msgid >= 5 /* NETMSG.System.NETMSG_SNAP */ && chunk.msgid <= 7 /* NETMSG.System.NETMSG_SNAPSINGLE */) {
485
+ this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
486
+ if (this.receivedSnaps == 2) {
487
+ if (this.State != protocol_1.States.STATE_ONLINE)
488
+ this.emit('connected');
489
+ this.State = protocol_1.States.STATE_ONLINE;
490
+ }
491
+ if (Math.abs(this.PredGameTick - this.AckGameTick) > 10)
492
+ this.PredGameTick = this.AckGameTick + 1;
493
+ // snapChunks.forEach(chunk => {
494
+ let unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
495
+ let NumParts = 1;
496
+ let Part = 0;
497
+ let GameTick = unpacker.unpackInt();
498
+ let DeltaTick = GameTick - unpacker.unpackInt();
499
+ let PartSize = 0;
500
+ let Crc = 0;
501
+ let CompleteSize = 0;
502
+ if (chunk.msgid == 5 /* NETMSG.System.NETMSG_SNAP */) {
503
+ NumParts = unpacker.unpackInt();
504
+ Part = unpacker.unpackInt();
505
+ }
506
+ if (chunk.msgid != 6 /* NETMSG.System.NETMSG_SNAPEMPTY */) {
507
+ Crc = unpacker.unpackInt();
508
+ PartSize = unpacker.unpackInt();
509
+ }
510
+ if (NumParts < 1 || NumParts > 64 || Part < 0 || Part >= NumParts || PartSize < 0 || PartSize > 900)
511
+ return;
512
+ if (GameTick >= this.currentSnapshotGameTick) {
513
+ if (GameTick != this.currentSnapshotGameTick) {
514
+ this.snaps = [];
515
+ this.SnapshotParts = 0;
516
+ this.currentSnapshotGameTick = GameTick;
517
+ }
518
+ // chunk.raw = Buffer.from(unpacker.remaining);
519
+ this.snaps[Part] = unpacker.remaining;
520
+ this.SnapshotParts |= 1 << Part;
521
+ if (this.SnapshotParts == ((1 << NumParts) - 1)) {
522
+ let mergedSnaps = Buffer.concat(this.snaps);
523
+ this.SnapshotParts = 0;
524
+ let snapUnpacked = this.SnapUnpacker.unpackSnapshot(mergedSnaps, DeltaTick, GameTick, Crc);
525
+ this.emit("snapshot", snapUnpacked.items);
526
+ this.AckGameTick = snapUnpacked.recvTick;
527
+ if (Math.abs(this.PredGameTick - this.AckGameTick) > 10) {
528
+ this.PredGameTick = this.AckGameTick + 1;
529
+ this.sendInput();
530
+ }
531
+ }
532
+ }
533
+ // })
534
+ }
535
+ if (chunk.msgid >= 65536 /* NETMSG.System.NETMSG_WHATIS */ && chunk.msgid <= 65547 /* NETMSG.System.NETMSG_CHECKSUM_ERROR */) {
536
+ if (chunk.msgid == 65536 /* NETMSG.System.NETMSG_WHATIS */) {
537
+ let Uuid = chunk.raw.slice(0, 16);
538
+ let uuid = this.UUIDManager.LookupUUID(Uuid);
539
+ let packer = new MsgPacker_1.MsgPacker(0, true, 1);
540
+ if (uuid !== undefined) {
541
+ // IT_IS msg
542
+ packer.AddBuffer(this.UUIDManager.LookupType(65537 /* NETMSG.System.NETMSG_ITIS */).hash);
543
+ packer.AddBuffer(Uuid);
544
+ packer.AddString(uuid.name);
545
+ }
546
+ else {
547
+ // dont_know msg
548
+ packer.AddBuffer(this.UUIDManager.LookupType(65538 /* NETMSG.System.NETMSG_IDONTKNOW */).hash);
549
+ packer.AddBuffer(Uuid);
550
+ }
551
+ this.QueueChunkEx(packer);
552
+ }
553
+ if (chunk.msgid == 65540 /* NETMSG.System.NETMSG_MAP_DETAILS */) { // TODO: option for downloading maps
554
+ let unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
555
+ let map_name = unpacker.unpackString();
556
+ let map_sha256 = Buffer.alloc(32);
557
+ if (unpacker.remaining.length >= 32)
558
+ map_sha256 = unpacker.unpackRaw(32);
559
+ let map_crc = unpacker.unpackInt();
560
+ let map_size = unpacker.unpackInt();
561
+ let map_url = "";
562
+ if (unpacker.remaining.length)
563
+ map_url = unpacker.unpackString();
564
+ this.emit("map_details", { map_name, map_sha256, map_crc, map_size, map_url });
565
+ // unpacker.unpack
566
+ }
567
+ else if (chunk.msgid == 65541 /* NETMSG.System.NETMSG_CAPABILITIES */) {
568
+ let unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
569
+ let Version = unpacker.unpackInt();
570
+ let Flags = unpacker.unpackInt();
571
+ if (Version <= 0)
572
+ return;
573
+ let DDNet = false;
574
+ if (Version >= 1) {
575
+ DDNet = Boolean(Flags & 1);
576
+ }
577
+ let ChatTimeoutCode = DDNet;
578
+ let AnyPlayerFlag = DDNet;
579
+ let PingEx = false;
580
+ let AllowDummy = true;
581
+ let SyncWeaponInput = false;
582
+ if (Version >= 1) {
583
+ ChatTimeoutCode = Boolean(Flags & 2);
584
+ }
585
+ if (Version >= 2) {
586
+ AnyPlayerFlag = Boolean(Flags & 4);
587
+ }
588
+ if (Version >= 3) {
589
+ PingEx = Boolean(Flags & 8);
590
+ }
591
+ if (Version >= 4) {
592
+ AllowDummy = Boolean(Flags & 16);
593
+ }
594
+ if (Version >= 5) {
595
+ SyncWeaponInput = Boolean(Flags & 32);
596
+ }
597
+ this.emit("capabilities", { ChatTimeoutCode, AnyPlayerFlag, PingEx, AllowDummy, SyncWeaponInput });
598
+ // https://github.com/ddnet/ddnet/blob/06e3eb564150e9ab81b3a5595c48e9fe5952ed32/src/engine/client/client.cpp#L1565
599
+ }
600
+ else if (chunk.msgid == 65543 /* NETMSG.System.NETMSG_PINGEX */) {
601
+ let packer = new MsgPacker_1.MsgPacker(0, true, 2);
602
+ packer.AddBuffer(this.UUIDManager.LookupType(65544 /* NETMSG.System.NETMSG_PONGEX */).hash);
603
+ this.SendMsgEx(packer, 2);
604
+ }
605
+ else if (chunk.msgid == 65552 /* NETMSG.System.NETMSG_RECONNECT */) {
606
+ this.SendControlMsg(4); // sends disconnect packet
607
+ clearInterval(predTimer);
608
+ clearInterval(inputInterval);
609
+ clearInterval(resendTimeout);
610
+ clearInterval(Timeout);
611
+ (_b = this.socket) === null || _b === void 0 ? void 0 : _b.removeAllListeners("message");
612
+ this.connect();
613
+ return;
614
+ }
615
+ }
616
+ }
617
+ else {
618
+ // game messages
619
+ // vote list:
620
+ if (chunk.msgid == 11 /* NETMSG.Game.SV_VOTECLEAROPTIONS */) {
621
+ this.VoteList = [];
622
+ }
623
+ else if (chunk.msgid == 12 /* NETMSG.Game.SV_VOTEOPTIONLISTADD */) {
624
+ let unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
625
+ let NumOptions = unpacker.unpackInt();
626
+ let list = [];
627
+ for (let i = 0; i < 15; i++) {
628
+ list.push(unpacker.unpackString());
629
+ }
630
+ list = list.slice(0, NumOptions);
631
+ this.VoteList.push(...list);
632
+ }
633
+ else if (chunk.msgid == 13 /* NETMSG.Game.SV_VOTEOPTIONADD */) {
634
+ let unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
635
+ this.VoteList.push(unpacker.unpackString());
636
+ }
637
+ else if (chunk.msgid == 14 /* NETMSG.Game.SV_VOTEOPTIONREMOVE */) {
638
+ let unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
639
+ let index = this.VoteList.indexOf(unpacker.unpackString());
640
+ if (index > -1)
641
+ this.VoteList = this.VoteList.splice(index, 1);
642
+ }
643
+ // events
644
+ if (chunk.msgid == 10 /* NETMSG.Game.SV_EMOTICON */) {
645
+ let unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
646
+ let unpacked = {
647
+ client_id: unpacker.unpackInt(),
648
+ emoticon: unpacker.unpackInt()
649
+ };
650
+ if (unpacked.client_id != -1) {
651
+ unpacked.author = {
652
+ ClientInfo: this.SnapshotUnpacker.getObjClientInfo(unpacked.client_id),
653
+ PlayerInfo: this.SnapshotUnpacker.getObjPlayerInfo(unpacked.client_id)
654
+ };
655
+ }
656
+ this.emit("emote", unpacked);
657
+ }
658
+ else if (chunk.msgid == 2 /* NETMSG.Game.SV_BROADCAST */) {
659
+ let unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
660
+ this.emit("broadcast", unpacker.unpackString());
661
+ }
662
+ if (chunk.msgid == 3 /* NETMSG.Game.SV_CHAT */) {
663
+ let unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
664
+ let unpacked = {
665
+ team: unpacker.unpackInt(),
666
+ client_id: unpacker.unpackInt(),
667
+ message: unpacker.unpackString()
668
+ };
669
+ if (unpacked.client_id != -1) {
670
+ unpacked.author = {
671
+ ClientInfo: this.SnapshotUnpacker.getObjClientInfo(unpacked.client_id),
672
+ PlayerInfo: this.SnapshotUnpacker.getObjPlayerInfo(unpacked.client_id)
673
+ };
674
+ }
675
+ this.emit("message", unpacked);
676
+ }
677
+ else if (chunk.msgid == 4 /* NETMSG.Game.SV_KILLMSG */) {
678
+ let unpacked = {};
679
+ let unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
680
+ unpacked.killer_id = unpacker.unpackInt();
681
+ unpacked.victim_id = unpacker.unpackInt();
682
+ unpacked.weapon = unpacker.unpackInt();
683
+ unpacked.special_mode = unpacker.unpackInt();
684
+ if (unpacked.victim_id != -1 && unpacked.victim_id < 64) {
685
+ unpacked.victim = { ClientInfo: this.SnapshotUnpacker.getObjClientInfo(unpacked.victim_id), PlayerInfo: this.SnapshotUnpacker.getObjPlayerInfo(unpacked.victim_id) };
686
+ }
687
+ if (unpacked.killer_id != -1 && unpacked.killer_id < 64)
688
+ unpacked.killer = { ClientInfo: this.SnapshotUnpacker.getObjClientInfo(unpacked.killer_id), PlayerInfo: this.SnapshotUnpacker.getObjPlayerInfo(unpacked.killer_id) };
689
+ this.emit("kill", unpacked);
690
+ }
691
+ else if (chunk.msgid == 1 /* NETMSG.Game.SV_MOTD */) {
692
+ let unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw);
693
+ let message = unpacker.unpackString();
694
+ this.emit("motd", message);
695
+ }
696
+ // packets neccessary for connection
697
+ // https://ddnet.org/docs/libtw2/connection/
698
+ if (chunk.msgid == 8 /* NETMSG.Game.SV_READYTOENTER */) {
699
+ var Msg = new MsgPacker_1.MsgPacker(15 /* NETMSG.System.NETMSG_ENTERGAME */, true, 1); /* entergame */
700
+ this.SendMsgEx(Msg);
701
+ this.OnEnterGame();
702
+ }
703
+ }
704
+ });
705
+ if (this.State == protocol_1.States.STATE_ONLINE) {
706
+ if (new Date().getTime() - this.time >= 500) {
707
+ this.Flush();
708
+ }
709
+ if (new Date().getTime() - this.time >= 1000) {
710
+ this.time = new Date().getTime();
711
+ this.SendControlMsg(0);
712
+ }
713
+ }
714
+ });
715
+ });
716
+ }
717
+ /** Sending the input. (automatically done unless options.lightweight is on) */
718
+ sendInput(input = this.movement.input) {
719
+ if (this.State != protocol_1.States.STATE_ONLINE)
720
+ return;
721
+ let inputMsg = new MsgPacker_1.MsgPacker(16, true, 0);
722
+ inputMsg.AddInt(this.AckGameTick);
723
+ inputMsg.AddInt(this.PredGameTick);
724
+ inputMsg.AddInt(40);
725
+ inputMsg.AddInt(input.m_Direction);
726
+ inputMsg.AddInt(input.m_TargetX);
727
+ inputMsg.AddInt(input.m_TargetY);
728
+ inputMsg.AddInt(input.m_Jump);
729
+ inputMsg.AddInt(input.m_Fire);
730
+ inputMsg.AddInt(input.m_Hook);
731
+ inputMsg.AddInt(input.m_PlayerFlags);
732
+ inputMsg.AddInt(input.m_WantedWeapon);
733
+ inputMsg.AddInt(input.m_NextWeapon);
734
+ inputMsg.AddInt(input.m_PrevWeapon);
735
+ this.SendMsgEx(inputMsg);
736
+ }
737
+ /** returns the movement object of the client */
738
+ get input() {
739
+ return this.movement.input;
740
+ }
741
+ /** Disconnect the client. */
742
+ Disconnect() {
743
+ return new Promise((resolve) => {
744
+ this.SendControlMsg(4).then(() => {
745
+ resolve(true);
746
+ if (this.socket)
747
+ this.socket.close();
748
+ this.socket = undefined;
749
+ this.State = protocol_1.States.STATE_OFFLINE;
750
+ });
751
+ });
752
+ }
753
+ /** Get all available vote options (for example for map voting) */
754
+ get VoteOptionList() {
755
+ return this.VoteList;
756
+ }
757
+ get rawSnapUnpacker() {
758
+ return this.SnapUnpacker;
759
+ }
760
+ }
761
+ exports.Client = Client;
762
+ //# sourceMappingURL=client.js.map