Aller au contenu
Afficher dans l'application

Une meilleure façon de naviguer. En savoir plus.

Asterobot

Une application plein écran sur votre écran d'accueil avec notifications push, badges et plus encore.

Pour installer cette application sur iOS et iPadOS
  1. Appuyez sur Icône de partage dans Safari
  2. Faites défiler le menu et appuyez sur Ajouter à l'écran d'accueil.
  3. Appuyez sur Ajouter dans le coin supérieur droit.
Pour installer cette application sur Android
  1. Appuyez sur le menu à trois points (⋮) dans le coin supérieur droit du navigateur.
  2. Appuyez sur Ajouter à l'écran d'accueil ou Installer l'application.
  3. Confirmez en appuyant sur Installer.

asterobot:protocol

(0 notes)

asterobot:protocol is how a script exchanges messages with the game: it sends them, waits for them, reacts to them, and changes or blocks them on their way through. Listening, Waiting, Sending and Intercepting explain how to use each part.

import { send, request, wait, on, onTraffic, intercept, off } from "asterobot:protocol";

These are the module's only exports. There's no protocol object to import.

Export What it does
send() Sends a message, and resolves once it's sent
request() Sends a request, and resolves with the response matched to it
wait() Resolves with the next inbound message that matches
on() Calls a handler for every inbound message that matches
onTraffic() Calls a handler for every message, in both directions
intercept() Decides whether a message goes on unchanged, is dropped or is replaced
off() Removes a handler registered with on(), onTraffic() or intercept()

Message names and fields are the ones in the Dofus protocol reference.

send()

send(type, payload, options?) returns Promise<void>.

Parameter Type Description
type string The message's name, such as "ChatChannelMessageRequest"
payload object The message's fields. Pass {} for a message you send without fields: leaving payload out is an error.
options.timeout number Milliseconds before the promise rejects. Default: 30000.
options.to "server" or "client" Where the message goes. Default: "server".

send() builds the message and writes it. The promise resolves as soon as the message is written: it doesn't wait for an answer, so use wait() when you need to know what the game did.

With to: "server", the message goes to the game server as if the Dofus client had sent it. onTraffic() handlers see it go out, and no interceptor is asked about it.

With to: "client", the message is delivered as an event from the server:

  • On a MITM bot, Asterobot writes it to the Dofus client, which acts on it as if the server had sent it.
  • On a Full socket bot there's no Dofus client, so the message only reaches the script's own on(), onTraffic() and wait().

Either way it arrives as an inbound message, so the same script works on both kinds of bot.

On a MITM bot, an IdentificationRequest sent to the server is never forwarded, because the Dofus client has already identified the session. The promise resolves anyway, and the bot's Console shows the warning Refused to forward a message that would re-authenticate a relayed session.

The promise rejects with:

Error Cause
protocol type must be a non-empty semantic message name type is missing, empty or not a string
semantic protobuf message is not mapped: <type> Asterobot has no message with that name. Check the spelling, and see After a game update.
<type>: expected an object payload is missing, null or undefined
<type>.<field>: unknown protobuf field The message has no field with that name, for example IdentificationRequest.token: unknown protobuf field
Another text starting with <type> A field's value doesn't fit. Payload errors lists them all.
protocol options must be an object options isn't an object, for example send(type, payload, 5000)
unknown protocol option "<name>" options has a key other than timeout and to
timeout/milliseconds must be a finite positive Number timeout isn't a number greater than 0
timeout/milliseconds is too large timeout is too big to be a duration
send option "to" must be "server" or "client" to isn't a string
unknown send target "<value>": expected "server" or "client" to is a string other than those two
behavior resource limit exceeded: maximum pending operations reached 32 operations are already pending. See Limits.

It also rejects when the message can't be written before the timeout, or when the game connection closes.

await send("ChatChannelMessageRequest", { channel: "GLOBAL", content: "Hello" });

request()

request(type, payload, options?) returns Promise<ProtocolTraffic>.

Parameter Type Description
type string The request's name
payload object Its fields, as for send()
options.timeout number Milliseconds before the promise rejects. Default: 30000.

options.to is accepted and ignored: a request always goes to the server.

request() sends the message as a request carrying a new uid, and resolves with the response the server sends back with the same uid, as a traffic object whose kind is "response".

Only a few Dofus requests get such a response. The game answers most of them with an event, or not at all, and request() then waits for its whole timeout before rejecting. For those, send the message with send() and wait() for the event.

The promise rejects with the same argument, payload and limit errors as send(), apart from the two about to, and with:

Error Cause
context deadline exceeded No response came back before the timeout
mitm relay refuses to identify: this Game session was already authenticated by the real DOFUS client The script sent IdentificationRequest on a MITM bot. The request isn't forwarded.

wait()

wait(selector, options?) returns Promise<ProtocolTraffic>.

Parameter Type Description
selector string or function A message name, "*" for any message, or a function that receives a traffic object and returns true for the message you want
options.timeout number Milliseconds before the promise rejects. There's no default: without a timeout, wait() waits until the script stops.

