diff --git a/README.md b/README.md
index f642b9b..66b1533 100644
--- a/README.md
+++ b/README.md
@@ -39,8 +39,10 @@ Script file | Description
[intercom_inside.ts](./examples/intercom_inside.ts) | An intercom script allowing communication with another room running the [intercom_outside.ts](./examples/intercom_outside.ts) script.
[intercom_outside.ts](./examples/intercom_outside.ts) | An intercom script allowing communication with another room running the [intercom_inside.ts](./examples/intercom_inside.ts) script.
[lock_inside.ts](./examples/lock_inside.ts) | A script that locks a door preventing others from using an exit in the room running the [lock_outside.ts](./examples/lock_outside.ts) script.
-[lock_outside.ts](./examples/lock_outside.ts) | A script that prevents characters from using an exit locked by the script running the [lock_inside.ts](./examples/lock_inside.ts) script.
+[lock_outside.ts](./examples/lock_outside.ts) | A script that prevents characters from using an exit locked by the [lock_inside.ts](./examples/lock_inside.ts) script.
[secret_exit.ts](./examples/secret_exit.ts) | A script that reveals a secret passage when the password "tapeworm" is spoken.
+[vip_list.ts](./examples/vip_list.ts) | A script that manages a list of VIP characters, requested by another room running the [vip_guard.ts](./examples/vip_guard.ts) script.
+[vip_guard.ts](./examples/vip_guard.ts) | A script that prevents characters from using an exit unless they are listed as VIP character by the [vip_list.ts](./examples/vip_list.ts) script.
## About
diff --git a/devbin/devutils/docsconverter.js b/devbin/devutils/docsconverter.js
index b1aecd2..4dfcf25 100644
--- a/devbin/devutils/docsconverter.js
+++ b/devbin/devutils/docsconverter.js
@@ -608,10 +608,16 @@ export default class DocsConverter {
* @return {string} Converted markdown.
*/
_convertToNamedHeaders(text, level = 0, idPrefix, headerCallback) {
+ let parentIds = [];
return text.replace(/^(#+)\s*(.*)/gm, (match, hashes, title) => {
title = title.trim();
const l = level + hashes.length;
- const id = this._stringToId(title, idPrefix);
+ parentIds = parentIds.slice(0, l);
+ let id = this._stringToId(title, idPrefix);
+ id = l > 3 && parentIds[l - 1]
+ ? parentIds[l - 1] + '-' + id
+ : id;
+ parentIds[l] = id;
headerCallback?.(title, hashes.length, id);
return `${escapeHtml(title)}`;
});
diff --git a/docs/documentation.md b/docs/documentation.md
index 89c8f6a..3ec8482 100644
--- a/docs/documentation.md
+++ b/docs/documentation.md
@@ -11,6 +11,8 @@
[onCharEvent](#oncharevent)
[onExitUse](#onexituse)
[onCommand](#oncommand)
+ [onRequest](#onrequest)
+ [onResponse](#onresponse)
[API references](#api-references)
Mucklet scripts are written in AssemblyScript, a strictly typed
@@ -38,8 +40,10 @@ Script file | Description
[intercom_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/intercom_inside.ts) | An intercom script allowing communication with another room running the [intercom_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/intercom_outside.ts) script.
[intercom_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/intercom_outside.ts) | An intercom script allowing communication with another room running the [intercom_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/intercom_inside.ts) script.
[lock_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_inside.ts) | A script that locks a door preventing others from using an exit in the room running the [lock_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_outside.ts) script.
-[lock_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_outside.ts) | A script that prevents characters from using an exit locked by the script running the [lock_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_inside.ts) script.
+[lock_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_outside.ts) | A script that prevents characters from using an exit locked by the [lock_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_inside.ts) script.
[secret_exit.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/secret_exit.ts) | A script that reveals a secret passage when the password "tapeworm" is spoken.
+[vip_list.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/vip_list.ts) | A script that manages a list of VIP characters, requested by another room running the [vip_guard.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/vip_guard.ts) script.
+[vip_guard.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/vip_guard.ts) | A script that prevents characters from using an exit unless they are listed as VIP character by the [vip_list.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/vip_list.ts) script.
Entry points
@@ -62,6 +66,8 @@ commands ([Room.addCommand](#function-room-addcommand)), or scheduled posts ([Sc
with delay), will be removed, and [onActivate](#onactivate) will be called
again on the new script version.
+Examples
+
```ts
// Send a describe to the room and log a message to the console on activation.
export function onActivate(): void {
@@ -73,14 +79,22 @@ export function onActivate(): void {
onRoomEvent
_onRoomEvent_ is called when an event occurs in the room, such as a _say_,
-_arrive_, or _sleep_. It requires that [Room.listen](#function-room-listen) has been called
-earlier, usually in the [onActivate](#onactivate) function.
+_arrive_, or _sleep_. [Room.listen](#function-room-listen) must have been called earlier to
+start listening to room events, usually in the [onActivate](#onactivate)
+function.
+
+Parameters
+
+* `addr` _(string)_: Address of this script instance receiving the event.
+* `ev` _(string)_: Event encoded as a json string.
+
+Examples
```ts
// Check the event type and decode the event.
export function onRoomEvent(
- addr: string, // Address of this script instance receiving the event.
- ev: string, // Event encoded as a json string.
+ addr: string,
+ ev: string,
): void {
const eventType = Event.getType(ev);
if (eventType == 'say') {
@@ -93,16 +107,27 @@ export function onRoomEvent(
onMessage
_onMessage_ is called when another script sends a message to this script,
-using [Script.post](#function-script-post). It requires that [Script.listen](#function-script-listen) has been
-called earlier, usually in the [onActivate](#onactivate) function.
+using [Script.post](#function-script-post). [Script.listen](#function-script-listen) must have been called
+earlier to start listening to messages, usually in the
+[onActivate](#onactivate) function.
+
+Parameters
+
+* `addr` _(string)_: Address of this script instance receiving the message.
+* `topic` _(string)_: Topic of the message. Determined by the sender.
+* `data` _(string | null)_: JSON encoded data of the message or null.
+ Determined by the sender.
+* `sender` _(string)_: Address of the sending script instance.
+
+Examples
```ts
// Receive a message from another script to change room profile
export function onMessage(
- addr: string, // Address of this script instance receiving the message.
- topic: string, // Topic of the message. Determined by the sender.
- data: string | null, // JSON encoded data of the message or null. Determined by the sender.
- sender: string, // Address of the sending script instance.
+ addr: string,
+ topic: string,
+ data: string | null,
+ sender: string,
): void {
if (topic == "changeProfile") {
Room.setProfile(JSON.parse(data))
@@ -113,17 +138,28 @@ export function onMessage(
onCharEvent
_onCharEvent_ is called when a character enters a room, leaves a room, or
-changes any of its properties while inside the room. It requires that
-[Room.listenCharEvent](#function-room-listencharevent) has been called earlier, usually in the
-[onActivate](#onactivate) function.
+changes any of its properties while inside the room.
+[Room.listenCharEvent](#function-room-listencharevent) must have been called earlier to start listening
+to character events, usually in the [onActivate](#onactivate) function.
+
+Parameters
+
+* `addr` _(string)_: Address of this script instance receiving the event.
+* `charId` _(string)_: ID of character.
+* `after` _(string | null)_: Character state after the event encoded as a
+ json string, or null if the character left the room.
+* `before` _(string | null)_: Character state before the event encoded as a
+ json string, or null if the character entered the room.
+
+Examples
```ts
// Output to log when a character arrives or leaves
export function onCharEvent(
- addr: string, // Address of this script instance receiving the event.
- charId: string, // ID of character.
- after: string | null, // Character state after the event encoded as a json string, or null if the character left the room.
- before: string | null, // Character state before the event encoded as a json string, or null if the character entered the room.
+ addr: string,
+ charId: string,
+ after: string | null,
+ before: string | null,
): void {
if (after == null && before != null) {
// If after is null, the character left
@@ -140,18 +176,26 @@ export function onCharEvent(
onExitUse
-_onExitUse_ is called when a character tries to use an exit. It requires that
-[Room.listenExit](#function-room-listenexit) has been called earlier, usually in the
-[onActivate](#onactivate) function. The script should call either
-[ExitAction.cancel](#method-exitaction-cancel) or [ExitAction.useExit](#method-exitaction-useexit) to determine what
-should happen. If neither method is called, the action will timeout after 1
-second, automatically canceling the exit use with a default message.
+_onExitUse_ is called when a character tries to use an exit.
+[Room.listenExit](#function-room-listenexit) must have been called earlier to start listening to
+exit use, usually in the [onActivate](#onactivate) function. The script
+should call either [ExitAction.cancel](#method-exitaction-cancel) or [ExitAction.useExit](#method-exitaction-useexit) to
+determine what should happen. If neither method is called, the action will
+timeout after 1 second, automatically canceling the exit use with a default
+message.
+
+Parameters
+
+* `addr` _(string)_: Address of this script instance receiving the event.
+* `cmdAction` _([ExitAction](#class-exitaction))_: Exit action object.
+
+Examples
```ts
// Prevent anyone from using an exit
export function onExitUse(
- addr: string, // Address of this script instance receiving the event.
- exitAction: ExitAction, // Exit action object.
+ addr: string,
+ exitAction: ExitAction,
): void {
exitAction.cancel("The door seems to be locked.");
}
@@ -159,13 +203,20 @@ export function onExitUse(
onCommand
-_onCommand_ is called when a character uses a custom command. It requires
-that [Room.addCommand](#function-room-addcommand) has been called earlier to register the command,
-usually in the [onActivate](#onactivate) function. The script may send a
-response to the caller using either [CmdAction.info](#method-cmdaction-info),
+_onCommand_ is called when a character uses a custom command.
+[Room.addCommand](#function-room-addcommand) must have been called earlier to register the
+command, usually in the [onActivate](#onactivate) function. The script may
+send a response to the caller using either [CmdAction.info](#method-cmdaction-info),
[CmdAction.error](#method-cmdaction-error), or [CmdAction.useExit](#method-cmdaction-useexit), but it is not
required. The response must be sent within 1 second from the call.
+Parameters
+
+* `addr` _(string)_: Address of this script instance receiving the action.
+* `cmdAction` _([CmdAction](#class-cmdaction))_: Command action object.
+
+Examples
+
```ts
// Adding a ping command on activation
export function onActivate(): void {
@@ -181,6 +232,64 @@ export function onCommand(
}
```
+onRequest
+
+_onRequest_ is called when another script sends a request to this script,
+using [Script.request](#function-script-request). [Script.listen](#function-script-listen) must have been called
+earlier to start listening to requests, usually in the
+[onActivate](#onactivate) function.
+
+Parameters
+
+* `addr` _(string)_: Address of this script instance receiving the request.
+* `request` _([Request](#class-request))_: Request object.
+
+Examples
+
+```ts
+// Receive a request from another script and send a response.
+export function onRequest(
+ addr: string,
+ request: Request,
+): void {
+ if (request.topic == "getValue") {
+ // Parse any data passed as arguments.
+ const key = request.parseData()
+ const value = Store.getString(key)
+ // Send a response to the request
+ request.reply(value)
+ }
+}
+```
+
+onResponse
+
+_onResponse_ is called when another script sends a response to a request by
+calling [Request.reply](#method-request-reply).
+
+Parameters
+
+* `addr` _(string)_: Address of the script instance receiving the response.
+* `response` _([Response](#class-response))_: Response object.
+
+Examples
+
+```ts
+// Receive a response to an request
+export function onResponse(
+ addr: string,
+ response: Response,
+): void {
+ response obn
+ // Parse any data passed as arguments.
+ const key = request.ParseData()
+ const value = Store.getString(key);
+ // Send a response to the request
+ request.reply(value)
+ }
+}
+```
+
API references
[Type aliases](#type-aliases)
@@ -209,6 +318,13 @@ export function onCommand(
[class ExitAction](#class-exitaction)
[method useExit](#method-exitaction-useexit)
[method cancel](#method-exitaction-cancel)
+ [class Request](#class-request)
+ [method parseData](#method-request-parsedata)
+ [method reply](#method-request-reply)
+ [method error](#method-request-error)
+ [class Response](#class-response)
+ [method isError](#method-response-iserror)
+ [method parseResult](#method-response-parseresult)
[Namespaces](#namespaces)
[Event namespace](#namespace-event)
[Field namespace](#namespace-field)
@@ -393,6 +509,7 @@ export function onCommand(
[function Script.getChar](#function-script-getchar)
[function Script.listen](#function-script-listen)
[function Script.post](#function-script-post)
+ [function Script.request](#function-script-request)
[function Script.unlisten](#function-script-unlisten)
[Script classes](#script-classes)
[class Script.Char](#class-script-char)
@@ -617,7 +734,7 @@ Responds to the command action with an info message.
Parameters
-* `msg` (string): Info message.
+* `msg` (string): Info message. It may be formatted with info formatting and span multiple paragraphs.
---
@@ -632,7 +749,7 @@ Responds to the command action with an error message.
Parameters
-* `msg` (string): Error message.
+* `msg` (string): Error message. It may be formatted and span multiple paragraphs.
---
@@ -766,6 +883,108 @@ shown.
* `msg` (string | null): Info message to show, or default message if null.
+---
+
+class Request
+
+Request is a request sent from another script.
+
+class Request properties
+
+* `actionId` (i32): Action ID
+* `topic` (string): Request topic
+* `data` (string): Request data encoded as JSON.
+* `sender` (string): Request sender address.
+
+
+---
+
+method Request.parseData
+
+```ts
+parseData(): T
+```
+
+Parses the data into a value of type T.
+
+Returns
+
+* (T)
+
+
+---
+
+method Request.reply
+
+```ts
+reply(result: string | null = null): void
+```
+
+Responds to the request with a reply containing JSON encoded result.
+
+Parameters
+
+* `result` (string | null): Reply data encoded as JSON.
+
+
+---
+
+method Request.error
+
+```ts
+error(msg: string): void
+```
+
+Responds to the request with an error message.
+
+Parameters
+
+* `msg` (string): Error message.
+
+
+---
+
+class Response
+
+Response is a response to a request sent by the script.
+
+class Response properties
+
+* `result` (string | null): Result encoded as JSON.
+* `error` (string | null): Error string or null on no error.
+
+
+---
+
+method Response.isError
+
+```ts
+isError(): boolean
+```
+
+Returns true if it is an error response by checking that the error
+property is not a null value.
+
+Returns
+
+* (boolean)
+
+
+---
+
+method Response.parseResult
+
+```ts
+parseResult(): T
+```
+
+Parses the result into a value of type T.
+
+Returns
+
+* (T)
+
+
Namespaces
Event functions
@@ -2075,6 +2294,10 @@ new JSON.Obj()
```
+class JSON.Obj properties
+
+* `storage` (Map<string, [JSON.Value](#class-json-value)>)
+
---
@@ -3332,12 +3555,14 @@ To get character description or image info use Room.getChar instead.
Script.listen(addrs: Array | null = null): void
```
-Starts listening for posted messages from any of the given `addr`
-addresses. If an address is a non-instance room, it will also listen to
-posted messages from any instance of that room.
+Starts listening for posted messages and requests, sent with
+[Script.post](#function-script-post) and [Script.request](#function-script-request), from any of the given
+`addr` addresses. If an address is a non-instance room, it will also
+listen to posted messages from any instance of that room.
-If no `addr` is provided, the script will listen to posts from _any_
-source, including scripts and bots controlled by other players.
+If no `addr` is provided, the script will listen to posts and requests
+from _any_ source, including scripts and bots controlled by other
+players.
Posts from the current script does not require listening. A script can
always post to itself.
@@ -3361,7 +3586,9 @@ help roomscript
Script.post(addr: string, topic: string, data: string | null = null, delay: i64 = 0): ID | null
```
-Posts a message to another script with the address `addr`.
+Posts a message to another script with the address `addr`. The receiving
+script will get the message through the [onMessage](#onmessage) entry
+point.
To get the address of a room script, use the `roomscript` command. For
more info, type:
@@ -3381,6 +3608,36 @@ help roomscript
* ([ID](#type-id) | null): Schedule [ID](#type-id) or null if the message was posted without delay of if the receiving script was not listening.
+---
+
+function Script.request
+
+```ts
+Script.request(addr: string, topic: string, data: string | null = null): Response
+```
+
+Sends a request to another script with the address `addr`. The receiving
+script will get the request through the [onRequest](#onrequest) entry
+point. Once replied, the requesting script will get the response together
+with provided context through the [onResponse](#onresponse) entry point
+
+To get the address of a room script, use the `roomscript` command. For
+more info, type:
+```
+help roomscript
+```
+
+Parameters
+
+* `addr` (string): Address of target script. If addr is "#", it will be a post to the current script instance.
+* `topic` (string): Message topic. May be any kind of string.
+* `data` (string | null): Additional data to be sent with the request. Must be valid JSON.
+
+Returns
+
+* ([Response](#class-response)): Response to the request.
+
+
---
function Script.unlisten
diff --git a/examples/intercom_inside.ts b/examples/intercom_inside.ts
index cca5e9f..1a56a8d 100644
--- a/examples/intercom_inside.ts
+++ b/examples/intercom_inside.ts
@@ -57,7 +57,7 @@ export function onRoomEvent(addr: string, ev: string): void {
}
}
-// onCommand is called when a characters uses a script command.
+// onCommand is called when a character uses a script command.
export function onCommand(addr: string, cmdAction: CmdAction): void {
// Get the current active state of the intercom.
const active = isActive()
diff --git a/examples/vip_guard.ts b/examples/vip_guard.ts
new file mode 100644
index 0000000..c5140bc
--- /dev/null
+++ b/examples/vip_guard.ts
@@ -0,0 +1,47 @@
+/**
+ * The vip_guard.ts is a script that prevents characters from using an exit
+ * unless they are added to the VIP list that is kept by the vip_list.ts script.
+ *
+ * When a character tries to use the exit, a request is sent to vip_list.ts to
+ * check whether or not they are VIP characters. The vip_guard.ts script and
+ * vip_list.ts may (and should) be running in different rooms.
+ */
+
+// Post address to the vipList script. Replace this.
+// To get a room script's address, type: roomscript
+const vipListAddr = "room.aaaaaaaaaaaaaaaaaaaa#bbbbbbbbbbbbbbbbbbbb"
+
+// ID of the exit to guard. Replace this.
+// To get a room script's address, type: get exit
+// The leading # should not be included.
+const exitId = "aaaaaaaaaaaaaaaaaaaa"
+
+export function onActivate(): void {
+ // Always listen and intercept any use of the exit.
+ Room.listenExit(exitId)
+}
+
+// onExitUse is called when someone tries to use the exit.
+export function onExitUse(addr: string, exitAction: ExitAction): void {
+ // Send a request to the vip_list.ts script. It waits until we receive a response.
+ const response = Script.request(vipListAddr, "isVip", JSON.stringify(exitAction.charId))
+
+ // Assert we didn't get an error response.
+ if (response.isError()) {
+ // We look the error for debugging purpose
+ console.debug("Request error: " + response.error!)
+ // We cancel the exit use attempt with a message.
+ exitAction.cancel("The guard can't seem to find the VIP list.")
+ return
+ }
+
+ // Parse the response. The vip_list.ts should have sent a boolean value.
+ const isVip = response.parseResult()
+ if (isVip) {
+ // We let the character use the exit.
+ exitAction.useExit()
+ } else {
+ // We cancel the exit use attempt with a message.
+ exitAction.cancel("The guard blocks your way as they cannot find you in the VIP list.")
+ }
+}
diff --git a/examples/vip_list.ts b/examples/vip_list.ts
new file mode 100644
index 0000000..34471be
--- /dev/null
+++ b/examples/vip_list.ts
@@ -0,0 +1,130 @@
+/**
+ * The vip_list.ts is a script that keeps a list of VIP characters, with
+ * commands to add, remove, and list them. Other scripts, such as vip_guard.ts,
+ * may send requests to ask whether a character is a VIP, using
+ * `Script.request`:
+ * ```
+ * const response = Script.request(vipListAddr, "isVip", JSON.stringify(charId))
+ * ```
+ *
+ * The vip_guard.ts script sends requests to this scripts to only let VIP
+ * characters use an exit.
+ *
+ * The script adds three commands to the room:
+ * ```
+ * add vip
+ * remove vip
+ * list vip
+ * ```
+ */
+
+// onActivate is called when the script is activated.
+export function onActivate(): void {
+ // Add commands for managing the VIP list
+ Room.addCommand(
+ "add",
+ new Command("add vip ", "Add a character to the VIP list.")
+ .field("Character", new Field.Char("Character to add.")),
+ )
+ Room.addCommand(
+ "remove",
+ new Command("remove vip ", "Remove a character from the VIP list.")
+ .field("Character", new Field.Char("Character to remove.")),
+ )
+ Room.addCommand(
+ "list",
+ new Command("list vip", "List all VIP characters."),
+ )
+ // Listen for script requests.
+ Script.listen()
+}
+
+// Command arguments class. Used by both the "add" and "remove" command.
+@json
+class Args {
+ @alias("Character")
+ char: FieldValue.Char = new FieldValue.Char();
+}
+
+// onCommand is called when a character uses a script command.
+export function onCommand(addr: string, cmdAction: CmdAction): void {
+ // Handle add command
+ if (cmdAction.keyword == "add") {
+ const args = JSON.parse(cmdAction.data)
+ // Check if the character is already added.
+ if (Store.getString(args.char.id) == null) {
+ // Add the character to the store. As value, we store the timestamp
+ // when the character was added. This value currently not used in
+ // this script.
+ Store.setString(args.char.id, Date.now().toString())
+ cmdAction.info(`**${args.char.name} ${args.char.surname}** was added to the VIP list.`)
+ } else {
+ cmdAction.info(`**${args.char.name} ${args.char.surname}** was already in the VIP list.`)
+ }
+ return
+ }
+
+ // Handle remove command
+ if (cmdAction.keyword == "remove") {
+ const args = JSON.parse(cmdAction.data)
+ // Check if the character is not already removed.
+ if (Store.getString(args.char.id) != null) {
+ // Remove the character from the store.
+ Store.deleteKey(args.char.id)
+ cmdAction.info(`**${args.char.name} ${args.char.surname}** was removed from the VIP list.`)
+ } else {
+ cmdAction.info(`**${args.char.name} ${args.char.surname}** was not found in the VIP list.`)
+ }
+ return
+ }
+
+ // Handle list command
+ if (cmdAction.keyword == "list") {
+ let chars = new Array()
+ // Iterate over all characters stored in the list
+ for (const iter = new Store.Iterator(); iter.isValid(); iter.next()) {
+ // Get the store key which is the character ID.
+ const charId = iter.getKeyString()
+ // Get character info.
+ const char = Script.getChar(charId)
+ // Verify that the character is found.
+ if (char != null) {
+ chars.push(char)
+ } else {
+ // The character is probably deleted.
+ // We prune our VIP list by deleting them there as well.
+ console.debug("Pruned " + charId)
+ Store.deleteKey(charId)
+ }
+ }
+
+ // Check if the list is empty. If so, show a simple message.
+ if (chars.length == 0) {
+ cmdAction.info("_List is empty_")
+ return
+ }
+
+ // Sort the characters by name and surname.
+ chars.sort((a: Script.Char, b: Script.Char) => a.name.localeCompare(b.name) || a.surname.localeCompare(b.surname))
+ // Concatenate the names into a string with line breaks between each character.
+ const list = chars
+ .map((char: Script.Char, i: i32, chars: Script.Char[]) => char.name + " " + char.surname)
+ .join("\n")
+ // Show the list with a header "VIP list". For help on how to format
+ // text, see: `help format info`
+ cmdAction.info("## VIP list\n" + list)
+ return
+ }
+}
+
+// onRequest is called when another script sends a request to this script.
+export function onRequest(addr: string, request: Request): void {
+ if (request.topic == "isVip") {
+ // Parse the data passed as arguments. It should be the charId.
+ const charId = request.parseData()
+ // If the charId exists in the store, the character is a VIP.
+ const isVip = Store.getString(charId) != null
+ // Send a response to the request. It must be JSON encoded.
+ request.reply(JSON.stringify(isVip))
+ }
+}
diff --git a/lib/env.ts b/lib/env.ts
index 98da82a..f44bda5 100644
--- a/lib/env.ts
+++ b/lib/env.ts
@@ -1,3 +1,4 @@
+
// @ts-nocheck
export declare namespace Room {
@@ -77,6 +78,9 @@ export declare namespace Script {
@external("env", "script.getChar")
export function getChar(charId: string): string | null
+
+ @external("env", "script.request")
+ export function request(addr: string, topic: string, data: string | null): T
}
export declare namespace Store {
@@ -134,3 +138,11 @@ export declare namespace CmdAction {
@external("env", "cmdAction.useExit")
export function useExit(actionId: i32, exitId: string): void
}
+
+export declare namespace RequestAction {
+ @external("env", "requestAction.reply")
+ export function reply(actionId: i32, result: string | null): void
+
+ @external("env", "requestAction.error")
+ export function error(actionId: i32, msg: string): void
+}
diff --git a/lib/host.ts b/lib/host.ts
index be35d6b..cea687c 100644
--- a/lib/host.ts
+++ b/lib/host.ts
@@ -24,8 +24,10 @@
* [intercom_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/intercom_inside.ts) | An intercom script allowing communication with another room running the [intercom_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/intercom_outside.ts) script.
* [intercom_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/intercom_outside.ts) | An intercom script allowing communication with another room running the [intercom_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/intercom_inside.ts) script.
* [lock_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_inside.ts) | A script that locks a door preventing others from using an exit in the room running the [lock_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_outside.ts) script.
- * [lock_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_outside.ts) | A script that prevents characters from using an exit locked by the script running the [lock_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_inside.ts) script.
+ * [lock_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_outside.ts) | A script that prevents characters from using an exit locked by the [lock_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_inside.ts) script.
* [secret_exit.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/secret_exit.ts) | A script that reveals a secret passage when the password "tapeworm" is spoken.
+ * [vip_list.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/vip_list.ts) | A script that manages a list of VIP characters, requested by another room running the [vip_guard.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/vip_guard.ts) script.
+ * [vip_guard.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/vip_guard.ts) | A script that prevents characters from using an exit unless they are listed as VIP character by the [vip_list.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/vip_list.ts) script.
*
* # Entry points
*
@@ -48,6 +50,8 @@
* with delay), will be removed, and [onActivate](#onactivate) will be called
* again on the new script version.
*
+ * ### Examples
+ *
* ```ts
* // Send a describe to the room and log a message to the console on activation.
* export function onActivate(): void {
@@ -59,14 +63,22 @@
* ## onRoomEvent
*
* _onRoomEvent_ is called when an event occurs in the room, such as a _say_,
- * _arrive_, or _sleep_. It requires that {@link Room.listen} has been called
- * earlier, usually in the [onActivate](#onactivate) function.
+ * _arrive_, or _sleep_. {@link Room.listen} must have been called earlier to
+ * start listening to room events, usually in the [onActivate](#onactivate)
+ * function.
+ *
+ * ### Parameters
+ *
+ * * `addr` _(string)_: Address of this script instance receiving the event.
+ * * `ev` _(string)_: Event encoded as a json string.
+ *
+ * ### Examples
*
* ```ts
* // Check the event type and decode the event.
* export function onRoomEvent(
- * addr: string, // Address of this script instance receiving the event.
- * ev: string, // Event encoded as a json string.
+ * addr: string,
+ * ev: string,
* ): void {
* const eventType = Event.getType(ev);
* if (eventType == 'say') {
@@ -79,16 +91,27 @@
* ## onMessage
*
* _onMessage_ is called when another script sends a message to this script,
- * using {@link Script.post}. It requires that {@link Script.listen} has been
- * called earlier, usually in the [onActivate](#onactivate) function.
+ * using {@link Script.post}. {@link Script.listen} must have been called
+ * earlier to start listening to messages, usually in the
+ * [onActivate](#onactivate) function.
+ *
+ * ### Parameters
+ *
+ * * `addr` _(string)_: Address of this script instance receiving the message.
+ * * `topic` _(string)_: Topic of the message. Determined by the sender.
+ * * `data` _(string | null)_: JSON encoded data of the message or null.
+ * Determined by the sender.
+ * * `sender` _(string)_: Address of the sending script instance.
+ *
+ * ### Examples
*
* ```ts
* // Receive a message from another script to change room profile
* export function onMessage(
- * addr: string, // Address of this script instance receiving the message.
- * topic: string, // Topic of the message. Determined by the sender.
- * data: string | null, // JSON encoded data of the message or null. Determined by the sender.
- * sender: string, // Address of the sending script instance.
+ * addr: string,
+ * topic: string,
+ * data: string | null,
+ * sender: string,
* ): void {
* if (topic == "changeProfile") {
* Room.setProfile(JSON.parse(data))
@@ -99,17 +122,28 @@
* ## onCharEvent
*
* _onCharEvent_ is called when a character enters a room, leaves a room, or
- * changes any of its properties while inside the room. It requires that
- * {@link Room.listenCharEvent} has been called earlier, usually in the
- * [onActivate](#onactivate) function.
+ * changes any of its properties while inside the room.
+ * {@link Room.listenCharEvent} must have been called earlier to start listening
+ * to character events, usually in the [onActivate](#onactivate) function.
+ *
+ * ### Parameters
+ *
+ * * `addr` _(string)_: Address of this script instance receiving the event.
+ * * `charId` _(string)_: ID of character.
+ * * `after` _(string | null)_: Character state after the event encoded as a
+ * json string, or null if the character left the room.
+ * * `before` _(string | null)_: Character state before the event encoded as a
+ * json string, or null if the character entered the room.
+ *
+ * ### Examples
*
* ```ts
* // Output to log when a character arrives or leaves
* export function onCharEvent(
- * addr: string, // Address of this script instance receiving the event.
- * charId: string, // ID of character.
- * after: string | null, // Character state after the event encoded as a json string, or null if the character left the room.
- * before: string | null, // Character state before the event encoded as a json string, or null if the character entered the room.
+ * addr: string,
+ * charId: string,
+ * after: string | null,
+ * before: string | null,
* ): void {
* if (after == null && before != null) {
* // If after is null, the character left
@@ -126,18 +160,26 @@
*
* ## onExitUse
*
- * _onExitUse_ is called when a character tries to use an exit. It requires that
- * {@link Room.listenExit} has been called earlier, usually in the
- * [onActivate](#onactivate) function. The script should call either
- * {@link ExitAction.cancel} or {@link ExitAction.useExit} to determine what
- * should happen. If neither method is called, the action will timeout after 1
- * second, automatically canceling the exit use with a default message.
+ * _onExitUse_ is called when a character tries to use an exit.
+ * {@link Room.listenExit} must have been called earlier to start listening to
+ * exit use, usually in the [onActivate](#onactivate) function. The script
+ * should call either {@link ExitAction.cancel} or {@link ExitAction.useExit} to
+ * determine what should happen. If neither method is called, the action will
+ * timeout after 1 second, automatically canceling the exit use with a default
+ * message.
+ *
+ * ### Parameters
+ *
+ * * `addr` _(string)_: Address of this script instance receiving the event.
+ * * `cmdAction` _({@link ExitAction})_: Exit action object.
+ *
+ * ### Examples
*
* ```ts
* // Prevent anyone from using an exit
* export function onExitUse(
- * addr: string, // Address of this script instance receiving the event.
- * exitAction: ExitAction, // Exit action object.
+ * addr: string,
+ * exitAction: ExitAction,
* ): void {
* exitAction.cancel("The door seems to be locked.");
* }
@@ -145,13 +187,20 @@
*
* ## onCommand
*
- * _onCommand_ is called when a character uses a custom command. It requires
- * that {@link Room.addCommand} has been called earlier to register the command,
- * usually in the [onActivate](#onactivate) function. The script may send a
- * response to the caller using either {@link CmdAction.info},
+ * _onCommand_ is called when a character uses a custom command.
+ * {@link Room.addCommand} must have been called earlier to register the
+ * command, usually in the [onActivate](#onactivate) function. The script may
+ * send a response to the caller using either {@link CmdAction.info},
* {@link CmdAction.error}, or {@link CmdAction.useExit}, but it is not
* required. The response must be sent within 1 second from the call.
*
+ * ### Parameters
+ *
+ * * `addr` _(string)_: Address of this script instance receiving the action.
+ * * `cmdAction` _({@link CmdAction})_: Command action object.
+ *
+ * ### Examples
+ *
* ```ts
* // Adding a ping command on activation
* export function onActivate(): void {
@@ -167,6 +216,64 @@
* }
* ```
*
+ * ## onRequest
+ *
+ * _onRequest_ is called when another script sends a request to this script,
+ * using {@link Script.request}. {@link Script.listen} must have been called
+ * earlier to start listening to requests, usually in the
+ * [onActivate](#onactivate) function.
+ *
+ * ### Parameters
+ *
+ * * `addr` _(string)_: Address of this script instance receiving the request.
+ * * `request` _({@link Request})_: Request object.
+ *
+ * ### Examples
+ *
+ * ```ts
+ * // Receive a request from another script and send a response.
+ * export function onRequest(
+ * addr: string,
+ * request: Request,
+ * ): void {
+ * if (request.topic == "getValue") {
+ * // Parse any data passed as arguments.
+ * const key = request.parseData()
+ * const value = Store.getString(key)
+ * // Send a response to the request
+ * request.reply(value)
+ * }
+ * }
+ * ```
+ *
+ * ## onResponse
+ *
+ * _onResponse_ is called when another script sends a response to a request by
+ * calling {@link Request.reply}.
+ *
+ * ### Parameters
+ *
+ * * `addr` _(string)_: Address of the script instance receiving the response.
+ * * `response` _({@link Response})_: Response object.
+ *
+ * ### Examples
+ *
+ * ```ts
+ * // Receive a response to an request
+ * export function onResponse(
+ * addr: string,
+ * response: Response,
+ * ): void {
+ * response obn
+ * // Parse any data passed as arguments.
+ * const key = request.ParseData()
+ * const value = Store.getString(key);
+ * // Send a response to the request
+ * request.reply(value)
+ * }
+ * }
+ * ```
+ *
* @packageDocumentation
*/
@@ -178,6 +285,7 @@ import {
Iterator as iterator_binding,
ExitAction as exitaction_binding,
CmdAction as cmdaction_binding,
+ RequestAction as requestaction_binding,
} from "./env";
import { JSON } from 'json-as'
export { JSON };
@@ -248,12 +356,55 @@ function keyToBuffer(key: T): ArrayBuffer {
return key;
}
+/**
+ * CmdAction is a command action triggered by a character.
+ */
+@json
+export class CmdAction {
+ /** Action ID */
+ actionId: i32 = 0;
+ /** Character performing the action */
+ char: Event.Char = new Event.Char();
+ /** Command keyword */
+ keyword: string = "";
+ /** Command data in JSON format. */
+ data: string = "";
+
+ /**
+ * Responds to the command action with an info message.
+ * @param msg Info message. It may be formatted with info formatting and span multiple paragraphs.
+ */
+ info(msg: string): void {
+ cmdaction_binding.info(this.actionId, msg);
+ }
+
+ /**
+ * Responds to the command action with an error message.
+ * @param msg Error message. It may be formatted and span multiple paragraphs.
+ */
+ error(msg: string): void {
+ cmdaction_binding.error(this.actionId, msg);
+ }
+
+ /**
+ * Responds to the command action by making the character use an exit.
+ *
+ * The exit may be hidden or inactive. May not be used in combination with
+ * info or error.
+ * @param exitId Exit ID.
+ */
+ useExit(exitId: ID): void {
+ cmdaction_binding.useExit(this.actionId, exitId);
+ }
+}
+
/**
* ExitAction is an action representing an intercepted use of an exit.
*
* It is passed to [onExitUse](#onexituse) entry point when a character tries to
* use an exit that is being listen to with {@link Room.listenExit}.
*/
+@json
export class ExitAction {
/** Action ID */
actionId: i32 = 0;
@@ -285,43 +436,68 @@ export class ExitAction {
}
/**
- * CmdAction is a command action triggered by a character.
+ * Request is a request sent from another script.
*/
-export class CmdAction {
+@json
+export class Request {
/** Action ID */
actionId: i32 = 0;
- /** Character performing the action */
- char: Event.Char = new Event.Char();
- /** Command keyword */
- keyword: string = "";
- /** Command data in JSON format. */
+ /** Request topic */
+ topic: string = "";
+ /** Request data encoded as JSON. */
data: string = "";
+ /** Request sender address. */
+ sender: string = "";
/**
- * Responds to the command action with an info message.
- * @param msg Info message.
+ * Parses the data into a value of type T.
*/
- info(msg: string): void {
- cmdaction_binding.info(this.actionId, msg);
+ parseData(): T {
+ return JSON.parse(this.data);
}
/**
- * Responds to the command action with an error message.
+ * Responds to the request with a reply containing JSON encoded result.
+ * @param result Reply data encoded as JSON.
+ */
+ reply(result: string | null = null): void {
+ requestaction_binding.reply(this.actionId, result);
+ }
+
+ /**
+ * Responds to the request with an error message.
* @param msg Error message.
*/
error(msg: string): void {
- cmdaction_binding.error(this.actionId, msg);
+ requestaction_binding.error(this.actionId, msg);
+ }
+}
+
+/**
+ * Response is a response to a request sent by the script.
+ */
+export class Response {
+ /** Result encoded as JSON. */
+ result: string | null = null;
+ /** Error string or null on no error. */
+ error: string | null = null;
+
+ /**
+ * Returns true if it is an error response by checking that the error
+ * property is not a null value.
+ */
+ isError(): boolean {
+ return this.error != null;
}
/**
- * Responds to the command action by making the character use an exit.
- *
- * The exit may be hidden or inactive. May not be used in combination with
- * info or error.
- * @param exitId Exit ID.
+ * Parses the result into a value of type T.
*/
- useExit(exitId: ID): void {
- cmdaction_binding.useExit(this.actionId, exitId);
+ parseResult(): T {
+ if (this.result == null) {
+ abort("no result to parse")
+ }
+ return JSON.parse(this.result!);
}
}
@@ -1367,12 +1543,14 @@ export namespace Script {
}
/**
- * Starts listening for posted messages from any of the given `addr`
- * addresses. If an address is a non-instance room, it will also listen to
- * posted messages from any instance of that room.
+ * Starts listening for posted messages and requests, sent with
+ * {@link Script.post} and {@link Script.request}, from any of the given
+ * `addr` addresses. If an address is a non-instance room, it will also
+ * listen to posted messages from any instance of that room.
*
- * If no `addr` is provided, the script will listen to posts from _any_
- * source, including scripts and bots controlled by other players.
+ * If no `addr` is provided, the script will listen to posts and requests
+ * from _any_ source, including scripts and bots controlled by other
+ * players.
*
* Posts from the current script does not require listening. A script can
* always post to itself.
@@ -1406,7 +1584,9 @@ export namespace Script {
}
/**
- * Posts a message to another script with the address `addr`.
+ * Posts a message to another script with the address `addr`. The receiving
+ * script will get the message through the [onMessage](#onmessage) entry
+ * point.
*
* To get the address of a room script, use the `roomscript` command. For
* more info, type:
@@ -1440,6 +1620,27 @@ export namespace Script {
return script_binding.cancelPost(scheduleId);
}
+ /**
+ * Sends a request to another script with the address `addr`. The receiving
+ * script will get the request through the [onRequest](#onrequest) entry
+ * point. Once replied, the requesting script will get the response together
+ * with provided context through the [onResponse](#onresponse) entry point
+ *
+ * To get the address of a room script, use the `roomscript` command. For
+ * more info, type:
+ * ```
+ * help roomscript
+ * ```
+ *
+ * @param addr - Address of target script. If addr is "#", it will be a post to the current script instance.
+ * @param topic - Message topic. May be any kind of string.
+ * @param data - Additional data to be sent with the request. Must be valid JSON.
+ * @returns Response to the request.
+ */
+ export function request(addr: string, topic: string, data: string | null = null): Response {
+ return script_binding.request(addr, topic, data);
+ }
+
/**
* Gets info on an existing character.
*
diff --git a/lib/types/host/index.d.ts b/lib/types/host/index.d.ts
index 21fca03..dae90d3 100644
--- a/lib/types/host/index.d.ts
+++ b/lib/types/host/index.d.ts
@@ -24,8 +24,10 @@
* [intercom_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/intercom_inside.ts) | An intercom script allowing communication with another room running the [intercom_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/intercom_outside.ts) script.
* [intercom_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/intercom_outside.ts) | An intercom script allowing communication with another room running the [intercom_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/intercom_inside.ts) script.
* [lock_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_inside.ts) | A script that locks a door preventing others from using an exit in the room running the [lock_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_outside.ts) script.
- * [lock_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_outside.ts) | A script that prevents characters from using an exit locked by the script running the [lock_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_inside.ts) script.
+ * [lock_outside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_outside.ts) | A script that prevents characters from using an exit locked by the [lock_inside.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/lock_inside.ts) script.
* [secret_exit.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/secret_exit.ts) | A script that reveals a secret passage when the password "tapeworm" is spoken.
+ * [vip_list.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/vip_list.ts) | A script that manages a list of VIP characters, requested by another room running the [vip_guard.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/vip_guard.ts) script.
+ * [vip_guard.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/vip_guard.ts) | A script that prevents characters from using an exit unless they are listed as VIP character by the [vip_list.ts](https://github.com/mucklet/mucklet-script/blob/master/examples/vip_list.ts) script.
*
* # Entry points
*
@@ -48,6 +50,8 @@
* with delay), will be removed, and [onActivate](#onactivate) will be called
* again on the new script version.
*
+ * ### Examples
+ *
* ```ts
* // Send a describe to the room and log a message to the console on activation.
* export function onActivate(): void {
@@ -59,14 +63,22 @@
* ## onRoomEvent
*
* _onRoomEvent_ is called when an event occurs in the room, such as a _say_,
- * _arrive_, or _sleep_. It requires that {@link Room.listen} has been called
- * earlier, usually in the [onActivate](#onactivate) function.
+ * _arrive_, or _sleep_. {@link Room.listen} must have been called earlier to
+ * start listening to room events, usually in the [onActivate](#onactivate)
+ * function.
+ *
+ * ### Parameters
+ *
+ * * `addr` _(string)_: Address of this script instance receiving the event.
+ * * `ev` _(string)_: Event encoded as a json string.
+ *
+ * ### Examples
*
* ```ts
* // Check the event type and decode the event.
* export function onRoomEvent(
- * addr: string, // Address of this script instance receiving the event.
- * ev: string, // Event encoded as a json string.
+ * addr: string,
+ * ev: string,
* ): void {
* const eventType = Event.getType(ev);
* if (eventType == 'say') {
@@ -79,16 +91,27 @@
* ## onMessage
*
* _onMessage_ is called when another script sends a message to this script,
- * using {@link Script.post}. It requires that {@link Script.listen} has been
- * called earlier, usually in the [onActivate](#onactivate) function.
+ * using {@link Script.post}. {@link Script.listen} must have been called
+ * earlier to start listening to messages, usually in the
+ * [onActivate](#onactivate) function.
+ *
+ * ### Parameters
+ *
+ * * `addr` _(string)_: Address of this script instance receiving the message.
+ * * `topic` _(string)_: Topic of the message. Determined by the sender.
+ * * `data` _(string | null)_: JSON encoded data of the message or null.
+ * Determined by the sender.
+ * * `sender` _(string)_: Address of the sending script instance.
+ *
+ * ### Examples
*
* ```ts
* // Receive a message from another script to change room profile
* export function onMessage(
- * addr: string, // Address of this script instance receiving the message.
- * topic: string, // Topic of the message. Determined by the sender.
- * data: string | null, // JSON encoded data of the message or null. Determined by the sender.
- * sender: string, // Address of the sending script instance.
+ * addr: string,
+ * topic: string,
+ * data: string | null,
+ * sender: string,
* ): void {
* if (topic == "changeProfile") {
* Room.setProfile(JSON.parse(data))
@@ -99,17 +122,28 @@
* ## onCharEvent
*
* _onCharEvent_ is called when a character enters a room, leaves a room, or
- * changes any of its properties while inside the room. It requires that
- * {@link Room.listenCharEvent} has been called earlier, usually in the
- * [onActivate](#onactivate) function.
+ * changes any of its properties while inside the room.
+ * {@link Room.listenCharEvent} must have been called earlier to start listening
+ * to character events, usually in the [onActivate](#onactivate) function.
+ *
+ * ### Parameters
+ *
+ * * `addr` _(string)_: Address of this script instance receiving the event.
+ * * `charId` _(string)_: ID of character.
+ * * `after` _(string | null)_: Character state after the event encoded as a
+ * json string, or null if the character left the room.
+ * * `before` _(string | null)_: Character state before the event encoded as a
+ * json string, or null if the character entered the room.
+ *
+ * ### Examples
*
* ```ts
* // Output to log when a character arrives or leaves
* export function onCharEvent(
- * addr: string, // Address of this script instance receiving the event.
- * charId: string, // ID of character.
- * after: string | null, // Character state after the event encoded as a json string, or null if the character left the room.
- * before: string | null, // Character state before the event encoded as a json string, or null if the character entered the room.
+ * addr: string,
+ * charId: string,
+ * after: string | null,
+ * before: string | null,
* ): void {
* if (after == null && before != null) {
* // If after is null, the character left
@@ -126,18 +160,26 @@
*
* ## onExitUse
*
- * _onExitUse_ is called when a character tries to use an exit. It requires that
- * {@link Room.listenExit} has been called earlier, usually in the
- * [onActivate](#onactivate) function. The script should call either
- * {@link ExitAction.cancel} or {@link ExitAction.useExit} to determine what
- * should happen. If neither method is called, the action will timeout after 1
- * second, automatically canceling the exit use with a default message.
+ * _onExitUse_ is called when a character tries to use an exit.
+ * {@link Room.listenExit} must have been called earlier to start listening to
+ * exit use, usually in the [onActivate](#onactivate) function. The script
+ * should call either {@link ExitAction.cancel} or {@link ExitAction.useExit} to
+ * determine what should happen. If neither method is called, the action will
+ * timeout after 1 second, automatically canceling the exit use with a default
+ * message.
+ *
+ * ### Parameters
+ *
+ * * `addr` _(string)_: Address of this script instance receiving the event.
+ * * `cmdAction` _({@link ExitAction})_: Exit action object.
+ *
+ * ### Examples
*
* ```ts
* // Prevent anyone from using an exit
* export function onExitUse(
- * addr: string, // Address of this script instance receiving the event.
- * exitAction: ExitAction, // Exit action object.
+ * addr: string,
+ * exitAction: ExitAction,
* ): void {
* exitAction.cancel("The door seems to be locked.");
* }
@@ -145,13 +187,20 @@
*
* ## onCommand
*
- * _onCommand_ is called when a character uses a custom command. It requires
- * that {@link Room.addCommand} has been called earlier to register the command,
- * usually in the [onActivate](#onactivate) function. The script may send a
- * response to the caller using either {@link CmdAction.info},
+ * _onCommand_ is called when a character uses a custom command.
+ * {@link Room.addCommand} must have been called earlier to register the
+ * command, usually in the [onActivate](#onactivate) function. The script may
+ * send a response to the caller using either {@link CmdAction.info},
* {@link CmdAction.error}, or {@link CmdAction.useExit}, but it is not
* required. The response must be sent within 1 second from the call.
*
+ * ### Parameters
+ *
+ * * `addr` _(string)_: Address of this script instance receiving the action.
+ * * `cmdAction` _({@link CmdAction})_: Command action object.
+ *
+ * ### Examples
+ *
* ```ts
* // Adding a ping command on activation
* export function onActivate(): void {
@@ -167,6 +216,64 @@
* }
* ```
*
+ * ## onRequest
+ *
+ * _onRequest_ is called when another script sends a request to this script,
+ * using {@link Script.request}. {@link Script.listen} must have been called
+ * earlier to start listening to requests, usually in the
+ * [onActivate](#onactivate) function.
+ *
+ * ### Parameters
+ *
+ * * `addr` _(string)_: Address of this script instance receiving the request.
+ * * `request` _({@link Request})_: Request object.
+ *
+ * ### Examples
+ *
+ * ```ts
+ * // Receive a request from another script and send a response.
+ * export function onRequest(
+ * addr: string,
+ * request: Request,
+ * ): void {
+ * if (request.topic == "getValue") {
+ * // Parse any data passed as arguments.
+ * const key = request.parseData()
+ * const value = Store.getString(key)
+ * // Send a response to the request
+ * request.reply(value)
+ * }
+ * }
+ * ```
+ *
+ * ## onResponse
+ *
+ * _onResponse_ is called when another script sends a response to a request by
+ * calling {@link Request.reply}.
+ *
+ * ### Parameters
+ *
+ * * `addr` _(string)_: Address of the script instance receiving the response.
+ * * `response` _({@link Response})_: Response object.
+ *
+ * ### Examples
+ *
+ * ```ts
+ * // Receive a response to an request
+ * export function onResponse(
+ * addr: string,
+ * response: Response,
+ * ): void {
+ * response obn
+ * // Parse any data passed as arguments.
+ * const key = request.ParseData()
+ * const value = Store.getString(key);
+ * // Send a response to the request
+ * request.reply(value)
+ * }
+ * }
+ * ```
+ *
* @packageDocumentation
*/
/** ID for in game entities such as characters, rooms, and areas. */
@@ -222,6 +329,37 @@ declare const enum ExitIcon {
In = 11,
Out = 12
}
+/**
+ * CmdAction is a command action triggered by a character.
+ */
+declare class CmdAction {
+ /** Action ID */
+ actionId: i32;
+ /** Character performing the action */
+ char: Event.Char;
+ /** Command keyword */
+ keyword: string;
+ /** Command data in JSON format. */
+ data: string;
+ /**
+ * Responds to the command action with an info message.
+ * @param msg Info message. It may be formatted with info formatting and span multiple paragraphs.
+ */
+ info(msg: string): void;
+ /**
+ * Responds to the command action with an error message.
+ * @param msg Error message. It may be formatted and span multiple paragraphs.
+ */
+ error(msg: string): void;
+ /**
+ * Responds to the command action by making the character use an exit.
+ *
+ * The exit may be hidden or inactive. May not be used in combination with
+ * info or error.
+ * @param exitId Exit ID.
+ */
+ useExit(exitId: ID): void;
+}
/**
* ExitAction is an action representing an intercepted use of an exit.
*
@@ -252,35 +390,49 @@ declare class ExitAction {
cancel(msg?: string | null): void;
}
/**
- * CmdAction is a command action triggered by a character.
+ * Request is a request sent from another script.
*/
-declare class CmdAction {
+declare class Request {
/** Action ID */
actionId: i32;
- /** Character performing the action */
- char: Event.Char;
- /** Command keyword */
- keyword: string;
- /** Command data in JSON format. */
+ /** Request topic */
+ topic: string;
+ /** Request data encoded as JSON. */
data: string;
+ /** Request sender address. */
+ sender: string;
/**
- * Responds to the command action with an info message.
- * @param msg Info message.
+ * Parses the data into a value of type T.
*/
- info(msg: string): void;
+ parseData(): T;
/**
- * Responds to the command action with an error message.
+ * Responds to the request with a reply containing JSON encoded result.
+ * @param result Reply data encoded as JSON.
+ */
+ reply(result?: string | null): void;
+ /**
+ * Responds to the request with an error message.
* @param msg Error message.
*/
error(msg: string): void;
+}
+/**
+ * Response is a response to a request sent by the script.
+ */
+declare class Response {
+ /** Result encoded as JSON. */
+ result: string | null;
+ /** Error string or null on no error. */
+ error: string | null;
/**
- * Responds to the command action by making the character use an exit.
- *
- * The exit may be hidden or inactive. May not be used in combination with
- * info or error.
- * @param exitId Exit ID.
+ * Returns true if it is an error response by checking that the error
+ * property is not a null value.
*/
- useExit(exitId: ID): void;
+ isError(): boolean;
+ /**
+ * Parses the result into a value of type T.
+ */
+ parseResult(): T;
}
/**
* BaseIterator is an iterator over items with an ID.
@@ -950,12 +1102,14 @@ declare namespace Script {
rp: RPState;
}
/**
- * Starts listening for posted messages from any of the given `addr`
- * addresses. If an address is a non-instance room, it will also listen to
- * posted messages from any instance of that room.
+ * Starts listening for posted messages and requests, sent with
+ * {@link Script.post} and {@link Script.request}, from any of the given
+ * `addr` addresses. If an address is a non-instance room, it will also
+ * listen to posted messages from any instance of that room.
*
- * If no `addr` is provided, the script will listen to posts from _any_
- * source, including scripts and bots controlled by other players.
+ * If no `addr` is provided, the script will listen to posts and requests
+ * from _any_ source, including scripts and bots controlled by other
+ * players.
*
* Posts from the current script does not require listening. A script can
* always post to itself.
@@ -983,7 +1137,9 @@ declare namespace Script {
*/
function unlisten(addrs?: string[] | null): void;
/**
- * Posts a message to another script with the address `addr`.
+ * Posts a message to another script with the address `addr`. The receiving
+ * script will get the message through the [onMessage](#onmessage) entry
+ * point.
*
* To get the address of a room script, use the `roomscript` command. For
* more info, type:
@@ -1008,6 +1164,24 @@ declare namespace Script {
* @returns True if the post was successfully canceled, otherwise false.
*/
function cancelPost(scheduleId: ID | null): boolean;
+ /**
+ * Sends a request to another script with the address `addr`. The receiving
+ * script will get the request through the [onRequest](#onrequest) entry
+ * point. Once replied, the requesting script will get the response together
+ * with provided context through the [onResponse](#onresponse) entry point
+ *
+ * To get the address of a room script, use the `roomscript` command. For
+ * more info, type:
+ * ```
+ * help roomscript
+ * ```
+ *
+ * @param addr - Address of target script. If addr is "#", it will be a post to the current script instance.
+ * @param topic - Message topic. May be any kind of string.
+ * @param data - Additional data to be sent with the request. Must be valid JSON.
+ * @returns Response to the request.
+ */
+ function request(addr: string, topic: string, data?: string | null): Response;
/**
* Gets info on an existing character.
*
diff --git a/package-lock.json b/package-lock.json
index 5cac5d5..253fc17 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,7 +11,7 @@
"dependencies": {
"assemblyscript": "^0.28.2",
"isomorphic-ws": "^5.0.0",
- "json-as": "github:anisus/json-as#863f37b8c6666e79c219f9e36b01efb5a49a9a19",
+ "json-as": "1.1.21",
"resclient": "^2.5.0",
"tinyargs": "^0.1.4",
"visitor-as": "^0.11.4"
@@ -1085,9 +1085,9 @@
}
},
"node_modules/json-as": {
- "version": "1.1.17",
- "resolved": "git+ssh://git@github.com/anisus/json-as.git#863f37b8c6666e79c219f9e36b01efb5a49a9a19",
- "integrity": "sha512-pIdamF7Vsr0sSPwIJqyy0EKtfab+1hwtVynO4jFqQf1Mt6Y1U9w8vxocGODyfJk8wThQDOWNlh3xkU/RlVlxKg=="
+ "version": "1.1.21",
+ "resolved": "https://registry.npmjs.org/json-as/-/json-as-1.1.21.tgz",
+ "integrity": "sha512-4WlxVqLY6sZHqGyFiKE+ulmbnxhiBlOPXb2KELjNpj1LXh0ZYhaPJq7Ml2Jnt2E5Zmn6AXPmyerdkR0w9GbXRg=="
},
"node_modules/json-buffer": {
"version": "3.0.1",
diff --git a/package.json b/package.json
index d2d69ba..c55448b 100644
--- a/package.json
+++ b/package.json
@@ -37,7 +37,7 @@
"dependencies": {
"assemblyscript": "^0.28.2",
"isomorphic-ws": "^5.0.0",
- "json-as": "github:anisus/json-as#863f37b8c6666e79c219f9e36b01efb5a49a9a19",
+ "json-as": "1.1.21",
"resclient": "^2.5.0",
"tinyargs": "^0.1.4",
"visitor-as": "^0.11.4"