mcbe-ipc 2.0.1 → 3.0.1

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/dist/ipc.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * @license
3
3
  * MIT License
4
4
  *
5
- * Copyright (c) 2024 OmniacDev
5
+ * Copyright (c) 2025 OmniacDev
6
6
  *
7
7
  * Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  * of this software and associated documentation files (the "Software"), to deal
@@ -22,405 +22,455 @@
22
22
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
23
  * SOFTWARE.
24
24
  */
25
- import { world, system, ScriptEventSource } from '@minecraft/server';
26
- var IPC;
27
- (function (IPC) {
28
- class Connection {
29
- *MAYBE_ENCRYPT(args) {
30
- return this._enc !== false ? yield* CRYPTO.encrypt(JSON.stringify(args), this._enc) : args;
31
- }
32
- *MAYBE_DECRYPT(args) {
33
- return this._enc !== false ? JSON.parse(yield* CRYPTO.decrypt(args[1], this._enc)) : args[1];
34
- }
35
- get from() {
36
- return this._from;
37
- }
38
- get to() {
39
- return this._to;
40
- }
41
- constructor(from, to, encryption) {
42
- this._from = from;
43
- this._to = to;
44
- this._enc = encryption;
45
- this._terminators = new Array();
46
- }
47
- terminate(notify = true) {
48
- const $ = this;
49
- $._terminators.forEach(terminate => terminate());
50
- $._terminators.length = 0;
51
- if (notify) {
52
- system.runJob(NET.emit('ipc', `${$._to}:terminate`, [$._from]));
25
+ import { ScriptEventSource, system, world } from '@minecraft/server';
26
+ export var PROTO;
27
+ (function (PROTO) {
28
+ class ByteQueue {
29
+ get end() {
30
+ return this._length + this._offset;
31
+ }
32
+ get front() {
33
+ return this._offset;
34
+ }
35
+ get data_view() {
36
+ return this._data_view;
37
+ }
38
+ constructor(size = 256) {
39
+ this._buffer = new Uint8Array(size);
40
+ this._data_view = new DataView(this._buffer.buffer);
41
+ this._length = 0;
42
+ this._offset = 0;
43
+ }
44
+ write(...values) {
45
+ this.ensure_capacity(values.length);
46
+ this._buffer.set(values, this.end);
47
+ this._length += values.length;
48
+ }
49
+ read(amount = 1) {
50
+ if (this._length > 0) {
51
+ const max_amount = amount > this._length ? this._length : amount;
52
+ const values = this._buffer.subarray(this._offset, this._offset + max_amount);
53
+ this._length -= max_amount;
54
+ this._offset += max_amount;
55
+ return globalThis.Array.from(values);
56
+ }
57
+ return [];
58
+ }
59
+ ensure_capacity(size) {
60
+ if (this.end + size > this._buffer.length) {
61
+ const larger_buffer = new Uint8Array((this.end + size) * 2);
62
+ larger_buffer.set(this._buffer.subarray(this._offset, this.end), 0);
63
+ this._buffer = larger_buffer;
64
+ this._offset = 0;
65
+ this._data_view = new DataView(this._buffer.buffer);
53
66
  }
54
67
  }
55
- send(channel, ...args) {
56
- const $ = this;
57
- system.runJob((function* () {
58
- const data = yield* $.MAYBE_ENCRYPT(args);
59
- yield* NET.emit('ipc', `${$._to}:${channel}:send`, [$._from, data]);
60
- })());
68
+ static from_uint8array(array) {
69
+ const byte_queue = new ByteQueue();
70
+ byte_queue._buffer = array;
71
+ byte_queue._length = array.length;
72
+ byte_queue._offset = 0;
73
+ byte_queue._data_view = new DataView(array.buffer);
74
+ return byte_queue;
61
75
  }
62
- invoke(channel, ...args) {
63
- const $ = this;
64
- system.runJob((function* () {
65
- const data = yield* $.MAYBE_ENCRYPT(args);
66
- yield* NET.emit('ipc', `${$._to}:${channel}:invoke`, [$._from, data]);
67
- })());
68
- return new Promise(resolve => {
69
- const terminate = NET.listen('ipc', `${$._from}:${channel}:handle`, function* (args) {
70
- if (args[0] === $._to) {
71
- const data = yield* $.MAYBE_DECRYPT(args);
72
- resolve(data);
73
- terminate();
74
- }
75
- });
76
- });
76
+ to_uint8array() {
77
+ return this._buffer.subarray(this._offset, this.end);
77
78
  }
78
- on(channel, listener) {
79
- const $ = this;
80
- const terminate = NET.listen('ipc', `${$._from}:${channel}:send`, function* (args) {
81
- if (args[0] === $._to) {
82
- const data = yield* $.MAYBE_DECRYPT(args);
83
- listener(...data);
79
+ }
80
+ PROTO.ByteQueue = ByteQueue;
81
+ let MIPS;
82
+ (function (MIPS) {
83
+ function* serialize(byte_queue) {
84
+ const uint8array = byte_queue.to_uint8array();
85
+ let str = '(0x';
86
+ for (let i = 0; i < uint8array.length; i++) {
87
+ const hex = uint8array[i].toString(16).padStart(2, '0').toUpperCase();
88
+ str += hex;
89
+ yield;
90
+ }
91
+ str += ')';
92
+ return str;
93
+ }
94
+ MIPS.serialize = serialize;
95
+ function* deserialize(str) {
96
+ if (str.startsWith('(0x') && str.endsWith(')')) {
97
+ const result = [];
98
+ const hex_str = str.slice(3, str.length - 1);
99
+ for (let i = 0; i < hex_str.length; i++) {
100
+ const hex = hex_str[i] + hex_str[++i];
101
+ result.push(parseInt(hex, 16));
102
+ yield;
84
103
  }
85
- });
86
- $._terminators.push(terminate);
87
- return terminate;
88
- }
89
- once(channel, listener) {
90
- const $ = this;
91
- const terminate = NET.listen('ipc', `${$._from}:${channel}:send`, function* (args) {
92
- if (args[0] === $._to) {
93
- const data = yield* $.MAYBE_DECRYPT(args);
94
- listener(...data);
95
- terminate();
104
+ return ByteQueue.from_uint8array(new Uint8Array(result));
105
+ }
106
+ return new ByteQueue();
107
+ }
108
+ MIPS.deserialize = deserialize;
109
+ })(MIPS = PROTO.MIPS || (PROTO.MIPS = {}));
110
+ PROTO.Void = {
111
+ *serialize() { },
112
+ *deserialize() { }
113
+ };
114
+ PROTO.Int8 = {
115
+ *serialize(value, stream) {
116
+ const length = 1;
117
+ stream.write(...globalThis.Array(length).fill(0));
118
+ stream.data_view.setInt8(stream.end - length, value);
119
+ },
120
+ *deserialize(stream) {
121
+ const value = stream.data_view.getInt8(stream.front);
122
+ stream.read(1);
123
+ return value;
124
+ }
125
+ };
126
+ PROTO.Int16 = {
127
+ *serialize(value, stream) {
128
+ const length = 2;
129
+ stream.write(...globalThis.Array(length).fill(0));
130
+ stream.data_view.setInt16(stream.end - length, value);
131
+ },
132
+ *deserialize(stream) {
133
+ const value = stream.data_view.getInt16(stream.front);
134
+ stream.read(2);
135
+ return value;
136
+ }
137
+ };
138
+ PROTO.Int32 = {
139
+ *serialize(value, stream) {
140
+ const length = 4;
141
+ stream.write(...globalThis.Array(length).fill(0));
142
+ stream.data_view.setInt32(stream.end - length, value);
143
+ },
144
+ *deserialize(stream) {
145
+ const value = stream.data_view.getInt32(stream.front);
146
+ stream.read(4);
147
+ return value;
148
+ }
149
+ };
150
+ PROTO.UInt8 = {
151
+ *serialize(value, stream) {
152
+ const length = 1;
153
+ stream.write(...globalThis.Array(length).fill(0));
154
+ stream.data_view.setUint8(stream.end - length, value);
155
+ },
156
+ *deserialize(stream) {
157
+ const value = stream.data_view.getUint8(stream.front);
158
+ stream.read(1);
159
+ return value;
160
+ }
161
+ };
162
+ PROTO.UInt16 = {
163
+ *serialize(value, stream) {
164
+ const length = 2;
165
+ stream.write(...globalThis.Array(length).fill(0));
166
+ stream.data_view.setUint16(stream.end - length, value);
167
+ },
168
+ *deserialize(stream) {
169
+ const value = stream.data_view.getUint16(stream.front);
170
+ stream.read(2);
171
+ return value;
172
+ }
173
+ };
174
+ PROTO.UInt32 = {
175
+ *serialize(value, stream) {
176
+ const length = 4;
177
+ stream.write(...globalThis.Array(length).fill(0));
178
+ stream.data_view.setUint32(stream.end - length, value);
179
+ },
180
+ *deserialize(stream) {
181
+ const value = stream.data_view.getUint32(stream.front);
182
+ stream.read(4);
183
+ return value;
184
+ }
185
+ };
186
+ PROTO.UVarInt32 = {
187
+ *serialize(value, stream) {
188
+ while (value >= 0x80) {
189
+ stream.write((value & 0x7f) | 0x80);
190
+ value >>= 7;
191
+ yield;
192
+ }
193
+ stream.write(value);
194
+ },
195
+ *deserialize(stream) {
196
+ let value = 0;
197
+ let size = 0;
198
+ let byte;
199
+ do {
200
+ byte = stream.read()[0];
201
+ value |= (byte & 0x7f) << (size * 7);
202
+ size += 1;
203
+ yield;
204
+ } while ((byte & 0x80) !== 0 && size < 10);
205
+ return value;
206
+ }
207
+ };
208
+ PROTO.Float32 = {
209
+ *serialize(value, stream) {
210
+ const length = 4;
211
+ stream.write(...globalThis.Array(length).fill(0));
212
+ stream.data_view.setFloat32(stream.end - length, value);
213
+ },
214
+ *deserialize(stream) {
215
+ const value = stream.data_view.getFloat32(stream.front);
216
+ stream.read(4);
217
+ return value;
218
+ }
219
+ };
220
+ PROTO.Float64 = {
221
+ *serialize(value, stream) {
222
+ const length = 8;
223
+ stream.write(...globalThis.Array(length).fill(0));
224
+ stream.data_view.setFloat64(stream.end - length, value);
225
+ },
226
+ *deserialize(stream) {
227
+ const value = stream.data_view.getFloat64(stream.front);
228
+ stream.read(8);
229
+ return value;
230
+ }
231
+ };
232
+ PROTO.String = {
233
+ *serialize(value, stream) {
234
+ yield* PROTO.UVarInt32.serialize(value.length, stream);
235
+ for (let i = 0; i < value.length; i++) {
236
+ const code = value.charCodeAt(i);
237
+ yield* PROTO.UVarInt32.serialize(code, stream);
238
+ }
239
+ },
240
+ *deserialize(stream) {
241
+ const length = yield* PROTO.UVarInt32.deserialize(stream);
242
+ let value = '';
243
+ for (let i = 0; i < length; i++) {
244
+ const code = yield* PROTO.UVarInt32.deserialize(stream);
245
+ value += globalThis.String.fromCharCode(code);
246
+ }
247
+ return value;
248
+ }
249
+ };
250
+ PROTO.Boolean = {
251
+ *serialize(value, stream) {
252
+ stream.write(value ? 1 : 0);
253
+ },
254
+ *deserialize(stream) {
255
+ const value = stream.read()[0];
256
+ return value === 1;
257
+ }
258
+ };
259
+ PROTO.UInt8Array = {
260
+ *serialize(value, stream) {
261
+ yield* PROTO.UVarInt32.serialize(value.length, stream);
262
+ stream.write(...value);
263
+ },
264
+ *deserialize(stream) {
265
+ const length = yield* PROTO.UVarInt32.deserialize(stream);
266
+ return new Uint8Array(stream.read(length));
267
+ }
268
+ };
269
+ PROTO.Date = {
270
+ *serialize(value, stream) {
271
+ yield* PROTO.Float64.serialize(value.getTime(), stream);
272
+ },
273
+ *deserialize(stream) {
274
+ return new globalThis.Date(yield* PROTO.Float64.deserialize(stream));
275
+ }
276
+ };
277
+ function Object(obj) {
278
+ return {
279
+ *serialize(value, stream) {
280
+ for (const key in obj) {
281
+ yield* obj[key].serialize(value[key], stream);
96
282
  }
97
- });
98
- $._terminators.push(terminate);
99
- return terminate;
100
- }
101
- handle(channel, listener) {
102
- const $ = this;
103
- const terminate = NET.listen('ipc', `${$._from}:${channel}:invoke`, function* (args) {
104
- if (args[0] === $._to) {
105
- const data = yield* $.MAYBE_DECRYPT(args);
106
- const result = listener(...data);
107
- const return_data = yield* $.MAYBE_ENCRYPT([result]);
108
- yield* NET.emit('ipc', `${$._to}:${channel}:handle`, [$._from, return_data]);
283
+ },
284
+ *deserialize(stream) {
285
+ const result = {};
286
+ for (const key in obj) {
287
+ result[key] = yield* obj[key].deserialize(stream);
109
288
  }
110
- });
111
- $._terminators.push(terminate);
112
- return terminate;
113
- }
289
+ return result;
290
+ }
291
+ };
114
292
  }
115
- IPC.Connection = Connection;
116
- class ConnectionManager {
117
- *MAYBE_ENCRYPT(args, encryption) {
118
- return encryption !== false ? yield* CRYPTO.encrypt(JSON.stringify(args), encryption) : args;
119
- }
120
- *MAYBE_DECRYPT(args, encryption) {
121
- return encryption !== false ? JSON.parse(yield* CRYPTO.decrypt(args[1], encryption)) : args[1];
122
- }
123
- get id() {
124
- return this._id;
125
- }
126
- constructor(id, force_encryption = false) {
127
- const $ = this;
128
- this._id = id;
129
- this._enc_map = new Map();
130
- this._con_map = new Map();
131
- this._enc_force = force_encryption;
132
- NET.listen('ipc', `${this._id}:handshake:SYN`, function* (args) {
133
- const secret = CRYPTO.make_secret(args[4]);
134
- const public_key = yield* CRYPTO.make_public(secret, args[4], args[3]);
135
- const enc = args[1] === 1 || $._enc_force ? yield* CRYPTO.make_shared(secret, args[2], args[3]) : false;
136
- $._enc_map.set(args[0], enc);
137
- yield* NET.emit('ipc', `${args[0]}:handshake:ACK`, [
138
- $._id,
139
- $._enc_force ? 1 : 0,
140
- public_key
141
- ]);
142
- });
143
- NET.listen('ipc', `${this._id}:terminate`, function* (args) {
144
- $._enc_map.delete(args[0]);
145
- });
146
- }
147
- connect(to, encrypted = false, timeout = 20) {
148
- const $ = this;
149
- return new Promise((resolve, reject) => {
150
- const con = this._con_map.get(to);
151
- if (con !== undefined) {
152
- con.terminate(false);
153
- resolve(con);
293
+ PROTO.Object = Object;
294
+ function Array(value) {
295
+ return {
296
+ *serialize(array, stream) {
297
+ yield* PROTO.UVarInt32.serialize(array.length, stream);
298
+ for (const item of array) {
299
+ yield* value.serialize(item, stream);
154
300
  }
155
- else {
156
- const secret = CRYPTO.make_secret();
157
- const enc_flag = encrypted ? 1 : 0;
158
- system.runJob((function* () {
159
- const public_key = yield* CRYPTO.make_public(secret);
160
- yield* NET.emit('ipc', `${to}:handshake:SYN`, [
161
- $._id,
162
- enc_flag,
163
- public_key,
164
- CRYPTO.PRIME,
165
- CRYPTO.MOD
166
- ]);
167
- })());
168
- function clear() {
169
- terminate();
170
- system.clearRun(timeout_handle);
171
- }
172
- const timeout_handle = system.runTimeout(() => {
173
- reject();
174
- clear();
175
- }, timeout);
176
- const terminate = NET.listen('ipc', `${this._id}:handshake:ACK`, function* (args) {
177
- if (args[0] === to) {
178
- const enc = args[1] === 1 || encrypted ? yield* CRYPTO.make_shared(secret, args[2]) : false;
179
- const new_con = new Connection($._id, to, enc);
180
- $._con_map.set(to, new_con);
181
- resolve(new_con);
182
- clear();
183
- }
184
- });
301
+ },
302
+ *deserialize(stream) {
303
+ const result = [];
304
+ const length = yield* PROTO.UVarInt32.deserialize(stream);
305
+ for (let i = 0; i < length; i++) {
306
+ result[i] = yield* value.deserialize(stream);
185
307
  }
186
- });
187
- }
188
- send(channel, ...args) {
189
- const $ = this;
190
- system.runJob((function* () {
191
- for (const [key, value] of $._enc_map) {
192
- const data = yield* $.MAYBE_ENCRYPT(args, value);
193
- yield* NET.emit('ipc', `${key}:${channel}:send`, [$._id, data]);
194
- }
195
- })());
196
- }
197
- invoke(channel, ...args) {
198
- const $ = this;
199
- const promises = [];
200
- for (const [key, value] of $._enc_map) {
201
- system.runJob((function* () {
202
- const data = yield* $.MAYBE_ENCRYPT(args, value);
203
- yield* NET.emit('ipc', `${key}:${channel}:invoke`, [$._id, data]);
204
- })());
205
- promises.push(new Promise(resolve => {
206
- const terminate = NET.listen('ipc', `${$._id}:${channel}:handle`, function* (args) {
207
- if (args[0] === key) {
208
- const data = yield* $.MAYBE_DECRYPT(args, value);
209
- resolve(data);
210
- terminate();
211
- }
212
- });
213
- }));
308
+ return result;
214
309
  }
215
- return promises;
216
- }
217
- on(channel, listener) {
218
- const $ = this;
219
- return NET.listen('ipc', `${$._id}:${channel}:send`, function* (args) {
220
- const enc = $._enc_map.get(args[0]);
221
- if (enc !== undefined) {
222
- const data = yield* $.MAYBE_DECRYPT(args, enc);
223
- listener(...data);
224
- }
225
- });
226
- }
227
- once(channel, listener) {
228
- const $ = this;
229
- const terminate = NET.listen('ipc', `${$._id}:${channel}:send`, function* (args) {
230
- const enc = $._enc_map.get(args[0]);
231
- if (enc !== undefined) {
232
- const data = yield* $.MAYBE_DECRYPT(args, enc);
233
- listener(...data);
234
- terminate();
310
+ };
311
+ }
312
+ PROTO.Array = Array;
313
+ function Tuple(...values) {
314
+ return {
315
+ *serialize(tuple, stream) {
316
+ for (let i = 0; i < values.length; i++) {
317
+ yield* values[i].serialize(tuple[i], stream);
235
318
  }
236
- });
237
- return terminate;
238
- }
239
- handle(channel, listener) {
240
- const $ = this;
241
- return NET.listen('ipc', `${$._id}:${channel}:invoke`, function* (args) {
242
- const enc = $._enc_map.get(args[0]);
243
- if (enc !== undefined) {
244
- const data = yield* $.MAYBE_DECRYPT(args, enc);
245
- const result = listener(...data);
246
- const return_data = yield* $.MAYBE_ENCRYPT([result], enc);
247
- yield* NET.emit('ipc', `${args[0]}:${channel}:handle`, [$._id, return_data]);
319
+ },
320
+ *deserialize(stream) {
321
+ const result = [];
322
+ for (let i = 0; i < values.length; i++) {
323
+ result[i] = yield* values[i].deserialize(stream);
248
324
  }
249
- });
250
- }
251
- }
252
- IPC.ConnectionManager = ConnectionManager;
253
- /** Sends a message with `args` to `channel` */
254
- function send(channel, ...args) {
255
- system.runJob(NET.emit('ipc', `${channel}:send`, args));
256
- }
257
- IPC.send = send;
258
- function invoke(channel, ...args) {
259
- system.runJob(NET.emit('ipc', `${channel}:invoke`, args));
260
- return new Promise(resolve => {
261
- const terminate = NET.listen('ipc', `${channel}:handle`, function* (args) {
262
- resolve(args);
263
- terminate();
264
- });
265
- });
266
- }
267
- IPC.invoke = invoke;
268
- /** Listens to `channel`. When a new message arrives, `listener` will be called with `listener(args)`. */
269
- function on(channel, listener) {
270
- return NET.listen('ipc', `${channel}:send`, function* (args) {
271
- listener(...args);
272
- });
273
- }
274
- IPC.on = on;
275
- /** Listens to `channel` once. When a new message arrives, `listener` will be called with `listener(args)`, and then removed. */
276
- function once(channel, listener) {
277
- const terminate = NET.listen('ipc', `${channel}:send`, function* (args) {
278
- listener(...args);
279
- terminate();
280
- });
281
- return terminate;
325
+ return result;
326
+ }
327
+ };
282
328
  }
283
- IPC.once = once;
284
- /** Adds a handler for an `invoke` IPC. This handler will be called whenever `invoke(channel, ...args)` is called */
285
- function handle(channel, listener) {
286
- return NET.listen('ipc', `${channel}:invoke`, function* (args) {
287
- const result = listener(...args);
288
- yield* NET.emit('ipc', `${channel}:handle`, result);
289
- });
329
+ PROTO.Tuple = Tuple;
330
+ function Optional(value) {
331
+ return {
332
+ *serialize(optional, stream) {
333
+ yield* PROTO.Boolean.serialize(value !== undefined, stream);
334
+ if (optional !== undefined) {
335
+ yield* value.serialize(optional, stream);
336
+ }
337
+ },
338
+ *deserialize(stream) {
339
+ const defined = yield* PROTO.Boolean.deserialize(stream);
340
+ if (defined) {
341
+ return yield* value.deserialize(stream);
342
+ }
343
+ return undefined;
344
+ }
345
+ };
290
346
  }
291
- IPC.handle = handle;
292
- })(IPC || (IPC = {}));
293
- export default IPC;
294
- var SERDE;
295
- (function (SERDE) {
296
- const INVALID_START_CODES = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57];
297
- const INVALID_CODES = [
298
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
299
- 31, 32, 33, 34, 35, 36, 37, 38, 39, 42, 43, 44, 47, 58, 59, 60, 61, 62, 63, 64, 91, 92, 93, 94, 96, 123, 124, 125,
300
- 126, 127
301
- ];
302
- const sequence_regex = /\?[0-9a-zA-Z.\-]{2}|[^?]+/g;
303
- const encoded_regex = /^\?[0-9a-zA-Z.\-]{2}$/;
304
- const BASE64 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-';
305
- function* b64_encode(char) {
306
- let encoded = '';
307
- for (let code = char.charCodeAt(0); code > 0; code = Math.floor(code / 64)) {
308
- encoded = BASE64[code % 64] + encoded;
309
- yield;
310
- }
311
- return encoded;
347
+ PROTO.Optional = Optional;
348
+ function Map(key, value) {
349
+ return {
350
+ *serialize(map, stream) {
351
+ yield* PROTO.UVarInt32.serialize(map.size, stream);
352
+ for (const [k, v] of map.entries()) {
353
+ yield* key.serialize(k, stream);
354
+ yield* value.serialize(v, stream);
355
+ }
356
+ },
357
+ *deserialize(stream) {
358
+ const size = yield* PROTO.UVarInt32.deserialize(stream);
359
+ const result = new globalThis.Map();
360
+ for (let i = 0; i < size; i++) {
361
+ const k = yield* key.deserialize(stream);
362
+ const v = yield* value.deserialize(stream);
363
+ result.set(k, v);
364
+ }
365
+ return result;
366
+ }
367
+ };
312
368
  }
313
- function* b64_decode(enc) {
314
- let code = 0;
315
- for (let i = 0; i < enc.length; i++) {
316
- code += 64 ** (enc.length - 1 - i) * BASE64.indexOf(enc[i]);
317
- yield;
318
- }
319
- return String.fromCharCode(code);
369
+ PROTO.Map = Map;
370
+ function Set(value) {
371
+ return {
372
+ *serialize(set, stream) {
373
+ yield* PROTO.UVarInt32.serialize(set.size, stream);
374
+ for (const [_, v] of set.entries()) {
375
+ yield* value.serialize(v, stream);
376
+ }
377
+ },
378
+ *deserialize(stream) {
379
+ const size = yield* PROTO.UVarInt32.deserialize(stream);
380
+ const result = new globalThis.Set();
381
+ for (let i = 0; i < size; i++) {
382
+ const v = yield* value.deserialize(stream);
383
+ result.add(v);
384
+ }
385
+ return result;
386
+ }
387
+ };
320
388
  }
321
- function* encode(str) {
322
- let result = '';
323
- for (let i = 0; i < str.length; i++) {
324
- const char = str.charAt(i);
325
- const char_code = char.charCodeAt(0);
326
- if ((i === 0 && INVALID_START_CODES.includes(char_code)) || INVALID_CODES.includes(char_code)) {
327
- result += `?${(yield* b64_encode(char)).padStart(2, '0')}`;
389
+ PROTO.Set = Set;
390
+ PROTO.Endpoint = PROTO.String;
391
+ PROTO.Header = PROTO.Object({
392
+ guid: PROTO.String,
393
+ encoding: PROTO.String,
394
+ index: PROTO.UVarInt32,
395
+ final: PROTO.Boolean
396
+ });
397
+ })(PROTO || (PROTO = {}));
398
+ export var NET;
399
+ (function (NET) {
400
+ const FRAG_MAX = 2048;
401
+ const ENCODING = 'mcbe-ipc:v3';
402
+ const ENDPOINTS = new Map();
403
+ function* serialize(byte_queue, max_size = Infinity) {
404
+ const uint8array = byte_queue.to_uint8array();
405
+ const result = [];
406
+ let acc_str = '';
407
+ let acc_size = 0;
408
+ for (let i = 0; i < uint8array.length; i++) {
409
+ const char_code = uint8array[i] | (uint8array[++i] << 8);
410
+ const utf16_size = char_code <= 0x7f ? 1 : char_code <= 0x7ff ? 2 : char_code <= 0xffff ? 3 : 4;
411
+ const char_size = char_code > 0xff ? utf16_size : 3;
412
+ if (acc_size + char_size > max_size) {
413
+ result.push(acc_str);
414
+ acc_str = '';
415
+ acc_size = 0;
328
416
  }
329
- else {
330
- result += char;
417
+ if (char_code > 0xff) {
418
+ acc_str += String.fromCharCode(char_code);
419
+ acc_size += utf16_size;
331
420
  }
332
- yield;
333
- }
334
- return result;
335
- }
336
- SERDE.encode = encode;
337
- function* decode(str) {
338
- let result = '';
339
- const seqs = str.match(sequence_regex) ?? [];
340
- for (let i = 0; i < seqs.length; i++) {
341
- const seq = seqs[i];
342
- if (seq.startsWith('?') && encoded_regex.test(seq))
343
- result += yield* b64_decode(seq.slice(1));
344
421
  else {
345
- result += seq;
422
+ acc_str += char_code.toString(16).padStart(2, '0').toUpperCase();
423
+ acc_size += 2;
346
424
  }
347
425
  yield;
348
426
  }
427
+ result.push(acc_str);
349
428
  return result;
350
429
  }
351
- SERDE.decode = decode;
352
- })(SERDE || (SERDE = {}));
353
- var CRYPTO;
354
- (function (CRYPTO) {
355
- CRYPTO.PRIME = 19893121;
356
- CRYPTO.MOD = 341;
357
- const to_HEX = (n) => n.toString(16).toUpperCase();
358
- const to_NUM = (h) => parseInt(h, 16);
359
- function* mod_exp(base, exp, mod) {
360
- let result = 1;
361
- let b = base % mod;
362
- for (let e = exp; e > 0; e = Math.floor(e / 2)) {
363
- if (e % 2 === 1) {
364
- result = (result * b) % mod;
430
+ NET.serialize = serialize;
431
+ function* deserialize(strings) {
432
+ const result = [];
433
+ for (let i = 0; i < strings.length; i++) {
434
+ const str = strings[i];
435
+ for (let j = 0; j < str.length; j++) {
436
+ const char_code = str.charCodeAt(j);
437
+ if (char_code <= 0xff) {
438
+ const hex = str[j] + str[++j];
439
+ const hex_code = parseInt(hex, 16);
440
+ result.push(hex_code & 0xff);
441
+ result.push(hex_code >> 8);
442
+ }
443
+ else {
444
+ result.push(char_code & 0xff);
445
+ result.push(char_code >> 8);
446
+ }
447
+ yield;
365
448
  }
366
- b = (b * b) % mod;
367
- yield;
368
- }
369
- return result;
370
- }
371
- function make_secret(mod = CRYPTO.MOD) {
372
- return Math.floor(Math.random() * (mod - 1)) + 1;
373
- }
374
- CRYPTO.make_secret = make_secret;
375
- function* make_public(secret, mod = CRYPTO.MOD, prime = CRYPTO.PRIME) {
376
- return to_HEX(yield* mod_exp(mod, secret, prime));
377
- }
378
- CRYPTO.make_public = make_public;
379
- function* make_shared(secret, other, prime = CRYPTO.PRIME) {
380
- return to_HEX(yield* mod_exp(to_NUM(other), secret, prime));
381
- }
382
- CRYPTO.make_shared = make_shared;
383
- function* encrypt(raw, key) {
384
- let encrypted = '';
385
- for (let i = 0; i < raw.length; i++) {
386
- encrypted += String.fromCharCode(raw.charCodeAt(i) ^ key.charCodeAt(i % key.length));
387
- yield;
388
- }
389
- return encrypted;
390
- }
391
- CRYPTO.encrypt = encrypt;
392
- function* decrypt(encrypted, key) {
393
- let decrypted = '';
394
- for (let i = 0; i < encrypted.length; i++) {
395
- decrypted += String.fromCharCode(encrypted.charCodeAt(i) ^ key.charCodeAt(i % key.length));
396
449
  yield;
397
450
  }
398
- return decrypted;
451
+ return PROTO.ByteQueue.from_uint8array(new Uint8Array(result));
399
452
  }
400
- CRYPTO.decrypt = decrypt;
401
- })(CRYPTO || (CRYPTO = {}));
402
- export var NET;
403
- (function (NET) {
404
- const FRAG_MAX = 2048;
405
- const namespace_listeners = new Map();
453
+ NET.deserialize = deserialize;
406
454
  system.afterEvents.scriptEventReceive.subscribe(event => {
407
455
  system.runJob((function* () {
408
- const ids = event.id.split(':');
409
- const namespace = yield* SERDE.decode(ids[0]);
410
- const listeners = namespace_listeners.get(namespace);
456
+ const [serialized_endpoint, serialized_header] = event.id.split(':');
457
+ const endpoint_stream = yield* PROTO.MIPS.deserialize(serialized_endpoint);
458
+ const endpoint = yield* PROTO.Endpoint.deserialize(endpoint_stream);
459
+ const listeners = ENDPOINTS.get(endpoint);
411
460
  if (event.sourceType === ScriptEventSource.Server && listeners) {
412
- const payload = Payload.fromString(yield* SERDE.decode(ids[1]));
461
+ const header_stream = yield* PROTO.MIPS.deserialize(serialized_header);
462
+ const header = yield* PROTO.Header.deserialize(header_stream);
413
463
  for (let i = 0; i < listeners.length; i++) {
414
- yield* listeners[i](payload, event.message);
464
+ yield* listeners[i](header, event.message);
415
465
  }
416
466
  }
417
467
  })());
418
468
  });
419
- function create_listener(namespace, listener) {
420
- let listeners = namespace_listeners.get(namespace);
469
+ function create_listener(endpoint, listener) {
470
+ let listeners = ENDPOINTS.get(endpoint);
421
471
  if (!listeners) {
422
472
  listeners = new Array();
423
- namespace_listeners.set(namespace, listeners);
473
+ ENDPOINTS.set(endpoint, listeners);
424
474
  }
425
475
  listeners.push(listener);
426
476
  return () => {
@@ -428,21 +478,10 @@ export var NET;
428
478
  if (idx !== -1)
429
479
  listeners.splice(idx, 1);
430
480
  if (listeners.length === 0) {
431
- namespace_listeners.delete(namespace);
481
+ ENDPOINTS.delete(endpoint);
432
482
  }
433
483
  };
434
484
  }
435
- let Payload;
436
- (function (Payload) {
437
- function toString(p) {
438
- return JSON.stringify(p);
439
- }
440
- Payload.toString = toString;
441
- function fromString(s) {
442
- return JSON.parse(s);
443
- }
444
- Payload.fromString = fromString;
445
- })(Payload || (Payload = {}));
446
485
  function generate_id() {
447
486
  const r = (Math.random() * 0x100000000) >>> 0;
448
487
  return ((r & 0xff).toString(16).padStart(2, '0') +
@@ -450,66 +489,93 @@ export var NET;
450
489
  ((r >> 16) & 0xff).toString(16).padStart(2, '0') +
451
490
  ((r >> 24) & 0xff).toString(16).padStart(2, '0')).toUpperCase();
452
491
  }
453
- function* emit(namespace, channel, args) {
454
- const id = generate_id();
455
- const enc_namespace = yield* SERDE.encode(namespace);
456
- const enc_args_str = yield* SERDE.encode(JSON.stringify(args));
457
- const RUN = function* (payload, data_str) {
458
- const enc_payload = yield* SERDE.encode(Payload.toString(payload));
459
- world.getDimension('overworld').runCommand(`scriptevent ${enc_namespace}:${enc_payload} ${data_str}`);
492
+ function* emit(endpoint, serializer, value) {
493
+ const guid = generate_id();
494
+ const endpoint_stream = new PROTO.ByteQueue();
495
+ yield* PROTO.Endpoint.serialize(endpoint, endpoint_stream);
496
+ const serialized_endpoint = yield* PROTO.MIPS.serialize(endpoint_stream);
497
+ const RUN = function* (header, serialized_packet) {
498
+ const header_stream = new PROTO.ByteQueue();
499
+ yield* PROTO.Header.serialize(header, header_stream);
500
+ const serialized_header = yield* PROTO.MIPS.serialize(header_stream);
501
+ world
502
+ .getDimension('overworld')
503
+ .runCommand(`scriptevent ${serialized_endpoint}:${serialized_header} ${serialized_packet}`);
460
504
  };
461
- let len = 0;
462
- let str = '';
463
- let str_size = 0;
464
- for (let i = 0; i < enc_args_str.length; i++) {
465
- const char = enc_args_str[i];
466
- const code = char.charCodeAt(0);
467
- const char_size = code <= 0x7f ? 1 : code <= 0x7ff ? 2 : code <= 0xffff ? 3 : 4;
468
- if (str_size + char_size < FRAG_MAX) {
469
- str += char;
470
- str_size += char_size;
471
- }
472
- else {
473
- yield* RUN([channel, id, len], str);
474
- len++;
475
- str = char;
476
- str_size = char_size;
477
- }
478
- yield;
505
+ const packet_stream = new PROTO.ByteQueue();
506
+ yield* serializer.serialize(value, packet_stream);
507
+ const serialized_packets = yield* serialize(packet_stream, FRAG_MAX);
508
+ for (let i = 0; i < serialized_packets.length; i++) {
509
+ const serialized_packet = serialized_packets[i];
510
+ yield* RUN({ guid, encoding: ENCODING, index: i, final: i === serialized_packets.length - 1 }, serialized_packet);
479
511
  }
480
- yield* RUN(len === 0 ? [channel, id] : [channel, id, len, 1], str);
481
512
  }
482
513
  NET.emit = emit;
483
- function listen(namespace, channel, callback) {
514
+ function listen(endpoint, serializer, callback) {
484
515
  const buffer = new Map();
485
- const listener = function* ([p_channel, p_id, p_index, p_final], data) {
486
- if (p_channel === channel) {
487
- if (p_index === undefined) {
488
- yield* callback(JSON.parse(yield* SERDE.decode(data)));
489
- }
490
- else {
491
- let fragment = buffer.get(p_id);
492
- if (!fragment) {
493
- fragment = { size: -1, data_strs: [], data_size: 0 };
494
- buffer.set(p_id, fragment);
495
- }
496
- if (p_final === 1)
497
- fragment.size = p_index + 1;
498
- fragment.data_strs[p_index] = data;
499
- fragment.data_size += p_index + 1;
500
- if (fragment.size !== -1 && fragment.data_size === (fragment.size * (fragment.size + 1)) / 2) {
501
- let full_str = '';
502
- for (let i = 0; i < fragment.data_strs.length; i++) {
503
- full_str += fragment.data_strs[i];
504
- yield;
505
- }
506
- yield* callback(JSON.parse(yield* SERDE.decode(full_str)));
507
- buffer.delete(p_id);
508
- }
509
- }
516
+ const listener = function* (payload, serialized_packet) {
517
+ let fragment = buffer.get(payload.guid);
518
+ if (!fragment) {
519
+ fragment = { size: -1, serialized_packets: [], data_size: 0 };
520
+ buffer.set(payload.guid, fragment);
521
+ }
522
+ if (payload.final) {
523
+ fragment.size = payload.index + 1;
524
+ }
525
+ fragment.serialized_packets[payload.index] = serialized_packet;
526
+ fragment.data_size += payload.index + 1;
527
+ if (fragment.size !== -1 && fragment.data_size === (fragment.size * (fragment.size + 1)) / 2) {
528
+ const stream = yield* deserialize(fragment.serialized_packets);
529
+ const value = yield* serializer.deserialize(stream);
530
+ yield* callback(value);
531
+ buffer.delete(payload.guid);
510
532
  }
511
533
  };
512
- return create_listener(namespace, listener);
534
+ return create_listener(endpoint, listener);
513
535
  }
514
536
  NET.listen = listen;
515
537
  })(NET || (NET = {}));
538
+ export var IPC;
539
+ (function (IPC) {
540
+ /** Sends a message with `args` to `channel` */
541
+ function send(channel, serializer, value) {
542
+ system.runJob(NET.emit(`ipc:${channel}:send`, serializer, value));
543
+ }
544
+ IPC.send = send;
545
+ /** Sends an `invoke` message through IPC, and expects a result asynchronously. */
546
+ function invoke(channel, serializer, value, deserializer) {
547
+ system.runJob(NET.emit(`ipc:${channel}:invoke`, serializer, value));
548
+ return new Promise(resolve => {
549
+ const terminate = NET.listen(`ipc:${channel}:handle`, deserializer, function* (value) {
550
+ resolve(value);
551
+ terminate();
552
+ });
553
+ });
554
+ }
555
+ IPC.invoke = invoke;
556
+ /** Listens to `channel`. When a new message arrives, `listener` will be called with `listener(args)`. */
557
+ function on(channel, deserializer, listener) {
558
+ return NET.listen(`ipc:${channel}:send`, deserializer, function* (value) {
559
+ listener(value);
560
+ });
561
+ }
562
+ IPC.on = on;
563
+ /** Listens to `channel` once. When a new message arrives, `listener` will be called with `listener(args)`, and then removed. */
564
+ function once(channel, deserializer, listener) {
565
+ const terminate = NET.listen(`ipc:${channel}:send`, deserializer, function* (value) {
566
+ listener(value);
567
+ terminate();
568
+ });
569
+ return terminate;
570
+ }
571
+ IPC.once = once;
572
+ /** Adds a handler for an `invoke` IPC. This handler will be called whenever `invoke(channel, ...args)` is called */
573
+ function handle(channel, deserializer, serializer, listener) {
574
+ return NET.listen(`ipc:${channel}:invoke`, deserializer, function* (value) {
575
+ const result = listener(value);
576
+ yield* NET.emit(`ipc:${channel}:handle`, serializer, result);
577
+ });
578
+ }
579
+ IPC.handle = handle;
580
+ })(IPC || (IPC = {}));
581
+ export default IPC;