options.to is accepted and ignored.

wait() looks at inbound messages that arrive after the call, and resolves with the first one that matches. When several waits match the same message, they all resolve with it. For each message, the handlers registered with on() and onTraffic() run before the waits are checked.

Since it only sees what arrives after the call, start the wait before you send the message it waits for, for example with Promise.all(): the answer can arrive before await send() has resolved. Waiting shows how.

A selector function runs for every inbound message until the wait settles. If it throws, the whole script stops, with evaluate protocol wait selector: <error>.

The promise rejects with:

Error Cause
protocol wait timed out The timeout passed before a message matched
protocol selector cannot be empty selector is ""
protocol selector must be a semantic type, '*', or predicate selector is neither a string nor a function
protocol options must be an object, unknown protocol option "<name>", timeout/milliseconds must be a finite positive Number, timeout/milliseconds is too large The options are wrong, as for send()
behavior resource limit exceeded: maximum waits reached 128 waits are already open
const echo = await wait(
  (traffic) => traffic.type === "ChatChannelMessageEvent" && traffic.payload?.content === "Hello",
  { timeout: 5000 },
);

on()

on(selector, handler) returns a handle, { id }, where id is a BigInt.

Parameter Type Description
selector string or function A message name, "*" for any message, or a function that returns true for the messages to handle
handler function Called with the traffic object of each matching inbound message. It may be async.

on() sends nothing and returns right away. From then on, handler runs for every inbound message that matches, until you pass the handle to off() or the script stops. Outbound messages never reach it, whatever the selector.

Handlers run one message at a time, in the order they were registered, onTraffic() handlers included. A handler registered while a message is being handled starts with the next message. An async handler returns at its first await, and the next handler doesn't wait for it to finish.

An error in a handler stops the script:

What happened Text in the Problems alert
The handler threw Game traffic handler failed: <error>
An async handler's promise rejected unhandled Promise rejection: <error>
The selector function threw evaluate protocol handler selector: <error>

on() throws a TypeError at once, instead of returning, when:

Error Cause
protocol selector cannot be empty selector is ""
protocol selector must be a semantic type, '*', or predicate selector is neither a string nor a function
protocol.on handler must be callable handler isn't a function
maximum behavior handlers reached 256 handlers from on(), onTraffic() and intercept() are already registered

If the script is already stopping, on() throws the reason it's stopping.

const handle = on("ChatChannelMessageEvent", (traffic) => {
  if (!traffic.payload) return;
  botInfo(`${traffic.payload.senderName}: ${traffic.payload.content}`);
});

onTraffic()

onTraffic(handler) returns a handle, { id }.

It works like on("*", handler), except that it receives messages in both directions:

  • what the game server sends;
  • what the Dofus client sends, on a MITM bot;
  • what the script sends with send() and request();
  • what someone sends from the bot's Network tool.

A message dropped by an interceptor never reaches it.

onTraffic() throws a TypeError with protocol.onTraffic handler must be callable when handler isn't a function, and with maximum behavior handlers reached past the limit. Errors in the handler stop the script, with the same texts as for on().

intercept()

intercept(selector, handler) or intercept(handler) returns a handle, { id }.

Parameter Type Description
selector string or function Optional. A message name, "*", or a function that returns true for the messages to decide about. With only one argument, handler is asked about every message.
handler function Called with the traffic object, and returns a decision. It must answer synchronously.

An interceptor is asked about the messages the bot carries: every inbound message from the game server, and on a MITM bot every outbound message from the Dofus client. It's never asked about:

  • a message the script sends, nor one sent from the bot's Network tool, although both still reach onTraffic();
  • on a MITM bot, the Dofus client's first message, and the responses to the script's own request() calls;
  • a message Asterobot can't read at all. A MITM bot forwards such a message without showing it to the script, and a Full socket bot closes its game connection when it receives one.

For each message, interceptors are asked in the order they were registered. One whose selector doesn't match, or that returns no decision, leaves the message to the next. The first decision wins, and the interceptors after it aren't asked.

As soon as one interceptor is registered, every message the bot carries waits for the script, whatever the selectors say, because Asterobot checks them inside the script. Remove an interceptor with off() once you no longer need it.

Return value What happens
undefined, null, or any value not listed below No decision. The next interceptor is asked, and when none decides, the message goes on unchanged.
"drop" The message stops here. On a MITM bot the other side never receives it, and on every bot on(), onTraffic() and wait() never see it. On a Full socket bot, dropping the response to a request() makes that request() wait for its timeout.
{ payload } The message goes on, rebuilt from these fields. It keeps its name, its kind and its uid. A field you leave out of the object is left out of the message, and the fields Asterobot has no name for are lost.
{ raw } The message is replaced by these bytes, a Uint8Array or an ArrayBuffer. They stand for the whole message as it travels on the connection, envelope included, not for traffic.rawAny. raw is used when both raw and payload are present.

