sonic-ws 1.1.1-patch → 1.2.0

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
@@ -38,8 +39,9 @@ Developer Experience:
38
39
  - Debug tools for socket ids, byte size, data logging, etc. for troubleshooting
39
40
  - Very minimal learning curve, easy to work in
40
41
  - JSDoc's for understanding; immensely intuitive (personally, I took a break for half a year and came back and snapped right back in)
42
+ - Almost every case has a pre-made wire optimization and boilerplate removal.
41
43
 
42
- Whether you're making a real-time game, a dashboard, a distributed system, or anything else, SonicWS gets you safe, structured packets, fast.
44
+ Whether you're making a real-time game, a dashboard, a distributed system, or anything else, SonicWS gets you safe, structured packets; fast.
43
45
 
44
46
  ## SAMPLES
45
47
 
@@ -117,4 +119,4 @@ Some weird error messages when invalid inputs are in like CreatePacket() and stu
117
119
 
118
120
  Better error handling
119
121
 
120
- ZLib/gzip compression
122
+ Some middleware support
package/dist/version.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** Current protocol version */
2
- export declare const VERSION = 15;
2
+ export declare const VERSION = 16;
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 = 15;
21
+ exports.VERSION = 16;
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;
@@ -165,10 +167,10 @@ class SonicWSCore {
165
167
  const value = data.slice(1);
166
168
  const packet = this.serverPackets.getPacket(this.serverPackets.getTag(key));
167
169
  if (packet.dataBatching == 0) {
168
- this.listenPacket(packet.listen(value, null), key);
170
+ this.listenPacket(await packet.listen(value, null), key);
169
171
  return;
170
172
  }
171
- const batchData = BatchHelper_1.BatchHelper.unravelBatch(packet, value, null);
173
+ const batchData = await BatchHelper_1.BatchHelper.unravelBatch(packet, value, null);
172
174
  if (typeof batchData == 'string')
173
175
  return this.invalidPacket(batchData);
174
176
  batchData.forEach(data => this.listenPacket(data, key));
@@ -202,8 +204,8 @@ class SonicWSCore {
202
204
  * @param tag The tag of the packet
203
205
  * @param values The values to send
204
206
  */
205
- send(tag, ...values) {
206
- const [code, data, packet] = (0, PacketUtils_1.processPacket)(this.clientPackets, tag, values);
207
+ async send(tag, ...values) {
208
+ const [code, data, packet] = await (0, PacketUtils_1.processPacket)(this.clientPackets, tag, values);
207
209
  if (packet.dataBatching == 0)
208
210
  this.raw_send((0, BufferUtil_1.toPacketBuffer)(code, data));
209
211
  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, rereference: 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, rereference: 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,127 @@ 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, rereference) {
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)
121
90
  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)
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)
115
+ return false;
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);
135
+ }
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);
131
143
  }
132
- computed.push(string);
144
+ catch {
145
+ return false;
146
+ }
147
+ };
148
+ default: throw new Error("Unknown type: " + type);
149
+ }
150
+ }
151
+ const fn = genFunc();
152
+ let parsed = null;
153
+ return gzipCompression
154
+ ? async (data, index) => {
155
+ if (rereference && data.length == 0) {
156
+ if (parsed == null)
157
+ return [data, false];
158
+ return parsed;
133
159
  }
134
- if (sectors < dataMin)
135
- return false;
136
- return computed;
160
+ try {
161
+ const dec = await (0, CompressionUtil_1.decompressGzip)(data);
162
+ return parsed = [dec, fn(dec, index)];
163
+ }
164
+ catch {
165
+ return [data, false];
166
+ }
167
+ }
168
+ : async (data, index) => {
169
+ if (rereference && data.length == 0) {
170
+ if (parsed == null)
171
+ return [data, false];
172
+ return parsed;
173
+ }
174
+ return parsed = [data, fn(data, index)];
137
175
  };
138
- default: throw new Error("Unknown type: " + type);
139
- }
140
176
  }
