Scripts run modern JavaScript, with three constructs left out and a few built-in objects missing. JSDoc comments make what the editor tells you more precise.
What works
The syntax of JavaScript up to ES2022 works, apart from the three constructs in the next section. That includes:
- classes, with private fields such as
#countand static blocks asyncfunctions andawait, withPromise.all(),Promise.allSettled()andPromise.any()- generators (
function*) andfor...of - optional chaining
?.,??and??=, spread and rest, destructuring, template literals BigInt, and typed arrays such asUint8Array- top-level
awaitandimport.meta - numeric separators, as in
60_000 - recent methods such as
Array.prototype.at(),flatMap(),Object.hasOwn(),String.prototype.replaceAll()andmatchAll()
Every file is an ES module, so it runs in strict mode: assigning to a variable you never declared throws, for example.
TypeScript isn't supported. A package's files must end in .js or .mjs.
Three constructs that don't work
| Construct | What happens |
|---|---|
Async generators, async function* |
The file can't be loaded, so the script doesn't start. |
for await (... of ...) |
The file can't be loaded, so the script doesn't start. |
import() called as a function |
The file loads, but the call rejects when it runs, with dynamic import() is not supported by this Asterobot runtime. |
Each has a plain replacement. Instead of an async generator, write an async function that returns an array. Instead of for await, put the await in the body of a regular loop:
for (const pending of promises) {
const value = await pending;
}
Instead of import(), import the module at the top of the file with a regular import statement.
The editor's warnings
The editor puts a warning on each of the three, in every file of the package, whether the file is open or not:
| On | Warning |
|---|---|
async function* |
Says that async generators aren't supported |
for await ( |
Says that for await...of isn't supported |
import( |
Dynamic import() is refused at runtime - a behavior's imports must be static. |
Warnings don't count in the error badge, and they don't stop you from saving or running, but the script won't work while one of these constructs is there. The editor finds them by searching the text, so the same words in a comment or a string get a warning too.
The editor also checks your code the way TypeScript checks JavaScript. It knows the ES2022 built-in objects, the asterobot: modules and the game's messages, and no browser or Node.js global, so document, setTimeout() or require() are marked as errors. The check isn't strict: a value that could be undefined isn't flagged, for example.
Built-in objects that don't exist
The editor completes three built-in objects that scripts don't have: Intl, WeakRef and FinalizationRegistry. Using one throws a ReferenceError when the code runs. Without Intl, format numbers and dates yourself.
Modules and imports lists the browser and Node.js globals that are missing too.
JSDoc types
Scripts are plain JavaScript, but the editor reads JSDoc comments and uses their types for completion and checks. These types can be used in any file, without an import:
| Type | What it describes |
|---|---|
BehaviorLaunch |
The launch object the entry function receives |
ProtocolTraffic |
A traffic object. ProtocolTraffic<GameMessageResults["ChatChannelMessageEvent"]> also describes its payload. |
GameMessageResults |
The payload of each message as a script receives it, by message name |
GameMessagePayloads |
The payload of each message as send() accepts it, by message name |
BehaviorParameters |
An export const parameters object |
BehaviorActions |
An export const actions object |
The message types are part of the typings behind the editor's IntelliSense badge. When the badge says the typings couldn't be loaded, the editor doesn't know any message name.
A handler you pass to on() with a message name already gets a typed payload, without any comment. JSDoc helps most in your own functions:
import { session, botInfo } from "asterobot:bot";
import { on, send } from "asterobot:protocol";
/**
* @param {ProtocolTraffic<GameMessageResults["ChatChannelMessageEvent"]>} traffic
* @returns {string}
*/
function formatChat(traffic) {
const payload = traffic.payload;
if (!payload) return "(a chat line Asterobot couldn't decode)";
return `[${payload.channel}] ${payload.senderName}: ${payload.content}`;
}
/** @param {BehaviorLaunch} launch */
export default async function behavior(launch) {
on("ChatChannelMessageEvent", (traffic) => {
botInfo(formatChat(traffic));
});
// 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,
});
}
}
In the same way, put /** @type {BehaviorParameters} */ on the line above export const parameters to have each setting's fields checked. Declare settings describes them.
The next chapter, Game protocol, goes into messages in detail.
Aucun avis à afficher.