From 4f1d5d6ab1d74ed4ba9f2b20076366eac16f2862 Mon Sep 17 00:00:00 2001 From: ForestOfLight Date: Sat, 30 May 2026 00:48:41 +0200 Subject: [PATCH] chore: change AddonAPIKit to single-file distro --- packs/BP/scripts/API/ConstructAPI.js | 2 +- .../API/controllers/BuildersController.js | 2 +- .../API/controllers/InstancesController.js | 2 +- packs/BP/scripts/API/models/BuildersModel.js | 2 +- packs/BP/scripts/API/models/InstancesModel.js | 2 +- packs/BP/scripts/lib/AddonAPIKit.js | 813 ++++++++++++++++++ .../scripts/lib/AddonAPIKit/APIController.js | 13 - packs/BP/scripts/lib/AddonAPIKit/APIModels.js | 20 - packs/BP/scripts/lib/AddonAPIKit/AddonAPI.js | 92 -- .../scripts/lib/AddonAPIKit/AddonAPICaller.js | 7 - .../BP/scripts/lib/AddonAPIKit/AddonAPIKit.js | 8 - .../lib/AddonAPIKit/Errors/APICallerError.js | 11 - .../lib/AddonAPIKit/Errors/APIErrorEnum.js | 6 - .../lib/AddonAPIKit/Errors/APIServerError.js | 10 - .../Errors/APIVersionMismatchError.js | 6 - .../scripts/lib/AddonAPIKit/MCBE-IPC/ipc.d.ts | 119 --- .../scripts/lib/AddonAPIKit/MCBE-IPC/ipc.js | 658 -------------- 17 files changed, 818 insertions(+), 955 deletions(-) create mode 100644 packs/BP/scripts/lib/AddonAPIKit.js delete mode 100644 packs/BP/scripts/lib/AddonAPIKit/APIController.js delete mode 100644 packs/BP/scripts/lib/AddonAPIKit/APIModels.js delete mode 100644 packs/BP/scripts/lib/AddonAPIKit/AddonAPI.js delete mode 100644 packs/BP/scripts/lib/AddonAPIKit/AddonAPICaller.js delete mode 100644 packs/BP/scripts/lib/AddonAPIKit/AddonAPIKit.js delete mode 100644 packs/BP/scripts/lib/AddonAPIKit/Errors/APICallerError.js delete mode 100644 packs/BP/scripts/lib/AddonAPIKit/Errors/APIErrorEnum.js delete mode 100644 packs/BP/scripts/lib/AddonAPIKit/Errors/APIServerError.js delete mode 100644 packs/BP/scripts/lib/AddonAPIKit/Errors/APIVersionMismatchError.js delete mode 100644 packs/BP/scripts/lib/AddonAPIKit/MCBE-IPC/ipc.d.ts delete mode 100644 packs/BP/scripts/lib/AddonAPIKit/MCBE-IPC/ipc.js diff --git a/packs/BP/scripts/API/ConstructAPI.js b/packs/BP/scripts/API/ConstructAPI.js index f29736d..f27d9f9 100644 --- a/packs/BP/scripts/API/ConstructAPI.js +++ b/packs/BP/scripts/API/ConstructAPI.js @@ -1,4 +1,4 @@ -import { AddonAPI } from "../lib/AddonAPIKit/AddonAPIKit"; +import { AddonAPI } from "../lib/AddonAPIKit"; import { PACK_IDENTIFIER } from "../consts"; import { InstancesController } from "./controllers/InstancesController"; import { structureCollection } from "../classes/Structure/StructureCollection"; diff --git a/packs/BP/scripts/API/controllers/BuildersController.js b/packs/BP/scripts/API/controllers/BuildersController.js index ddea020..20d2032 100644 --- a/packs/BP/scripts/API/controllers/BuildersController.js +++ b/packs/BP/scripts/API/controllers/BuildersController.js @@ -1,5 +1,5 @@ import { BuilderNotFoundError } from "../../classes/Errors/BuilderNotFoundError"; -import { APICallerError } from "../../lib/AddonAPIKit/AddonAPIKit"; +import { APICallerError } from "../../lib/AddonAPIKit"; import { BuilderIdParameterModel } from "../models/BuildersModel"; export class BuildersController extends APIController { diff --git a/packs/BP/scripts/API/controllers/InstancesController.js b/packs/BP/scripts/API/controllers/InstancesController.js index e84d568..ba97d39 100644 --- a/packs/BP/scripts/API/controllers/InstancesController.js +++ b/packs/BP/scripts/API/controllers/InstancesController.js @@ -1,7 +1,7 @@ import { InstanceExistsError } from "../../classes/Errors/InstanceExistsError"; import { InstanceNotFoundError } from "../../classes/Errors/InstanceNotFoundError"; import { StructureNotFoundError } from "../../classes/Errors/StructureNotFoundError"; -import { APICallerError, VoidModel } from "../../lib/AddonAPIKit/AddonAPIKit"; +import { APICallerError, VoidModel } from "../../lib/AddonAPIKit"; import { AddInstanceParameterModel, InstanceModel, InstanceNameParameterModel, InstancesModel, StructureMaterialsModel } from "../models/InstancesModel"; export class InstancesController extends APIController { diff --git a/packs/BP/scripts/API/models/BuildersModel.js b/packs/BP/scripts/API/models/BuildersModel.js index 36f2b3d..07bb00c 100644 --- a/packs/BP/scripts/API/models/BuildersModel.js +++ b/packs/BP/scripts/API/models/BuildersModel.js @@ -1,4 +1,4 @@ -import { PROTO } from "../../lib/AddonAPIKit/AddonAPIKit"; +import { PROTO } from "../../lib/AddonAPIKit"; export const BuilderModel = PROTO.Object({ playerId: PROTO.String, diff --git a/packs/BP/scripts/API/models/InstancesModel.js b/packs/BP/scripts/API/models/InstancesModel.js index 1382190..cc16bd5 100644 --- a/packs/BP/scripts/API/models/InstancesModel.js +++ b/packs/BP/scripts/API/models/InstancesModel.js @@ -1,4 +1,4 @@ -import { PROTO } from '../../lib/AddonAPIKit/AddonAPIKit'; +import { PROTO } from '../../lib/AddonAPIKit'; const LocationModel = PROTO.Object({ x: PROTO.Float64, diff --git a/packs/BP/scripts/lib/AddonAPIKit.js b/packs/BP/scripts/lib/AddonAPIKit.js new file mode 100644 index 0000000..97670ca --- /dev/null +++ b/packs/BP/scripts/lib/AddonAPIKit.js @@ -0,0 +1,813 @@ +/** @license MIT + * AddonAPIKit - Copyright (c) 2026 ForestOfLight + * MCBE-IPC - Copyright (c) 2026 OmniacDev + * See LICENSE for details. + */ + +// MCBE-IPC/ipc.js +import { ScriptEventSource, system } from "@minecraft/server"; +var UTIL; +(function(UTIL2) { + function generate_id() { + const r = Math.random() * 4294967296 >>> 0; + return r.toString(16).padStart(8, "0").toUpperCase(); + } + UTIL2.generate_id = generate_id; +})(UTIL || (UTIL = {})); +var PROTO; +(function(PROTO2) { + class Buffer { + get end() { + return this._length + this._offset; + } + get front() { + return this._offset; + } + get data_view() { + return this._data_view; + } + constructor(size = 256) { + this._buffer = new Uint8Array(size); + this._data_view = new DataView(this._buffer.buffer); + this._length = 0; + this._offset = 0; + } + reserve(amount) { + this.ensure_capacity(amount); + const end = this.end; + this._length += amount; + return end; + } + consume(amount) { + if (amount > this._length) + throw new Error("not enough bytes"); + const front = this.front; + this._length -= amount; + this._offset += amount; + return front; + } + write(input) { + if (typeof input === "number") { + const offset = this.reserve(1); + this._buffer[offset] = input; + } else { + const offset = this.reserve(input.length); + this._buffer.set(input, offset); + } + } + read(amount) { + if (amount === void 0) { + const offset = this.consume(1); + return this._buffer[offset]; + } else { + const offset = this.consume(amount); + return this._buffer.slice(offset, offset + amount); + } + } + ensure_capacity(size) { + if (this.end + size > this._buffer.length) { + const larger_buffer = new Uint8Array((this.end + size) * 2); + larger_buffer.set(this._buffer.subarray(this._offset, this.end), 0); + this._buffer = larger_buffer; + this._offset = 0; + this._data_view = new DataView(this._buffer.buffer); + } + } + static from_uint8array(array) { + const buffer = new Buffer(); + buffer._buffer = array; + buffer._length = array.length; + buffer._offset = 0; + buffer._data_view = new DataView(array.buffer); + return buffer; + } + to_uint8array() { + return this._buffer.subarray(this._offset, this.end); + } + } + PROTO2.Buffer = Buffer; + let MIPS; + (function(MIPS2) { + function is_valid(str) { + return str.startsWith("(0x") && str.endsWith(")"); + } + MIPS2.is_valid = is_valid; + function* serialize(stream) { + const uint8array = stream.to_uint8array(); + let str = "(0x"; + for (let i = 0; i < uint8array.length; i++) { + const hex = uint8array[i].toString(16).padStart(2, "0").toUpperCase(); + str += hex; + yield; + } + str += ")"; + return str; + } + MIPS2.serialize = serialize; + function* deserialize(str) { + if (is_valid(str)) { + const buffer = new Buffer(); + const hex_str = str.slice(3, str.length - 1); + for (let i = 0; i < hex_str.length; i++) { + const hex = hex_str[i] + hex_str[++i]; + buffer.write(parseInt(hex, 16)); + yield; + } + return buffer; + } + return new Buffer(); + } + MIPS2.deserialize = deserialize; + })(MIPS = PROTO2.MIPS || (PROTO2.MIPS = {})); + PROTO2.Void = { + *serialize() { + }, + *deserialize() { + } + }; + PROTO2.Null = { + *serialize() { + }, + *deserialize() { + return null; + } + }; + PROTO2.Undefined = { + *serialize() { + }, + *deserialize() { + return void 0; + } + }; + PROTO2.Int8 = { + *serialize(value, stream) { + stream.data_view.setInt8(stream.reserve(1), value); + }, + *deserialize(stream) { + return stream.data_view.getInt8(stream.consume(1)); + } + }; + PROTO2.Int16 = { + *serialize(value, stream) { + stream.data_view.setInt16(stream.reserve(2), value); + }, + *deserialize(stream) { + return stream.data_view.getInt16(stream.consume(2)); + } + }; + PROTO2.Int32 = { + *serialize(value, stream) { + stream.data_view.setInt32(stream.reserve(4), value); + }, + *deserialize(stream) { + return stream.data_view.getInt32(stream.consume(4)); + } + }; + PROTO2.UInt8 = { + *serialize(value, stream) { + stream.data_view.setUint8(stream.reserve(1), value); + }, + *deserialize(stream) { + return stream.data_view.getUint8(stream.consume(1)); + } + }; + PROTO2.UInt16 = { + *serialize(value, stream) { + stream.data_view.setUint16(stream.reserve(2), value); + }, + *deserialize(stream) { + return stream.data_view.getUint16(stream.consume(2)); + } + }; + PROTO2.UInt32 = { + *serialize(value, stream) { + stream.data_view.setUint32(stream.reserve(4), value); + }, + *deserialize(stream) { + return stream.data_view.getUint32(stream.consume(4)); + } + }; + PROTO2.UVarInt32 = { + *serialize(value, stream) { + value >>>= 0; + while (value >= 128) { + stream.write(value & 127 | 128); + value >>>= 7; + yield; + } + stream.write(value); + }, + *deserialize(stream) { + let value = 0; + for (let size = 0; size < 5; size++) { + const byte = stream.read(); + value |= (byte & 127) << size * 7; + yield; + if ((byte & 128) == 0) + break; + } + return value >>> 0; + } + }; + PROTO2.VarInt32 = { + *serialize(value, stream) { + const zigzag = value << 1 ^ value >> 31; + yield* PROTO2.UVarInt32.serialize(zigzag, stream); + }, + *deserialize(stream) { + const zigzag = yield* PROTO2.UVarInt32.deserialize(stream); + return zigzag >>> 1 ^ -(zigzag & 1); + } + }; + PROTO2.Float32 = { + *serialize(value, stream) { + stream.data_view.setFloat32(stream.reserve(4), value); + }, + *deserialize(stream) { + return stream.data_view.getFloat32(stream.consume(4)); + } + }; + PROTO2.Float64 = { + *serialize(value, stream) { + stream.data_view.setFloat64(stream.reserve(8), value); + }, + *deserialize(stream) { + return stream.data_view.getFloat64(stream.consume(8)); + } + }; + PROTO2.String = { + *serialize(value, stream) { + yield* PROTO2.UVarInt32.serialize(value.length, stream); + for (let i = 0; i < value.length; i++) { + const code = value.charCodeAt(i); + yield* PROTO2.UVarInt32.serialize(code, stream); + } + }, + *deserialize(stream) { + const length = yield* PROTO2.UVarInt32.deserialize(stream); + let value = ""; + for (let i = 0; i < length; i++) { + const code = yield* PROTO2.UVarInt32.deserialize(stream); + value += globalThis.String.fromCharCode(code); + } + return value; + } + }; + PROTO2.Boolean = { + *serialize(value, stream) { + stream.write(value ? 1 : 0); + }, + *deserialize(stream) { + return stream.read() !== 0; + } + }; + PROTO2.UInt8Array = { + *serialize(value, stream) { + yield* PROTO2.UVarInt32.serialize(value.length, stream); + stream.write(value); + }, + *deserialize(stream) { + const length = yield* PROTO2.UVarInt32.deserialize(stream); + return stream.read(length); + } + }; + PROTO2.Date = { + *serialize(value, stream) { + yield* PROTO2.Float64.serialize(value.getTime(), stream); + }, + *deserialize(stream) { + return new globalThis.Date(yield* PROTO2.Float64.deserialize(stream)); + } + }; + function Object2(s) { + return { + *serialize(value, stream) { + for (const key in s) { + yield* s[key].serialize(value[key], stream); + } + }, + *deserialize(stream) { + const result = {}; + for (const key in s) { + result[key] = yield* s[key].deserialize(stream); + } + return result; + } + }; + } + PROTO2.Object = Object2; + function Array2(s) { + return { + *serialize(value, stream) { + yield* PROTO2.UVarInt32.serialize(value.length, stream); + for (const item of value) { + yield* s.serialize(item, stream); + } + }, + *deserialize(stream) { + const result = []; + const length = yield* PROTO2.UVarInt32.deserialize(stream); + for (let i = 0; i < length; i++) { + result[i] = yield* s.deserialize(stream); + } + return result; + } + }; + } + PROTO2.Array = Array2; + function Tuple(...s) { + return { + *serialize(value, stream) { + for (let i = 0; i < s.length; i++) { + yield* s[i].serialize(value[i], stream); + } + }, + *deserialize(stream) { + const result = []; + for (let i = 0; i < s.length; i++) { + result[i] = yield* s[i].deserialize(stream); + } + return result; + } + }; + } + PROTO2.Tuple = Tuple; + function Optional(s) { + return { + *serialize(value, stream) { + const def = value !== void 0; + yield* PROTO2.Boolean.serialize(def, stream); + if (def) + yield* s.serialize(value, stream); + }, + *deserialize(stream) { + const def = yield* PROTO2.Boolean.deserialize(stream); + if (def) + return yield* s.deserialize(stream); + return void 0; + } + }; + } + PROTO2.Optional = Optional; + function Map2(kS, vS) { + return { + *serialize(value, stream) { + yield* PROTO2.UVarInt32.serialize(value.size, stream); + for (const [k, v] of value) { + yield* kS.serialize(k, stream); + yield* vS.serialize(v, stream); + } + }, + *deserialize(stream) { + const size = yield* PROTO2.UVarInt32.deserialize(stream); + const result = new globalThis.Map(); + for (let i = 0; i < size; i++) { + const k = yield* kS.deserialize(stream); + const v = yield* vS.deserialize(stream); + result.set(k, v); + } + return result; + } + }; + } + PROTO2.Map = Map2; + function Set(s) { + return { + *serialize(set, stream) { + yield* PROTO2.UVarInt32.serialize(set.size, stream); + for (const v of set) { + yield* s.serialize(v, stream); + } + }, + *deserialize(stream) { + const size = yield* PROTO2.UVarInt32.deserialize(stream); + const result = new globalThis.Set(); + for (let i = 0; i < size; i++) { + const v = yield* s.deserialize(stream); + result.add(v); + } + return result; + } + }; + } + PROTO2.Set = Set; + function Cached(s, depth = 16) { + const cache = new globalThis.Map(); + return { + *serialize(value, stream) { + const hit = cache.get(value); + if (hit !== void 0) { + stream.write(hit); + cache.delete(value); + cache.set(value, hit); + } else { + const buffer = new PROTO2.Buffer(); + yield* s.serialize(value, buffer); + const bytes = buffer.to_uint8array(); + stream.write(bytes); + cache.set(value, bytes); + if (cache.size > depth) { + const first = cache.keys().next().value; + cache.delete(first); + } + } + }, + *deserialize(stream) { + return yield* s.deserialize(stream); + } + }; + } + PROTO2.Cached = Cached; +})(PROTO || (PROTO = {})); +var NET; +(function(NET2) { + const Endpoint = PROTO.String; + const Meta = PROTO.Object({ + guid: PROTO.String, + signature: PROTO.String + }); + const Header = PROTO.Object({ + meta: Meta, + index: PROTO.UVarInt32, + final: PROTO.Boolean + }); + const LISTENERS = /* @__PURE__ */ new Map(); + NET2.SIGNATURE = "mcbe-ipc:v3"; + NET2.FRAG_MAX = 2048; + function* serialize(buffer, max_size = Infinity) { + const uint8array = buffer.to_uint8array(); + const result = []; + let acc_str = ""; + let acc_size = 0; + for (let i = 0; i < uint8array.length; i++) { + const char_code = uint8array[i] | uint8array[++i] << 8; + const utf16_size = char_code <= 127 ? 1 : char_code <= 2047 ? 2 : char_code <= 65535 ? 3 : 4; + const char_size = char_code > 255 ? utf16_size : 2; + if (acc_size + char_size > max_size) { + result.push(acc_str); + acc_str = ""; + acc_size = 0; + } + if (char_code > 255) { + acc_str += String.fromCharCode(char_code); + acc_size += utf16_size; + } else { + acc_str += char_code.toString(16).padStart(2, "0").toUpperCase(); + acc_size += 2; + } + yield; + } + result.push(acc_str); + return result; + } + NET2.serialize = serialize; + function* deserialize(strings) { + const buffer = new PROTO.Buffer(); + for (let i = 0; i < strings.length; i++) { + const str = strings[i]; + for (let j = 0; j < str.length; j++) { + const char_code = str.charCodeAt(j); + if (char_code <= 255) { + const hex = str[j] + str[++j]; + const hex_code = parseInt(hex, 16); + buffer.write(hex_code & 255); + buffer.write(hex_code >> 8); + } else { + buffer.write(char_code & 255); + buffer.write(char_code >> 8); + } + yield; + } + yield; + } + return buffer; + } + NET2.deserialize = deserialize; + system.afterEvents.scriptEventReceive.subscribe((event) => { + system.runJob((function* () { + if (event.sourceType !== ScriptEventSource.Server) + return; + const [serialized_endpoint, serialized_header] = event.id.split(":"); + if (!PROTO.MIPS.is_valid(serialized_endpoint)) + return; + const endpoint_stream = yield* PROTO.MIPS.deserialize(serialized_endpoint); + const endpoint = yield* Endpoint.deserialize(endpoint_stream); + const listeners = LISTENERS.get(endpoint); + if (listeners !== void 0 && PROTO.MIPS.is_valid(serialized_header)) { + const header_stream = yield* PROTO.MIPS.deserialize(serialized_header); + const header = yield* Header.deserialize(header_stream); + for (const listener of [...listeners]) { + try { + yield* listener(header, event.message); + } catch (e) { + console.error(`[MCBE-IPC] listener error while handling packet on "${endpoint}":`, e); + } + } + } + })()); + }); + function register(endpoint, listener) { + let listeners = LISTENERS.get(endpoint); + if (listeners === void 0) { + listeners = new Array(); + LISTENERS.set(endpoint, listeners); + } + listeners.push(listener); + return () => { + const idx = listeners.indexOf(listener); + if (idx !== -1) + listeners.splice(idx, 1); + if (listeners.length === 0) { + LISTENERS.delete(endpoint); + } + }; + } + function* emit(endpoint, serializer, value, options) { + const guid = options?.metaOverride?.guid ?? UTIL.generate_id(); + const signature = options?.metaOverride?.signature ?? NET2.SIGNATURE; + const endpoint_stream = new PROTO.Buffer(); + yield* Endpoint.serialize(endpoint, endpoint_stream); + const serialized_endpoint = yield* PROTO.MIPS.serialize(endpoint_stream); + const packet_stream = new PROTO.Buffer(); + yield* serializer.serialize(value, packet_stream); + const serialized_packets = yield* serialize(packet_stream, NET2.FRAG_MAX); + for (let i = 0; i < serialized_packets.length; i++) { + const serialized_packet = serialized_packets[i]; + const header = { + meta: { guid, signature }, + index: i, + final: i === serialized_packets.length - 1 + }; + const header_stream = new PROTO.Buffer(); + yield* Header.serialize(header, header_stream); + const serialized_header = yield* PROTO.MIPS.serialize(header_stream); + system.sendScriptEvent(`${serialized_endpoint}:${serialized_header}`, serialized_packet); + } + } + NET2.emit = emit; + function listen(endpoint, deserializer, callback, options) { + const buffer = /* @__PURE__ */ new Map(); + const listener = function* (header, fragment) { + let packet = buffer.get(header.meta.guid); + if (packet === void 0) { + if (options?.filter?.(header.meta) === false) + return; + packet = { size: -1, fragments: [], received: 0 }; + buffer.set(header.meta.guid, packet); + } + if (header.final) { + packet.size = header.index + 1; + } + if (packet.fragments[header.index] === void 0) { + packet.fragments[header.index] = fragment; + packet.received++; + } else { + throw new Error(`received duplicate fragment ${header.index} for packet ${header.meta.guid}`); + } + if (packet.size !== -1 && packet.size === packet.received) { + const stream = yield* deserialize(packet.fragments); + const value = yield* deserializer.deserialize(stream); + yield* callback(value, header.meta); + buffer.delete(header.meta.guid); + } + }; + return register(endpoint, listener); + } + NET2.listen = listen; +})(NET || (NET = {})); +var IPC; +(function(IPC2) { + function send(channel, serializer, value) { + system.runJob(NET.emit(`ipc:${channel}:send`, serializer, value)); + } + IPC2.send = send; + function invoke(channel, serializer, value, deserializer) { + const id = UTIL.generate_id(); + return new Promise((resolve) => { + const terminate = NET.listen(`ipc:${channel}:handle`, deserializer, function* (value2, meta) { + if (meta.signature.includes(`+correlation`) && meta.guid !== id) + return; + resolve(value2); + terminate(); + }, { + filter: (meta) => !meta.signature.includes(`+correlation`) || meta.guid === id + }); + system.runJob(NET.emit(`ipc:${channel}:invoke`, serializer, value, { + metaOverride: { + guid: id, + signature: `${NET.SIGNATURE}+correlation` + } + })); + }); + } + IPC2.invoke = invoke; + function on(channel, deserializer, listener) { + return NET.listen(`ipc:${channel}:send`, deserializer, function* (value) { + listener(value); + }); + } + IPC2.on = on; + function once(channel, deserializer, listener) { + const terminate = NET.listen(`ipc:${channel}:send`, deserializer, function* (value) { + listener(value); + terminate(); + }); + return terminate; + } + IPC2.once = once; + function handle(channel, deserializer, serializer, listener) { + return NET.listen(`ipc:${channel}:invoke`, deserializer, function* (value, meta) { + const result = listener(value); + yield* NET.emit(`ipc:${channel}:handle`, serializer, result, { + metaOverride: meta.signature.includes(`+correlation`) ? { + guid: meta.guid, + signature: `${NET.SIGNATURE}+correlation` + } : void 0 + }); + }); + } + IPC2.handle = handle; +})(IPC || (IPC = {})); + +// Errors/APIErrorEnum.js +var APIErrorEnum = Object.freeze({ + Unknown: 0, + Success: 1, + Caller: 2, + Server: 3 +}); + +// Errors/APICallerError.js +var APICallerError = class extends Error { + constructor(error) { + super(error.message); + this.errorName = error.name; + this.errorMessage = error.message; + this.errorCode = APIErrorEnum.Caller; + this.name = "APICallerError"; + } +}; + +// Errors/APIServerError.js +var APIServerError = class extends Error { + constructor(error) { + super(error.message); + this.thrownError = error; + this.errorCode = APIErrorEnum.Server; + this.name = "APIServerError"; + } +}; + +// Errors/APIVersionMismatchError.js +var APIVersionMismatchError = class extends Error { + constructor(serverApiVersion, callerApiVersion) { + super(`API version numbers do not match (${callerApiVersion} != ${serverApiVersion}). Please use API version ${serverApiVersion}.`); + this.name = "APIVersionMismatchError"; + } +}; + +// APIModels.js +var VoidModel = PROTO.Void; +var ErrorModel = PROTO.Optional(PROTO.Object({ + code: PROTO.Int8, + name: PROTO.Optional(PROTO.String), + message: PROTO.Optional(PROTO.String) +})); +var ReturnModelShell = { + apiVersion: PROTO.String, + data: void 0, + error: ErrorModel +}; +var CallModelShell = { + apiVersion: PROTO.String, + parameterMap: void 0 +}; + +// AddonAPI.js +var AddonAPI = class { + #name; + #version; + constructor(name, version) { + this.#name = name; + this.#version = version; + } + get name() { + return this.#name; + } + get version() { + return this.#version; + } + get endpointBase() { + return this.#name + ":"; + } + setupController(apiController) { + for (const [endpoint, features] of Object.entries(apiController.endpoints)) { + const { callback, parameterModel, returnModel } = features; + const boundCallback = callback.bind(apiController); + this.#setupEndpoint(endpoint, boundCallback, parameterModel, returnModel); + } + } + #setupEndpoint(endpoint, callback, parameterModel, returnDataModel) { + const returnPacketModel = this.#resolveReturnModel(returnDataModel); + const endpointPath = this.endpointBase + endpoint; + IPC.handle(endpointPath, parameterModel, returnPacketModel, (callPacket) => { + const apiVersion = callPacket.apiVersion; + const parameters = Object.values(callPacket.parameterMap); + return this.#handleCallback(apiVersion, callback, parameters); + }); + } + #handleCallback(apiVersion, callback, parameters) { + try { + this.#assertVersionsMatch(apiVersion); + const returnValue = callback(...parameters); + return this.#bundleReturnPacket({ code: APIErrorEnum.Success }, returnValue); + } catch (error) { + if (error instanceof APICallerError) { + const errorPacket2 = this.#resolveErrorPacket(error); + return this.#bundleReturnPacket(errorPacket2); + } + console.error(error); + const apiError = new APIServerError(error); + const errorPacket = this.#resolveErrorPacket(apiError); + return this.#bundleReturnPacket(errorPacket); + } + } + #assertVersionsMatch(versionToCheck) { + if (versionToCheck !== this.version) { + const apiVersionMismatchError = new APIVersionMismatchError(this.version, versionToCheck); + throw new APICallerError(apiVersionMismatchError); + } + } + #resolveReturnModel(returnDataModel) { + let returnModel = { ...ReturnModelShell }; + returnModel.data = returnDataModel; + returnModel = PROTO.Object(returnModel); + return returnModel; + } + #bundleReturnPacket(errorPacket, returnValue = void 0) { + return { + apiVersion: this.version, + data: returnValue, + error: errorPacket + }; + } + #resolveErrorPacket(error) { + return { + code: error.errorCode, + name: error.thrownError.name, + message: error.thrownError.message + }; + } +}; + +// APIController.js +var APIController = class _APIController { + #endpoints; + constructor(endpoints) { + if (this.constructor === _APIController) + throw new Error("Cannot instantiate abstract class 'APIController'"); + this.#endpoints = endpoints; + } + get endpoints() { + return this.#endpoints; + } +}; + +// AddonAPICaller.js +var AddonAPICaller = class { + static async call(endpoint, parameterModel, parameterMap, returnDataModel) { + return await IPC.invoke(endpoint, parameterModel, parameterMap, returnDataModel).then((result) => result.value); + } +}; +export { + APICallerError, + APIController, + AddonAPI, + AddonAPICaller, + PROTO, + VoidModel +}; +/** + * @license + * MIT License + * + * Copyright (c) 2026 OmniacDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ diff --git a/packs/BP/scripts/lib/AddonAPIKit/APIController.js b/packs/BP/scripts/lib/AddonAPIKit/APIController.js deleted file mode 100644 index 2ea4391..0000000 --- a/packs/BP/scripts/lib/AddonAPIKit/APIController.js +++ /dev/null @@ -1,13 +0,0 @@ -export class APIController { - #endpoints; - - constructor(endpoints) { - if (this.constructor === APIController) - throw new Error("Cannot instantiate abstract class 'APIController'"); - this.#endpoints = endpoints; - } - - get endpoints() { - return this.#endpoints; - } -} \ No newline at end of file diff --git a/packs/BP/scripts/lib/AddonAPIKit/APIModels.js b/packs/BP/scripts/lib/AddonAPIKit/APIModels.js deleted file mode 100644 index f0ca617..0000000 --- a/packs/BP/scripts/lib/AddonAPIKit/APIModels.js +++ /dev/null @@ -1,20 +0,0 @@ -import { PROTO } from "./MCBE-IPC/ipc"; - -export const VoidModel = PROTO.Void; - -export const ErrorModel = PROTO.Optional(PROTO.Object({ - code: PROTO.Int8, - name: PROTO.Optional(PROTO.String), - message: PROTO.Optional(PROTO.String) -})); - -export const ReturnModelShell = { - apiVersion: PROTO.String, - data: void 0, - error: ErrorModel -}; - -export const CallModelShell = { - apiVersion: PROTO.String, - parameterMap: void 0 -}; \ No newline at end of file diff --git a/packs/BP/scripts/lib/AddonAPIKit/AddonAPI.js b/packs/BP/scripts/lib/AddonAPIKit/AddonAPI.js deleted file mode 100644 index c02c006..0000000 --- a/packs/BP/scripts/lib/AddonAPIKit/AddonAPI.js +++ /dev/null @@ -1,92 +0,0 @@ -import { IPC, PROTO } from "./MCBE-IPC/ipc"; -import { APICallerError } from "./Errors/APICallerError"; -import { APIErrorEnum } from "./Errors/APIErrorEnum"; -import { APIServerError } from "./Errors/APIServerError"; -import { APIVersionMismatchError } from "./Errors/APIVersionMismatchError"; -import { ReturnModelShell } from "./APIModels"; - -export class AddonAPI { - #name; - #version; - - constructor(name, version) { - this.#name = name; - this.#version = version; - } - - get name() { - return this.#name; - } - - get version() { - return this.#version; - } - - get endpointBase() { - return this.#name + ':'; - } - - setupController(apiController) { - for (const [endpoint, features] of Object.entries(apiController.endpoints)) { - const {callback, parameterModel, returnModel} = features; - const boundCallback = callback.bind(apiController); - this.#setupEndpoint(endpoint, boundCallback, parameterModel, returnModel); - } - } - - #setupEndpoint(endpoint, callback, parameterModel, returnDataModel) { - const returnPacketModel = this.#resolveReturnModel(returnDataModel); - const endpointPath = this.endpointBase + endpoint; - IPC.handle(endpointPath, parameterModel, returnPacketModel, (callPacket) => { - const apiVersion = callPacket.apiVersion; - const parameters = Object.values(callPacket.parameterMap); - return this.#handleCallback(apiVersion, callback, parameters); - }); - } - - #handleCallback(apiVersion, callback, parameters) { - try { - this.#assertVersionsMatch(apiVersion); - const returnValue = callback(...parameters); - return this.#bundleReturnPacket({ code: APIErrorEnum.Success }, returnValue); - } catch(error) { - if (error instanceof APICallerError) - const errorPacket = this.#resolveErrorPacket(error); - return this.#bundleReturnPacket(errorPacket); - console.error(error); - const apiError = new APIServerError(error); - const errorPacket = this.#resolveErrorPacket(apiError); - return this.#bundleReturnPacket(errorPacket); - } - } - - #assertVersionsMatch(versionToCheck) { - if (versionToCheck !== this.version) { - const apiVersionMismatchError = new APIVersionMismatchError(this.version, versionToCheck); - throw new APICallerError(apiVersionMismatchError); - } - } - - #resolveReturnModel(returnDataModel) { - let returnModel = { ...ReturnModelShell }; - returnModel.data = returnDataModel; - returnModel = PROTO.Object(returnModel); - return returnModel; - } - - #bundleReturnPacket(errorPacket, returnValue = void 0) { - return { - apiVersion: this.version, - data: returnValue, - error: errorPacket - }; - } - - #resolveErrorPacket(error) { - return { - code: error.errorCode, - name: error.thrownError.name, - message: error.thrownError.message - }; - } -} \ No newline at end of file diff --git a/packs/BP/scripts/lib/AddonAPIKit/AddonAPICaller.js b/packs/BP/scripts/lib/AddonAPIKit/AddonAPICaller.js deleted file mode 100644 index 23fff2c..0000000 --- a/packs/BP/scripts/lib/AddonAPIKit/AddonAPICaller.js +++ /dev/null @@ -1,7 +0,0 @@ -import { IPC } from "./MCBE-IPC/ipc"; - -export class AddonAPICaller { - static async call(endpoint, parameterModel, parameterMap, returnDataModel) { - return await IPC.invoke(endpoint, parameterModel, parameterMap, returnDataModel).then(result => result.value); - } -} \ No newline at end of file diff --git a/packs/BP/scripts/lib/AddonAPIKit/AddonAPIKit.js b/packs/BP/scripts/lib/AddonAPIKit/AddonAPIKit.js deleted file mode 100644 index d08b378..0000000 --- a/packs/BP/scripts/lib/AddonAPIKit/AddonAPIKit.js +++ /dev/null @@ -1,8 +0,0 @@ -import { AddonAPI } from "./AddonAPI"; -import { APIController } from "./APIController"; -import { VoidModel } from "./APIModels"; -import { APICallerError } from "./Errors/APICallerError"; -import { PROTO } from "./MCBE-IPC/ipc"; -import { AddonAPICaller } from "./AddonAPICaller"; - -export { AddonAPI, APIController, VoidModel, APICallerError, PROTO, AddonAPICaller }; \ No newline at end of file diff --git a/packs/BP/scripts/lib/AddonAPIKit/Errors/APICallerError.js b/packs/BP/scripts/lib/AddonAPIKit/Errors/APICallerError.js deleted file mode 100644 index 27293da..0000000 --- a/packs/BP/scripts/lib/AddonAPIKit/Errors/APICallerError.js +++ /dev/null @@ -1,11 +0,0 @@ -import { APIErrorEnum } from "./APIErrorEnum"; - -export class APICallerError extends Error { - constructor(error) { - super(error.message); - this.errorName = error.name; - this.errorMessage = error.message; - this.errorCode = APIErrorEnum.Caller; - this.name = "APICallerError"; - } -} \ No newline at end of file diff --git a/packs/BP/scripts/lib/AddonAPIKit/Errors/APIErrorEnum.js b/packs/BP/scripts/lib/AddonAPIKit/Errors/APIErrorEnum.js deleted file mode 100644 index ba33a7d..0000000 --- a/packs/BP/scripts/lib/AddonAPIKit/Errors/APIErrorEnum.js +++ /dev/null @@ -1,6 +0,0 @@ -export const APIErrorEnum = Object.freeze({ - Unknown: 0, - Success: 1, - Caller: 2, - Server: 3 -}); \ No newline at end of file diff --git a/packs/BP/scripts/lib/AddonAPIKit/Errors/APIServerError.js b/packs/BP/scripts/lib/AddonAPIKit/Errors/APIServerError.js deleted file mode 100644 index 0b91e62..0000000 --- a/packs/BP/scripts/lib/AddonAPIKit/Errors/APIServerError.js +++ /dev/null @@ -1,10 +0,0 @@ -import { APIErrorEnum } from "./APIErrorEnum"; - -export class APIServerError extends Error { - constructor(error) { - super(error.message); - this.thrownError = error; - this.errorCode = APIErrorEnum.Server; - this.name = "APIServerError"; - } -} \ No newline at end of file diff --git a/packs/BP/scripts/lib/AddonAPIKit/Errors/APIVersionMismatchError.js b/packs/BP/scripts/lib/AddonAPIKit/Errors/APIVersionMismatchError.js deleted file mode 100644 index 6bb8fa0..0000000 --- a/packs/BP/scripts/lib/AddonAPIKit/Errors/APIVersionMismatchError.js +++ /dev/null @@ -1,6 +0,0 @@ -export class APIVersionMismatchError extends Error { - constructor(serverApiVersion, callerApiVersion) { - super(`API version numbers do not match (${callerApiVersion} != ${serverApiVersion}). Please use API version ${serverApiVersion}.`); - this.name = 'APIVersionMismatchError'; - } -} \ No newline at end of file diff --git a/packs/BP/scripts/lib/AddonAPIKit/MCBE-IPC/ipc.d.ts b/packs/BP/scripts/lib/AddonAPIKit/MCBE-IPC/ipc.d.ts deleted file mode 100644 index 6d6a10b..0000000 --- a/packs/BP/scripts/lib/AddonAPIKit/MCBE-IPC/ipc.d.ts +++ /dev/null @@ -1,119 +0,0 @@ -/** - * @license - * MIT License - * - * Copyright (c) 2026 OmniacDev - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -export declare namespace PROTO { - interface Serializer { - serialize(value: T, stream: Buffer): Generator; - } - interface Deserializer { - deserialize(stream: Buffer): Generator; - } - interface Serializable extends Serializer, Deserializer { - } - class Buffer { - private _buffer; - private _data_view; - private _length; - private _offset; - get end(): number; - get front(): number; - get data_view(): DataView; - constructor(size?: number); - reserve(amount: number): number; - consume(amount: number): number; - write(byte: number): void; - write(bytes: Uint8Array): void; - read(): number; - read(amount: number): Uint8Array; - ensure_capacity(size: number): void; - static from_uint8array(array: Uint8Array): Buffer; - to_uint8array(): Uint8Array; - } - namespace MIPS { - function is_valid(str: string): boolean; - function serialize(stream: PROTO.Buffer): Generator; - function deserialize(str: string): Generator; - } - const Void: PROTO.Serializable; - const Null: PROTO.Serializable; - const Undefined: PROTO.Serializable; - const Int8: PROTO.Serializable; - const Int16: PROTO.Serializable; - const Int32: PROTO.Serializable; - const UInt8: PROTO.Serializable; - const UInt16: PROTO.Serializable; - const UInt32: PROTO.Serializable; - const UVarInt32: PROTO.Serializable; - const VarInt32: PROTO.Serializable; - const Float32: PROTO.Serializable; - const Float64: PROTO.Serializable; - const String: PROTO.Serializable; - const Boolean: PROTO.Serializable; - const UInt8Array: PROTO.Serializable; - const Date: PROTO.Serializable; - function Object(s: { - [K in keyof T]: PROTO.Serializable; - }): PROTO.Serializable; - function Array(s: PROTO.Serializable): PROTO.Serializable; - function Tuple(...s: { - [K in keyof T]: PROTO.Serializable; - }): PROTO.Serializable; - function Optional(s: PROTO.Serializable): PROTO.Serializable; - function Map(kS: PROTO.Serializable, vS: PROTO.Serializable): PROTO.Serializable>; - function Set(s: PROTO.Serializable): PROTO.Serializable>; - function Cached(s: PROTO.Serializable, depth?: number): PROTO.Serializable; -} -export declare namespace NET { - type Meta = { - guid: string; - signature: string; - }; - const Meta: PROTO.Serializable; - export const SIGNATURE: string; - export let FRAG_MAX: number; - export function serialize(buffer: PROTO.Buffer, max_size?: number): Generator; - export function deserialize(strings: string[]): Generator; - export interface EmitOptions { - metaOverride?: Partial; - } - export function emit(endpoint: string, serializer: PROTO.Serializer, value: NoInfer, options?: EmitOptions): Generator; - export interface ListenOptions { - filter?: (meta: Meta) => boolean; - } - export function listen(endpoint: string, deserializer: PROTO.Deserializer, callback: (value: NoInfer, meta: Meta) => Generator, options?: ListenOptions): () => void; - export {}; -} -export declare namespace IPC { - /** Sends a message with `args` to `channel` */ - function send(channel: string, serializer: PROTO.Serializer, value: NoInfer): void; - /** Sends an `invoke` message through IPC, and expects a result asynchronously. */ - function invoke(channel: string, serializer: PROTO.Serializer, value: NoInfer, deserializer: PROTO.Deserializer): Promise>; - /** Listens to `channel`. When a new message arrives, `listener` will be called with `listener(args)`. */ - function on(channel: string, deserializer: PROTO.Deserializer, listener: (value: NoInfer) => void): () => void; - /** Listens to `channel` once. When a new message arrives, `listener` will be called with `listener(args)`, and then removed. */ - function once(channel: string, deserializer: PROTO.Deserializer, listener: (value: NoInfer) => void): () => void; - /** Adds a handler for an `invoke` IPC. This handler will be called whenever `invoke(channel, ...args)` is called */ - function handle(channel: string, deserializer: PROTO.Deserializer, serializer: PROTO.Serializer, listener: (value: NoInfer) => NoInfer): () => void; -} -export default IPC; diff --git a/packs/BP/scripts/lib/AddonAPIKit/MCBE-IPC/ipc.js b/packs/BP/scripts/lib/AddonAPIKit/MCBE-IPC/ipc.js deleted file mode 100644 index 8da8f92..0000000 --- a/packs/BP/scripts/lib/AddonAPIKit/MCBE-IPC/ipc.js +++ /dev/null @@ -1,658 +0,0 @@ -/** - * @license - * MIT License - * - * Copyright (c) 2026 OmniacDev - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -import { ScriptEventSource, system } from '@minecraft/server'; -var UTIL; -(function (UTIL) { - function generate_id() { - const r = (Math.random() * 0x100000000) >>> 0; - return r.toString(16).padStart(8, '0').toUpperCase(); - } - UTIL.generate_id = generate_id; -})(UTIL || (UTIL = {})); -export var PROTO; -(function (PROTO) { - class Buffer { - get end() { - return this._length + this._offset; - } - get front() { - return this._offset; - } - get data_view() { - return this._data_view; - } - constructor(size = 256) { - this._buffer = new Uint8Array(size); - this._data_view = new DataView(this._buffer.buffer); - this._length = 0; - this._offset = 0; - } - reserve(amount) { - this.ensure_capacity(amount); - const end = this.end; - this._length += amount; - return end; - } - consume(amount) { - if (amount > this._length) - throw new Error('not enough bytes'); - const front = this.front; - this._length -= amount; - this._offset += amount; - return front; - } - write(input) { - if (typeof input === 'number') { - const offset = this.reserve(1); - this._buffer[offset] = input; - } - else { - const offset = this.reserve(input.length); - this._buffer.set(input, offset); - } - } - read(amount) { - if (amount === undefined) { - const offset = this.consume(1); - return this._buffer[offset]; - } - else { - const offset = this.consume(amount); - return this._buffer.slice(offset, offset + amount); - } - } - ensure_capacity(size) { - if (this.end + size > this._buffer.length) { - const larger_buffer = new Uint8Array((this.end + size) * 2); - larger_buffer.set(this._buffer.subarray(this._offset, this.end), 0); - this._buffer = larger_buffer; - this._offset = 0; - this._data_view = new DataView(this._buffer.buffer); - } - } - static from_uint8array(array) { - const buffer = new Buffer(); - buffer._buffer = array; - buffer._length = array.length; - buffer._offset = 0; - buffer._data_view = new DataView(array.buffer); - return buffer; - } - to_uint8array() { - return this._buffer.subarray(this._offset, this.end); - } - } - PROTO.Buffer = Buffer; - let MIPS; - (function (MIPS) { - function is_valid(str) { - return str.startsWith('(0x') && str.endsWith(')'); - } - MIPS.is_valid = is_valid; - function* serialize(stream) { - const uint8array = stream.to_uint8array(); - let str = '(0x'; - for (let i = 0; i < uint8array.length; i++) { - const hex = uint8array[i].toString(16).padStart(2, '0').toUpperCase(); - str += hex; - yield; - } - str += ')'; - return str; - } - MIPS.serialize = serialize; - function* deserialize(str) { - if (is_valid(str)) { - const buffer = new Buffer(); - const hex_str = str.slice(3, str.length - 1); - for (let i = 0; i < hex_str.length; i++) { - const hex = hex_str[i] + hex_str[++i]; - buffer.write(parseInt(hex, 16)); - yield; - } - return buffer; - } - return new Buffer(); - } - MIPS.deserialize = deserialize; - })(MIPS = PROTO.MIPS || (PROTO.MIPS = {})); - PROTO.Void = { - *serialize() { }, - *deserialize() { } - }; - PROTO.Null = { - *serialize() { }, - *deserialize() { - return null; - } - }; - PROTO.Undefined = { - *serialize() { }, - *deserialize() { - return undefined; - } - }; - PROTO.Int8 = { - *serialize(value, stream) { - stream.data_view.setInt8(stream.reserve(1), value); - }, - *deserialize(stream) { - return stream.data_view.getInt8(stream.consume(1)); - } - }; - PROTO.Int16 = { - *serialize(value, stream) { - stream.data_view.setInt16(stream.reserve(2), value); - }, - *deserialize(stream) { - return stream.data_view.getInt16(stream.consume(2)); - } - }; - PROTO.Int32 = { - *serialize(value, stream) { - stream.data_view.setInt32(stream.reserve(4), value); - }, - *deserialize(stream) { - return stream.data_view.getInt32(stream.consume(4)); - } - }; - PROTO.UInt8 = { - *serialize(value, stream) { - stream.data_view.setUint8(stream.reserve(1), value); - }, - *deserialize(stream) { - return stream.data_view.getUint8(stream.consume(1)); - } - }; - PROTO.UInt16 = { - *serialize(value, stream) { - stream.data_view.setUint16(stream.reserve(2), value); - }, - *deserialize(stream) { - return stream.data_view.getUint16(stream.consume(2)); - } - }; - PROTO.UInt32 = { - *serialize(value, stream) { - stream.data_view.setUint32(stream.reserve(4), value); - }, - *deserialize(stream) { - return stream.data_view.getUint32(stream.consume(4)); - } - }; - PROTO.UVarInt32 = { - *serialize(value, stream) { - value >>>= 0; - while (value >= 0x80) { - stream.write((value & 0x7f) | 0x80); - value >>>= 7; - yield; - } - stream.write(value); - }, - *deserialize(stream) { - let value = 0; - for (let size = 0; size < 5; size++) { - const byte = stream.read(); - value |= (byte & 0x7f) << (size * 7); - yield; - if ((byte & 0x80) == 0) - break; - } - return value >>> 0; - } - }; - PROTO.VarInt32 = { - *serialize(value, stream) { - const zigzag = (value << 1) ^ (value >> 31); - yield* PROTO.UVarInt32.serialize(zigzag, stream); - }, - *deserialize(stream) { - const zigzag = yield* PROTO.UVarInt32.deserialize(stream); - return (zigzag >>> 1) ^ -(zigzag & 1); - } - }; - PROTO.Float32 = { - *serialize(value, stream) { - stream.data_view.setFloat32(stream.reserve(4), value); - }, - *deserialize(stream) { - return stream.data_view.getFloat32(stream.consume(4)); - } - }; - PROTO.Float64 = { - *serialize(value, stream) { - stream.data_view.setFloat64(stream.reserve(8), value); - }, - *deserialize(stream) { - return stream.data_view.getFloat64(stream.consume(8)); - } - }; - PROTO.String = { - *serialize(value, stream) { - yield* PROTO.UVarInt32.serialize(value.length, stream); - for (let i = 0; i < value.length; i++) { - const code = value.charCodeAt(i); - yield* PROTO.UVarInt32.serialize(code, stream); - } - }, - *deserialize(stream) { - const length = yield* PROTO.UVarInt32.deserialize(stream); - let value = ''; - for (let i = 0; i < length; i++) { - const code = yield* PROTO.UVarInt32.deserialize(stream); - value += globalThis.String.fromCharCode(code); - } - return value; - } - }; - PROTO.Boolean = { - *serialize(value, stream) { - stream.write(value ? 1 : 0); - }, - *deserialize(stream) { - return stream.read() !== 0; - } - }; - PROTO.UInt8Array = { - *serialize(value, stream) { - yield* PROTO.UVarInt32.serialize(value.length, stream); - stream.write(value); - }, - *deserialize(stream) { - const length = yield* PROTO.UVarInt32.deserialize(stream); - return stream.read(length); - } - }; - PROTO.Date = { - *serialize(value, stream) { - yield* PROTO.Float64.serialize(value.getTime(), stream); - }, - *deserialize(stream) { - return new globalThis.Date(yield* PROTO.Float64.deserialize(stream)); - } - }; - function Object(s) { - return { - *serialize(value, stream) { - for (const key in s) { - yield* s[key].serialize(value[key], stream); - } - }, - *deserialize(stream) { - const result = {}; - for (const key in s) { - result[key] = yield* s[key].deserialize(stream); - } - return result; - } - }; - } - PROTO.Object = Object; - function Array(s) { - return { - *serialize(value, stream) { - yield* PROTO.UVarInt32.serialize(value.length, stream); - for (const item of value) { - yield* s.serialize(item, stream); - } - }, - *deserialize(stream) { - const result = []; - const length = yield* PROTO.UVarInt32.deserialize(stream); - for (let i = 0; i < length; i++) { - result[i] = yield* s.deserialize(stream); - } - return result; - } - }; - } - PROTO.Array = Array; - function Tuple(...s) { - return { - *serialize(value, stream) { - for (let i = 0; i < s.length; i++) { - yield* s[i].serialize(value[i], stream); - } - }, - *deserialize(stream) { - const result = []; - for (let i = 0; i < s.length; i++) { - result[i] = yield* s[i].deserialize(stream); - } - return result; - } - }; - } - PROTO.Tuple = Tuple; - function Optional(s) { - return { - *serialize(value, stream) { - const def = value !== undefined; - yield* PROTO.Boolean.serialize(def, stream); - if (def) - yield* s.serialize(value, stream); - }, - *deserialize(stream) { - const def = yield* PROTO.Boolean.deserialize(stream); - if (def) - return yield* s.deserialize(stream); - return undefined; - } - }; - } - PROTO.Optional = Optional; - function Map(kS, vS) { - return { - *serialize(value, stream) { - yield* PROTO.UVarInt32.serialize(value.size, stream); - for (const [k, v] of value) { - yield* kS.serialize(k, stream); - yield* vS.serialize(v, stream); - } - }, - *deserialize(stream) { - const size = yield* PROTO.UVarInt32.deserialize(stream); - const result = new globalThis.Map(); - for (let i = 0; i < size; i++) { - const k = yield* kS.deserialize(stream); - const v = yield* vS.deserialize(stream); - result.set(k, v); - } - return result; - } - }; - } - PROTO.Map = Map; - function Set(s) { - return { - *serialize(set, stream) { - yield* PROTO.UVarInt32.serialize(set.size, stream); - for (const v of set) { - yield* s.serialize(v, stream); - } - }, - *deserialize(stream) { - const size = yield* PROTO.UVarInt32.deserialize(stream); - const result = new globalThis.Set(); - for (let i = 0; i < size; i++) { - const v = yield* s.deserialize(stream); - result.add(v); - } - return result; - } - }; - } - PROTO.Set = Set; - function Cached(s, depth = 16) { - const cache = new globalThis.Map(); - return { - *serialize(value, stream) { - const hit = cache.get(value); - if (hit !== undefined) { - stream.write(hit); - cache.delete(value); - cache.set(value, hit); - } - else { - const buffer = new PROTO.Buffer(); - yield* s.serialize(value, buffer); - const bytes = buffer.to_uint8array(); - stream.write(bytes); - cache.set(value, bytes); - if (cache.size > depth) { - const first = cache.keys().next().value; - cache.delete(first); - } - } - }, - *deserialize(stream) { - return yield* s.deserialize(stream); - } - }; - } - PROTO.Cached = Cached; -})(PROTO || (PROTO = {})); -export var NET; -(function (NET) { - const Endpoint = PROTO.String; - const Meta = PROTO.Object({ - guid: PROTO.String, - signature: PROTO.String - }); - const Header = PROTO.Object({ - meta: Meta, - index: PROTO.UVarInt32, - final: PROTO.Boolean - }); - const LISTENERS = new Map(); - NET.SIGNATURE = 'mcbe-ipc:v3'; - NET.FRAG_MAX = 2048; - function* serialize(buffer, max_size = Infinity) { - const uint8array = buffer.to_uint8array(); - const result = []; - let acc_str = ''; - let acc_size = 0; - for (let i = 0; i < uint8array.length; i++) { - const char_code = uint8array[i] | (uint8array[++i] << 8); - const utf16_size = char_code <= 0x7f ? 1 : char_code <= 0x7ff ? 2 : char_code <= 0xffff ? 3 : 4; - const char_size = char_code > 0xff ? utf16_size : 2; - if (acc_size + char_size > max_size) { - result.push(acc_str); - acc_str = ''; - acc_size = 0; - } - if (char_code > 0xff) { - acc_str += String.fromCharCode(char_code); - acc_size += utf16_size; - } - else { - acc_str += char_code.toString(16).padStart(2, '0').toUpperCase(); - acc_size += 2; - } - yield; - } - result.push(acc_str); - return result; - } - NET.serialize = serialize; - function* deserialize(strings) { - const buffer = new PROTO.Buffer(); - for (let i = 0; i < strings.length; i++) { - const str = strings[i]; - for (let j = 0; j < str.length; j++) { - const char_code = str.charCodeAt(j); - if (char_code <= 0xff) { - const hex = str[j] + str[++j]; - const hex_code = parseInt(hex, 16); - buffer.write(hex_code & 0xff); - buffer.write(hex_code >> 8); - } - else { - buffer.write(char_code & 0xff); - buffer.write(char_code >> 8); - } - yield; - } - yield; - } - return buffer; - } - NET.deserialize = deserialize; - system.afterEvents.scriptEventReceive.subscribe(event => { - system.runJob((function* () { - if (event.sourceType !== ScriptEventSource.Server) - return; - const [serialized_endpoint, serialized_header] = event.id.split(':'); - if (!PROTO.MIPS.is_valid(serialized_endpoint)) - return; - const endpoint_stream = yield* PROTO.MIPS.deserialize(serialized_endpoint); - const endpoint = yield* Endpoint.deserialize(endpoint_stream); - const listeners = LISTENERS.get(endpoint); - if (listeners !== undefined && PROTO.MIPS.is_valid(serialized_header)) { - const header_stream = yield* PROTO.MIPS.deserialize(serialized_header); - const header = yield* Header.deserialize(header_stream); - for (const listener of [...listeners]) { - try { - yield* listener(header, event.message); - } - catch (e) { - console.error(`[MCBE-IPC] listener error while handling packet on "${endpoint}":`, e); - } - } - } - })()); - }); - function register(endpoint, listener) { - let listeners = LISTENERS.get(endpoint); - if (listeners === undefined) { - listeners = new Array(); - LISTENERS.set(endpoint, listeners); - } - listeners.push(listener); - return () => { - const idx = listeners.indexOf(listener); - if (idx !== -1) - listeners.splice(idx, 1); - if (listeners.length === 0) { - LISTENERS.delete(endpoint); - } - }; - } - function* emit(endpoint, serializer, value, options) { - const guid = options?.metaOverride?.guid ?? UTIL.generate_id(); - const signature = options?.metaOverride?.signature ?? NET.SIGNATURE; - const endpoint_stream = new PROTO.Buffer(); - yield* Endpoint.serialize(endpoint, endpoint_stream); - const serialized_endpoint = yield* PROTO.MIPS.serialize(endpoint_stream); - const packet_stream = new PROTO.Buffer(); - yield* serializer.serialize(value, packet_stream); - const serialized_packets = yield* serialize(packet_stream, NET.FRAG_MAX); - for (let i = 0; i < serialized_packets.length; i++) { - const serialized_packet = serialized_packets[i]; - const header = { - meta: { guid, signature }, - index: i, - final: i === serialized_packets.length - 1 - }; - const header_stream = new PROTO.Buffer(); - yield* Header.serialize(header, header_stream); - const serialized_header = yield* PROTO.MIPS.serialize(header_stream); - system.sendScriptEvent(`${serialized_endpoint}:${serialized_header}`, serialized_packet); - } - } - NET.emit = emit; - function listen(endpoint, deserializer, callback, options) { - const buffer = new Map(); - const listener = function* (header, fragment) { - let packet = buffer.get(header.meta.guid); - if (packet === undefined) { - if (options?.filter?.(header.meta) === false) - return; - packet = { size: -1, fragments: [], received: 0 }; - buffer.set(header.meta.guid, packet); - } - if (header.final) { - packet.size = header.index + 1; - } - if (packet.fragments[header.index] === undefined) { - packet.fragments[header.index] = fragment; - packet.received++; - } - else { - throw new Error(`received duplicate fragment ${header.index} for packet ${header.meta.guid}`); - } - if (packet.size !== -1 && packet.size === packet.received) { - const stream = yield* deserialize(packet.fragments); - const value = yield* deserializer.deserialize(stream); - yield* callback(value, header.meta); - buffer.delete(header.meta.guid); - } - }; - return register(endpoint, listener); - } - NET.listen = listen; -})(NET || (NET = {})); -export var IPC; -(function (IPC) { - /** Sends a message with `args` to `channel` */ - function send(channel, serializer, value) { - system.runJob(NET.emit(`ipc:${channel}:send`, serializer, value)); - } - IPC.send = send; - /** Sends an `invoke` message through IPC, and expects a result asynchronously. */ - function invoke(channel, serializer, value, deserializer) { - const id = UTIL.generate_id(); - return new Promise(resolve => { - const terminate = NET.listen(`ipc:${channel}:handle`, deserializer, function* (value, meta) { - if (meta.signature.includes(`+correlation`) && meta.guid !== id) - return; - resolve(value); - terminate(); - }, { - filter: meta => !meta.signature.includes(`+correlation`) || meta.guid === id - }); - system.runJob(NET.emit(`ipc:${channel}:invoke`, serializer, value, { - metaOverride: { - guid: id, - signature: `${NET.SIGNATURE}+correlation` - } - })); - }); - } - IPC.invoke = invoke; - /** Listens to `channel`. When a new message arrives, `listener` will be called with `listener(args)`. */ - function on(channel, deserializer, listener) { - return NET.listen(`ipc:${channel}:send`, deserializer, function* (value) { - listener(value); - }); - } - IPC.on = on; - /** Listens to `channel` once. When a new message arrives, `listener` will be called with `listener(args)`, and then removed. */ - function once(channel, deserializer, listener) { - const terminate = NET.listen(`ipc:${channel}:send`, deserializer, function* (value) { - listener(value); - terminate(); - }); - return terminate; - } - IPC.once = once; - /** Adds a handler for an `invoke` IPC. This handler will be called whenever `invoke(channel, ...args)` is called */ - function handle(channel, deserializer, serializer, listener) { - return NET.listen(`ipc:${channel}:invoke`, deserializer, function* (value, meta) { - const result = listener(value); - yield* NET.emit(`ipc:${channel}:handle`, serializer, result, { - metaOverride: meta.signature.includes(`+correlation`) - ? { - guid: meta.guid, - signature: `${NET.SIGNATURE}+correlation` - } - : undefined - }); - }); - } - IPC.handle = handle; -})(IPC || (IPC = {})); -export default IPC;