After a replacement, the script's handlers and waits see the new message. A MITM bot forwards raw bytes even when Asterobot can't read them, and its handlers then see the original message. On a Full socket bot, bytes Asterobot can't read change nothing.

An async handler returns a promise, and a promise isn't a decision: the message goes on before the promise settles. If that promise rejects, nothing catches it, and the script stops with unhandled Promise rejection: <error>.

The message waits at most 50 ms for a decision, counted from when it arrives, so time the script spends on other work counts too. Past that, it goes on unchanged and nothing is written anywhere: the handler keeps running, and its answer is ignored. On a MITM bot, the person playing feels a slow interceptor as lag. Intercepting explains these rules with examples.

When a handler throws, or its selector function throws, the script doesn't stop. The message goes to the next interceptor, or on unchanged, and the bot's Console gets an error line for that message. When several interceptors fail on the same message, the line is written for the first failure only, and again at the tenth, ending with (10 times).

Console line Cause
interceptor failed: <error> The handler threw, or ran for more than 250 ms
interceptor selector failed: <error> The selector function threw
build replacement payload for <type>: <error> The payload doesn't fit the message. <error> is one of the payload errors.
re-encode <type>: <error> Asterobot couldn't rebuild the message with the new fields
cannot replace the payload of <wire name>: this build has no name for it, so there is nothing to build a replacement from - use { raw } instead { payload } was returned for a message without a readable name

intercept() throws a TypeError, like on(), for a bad selector, with protocol.intercept handler must be callable when handler isn't a function, and with maximum behavior handlers reached past the limit.

intercept("ChatChannelMessageRequest", (traffic) => {
  if (!traffic.payload) return;
  return { payload: { ...traffic.payload, content: traffic.payload.content.toUpperCase() } };
});

On a MITM bot, this turns everything the player types in chat into capital letters before the server receives it.

off()

off(handle) returns undefined.

It removes a handler registered with on(), onTraffic() or intercept(), given the handle they returned. A handler removed while a message is being handled doesn't run for that message if its turn hasn't come yet. off() never throws: a handle that was already removed, or anything else, is ignored. It doesn't remove what onChange() from asterobot:parameters registered: use offChange() for that.

The traffic object

Handlers, selector functions and interceptors receive a traffic object, and wait() and request() resolve with one. Traffic explains its properties in depth.

Property Type Value
sequence BigInt The message's position in the bot's traffic. A dropped message leaves a gap. On a MITM bot, the object request() resolves with has 0n.
direction string "inbound" from the server towards the client, "outbound" from the client towards the server
kind string "request", "event" or "response". The type also lists "unknown", which scripts never receive, because a message Asterobot can't read isn't delivered.
uid number The number that pairs a request with its response. -1 on events, and on messages sent with send().
type string The message's readable name, or "" when Asterobot has no name for it
wireType string The name the message has on the connection, which changes between game versions
typeUrl string The full type identifier of the message's content
payload object, or absent The message's fields, when Asterobot could read them
unknown boolean true when there's no payload
decodeError string, or absent What went wrong while reading the message's content. It can be there along with a payload.
rawAny Uint8Array The message's content as bytes, without its envelope. Always present, possibly empty.

Payload values

A payload's field names are the camelCase names, such as senderName. When sending, the names from the protocol definitions, such as sender_name, work too, but not both for the same field. Payloads covers every case.

Field type A script reads A script can send
64-bit integer A BigInt A BigInt, a string of digits, or a whole number no bigger than Number.MAX_SAFE_INTEGER either way
32-bit integer A number A whole number within the field's range
Floating point A number A number
Boolean A boolean A boolean
String A string A string
Bytes A Uint8Array A Uint8Array or an ArrayBuffer
Enum The value's name, such as "GLOBAL", or a number for a value without a name The name or the number
List An array An array
Map An object with string keys A plain object
Nested message An object An object, or null to leave it out
Group of alternatives (oneof) Only the field that's set One field of the group at most

A nested message, an optional field or an alternative that the message doesn't set is absent from payload. Other fields are always there, with 0, "", false or an empty array when they're not set.

When sending, a field you leave out isn't sent. Setting a field to undefined is an error, and null is only accepted for a nested message.

The editor completes message names and payload fields, and knows the types ProtocolTraffic, ProtocolOptions, ProtocolSelector, ProtocolSubscription and ProtocolDecision.

Commentaires des utilisateurs

Aucun avis à afficher.

Compte

Navigation

Recherche

Recherche

Configurer les notifications push du navigateur

Chrome (Android)
  1. Appuyez sur l'icône de cadenas à côté de la barre d'adresse.
  2. Tap Autorisations → Notifications.
  3. Ajustez vos préférences.
Chrome (Desktop)
  1. Cliquez sur l'icône représentant un cadenas dans la barre d'adresse..
  2. Select Paramètres du site.
  3. Find Notifications et ajustez vos préférences.