wait() pauses your code until a message you describe arrives, and hands you that message. It's the tool for "do something, then carry on when the game answers".
wait()
const traffic = await wait(selector, { timeout: 5000 });
wait() returns a promise that resolves with the traffic object of the next message matching selector. The selector is the same as for on(): a message name, "*" for any message, or a function that returns true for the message you want. Listening describes them.
The rest of the bot doesn't pause while you wait. Handlers keep running, and other parts of your code can wait for other messages at the same time.
Only inbound messages
wait() only sees inbound messages: what the game server sends, and what a script or the Network tool sends to the client. A message going to the server never resolves a wait, even with "*". Use onTraffic() to see those.
No timeout unless you pass one
Important
wait() has no timeout of its own. Without { timeout }, a wait that never matches stays open until the script stops, and the code after it never runs. Always pass a timeout.
timeout is a number of milliseconds greater than zero. When it runs out, the promise rejects with protocol wait timed out. That's what gets your code going again when a message doesn't come, whether the game never sends it or its name changed after an update.
| Function | Default timeout |
|---|---|
wait() |
None: it waits until the script stops |
send() |
30 seconds |
request() |
30 seconds |
A wait can't be cancelled. It ends when a message matches, when its timeout runs out, or when the script stops, so give it the shortest timeout that makes sense.
Start waiting before you send
A wait only sees messages that arrive after wait() was called. It doesn't look back.
That matters when you send a message and wait for the game's answer. Nothing guarantees that send() resolves before the answer arrives, so a wait started after await send() can miss an answer that came quickly. Start the wait first, and await both together:
const [echo] = await Promise.all([
wait(
(traffic) => traffic.type === "ChatChannelMessageEvent" && traffic.payload?.content === text,
{ timeout: 5000 },
),
send("ChatChannelMessageRequest", { channel: "PARTY", content: text }),
]);
wait() is called first, so it's in place before the message goes out. Promise.all resolves with both results, the matching message first, and rejects as soon as either one fails.
Don't store the wait's promise to await it after send():
// Don't: if send() rejects, this wait is left behind.
const pending = wait("ChatChannelMessageEvent", { timeout: 5000 });
await send("ChatChannelMessageRequest", { channel: "PARTY", content: text });
await pending;
If send() rejects there, nothing awaits pending any more. Its timeout rejects it later with nothing to handle the rejection, and an unhandled rejection stops the script. Promise.all handles both promises, so a rejection that comes after the other one failed does no harm.
Several waits for one message
- When several waits match the same message, they all resolve with it, in the order they were started.
- Waits resolve after every
on()andonTraffic()handler has run for that message. - A function selector that throws stops the whole script, not only the wait, with an error that includes
evaluate protocol wait selector:. - A script can have 128 waits open at once. One more rejects with
behavior resource limit exceeded: maximum waits reached.
Patterns
Carry on when nothing comes
Catch the timeout and decide what happens next:
try {
const traffic = await wait("InventoryWeightEvent", { timeout: 10000 });
botInfo("Pods:", traffic.payload?.inventoryWeight);
} catch (error) {
// No update can also mean the weight didn't change.
botWarn("No weight update:", String(error));
}
Wait for one of several messages
A function selector can accept several names, and the message you get tells you which one came:
const names = new Set(["InventoryWeightEvent", "InventoryContentEvent"]);
const traffic = await wait((candidate) => names.has(candidate.type), { timeout: 10000 });
botInfo("Received", traffic.type);
Wait inside a handler
Waiting in an async handler doesn't hold up other handlers or messages, which is how the handler gets to see the answer arrive. Put the wait in try/catch: a timeout that escapes a handler stops the script.
This script repeats in the party channel what a party member asks it to say with !say, and checks that the line went through:
import { session, botInfo, botWarn } from "asterobot:bot";
import { on, send, wait } from "asterobot:protocol";
export default async function behavior(launch) {
on("ChatChannelMessageEvent", async (traffic) => {
const content = traffic.payload?.content;
if (traffic.payload?.channel !== "PARTY" || typeof content !== "string" || !content.startsWith("!say ")) return;
const text = content.slice("!say ".length);
// Never repeat a command: the game sends our own line back to us.
if (text === "" || text.startsWith("!")) return;
try {
await Promise.all([
wait(
(echo) => echo.type === "ChatChannelMessageEvent" && echo.payload?.content === text,
{ timeout: 5000 },
),
send("ChatChannelMessageRequest", { channel: "PARTY", content: text }),
]);
botInfo("Said in party:", text);
} catch (error) {
// An error that escapes a handler stops the whole script.
botWarn("Couldn't say it:", String(error));
}
});
// A new game connection starts with this message. MITM bots never launch
// with "initial": the Dofus client has already identified their session.
if (launch.reason === "initial") {
await send("IdentificationRequest", {
ticketKey: session.gameToken,
languageCode: session.language,
});
}
}
Errors
wait() never throws: every problem rejects its promise.
| Error | Cause |
|---|---|
protocol wait timed out |
The timeout ran out before a message matched. |
behavior resource limit exceeded: maximum waits reached |
128 waits are already open. |
timeout/milliseconds must be a finite positive Number |
timeout is 0, negative, or not a number. |
timeout/milliseconds is too large |
timeout is too large to be a duration. |
protocol options must be an object |
The second argument isn't an object. |
unknown protocol option "retries" |
The options have a key other than timeout and to. to is accepted and ignored. |
protocol selector cannot be empty |
The selector is "". |
protocol selector must be a semantic type, '*', or predicate |
The selector is neither a string nor a function. |
Next, Sending covers send() and request(), and Limits lists every limit.
Aucun avis à afficher.