@mine-scripters/minecraft-rmi 1.0.0 → 1.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/README.md +44 -1
- package/dist/MinecraftRMI.js +114 -46
- package/dist/MinecraftRMI.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,3 +1,46 @@
|
|
|
1
|
-
|
|
1
|
+
//# Minecraft RMI (Remote method invocation)
|
|
2
2
|
|
|
3
3
|
Allow multiple addons to communicate by exposing an API
|
|
4
|
+
|
|
5
|
+
## Protocol
|
|
6
|
+
|
|
7
|
+
The protocol is built on top of an ACK'ed communication that specifies how to send commands and arguments
|
|
8
|
+
across the addon boundaries.
|
|
9
|
+
|
|
10
|
+
### Raw communication
|
|
11
|
+
|
|
12
|
+
Note that when sending scriptevents, to prevent Minecraft from trying to convert it to json, we append a "-" at
|
|
13
|
+
the start of the message.
|
|
14
|
+
|
|
15
|
+
1. The receiver needs to be ready to accept incoming data by listening to an agreed scriptevent.
|
|
16
|
+
2. The sender generates a unique identifier `id` used across all the message.
|
|
17
|
+
3. If the sender has any object to transfer (such as arguments or data), it must be converted to a JSON
|
|
18
|
+
string (via JSON.stringify) and split into chunks of 2048 (the current limit for message).
|
|
19
|
+
4. The sender starts listening on the scriptevent `minescripters_rmi:${id}.sender` for incoming transactions
|
|
20
|
+
5. The sender starts by sending a message header as a JSON string.
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
interface MessageHeader {
|
|
24
|
+
// Message identifier generated by the sender that identifies this whole message
|
|
25
|
+
id: string;
|
|
26
|
+
// Number of chunks to be sent - if any.
|
|
27
|
+
chunkCount?: number;
|
|
28
|
+
|
|
29
|
+
// Additional data - Must be kept at minimum as this whole header cannot excede the limit of 2048 characters when JSONfied
|
|
30
|
+
// https://learn.microsoft.com/en-us/minecraft/creator/commands/commands/scriptevent?view=minecraft-bedrock-stable
|
|
31
|
+
header: unknown;
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
6. The receiver receives the header, grabs the `id`.
|
|
36
|
+
7. If there is any chunk to be received, the receiver starts listening on `minescripters_rmi:${id}.receiver`
|
|
37
|
+
8. The receiver Sends and `ack` message by sending a scriptevent to `${id}.sender`
|
|
38
|
+
9. The sender receives the `ack` message and closes connection to `minescripters_rmi:${id}.sender` if there are no chunks to be sent.
|
|
39
|
+
10. If there is any chunk to be sent, the sender sends them on `minescripters_rmi:${id}.receiver`
|
|
40
|
+
Note: Care must be taken into account to not execute more commands than possible. There is still no way to know if we are reaching the limit, so throttling them if required.
|
|
41
|
+
|
|
42
|
+
11. The receiver receives the chunks, concatenates and parses the result, closes `${id}.receiver`.
|
|
43
|
+
12. The receiver sends a final ack by sending a scriptevent to `${id}.sender`
|
|
44
|
+
13. The sender sees the ack and closes `${id}.sender`
|
|
45
|
+
|
|
46
|
+
This allows us to send a message across addons, with json data.
|
package/dist/MinecraftRMI.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { world, system
|
|
1
|
+
import { DimensionTypes, world, system } from '@minecraft/server';
|
|
2
2
|
|
|
3
3
|
const MINESCRIPTERS_NAMESPACE = 'minescripters';
|
|
4
4
|
const buildServerNamespace = (namespace) => `${MINESCRIPTERS_NAMESPACE}_${namespace}`;
|
|
@@ -8,14 +8,6 @@ const sendEvent = (event) => {
|
|
|
8
8
|
return world.getDimension(dt.typeId)?.runCommand(`scriptevent ${event}`).successCount;
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
const argsKey = (namespace, message) => `${buildServerNamespace(namespace)}:rmi.payload.${message.endpoint}.${message.id}.args`;
|
|
12
|
-
const returnValueKey = (namespace, message) => `${buildServerNamespace(namespace)}:rmi.payload.${message.endpoint}.${message.id}.return`;
|
|
13
|
-
const setDynamicPropertyAndExpire = (key, value, timeout) => {
|
|
14
|
-
world.setDynamicProperty(key, JSON.stringify(value));
|
|
15
|
-
system.runTimeout(() => {
|
|
16
|
-
world.setDynamicProperty(key);
|
|
17
|
-
}, timeout);
|
|
18
|
-
};
|
|
19
11
|
|
|
20
12
|
var SchemaEntryType;
|
|
21
13
|
(function (SchemaEntryType) {
|
|
@@ -150,6 +142,105 @@ const normalize = (schema) => {
|
|
|
150
142
|
return schema;
|
|
151
143
|
};
|
|
152
144
|
|
|
145
|
+
const makeId = () => {
|
|
146
|
+
return Math.random().toString(36).substring(2);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const RMI_NAMESPACE = 'minescripters_rmi';
|
|
150
|
+
// Prevents the scriptevent parser from identifying it as a json object an failing to parse
|
|
151
|
+
const CHUNK_PADDING = '-';
|
|
152
|
+
const receiverScriptEvent = (id) => `${RMI_NAMESPACE}:${id}.receiver`;
|
|
153
|
+
const senderScriptEvent = (id) => `${RMI_NAMESPACE}:${id}.sender`;
|
|
154
|
+
const promiseResolver = () => {
|
|
155
|
+
let resolver = () => { };
|
|
156
|
+
return [
|
|
157
|
+
new Promise((resolve) => {
|
|
158
|
+
resolver = resolve;
|
|
159
|
+
}),
|
|
160
|
+
resolver,
|
|
161
|
+
];
|
|
162
|
+
};
|
|
163
|
+
const ackWaiter = async (scriptEvent) => {
|
|
164
|
+
const [acked, ack] = promiseResolver();
|
|
165
|
+
const namespace = scriptEvent.split(':')[0];
|
|
166
|
+
const listener = system.afterEvents.scriptEventReceive.subscribe((event) => {
|
|
167
|
+
if (event.id === scriptEvent) {
|
|
168
|
+
ack();
|
|
169
|
+
}
|
|
170
|
+
}, {
|
|
171
|
+
namespaces: [namespace],
|
|
172
|
+
});
|
|
173
|
+
await acked;
|
|
174
|
+
system.afterEvents.scriptEventReceive.unsubscribe(listener);
|
|
175
|
+
};
|
|
176
|
+
const internalSendMessage = async (header, data, scriptevent, maxMessageSize = 2048) => {
|
|
177
|
+
const id = makeId();
|
|
178
|
+
const chunks = [];
|
|
179
|
+
if (data !== undefined) {
|
|
180
|
+
const dataString = JSON.stringify(data);
|
|
181
|
+
for (let i = 0; i < maxMessageSize; i += maxMessageSize) {
|
|
182
|
+
chunks.push(dataString.slice(i, i + maxMessageSize));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const transportHeader = {
|
|
186
|
+
id,
|
|
187
|
+
header,
|
|
188
|
+
};
|
|
189
|
+
if (chunks.length > 0) {
|
|
190
|
+
transportHeader.chunkCount = chunks.length;
|
|
191
|
+
}
|
|
192
|
+
const initialAck = ackWaiter(senderScriptEvent(id));
|
|
193
|
+
const rawTransportHeader = JSON.stringify(transportHeader);
|
|
194
|
+
if (rawTransportHeader.length > 2048) {
|
|
195
|
+
console.error('Transport header is bigger than 2048 characters:', rawTransportHeader);
|
|
196
|
+
throw new Error('Transport header is bigger than 2048');
|
|
197
|
+
}
|
|
198
|
+
sendEvent(`${scriptevent} ${rawTransportHeader}`);
|
|
199
|
+
await initialAck;
|
|
200
|
+
if (chunks.length > 0) {
|
|
201
|
+
const chunksAck = ackWaiter(senderScriptEvent(id));
|
|
202
|
+
for (const chunk of chunks) {
|
|
203
|
+
sendEvent(`${receiverScriptEvent(id)} ${CHUNK_PADDING}${chunk}`);
|
|
204
|
+
}
|
|
205
|
+
await chunksAck;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
const internalMessageReceived = async (rawHeader) => {
|
|
209
|
+
const header = JSON.parse(rawHeader);
|
|
210
|
+
const id = header.id;
|
|
211
|
+
if (!id) {
|
|
212
|
+
console.error('Unknown data received:', header);
|
|
213
|
+
throw new Error('Unknow data received');
|
|
214
|
+
}
|
|
215
|
+
const chunkCount = header.chunkCount;
|
|
216
|
+
const chunks = [];
|
|
217
|
+
let data = undefined;
|
|
218
|
+
if (chunkCount && chunkCount > 0) {
|
|
219
|
+
const [acked, ack] = promiseResolver();
|
|
220
|
+
const listener = system.afterEvents.scriptEventReceive.subscribe((event) => {
|
|
221
|
+
if (event.id === receiverScriptEvent(id)) {
|
|
222
|
+
// Removes CHUNK_PADDING
|
|
223
|
+
chunks.push(event.message.slice(1));
|
|
224
|
+
if (chunks.length === chunkCount) {
|
|
225
|
+
ack();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}, {
|
|
229
|
+
namespaces: [RMI_NAMESPACE],
|
|
230
|
+
});
|
|
231
|
+
sendEvent(`${senderScriptEvent(id)}`);
|
|
232
|
+
await acked;
|
|
233
|
+
system.afterEvents.scriptEventReceive.unsubscribe(listener);
|
|
234
|
+
const rawData = chunks.join('');
|
|
235
|
+
data = JSON.parse(rawData);
|
|
236
|
+
sendEvent(`${senderScriptEvent(id)}`);
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
header: header.header,
|
|
240
|
+
data,
|
|
241
|
+
};
|
|
242
|
+
};
|
|
243
|
+
|
|
153
244
|
const serverStopEvent = (server) => `${buildServerNamespace(server.namespace)}:rmi.event-stop`;
|
|
154
245
|
const serverReturnEvent = (namespace, message) => {
|
|
155
246
|
const localNamespace = `${buildServerNamespace(namespace)}_${message.id}`;
|
|
@@ -159,31 +250,19 @@ const returnError = (server, payload, error) => {
|
|
|
159
250
|
const message = {
|
|
160
251
|
id: payload.id,
|
|
161
252
|
endpoint: payload.endpoint,
|
|
162
|
-
|
|
253
|
+
hasReturn: false,
|
|
163
254
|
isError: true,
|
|
164
255
|
};
|
|
165
|
-
|
|
166
|
-
setDynamicPropertyAndExpire(key, error, payload.timeout);
|
|
167
|
-
sendEvent(`${serverReturnEvent(server.namespace, message)} ${JSON.stringify(message)}`);
|
|
256
|
+
internalSendMessage(message, error, serverReturnEvent(server.namespace, message));
|
|
168
257
|
};
|
|
169
258
|
const returnValue = (server, payload, value) => {
|
|
170
259
|
const message = {
|
|
171
260
|
id: payload.id,
|
|
172
261
|
endpoint: payload.endpoint,
|
|
173
|
-
|
|
262
|
+
hasReturn: value !== undefined,
|
|
174
263
|
isError: false,
|
|
175
264
|
};
|
|
176
|
-
|
|
177
|
-
const key = returnValueKey(server.namespace, message);
|
|
178
|
-
setDynamicPropertyAndExpire(key, value, payload.timeout);
|
|
179
|
-
}
|
|
180
|
-
sendEvent(`${serverReturnEvent(server.namespace, message)} ${JSON.stringify(message)}`);
|
|
181
|
-
};
|
|
182
|
-
const getParams = (namespace, payload) => {
|
|
183
|
-
if (payload.hasArguments) {
|
|
184
|
-
return JSON.parse(world.getDynamicProperty(argsKey(namespace, payload)));
|
|
185
|
-
}
|
|
186
|
-
return [];
|
|
265
|
+
internalSendMessage(message, value, serverReturnEvent(server.namespace, message));
|
|
187
266
|
};
|
|
188
267
|
const start = (server) => {
|
|
189
268
|
const stopEvent = serverStopEvent(server);
|
|
@@ -193,13 +272,13 @@ const start = (server) => {
|
|
|
193
272
|
system.afterEvents.scriptEventReceive.unsubscribe(handler);
|
|
194
273
|
}
|
|
195
274
|
else if (event.id === payloadEvent) {
|
|
196
|
-
const
|
|
197
|
-
|
|
275
|
+
const messageReceived = await internalMessageReceived(event.message);
|
|
276
|
+
const payload = messageReceived.header;
|
|
198
277
|
if (!(payload.endpoint in server.endpoints)) {
|
|
199
278
|
returnError(server, payload, `Endpoint ${payload.endpoint} not found`);
|
|
200
279
|
return;
|
|
201
280
|
}
|
|
202
|
-
const params =
|
|
281
|
+
const params = (messageReceived.data === undefined ? [] : messageReceived.data);
|
|
203
282
|
const endpoint = server.endpoints[payload.endpoint];
|
|
204
283
|
if (endpoint.schema?.arguments) {
|
|
205
284
|
try {
|
|
@@ -235,29 +314,23 @@ const startServer = (_server) => {
|
|
|
235
314
|
start(server);
|
|
236
315
|
};
|
|
237
316
|
|
|
238
|
-
const makeId = () => {
|
|
239
|
-
return Math.random().toString(36).substring(2);
|
|
240
|
-
};
|
|
241
|
-
|
|
242
317
|
const responseListener = (input) => {
|
|
243
318
|
let handler;
|
|
244
319
|
const promise = new Promise((resolve, reject) => {
|
|
245
320
|
const cancelHandler = system.runTimeout(() => {
|
|
246
321
|
reject(new Error(`Timeout: Timed out trying to run ${input.endpoint} of ${input.namespace}`));
|
|
247
322
|
}, input.timeout);
|
|
248
|
-
handler = system.afterEvents.scriptEventReceive.subscribe((event) => {
|
|
323
|
+
handler = system.afterEvents.scriptEventReceive.subscribe(async (event) => {
|
|
249
324
|
if (event.id === input.eventKey) {
|
|
250
325
|
try {
|
|
251
|
-
const
|
|
326
|
+
const response = await internalMessageReceived(event.message);
|
|
327
|
+
const returnMessage = response.header;
|
|
252
328
|
if (returnMessage.isError) {
|
|
253
|
-
|
|
254
|
-
reject(new Error(errorString));
|
|
329
|
+
reject(new Error(response.data));
|
|
255
330
|
}
|
|
256
331
|
else {
|
|
257
|
-
if (returnMessage.
|
|
258
|
-
|
|
259
|
-
world.setDynamicProperty(returnValueKey(input.namespace, returnMessage));
|
|
260
|
-
resolve(JSON.parse(returnValue));
|
|
332
|
+
if (returnMessage.hasReturn) {
|
|
333
|
+
resolve(response.data);
|
|
261
334
|
}
|
|
262
335
|
else {
|
|
263
336
|
resolve(undefined);
|
|
@@ -287,7 +360,6 @@ const sendMessage = async (namespace, endpoint, args, timeout = 60) => {
|
|
|
287
360
|
const message = {
|
|
288
361
|
id: messageId,
|
|
289
362
|
endpoint: endpoint,
|
|
290
|
-
hasArguments: args !== undefined && args.length > 0,
|
|
291
363
|
timeout,
|
|
292
364
|
};
|
|
293
365
|
const [clean, promise] = responseListener({
|
|
@@ -298,11 +370,7 @@ const sendMessage = async (namespace, endpoint, args, timeout = 60) => {
|
|
|
298
370
|
timeout,
|
|
299
371
|
});
|
|
300
372
|
try {
|
|
301
|
-
|
|
302
|
-
const argumentsKey = argsKey(namespace, message);
|
|
303
|
-
setDynamicPropertyAndExpire(argumentsKey, args, timeout);
|
|
304
|
-
}
|
|
305
|
-
sendEvent(`${inputMessageEvent(namespace)} ${JSON.stringify(message)}`);
|
|
373
|
+
internalSendMessage(message, args, inputMessageEvent(namespace));
|
|
306
374
|
return await promise;
|
|
307
375
|
}
|
|
308
376
|
finally {
|
package/dist/MinecraftRMI.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MinecraftRMI.js","sources":["../src/Communication.ts","../src/Schema.ts","../src/Server.ts","../src/Utils.ts","../src/Client.ts"],"sourcesContent":["import { DimensionTypes, system, world } from '@minecraft/server';\n\ninterface Message {\n id: string;\n endpoint: string;\n}\n\nexport interface InputMessage extends Message {\n hasArguments: boolean;\n timeout: number;\n}\n\nexport interface OutputMessage extends Message {\n hasValue: boolean;\n isError: boolean;\n}\n\nconst MINESCRIPTERS_NAMESPACE = 'minescripters';\n\nexport const buildServerNamespace = (namespace: string) => `${MINESCRIPTERS_NAMESPACE}_${namespace}`;\n\nexport const inputMessageEvent = (namespace: string) => `${buildServerNamespace(namespace)}:rmi.event-payload`;\n\nexport const sendEvent = (event: string) => {\n DimensionTypes.getAll().some((dt) => {\n return world.getDimension(dt.typeId)?.runCommand(`scriptevent ${event}`).successCount;\n });\n};\n\nexport const argsKey = (namespace: string, message: Message) =>\n `${buildServerNamespace(namespace)}:rmi.payload.${message.endpoint}.${message.id}.args`;\nexport const returnValueKey = (namespace: string, message: Message) =>\n `${buildServerNamespace(namespace)}:rmi.payload.${message.endpoint}.${message.id}.return`;\n\nexport const setDynamicPropertyAndExpire = (key: string, value: unknown, timeout: number) => {\n world.setDynamicProperty(key, JSON.stringify(value));\n system.runTimeout(() => {\n world.setDynamicProperty(key);\n }, timeout);\n};\n","export enum SchemaEntryType {\n OBJECT,\n NUMBER,\n STRING,\n ARRAY,\n BOOL,\n ANY,\n}\n\ninterface SchemaEntryBase {\n isOptional?: boolean;\n allowNull?: boolean;\n}\n\nexport interface SchemaEntryNumber extends SchemaEntryBase {\n type: SchemaEntryType.NUMBER;\n}\n\nexport interface SchemaEntryString extends SchemaEntryBase {\n type: SchemaEntryType.STRING;\n}\n\nexport interface SchemaEntryObject extends SchemaEntryBase {\n type: SchemaEntryType.OBJECT;\n extraKeys?: SchemaEntry;\n entries?: {\n [key: string]: SchemaEntry;\n };\n}\n\nexport interface SchemaEntryBool extends SchemaEntryBase {\n type: SchemaEntryType.BOOL;\n}\n\nexport interface SchemaEntryArray extends SchemaEntryBase {\n type: SchemaEntryType.ARRAY;\n items?: SchemaEntry;\n}\n\nexport type SchemaEntry =\n | SchemaEntryNumber\n | SchemaEntryString\n | SchemaEntryBool\n | SchemaEntryObject\n | SchemaEntryArray\n | SchemaEntryType\n | Array<SchemaEntry>;\n\ntype InternalSchema =\n | SchemaEntryNumber\n | SchemaEntryString\n | SchemaEntryBool\n | SchemaEntryObject\n | SchemaEntryArray\n | SchemaEntryType.ANY\n | Array<SchemaEntry>;\n\nconst validateBase = (schema: SchemaEntryBase, obj: unknown) => {\n if (!schema.isOptional) {\n if (obj === undefined) {\n throw new Error('Invalid schema, undefined but not optional');\n }\n }\n\n if (!schema.allowNull) {\n if (obj === null) {\n throw new Error('Invalid schema, null but does not allow null');\n }\n }\n};\n\nexport const validate = (schema: SchemaEntry, obj: unknown) => {\n schema = normalize(schema);\n\n if (Array.isArray(schema)) {\n let passed = false;\n for (const subSchema of schema) {\n try {\n validate(subSchema, obj);\n passed = true;\n break;\n } catch (e) {\n console.error(e);\n }\n }\n\n if (!passed) {\n throw new Error('Invalid schema');\n }\n return;\n }\n\n if (schema === SchemaEntryType.ANY) {\n return;\n }\n\n validateBase(schema, obj);\n\n if (obj === null || obj === undefined) {\n return;\n }\n\n if (schema.type === SchemaEntryType.NUMBER) {\n if (typeof obj !== 'number' && typeof obj !== 'bigint') {\n throw new Error('Invalid schema, not a number (or bigint)');\n }\n } else if (schema.type === SchemaEntryType.ARRAY) {\n if (!Array.isArray(obj)) {\n throw new Error('Invalid schema, not an array');\n }\n\n if (schema.items) {\n for (const entry of obj) {\n validate(schema.items, entry);\n }\n }\n } else if (schema.type === SchemaEntryType.STRING) {\n if (typeof obj !== 'string') {\n throw new Error('Invalid schema, not a string');\n }\n } else if (schema.type === SchemaEntryType.BOOL) {\n if (typeof obj !== 'boolean') {\n throw new Error('Invalid schema, not a bool');\n }\n } else if (schema.type === SchemaEntryType.OBJECT) {\n if (typeof obj !== 'object' || Array.isArray(obj)) {\n throw new Error('Invalid schema, not an object');\n }\n\n if (schema.entries) {\n for (const key of Object.keys(obj)) {\n if (key in schema.entries) {\n validate(schema.entries[key], (obj as { [key]: unknown })[key]);\n } else {\n if (!schema.extraKeys) {\n throw new Error('Invalid schema, invalid key: ' + key);\n }\n\n validate(schema.extraKeys, (obj as { [key]: unknown })[key]);\n }\n }\n } else if (schema.extraKeys) {\n const extraKeys = schema.extraKeys;\n Object.values(obj).forEach((o) => validate(extraKeys, o));\n }\n }\n};\n\nexport const validateArray = (schemas: Array<SchemaEntry>, objs: Array<unknown>) => {\n objs = [...objs];\n while (schemas.length > objs.length) {\n objs.push(undefined);\n }\n\n for (let i = 0; i < schemas.length; i++) {\n validate(schemas[i], objs[i]);\n }\n};\n\nconst normalize = (schema: SchemaEntry): InternalSchema => {\n if (schema === SchemaEntryType.NUMBER) {\n return {\n type: SchemaEntryType.NUMBER,\n };\n } else if (schema === SchemaEntryType.STRING) {\n return {\n type: SchemaEntryType.STRING,\n };\n } else if (schema === SchemaEntryType.OBJECT) {\n return {\n type: SchemaEntryType.OBJECT,\n };\n } else if (schema === SchemaEntryType.ARRAY) {\n return {\n type: SchemaEntryType.ARRAY,\n };\n } else if (schema === SchemaEntryType.BOOL) {\n return {\n type: SchemaEntryType.BOOL,\n };\n }\n\n return schema;\n};\n","import { system, world } from '@minecraft/server';\nimport {\n buildServerNamespace,\n sendEvent,\n argsKey,\n InputMessage,\n OutputMessage,\n returnValueKey,\n inputMessageEvent,\n setDynamicPropertyAndExpire,\n} from './Communication';\nimport { SchemaEntry, validate, validateArray } from './Schema';\n\nexport interface Server {\n namespace: string;\n endpoints: Record<string, Endpoint>;\n}\n\nexport interface Endpoint {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n handler: (...params: Array<any>) => unknown;\n schema?: EndpointSchema;\n}\n\nexport type EndpointSchema = {\n arguments?: Array<SchemaEntry>;\n returnValue?: SchemaEntry;\n};\n\nconst serverStopEvent = (server: Server) => `${buildServerNamespace(server.namespace)}:rmi.event-stop`;\nconst serverReturnEvent = (namespace: string, message: OutputMessage) => {\n const localNamespace = `${buildServerNamespace(namespace)}_${message.id}`;\n return `${localNamespace}:${message.endpoint}`;\n};\n\nconst returnError = (server: Server, payload: InputMessage, error: string) => {\n const message: OutputMessage = {\n id: payload.id,\n endpoint: payload.endpoint,\n hasValue: false,\n isError: true,\n };\n\n const key = returnValueKey(server.namespace, message);\n setDynamicPropertyAndExpire(key, error, payload.timeout);\n\n sendEvent(`${serverReturnEvent(server.namespace, message)} ${JSON.stringify(message)}`);\n};\n\nconst returnValue = (server: Server, payload: InputMessage, value: unknown) => {\n const message: OutputMessage = {\n id: payload.id,\n endpoint: payload.endpoint,\n hasValue: value !== undefined,\n isError: false,\n };\n\n if (value !== undefined) {\n const key = returnValueKey(server.namespace, message);\n setDynamicPropertyAndExpire(key, value, payload.timeout);\n }\n\n sendEvent(`${serverReturnEvent(server.namespace, message)} ${JSON.stringify(message)}`);\n};\n\nconst getParams = (namespace: string, payload: InputMessage): Array<unknown> => {\n if (payload.hasArguments) {\n return JSON.parse(world.getDynamicProperty(argsKey(namespace, payload)) as string) as unknown as Array<unknown>;\n }\n\n return [];\n};\n\nconst start = (server: Server) => {\n const stopEvent = serverStopEvent(server);\n const payloadEvent = inputMessageEvent(server.namespace);\n const handler = system.afterEvents.scriptEventReceive.subscribe(\n async (event) => {\n if (event.id === stopEvent) {\n system.afterEvents.scriptEventReceive.unsubscribe(handler);\n } else if (event.id === payloadEvent) {\n const payload = JSON.parse(event.message) as InputMessage;\n // validate payload\n\n if (!(payload.endpoint in server.endpoints)) {\n returnError(server, payload, `Endpoint ${payload.endpoint} not found`);\n return;\n }\n\n const params = getParams(server.namespace, payload);\n\n const endpoint = server.endpoints[payload.endpoint];\n if (endpoint.schema?.arguments) {\n try {\n validateArray(endpoint.schema.arguments, params);\n } catch (e) {\n returnError(server, payload, `Failed schema validation for arguments: ${e}`);\n }\n }\n\n const response = await endpoint.handler(...params);\n\n if (endpoint.schema?.returnValue) {\n try {\n validate(endpoint.schema.returnValue, response);\n } catch (e) {\n returnError(server, payload, `Failed schema validation for return value: ${e}`);\n }\n }\n\n returnValue(server, payload, response);\n }\n },\n {\n namespaces: [buildServerNamespace(server.namespace)],\n }\n );\n};\n\nexport const stopServer = (server: Server) => {\n sendEvent(serverStopEvent(server));\n};\n\nexport const startServer = (_server: Server) => {\n if (_server.namespace.includes(':')) {\n throw new Error('`:` is not a legal character for a namespace in: ' + _server.namespace);\n }\n\n const server = {\n ..._server,\n endpoints: { ..._server.endpoints },\n };\n\n start(server);\n};\n","export const makeId = (): string => {\n return Math.random().toString(36).substring(2);\n};\n","import { system, world } from '@minecraft/server';\nimport {\n buildServerNamespace,\n sendEvent,\n argsKey,\n InputMessage,\n OutputMessage,\n returnValueKey,\n inputMessageEvent,\n setDynamicPropertyAndExpire,\n} from './Communication';\nimport { makeId } from './Utils';\n\ninterface ResponseListenerInput {\n timeout: number;\n endpoint: string;\n namespace: string;\n localNamespace: string;\n eventKey: string;\n}\n\nconst responseListener = (input: ResponseListenerInput): [() => void, Promise<unknown>] => {\n let handler: ReturnType<typeof system.afterEvents.scriptEventReceive.subscribe>;\n const promise = new Promise<unknown>((resolve, reject) => {\n const cancelHandler = system.runTimeout(() => {\n reject(new Error(`Timeout: Timed out trying to run ${input.endpoint} of ${input.namespace}`));\n }, input.timeout);\n\n handler = system.afterEvents.scriptEventReceive.subscribe(\n (event) => {\n if (event.id === input.eventKey) {\n try {\n const returnMessage: OutputMessage = JSON.parse(event.message);\n if (returnMessage.isError) {\n const errorString = world.getDynamicProperty(returnValueKey(input.namespace, returnMessage)) as string;\n reject(new Error(errorString));\n } else {\n if (returnMessage.hasValue) {\n const returnValue = world.getDynamicProperty(returnValueKey(input.namespace, returnMessage)) as string;\n world.setDynamicProperty(returnValueKey(input.namespace, returnMessage));\n resolve(JSON.parse(returnValue));\n } else {\n resolve(undefined);\n }\n }\n } catch (e) {\n reject(e);\n } finally {\n system.clearRun(cancelHandler);\n }\n }\n },\n {\n namespaces: [input.localNamespace],\n }\n );\n });\n\n const clean = () => {\n system.afterEvents.scriptEventReceive.unsubscribe(handler);\n };\n\n return [clean, promise];\n};\n\nexport const sendMessage = async (\n namespace: string,\n endpoint: string,\n args: Array<unknown> | undefined,\n timeout: number = 60\n): Promise<unknown> => {\n const messageId = makeId();\n const localNamespace = `${buildServerNamespace(namespace)}_${messageId}`;\n const eventKey = `${localNamespace}:${endpoint}`;\n\n const message: InputMessage = {\n id: messageId,\n endpoint: endpoint,\n hasArguments: args !== undefined && args.length > 0,\n timeout,\n };\n\n const [clean, promise] = responseListener({\n endpoint,\n eventKey,\n localNamespace,\n namespace,\n timeout,\n });\n\n try {\n if (message.hasArguments) {\n const argumentsKey = argsKey(namespace, message);\n setDynamicPropertyAndExpire(argumentsKey, args, timeout);\n }\n\n sendEvent(`${inputMessageEvent(namespace)} ${JSON.stringify(message)}`);\n return await promise;\n } finally {\n clean();\n }\n};\n"],"names":[],"mappings":";;AAiBA,MAAM,uBAAuB,GAAG,eAAe;AAExC,MAAM,oBAAoB,GAAG,CAAC,SAAiB,KAAK,CAAG,EAAA,uBAAuB,CAAI,CAAA,EAAA,SAAS,EAAE;AAE7F,MAAM,iBAAiB,GAAG,CAAC,SAAiB,KAAK,GAAG,oBAAoB,CAAC,SAAS,CAAC,oBAAoB;AAEvG,MAAM,SAAS,GAAG,CAAC,KAAa,KAAI;IACzC,cAAc,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,KAAI;AAClC,QAAA,OAAO,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAe,YAAA,EAAA,KAAK,EAAE,CAAC,CAAC,YAAY;AACvF,KAAC,CAAC;AACJ,CAAC;AAEM,MAAM,OAAO,GAAG,CAAC,SAAiB,EAAE,OAAgB,KACzD,CAAA,EAAG,oBAAoB,CAAC,SAAS,CAAC,CAAA,aAAA,EAAgB,OAAO,CAAC,QAAQ,CAAA,CAAA,EAAI,OAAO,CAAC,EAAE,CAAA,KAAA,CAAO;AAClF,MAAM,cAAc,GAAG,CAAC,SAAiB,EAAE,OAAgB,KAChE,CAAA,EAAG,oBAAoB,CAAC,SAAS,CAAC,CAAA,aAAA,EAAgB,OAAO,CAAC,QAAQ,CAAA,CAAA,EAAI,OAAO,CAAC,EAAE,CAAA,OAAA,CAAS;AAEpF,MAAM,2BAA2B,GAAG,CAAC,GAAW,EAAE,KAAc,EAAE,OAAe,KAAI;AAC1F,IAAA,KAAK,CAAC,kBAAkB,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AACpD,IAAA,MAAM,CAAC,UAAU,CAAC,MAAK;AACrB,QAAA,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC;KAC9B,EAAE,OAAO,CAAC;AACb,CAAC;;ICvCW;AAAZ,CAAA,UAAY,eAAe,EAAA;AACzB,IAAA,eAAA,CAAA,eAAA,CAAA,QAAA,CAAA,GAAA,CAAA,CAAA,GAAA,QAAM;AACN,IAAA,eAAA,CAAA,eAAA,CAAA,QAAA,CAAA,GAAA,CAAA,CAAA,GAAA,QAAM;AACN,IAAA,eAAA,CAAA,eAAA,CAAA,QAAA,CAAA,GAAA,CAAA,CAAA,GAAA,QAAM;AACN,IAAA,eAAA,CAAA,eAAA,CAAA,OAAA,CAAA,GAAA,CAAA,CAAA,GAAA,OAAK;AACL,IAAA,eAAA,CAAA,eAAA,CAAA,MAAA,CAAA,GAAA,CAAA,CAAA,GAAA,MAAI;AACJ,IAAA,eAAA,CAAA,eAAA,CAAA,KAAA,CAAA,GAAA,CAAA,CAAA,GAAA,KAAG;AACL,CAAC,EAPW,eAAe,KAAf,eAAe,GAO1B,EAAA,CAAA,CAAA;AAkDD,MAAM,YAAY,GAAG,CAAC,MAAuB,EAAE,GAAY,KAAI;AAC7D,IAAA,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;AACtB,QAAA,IAAI,GAAG,KAAK,SAAS,EAAE;AACrB,YAAA,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC;;;AAIjE,IAAA,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;AACrB,QAAA,IAAI,GAAG,KAAK,IAAI,EAAE;AAChB,YAAA,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC;;;AAGrE,CAAC;MAEY,QAAQ,GAAG,CAAC,MAAmB,EAAE,GAAY,KAAI;AAC5D,IAAA,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC;AAE1B,IAAA,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;QACzB,IAAI,MAAM,GAAG,KAAK;AAClB,QAAA,KAAK,MAAM,SAAS,IAAI,MAAM,EAAE;AAC9B,YAAA,IAAI;AACF,gBAAA,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC;gBACxB,MAAM,GAAG,IAAI;gBACb;;YACA,OAAO,CAAC,EAAE;AACV,gBAAA,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;;;QAIpB,IAAI,CAAC,MAAM,EAAE;AACX,YAAA,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC;;QAEnC;;AAGF,IAAA,IAAI,MAAM,KAAK,eAAe,CAAC,GAAG,EAAE;QAClC;;AAGF,IAAA,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC;IAEzB,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,EAAE;QACrC;;IAGF,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,CAAC,MAAM,EAAE;QAC1C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AACtD,YAAA,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC;;;SAExD,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,CAAC,KAAK,EAAE;QAChD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;AACvB,YAAA,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC;;AAGjD,QAAA,IAAI,MAAM,CAAC,KAAK,EAAE;AAChB,YAAA,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE;AACvB,gBAAA,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC;;;;SAG5B,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,CAAC,MAAM,EAAE;AACjD,QAAA,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AAC3B,YAAA,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC;;;SAE5C,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,CAAC,IAAI,EAAE;AAC/C,QAAA,IAAI,OAAO,GAAG,KAAK,SAAS,EAAE;AAC5B,YAAA,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC;;;SAE1C,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,CAAC,MAAM,EAAE;AACjD,QAAA,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;AACjD,YAAA,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC;;AAGlD,QAAA,IAAI,MAAM,CAAC,OAAO,EAAE;YAClB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;AAClC,gBAAA,IAAI,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE;AACzB,oBAAA,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAG,GAA0B,CAAC,GAAG,CAAC,CAAC;;qBAC1D;AACL,oBAAA,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;AACrB,wBAAA,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,GAAG,CAAC;;oBAGxD,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAG,GAA0B,CAAC,GAAG,CAAC,CAAC;;;;AAG3D,aAAA,IAAI,MAAM,CAAC,SAAS,EAAE;AAC3B,YAAA,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS;YAClC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;;;AAG/D;MAEa,aAAa,GAAG,CAAC,OAA2B,EAAE,IAAoB,KAAI;AACjF,IAAA,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC;IAChB,OAAO,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE;AACnC,QAAA,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;;AAGtB,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACvC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;;AAEjC;AAEA,MAAM,SAAS,GAAG,CAAC,MAAmB,KAAoB;AACxD,IAAA,IAAI,MAAM,KAAK,eAAe,CAAC,MAAM,EAAE;QACrC,OAAO;YACL,IAAI,EAAE,eAAe,CAAC,MAAM;SAC7B;;AACI,SAAA,IAAI,MAAM,KAAK,eAAe,CAAC,MAAM,EAAE;QAC5C,OAAO;YACL,IAAI,EAAE,eAAe,CAAC,MAAM;SAC7B;;AACI,SAAA,IAAI,MAAM,KAAK,eAAe,CAAC,MAAM,EAAE;QAC5C,OAAO;YACL,IAAI,EAAE,eAAe,CAAC,MAAM;SAC7B;;AACI,SAAA,IAAI,MAAM,KAAK,eAAe,CAAC,KAAK,EAAE;QAC3C,OAAO;YACL,IAAI,EAAE,eAAe,CAAC,KAAK;SAC5B;;AACI,SAAA,IAAI,MAAM,KAAK,eAAe,CAAC,IAAI,EAAE;QAC1C,OAAO;YACL,IAAI,EAAE,eAAe,CAAC,IAAI;SAC3B;;AAGH,IAAA,OAAO,MAAM;AACf,CAAC;;AC1JD,MAAM,eAAe,GAAG,CAAC,MAAc,KAAK,CAAG,EAAA,oBAAoB,CAAC,MAAM,CAAC,SAAS,CAAC,iBAAiB;AACtG,MAAM,iBAAiB,GAAG,CAAC,SAAiB,EAAE,OAAsB,KAAI;AACtE,IAAA,MAAM,cAAc,GAAG,CAAG,EAAA,oBAAoB,CAAC,SAAS,CAAC,CAAA,CAAA,EAAI,OAAO,CAAC,EAAE,CAAA,CAAE;AACzE,IAAA,OAAO,GAAG,cAAc,CAAA,CAAA,EAAI,OAAO,CAAC,QAAQ,EAAE;AAChD,CAAC;AAED,MAAM,WAAW,GAAG,CAAC,MAAc,EAAE,OAAqB,EAAE,KAAa,KAAI;AAC3E,IAAA,MAAM,OAAO,GAAkB;QAC7B,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,QAAQ,EAAE,OAAO,CAAC,QAAQ;AAC1B,QAAA,QAAQ,EAAE,KAAK;AACf,QAAA,OAAO,EAAE,IAAI;KACd;IAED,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC;IACrD,2BAA2B,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC;AAExD,IAAA,SAAS,CAAC,CAAG,EAAA,iBAAiB,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAI,CAAA,EAAA,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA,CAAE,CAAC;AACzF,CAAC;AAED,MAAM,WAAW,GAAG,CAAC,MAAc,EAAE,OAAqB,EAAE,KAAc,KAAI;AAC5E,IAAA,MAAM,OAAO,GAAkB;QAC7B,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,QAAQ,EAAE,KAAK,KAAK,SAAS;AAC7B,QAAA,OAAO,EAAE,KAAK;KACf;AAED,IAAA,IAAI,KAAK,KAAK,SAAS,EAAE;QACvB,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC;QACrD,2BAA2B,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC;;AAG1D,IAAA,SAAS,CAAC,CAAG,EAAA,iBAAiB,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAI,CAAA,EAAA,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA,CAAE,CAAC;AACzF,CAAC;AAED,MAAM,SAAS,GAAG,CAAC,SAAiB,EAAE,OAAqB,KAAoB;AAC7E,IAAA,IAAI,OAAO,CAAC,YAAY,EAAE;AACxB,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,kBAAkB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAW,CAA8B;;AAGjH,IAAA,OAAO,EAAE;AACX,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,MAAc,KAAI;AAC/B,IAAA,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC;IACzC,MAAM,YAAY,GAAG,iBAAiB,CAAC,MAAM,CAAC,SAAS,CAAC;AACxD,IAAA,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAC7D,OAAO,KAAK,KAAI;AACd,QAAA,IAAI,KAAK,CAAC,EAAE,KAAK,SAAS,EAAE;YAC1B,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,WAAW,CAAC,OAAO,CAAC;;AACrD,aAAA,IAAI,KAAK,CAAC,EAAE,KAAK,YAAY,EAAE;YACpC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAiB;;YAGzD,IAAI,EAAE,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,EAAE;gBAC3C,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,CAAY,SAAA,EAAA,OAAO,CAAC,QAAQ,CAAY,UAAA,CAAA,CAAC;gBACtE;;YAGF,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC;YAEnD,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC;AACnD,YAAA,IAAI,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE;AAC9B,gBAAA,IAAI;oBACF,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC;;gBAChD,OAAO,CAAC,EAAE;oBACV,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,CAA2C,wCAAA,EAAA,CAAC,CAAE,CAAA,CAAC;;;YAIhF,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC;AAElD,YAAA,IAAI,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE;AAChC,gBAAA,IAAI;oBACF,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC;;gBAC/C,OAAO,CAAC,EAAE;oBACV,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,CAA8C,2CAAA,EAAA,CAAC,CAAE,CAAA,CAAC;;;AAInF,YAAA,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC;;AAE1C,KAAC,EACD;QACE,UAAU,EAAE,CAAC,oBAAoB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AACrD,KAAA,CACF;AACH,CAAC;AAMY,MAAA,WAAW,GAAG,CAAC,OAAe,KAAI;IAC7C,IAAI,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;QACnC,MAAM,IAAI,KAAK,CAAC,mDAAmD,GAAG,OAAO,CAAC,SAAS,CAAC;;AAG1F,IAAA,MAAM,MAAM,GAAG;AACb,QAAA,GAAG,OAAO;AACV,QAAA,SAAS,EAAE,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE;KACpC;IAED,KAAK,CAAC,MAAM,CAAC;AACf;;ACtIO,MAAM,MAAM,GAAG,MAAa;AACjC,IAAA,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAChD,CAAC;;ACmBD,MAAM,gBAAgB,GAAG,CAAC,KAA4B,KAAoC;AACxF,IAAA,IAAI,OAA2E;IAC/E,MAAM,OAAO,GAAG,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,MAAM,KAAI;AACvD,QAAA,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,MAAK;AAC3C,YAAA,MAAM,CAAC,IAAI,KAAK,CAAC,oCAAoC,KAAK,CAAC,QAAQ,CAAA,IAAA,EAAO,KAAK,CAAC,SAAS,CAAE,CAAA,CAAC,CAAC;AAC/F,SAAC,EAAE,KAAK,CAAC,OAAO,CAAC;AAEjB,QAAA,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,SAAS,CACvD,CAAC,KAAK,KAAI;YACR,IAAI,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,QAAQ,EAAE;AAC/B,gBAAA,IAAI;oBACF,MAAM,aAAa,GAAkB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;AAC9D,oBAAA,IAAI,aAAa,CAAC,OAAO,EAAE;AACzB,wBAAA,MAAM,WAAW,GAAG,KAAK,CAAC,kBAAkB,CAAC,cAAc,CAAC,KAAK,CAAC,SAAS,EAAE,aAAa,CAAC,CAAW;AACtG,wBAAA,MAAM,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;;yBACzB;AACL,wBAAA,IAAI,aAAa,CAAC,QAAQ,EAAE;AAC1B,4BAAA,MAAM,WAAW,GAAG,KAAK,CAAC,kBAAkB,CAAC,cAAc,CAAC,KAAK,CAAC,SAAS,EAAE,aAAa,CAAC,CAAW;AACtG,4BAAA,KAAK,CAAC,kBAAkB,CAAC,cAAc,CAAC,KAAK,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;4BACxE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;;6BAC3B;4BACL,OAAO,CAAC,SAAS,CAAC;;;;gBAGtB,OAAO,CAAC,EAAE;oBACV,MAAM,CAAC,CAAC,CAAC;;wBACD;AACR,oBAAA,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC;;;AAGpC,SAAC,EACD;AACE,YAAA,UAAU,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC;AACnC,SAAA,CACF;AACH,KAAC,CAAC;IAEF,MAAM,KAAK,GAAG,MAAK;QACjB,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,WAAW,CAAC,OAAO,CAAC;AAC5D,KAAC;AAED,IAAA,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC;AACzB,CAAC;AAEM,MAAM,WAAW,GAAG,OACzB,SAAiB,EACjB,QAAgB,EAChB,IAAgC,EAChC,OAAkB,GAAA,EAAE,KACA;AACpB,IAAA,MAAM,SAAS,GAAG,MAAM,EAAE;IAC1B,MAAM,cAAc,GAAG,CAAA,EAAG,oBAAoB,CAAC,SAAS,CAAC,CAAA,CAAA,EAAI,SAAS,CAAA,CAAE;AACxE,IAAA,MAAM,QAAQ,GAAG,CAAA,EAAG,cAAc,CAAI,CAAA,EAAA,QAAQ,EAAE;AAEhD,IAAA,MAAM,OAAO,GAAiB;AAC5B,QAAA,EAAE,EAAE,SAAS;AACb,QAAA,QAAQ,EAAE,QAAQ;QAClB,YAAY,EAAE,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QACnD,OAAO;KACR;AAED,IAAA,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,gBAAgB,CAAC;QACxC,QAAQ;QACR,QAAQ;QACR,cAAc;QACd,SAAS;QACT,OAAO;AACR,KAAA,CAAC;AAEF,IAAA,IAAI;AACF,QAAA,IAAI,OAAO,CAAC,YAAY,EAAE;YACxB,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC;AAChD,YAAA,2BAA2B,CAAC,YAAY,EAAE,IAAI,EAAE,OAAO,CAAC;;AAG1D,QAAA,SAAS,CAAC,CAAA,EAAG,iBAAiB,CAAC,SAAS,CAAC,CAAA,CAAA,EAAI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA,CAAE,CAAC;QACvE,OAAO,MAAM,OAAO;;YACZ;AACR,QAAA,KAAK,EAAE;;AAEX;;;;"}
|
|
1
|
+
{"version":3,"file":"MinecraftRMI.js","sources":["../src/Communication.ts","../src/Schema.ts","../src/Utils.ts","../src/Transport.ts","../src/Server.ts","../src/Client.ts"],"sourcesContent":["import { DimensionTypes, world } from '@minecraft/server';\n\ninterface Message {\n id: string;\n endpoint: string;\n}\n\nexport interface InputMessage extends Message {\n timeout: number;\n}\n\nexport interface OutputMessage extends Message {\n isError: boolean;\n hasReturn: boolean;\n}\n\nconst MINESCRIPTERS_NAMESPACE = 'minescripters';\n\nexport const buildServerNamespace = (namespace: string) => `${MINESCRIPTERS_NAMESPACE}_${namespace}`;\n\nexport const inputMessageEvent = (namespace: string) => `${buildServerNamespace(namespace)}:rmi.event-payload`;\n\nexport const sendEvent = (event: string) => {\n DimensionTypes.getAll().some((dt) => {\n return world.getDimension(dt.typeId)?.runCommand(`scriptevent ${event}`).successCount;\n });\n};\n","export enum SchemaEntryType {\n OBJECT,\n NUMBER,\n STRING,\n ARRAY,\n BOOL,\n ANY,\n}\n\ninterface SchemaEntryBase {\n isOptional?: boolean;\n allowNull?: boolean;\n}\n\nexport interface SchemaEntryNumber extends SchemaEntryBase {\n type: SchemaEntryType.NUMBER;\n}\n\nexport interface SchemaEntryString extends SchemaEntryBase {\n type: SchemaEntryType.STRING;\n}\n\nexport interface SchemaEntryObject extends SchemaEntryBase {\n type: SchemaEntryType.OBJECT;\n extraKeys?: SchemaEntry;\n entries?: {\n [key: string]: SchemaEntry;\n };\n}\n\nexport interface SchemaEntryBool extends SchemaEntryBase {\n type: SchemaEntryType.BOOL;\n}\n\nexport interface SchemaEntryArray extends SchemaEntryBase {\n type: SchemaEntryType.ARRAY;\n items?: SchemaEntry;\n}\n\nexport type SchemaEntry =\n | SchemaEntryNumber\n | SchemaEntryString\n | SchemaEntryBool\n | SchemaEntryObject\n | SchemaEntryArray\n | SchemaEntryType\n | Array<SchemaEntry>;\n\ntype InternalSchema =\n | SchemaEntryNumber\n | SchemaEntryString\n | SchemaEntryBool\n | SchemaEntryObject\n | SchemaEntryArray\n | SchemaEntryType.ANY\n | Array<SchemaEntry>;\n\nconst validateBase = (schema: SchemaEntryBase, obj: unknown) => {\n if (!schema.isOptional) {\n if (obj === undefined) {\n throw new Error('Invalid schema, undefined but not optional');\n }\n }\n\n if (!schema.allowNull) {\n if (obj === null) {\n throw new Error('Invalid schema, null but does not allow null');\n }\n }\n};\n\nexport const validate = (schema: SchemaEntry, obj: unknown) => {\n schema = normalize(schema);\n\n if (Array.isArray(schema)) {\n let passed = false;\n for (const subSchema of schema) {\n try {\n validate(subSchema, obj);\n passed = true;\n break;\n } catch (e) {\n console.error(e);\n }\n }\n\n if (!passed) {\n throw new Error('Invalid schema');\n }\n return;\n }\n\n if (schema === SchemaEntryType.ANY) {\n return;\n }\n\n validateBase(schema, obj);\n\n if (obj === null || obj === undefined) {\n return;\n }\n\n if (schema.type === SchemaEntryType.NUMBER) {\n if (typeof obj !== 'number' && typeof obj !== 'bigint') {\n throw new Error('Invalid schema, not a number (or bigint)');\n }\n } else if (schema.type === SchemaEntryType.ARRAY) {\n if (!Array.isArray(obj)) {\n throw new Error('Invalid schema, not an array');\n }\n\n if (schema.items) {\n for (const entry of obj) {\n validate(schema.items, entry);\n }\n }\n } else if (schema.type === SchemaEntryType.STRING) {\n if (typeof obj !== 'string') {\n throw new Error('Invalid schema, not a string');\n }\n } else if (schema.type === SchemaEntryType.BOOL) {\n if (typeof obj !== 'boolean') {\n throw new Error('Invalid schema, not a bool');\n }\n } else if (schema.type === SchemaEntryType.OBJECT) {\n if (typeof obj !== 'object' || Array.isArray(obj)) {\n throw new Error('Invalid schema, not an object');\n }\n\n if (schema.entries) {\n for (const key of Object.keys(obj)) {\n if (key in schema.entries) {\n validate(schema.entries[key], (obj as { [key]: unknown })[key]);\n } else {\n if (!schema.extraKeys) {\n throw new Error('Invalid schema, invalid key: ' + key);\n }\n\n validate(schema.extraKeys, (obj as { [key]: unknown })[key]);\n }\n }\n } else if (schema.extraKeys) {\n const extraKeys = schema.extraKeys;\n Object.values(obj).forEach((o) => validate(extraKeys, o));\n }\n }\n};\n\nexport const validateArray = (schemas: Array<SchemaEntry>, objs: Array<unknown>) => {\n objs = [...objs];\n while (schemas.length > objs.length) {\n objs.push(undefined);\n }\n\n for (let i = 0; i < schemas.length; i++) {\n validate(schemas[i], objs[i]);\n }\n};\n\nconst normalize = (schema: SchemaEntry): InternalSchema => {\n if (schema === SchemaEntryType.NUMBER) {\n return {\n type: SchemaEntryType.NUMBER,\n };\n } else if (schema === SchemaEntryType.STRING) {\n return {\n type: SchemaEntryType.STRING,\n };\n } else if (schema === SchemaEntryType.OBJECT) {\n return {\n type: SchemaEntryType.OBJECT,\n };\n } else if (schema === SchemaEntryType.ARRAY) {\n return {\n type: SchemaEntryType.ARRAY,\n };\n } else if (schema === SchemaEntryType.BOOL) {\n return {\n type: SchemaEntryType.BOOL,\n };\n }\n\n return schema;\n};\n","export const makeId = (): string => {\n return Math.random().toString(36).substring(2);\n};\n","import { system } from '@minecraft/server';\nimport { makeId } from './Utils';\nimport { sendEvent } from './Communication';\n\ninterface TransportHeader {\n id: string;\n chunkCount?: number;\n header: unknown;\n}\n\nexport interface Received {\n header: unknown;\n data?: unknown;\n}\n\nconst RMI_NAMESPACE = 'minescripters_rmi';\n// Prevents the scriptevent parser from identifying it as a json object an failing to parse\nconst CHUNK_PADDING = '-';\n\nconst receiverScriptEvent = (id: string) => `${RMI_NAMESPACE}:${id}.receiver`;\nconst senderScriptEvent = (id: string) => `${RMI_NAMESPACE}:${id}.sender`;\n\nconst promiseResolver = (): [Promise<void>, () => void] => {\n let resolver: () => void = () => {};\n return [\n new Promise((resolve) => {\n resolver = resolve;\n }),\n resolver,\n ];\n};\n\nconst ackWaiter = async (scriptEvent: string) => {\n const [acked, ack] = promiseResolver();\n\n const namespace = scriptEvent.split(':')[0];\n const listener = system.afterEvents.scriptEventReceive.subscribe(\n (event) => {\n if (event.id === scriptEvent) {\n ack();\n }\n },\n {\n namespaces: [namespace],\n }\n );\n\n await acked;\n\n system.afterEvents.scriptEventReceive.unsubscribe(listener);\n};\n\nexport const internalSendMessage = async (\n header: unknown,\n data: unknown,\n scriptevent: string,\n maxMessageSize = 2048\n) => {\n const id = makeId();\n\n const chunks: Array<string> = [];\n\n if (data !== undefined) {\n const dataString = JSON.stringify(data);\n for (let i = 0; i < maxMessageSize; i += maxMessageSize) {\n chunks.push(dataString.slice(i, i + maxMessageSize));\n }\n }\n\n const transportHeader: TransportHeader = {\n id,\n header,\n };\n\n if (chunks.length > 0) {\n transportHeader.chunkCount = chunks.length;\n }\n\n const initialAck = ackWaiter(senderScriptEvent(id));\n const rawTransportHeader = JSON.stringify(transportHeader);\n if (rawTransportHeader.length > 2048) {\n console.error('Transport header is bigger than 2048 characters:', rawTransportHeader);\n throw new Error('Transport header is bigger than 2048');\n }\n\n sendEvent(`${scriptevent} ${rawTransportHeader}`);\n\n await initialAck;\n if (chunks.length > 0) {\n const chunksAck = ackWaiter(senderScriptEvent(id));\n\n for (const chunk of chunks) {\n sendEvent(`${receiverScriptEvent(id)} ${CHUNK_PADDING}${chunk}`);\n }\n\n await chunksAck;\n }\n};\n\nexport const internalMessageReceived = async (rawHeader: string): Promise<Received> => {\n const header = JSON.parse(rawHeader) as Partial<TransportHeader>;\n const id = header.id;\n\n if (!id) {\n console.error('Unknown data received:', header);\n throw new Error('Unknow data received');\n }\n\n const chunkCount = header.chunkCount;\n const chunks: Array<string> = [];\n let data = undefined;\n\n if (chunkCount && chunkCount > 0) {\n const [acked, ack] = promiseResolver();\n\n const listener = system.afterEvents.scriptEventReceive.subscribe(\n (event) => {\n if (event.id === receiverScriptEvent(id)) {\n // Removes CHUNK_PADDING\n chunks.push(event.message.slice(1));\n\n if (chunks.length === chunkCount) {\n ack();\n }\n }\n },\n {\n namespaces: [RMI_NAMESPACE],\n }\n );\n\n sendEvent(`${senderScriptEvent(id)}`);\n\n await acked;\n system.afterEvents.scriptEventReceive.unsubscribe(listener);\n\n const rawData = chunks.join('');\n\n data = JSON.parse(rawData);\n sendEvent(`${senderScriptEvent(id)}`);\n }\n\n return {\n header: header.header,\n data,\n };\n};\n","import { system } from '@minecraft/server';\nimport { buildServerNamespace, sendEvent, InputMessage, OutputMessage, inputMessageEvent } from './Communication';\nimport { SchemaEntry, validate, validateArray } from './Schema';\nimport { internalMessageReceived, internalSendMessage } from './Transport';\n\nexport interface Server {\n namespace: string;\n endpoints: Record<string, Endpoint>;\n}\n\nexport interface Endpoint {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n handler: (...params: Array<any>) => unknown;\n schema?: EndpointSchema;\n}\n\nexport type EndpointSchema = {\n arguments?: Array<SchemaEntry>;\n returnValue?: SchemaEntry;\n};\n\nconst serverStopEvent = (server: Server) => `${buildServerNamespace(server.namespace)}:rmi.event-stop`;\nconst serverReturnEvent = (namespace: string, message: OutputMessage) => {\n const localNamespace = `${buildServerNamespace(namespace)}_${message.id}`;\n return `${localNamespace}:${message.endpoint}`;\n};\n\nconst returnError = (server: Server, payload: InputMessage, error: string) => {\n const message: OutputMessage = {\n id: payload.id,\n endpoint: payload.endpoint,\n hasReturn: false,\n isError: true,\n };\n\n internalSendMessage(message, error, serverReturnEvent(server.namespace, message));\n};\n\nconst returnValue = (server: Server, payload: InputMessage, value: unknown) => {\n const message: OutputMessage = {\n id: payload.id,\n endpoint: payload.endpoint,\n hasReturn: value !== undefined,\n isError: false,\n };\n\n internalSendMessage(message, value, serverReturnEvent(server.namespace, message));\n};\n\nconst start = (server: Server) => {\n const stopEvent = serverStopEvent(server);\n const payloadEvent = inputMessageEvent(server.namespace);\n const handler = system.afterEvents.scriptEventReceive.subscribe(\n async (event) => {\n if (event.id === stopEvent) {\n system.afterEvents.scriptEventReceive.unsubscribe(handler);\n } else if (event.id === payloadEvent) {\n const messageReceived = await internalMessageReceived(event.message);\n const payload = messageReceived.header as InputMessage;\n\n if (!(payload.endpoint in server.endpoints)) {\n returnError(server, payload, `Endpoint ${payload.endpoint} not found`);\n return;\n }\n\n const params = (messageReceived.data === undefined ? [] : messageReceived.data) as Array<unknown>;\n\n const endpoint = server.endpoints[payload.endpoint];\n if (endpoint.schema?.arguments) {\n try {\n validateArray(endpoint.schema.arguments, params);\n } catch (e) {\n returnError(server, payload, `Failed schema validation for arguments: ${e}`);\n }\n }\n\n const response = await endpoint.handler(...params);\n\n if (endpoint.schema?.returnValue) {\n try {\n validate(endpoint.schema.returnValue, response);\n } catch (e) {\n returnError(server, payload, `Failed schema validation for return value: ${e}`);\n }\n }\n\n returnValue(server, payload, response);\n }\n },\n {\n namespaces: [buildServerNamespace(server.namespace)],\n }\n );\n};\n\nexport const stopServer = (server: Server) => {\n sendEvent(serverStopEvent(server));\n};\n\nexport const startServer = (_server: Server) => {\n if (_server.namespace.includes(':')) {\n throw new Error('`:` is not a legal character for a namespace in: ' + _server.namespace);\n }\n\n const server = {\n ..._server,\n endpoints: { ..._server.endpoints },\n };\n\n start(server);\n};\n","import { system } from '@minecraft/server';\nimport { buildServerNamespace, InputMessage, OutputMessage, inputMessageEvent } from './Communication';\nimport { makeId } from './Utils';\nimport { internalMessageReceived, internalSendMessage } from './Transport';\n\ninterface ResponseListenerInput {\n timeout: number;\n endpoint: string;\n namespace: string;\n localNamespace: string;\n eventKey: string;\n}\n\nconst responseListener = (input: ResponseListenerInput): [() => void, Promise<unknown>] => {\n let handler: ReturnType<typeof system.afterEvents.scriptEventReceive.subscribe>;\n const promise = new Promise<unknown>((resolve, reject) => {\n const cancelHandler = system.runTimeout(() => {\n reject(new Error(`Timeout: Timed out trying to run ${input.endpoint} of ${input.namespace}`));\n }, input.timeout);\n\n handler = system.afterEvents.scriptEventReceive.subscribe(\n async (event) => {\n if (event.id === input.eventKey) {\n try {\n const response = await internalMessageReceived(event.message);\n const returnMessage: OutputMessage = response.header as OutputMessage;\n if (returnMessage.isError) {\n reject(new Error(response.data as string));\n } else {\n if (returnMessage.hasReturn) {\n resolve(response.data);\n } else {\n resolve(undefined);\n }\n }\n } catch (e) {\n reject(e);\n } finally {\n system.clearRun(cancelHandler);\n }\n }\n },\n {\n namespaces: [input.localNamespace],\n }\n );\n });\n\n const clean = () => {\n system.afterEvents.scriptEventReceive.unsubscribe(handler);\n };\n\n return [clean, promise];\n};\n\nexport const sendMessage = async (\n namespace: string,\n endpoint: string,\n args: Array<unknown> | undefined,\n timeout: number = 60\n): Promise<unknown> => {\n const messageId = makeId();\n const localNamespace = `${buildServerNamespace(namespace)}_${messageId}`;\n const eventKey = `${localNamespace}:${endpoint}`;\n\n const message: InputMessage = {\n id: messageId,\n endpoint: endpoint,\n timeout,\n };\n\n const [clean, promise] = responseListener({\n endpoint,\n eventKey,\n localNamespace,\n namespace,\n timeout,\n });\n\n try {\n internalSendMessage(message, args, inputMessageEvent(namespace));\n\n return await promise;\n } finally {\n clean();\n }\n};\n"],"names":[],"mappings":"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"}
|