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/index.js +16 -9
- package/index.ts +5 -9
- package/lib/MsgPacker.js +4 -3
- package/lib/MsgPacker.ts +2 -6
- package/lib/MsgUnpacker.js +0 -3
- package/lib/MsgUnpacker.ts +1 -6
- package/lib/client.js +359 -280
- package/lib/client.ts +381 -200
- package/lib/movement.js +54 -0
- package/lib/movement.ts +63 -0
- package/lib/snapshot.js +6 -14
- package/lib/snapshot.ts +9 -15
- package/package.json +1 -1
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
|
|
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.
|
|
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.
|
|
154
|
+
_this.lastSendTime = new Date().getTime();
|
|
171
155
|
return _this;
|
|
172
156
|
}
|
|
173
157
|
Client.prototype.Unpack = function (packet) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
return
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
chunk.
|
|
201
|
-
chunk.
|
|
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 (
|
|
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 ==
|
|
254
|
-
|
|
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
|
-
|
|
259
|
-
header[index] =
|
|
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,
|
|
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
|
-
|
|
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 ==
|
|
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
|
|
288
|
-
var
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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 =
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
509
|
-
// module.exports = Client;
|
|
588
|
+
exports.Client = Client;
|