sonic-ws 1.1.1 → 1.2.1-wtf

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,8 +7,9 @@ SonicWS is an ultra-lightweight, high-performance WebSocket library focused on m
7
7
  Compression:
8
8
  - Lossless compression up to 70% or more (for example, 38kb -> 14kb)
9
9
  - Optimized bandwidth for many different types to fit special constraints
10
- - Automatic helpers to flatten typed nested arrays for maximum wire efficiency (for example, [[1,2,3],[4,5,6]] to [[1,4],[2,5],[3,6]])
10
+ - Automatic helpers to flatten typed nested arrays for maximum wire efficiency (for example, [[1,false,"text"],[4,true,"other"]] to [[1,4],[false,true],["text,"other"]])
11
11
  - Uses raw binary bytes to transmit data as efficiently as possible while still using high level readable code
12
+ - Built-in ability to use compression libraries
12
13
 
13
14
  Developer Friendly:
14
15
  - Predefined data types of various sized integers, single and double precision floating point numbers, strings, enums, etc. and RAW to allow for developers to do anything they want
@@ -22,7 +23,8 @@ Security:
22
23
  - Built-in ability for handshake packets, preventing repetitive initiation checks in listeners (for example, removes if(!init) everywhere)
23
24
  - Built-in rate limiting for packets; ability for global send & receive, alongside per-packet rate limiting
24
25
  - Built-in disabling & enabling of packets to prevent abuse
25
- - Prevents any race conditions; your callbacks will not be called until they finish.
26
+ - Prevents any race conditions; your callbacks will not be called until the last one finishes. (Alongside async options!)
27
+ - Prevents niche bugs found in other websocket libraries, such as functions calling after the socket already closed.
26
28
 
27
29
  Performance & Scaling:
28
30
  - Can handle very large packets in microseconds
@@ -38,8 +40,9 @@ Developer Experience:
38
40
  - Debug tools for socket ids, byte size, data logging, etc. for troubleshooting
39
41
  - Very minimal learning curve, easy to work in
40
42
  - JSDoc's for understanding; immensely intuitive (personally, I took a break for half a year and came back and snapped right back in)
43
+ - Almost every case has a pre-made wire optimization and boilerplate removal.
41
44
 
42
- Whether you're making a real-time game, a dashboard, a distributed system, or anything else, SonicWS gets you safe, structured packets, fast.
45
+ Whether you're making a real-time game, a dashboard, a distributed system, or anything else, SonicWS gets you safe, structured packets; fast.
43
46
 
44
47
  ## SAMPLES
45
48
 
@@ -117,4 +120,6 @@ Some weird error messages when invalid inputs are in like CreatePacket() and stu
117
120
 
118
121
  Better error handling
119
122
 
120
- ZLib/gzip compression
123
+ Some middleware support
124
+
125
+ Debug menus for client/server
package/dist/version.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** Current protocol version */
2
- export declare const VERSION = 14;
2
+ export declare const VERSION = 17;
3
3
  /** Server data suffix */
4
4
  export declare const SERVER_SUFFIX = "SWS";
5
5
  /** Server data suffix in array */
package/dist/version.js CHANGED
@@ -18,7 +18,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.SERVER_SUFFIX_NUMS = exports.SERVER_SUFFIX = exports.VERSION = void 0;
19
19
  const StringUtil_1 = require("./ws/util/StringUtil");
20
20
  /** Current protocol version */
21
- exports.VERSION = 14;
21
+ exports.VERSION = 17;
22
22
  /** Server data suffix */
23
23
  exports.SERVER_SUFFIX = "SWS";
24
24
  /** Server data suffix in array */
@@ -26,6 +26,7 @@ export declare abstract class SonicWSCore implements Connection {
26
26
  private asyncMap;
27
27
  constructor(ws: WebSocket, bufferHandler: (val: MessageEvent) => Promise<Uint8Array>);
28
28
  private reading;
29
+ private readQueue;
29
30
  private serverKeyHandler;
30
31
  private invalidPacket;
31
32
  private listenLock;
@@ -50,7 +51,7 @@ export declare abstract class SonicWSCore implements Connection {
50
51
  * @param tag The tag of the packet
51
52
  * @param values The values to send
52
53
  */
53
- send(tag: string, ...values: any[]): void;
54
+ send(tag: string, ...values: any[]): Promise<void>;
54
55
  /**
55
56
  * Listens for when the client connects
56
57
  * @param listener Callback on connection
@@ -63,27 +63,28 @@ class SonicWSCore {
63
63
  this.bufferHandler = bufferHandler;
64
64
  }
65
65
  reading = false;
66
+ readQueue = [];
66
67
  async serverKeyHandler(event) {
67
- // stupid asynchronous bullshit
68
68
  if (this.reading)
69
- return this.messageHandler(event);
69
+ return this.readQueue.push(event);
70
70
  this.reading = true;
71
- const data = await this.bufferHandler(event);
72
- if (data.length < 3 || (0, BufferUtil_1.as8String)(data.slice(0, 3)) != version_1.SERVER_SUFFIX) {
71
+ const cdata = await this.bufferHandler(event);
72
+ if (cdata.length < 3 || (0, BufferUtil_1.as8String)(cdata.slice(0, 3)) != version_1.SERVER_SUFFIX) {
73
73
  this.socket.close(1000);
74
74
  throw new Error("The server requested is not a Sonic WS server.");
75
75
  }
76
- const version = data[3];
76
+ const version = cdata[3];
77
77
  if (version != version_1.VERSION) {
78
78
  this.socket.close(1000);
79
79
  throw new Error(`Version mismatch: ${version > version_1.VERSION ? "client" : "server"} is outdated (server: ${version}, client: ${version_1.VERSION})`);
80
80
  }
81
- const [ckOff, id] = (0, CompressionUtil_1.readVarInt)(data, 4);
81
+ const data = await (0, CompressionUtil_1.decompressGzip)(cdata.subarray(4, cdata.length));
82
+ const [ckOff, id] = (0, CompressionUtil_1.readVarInt)(data, 0);
82
83
  this.id = id;
83
84
  const [valuesOff, ckLength] = (0, CompressionUtil_1.readVarInt)(data, ckOff);
84
- const ckData = data.slice(valuesOff, valuesOff + ckLength);
85
+ const ckData = data.subarray(valuesOff, valuesOff + ckLength);
85
86
  this.clientPackets.holdPackets(Packets_1.Packet.deserializeAll(ckData, true));
86
- const skData = data.slice(valuesOff + ckLength, data.length);
87
+ const skData = data.subarray(valuesOff + ckLength, data.length);
87
88
  this.serverPackets.holdPackets(Packets_1.Packet.deserializeAll(skData, true));
88
89
  this.batcher.registerSendPackets(this.clientPackets, this);
89
90
  for (const p of this.serverPackets.getPackets()) {
@@ -105,6 +106,8 @@ class SonicWSCore {
105
106
  this.readyListeners = null; // clear
106
107
  this.socket.removeEventListener('message', this.serverKeyHandler);
107
108
  this.socket.addEventListener('message', this.messageHandler);
109
+ this.readQueue.forEach(e => this.messageHandler(e));
110
+ this.readQueue = [];
108
111
  }
109
112
  invalidPacket(listened) {
110
113
  console.error(listened);
@@ -136,7 +139,7 @@ class SonicWSCore {
136
139
  packetQueue = this.packetQueue;
137
140
  }
138
141
  if (locked) {
139
- packetQueue.push([data, code]);
142
+ packetQueue.push(data);
140
143
  return;
141
144
  }
142
145
  if (isAsync)
@@ -144,12 +147,11 @@ class SonicWSCore {
144
147
  else
145
148
  this.listenLock = true;
146
149
  let currentData = data;
147
- let currentCode = code;
148
150
  while (true) {
149
151
  await (0, PacketUtils_1.listenPacket)(currentData, listeners, this.invalidPacket);
150
152
  if (packetQueue.length === 0)
151
153
  break;
152
- [currentData, currentCode] = packetQueue.shift();
154
+ currentData = packetQueue.shift();
153
155
  }
154
156
  if (isAsync)
155
157
  asyncData[0] = false;
@@ -164,11 +166,18 @@ class SonicWSCore {
164
166
  const key = data[0];
165
167
  const value = data.slice(1);
166
168
  const packet = this.serverPackets.getPacket(this.serverPackets.getTag(key));
169
+ if (packet.rereference && value.length == 0) {
170
+ if (packet.lastReceived[0] === undefined)
171
+ return this.invalidPacket("No previous value to rereference");
172
+ this.listenPacket(packet.lastReceived[0], key);
173
+ return;
174
+ }
167
175
  if (packet.dataBatching == 0) {
168
- this.listenPacket(packet.listen(value, null), key);
176
+ const res = packet.lastReceived[0] = await packet.listen(value, null);
177
+ this.listenPacket(res, key);
169
178
  return;
170
179
  }
171
- const batchData = BatchHelper_1.BatchHelper.unravelBatch(packet, value, null);
180
+ const batchData = await BatchHelper_1.BatchHelper.unravelBatch(packet, value, null);
172
181
  if (typeof batchData == 'string')
173
182
  return this.invalidPacket(batchData);
174
183
  batchData.forEach(data => this.listenPacket(data, key));
@@ -202,8 +211,8 @@ class SonicWSCore {
202
211
  * @param tag The tag of the packet
203
212
  * @param values The values to send
204
213
  */
205
- send(tag, ...values) {
206
- const [code, data, packet] = (0, PacketUtils_1.processPacket)(this.clientPackets, tag, values);
214
+ async send(tag, ...values) {
215
+ const [code, data, packet] = await (0, PacketUtils_1.processPacket)(this.clientPackets, tag, values, 0);
207
216
  if (packet.dataBatching == 0)
208
217
  this.raw_send((0, BufferUtil_1.toPacketBuffer)(code, data));
209
218
  else
@@ -1,19 +1,13 @@
1
1
  import { EnumPackage } from "../util/enums/EnumType";
2
2
  import { Packet } from "./Packets";
3
3
  import { PacketType } from "./PacketType";
4
- export type PacketTypeValidator = (data: Uint8Array, index: number) => false | any;
4
+ export type PacketTypeValidator = (data: Uint8Array, index: number) => Promise<[Uint8Array, false | any]>;
5
5
  export type PacketReceiveProcessor = (data: Uint8Array, validationResult: any, index: number) => any;
6
- export type PacketSendProcessor = (...data: any) => number[];
7
- export declare function createValidator<T extends PacketType>(type: T, dataCap: number, dataMin: number, packet: Packet<T | T[]>): PacketTypeValidator;
6
+ export type PacketSendProcessor = (ident: string, ...data: any[]) => Promise<Uint8Array>;
7
+ export declare function createValidator<T extends PacketType>(type: T, dataCap: number, dataMin: number, packet: Packet<T | T[]>, gzipCompression: boolean): PacketTypeValidator;
8
8
  export declare function createReceiveProcessor(type: PacketType, enumData: EnumPackage[], cap: number): PacketReceiveProcessor;
9
9
  /** Creates a function that processes a packet type */
10
- export declare function createSendProcessor(type: PacketType): PacketSendProcessor;
10
+ export declare function createSendProcessor(type: PacketType, gzipCompression: boolean): PacketSendProcessor;
11
11
  export declare function createObjSendProcessor(packet: Packet<PacketType[]>): PacketSendProcessor;
12
12
  export declare function createObjReceiveProcessor(packet: Packet<PacketType[]>): PacketReceiveProcessor;
13
13
  export declare function createObjValidator(packet: Packet<PacketType[]>): PacketTypeValidator;
14
- type BuildTuple<T, N extends number, R extends unknown[] = []> = R['length'] extends N ? R : BuildTuple<T, N, [T, ...R]>;
15
- export type PacketResponse<T extends PacketType | readonly PacketType[], N extends number | readonly number[]> = T extends PacketType[] ? N extends number[] ? PacketResponseArray<T, N> : never : BuildTuple<T extends PacketType.NONE ? undefined : T extends PacketType.RAW ? Uint8Array : T extends PacketType.BYTES | PacketType.UBYTES ? number : T extends PacketType.SHORTS | PacketType.USHORTS ? number : T extends PacketType.VARINT | PacketType.UVARINT | PacketType.DELTAS ? number : T extends PacketType.FLOATS | PacketType.DOUBLES ? number : T extends PacketType.BOOLEANS ? boolean : T extends PacketType.STRINGS_ASCII | PacketType.STRINGS_UTF16 ? string : T extends PacketType.ENUMS ? any : never, N extends number ? N : never>;
16
- type PacketResponseArray<T extends PacketType[], N extends number[]> = {
17
- [K in keyof T]: K extends number ? PacketResponse<T[K], N[K] & number> : never;
18
- };
19
- export {};
@@ -52,91 +52,116 @@ function VARINT_VERIF(cap, min) {
52
52
  };
53
53
  }
54
54
  ;
55
- function createValidator(type, dataCap, dataMin, packet) {
56
- switch (type) {
57
- case PacketType_1.PacketType.NONE: return (data) => data.length == 0;
58
- case PacketType_1.PacketType.RAW: return () => undefined;
59
- case PacketType_1.PacketType.ENUMS: return (data, index) => {
60
- if (data.length < dataMin || data.length > dataCap || index >= packet.enumData.length)
61
- return false;
62
- const pkg = packet.enumData[index];
63
- for (let i = 0; i < data.length; i++) {
64
- if (pkg.values.length <= data[i])
55
+ function createValidator(type, dataCap, dataMin, packet, gzipCompression) {
56
+ function genFunc() {
57
+ switch (type) {
58
+ case PacketType_1.PacketType.NONE: return (data) => data.length == 0;
59
+ case PacketType_1.PacketType.RAW: return () => undefined;
60
+ case PacketType_1.PacketType.ENUMS: return (data, index) => {
61
+ if (data.length < dataMin || data.length > dataCap || index >= packet.enumData.length)
65
62
  return false;
66
- }
67
- };
68
- case PacketType_1.PacketType.BYTES: return BYTE_LEN(dataCap, dataMin);
69
- case PacketType_1.PacketType.UBYTES: return BYTE_LEN(dataCap, dataMin);
70
- case PacketType_1.PacketType.SHORTS: return SHORT_LEN(dataCap, dataMin);
71
- case PacketType_1.PacketType.USHORTS: return SHORT_LEN(dataCap, dataMin);
72
- case PacketType_1.PacketType.VARINT: return VARINT_VERIF(dataCap, dataMin);
73
- case PacketType_1.PacketType.UVARINT: return VARINT_VERIF(dataCap, dataMin);
74
- case PacketType_1.PacketType.DELTAS: return VARINT_VERIF(dataCap, dataMin);
75
- case PacketType_1.PacketType.FLOATS: return (data) => {
76
- if (data.length % 4 !== 0)
77
- return false;
78
- const sectors = data.length * CompressionUtil_1.ONE_FOURTH;
79
- if (sectors > dataCap || sectors < dataMin)
80
- return false;
81
- return undefined;
82
- };
83
- case PacketType_1.PacketType.DOUBLES: return (data) => {
84
- if (data.length % 8 !== 0)
85
- return false;
86
- const sectors = data.length * CompressionUtil_1.ONE_EIGHT;
87
- if (sectors > dataCap || sectors < dataMin)
88
- return false;
89
- return undefined;
90
- };
91
- case PacketType_1.PacketType.BOOLEANS:
92
- {
93
- const min = Math.ceil(dataMin * CompressionUtil_1.ONE_EIGHT);
94
- const cap = Math.ceil(dataCap * CompressionUtil_1.ONE_EIGHT);
95
- return (data) => data.length >= min && data.length <= cap;
96
- }
97
- ;
98
- case PacketType_1.PacketType.STRINGS_ASCII: return (data) => {
99
- let index = 0;
100
- const [offCount, stringCount] = (0, CompressionUtil_1.readVarInt)(data, index);
101
- index = offCount;
102
- if (stringCount < dataMin || stringCount > dataCap)
103
- return false;
104
- const lengths = [];
105
- let totalLength = 0;
106
- for (let i = 0; i < stringCount; i++) {
107
- const [offLen, strLen] = (0, CompressionUtil_1.readVarInt)(data, index);
108
- index = offLen;
109
- lengths.push(strLen);
110
- totalLength += strLen;
111
- }
112
- if (index + Math.ceil(totalLength / 8) > data.length)
113
- return false;
114
- return [stringCount, lengths, index];
115
- };
116
- case PacketType_1.PacketType.STRINGS_UTF16: return (data) => {
117
- let sectors = 0, index = 0, computed = [];
118
- while (index < data.length) {
119
- sectors++;
120
- if (sectors > dataCap)
63
+ const pkg = packet.enumData[index];
64
+ for (let i = 0; i < data.length; i++) {
65
+ if (pkg.values.length <= data[i])
66
+ return false;
67
+ }
68
+ };
69
+ case PacketType_1.PacketType.BYTES: return BYTE_LEN(dataCap, dataMin);
70
+ case PacketType_1.PacketType.UBYTES: return BYTE_LEN(dataCap, dataMin);
71
+ case PacketType_1.PacketType.HEX: return BYTE_LEN(dataCap, dataMin);
72
+ case PacketType_1.PacketType.SHORTS: return SHORT_LEN(dataCap, dataMin);
73
+ case PacketType_1.PacketType.USHORTS: return SHORT_LEN(dataCap, dataMin);
74
+ case PacketType_1.PacketType.VARINT: return VARINT_VERIF(dataCap, dataMin);
75
+ case PacketType_1.PacketType.UVARINT: return VARINT_VERIF(dataCap, dataMin);
76
+ case PacketType_1.PacketType.DELTAS: return VARINT_VERIF(dataCap, dataMin);
77
+ case PacketType_1.PacketType.FLOATS: return (data) => {
78
+ if (data.length % 4 !== 0)
79
+ return false;
80
+ const sectors = data.length * CompressionUtil_1.ONE_FOURTH;
81
+ if (sectors > dataCap || sectors < dataMin)
82
+ return false;
83
+ return undefined;
84
+ };
85
+ case PacketType_1.PacketType.DOUBLES: return (data) => {
86
+ if (data.length % 8 !== 0)
87
+ return false;
88
+ const sectors = data.length * CompressionUtil_1.ONE_EIGHT;
89
+ if (sectors > dataCap || sectors < dataMin)
90
+ return false;
91
+ return undefined;
92
+ };
93
+ case PacketType_1.PacketType.BOOLEANS:
94
+ {
95
+ const min = Math.ceil(dataMin * CompressionUtil_1.ONE_EIGHT);
96
+ const cap = Math.ceil(dataCap * CompressionUtil_1.ONE_EIGHT);
97
+ return (data) => data.length >= min && data.length <= cap;
98
+ }
99
+ ;
100
+ case PacketType_1.PacketType.STRINGS_ASCII: return (data) => {
101
+ let index = 0;
102
+ const [offCount, stringCount] = (0, CompressionUtil_1.readVarInt)(data, index);
103
+ index = offCount;
104
+ if (stringCount < dataMin || stringCount > dataCap)
105
+ return false;
106
+ const lengths = [];
107
+ let totalLength = 0;
108
+ for (let i = 0; i < stringCount; i++) {
109
+ const [offLen, strLen] = (0, CompressionUtil_1.readVarInt)(data, index);
110
+ index = offLen;
111
+ lengths.push(strLen);
112
+ totalLength += strLen;
113
+ }
114
+ if (index + Math.ceil(totalLength / 8) > data.length)
121
115
  return false;
122
- const [off, strLength] = (0, CompressionUtil_1.readVarInt)(data, index);
123
- index = off;
124
- let string = [];
125
- for (let i = 0; i < strLength; i++) {
126
- const [newOff, char] = (0, CompressionUtil_1.readVarInt)(data, index);
127
- index = newOff;
128
- if (index > data.length)
116
+ return [stringCount, lengths, index];
117
+ };
118
+ case PacketType_1.PacketType.STRINGS_UTF16: return (data) => {
119
+ let sectors = 0, index = 0, computed = [];
120
+ while (index < data.length) {
121
+ sectors++;
122
+ if (sectors > dataCap)
129
123
  return false;
130
- string.push(char);
124
+ const [off, strLength] = (0, CompressionUtil_1.readVarInt)(data, index);
125
+ index = off;
126
+ let string = [];
127
+ for (let i = 0; i < strLength; i++) {
128
+ const [newOff, char] = (0, CompressionUtil_1.readVarInt)(data, index);
129
+ index = newOff;
130
+ if (index > data.length)
131
+ return false;
132
+ string.push(char);
133
+ }
134
+ computed.push(string);
131
135
  }
132
- computed.push(string);
136
+ if (sectors < dataMin)
137
+ return false;
138
+ return computed;
139
+ };
140
+ case PacketType_1.PacketType.JSON: return (data) => {
141
+ try {
142
+ return (0, CompressionUtil_1.decompressJSON)(data);
143
+ }
144
+ catch {
145
+ return false;
146
+ }
147
+ };
148
+ default: throw new Error("Unknown type: " + type);
149
+ }
150
+ }
151
+ const fn = genFunc();
152
+ return gzipCompression
153
+ ? async (data, index) => {
154
+ try {
155
+ const dec = await (0, CompressionUtil_1.decompressGzip)(data);
156
+ return [dec, fn(dec, index)];
133
157
  }
134
- if (sectors < dataMin)
135
- return false;
136
- return computed;
158
+ catch {
159
+ return [data, false];
160
+ }
161
+ }
162
+ : async (data, index) => {
163
+ return [data, fn(data, index)];
137
164
  };
138
- default: throw new Error("Unknown type: " + type);
139
- }
140
165
  }
141
166
  function createReceiveProcessor(type, enumData, cap) {
142
167
  switch (type) {
@@ -144,6 +169,7 @@ function createReceiveProcessor(type, enumData, cap) {
144
169
  case PacketType_1.PacketType.RAW: return (data) => data;
145
170
  case PacketType_1.PacketType.BYTES: return (data) => Array.from(data).map(CompressionUtil_1.demapZigZag);
146
171
  case PacketType_1.PacketType.UBYTES: return (data) => Array.from(data);
172
+ case PacketType_1.PacketType.HEX: return (data) => (0, CompressionUtil_1.bytesToHex)(data);
147
173
  case PacketType_1.PacketType.SHORTS: return (data) => (0, BufferUtil_1.splitBuffer)(data, 2).map(v => (0, CompressionUtil_1.demapShort_ZZ)(v));
148
174
  case PacketType_1.PacketType.USHORTS: return (data) => (0, BufferUtil_1.splitBuffer)(data, 2).map(v => (0, CompressionUtil_1.fromShort)(v));
149
175
  case PacketType_1.PacketType.VARINT: return (_, computed) => computed.map(CompressionUtil_1.demapZigZag);
@@ -170,64 +196,86 @@ function createReceiveProcessor(type, enumData, cap) {
170
196
  }
171
197
  return strings;
172
198
  };
173
- case PacketType_1.PacketType.STRINGS_UTF16: return (data, computed) => {
199
+ case PacketType_1.PacketType.STRINGS_UTF16: return (_, computed) => {
174
200
  return computed.map(codes => String.fromCodePoint(...codes));
175
201
  };
202
+ case PacketType_1.PacketType.JSON: return (_, computed) => computed;
176
203
  default: throw new Error("Unknown type: " + type);
177
204
  }
178
205
  }
179
206
  /** Creates a function that processes a packet type */
180
- function createSendProcessor(type) {
181
- switch (type) {
182
- case PacketType_1.PacketType.NONE: return () => [];
183
- case PacketType_1.PacketType.RAW: return (data) => Array.from(data);
184
- case PacketType_1.PacketType.ENUMS: return (enums) => enums;
185
- case PacketType_1.PacketType.BYTES: return (numbers) => numbers.map(CompressionUtil_1.mapZigZag);
186
- case PacketType_1.PacketType.UBYTES: return (numbers) => numbers.map(CompressionUtil_1.toByte);
187
- case PacketType_1.PacketType.SHORTS: return (numbers) => numbers.map(CompressionUtil_1.mapShort_ZZ).flat();
188
- case PacketType_1.PacketType.USHORTS: return (numbers) => numbers.map(CompressionUtil_1.toShort).flat();
189
- case PacketType_1.PacketType.VARINT: return (numbers) => numbers.map(n => (0, CompressionUtil_1.convertVarInt)((0, CompressionUtil_1.mapZigZag)(n))).flat();
190
- case PacketType_1.PacketType.UVARINT: return (numbers) => numbers.map(CompressionUtil_1.convertVarInt).flat();
191
- case PacketType_1.PacketType.DELTAS: return (numbers) => numbers.map((n, i) => (0, CompressionUtil_1.convertVarInt)((0, CompressionUtil_1.mapZigZag)(n - (numbers[i - 1] || 0)))).flat();
192
- case PacketType_1.PacketType.FLOATS: return (singles) => singles.map(CompressionUtil_1.convertFloat).flat();
193
- case PacketType_1.PacketType.DOUBLES: return (doubles) => doubles.map(CompressionUtil_1.convertDouble).flat();
194
- case PacketType_1.PacketType.BOOLEANS: return (bools) => (0, ArrayUtil_1.splitArray)(bools, 8).map((bools) => (0, CompressionUtil_1.compressBools)(bools)).flat();
195
- case PacketType_1.PacketType.STRINGS_ASCII: return (strings) => {
196
- return [
197
- ...(0, CompressionUtil_1.convertVarInt)(strings.length),
198
- ...strings.map(str => (0, CompressionUtil_1.convertVarInt)(str.length)).flat(),
199
- ...(0, CompressionUtil_1.encodeHuffman)(strings.reduce((a, b) => a + String(b), "")),
200
- ];
201
- };
202
- case PacketType_1.PacketType.STRINGS_UTF16: return (strings) => {
203
- const res = [];
204
- for (const v of strings) {
205
- const string = String(v);
206
- const charCodes = (0, StringUtil_1.processCharCodes)(string);
207
- // hate js man
208
- const length = charCodes.length;
209
- res.push(...(0, CompressionUtil_1.convertVarInt)(length));
210
- res.push(...charCodes.map(CompressionUtil_1.convertVarInt).flat());
211
- }
212
- return res;
207
+ function createSendProcessor(type, gzipCompression) {
208
+ function genFunc() {
209
+ switch (type) {
210
+ case PacketType_1.PacketType.NONE: return () => [];
211
+ case PacketType_1.PacketType.RAW: return (data) => Array.from(data);
212
+ case PacketType_1.PacketType.ENUMS: return (enums) => enums;
213
+ case PacketType_1.PacketType.BYTES: return (numbers) => numbers.map(CompressionUtil_1.mapZigZag);
214
+ case PacketType_1.PacketType.UBYTES: return (numbers) => numbers.map(CompressionUtil_1.toByte);
215
+ case PacketType_1.PacketType.HEX: return (hex) => {
216
+ if (typeof hex != "string") {
217
+ if (hex instanceof Array && hex.length == 1)
218
+ return (0, CompressionUtil_1.hexToBytes)(hex[0]);
219
+ throw new Error("Cannot send more than 1 hex string; this packet is equivalent to UBYTES: " + JSON.stringify(hex));
220
+ }
221
+ return (0, CompressionUtil_1.hexToBytes)(hex);
222
+ };
223
+ case PacketType_1.PacketType.SHORTS: return (numbers) => numbers.map(CompressionUtil_1.mapShort_ZZ).flat();
224
+ case PacketType_1.PacketType.USHORTS: return (numbers) => numbers.map(CompressionUtil_1.toShort).flat();
225
+ case PacketType_1.PacketType.VARINT: return (numbers) => numbers.map(n => (0, CompressionUtil_1.convertVarInt)((0, CompressionUtil_1.mapZigZag)(n))).flat();
226
+ case PacketType_1.PacketType.UVARINT: return (numbers) => numbers.map(CompressionUtil_1.convertVarInt).flat();
227
+ case PacketType_1.PacketType.DELTAS: return (numbers) => numbers.map((n, i) => (0, CompressionUtil_1.convertVarInt)((0, CompressionUtil_1.mapZigZag)(n - (numbers[i - 1] || 0)))).flat();
228
+ case PacketType_1.PacketType.FLOATS: return (singles) => singles.map(CompressionUtil_1.convertFloat).flat();
229
+ case PacketType_1.PacketType.DOUBLES: return (doubles) => doubles.map(CompressionUtil_1.convertDouble).flat();
230
+ case PacketType_1.PacketType.BOOLEANS: return (bools) => (0, ArrayUtil_1.splitArray)(bools, 8).map((bools) => (0, CompressionUtil_1.compressBools)(bools)).flat();
231
+ case PacketType_1.PacketType.STRINGS_ASCII: return (strings) => {
232
+ return [
233
+ ...(0, CompressionUtil_1.convertVarInt)(strings.length),
234
+ ...strings.map(str => (0, CompressionUtil_1.convertVarInt)(str.length)).flat(),
235
+ ...(0, CompressionUtil_1.encodeHuffman)(strings.reduce((a, b) => a + String(b), "")),
236
+ ];
237
+ };
238
+ case PacketType_1.PacketType.STRINGS_UTF16: return (strings) => {
239
+ const res = [];
240
+ for (const v of strings) {
241
+ const string = String(v);
242
+ const charCodes = (0, StringUtil_1.processCharCodes)(string);
243
+ // hate js man
244
+ const length = charCodes.length;
245
+ res.push(...(0, CompressionUtil_1.convertVarInt)(length));
246
+ res.push(...charCodes.map(CompressionUtil_1.convertVarInt).flat());
247
+ }
248
+ return res;
249
+ };
250
+ case PacketType_1.PacketType.JSON: return (value) => Array.from((0, CompressionUtil_1.compressJSON)(value));
251
+ default: throw new Error("Unknown type: " + type);
252
+ }
253
+ }
254
+ const fn = genFunc();
255
+ if (!gzipCompression) {
256
+ return async (_, data) => {
257
+ return new Uint8Array(fn(data));
213
258
  };
214
- default: throw new Error("Unknown type: " + type);
215
259
  }
260
+ return async (ident, data) => {
261
+ return (0, CompressionUtil_1.compressGzip)(new Uint8Array(fn(data)), ident);
262
+ };
216
263
  }
217
264
  function createObjSendProcessor(packet) {
218
265
  const size = packet.type.length;
219
- const processors = packet.type.map(t => createSendProcessor(t));
220
- return (data) => {
266
+ // TODO: Add compression and add rereferences[]
267
+ const processors = packet.type.map(t => createSendProcessor(t, false));
268
+ return async (ident, data) => {
221
269
  let result = [];
222
270
  for (let i = 0; i < size; i++) {
223
271
  const sectorData = data[i];
224
- const d = processors[i](Array.isArray(sectorData) ? sectorData : [sectorData]);
272
+ const d = await processors[i](ident, Array.isArray(sectorData) ? sectorData : [sectorData]);
225
273
  if (d.length > CompressionUtil_1.MAX_UVARINT)
226
274
  throw new Error(`Cannot send ${d.length}/${CompressionUtil_1.MAX_UVARINT} bytes of data!`);
227
275
  result.push(...(0, CompressionUtil_1.convertVarInt)(d.length));
228
276
  d.forEach(val => result.push(val));
229
277
  }
230
- return result;
278
+ return new Uint8Array(result);
231
279
  };
232
280
  }
233
281
  function createObjReceiveProcessor(packet) {
@@ -247,22 +295,22 @@ function createObjReceiveProcessor(packet) {
247
295
  };
248
296
  }
249
297
  function createObjValidator(packet) {
250
- const validators = packet.type.map((t, i) => createValidator(t, packet.dataMax[i], packet.dataMin[i], packet));
251
- return (data) => {
298
+ const validators = packet.type.map((t, i) => createValidator(t, packet.dataMax[i], packet.dataMin[i], packet, false));
299
+ return async (data) => {
252
300
  let index = 0, enums = 0, computedData = [];
253
301
  while (index < data.length) {
254
302
  if (computedData.length > packet.type.length)
255
- return false; // only types amount of values
303
+ return [data, false]; // only types amount of values
256
304
  const [off, sectorLength] = (0, CompressionUtil_1.readVarInt)(data, index);
257
305
  index = off;
258
306
  if (sectorLength + index > data.length)
259
- return false;
307
+ return [data, false];
260
308
  const sector = data.subarray(index, index += sectorLength);
261
- const result = validators[computedData.length](sector, packet.type[computedData.length] == PacketType_1.PacketType.ENUMS ? enums++ : 0);
309
+ const [, result] = await validators[computedData.length](sector, packet.type[computedData.length] == PacketType_1.PacketType.ENUMS ? enums++ : 0);
262
310
  if (result === false)
263
- return false; // chat i used === to fix a bug !!!!
311
+ return [data, false]; // chat i used === to fix a bug !!!!
264
312
  computedData.push(result);
265
313
  }
266
- return computedData;
314
+ return [data, computedData];
267
315
  };
268
316
  }
@@ -31,5 +31,11 @@ export declare enum PacketType {
31
31
  /** One or more double precision floating point numbers. */
32
32
  DOUBLES = 13,
33
33
  /** One or more true/false */
34
- BOOLEANS = 14
34
+ BOOLEANS = 14,
35
+ /** Consumes multiple keys to describe the value. E.g. if you want to send a boolean, this could take up 2 keys instead of sending 2 bytes. Currently W.I.P. */
36
+ KEY_EFFECTIVE = 15,
37
+ /** A more optimized version of JSON for when it's a necessity. However, please try to avoid this; the other types are usually better. */
38
+ JSON = 16,
39
+ /** Hex bytes, e.g. 0xFFFFFF - the result will always be returned in lowercase. This can only hold 1 hex string, since it's the same as UBYTES but auto-parses. */
40
+ HEX = 17
35
41
  }
@@ -52,4 +52,10 @@ var PacketType;
52
52
  PacketType[PacketType["DOUBLES"] = 13] = "DOUBLES";
53
53
  /** One or more true/false */
54
54
  PacketType[PacketType["BOOLEANS"] = 14] = "BOOLEANS";
55
+ /** Consumes multiple keys to describe the value. E.g. if you want to send a boolean, this could take up 2 keys instead of sending 2 bytes. Currently W.I.P. */
56
+ PacketType[PacketType["KEY_EFFECTIVE"] = 15] = "KEY_EFFECTIVE";
57
+ /** A more optimized version of JSON for when it's a necessity. However, please try to avoid this; the other types are usually better. */
58
+ PacketType[PacketType["JSON"] = 16] = "JSON";
59
+ /** Hex bytes, e.g. 0xFFFFFF - the result will always be returned in lowercase. This can only hold 1 hex string, since it's the same as UBYTES but auto-parses. */
60
+ PacketType[PacketType["HEX"] = 17] = "HEX";
55
61
  })(PacketType || (exports.PacketType = PacketType = {}));