@mine-scripters/minecraft-rmi 1.0.0 → 1.0.2
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 +116 -52
- 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,20 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { system } from '@minecraft/server';
|
|
2
2
|
|
|
3
3
|
const MINESCRIPTERS_NAMESPACE = 'minescripters';
|
|
4
4
|
const buildServerNamespace = (namespace) => `${MINESCRIPTERS_NAMESPACE}_${namespace}`;
|
|
5
5
|
const inputMessageEvent = (namespace) => `${buildServerNamespace(namespace)}:rmi.event-payload`;
|
|
6
|
-
const sendEvent = (event) => {
|
|
7
|
-
|
|
8
|
-
return world.getDimension(dt.typeId)?.runCommand(`scriptevent ${event}`).successCount;
|
|
9
|
-
});
|
|
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);
|
|
6
|
+
const sendEvent = (event, message) => {
|
|
7
|
+
system.sendScriptEvent(event, message);
|
|
18
8
|
};
|
|
19
9
|
|
|
20
10
|
var SchemaEntryType;
|
|
@@ -42,6 +32,7 @@ const validate = (schema, obj) => {
|
|
|
42
32
|
schema = normalize(schema);
|
|
43
33
|
if (Array.isArray(schema)) {
|
|
44
34
|
let passed = false;
|
|
35
|
+
const errors = [];
|
|
45
36
|
for (const subSchema of schema) {
|
|
46
37
|
try {
|
|
47
38
|
validate(subSchema, obj);
|
|
@@ -49,11 +40,11 @@ const validate = (schema, obj) => {
|
|
|
49
40
|
break;
|
|
50
41
|
}
|
|
51
42
|
catch (e) {
|
|
52
|
-
|
|
43
|
+
errors.push(e);
|
|
53
44
|
}
|
|
54
45
|
}
|
|
55
46
|
if (!passed) {
|
|
56
|
-
throw new
|
|
47
|
+
throw new AggregateError(errors, 'Invalid schema, none of the schemas matched');
|
|
57
48
|
}
|
|
58
49
|
return;
|
|
59
50
|
}
|
|
@@ -150,6 +141,102 @@ const normalize = (schema) => {
|
|
|
150
141
|
return schema;
|
|
151
142
|
};
|
|
152
143
|
|
|
144
|
+
const makeId = () => {
|
|
145
|
+
return Math.random().toString(36).substring(2);
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const RMI_NAMESPACE = 'minescripters_rmi';
|
|
149
|
+
const receiverScriptEvent = (id) => `${RMI_NAMESPACE}:${id}.receiver`;
|
|
150
|
+
const senderScriptEvent = (id) => `${RMI_NAMESPACE}:${id}.sender`;
|
|
151
|
+
const promiseResolver = () => {
|
|
152
|
+
let resolver = () => { };
|
|
153
|
+
return [
|
|
154
|
+
new Promise((resolve) => {
|
|
155
|
+
resolver = resolve;
|
|
156
|
+
}),
|
|
157
|
+
resolver,
|
|
158
|
+
];
|
|
159
|
+
};
|
|
160
|
+
const ackWaiter = async (scriptEvent) => {
|
|
161
|
+
const [acked, ack] = promiseResolver();
|
|
162
|
+
const namespace = scriptEvent.split(':')[0];
|
|
163
|
+
const listener = system.afterEvents.scriptEventReceive.subscribe((event) => {
|
|
164
|
+
if (event.id === scriptEvent) {
|
|
165
|
+
ack();
|
|
166
|
+
}
|
|
167
|
+
}, {
|
|
168
|
+
namespaces: [namespace],
|
|
169
|
+
});
|
|
170
|
+
await acked;
|
|
171
|
+
system.afterEvents.scriptEventReceive.unsubscribe(listener);
|
|
172
|
+
};
|
|
173
|
+
const internalSendMessage = async (header, data, scriptevent, maxMessageSize = 2048) => {
|
|
174
|
+
const id = makeId();
|
|
175
|
+
const chunks = [];
|
|
176
|
+
if (data !== undefined) {
|
|
177
|
+
const dataString = JSON.stringify(data);
|
|
178
|
+
for (let i = 0; i < dataString.length; i += maxMessageSize) {
|
|
179
|
+
chunks.push(dataString.slice(i, i + maxMessageSize));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const transportHeader = {
|
|
183
|
+
id,
|
|
184
|
+
header,
|
|
185
|
+
};
|
|
186
|
+
if (chunks.length > 0) {
|
|
187
|
+
transportHeader.chunkCount = chunks.length;
|
|
188
|
+
}
|
|
189
|
+
const initialAck = ackWaiter(senderScriptEvent(id));
|
|
190
|
+
const rawTransportHeader = JSON.stringify(transportHeader);
|
|
191
|
+
if (rawTransportHeader.length > 2048) {
|
|
192
|
+
console.error('Transport header is bigger than 2048 characters:', rawTransportHeader);
|
|
193
|
+
throw new Error('Transport header is bigger than 2048');
|
|
194
|
+
}
|
|
195
|
+
sendEvent(scriptevent, rawTransportHeader);
|
|
196
|
+
await initialAck;
|
|
197
|
+
if (chunks.length > 0) {
|
|
198
|
+
const chunksAck = ackWaiter(senderScriptEvent(id));
|
|
199
|
+
for (const chunk of chunks) {
|
|
200
|
+
sendEvent(receiverScriptEvent(id), chunk);
|
|
201
|
+
}
|
|
202
|
+
await chunksAck;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
const internalMessageReceived = async (rawHeader) => {
|
|
206
|
+
const header = JSON.parse(rawHeader);
|
|
207
|
+
const id = header.id;
|
|
208
|
+
if (!id) {
|
|
209
|
+
console.error('Unknown data received:', header);
|
|
210
|
+
throw new Error('Unknow data received');
|
|
211
|
+
}
|
|
212
|
+
const chunkCount = header.chunkCount;
|
|
213
|
+
const chunks = [];
|
|
214
|
+
let data = undefined;
|
|
215
|
+
if (chunkCount && chunkCount > 0) {
|
|
216
|
+
const [acked, ack] = promiseResolver();
|
|
217
|
+
const listener = system.afterEvents.scriptEventReceive.subscribe((event) => {
|
|
218
|
+
if (event.id === receiverScriptEvent(id)) {
|
|
219
|
+
chunks.push(event.message);
|
|
220
|
+
if (chunks.length === chunkCount) {
|
|
221
|
+
ack();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}, {
|
|
225
|
+
namespaces: [RMI_NAMESPACE],
|
|
226
|
+
});
|
|
227
|
+
sendEvent(`${senderScriptEvent(id)}`, '');
|
|
228
|
+
await acked;
|
|
229
|
+
system.afterEvents.scriptEventReceive.unsubscribe(listener);
|
|
230
|
+
const rawData = chunks.join('');
|
|
231
|
+
data = JSON.parse(rawData);
|
|
232
|
+
sendEvent(`${senderScriptEvent(id)}`, '');
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
header: header.header,
|
|
236
|
+
data,
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
|
|
153
240
|
const serverStopEvent = (server) => `${buildServerNamespace(server.namespace)}:rmi.event-stop`;
|
|
154
241
|
const serverReturnEvent = (namespace, message) => {
|
|
155
242
|
const localNamespace = `${buildServerNamespace(namespace)}_${message.id}`;
|
|
@@ -159,31 +246,19 @@ const returnError = (server, payload, error) => {
|
|
|
159
246
|
const message = {
|
|
160
247
|
id: payload.id,
|
|
161
248
|
endpoint: payload.endpoint,
|
|
162
|
-
|
|
249
|
+
hasReturn: false,
|
|
163
250
|
isError: true,
|
|
164
251
|
};
|
|
165
|
-
|
|
166
|
-
setDynamicPropertyAndExpire(key, error, payload.timeout);
|
|
167
|
-
sendEvent(`${serverReturnEvent(server.namespace, message)} ${JSON.stringify(message)}`);
|
|
252
|
+
internalSendMessage(message, error, serverReturnEvent(server.namespace, message));
|
|
168
253
|
};
|
|
169
254
|
const returnValue = (server, payload, value) => {
|
|
170
255
|
const message = {
|
|
171
256
|
id: payload.id,
|
|
172
257
|
endpoint: payload.endpoint,
|
|
173
|
-
|
|
258
|
+
hasReturn: value !== undefined,
|
|
174
259
|
isError: false,
|
|
175
260
|
};
|
|
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 [];
|
|
261
|
+
internalSendMessage(message, value, serverReturnEvent(server.namespace, message));
|
|
187
262
|
};
|
|
188
263
|
const start = (server) => {
|
|
189
264
|
const stopEvent = serverStopEvent(server);
|
|
@@ -193,13 +268,13 @@ const start = (server) => {
|
|
|
193
268
|
system.afterEvents.scriptEventReceive.unsubscribe(handler);
|
|
194
269
|
}
|
|
195
270
|
else if (event.id === payloadEvent) {
|
|
196
|
-
const
|
|
197
|
-
|
|
271
|
+
const messageReceived = await internalMessageReceived(event.message);
|
|
272
|
+
const payload = messageReceived.header;
|
|
198
273
|
if (!(payload.endpoint in server.endpoints)) {
|
|
199
274
|
returnError(server, payload, `Endpoint ${payload.endpoint} not found`);
|
|
200
275
|
return;
|
|
201
276
|
}
|
|
202
|
-
const params =
|
|
277
|
+
const params = (messageReceived.data === undefined ? [] : messageReceived.data);
|
|
203
278
|
const endpoint = server.endpoints[payload.endpoint];
|
|
204
279
|
if (endpoint.schema?.arguments) {
|
|
205
280
|
try {
|
|
@@ -235,29 +310,23 @@ const startServer = (_server) => {
|
|
|
235
310
|
start(server);
|
|
236
311
|
};
|
|
237
312
|
|
|
238
|
-
const makeId = () => {
|
|
239
|
-
return Math.random().toString(36).substring(2);
|
|
240
|
-
};
|
|
241
|
-
|
|
242
313
|
const responseListener = (input) => {
|
|
243
314
|
let handler;
|
|
244
315
|
const promise = new Promise((resolve, reject) => {
|
|
245
316
|
const cancelHandler = system.runTimeout(() => {
|
|
246
317
|
reject(new Error(`Timeout: Timed out trying to run ${input.endpoint} of ${input.namespace}`));
|
|
247
318
|
}, input.timeout);
|
|
248
|
-
handler = system.afterEvents.scriptEventReceive.subscribe((event) => {
|
|
319
|
+
handler = system.afterEvents.scriptEventReceive.subscribe(async (event) => {
|
|
249
320
|
if (event.id === input.eventKey) {
|
|
250
321
|
try {
|
|
251
|
-
const
|
|
322
|
+
const response = await internalMessageReceived(event.message);
|
|
323
|
+
const returnMessage = response.header;
|
|
252
324
|
if (returnMessage.isError) {
|
|
253
|
-
|
|
254
|
-
reject(new Error(errorString));
|
|
325
|
+
reject(new Error(response.data));
|
|
255
326
|
}
|
|
256
327
|
else {
|
|
257
|
-
if (returnMessage.
|
|
258
|
-
|
|
259
|
-
world.setDynamicProperty(returnValueKey(input.namespace, returnMessage));
|
|
260
|
-
resolve(JSON.parse(returnValue));
|
|
328
|
+
if (returnMessage.hasReturn) {
|
|
329
|
+
resolve(response.data);
|
|
261
330
|
}
|
|
262
331
|
else {
|
|
263
332
|
resolve(undefined);
|
|
@@ -287,7 +356,6 @@ const sendMessage = async (namespace, endpoint, args, timeout = 60) => {
|
|
|
287
356
|
const message = {
|
|
288
357
|
id: messageId,
|
|
289
358
|
endpoint: endpoint,
|
|
290
|
-
hasArguments: args !== undefined && args.length > 0,
|
|
291
359
|
timeout,
|
|
292
360
|
};
|
|
293
361
|
const [clean, promise] = responseListener({
|
|
@@ -298,11 +366,7 @@ const sendMessage = async (namespace, endpoint, args, timeout = 60) => {
|
|
|
298
366
|
timeout,
|
|
299
367
|
});
|
|
300
368
|
try {
|
|
301
|
-
|
|
302
|
-
const argumentsKey = argsKey(namespace, message);
|
|
303
|
-
setDynamicPropertyAndExpire(argumentsKey, args, timeout);
|
|
304
|
-
}
|
|
305
|
-
sendEvent(`${inputMessageEvent(namespace)} ${JSON.stringify(message)}`);
|
|
369
|
+
internalSendMessage(message, args, inputMessageEvent(namespace));
|
|
306
370
|
return await promise;
|
|
307
371
|
}
|
|
308
372
|
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 { system } 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, message: string) => {\n system.sendScriptEvent(event, message);\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 const errors = [];\n for (const subSchema of schema) {\n try {\n validate(subSchema, obj);\n passed = true;\n break;\n } catch (e) {\n errors.push(e);\n }\n }\n\n if (!passed) {\n throw new AggregateError(errors, 'Invalid schema, none of the schemas matched');\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\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 < dataString.length; 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);\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 chunks.push(event.message);\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 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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"}
|