141
177
  function createReceiveProcessor(type, enumData, cap) {
142
178
  switch (type) {
@@ -144,6 +180,7 @@ function createReceiveProcessor(type, enumData, cap) {
144
180
  case PacketType_1.PacketType.RAW: return (data) => data;
145
181
  case PacketType_1.PacketType.BYTES: return (data) => Array.from(data).map(CompressionUtil_1.demapZigZag);
146
182
  case PacketType_1.PacketType.UBYTES: return (data) => Array.from(data);
183
+ case PacketType_1.PacketType.HEX: return (data) => (0, CompressionUtil_1.bytesToHex)(data);
147
184
  case PacketType_1.PacketType.SHORTS: return (data) => (0, BufferUtil_1.splitBuffer)(data, 2).map(v => (0, CompressionUtil_1.demapShort_ZZ)(v));
148
185
  case PacketType_1.PacketType.USHORTS: return (data) => (0, BufferUtil_1.splitBuffer)(data, 2).map(v => (0, CompressionUtil_1.fromShort)(v));
149
186
  case PacketType_1.PacketType.VARINT: return (_, computed) => computed.map(CompressionUtil_1.demapZigZag);
@@ -170,64 +207,101 @@ function createReceiveProcessor(type, enumData, cap) {
170
207
  }
171
208
  return strings;
172
209
  };
173
- case PacketType_1.PacketType.STRINGS_UTF16: return (data, computed) => {
210
+ case PacketType_1.PacketType.STRINGS_UTF16: return (_, computed) => {
174
211
  return computed.map(codes => String.fromCodePoint(...codes));
175
212
  };
213
+ case PacketType_1.PacketType.JSON: return (_, computed) => computed;
176
214
  default: throw new Error("Unknown type: " + type);
177
215
  }
178
216
  }
179
217
  /** 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());
218
+ function createSendProcessor(type, gzipCompression, rereference) {
219
+ function genFunc() {
220
+ switch (type) {
221
+ case PacketType_1.PacketType.NONE: return () => [];
222
+ case PacketType_1.PacketType.RAW: return (data) => Array.from(data);
223
+ case PacketType_1.PacketType.ENUMS: return (enums) => enums;
224
+ case PacketType_1.PacketType.BYTES: return (numbers) => numbers.map(CompressionUtil_1.mapZigZag);
225
+ case PacketType_1.PacketType.UBYTES: return (numbers) => numbers.map(CompressionUtil_1.toByte);
226
+ case PacketType_1.PacketType.HEX: return (hex) => {
227
+ if (typeof hex != "string") {
228
+ if (hex instanceof Array && hex.length == 1)
229
+ return (0, CompressionUtil_1.hexToBytes)(hex[0]);
230
+ throw new Error("Cannot send more than 1 hex string; this packet is equivalent to UBYTES: " + JSON.stringify(hex));
231
+ }
232
+ return (0, CompressionUtil_1.hexToBytes)(hex);
233
+ };
234
+ case PacketType_1.PacketType.SHORTS: return (numbers) => numbers.map(CompressionUtil_1.mapShort_ZZ).flat();
235
+ case PacketType_1.PacketType.USHORTS: return (numbers) => numbers.map(CompressionUtil_1.toShort).flat();
236
+ case PacketType_1.PacketType.VARINT: return (numbers) => numbers.map(n => (0, CompressionUtil_1.convertVarInt)((0, CompressionUtil_1.mapZigZag)(n))).flat();
237
+ case PacketType_1.PacketType.UVARINT: return (numbers) => numbers.map(CompressionUtil_1.convertVarInt).flat();
238
+ 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();
239
+ case PacketType_1.PacketType.FLOATS: return (singles) => singles.map(CompressionUtil_1.convertFloat).flat();
240
+ case PacketType_1.PacketType.DOUBLES: return (doubles) => doubles.map(CompressionUtil_1.convertDouble).flat();
241
+ case PacketType_1.PacketType.BOOLEANS: return (bools) => (0, ArrayUtil_1.splitArray)(bools, 8).map((bools) => (0, CompressionUtil_1.compressBools)(bools)).flat();
242
+ case PacketType_1.PacketType.STRINGS_ASCII: return (strings) => {
243
+ return [
244
+ ...(0, CompressionUtil_1.convertVarInt)(strings.length),
245
+ ...strings.map(str => (0, CompressionUtil_1.convertVarInt)(str.length)).flat(),
246
+ ...(0, CompressionUtil_1.encodeHuffman)(strings.reduce((a, b) => a + String(b), "")),
247
+ ];
248
+ };
249
+ case PacketType_1.PacketType.STRINGS_UTF16: return (strings) => {
250
+ const res = [];
251
+ for (const v of strings) {
252
+ const string = String(v);
253
+ const charCodes = (0, StringUtil_1.processCharCodes)(string);
254
+ // hate js man
255
+ const length = charCodes.length;
256
+ res.push(...(0, CompressionUtil_1.convertVarInt)(length));
257
+ res.push(...charCodes.map(CompressionUtil_1.convertVarInt).flat());
258
+ }
259
+ return res;
260
+ };
261
+ case PacketType_1.PacketType.JSON: return (value) => Array.from((0, CompressionUtil_1.compressJSON)(value));
262
+ default: throw new Error("Unknown type: " + type);
263
+ }
264
+ }
265
+ const fn = genFunc();
266
+ let lastSent;
267
+ if (!gzipCompression) {
268
+ return async (_, data) => {
269
+ if (rereference) {
270
+ const jstr = JSON.stringify(data);
271
+ if (jstr == lastSent) {
272
+ return CompressionUtil_1.EMPTY_UINT8;
273
+ }
274
+ lastSent = jstr;
211
275
  }
212
- return res;
276
+ return new Uint8Array(fn(data));
213
277
  };
214
- default: throw new Error("Unknown type: " + type);
215
278
  }
279
+ return async (ident, data) => {
280
+ if (rereference) {
281
+ const jstr = JSON.stringify(data);
282
+ if (jstr == lastSent) {
283
+ return CompressionUtil_1.EMPTY_UINT8;
284
+ }
285
+ lastSent = jstr;
286
+ }
287
+ return (0, CompressionUtil_1.compressGzip)(new Uint8Array(fn(data)), ident);
288
+ };
216
289
  }
217
290
  function createObjSendProcessor(packet) {
218
291
  const size = packet.type.length;
219
- const processors = packet.type.map(t => createSendProcessor(t));
220
- return (data) => {
292
+ // TODO: Add compression and add rereferences[]
293
+ const processors = packet.type.map(t => createSendProcessor(t, false, false));
294
+ return async (ident, data) => {
221
295
  let result = [];
222
296
  for (let i = 0; i < size; i++) {
223
297
  const sectorData = data[i];
224
- const d = processors[i](Array.isArray(sectorData) ? sectorData : [sectorData]);
298
+ const d = await processors[i](ident, Array.isArray(sectorData) ? sectorData : [sectorData]);
225
299
  if (d.length > CompressionUtil_1.MAX_UVARINT)
226
300
  throw new Error(`Cannot send ${d.length}/${CompressionUtil_1.MAX_UVARINT} bytes of data!`);
227
301
  result.push(...(0, CompressionUtil_1.convertVarInt)(d.length));
228
302
  d.forEach(val => result.push(val));
229
303
  }
230
- return result;
304
+ return new Uint8Array(result);
231
305
  };
232
306
  }
233
307
  function createObjReceiveProcessor(packet) {
@@ -247,22 +321,22 @@ function createObjReceiveProcessor(packet) {
247
321
  };
248
322
  }
249
323
  function createObjValidator(packet) {
250
- const validators = packet.type.map((t, i) => createValidator(t, packet.dataMax[i], packet.dataMin[i], packet));
251
- return (data) => {
324
+ const validators = packet.type.map((t, i) => createValidator(t, packet.dataMax[i], packet.dataMin[i], packet, false, false));
325
+ return async (data) => {
252
326
  let index = 0, enums = 0, computedData = [];
253
327
  while (index < data.length) {
254
328
  if (computedData.length > packet.type.length)
255
- return false; // only types amount of values
329
+ return [data, false]; // only types amount of values
256
330
  const [off, sectorLength] = (0, CompressionUtil_1.readVarInt)(data, index);
257
331
  index = off;
258
332
  if (sectorLength + index > data.length)
259
- return false;
333
+ return [data, false];
260
334
  const sector = data.subarray(index, index += sectorLength);
261
- const result = validators[computedData.length](sector, packet.type[computedData.length] == PacketType_1.PacketType.ENUMS ? enums++ : 0);
335
+ const [, result] = await validators[computedData.length](sector, packet.type[computedData.length] == PacketType_1.PacketType.ENUMS ? enums++ : 0);
262
336
  if (result === false)
263
- return false; // chat i used === to fix a bug !!!!
337
+ return [data, false]; // chat i used === to fix a bug !!!!
264
338
  computedData.push(result);
265
339
  }
266
- return computedData;
340
+ return [data, computedData];
267
341
  };
268
342
  }
@@ -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 = {}));