teeworlds 2.1.3 → 2.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -12,54 +12,32 @@ var __extends = (this && this.__extends) || (function () {
12
12
  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
13
13
  };
14
14
  })();
15
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
16
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
17
- return new (P || (P = Promise))(function (resolve, reject) {
18
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
19
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
20
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
21
- step((generator = generator.apply(thisArg, _arguments || [])).next());
22
- });
23
- };
24
- var __generator = (this && this.__generator) || function (thisArg, body) {
25
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
26
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
27
- function verb(n) { return function (v) { return step([n, v]); }; }
28
- function step(op) {
29
- if (f) throw new TypeError("Generator is already executing.");
30
- while (_) try {
31
- 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;
32
- if (y = 0, t) op = [op[0] & 2, t.value];
33
- switch (op[0]) {
34
- case 0: case 1: t = op; break;
35
- case 4: _.label++; return { value: op[1], done: false };
36
- case 5: _.label++; y = op[1]; op = [0]; continue;
37
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
38
- default:
39
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
40
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
41
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
42
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
43
- if (t[2]) _.ops.pop();
44
- _.trys.pop(); continue;
45
- }
46
- op = body.call(thisArg, _);
47
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
48
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
49
- }
50
- };
51
15
  var __importDefault = (this && this.__importDefault) || function (mod) {
52
16
  return (mod && mod.__esModule) ? mod : { "default": mod };
53
17
  };
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.Client = void 0;
54
20
  var crypto_1 = require("crypto");
55
21
  var dgram_1 = __importDefault(require("dgram"));
56
22
  var stream_1 = require("stream");
57
23
  var MsgUnpacker_1 = require("./MsgUnpacker");
58
- var MsgPacker_1 = __importDefault(require("./MsgPacker"));
24
+ var movement_1 = __importDefault(require("./movement"));
25
+ var MsgPacker_1 = require("./MsgPacker");
59
26
  var snapshot_1 = require("./snapshot");
60
27
  var huffman_1 = __importDefault(require("./huffman"));
61
28
  var huff = new huffman_1.default();
62
29
  var SnapUnpacker = new snapshot_1.Snapshot();
30
+ var States;
31
+ (function (States) {
32
+ States[States["STATE_OFFLINE"] = 0] = "STATE_OFFLINE";
33
+ States[States["STATE_CONNECTING"] = 1] = "STATE_CONNECTING";
34
+ States[States["STATE_LOADING"] = 2] = "STATE_LOADING";
35
+ States[States["STATE_ONLINE"] = 3] = "STATE_ONLINE";
36
+ States[States["STATE_DEMOPLAYBACK"] = 4] = "STATE_DEMOPLAYBACK";
37
+ States[States["STATE_QUITTING"] = 5] = "STATE_QUITTING";
38
+ States[States["STATE_RESTARTING"] = 6] = "STATE_RESTARTING";
39
+ })(States || (States = {}));
40
+ ;
63
41
  var NETMSGTYPE;
64
42
  (function (NETMSGTYPE) {
65
43
  NETMSGTYPE[NETMSGTYPE["EX"] = 0] = "EX";
@@ -149,73 +127,73 @@ function arrStartsWith(arr, arrStart, start) {
149
127
  }
150
128
  var Client = /** @class */ (function (_super) {
151
129
  __extends(Client, _super);
152
- function Client(ip, port, nickname) {
130
+ function Client(ip, port, nickname, options) {
153
131
  var _this = _super.call(this) || this;
154
132
  _this.host = ip;
155
133
  _this.port = port;
156
134
  _this.name = nickname;
135
+ _this.AckGameTick = 0;
136
+ _this.PredGameTick = 0;
137
+ if (options)
138
+ _this.options = options;
139
+ _this.timer = 0;
140
+ _this.movement = new movement_1.default();
157
141
  _this.snaps = [];
158
142
  _this.client_infos = [];
159
143
  _this.player_infos = [];
160
- _this.State = 0; // 0 = offline; 1 = STATE_CONNECTING = 1, STATE_LOADING = 2, STATE_ONLINE = 3
144
+ _this.sentChunkQueue = [];
145
+ _this.State = States.STATE_OFFLINE; // 0 = offline; 1 = STATE_CONNECTING = 1, STATE_LOADING = 2, STATE_ONLINE = 3
161
146
  _this.ack = 0; // ack of messages the client has received
162
147
  _this.clientAck = 0; // ack of messages the client has sent
163
148
  _this.receivedSnaps = 0; /* wait for 2 snaps before seeing self as connected */
164
149
  _this.lastMsg = "";
165
- _this._port = Math.floor(Math.random() * 65535);
166
150
  _this.socket = dgram_1.default.createSocket("udp4");
167
151
  _this.socket.bind();
168
152
  _this.TKEN = Buffer.from([255, 255, 255, 255]);
169
153
  _this.time = new Date().getTime() + 2000; // time (used for keepalives, start to send keepalives after 2 seconds)
170
- _this.State = 0;
154
+ _this.lastSendTime = new Date().getTime();
171
155
  return _this;
172
156
  }
173
157
  Client.prototype.Unpack = function (packet) {
174
- return __awaiter(this, void 0, void 0, function () {
175
- var unpacked, i, chunk;
176
- return __generator(this, function (_a) {
177
- unpacked = { twprotocol: { flags: packet[0], ack: packet[1], chunkAmount: packet[2], size: packet.byteLength - 3 }, chunks: [] };
178
- 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)
179
- return [2 /*return*/, unpacked];
180
- packet = packet.slice(3);
181
- if (unpacked.twprotocol.flags & 128) {
182
- packet = huff.decompress(packet);
183
- if (packet.length == 1 && packet[0] == -1)
184
- return [2 /*return*/, unpacked];
185
- }
186
- // return unpacked;
187
- for (i = 0; i < unpacked.twprotocol.chunkAmount; i++) {
188
- chunk = {};
189
- chunk.bytes = ((packet[0] & 0x3f) << 4) | (packet[1] & ((1 << 4) - 1)); // idk what this shit is but it works
190
- chunk.flags = (packet[0] >> 6) & 3;
191
- chunk.sequence = -1;
192
- if (chunk.flags & 1) {
193
- chunk.seq = ((packet[1] & 0xf0) << 2) | packet[2];
194
- packet = packet.slice(3); // remove flags & size
195
- }
196
- else
197
- packet = packet.slice(2);
198
- chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
199
- chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
200
- chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
201
- chunk.raw = packet.slice(1, chunk.bytes);
202
- Object.values(messageUUIDs).forEach(function (a, i) {
203
- if (a.compare(packet.slice(0, 16)) == 0) {
204
- chunk.extended_msgid = a;
205
- // chunk.type = 'sys';
206
- chunk.msg = Object.keys(messageUUIDs)[i];
207
- }
208
- });
209
- packet = packet.slice(chunk.bytes); // +1 cuz it adds an extra \x00 for easier parsing i guess
210
- unpacked.chunks.push(chunk);
158
+ var unpacked = { twprotocol: { flags: packet[0], ack: packet[1], chunkAmount: packet[2], size: packet.byteLength - 3 }, chunks: [] };
159
+ 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)
160
+ return unpacked;
161
+ packet = packet.slice(3);
162
+ if (unpacked.twprotocol.flags & 128) {
163
+ packet = huff.decompress(packet);
164
+ if (packet.length == 1 && packet[0] == -1)
165
+ return unpacked;
166
+ }
167
+ for (var i = 0; i < unpacked.twprotocol.chunkAmount; i++) {
168
+ var chunk = {};
169
+ chunk.bytes = ((packet[0] & 0x3f) << 4) | (packet[1] & ((1 << 4) - 1));
170
+ chunk.flags = (packet[0] >> 6) & 3;
171
+ chunk.sequence = -1;
172
+ if (chunk.flags & 1) {
173
+ chunk.seq = ((packet[1] & 0xf0) << 2) | packet[2];
174
+ packet = packet.slice(3); // remove flags & size
175
+ }
176
+ else
177
+ packet = packet.slice(2);
178
+ chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
179
+ chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
180
+ chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
181
+ chunk.raw = packet.slice(1, chunk.bytes);
182
+ Object.values(messageUUIDs).forEach(function (a, i) {
183
+ if (a.compare(packet.slice(0, 16)) == 0) {
184
+ chunk.extended_msgid = a;
185
+ chunk.msg = Object.keys(messageUUIDs)[i];
211
186
  }
212
- return [2 /*return*/, unpacked];
213
187
  });
214
- });
188
+ packet = packet.slice(chunk.bytes);
189
+ unpacked.chunks.push(chunk);
190
+ }
191
+ return unpacked;
215
192
  };
216
193
  Client.prototype.SendControlMsg = function (msg, ExtraMsg) {
217
194
  var _this = this;
218
195
  if (ExtraMsg === void 0) { ExtraMsg = ""; }
196
+ this.lastSendTime = new Date().getTime();
219
197
  return new Promise(function (resolve, reject) {
220
198
  if (_this.socket) {
221
199
  var latestBuf = Buffer.from([0x10 + (((16 << 4) & 0xf0) | ((_this.ack >> 8) & 0xf)), _this.ack & 0xff, 0x00, msg]);
@@ -231,229 +209,331 @@ var Client = /** @class */ (function (_super) {
231
209
  */
232
210
  });
233
211
  };
234
- Client.prototype.SendMsgEx = function (Msg, Flags) {
235
- if (this.State == -1)
236
- throw new Error("Client is not connected");
237
- if (!this.socket)
238
- return;
239
- var header = [];
240
- header[0] = ((Flags & 3) << 6) | ((Msg.size >> 4) & 0x3f);
241
- header[1] = (Msg.size & 0xf);
242
- if (Flags & 1) {
243
- this.clientAck = (this.clientAck + 1) % (1 << 10);
244
- header[1] |= (this.clientAck >> 2) & 0xf0;
245
- header[2] = this.clientAck & 0xff;
246
- }
247
- var latestBuf = Buffer.from([0x0 + (((16 << 4) & 0xf0) | ((this.ack >> 8) & 0xf)), this.ack & 0xff, 0x1, header[0], header[1], this.clientAck]);
248
- var latestBuf = Buffer.concat([latestBuf, Msg.buffer, this.TKEN]);
249
- this.socket.send(latestBuf, 0, latestBuf.length, this.port, this.host);
250
- };
251
- Client.prototype.SendMsgExWithChunks = function (Msgs, Flags) {
212
+ Client.prototype.SendMsgEx = function (Msgs, Flags) {
252
213
  var _this = this;
253
- if (this.State == -1)
254
- throw new Error("Client is not connected");
214
+ if (this.State == States.STATE_OFFLINE)
215
+ return;
255
216
  if (!this.socket)
256
217
  return;
218
+ var _Msgs;
219
+ if (Msgs instanceof Array)
220
+ _Msgs = Msgs;
221
+ else
222
+ _Msgs = [Msgs];
223
+ this.lastSendTime = new Date().getTime();
257
224
  var header = [];
258
- Msgs.forEach(function (Msg, index) {
259
- header[index] = new Array(2);
225
+ _Msgs.forEach(function (Msg, index) {
226
+ header[index] = Buffer.alloc((Flags & 1 ? 3 : 2));
260
227
  header[index][0] = ((Flags & 3) << 6) | ((Msg.size >> 4) & 0x3f);
261
228
  header[index][1] = (Msg.size & 0xf);
262
229
  if (Flags & 1) {
263
230
  _this.clientAck = (_this.clientAck + 1) % (1 << 10);
264
231
  header[index][1] |= (_this.clientAck >> 2) & 0xf0;
265
232
  header[index][2] = _this.clientAck & 0xff;
233
+ header[index][0] = (((Flags | 2) & 3) << 6) | ((Msg.size >> 4) & 0x3f); // 2 is resend flag (ugly hack for queue)
234
+ _this.sentChunkQueue.push(Buffer.concat([header[index], Msg.buffer]));
235
+ header[index][0] = (((Flags) & 3) << 6) | ((Msg.size >> 4) & 0x3f);
266
236
  }
267
237
  });
268
- var packetHeader = Buffer.from([0x0 + (((16 << 4) & 0xf0) | ((this.ack >> 8) & 0xf)), this.ack & 0xff, Msgs.length]);
238
+ var packetHeader = Buffer.from([0x0 + (((16 << 4) & 0xf0) | ((this.ack >> 8) & 0xf)), this.ack & 0xff, _Msgs.length]);
269
239
  var chunks = Buffer.from([]);
270
- Msgs.forEach(function (Msg, index) {
240
+ _Msgs.forEach(function (Msg, index) {
271
241
  chunks = Buffer.concat([chunks, Buffer.from(header[index]), Msg.buffer]);
272
242
  });
273
243
  var packet = Buffer.concat([(packetHeader), chunks, this.TKEN]);
274
244
  this.socket.send(packet, 0, packet.length, this.port, this.host);
275
245
  };
246
+ Client.prototype.SendMsgRaw = function (chunks) {
247
+ if (this.State == States.STATE_OFFLINE)
248
+ return;
249
+ if (!this.socket)
250
+ return;
251
+ this.lastSendTime = new Date().getTime();
252
+ var packetHeader = Buffer.from([0x0 + (((16 << 4) & 0xf0) | ((this.ack >> 8) & 0xf)), this.ack & 0xff, chunks.length]);
253
+ var packet = Buffer.concat([(packetHeader), Buffer.concat(chunks), this.TKEN]);
254
+ this.socket.send(packet, 0, packet.length, this.port, this.host);
255
+ };
256
+ Client.prototype.MsgToChunk = function (packet) {
257
+ var chunk = {};
258
+ chunk.bytes = ((packet[0] & 0x3f) << 4) | (packet[1] & ((1 << 4) - 1));
259
+ chunk.flags = (packet[0] >> 6) & 3;
260
+ chunk.sequence = -1;
261
+ if (chunk.flags & 1) {
262
+ chunk.seq = ((packet[1] & 0xf0) << 2) | packet[2];
263
+ packet = packet.slice(3); // remove flags & size
264
+ }
265
+ else
266
+ packet = packet.slice(2);
267
+ chunk.type = packet[0] & 1 ? "sys" : "game"; // & 1 = binary, ****_***1. e.g 0001_0111 sys, 0001_0110 game
268
+ chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
269
+ chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
270
+ chunk.raw = packet.slice(1, chunk.bytes);
271
+ Object.values(messageUUIDs).forEach(function (a, i) {
272
+ if (a.compare(packet.slice(0, 16)) === 0) {
273
+ chunk.extended_msgid = a;
274
+ chunk.msg = Object.keys(messageUUIDs)[i];
275
+ }
276
+ });
277
+ return chunk;
278
+ };
276
279
  Client.prototype.connect = function () {
277
280
  var _this = this;
281
+ this.State = States.STATE_CONNECTING;
282
+ var predTimer = setInterval(function () {
283
+ if (_this.State == States.STATE_ONLINE) {
284
+ if (_this.AckGameTick > 0)
285
+ _this.PredGameTick++;
286
+ }
287
+ else if (_this.State == States.STATE_OFFLINE)
288
+ clearInterval(predTimer);
289
+ }, 20);
278
290
  this.SendControlMsg(1, "TKEN");
279
291
  var connectInterval = setInterval(function () {
280
- if (_this.State == 0)
292
+ if (_this.State == States.STATE_CONNECTING)
281
293
  _this.SendControlMsg(1, "TKEN");
282
294
  else
283
295
  clearInterval(connectInterval);
284
296
  }, 500);
297
+ var inputInterval = setInterval(function () {
298
+ if (_this.State == States.STATE_OFFLINE)
299
+ clearInterval(inputInterval);
300
+ if (_this.State != States.STATE_ONLINE)
301
+ return;
302
+ _this.time = new Date().getTime();
303
+ _this.sendInput();
304
+ }, 500);
305
+ var resendTimeout = setInterval(function () {
306
+ if (_this.State != States.STATE_OFFLINE) {
307
+ if (((new Date().getTime()) - _this.lastSendTime) > 900 && _this.sentChunkQueue.length > 0) {
308
+ _this.SendMsgRaw([_this.sentChunkQueue[0]]);
309
+ }
310
+ }
311
+ else
312
+ clearInterval(resendTimeout);
313
+ }, 1000);
285
314
  this.time = new Date().getTime() + 2000; // start sending keepalives after 2s
286
315
  if (this.socket)
287
- this.socket.on("message", function (a) { return __awaiter(_this, void 0, void 0, function () {
288
- var unpacked, chunkMessages, chat, chat, info, client_version, randomUuid, reason, Msg, Msg, info, info, chunks, part_1, num_parts_1;
289
- var _this = this;
290
- return __generator(this, function (_a) {
291
- switch (_a.label) {
292
- case 0: return [4 /*yield*/, this.Unpack(a)];
293
- case 1:
294
- unpacked = _a.sent();
295
- if (unpacked.twprotocol.flags != 128 && unpacked.twprotocol.ack) {
296
- unpacked.chunks.forEach(function (a) {
297
- if (a.msg && !a.msg.startsWith("SNAP")) {
298
- if (a.seq != undefined && a.seq != -1)
299
- _this.ack = a.seq;
300
- }
301
- });
302
- }
303
- chunkMessages = unpacked.chunks.map(function (a) { return a.msg; });
304
- if (chunkMessages.includes("SV_CHAT")) {
305
- chat = unpacked.chunks.filter(function (a) { return a.msg == "SV_CHAT"; });
306
- chat.forEach(function (a) {
307
- if (a.msg == "SV_CHAT") {
308
- var unpacked = {};
309
- unpacked.team = MsgUnpacker_1.unpackInt(a.raw.toJSON().data).result;
310
- var remaining = MsgUnpacker_1.unpackInt(a.raw.toJSON().data).remaining;
311
- unpacked.client_id = MsgUnpacker_1.unpackInt(remaining).result;
312
- remaining = MsgUnpacker_1.unpackInt(remaining).remaining;
313
- unpacked.message = MsgUnpacker_1.unpackString(remaining).result;
314
- if (unpacked.client_id != -1)
315
- unpacked.author = { ClientInfo: _this.client_infos[unpacked.client_id], PlayerInfo: _this.player_infos[unpacked.client_id] };
316
- // console.log(unpacked)
317
- _this.emit("message", unpacked);
318
- }
319
- });
320
- }
321
- if (chunkMessages.includes("SV_KILL_MSG")) {
322
- chat = unpacked.chunks.filter(function (a) { return a.msg == "SV_KILL_MSG"; });
323
- chat.forEach(function (a) {
324
- if (a.msg == "SV_KILL_MSG") {
325
- var unpacked = {};
326
- var unpacker = new MsgUnpacker_1.MsgUnpacker(a.raw.toJSON().data);
327
- unpacked.killer_id = unpacker.unpackInt();
328
- unpacked.victim_id = unpacker.unpackInt();
329
- unpacked.weapon = unpacker.unpackInt();
330
- unpacked.special_mode = unpacker.unpackInt();
331
- if (unpacked.victim_id != -1)
332
- unpacked.victim = { ClientInfo: _this.client_infos[unpacked.victim_id], PlayerInfo: _this.player_infos[unpacked.victim_id] };
333
- if (unpacked.killer_id != -1)
334
- unpacked.killer = { ClientInfo: _this.client_infos[unpacked.killer_id], PlayerInfo: _this.player_infos[unpacked.killer_id] };
335
- // console.log(unpacked)
336
- _this.emit("kill", unpacked);
316
+ this.socket.on("message", function (a, rinfo) {
317
+ var _a, _b, _c, _d, _e, _f;
318
+ if (_this.State == 0 || rinfo.address != _this.host || rinfo.port != _this.port)
319
+ return;
320
+ clearInterval(connectInterval);
321
+ if (a.toJSON().data[0] == 0x10) {
322
+ if (a.toString().includes("TKEN") || a.toJSON().data[3] == 0x2) {
323
+ clearInterval(connectInterval);
324
+ _this.TKEN = Buffer.from(a.toJSON().data.slice(a.toJSON().data.length - 4, a.toJSON().data.length));
325
+ _this.SendControlMsg(3);
326
+ _this.State = States.STATE_LOADING; // loading state
327
+ _this.receivedSnaps = 0;
328
+ var info = new MsgPacker_1.MsgPacker(1, true);
329
+ info.AddString("0.6 626fce9a778df4d4");
330
+ info.AddString(((_a = _this.options) === null || _a === void 0 ? void 0 : _a.password) === undefined ? "" : (_b = _this.options) === null || _b === void 0 ? void 0 : _b.password); // password
331
+ var client_version = new MsgPacker_1.MsgPacker(0, true);
332
+ client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
333
+ var randomUuid = Buffer.alloc(16);
334
+ crypto_1.randomBytes(16).copy(randomUuid);
335
+ client_version.AddBuffer(randomUuid);
336
+ if (((_c = _this.options) === null || _c === void 0 ? void 0 : _c.ddnet_version) !== undefined) {
337
+ client_version.AddInt((_d = _this.options) === null || _d === void 0 ? void 0 : _d.ddnet_version.version);
338
+ client_version.AddString("DDNet " + ((_e = _this.options) === null || _e === void 0 ? void 0 : _e.ddnet_version.release_version));
339
+ }
340
+ else {
341
+ client_version.AddInt(16003);
342
+ client_version.AddString("DDNet 16.0.3");
343
+ }
344
+ _this.SendMsgEx([client_version, info], 1);
345
+ }
346
+ else if (a.toJSON().data[3] == 0x4) {
347
+ // disconnected
348
+ _this.State = States.STATE_OFFLINE;
349
+ var reason = (MsgUnpacker_1.unpackString(a.toJSON().data.slice(4)).result);
350
+ _this.emit("disconnect", reason);
351
+ }
352
+ }
353
+ var unpacked = _this.Unpack(a);
354
+ unpacked.chunks.forEach(function (a) {
355
+ if (a.flags & 1) { // vital
356
+ if (a.seq != undefined && a.seq != -1)
357
+ _this.ack = a.seq;
358
+ }
359
+ });
360
+ _this.sentChunkQueue.forEach(function (buff, i) {
361
+ var chunk = _this.MsgToChunk(buff);
362
+ if (chunk.flags & 1) {
363
+ if (chunk.seq && chunk.seq < _this.ack) {
364
+ _this.sentChunkQueue.splice(i, 1);
365
+ }
366
+ }
367
+ });
368
+ var snapChunks = unpacked.chunks.filter(function (a) { return a.msg === "SNAP" || a.msg === "SNAP_SINGLE" || a.msg === "SNAP_EMPTY"; });
369
+ if (snapChunks.length > 0) {
370
+ var part = 0;
371
+ var num_parts = 1;
372
+ snapChunks.forEach(function (chunk) {
373
+ var unpacker = new MsgUnpacker_1.MsgUnpacker(chunk.raw.toJSON().data);
374
+ var AckGameTick = unpacker.unpackInt();
375
+ if (AckGameTick > _this.AckGameTick) {
376
+ _this.AckGameTick = AckGameTick;
377
+ if (Math.abs(_this.PredGameTick - _this.AckGameTick) > 10)
378
+ _this.PredGameTick = AckGameTick + 1;
379
+ }
380
+ // chunk.raw = Buffer.from(unpackInt(chunk?.raw?.toJSON().data).remaining);
381
+ var DeltaTick = AckGameTick - unpacker.unpackInt();
382
+ var num_parts = 1;
383
+ var part = 0;
384
+ if (chunk.msg === "SNAP") {
385
+ // chunk.raw = Buffer.from(unpackInt(chunk?.raw?.toJSON().data).remaining); // delta tick
386
+ num_parts = unpacker.unpackInt();
387
+ // chunk.raw = Buffer.from(unpackInt(chunk?.raw?.toJSON().data).remaining); // num parts
388
+ part = unpacker.unpackInt();
389
+ }
390
+ var crc = 0;
391
+ var part_size = 0;
392
+ if (chunk.msg != "SNAP_EMPTY") {
393
+ crc = unpacker.unpackInt(); // crc
394
+ part_size = unpacker.unpackInt();
395
+ }
396
+ if (part === 0 || _this.snaps.length > 30) {
397
+ _this.snaps = [];
398
+ }
399
+ chunk.raw = Buffer.from(unpacker.remaining);
400
+ _this.snaps.push(chunk.raw);
401
+ if ((num_parts - 1) === part && _this.snaps.length === num_parts) {
402
+ var mergedSnaps_1 = Buffer.concat(_this.snaps);
403
+ // mergedSnaps = Buffer.from(unpackInt(mergedSnaps.toJSON().data).remaining);
404
+ var snapUnpacked = SnapUnpacker.unpackSnapshot(mergedSnaps_1.toJSON().data, 1);
405
+ // console.log(snapUnpacked.items, toHexStream(mergedSnaps));
406
+ snapUnpacked.items.forEach(function (a, i) {
407
+ if (a.type_id === items.OBJ_CLIENT_INFO) {
408
+ _this.client_infos[a.id] = a.parsed;
409
+ if (_this.client_infos[a.id].name.includes("�") || _this.client_infos[a.id].clan.includes("�")) {
410
+ console.log("bad name", _this.client_infos[a.id], toHexStream(mergedSnaps_1), chunk, AckGameTick, DeltaTick, crc, part_size);
337
411
  }
338
- });
339
- }
340
- if (a.toJSON().data[0] == 0x10) {
341
- if (a.toString().includes("TKEN") || arrStartsWith(a.toJSON().data, [0x10, 0x0, 0x0, 0x0])) {
342
- clearInterval(connectInterval);
343
- this.TKEN = Buffer.from(a.toJSON().data.slice(a.toJSON().data.length - 4, a.toJSON().data.length));
344
- this.SendControlMsg(3);
345
- this.State = 2; // loading state
346
- info = new MsgPacker_1.default(1, true);
347
- info.AddString("0.6 626fce9a778df4d4");
348
- info.AddString(""); // password
349
- client_version = new MsgPacker_1.default(0, true);
350
- client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
351
- randomUuid = new Uint8Array(16);
352
- crypto_1.randomBytes(16).copy(randomUuid);
353
- client_version.AddBuffer(Buffer.from(randomUuid));
354
- client_version.AddInt(15091);
355
- client_version.AddString("DDNet 15.9.1");
356
- this.SendMsgExWithChunks([client_version, info], 1);
357
- }
358
- else if (a.toJSON().data[3] == 0x4) {
359
- // disconnected
360
- this.State = 0;
361
- reason = (MsgUnpacker_1.unpackString(a.toJSON().data.slice(4)).result);
362
- this.State = -1;
363
- this.emit("disconnect", reason);
364
- }
365
- }
366
- if (unpacked.chunks[0] && chunkMessages.includes("SV_READY_TO_ENTER")) {
367
- Msg = new MsgPacker_1.default(15, true);
368
- this.SendMsgEx(Msg, 1);
369
- }
370
- else if ((unpacked.chunks[0] && chunkMessages.includes("CAPABILITIES") || unpacked.chunks[0] && chunkMessages.includes("MAP_CHANGE"))) {
371
- Msg = new MsgPacker_1.default(14, true);
372
- this.SendMsgEx(Msg, 1);
373
- }
374
- else if ((unpacked.chunks[0] && chunkMessages.includes("CON_READY") || unpacked.chunks[0] && chunkMessages.includes("SV_MOTD"))) {
375
- info = new MsgPacker_1.default(20, false);
376
- info.AddString(this.name); /* name */
377
- info.AddString(""); /* clan */
378
- info.AddInt(-1); /* country */
379
- info.AddString("greyfox"); /* skin */
380
- info.AddInt(1); /* use custom color */
381
- info.AddInt(10346103); /* color body */
382
- info.AddInt(65535); /* color feet */
383
- this.SendMsgEx(info, 1);
384
- }
385
- else if (unpacked.chunks[0] && chunkMessages.includes("SV_READY_TO_ENTER")) {
386
- if (this.State != 3) {
387
- this.emit('connected');
412
+ console.log(_this.client_infos[a.id]);
388
413
  }
389
- this.State = 3;
390
- }
391
- else if (unpacked.chunks[0] && chunkMessages.includes("PING")) {
392
- info = new MsgPacker_1.default(23, true);
393
- this.SendMsgEx(info, 1);
394
- }
395
- if (chunkMessages.includes("SNAP") || chunkMessages.includes("SNAP_EMPTY") || chunkMessages.includes("SNAP_SINGLE")) {
396
- this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
397
- if (this.receivedSnaps >= 2) {
398
- if (this.State != 3)
399
- this.emit('connected');
400
- this.State = 3;
401
- }
402
- chunks = unpacked.chunks.filter(function (a) { return a.msg == "SNAP" || a.msg == "SNAP_SINGLE" || a.msg == "SNAP_EMPTY"; });
403
- if (chunks.length > 0) {
404
- part_1 = 0;
405
- num_parts_1 = 1;
406
- chunks.forEach(function (chunk) {
407
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
408
- var AckGameTick = (MsgUnpacker_1.unpackInt(chunk.raw.toJSON().data).result);
409
- chunk.raw = Buffer.from(MsgUnpacker_1.unpackInt((_a = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _a === void 0 ? void 0 : _a.toJSON().data).remaining);
410
- var DeltaTick = MsgUnpacker_1.unpackInt((_b = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _b === void 0 ? void 0 : _b.toJSON().data).result;
411
- if (chunk.msg == "SNAP") {
412
- chunk.raw = Buffer.from(MsgUnpacker_1.unpackInt((_c = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _c === void 0 ? void 0 : _c.toJSON().data).remaining); // delta tick
413
- num_parts_1 = (MsgUnpacker_1.unpackInt((_d = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _d === void 0 ? void 0 : _d.toJSON().data).result);
414
- chunk.raw = Buffer.from(MsgUnpacker_1.unpackInt((_e = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _e === void 0 ? void 0 : _e.toJSON().data).remaining); // num parts
415
- part_1 = (MsgUnpacker_1.unpackInt((_f = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _f === void 0 ? void 0 : _f.toJSON().data).result);
416
- }
417
- chunk.raw = Buffer.from(MsgUnpacker_1.unpackInt((_g = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _g === void 0 ? void 0 : _g.toJSON().data).remaining); // part
418
- if (chunk.msg != "SNAP_EMPTY")
419
- chunk.raw = Buffer.from(MsgUnpacker_1.unpackInt((_h = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _h === void 0 ? void 0 : _h.toJSON().data).remaining); // crc
420
- chunk.raw = Buffer.from(MsgUnpacker_1.unpackInt((_j = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _j === void 0 ? void 0 : _j.toJSON().data).remaining); // crc
421
- if (part_1 == 0 || _this.snaps.length > 30) {
422
- _this.snaps = [];
423
- }
424
- _this.snaps.push(chunk.raw);
425
- if ((num_parts_1 - 1) == part_1 && _this.snaps.length == num_parts_1) {
426
- var mergedSnaps = Buffer.concat(_this.snaps);
427
- var snapUnpacked = SnapUnpacker.unpackSnapshot(mergedSnaps.toJSON().data, 1);
428
- snapUnpacked.items.forEach(function (a, i) {
429
- if (a.type_id == items.OBJ_CLIENT_INFO) {
430
- _this.client_infos[a.id] = a.parsed;
431
- // console.log(a.parsed, i)
432
- // console.log(this.client_infos[a.id])
433
- }
434
- else if (a.type_id == items.OBJ_PLAYER_INFO) {
435
- _this.player_infos[i] = a.parsed;
436
- }
437
- else if (a.type_id == items.OBJ_EX || a.type_id > 0x4000) {
438
- if (a.data.length == 5 && (a.parsed.freeze_end > 0 || a.parsed.freeze_end == -1)) {
439
- // var packer = new MsgPacker(22, false)
440
- // this.SendMsgEx(packer, 1)
441
- }
442
- }
443
- });
444
- }
445
- });
446
- }
447
- }
448
- if (new Date().getTime() - this.time >= 1000) {
449
- this.time = new Date().getTime();
450
- this.SendControlMsg(0);
451
- }
452
- return [2 /*return*/];
414
+ });
415
+ }
416
+ });
417
+ }
418
+ var chunkMessages = unpacked.chunks.map(function (a) { return a.msg; });
419
+ if (chunkMessages.includes("SV_CHAT")) {
420
+ var chat = unpacked.chunks.filter(function (a) { return a.msg == "SV_CHAT"; });
421
+ chat.forEach(function (a) {
422
+ if (a.msg == "SV_CHAT") {
423
+ var unpacker = new MsgUnpacker_1.MsgUnpacker(a.raw.toJSON().data);
424
+ var unpacked = {
425
+ team: unpacker.unpackInt(),
426
+ client_id: unpacker.unpackInt(),
427
+ message: unpacker.unpackString()
428
+ };
429
+ if (unpacked.client_id != -1)
430
+ unpacked.author = {
431
+ ClientInfo: _this.client_infos[unpacked.client_id],
432
+ PlayerInfo: _this.player_infos[unpacked.client_id]
433
+ };
434
+ _this.emit("message", unpacked);
435
+ }
436
+ });
437
+ }
438
+ if (chunkMessages.includes("SV_KILL_MSG")) {
439
+ var chat = unpacked.chunks.filter(function (a) { return a.msg == "SV_KILL_MSG"; });
440
+ chat.forEach(function (a) {
441
+ if (a.msg == "SV_KILL_MSG") {
442
+ var unpacked = {};
443
+ var unpacker = new MsgUnpacker_1.MsgUnpacker(a.raw.toJSON().data);
444
+ unpacked.killer_id = unpacker.unpackInt();
445
+ unpacked.victim_id = unpacker.unpackInt();
446
+ unpacked.weapon = unpacker.unpackInt();
447
+ unpacked.special_mode = unpacker.unpackInt();
448
+ if (unpacked.victim_id != -1)
449
+ unpacked.victim = { ClientInfo: _this.client_infos[unpacked.victim_id], PlayerInfo: _this.player_infos[unpacked.victim_id] };
450
+ if (unpacked.killer_id != -1)
451
+ unpacked.killer = { ClientInfo: _this.client_infos[unpacked.killer_id], PlayerInfo: _this.player_infos[unpacked.killer_id] };
452
+ _this.emit("kill", unpacked);
453
+ }
454
+ });
455
+ }
456
+ if (unpacked.chunks[0] && chunkMessages.includes("SV_READY_TO_ENTER")) {
457
+ var Msg = new MsgPacker_1.MsgPacker(15, true); /* entergame */
458
+ _this.SendMsgEx(Msg, 1);
459
+ }
460
+ else if ((unpacked.chunks[0] && chunkMessages.includes("CAPABILITIES") || unpacked.chunks[0] && chunkMessages.includes("MAP_CHANGE"))) {
461
+ // send ready
462
+ var Msg = new MsgPacker_1.MsgPacker(14, true); /* ready */
463
+ _this.SendMsgEx(Msg, 1);
464
+ }
465
+ else if ((unpacked.chunks[0] && chunkMessages.includes("CON_READY") || unpacked.chunks[0] && chunkMessages.includes("SV_MOTD"))) {
466
+ var info = new MsgPacker_1.MsgPacker(20, false);
467
+ if ((_f = _this.options) === null || _f === void 0 ? void 0 : _f.identity) {
468
+ info.AddString(_this.options.identity.name);
469
+ info.AddString(_this.options.identity.clan);
470
+ info.AddInt(_this.options.identity.country);
471
+ info.AddString(_this.options.identity.skin);
472
+ info.AddInt(_this.options.identity.use_custom_color);
473
+ info.AddInt(_this.options.identity.color_body);
474
+ info.AddInt(_this.options.identity.color_feet);
453
475
  }
454
- });
455
- }); });
476
+ else {
477
+ info.AddString(_this.name); /* name */
478
+ info.AddString(""); /* clan */
479
+ info.AddInt(-1); /* country */
480
+ info.AddString("greyfox"); /* skin */
481
+ info.AddInt(1); /* use custom color */
482
+ info.AddInt(10346103); /* color body */
483
+ info.AddInt(65535); /* color feet */
484
+ }
485
+ _this.SendMsgEx(info, 1);
486
+ }
487
+ else if (unpacked.chunks[0] && chunkMessages.includes("PING")) {
488
+ var info = new MsgPacker_1.MsgPacker(23, true);
489
+ _this.SendMsgEx(info, 1);
490
+ }
491
+ if (chunkMessages.includes("SNAP") || chunkMessages.includes("SNAP_EMPTY") || chunkMessages.includes("SNAP_SINGLE")) {
492
+ _this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
493
+ if (_this.receivedSnaps == 2) {
494
+ if (_this.State != States.STATE_ONLINE)
495
+ _this.emit('connected');
496
+ _this.State = States.STATE_ONLINE;
497
+ }
498
+ }
499
+ if (new Date().getTime() - _this.time >= 1000 && _this.State == States.STATE_ONLINE) {
500
+ _this.time = new Date().getTime();
501
+ _this.SendControlMsg(0);
502
+ }
503
+ });
456
504
  };
505
+ Client.prototype.sendInput = function (input) {
506
+ if (input === void 0) { input = this.movement.input; }
507
+ if (this.State != States.STATE_ONLINE)
508
+ return;
509
+ var inputMsg = new MsgPacker_1.MsgPacker(16, true);
510
+ inputMsg.AddInt(this.AckGameTick);
511
+ inputMsg.AddInt(this.PredGameTick);
512
+ inputMsg.AddInt(40);
513
+ var input_data = [
514
+ input.m_Direction,
515
+ input.m_TargetX,
516
+ input.m_TargetY,
517
+ input.m_Jump,
518
+ input.m_Fire,
519
+ input.m_Hook,
520
+ input.m_PlayerFlags,
521
+ input.m_WantedWeapon,
522
+ input.m_NextWeapon,
523
+ input.m_PrevWeapon
524
+ ];
525
+ input_data.forEach(function (a) {
526
+ inputMsg.AddInt(a);
527
+ });
528
+ this.SendMsgEx(inputMsg, 0);
529
+ };
530
+ Object.defineProperty(Client.prototype, "input", {
531
+ get: function () {
532
+ return this.movement.input;
533
+ },
534
+ enumerable: false,
535
+ configurable: true
536
+ });
457
537
  Client.prototype.Disconnect = function () {
458
538
  var _this = this;
459
539
  return new Promise(function (resolve) {
@@ -462,24 +542,24 @@ var Client = /** @class */ (function (_super) {
462
542
  if (_this.socket)
463
543
  _this.socket.close();
464
544
  _this.socket = undefined;
465
- _this.State = -1;
545
+ _this.State = States.STATE_OFFLINE;
466
546
  });
467
547
  });
468
548
  };
469
549
  Client.prototype.Say = function (message, team) {
470
550
  if (team === void 0) { team = false; }
471
- var packer = new MsgPacker_1.default(NETMSGTYPE.CL_SAY, false);
551
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_SAY, false);
472
552
  packer.AddInt(team ? 1 : 0); // team
473
553
  packer.AddString(message);
474
554
  this.SendMsgEx(packer, 1);
475
555
  };
476
556
  Client.prototype.Vote = function (vote) {
477
- var packer = new MsgPacker_1.default(NETMSGTYPE.CL_VOTE, false);
557
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_VOTE, false);
478
558
  packer.AddInt(vote ? 1 : 0);
479
559
  this.SendMsgEx(packer, 1);
480
560
  };
481
561
  Client.prototype.ChangePlayerInfo = function (playerInfo) {
482
- var packer = new MsgPacker_1.default(NETMSGTYPE.CL_CHANGEINFO, false);
562
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_CHANGEINFO, false);
483
563
  packer.AddString(playerInfo.name); //m_pName);
484
564
  packer.AddString(playerInfo.clan); //m_pClan);
485
565
  packer.AddInt(playerInfo.country); //m_Country);
@@ -490,20 +570,19 @@ var Client = /** @class */ (function (_super) {
490
570
  this.SendMsgEx(packer, 1);
491
571
  };
492
572
  Client.prototype.Kill = function () {
493
- var packer = new MsgPacker_1.default(NETMSGTYPE.CL_KILL, false);
573
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_KILL, false);
494
574
  this.SendMsgEx(packer, 1);
495
575
  };
496
576
  Client.prototype.ChangeTeam = function (team) {
497
- var packer = new MsgPacker_1.default(NETMSGTYPE.CL_SETTEAM, false);
577
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_SETTEAM, false);
498
578
  packer.AddInt(team);
499
579
  this.SendMsgEx(packer, 1);
500
580
  };
501
581
  Client.prototype.Emote = function (emote) {
502
- var packer = new MsgPacker_1.default(NETMSGTYPE.CL_EMOTICON, false);
582
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_EMOTICON, false);
503
583
  packer.AddInt(emote);
504
584
  this.SendMsgEx(packer, 1);
505
585
  };
506
586
  return Client;
507
587
  }(stream_1.EventEmitter));
508
- module.exports = Client;
509
- // module.exports = Client;
588
+ exports.Client = Client;