teeworlds 2.0.7 → 2.0.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/README.md CHANGED
@@ -7,7 +7,7 @@ https://www.npmjs.com/package/teeworlds
7
7
  # Usage
8
8
  Example file:
9
9
  ```const teeworlds = require('teeworlds');
10
- let client = new teeworlds.Client("127.0.0.1", 8303, "teest");
10
+ let client = new teeworlds.Client("127.0.0.1", 8303, "nameless tee");
11
11
 
12
12
  client.connect();
13
13
 
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var MsgPacker = /** @class */ (function () {
3
+ function MsgPacker(msg, sys) {
4
+ this.result = Buffer.from([2 * msg + (sys ? 1 : 0)]); // booleans turn into int automatically.
5
+ this.sys = sys;
6
+ }
7
+ MsgPacker.prototype.AddString = function (str) {
8
+ this.result = Buffer.concat([this.result, Buffer.from(str), Buffer.from([0x00])]);
9
+ };
10
+ MsgPacker.prototype.AddBuffer = function (buffer) {
11
+ this.result = Buffer.concat([this.result, buffer]);
12
+ };
13
+ MsgPacker.prototype.AddInt = function (i) {
14
+ var result = [];
15
+ var pDst = (i >> 25) & 0x40;
16
+ var i = i ^ (i >> 31);
17
+ pDst |= i & 0x3f;
18
+ i >>= 6;
19
+ if (i) {
20
+ pDst |= 0x80;
21
+ result.push(pDst);
22
+ while (true) {
23
+ pDst++;
24
+ pDst = i & (0x7f);
25
+ i >>= 7;
26
+ pDst |= (Number(i != 0)) << 7;
27
+ result.push(pDst);
28
+ if (!i)
29
+ break;
30
+ }
31
+ }
32
+ else
33
+ result.push(pDst);
34
+ // ... i'll just stop trying to understand.
35
+ this.result = Buffer.concat([this.result, Buffer.from(result)]);
36
+ };
37
+ Object.defineProperty(MsgPacker.prototype, "size", {
38
+ get: function () {
39
+ return this.result.byteLength;
40
+ },
41
+ enumerable: false,
42
+ configurable: true
43
+ });
44
+ Object.defineProperty(MsgPacker.prototype, "buffer", {
45
+ get: function () {
46
+ return this.result;
47
+ },
48
+ enumerable: false,
49
+ configurable: true
50
+ });
51
+ return MsgPacker;
52
+ }());
53
+ module.exports = MsgPacker;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var decoder = new TextDecoder('utf-8');
3
+ function unpackInt(pSrc) {
4
+ var result = 0;
5
+ var len = 1;
6
+ var iter = pSrc[Symbol.iterator]();
7
+ var src = iter.next();
8
+ // if (src.done)
9
+ // console.warn("Unexpected end", src)
10
+ src = src.value;
11
+ var sign = ((src >> 6) & 1);
12
+ result |= (src & 63);
13
+ for (var i = 0; i < 4; i++) {
14
+ if ((src & 128) == 0)
15
+ break;
16
+ src = iter.next();
17
+ // console.log(src & 0b1000_0000)
18
+ // if (src.done)
19
+ // console.warn("Unexpected end", src);
20
+ src = src.value;
21
+ len += 1;
22
+ if (i == 3 && (src & 240) != 0)
23
+ console.warn("NonZeroIntPadding");
24
+ result |= ((src & 127)) << (6 + 7 * i);
25
+ }
26
+ if (len > 1 && src == 0) {
27
+ console.warn("OverlongIntEncoding");
28
+ }
29
+ result ^= -sign;
30
+ return { result: result, remaining: Array.from(iter) };
31
+ }
32
+ function unpackString(pSrc) {
33
+ var result = pSrc.slice(0, pSrc.indexOf(0));
34
+ pSrc = pSrc.slice(pSrc.indexOf(0), pSrc.length);
35
+ return { result: decoder.decode(new Uint8Array(result)), remaining: pSrc };
36
+ }
37
+ module.exports = { unpackInt: unpackInt, unpackString: unpackString };
package/lib/client.js ADDED
@@ -0,0 +1,511 @@
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 (b.hasOwnProperty(p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ extendStatics(d, b);
11
+ function __() { this.constructor = d; }
12
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
13
+ };
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
52
+ return (mod && mod.__esModule) ? mod : { "default": mod };
53
+ };
54
+ var crypto_1 = require("crypto");
55
+ var dgram_1 = __importDefault(require("dgram"));
56
+ var stream_1 = require("stream");
57
+ var MsgUnpacker_1 = __importDefault(require("./MsgUnpacker"));
58
+ var MsgPacker_1 = __importDefault(require("./MsgPacker"));
59
+ var snapshot_1 = require("./snapshot");
60
+ var huffman_1 = __importDefault(require("./huffman"));
61
+ var huff = new huffman_1.default();
62
+ var SnapUnpacker = new snapshot_1.Snapshot();
63
+ var NETMSGTYPE;
64
+ (function (NETMSGTYPE) {
65
+ NETMSGTYPE[NETMSGTYPE["EX"] = 0] = "EX";
66
+ NETMSGTYPE[NETMSGTYPE["SV_MOTD"] = 1] = "SV_MOTD";
67
+ NETMSGTYPE[NETMSGTYPE["SV_BROADCAST"] = 2] = "SV_BROADCAST";
68
+ NETMSGTYPE[NETMSGTYPE["SV_CHAT"] = 3] = "SV_CHAT";
69
+ NETMSGTYPE[NETMSGTYPE["SV_KILLMSG"] = 4] = "SV_KILLMSG";
70
+ NETMSGTYPE[NETMSGTYPE["SV_SOUNDGLOBAL"] = 5] = "SV_SOUNDGLOBAL";
71
+ NETMSGTYPE[NETMSGTYPE["SV_TUNEPARAMS"] = 6] = "SV_TUNEPARAMS";
72
+ NETMSGTYPE[NETMSGTYPE["SV_EXTRAPROJECTILE"] = 7] = "SV_EXTRAPROJECTILE";
73
+ NETMSGTYPE[NETMSGTYPE["SV_READYTOENTER"] = 8] = "SV_READYTOENTER";
74
+ NETMSGTYPE[NETMSGTYPE["SV_WEAPONPICKUP"] = 9] = "SV_WEAPONPICKUP";
75
+ NETMSGTYPE[NETMSGTYPE["SV_EMOTICON"] = 10] = "SV_EMOTICON";
76
+ NETMSGTYPE[NETMSGTYPE["SV_VOTECLEAROPTIONS"] = 11] = "SV_VOTECLEAROPTIONS";
77
+ NETMSGTYPE[NETMSGTYPE["SV_VOTEOPTIONLISTADD"] = 12] = "SV_VOTEOPTIONLISTADD";
78
+ NETMSGTYPE[NETMSGTYPE["SV_VOTEOPTIONADD"] = 13] = "SV_VOTEOPTIONADD";
79
+ NETMSGTYPE[NETMSGTYPE["SV_VOTEOPTIONREMOVE"] = 14] = "SV_VOTEOPTIONREMOVE";
80
+ NETMSGTYPE[NETMSGTYPE["SV_VOTESET"] = 15] = "SV_VOTESET";
81
+ NETMSGTYPE[NETMSGTYPE["SV_VOTESTATUS"] = 16] = "SV_VOTESTATUS";
82
+ NETMSGTYPE[NETMSGTYPE["CL_SAY"] = 17] = "CL_SAY";
83
+ NETMSGTYPE[NETMSGTYPE["CL_SETTEAM"] = 18] = "CL_SETTEAM";
84
+ NETMSGTYPE[NETMSGTYPE["CL_SETSPECTATORMODE"] = 19] = "CL_SETSPECTATORMODE";
85
+ NETMSGTYPE[NETMSGTYPE["CL_STARTINFO"] = 20] = "CL_STARTINFO";
86
+ NETMSGTYPE[NETMSGTYPE["CL_CHANGEINFO"] = 21] = "CL_CHANGEINFO";
87
+ NETMSGTYPE[NETMSGTYPE["CL_KILL"] = 22] = "CL_KILL";
88
+ NETMSGTYPE[NETMSGTYPE["CL_EMOTICON"] = 23] = "CL_EMOTICON";
89
+ NETMSGTYPE[NETMSGTYPE["CL_VOTE"] = 24] = "CL_VOTE";
90
+ NETMSGTYPE[NETMSGTYPE["CL_CALLVOTE"] = 25] = "CL_CALLVOTE";
91
+ NETMSGTYPE[NETMSGTYPE["CL_ISDDNETLEGACY"] = 26] = "CL_ISDDNETLEGACY";
92
+ NETMSGTYPE[NETMSGTYPE["SV_DDRACETIMELEGACY"] = 27] = "SV_DDRACETIMELEGACY";
93
+ NETMSGTYPE[NETMSGTYPE["SV_RECORDLEGACY"] = 28] = "SV_RECORDLEGACY";
94
+ NETMSGTYPE[NETMSGTYPE["UNUSED"] = 29] = "UNUSED";
95
+ NETMSGTYPE[NETMSGTYPE["SV_TEAMSSTATELEGACY"] = 30] = "SV_TEAMSSTATELEGACY";
96
+ NETMSGTYPE[NETMSGTYPE["CL_SHOWOTHERSLEGACY"] = 31] = "CL_SHOWOTHERSLEGACY";
97
+ NETMSGTYPE[NETMSGTYPE["NUM"] = 32] = "NUM";
98
+ })(NETMSGTYPE || (NETMSGTYPE = {}));
99
+ var items;
100
+ (function (items) {
101
+ items[items["OBJ_EX"] = 0] = "OBJ_EX";
102
+ items[items["OBJ_PLAYER_INPUT"] = 1] = "OBJ_PLAYER_INPUT";
103
+ items[items["OBJ_PROJECTILE"] = 2] = "OBJ_PROJECTILE";
104
+ items[items["OBJ_LASER"] = 3] = "OBJ_LASER";
105
+ items[items["OBJ_PICKUP"] = 4] = "OBJ_PICKUP";
106
+ items[items["OBJ_FLAG"] = 5] = "OBJ_FLAG";
107
+ items[items["OBJ_GAME_INFO"] = 6] = "OBJ_GAME_INFO";
108
+ items[items["OBJ_GAME_DATA"] = 7] = "OBJ_GAME_DATA";
109
+ items[items["OBJ_CHARACTER_CORE"] = 8] = "OBJ_CHARACTER_CORE";
110
+ items[items["OBJ_CHARACTER"] = 9] = "OBJ_CHARACTER";
111
+ items[items["OBJ_PLAYER_INFO"] = 10] = "OBJ_PLAYER_INFO";
112
+ items[items["OBJ_CLIENT_INFO"] = 11] = "OBJ_CLIENT_INFO";
113
+ items[items["OBJ_SPECTATOR_INFO"] = 12] = "OBJ_SPECTATOR_INFO";
114
+ items[items["EVENT_COMMON"] = 13] = "EVENT_COMMON";
115
+ items[items["EVENT_EXPLOSION"] = 14] = "EVENT_EXPLOSION";
116
+ items[items["EVENT_SPAWN"] = 15] = "EVENT_SPAWN";
117
+ items[items["EVENT_HAMMERHIT"] = 16] = "EVENT_HAMMERHIT";
118
+ items[items["EVENT_DEATH"] = 17] = "EVENT_DEATH";
119
+ items[items["EVENT_SOUND_GLOBAL"] = 18] = "EVENT_SOUND_GLOBAL";
120
+ items[items["EVENT_SOUND_WORLD"] = 19] = "EVENT_SOUND_WORLD";
121
+ items[items["EVENT_DAMAGE_INDICATOR"] = 20] = "EVENT_DAMAGE_INDICATOR";
122
+ })(items || (items = {}));
123
+ function toHexStream(buff) {
124
+ return buff.toJSON().data.map(function (a) { return ('0' + (a & 0xff).toString(16)).slice(-2); }).join("");
125
+ }
126
+ var messageTypes = [
127
+ ["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"],
128
+ ["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"]
129
+ ];
130
+ var messageUUIDs = {
131
+ "WHAT_IS": Buffer.from([0x24, 0x5e, 0x50, 0x97, 0x9f, 0xe0, 0x39, 0xd6, 0xbf, 0x7d, 0x9a, 0x29, 0xe1, 0x69, 0x1e, 0x4c]),
132
+ "IT_IS": Buffer.from([0x69, 0x54, 0x84, 0x7e, 0x2e, 0x87, 0x36, 0x03, 0xb5, 0x62, 0x36, 0xda, 0x29, 0xed, 0x1a, 0xca]),
133
+ "I_DONT_KNOW": Buffer.from([0x41, 0x69, 0x11, 0xb5, 0x79, 0x73, 0x33, 0xbf, 0x8d, 0x52, 0x7b, 0xf0, 0x1e, 0x51, 0x9c, 0xf0]),
134
+ "RCON_TYPE": Buffer.from([0x12, 0x81, 0x0e, 0x1f, 0xa1, 0xdb, 0x33, 0x78, 0xb4, 0xfb, 0x16, 0x4e, 0xd6, 0x50, 0x59, 0x26]),
135
+ "MAP_DETAILS": Buffer.from([0xf9, 0x11, 0x7b, 0x3c, 0x80, 0x39, 0x34, 0x16, 0x9f, 0xc0, 0xae, 0xf2, 0xbc, 0xb7, 0x5c, 0x03]),
136
+ "CLIENT_VERSION": Buffer.from([0x8c, 0x00, 0x13, 0x04, 0x84, 0x61, 0x3e, 0x47, 0x87, 0x87, 0xf6, 0x72, 0xb3, 0x83, 0x5b, 0xd4]),
137
+ "CAPABILITIES": Buffer.from([0xf6, 0x21, 0xa5, 0xa1, 0xf5, 0x85, 0x37, 0x75, 0x8e, 0x73, 0x41, 0xbe, 0xee, 0x79, 0xf2, 0xb2]),
138
+ };
139
+ function arrStartsWith(arr, arrStart, start) {
140
+ if (start === void 0) { start = 0; }
141
+ arr.splice(0, start);
142
+ for (var i = 0; i < arrStart.length; i++) {
143
+ if (arr[i] == arrStart[i])
144
+ continue;
145
+ else
146
+ return false;
147
+ }
148
+ return true;
149
+ }
150
+ var Client = /** @class */ (function (_super) {
151
+ __extends(Client, _super);
152
+ function Client(ip, port, nickname) {
153
+ var _this = _super.call(this) || this;
154
+ _this.host = ip;
155
+ _this.port = port;
156
+ _this.name = nickname;
157
+ _this.snaps = [];
158
+ _this.client_infos = [];
159
+ _this.player_infos = [];
160
+ _this.State = 0; // 0 = offline; 1 = STATE_CONNECTING = 1, STATE_LOADING = 2, STATE_ONLINE = 3
161
+ _this.ack = 0; // ack of messages the client has received
162
+ _this.clientAck = 0; // ack of messages the client has sent
163
+ _this.receivedSnaps = 0; /* wait for 2 snaps before seeing self as connected */
164
+ _this.lastMsg = "";
165
+ _this._port = Math.floor(Math.random() * 65535);
166
+ _this.socket = dgram_1.default.createSocket("udp4");
167
+ _this.socket.bind();
168
+ _this.TKEN = Buffer.from([255, 255, 255, 255]);
169
+ _this.time = new Date().getTime() + 2000; // time (used for keepalives, start to send keepalives after 2 seconds)
170
+ _this.State = 0;
171
+ return _this;
172
+ }
173
+ 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);
211
+ }
212
+ return [2 /*return*/, unpacked];
213
+ });
214
+ });
215
+ };
216
+ Client.prototype.SendControlMsg = function (msg, ExtraMsg) {
217
+ var _this = this;
218
+ if (ExtraMsg === void 0) { ExtraMsg = ""; }
219
+ return new Promise(function (resolve, reject) {
220
+ if (_this.socket) {
221
+ var latestBuf = Buffer.from([0x10 + (((16 << 4) & 0xf0) | ((_this.ack >> 8) & 0xf)), _this.ack & 0xff, 0x00, msg]);
222
+ latestBuf = Buffer.concat([latestBuf, Buffer.from(ExtraMsg), _this.TKEN]); // move header (latestBuf), optional extraMsg & TKEN into 1 buffer
223
+ _this.socket.send(latestBuf, 0, latestBuf.length, _this.port, _this.host, function (err, bytes) {
224
+ resolve(bytes);
225
+ });
226
+ }
227
+ setTimeout(function () { resolve("failed, rip"); }, 2000);
228
+ /* after 2 seconds it was probably not able to send,
229
+ so when sending a quit message the user doesnt
230
+ stay stuck not being able to ctrl + c
231
+ */
232
+ });
233
+ };
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) {
252
+ var _this = this;
253
+ if (this.State == -1)
254
+ throw new Error("Client is not connected");
255
+ if (!this.socket)
256
+ return;
257
+ var header = [];
258
+ Msgs.forEach(function (Msg, index) {
259
+ header[index] = new Array(2);
260
+ header[index][0] = ((Flags & 3) << 6) | ((Msg.size >> 4) & 0x3f);
261
+ header[index][1] = (Msg.size & 0xf);
262
+ if (Flags & 1) {
263
+ _this.clientAck = (_this.clientAck + 1) % (1 << 10);
264
+ header[index][1] |= (_this.clientAck >> 2) & 0xf0;
265
+ header[index][2] = _this.clientAck & 0xff;
266
+ }
267
+ });
268
+ var packetHeader = Buffer.from([0x0 + (((16 << 4) & 0xf0) | ((this.ack >> 8) & 0xf)), this.ack & 0xff, Msgs.length]);
269
+ var chunks = Buffer.from([]);
270
+ Msgs.forEach(function (Msg, index) {
271
+ chunks = Buffer.concat([chunks, Buffer.from(header[index]), Msg.buffer]);
272
+ });
273
+ var packet = Buffer.concat([(packetHeader), chunks, this.TKEN]);
274
+ this.socket.send(packet, 0, packet.length, this.port, this.host);
275
+ };
276
+ Client.prototype.connect = function () {
277
+ var _this = this;
278
+ this.SendControlMsg(1, "TKEN");
279
+ var connectInterval = setInterval(function () {
280
+ if (_this.State == 0)
281
+ _this.SendControlMsg(1, "TKEN");
282
+ else
283
+ clearInterval(connectInterval);
284
+ }, 500);
285
+ this.time = new Date().getTime() + 2000; // start sending keepalives after 2s
286
+ 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.default.unpackInt(a.raw.toJSON().data).result;
310
+ var remaining = MsgUnpacker_1.default.unpackInt(a.raw.toJSON().data).remaining;
311
+ unpacked.client_id = MsgUnpacker_1.default.unpackInt(remaining).result;
312
+ remaining = MsgUnpacker_1.default.unpackInt(remaining).remaining;
313
+ unpacked.message = MsgUnpacker_1.default.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
+ unpacked.killer_id = MsgUnpacker_1.default.unpackInt(a.raw.toJSON().data).result;
327
+ var remaining = MsgUnpacker_1.default.unpackInt(a.raw.toJSON().data).remaining;
328
+ unpacked.victim_id = MsgUnpacker_1.default.unpackInt(remaining).result;
329
+ remaining = MsgUnpacker_1.default.unpackInt(remaining).remaining;
330
+ unpacked.weapon = MsgUnpacker_1.default.unpackInt(remaining).result;
331
+ remaining = MsgUnpacker_1.default.unpackInt(remaining).remaining;
332
+ unpacked.special_mode = MsgUnpacker_1.default.unpackInt(remaining).result;
333
+ if (unpacked.victim_id != -1)
334
+ unpacked.victim = { ClientInfo: _this.client_infos[unpacked.victim_id], PlayerInfo: _this.player_infos[unpacked.victim_id] };
335
+ if (unpacked.killer_id != -1)
336
+ unpacked.killer = { ClientInfo: _this.client_infos[unpacked.killer_id], PlayerInfo: _this.player_infos[unpacked.killer_id] };
337
+ // console.log(unpacked)
338
+ _this.emit("kill", unpacked);
339
+ }
340
+ });
341
+ }
342
+ if (a.toJSON().data[0] == 0x10) {
343
+ if (a.toString().includes("TKEN") || arrStartsWith(a.toJSON().data, [0x10, 0x0, 0x0, 0x0])) {
344
+ clearInterval(connectInterval);
345
+ this.TKEN = Buffer.from(a.toJSON().data.slice(a.toJSON().data.length - 4, a.toJSON().data.length));
346
+ this.SendControlMsg(3);
347
+ this.State = 2; // loading state
348
+ info = new MsgPacker_1.default(1, true);
349
+ info.AddString("0.6 626fce9a778df4d4");
350
+ info.AddString(""); // password
351
+ client_version = new MsgPacker_1.default(0, true);
352
+ client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
353
+ randomUuid = new Uint8Array(16);
354
+ crypto_1.randomBytes(16).copy(randomUuid);
355
+ client_version.AddBuffer(Buffer.from(randomUuid));
356
+ client_version.AddInt(15091);
357
+ client_version.AddString("DDNet 15.9.1");
358
+ this.SendMsgExWithChunks([client_version, info], 1);
359
+ }
360
+ else if (a.toJSON().data[3] == 0x4) {
361
+ // disconnected
362
+ this.State = 0;
363
+ reason = (MsgUnpacker_1.default.unpackString(a.toJSON().data.slice(4)).result);
364
+ this.State = -1;
365
+ this.emit("disconnect", reason);
366
+ }
367
+ }
368
+ if (unpacked.chunks[0] && chunkMessages.includes("SV_READY_TO_ENTER")) {
369
+ Msg = new MsgPacker_1.default(15, true);
370
+ this.SendMsgEx(Msg, 1);
371
+ }
372
+ else if ((unpacked.chunks[0] && chunkMessages.includes("CAPABILITIES") || unpacked.chunks[0] && chunkMessages.includes("MAP_CHANGE"))) {
373
+ Msg = new MsgPacker_1.default(14, true);
374
+ this.SendMsgEx(Msg, 1);
375
+ }
376
+ else if ((unpacked.chunks[0] && chunkMessages.includes("CON_READY") || unpacked.chunks[0] && chunkMessages.includes("SV_MOTD"))) {
377
+ info = new MsgPacker_1.default(20, false);
378
+ info.AddString(this.name); /* name */
379
+ info.AddString(""); /* clan */
380
+ info.AddInt(-1); /* country */
381
+ info.AddString("greyfox"); /* skin */
382
+ info.AddInt(1); /* use custom color */
383
+ info.AddInt(10346103); /* color body */
384
+ info.AddInt(65535); /* color feet */
385
+ this.SendMsgEx(info, 1);
386
+ }
387
+ else if (unpacked.chunks[0] && chunkMessages.includes("SV_READY_TO_ENTER")) {
388
+ if (this.State != 3) {
389
+ this.emit('connected');
390
+ }
391
+ this.State = 3;
392
+ }
393
+ else if (unpacked.chunks[0] && chunkMessages.includes("PING")) {
394
+ info = new MsgPacker_1.default(23, true);
395
+ this.SendMsgEx(info, 1);
396
+ }
397
+ if (chunkMessages.includes("SNAP") || chunkMessages.includes("SNAP_EMPTY") || chunkMessages.includes("SNAP_SINGLE")) {
398
+ this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
399
+ if (this.receivedSnaps >= 2) {
400
+ if (this.State != 3)
401
+ this.emit('connected');
402
+ this.State = 3;
403
+ }
404
+ chunks = unpacked.chunks.filter(function (a) { return a.msg == "SNAP" || a.msg == "SNAP_SINGLE" || a.msg == "SNAP_EMPTY"; });
405
+ if (chunks.length > 0) {
406
+ part_1 = 0;
407
+ num_parts_1 = 1;
408
+ chunks.forEach(function (chunk) {
409
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
410
+ var AckGameTick = (MsgUnpacker_1.default.unpackInt(chunk.raw.toJSON().data).result);
411
+ chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_a = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _a === void 0 ? void 0 : _a.toJSON().data).remaining);
412
+ var DeltaTick = MsgUnpacker_1.default.unpackInt((_b = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _b === void 0 ? void 0 : _b.toJSON().data).result;
413
+ if (chunk.msg == "SNAP") {
414
+ chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_c = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _c === void 0 ? void 0 : _c.toJSON().data).remaining); // delta tick
415
+ num_parts_1 = (MsgUnpacker_1.default.unpackInt((_d = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _d === void 0 ? void 0 : _d.toJSON().data).result);
416
+ chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_e = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _e === void 0 ? void 0 : _e.toJSON().data).remaining); // num parts
417
+ part_1 = (MsgUnpacker_1.default.unpackInt((_f = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _f === void 0 ? void 0 : _f.toJSON().data).result);
418
+ }
419
+ chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_g = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _g === void 0 ? void 0 : _g.toJSON().data).remaining); // part
420
+ if (chunk.msg != "SNAP_EMPTY")
421
+ chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_h = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _h === void 0 ? void 0 : _h.toJSON().data).remaining); // crc
422
+ chunk.raw = Buffer.from(MsgUnpacker_1.default.unpackInt((_j = chunk === null || chunk === void 0 ? void 0 : chunk.raw) === null || _j === void 0 ? void 0 : _j.toJSON().data).remaining); // crc
423
+ if (part_1 == 0 || _this.snaps.length > 30) {
424
+ _this.snaps = [];
425
+ }
426
+ _this.snaps.push(chunk.raw);
427
+ if ((num_parts_1 - 1) == part_1 && _this.snaps.length == num_parts_1) {
428
+ var mergedSnaps = Buffer.concat(_this.snaps);
429
+ var snapUnpacked = SnapUnpacker.unpackSnapshot(mergedSnaps.toJSON().data, 1);
430
+ snapUnpacked.items.forEach(function (a, i) {
431
+ if (a.type_id == items.OBJ_CLIENT_INFO) {
432
+ _this.client_infos[a.id] = a.parsed;
433
+ // console.log(a.parsed, i)
434
+ // console.log(this.client_infos[a.id])
435
+ }
436
+ else if (a.type_id == items.OBJ_PLAYER_INFO) {
437
+ _this.player_infos[i] = a.parsed;
438
+ }
439
+ else if (a.type_id == items.OBJ_EX || a.type_id > 0x4000) {
440
+ if (a.data.length == 5 && (a.parsed.freeze_end > 0 || a.parsed.freeze_end == -1)) {
441
+ // var packer = new MsgPacker(22, false)
442
+ // this.SendMsgEx(packer, 1)
443
+ }
444
+ }
445
+ });
446
+ }
447
+ });
448
+ }
449
+ }
450
+ if (new Date().getTime() - this.time >= 1000) {
451
+ this.time = new Date().getTime();
452
+ this.SendControlMsg(0);
453
+ }
454
+ return [2 /*return*/];
455
+ }
456
+ });
457
+ }); });
458
+ };
459
+ Client.prototype.Disconnect = function () {
460
+ var _this = this;
461
+ return new Promise(function (resolve) {
462
+ _this.SendControlMsg(4).then(function () {
463
+ resolve(true);
464
+ if (_this.socket)
465
+ _this.socket.close();
466
+ _this.socket = undefined;
467
+ _this.State = -1;
468
+ });
469
+ });
470
+ };
471
+ Client.prototype.Say = function (message, team) {
472
+ if (team === void 0) { team = false; }
473
+ var packer = new MsgPacker_1.default(NETMSGTYPE.CL_SAY, false);
474
+ packer.AddInt(team ? 1 : 0); // team
475
+ packer.AddString(message);
476
+ this.SendMsgEx(packer, 1);
477
+ };
478
+ Client.prototype.Vote = function (vote) {
479
+ var packer = new MsgPacker_1.default(NETMSGTYPE.CL_VOTE, false);
480
+ packer.AddInt(vote ? 1 : 0);
481
+ this.SendMsgEx(packer, 1);
482
+ };
483
+ Client.prototype.ChangePlayerInfo = function (playerInfo) {
484
+ var packer = new MsgPacker_1.default(NETMSGTYPE.CL_CHANGEINFO, false);
485
+ packer.AddString(playerInfo.name); //m_pName);
486
+ packer.AddString(playerInfo.clan); //m_pClan);
487
+ packer.AddInt(playerInfo.country); //m_Country);
488
+ packer.AddString(playerInfo.skin); //m_pSkin);
489
+ packer.AddInt(playerInfo.use_custom_color ? 1 : 0); //m_UseCustomColor);
490
+ packer.AddInt(playerInfo.color_body); //m_ColorBody);
491
+ packer.AddInt(playerInfo.color_feet); //m_ColorFeet);
492
+ this.SendMsgEx(packer, 1);
493
+ };
494
+ Client.prototype.Kill = function () {
495
+ var packer = new MsgPacker_1.default(NETMSGTYPE.CL_KILL, false);
496
+ this.SendMsgEx(packer, 1);
497
+ };
498
+ Client.prototype.ChangeTeam = function (team) {
499
+ var packer = new MsgPacker_1.default(NETMSGTYPE.CL_SETTEAM, false);
500
+ packer.AddInt(team);
501
+ this.SendMsgEx(packer, 1);
502
+ };
503
+ Client.prototype.Emote = function (emote) {
504
+ var packer = new MsgPacker_1.default(NETMSGTYPE.CL_EMOTICON, false);
505
+ packer.AddInt(emote);
506
+ this.SendMsgEx(packer, 1);
507
+ };
508
+ return Client;
509
+ }(stream_1.EventEmitter));
510
+ module.exports = Client;
511
+ // module.exports = Client;
package/lib/huffman.js ADDED
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+ var FREQ_TABLE = [
3
+ 1 << 30, 4545, 2657, 431, 1950, 919, 444, 482, 2244, 617, 838, 542, 715, 1814, 304, 240, 754, 212, 647, 186,
4
+ 283, 131, 146, 166, 543, 164, 167, 136, 179, 859, 363, 113, 157, 154, 204, 108, 137, 180, 202, 176,
5
+ 872, 404, 168, 134, 151, 111, 113, 109, 120, 126, 129, 100, 41, 20, 16, 22, 18, 18, 17, 19,
6
+ 16, 37, 13, 21, 362, 166, 99, 78, 95, 88, 81, 70, 83, 284, 91, 187, 77, 68, 52, 68,
7
+ 59, 66, 61, 638, 71, 157, 50, 46, 69, 43, 11, 24, 13, 19, 10, 12, 12, 20, 14, 9,
8
+ 20, 20, 10, 10, 15, 15, 12, 12, 7, 19, 15, 14, 13, 18, 35, 19, 17, 14, 8, 5,
9
+ 15, 17, 9, 15, 14, 18, 8, 10, 2173, 134, 157, 68, 188, 60, 170, 60, 194, 62, 175, 71,
10
+ 148, 67, 167, 78, 211, 67, 156, 69, 1674, 90, 174, 53, 147, 89, 181, 51, 174, 63, 163, 80,
11
+ 167, 94, 128, 122, 223, 153, 218, 77, 200, 110, 190, 73, 174, 69, 145, 66, 277, 143, 141, 60,
12
+ 136, 53, 180, 57, 142, 57, 158, 61, 166, 112, 152, 92, 26, 22, 21, 28, 20, 26, 30, 21,
13
+ 32, 27, 20, 17, 23, 21, 30, 22, 22, 21, 27, 25, 17, 27, 23, 18, 39, 26, 15, 21,
14
+ 12, 18, 18, 27, 20, 18, 15, 19, 11, 17, 33, 12, 18, 15, 19, 18, 16, 26, 17, 18,
15
+ 9, 10, 25, 22, 22, 17, 20, 16, 6, 16, 15, 20, 14, 18, 24, 335, 1517
16
+ ], HUFFMAN_EOF_SYMBOL = 256, HUFFMAN_MAX_SYMBOLS = HUFFMAN_EOF_SYMBOL + 1, HUFFMAN_MAX_NODES = HUFFMAN_MAX_SYMBOLS * 2 - 1, HUFFMAN_LUTBITS = 10, HUFFMAN_LUTSIZE = 1 << HUFFMAN_LUTBITS, HUFFMAN_LUTMASK = HUFFMAN_LUTSIZE - 1;
17
+ var Huffman = /** @class */ (function () {
18
+ function Huffman(frequencies) {
19
+ if (frequencies === void 0) { frequencies = FREQ_TABLE; }
20
+ this.nodes = new Array(HUFFMAN_MAX_NODES);
21
+ for (var i = 0; i < HUFFMAN_MAX_NODES; i++) {
22
+ this.nodes[i] = {};
23
+ }
24
+ this.decode_lut = new Array(HUFFMAN_LUTSIZE);
25
+ this.num_nodes = 0;
26
+ this.start_node_index = 0;
27
+ this.construct_tree(frequencies);
28
+ for (var i = 0; i < HUFFMAN_LUTSIZE; i++) {
29
+ var bits = i;
30
+ var broke = false;
31
+ var index = this.start_node_index;
32
+ for (var x = 0; x < HUFFMAN_LUTBITS; x++) {
33
+ if (bits & 1)
34
+ index = this.nodes[index].right;
35
+ else
36
+ index = this.nodes[index].left;
37
+ bits >>= 1;
38
+ if (this.nodes[index].numbits) {
39
+ this.decode_lut[i] = index;
40
+ broke = true;
41
+ break;
42
+ }
43
+ }
44
+ if (!broke) {
45
+ this.decode_lut[i] = index;
46
+ }
47
+ }
48
+ }
49
+ Huffman.prototype.set_bits_r = function (node_index, bits, depth) {
50
+ if (this.nodes[node_index].right != 0xffff)
51
+ this.set_bits_r(this.nodes[node_index].right, bits | (1 << depth), depth + 1);
52
+ if (this.nodes[node_index].left != 0xffff)
53
+ this.set_bits_r(this.nodes[node_index].left, bits, depth + 1);
54
+ if (this.nodes[node_index].numbits) {
55
+ this.nodes[node_index].bits = bits;
56
+ this.nodes[node_index].numbits = depth;
57
+ }
58
+ };
59
+ Huffman.prototype.bubble_sort = function (index_list, node_list, size) {
60
+ var changed = true;
61
+ while (changed) {
62
+ changed = false;
63
+ for (var i = 0; i < size - 1; i++) {
64
+ if (node_list[index_list[i]].frequency < node_list[index_list[i + 1]].frequency) {
65
+ var temp = index_list[i];
66
+ index_list[i] = index_list[i + 1];
67
+ index_list[i + 1] = temp;
68
+ changed = true;
69
+ }
70
+ }
71
+ size--;
72
+ }
73
+ return index_list;
74
+ };
75
+ Huffman.prototype.construct_tree = function (frequencies) {
76
+ if (frequencies === void 0) { frequencies = FREQ_TABLE; }
77
+ var nodes_left_storage = new Array(HUFFMAN_MAX_SYMBOLS);
78
+ for (var i = 0; i < HUFFMAN_MAX_SYMBOLS; i++) {
79
+ nodes_left_storage[i] = {};
80
+ }
81
+ var nodes_left = new Array(HUFFMAN_MAX_SYMBOLS);
82
+ var num_nodes_left = HUFFMAN_MAX_SYMBOLS;
83
+ for (var i = 0; i < HUFFMAN_MAX_SYMBOLS; i++) {
84
+ this.nodes[i].numbits = 0xFFFFFFFF;
85
+ this.nodes[i].symbol = i;
86
+ this.nodes[i].left = 0xFFFF;
87
+ this.nodes[i].right = 0xFFFF;
88
+ if (i == HUFFMAN_EOF_SYMBOL) {
89
+ nodes_left_storage[i].frequency = 1;
90
+ }
91
+ else
92
+ nodes_left_storage[i].frequency = frequencies[i];
93
+ nodes_left_storage[i].node_id = i;
94
+ nodes_left[i] = i;
95
+ }
96
+ this.num_nodes = HUFFMAN_MAX_SYMBOLS;
97
+ while (num_nodes_left > 1) {
98
+ nodes_left = this.bubble_sort(nodes_left, nodes_left_storage, num_nodes_left);
99
+ this.nodes[this.num_nodes].numbits = 0;
100
+ this.nodes[this.num_nodes].left = nodes_left_storage[nodes_left[num_nodes_left - 1]].node_id;
101
+ this.nodes[this.num_nodes].right = nodes_left_storage[nodes_left[num_nodes_left - 2]].node_id;
102
+ nodes_left_storage[nodes_left[num_nodes_left - 2]].node_id = this.num_nodes;
103
+ nodes_left_storage[nodes_left[num_nodes_left - 2]].frequency = nodes_left_storage[nodes_left[num_nodes_left - 1]].frequency
104
+ + nodes_left_storage[nodes_left[num_nodes_left - 2]].frequency;
105
+ this.num_nodes++;
106
+ num_nodes_left--;
107
+ }
108
+ this.start_node_index = this.num_nodes - 1;
109
+ this.set_bits_r(this.start_node_index, 0, 0);
110
+ };
111
+ Huffman.prototype.compress = function (inp_buffer, start_index, size) {
112
+ if (start_index === void 0) { start_index = 0; }
113
+ if (size === void 0) { size = 0; }
114
+ var output = [];
115
+ var bits = 0;
116
+ var bitcount = 0;
117
+ if (size == 0)
118
+ size = inp_buffer.byteLength;
119
+ inp_buffer = inp_buffer.slice(start_index, start_index + size);
120
+ for (var i = 0; i < size; i++) {
121
+ var x = inp_buffer[i];
122
+ bits |= this.nodes[x].bits << bitcount;
123
+ bitcount += this.nodes[x].numbits;
124
+ while (bitcount >= 8) {
125
+ output.push(bits & 0xff);
126
+ bits >>= 8;
127
+ bitcount -= 8;
128
+ }
129
+ }
130
+ bits |= this.nodes[HUFFMAN_EOF_SYMBOL].bits << bitcount;
131
+ bitcount += this.nodes[HUFFMAN_EOF_SYMBOL].numbits;
132
+ while (bitcount >= 8) {
133
+ output.push(bits & 0xff);
134
+ bits >>= 8;
135
+ bitcount -= 8;
136
+ }
137
+ output.push(bits);
138
+ return Buffer.from(output);
139
+ };
140
+ Huffman.prototype.decompress = function (inp_buffer, size) {
141
+ if (size === void 0) { size = 0; }
142
+ var bits = 0;
143
+ var bitcount = 0;
144
+ var eof = this.nodes[HUFFMAN_EOF_SYMBOL];
145
+ var output = [];
146
+ if (size == 0)
147
+ size = inp_buffer.byteLength;
148
+ inp_buffer = inp_buffer.slice(0, size);
149
+ var src_index = 0;
150
+ while (true) {
151
+ var node_i = -1;
152
+ if (bitcount >= HUFFMAN_LUTBITS)
153
+ node_i = this.decode_lut[bits & HUFFMAN_LUTMASK];
154
+ while (bitcount < 24 && src_index != size) {
155
+ bits |= inp_buffer[src_index] << bitcount;
156
+ bitcount += 8;
157
+ src_index++;
158
+ }
159
+ if (node_i == -1)
160
+ node_i = this.decode_lut[bits & HUFFMAN_LUTMASK];
161
+ if (this.nodes[node_i].numbits) {
162
+ bits >>= this.nodes[node_i].numbits;
163
+ bitcount -= this.nodes[node_i].numbits;
164
+ }
165
+ else {
166
+ bits >>= HUFFMAN_LUTBITS;
167
+ bitcount -= HUFFMAN_LUTBITS;
168
+ while (true) {
169
+ if (bits & 1) {
170
+ node_i = this.nodes[node_i].right;
171
+ }
172
+ else
173
+ node_i = this.nodes[node_i].left;
174
+ bitcount -= 1;
175
+ bits >>= 1;
176
+ if (this.nodes[node_i].numbits)
177
+ break;
178
+ if (bitcount == 0)
179
+ throw new Error("No more bits, decoding error");
180
+ }
181
+ }
182
+ if (this.nodes[node_i] == eof)
183
+ break;
184
+ output.push(this.nodes[node_i].symbol);
185
+ }
186
+ return Buffer.from(output);
187
+ };
188
+ return Huffman;
189
+ }());
190
+ module.exports = Huffman;
@@ -0,0 +1,401 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Snapshot = void 0;
4
+ var MsgUnpacker = require('./MsgUnpacker');
5
+ var decoder = new TextDecoder('utf-8');
6
+ var itemAppendix = [
7
+ { "type_id": 0, "size": 0, "name": "obj_ex" },
8
+ { "type_id": 1, "size": 10, "name": "obj_player_input" },
9
+ { "type_id": 2, "size": 6, "name": "obj_projectile" },
10
+ { "type_id": 3, "size": 5, "name": "obj_laser" },
11
+ { "type_id": 4, "size": 4, "name": "obj_pickup" },
12
+ { "type_id": 5, "size": 3, "name": "obj_flag" },
13
+ { "type_id": 6, "size": 8, "name": "obj_game_info" },
14
+ { "type_id": 7, "size": 4, "name": "obj_game_data" },
15
+ { "type_id": 8, "size": 15, "name": "obj_character_core" },
16
+ { "type_id": 9, "size": 22, "name": "obj_character" },
17
+ { "type_id": 10, "size": 5, "name": "obj_player_info" },
18
+ { "type_id": 11, "size": 17, "name": "obj_client_info" },
19
+ { "type_id": 12, "size": 3, "name": "obj_spectator_info" },
20
+ { "type_id": 13, "size": 2, "name": "event_common" },
21
+ { "type_id": 14, "size": 2, "name": "event_explosion" },
22
+ { "type_id": 15, "size": 2, "name": "event_spawn" },
23
+ { "type_id": 16, "size": 2, "name": "event_hammerhit" },
24
+ { "type_id": 17, "size": 3, "name": "event_death" },
25
+ { "type_id": 18, "size": 3, "name": "event_sound_global" },
26
+ { "type_id": 19, "size": 3, "name": "event_sound_world" },
27
+ { "type_id": 20, "size": 3, "name": "event_damage_indicator" }
28
+ ];
29
+ var items;
30
+ (function (items) {
31
+ items[items["OBJ_EX"] = 0] = "OBJ_EX";
32
+ items[items["OBJ_PLAYER_INPUT"] = 1] = "OBJ_PLAYER_INPUT";
33
+ items[items["OBJ_PROJECTILE"] = 2] = "OBJ_PROJECTILE";
34
+ items[items["OBJ_LASER"] = 3] = "OBJ_LASER";
35
+ items[items["OBJ_PICKUP"] = 4] = "OBJ_PICKUP";
36
+ items[items["OBJ_FLAG"] = 5] = "OBJ_FLAG";
37
+ items[items["OBJ_GAME_INFO"] = 6] = "OBJ_GAME_INFO";
38
+ items[items["OBJ_GAME_DATA"] = 7] = "OBJ_GAME_DATA";
39
+ items[items["OBJ_CHARACTER_CORE"] = 8] = "OBJ_CHARACTER_CORE";
40
+ items[items["OBJ_CHARACTER"] = 9] = "OBJ_CHARACTER";
41
+ items[items["OBJ_PLAYER_INFO"] = 10] = "OBJ_PLAYER_INFO";
42
+ items[items["OBJ_CLIENT_INFO"] = 11] = "OBJ_CLIENT_INFO";
43
+ items[items["OBJ_SPECTATOR_INFO"] = 12] = "OBJ_SPECTATOR_INFO";
44
+ items[items["EVENT_COMMON"] = 13] = "EVENT_COMMON";
45
+ items[items["EVENT_EXPLOSION"] = 14] = "EVENT_EXPLOSION";
46
+ items[items["EVENT_SPAWN"] = 15] = "EVENT_SPAWN";
47
+ items[items["EVENT_HAMMERHIT"] = 16] = "EVENT_HAMMERHIT";
48
+ items[items["EVENT_DEATH"] = 17] = "EVENT_DEATH";
49
+ items[items["EVENT_SOUND_GLOBAL"] = 18] = "EVENT_SOUND_GLOBAL";
50
+ items[items["EVENT_SOUND_WORLD"] = 19] = "EVENT_SOUND_WORLD";
51
+ items[items["EVENT_DAMAGE_INDICATOR"] = 20] = "EVENT_DAMAGE_INDICATOR";
52
+ })(items || (items = {}));
53
+ var Snapshot = /** @class */ (function () {
54
+ function Snapshot() {
55
+ }
56
+ Snapshot.prototype.IntsToStr = function (pInts) {
57
+ var pIntz = [];
58
+ var pStr = '';
59
+ for (var _i = 0, pInts_1 = pInts; _i < pInts_1.length; _i++) {
60
+ var x = pInts_1[_i];
61
+ pStr += String.fromCharCode((((x) >> 24) & 0xff) - 128);
62
+ pIntz.push((((x) >> 24) & 0xff) - 128);
63
+ pStr += String.fromCharCode((((x) >> 16) & 0xff) - 128);
64
+ pIntz.push((((x) >> 16) & 0xff) - 128);
65
+ pStr += String.fromCharCode((((x) >> 8) & 0xff) - 128);
66
+ pIntz.push((((x) >> 8) & 0xff) - 128);
67
+ pStr += String.fromCharCode(((x) & 0xff) - 128);
68
+ pIntz.push(((x) & 0xff) - 128);
69
+ }
70
+ pIntz.splice(-1, 1);
71
+ pStr = decoder.decode(new Uint8Array(pIntz));
72
+ pStr = pStr.replace(/\x00|\u0000/g, ""); //.replace(/タ/g, "")
73
+ return pStr;
74
+ };
75
+ Snapshot.prototype.parseItem = function (data, Type) {
76
+ var _item = {};
77
+ switch (Type) {
78
+ case items.OBJ_EX:
79
+ break;
80
+ case items.OBJ_PLAYER_INPUT:
81
+ _item = {
82
+ direction: data[0],
83
+ target_x: data[1],
84
+ target_y: data[2],
85
+ jump: data[3],
86
+ fire: data[4],
87
+ hook: data[5],
88
+ player_flags: data[6],
89
+ wanted_weapon: data[7],
90
+ next_weapon: data[8],
91
+ prev_weapon: data[9],
92
+ };
93
+ break;
94
+ case items.OBJ_PROJECTILE:
95
+ _item = {
96
+ x: data[0],
97
+ y: data[1],
98
+ vel_x: data[2],
99
+ vel_y: data[3],
100
+ type_: data[4],
101
+ start_tick: data[5],
102
+ };
103
+ break;
104
+ case items.OBJ_LASER:
105
+ _item = {
106
+ x: data[0],
107
+ y: data[1],
108
+ from_x: data[2],
109
+ from_y: data[3],
110
+ start_tick: data[4],
111
+ };
112
+ break;
113
+ case items.OBJ_PICKUP:
114
+ _item = {
115
+ x: data[0],
116
+ y: data[1],
117
+ type_: data[2],
118
+ subtype: data[3],
119
+ };
120
+ break;
121
+ case items.OBJ_FLAG:
122
+ _item = {
123
+ x: data[0],
124
+ y: data[1],
125
+ team: data[2],
126
+ };
127
+ break;
128
+ case items.OBJ_GAME_INFO:
129
+ _item = {
130
+ game_flags: data[0],
131
+ game_state_flags: data[1],
132
+ round_start_tick: data[2],
133
+ warmup_timer: data[3],
134
+ score_limit: data[4],
135
+ time_limit: data[5],
136
+ round_num: data[6],
137
+ round_current: data[7],
138
+ };
139
+ break;
140
+ case items.OBJ_GAME_DATA:
141
+ _item = {
142
+ teamscore_red: data[0],
143
+ teamscore_blue: data[1],
144
+ flag_carrier_red: data[2],
145
+ flag_carrier_blue: data[3],
146
+ };
147
+ break;
148
+ case items.OBJ_CHARACTER_CORE:
149
+ _item = {
150
+ tick: data[0],
151
+ x: data[1],
152
+ y: data[2],
153
+ vel_x: data[3],
154
+ vel_y: data[4],
155
+ angle: data[5],
156
+ direction: data[6],
157
+ jumped: data[7],
158
+ hooked_player: data[8],
159
+ hook_state: data[9],
160
+ hook_tick: data[10],
161
+ hook_x: data[11],
162
+ hook_y: data[12],
163
+ hook_dx: data[13],
164
+ hook_dy: data[14],
165
+ };
166
+ break;
167
+ case items.OBJ_CHARACTER:
168
+ _item = {
169
+ character_core: {
170
+ tick: data[0],
171
+ x: data[1],
172
+ y: data[2],
173
+ vel_x: data[3],
174
+ vel_y: data[4],
175
+ angle: data[5],
176
+ direction: data[6],
177
+ jumped: data[7],
178
+ hooked_player: data[8],
179
+ hook_state: data[9],
180
+ hook_tick: data[10],
181
+ hook_x: data[11],
182
+ hook_y: data[12],
183
+ hook_dx: data[13],
184
+ hook_dy: data[14],
185
+ },
186
+ player_flags: data[15],
187
+ health: data[16],
188
+ armor: data[17],
189
+ ammo_count: data[18],
190
+ weapon: data[19],
191
+ emote: data[20],
192
+ attack_tick: data[21],
193
+ };
194
+ break;
195
+ case items.OBJ_PLAYER_INFO:
196
+ _item = {
197
+ local: data[0],
198
+ client_id: data[1],
199
+ team: data[2],
200
+ score: data[3],
201
+ latency: data[4],
202
+ };
203
+ break;
204
+ case items.OBJ_CLIENT_INFO:
205
+ _item = {
206
+ name: this.IntsToStr([data[0], data[1], data[2], data[3]]),
207
+ clan: this.IntsToStr([data[4], data[5], data[6]]),
208
+ country: data[7],
209
+ skin: this.IntsToStr([data[8], data[9], data[10], data[11], data[12], data[13]]),
210
+ use_custom_color: Number(data.slice(14, 15)),
211
+ color_body: Number(data.slice(15, 16)),
212
+ color_feet: Number(data.slice(16, 17)),
213
+ };
214
+ break;
215
+ case items.OBJ_SPECTATOR_INFO:
216
+ _item = {
217
+ spectator_id: data[0],
218
+ x: data[1],
219
+ y: data[2],
220
+ };
221
+ break;
222
+ case items.EVENT_COMMON:
223
+ _item = {
224
+ x: data[0],
225
+ y: data[1],
226
+ };
227
+ break;
228
+ case items.EVENT_EXPLOSION:
229
+ _item = {
230
+ common: {
231
+ x: data[0],
232
+ y: data[1]
233
+ }
234
+ };
235
+ break;
236
+ case items.EVENT_SPAWN:
237
+ _item = {
238
+ common: {
239
+ x: data[0],
240
+ y: data[1]
241
+ }
242
+ };
243
+ break;
244
+ case items.EVENT_HAMMERHIT:
245
+ _item = {
246
+ common: {
247
+ x: data[0],
248
+ y: data[1]
249
+ }
250
+ };
251
+ break;
252
+ case items.EVENT_DEATH:
253
+ _item = {
254
+ client_id: data[0],
255
+ common: {
256
+ x: data[1],
257
+ y: data[2]
258
+ }
259
+ };
260
+ break;
261
+ case items.EVENT_SOUND_GLOBAL:
262
+ _item = {
263
+ common: {
264
+ x: data[0],
265
+ y: data[1]
266
+ },
267
+ sound_id: data[2]
268
+ };
269
+ break;
270
+ case items.EVENT_SOUND_WORLD:
271
+ _item = {
272
+ common: {
273
+ x: data[0],
274
+ y: data[1]
275
+ },
276
+ sound_id: data[2]
277
+ };
278
+ break;
279
+ case items.EVENT_DAMAGE_INDICATOR:
280
+ _item = {
281
+ angle: data[0],
282
+ common: {
283
+ x: data[0],
284
+ y: data[1]
285
+ },
286
+ };
287
+ break;
288
+ }
289
+ return _item;
290
+ };
291
+ Snapshot.prototype.unpackSnapshot = function (snap, lost) {
292
+ // var size = MsgUnpacker.unpackInt(snap).result;
293
+ if (lost === void 0) { lost = 0; }
294
+ snap = MsgUnpacker.unpackInt(snap).remaining;
295
+ /* key = (((type_id) << 16) | (id))
296
+ * key_to_id = ((key) & 0xffff)
297
+ * key_to_type_id = ((key >> 16) & 0xffff)
298
+ * https://github.com/heinrich5991/libtw2/blob/master/snapshot/src/
299
+ * https://github.com/heinrich5991/libtw2/blob/master/doc/snapshot.md
300
+ */
301
+ // snap = MsgUnpacker.unpackInt(snap).remaining;
302
+ // console.log(MsgUnpacker.unpackInt(snap).result, "tick?") // key?
303
+ // snap = MsgUnpacker.unpackInt(snap).remaining;
304
+ for (var i = 0; i < (lost); i++)
305
+ snap = MsgUnpacker.unpackInt(snap).remaining;
306
+ // console.log(MsgUnpacker.unpackInt(snap).result, "?") // key?
307
+ // snap = MsgUnpacker.unpackInt(snap).remaining;
308
+ var client_infos = [];
309
+ var player_infos = [];
310
+ var items = { items: [], /* client_infos: client_infos, player_infos: player_infos,*/ lost: 0 };
311
+ while (snap.length != 0) {
312
+ snap = MsgUnpacker.unpackInt(snap).remaining;
313
+ var type_id = MsgUnpacker.unpackInt(snap).result;
314
+ // console.log(type_id, "type_id");
315
+ snap = MsgUnpacker.unpackInt(snap).remaining;
316
+ var id = MsgUnpacker.unpackInt(snap).result;
317
+ // console.log(id, "id");
318
+ var key = (((type_id) << 16) | (id));
319
+ // console.log(key, "key")
320
+ var _size = 0;
321
+ if (itemAppendix[type_id] && type_id > 0) {
322
+ // console.log("_size is not set")
323
+ // type_id is in itemAppendix -> _size is not set!
324
+ _size = itemAppendix[type_id].size;
325
+ }
326
+ else {
327
+ // console.log("_size is set")
328
+ // _size is set.
329
+ snap = MsgUnpacker.unpackInt(snap).remaining;
330
+ _size = (MsgUnpacker.unpackInt(snap).result);
331
+ }
332
+ // console.log(_size, "size!")
333
+ var data = [];
334
+ for (var i = 0; i < _size; i++) {
335
+ if (snap.length == 0) {
336
+ items.lost++;
337
+ }
338
+ if (snap[0]) {
339
+ snap = MsgUnpacker.unpackInt(snap).remaining;
340
+ data.push(MsgUnpacker.unpackInt(snap).result);
341
+ }
342
+ else
343
+ break;
344
+ }
345
+ if (type_id > 0x4000 || type_id == 0) {
346
+ if (_size == 5 && id == 0) {
347
+ // console.log("DdnetCharacter???")
348
+ var Ddnet_Character = {
349
+ flags: data[0],
350
+ freeze_end: data[1],
351
+ jumps: data[2],
352
+ tele_checkpoint: data[3],
353
+ strong_weak_id: data[4]
354
+ // score: (!players[id] == undefined || typeof players[id].score == 'undefined') ? -1 : players[id].score
355
+ };
356
+ // console.log(Ddnet_Character)
357
+ if (Ddnet_Character.freeze_end > 0 || Ddnet_Character.freeze_end == -1) // freezed or deepfreezed
358
+ console.log(Ddnet_Character);
359
+ } // else
360
+ // console.log("lolol uuid??", _size, type_id, id, data)
361
+ }
362
+ if (type_id == 11) {
363
+ // obj_client_info!
364
+ var client_info = {
365
+ name: this.IntsToStr(data.slice(0, 4)),
366
+ clan: this.IntsToStr(data.slice(4, 7)),
367
+ country: Number(data.slice(7, 8)),
368
+ skin: this.IntsToStr(data.slice(8, 14)),
369
+ use_custom_color: Number(data.slice(14, 15)),
370
+ color_body: Number(data.slice(15, 16)),
371
+ color_feet: Number(data.slice(16, 17)),
372
+ };
373
+ client_infos[id] = client_info;
374
+ // console.log(client_info.name, client_info.clan, client_info.skin)
375
+ }
376
+ else if (type_id == 10) {
377
+ var player_info = {
378
+ local: Number(data.slice(0, 1)),
379
+ client_id: Number(data.slice(1, 2)),
380
+ team: Number(data.slice(2, 3)),
381
+ score: Number(data.slice(3, 4)),
382
+ latency: Number(data.slice(4, 5))
383
+ };
384
+ player_infos[player_info.client_id] = player_info;
385
+ // players[id].score = player_info.score
386
+ // console.log(player_info, client_infos[player_info.client_id], data)
387
+ }
388
+ // if (type_id == 10 || type_id == 11)
389
+ // console.log(this.parseItem(data, type_id), itemAppendix[type_id].name, type_id)
390
+ var parsed = this.parseItem(data, type_id);
391
+ // console.log(data)
392
+ // console.log('')
393
+ items.items.push({ data: data, parsed: parsed, type_id: type_id, id: id, key: key });
394
+ }
395
+ // items.client_infos = client_infos;
396
+ // items.player_infos = player_infos;
397
+ return items;
398
+ };
399
+ return Snapshot;
400
+ }());
401
+ exports.Snapshot = Snapshot;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teeworlds",
3
- "version": "2.0.7",
3
+ "version": "2.0.8",
4
4
  "description": "Library for (ingame) teeworlds bots.",
5
5
  "license": "MIT",
6
6
  "main": "index.js",