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:pathfinding

(0 notes)

asterobot:pathfinding computes moves on a map the way the Dofus client does. findPath() gives the route the client would walk from one cell to another, the key cells to send for it and how long the walk lasts. The other functions work with cell positions: where a cell sits on the map's grid, and the distance and the direction between two cells.

It only computes. To walk, call move() from asterobot:movement, or send the walk yourself as Walk along a path shows.

import { findPath, cellToPoint, pointToCell, distance, direction } from "asterobot:pathfinding";

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

Export Returns What it does
findPath() A path or undefined, right away Finds the route from one cell of a map to another
cellToPoint() A point, right away Gives a cell's position on the grid
pointToCell() A cell or undefined, right away Gives the cell at a grid position
distance() A number, right away Measures the grid distance between two cells
direction() A direction or undefined, right away Gives the direction from one cell to another

None of them returns a promise. Like the functions of asterobot:gamedata, they throw when the top level of a module calls them while Asterobot reads the package's declarations: see Declarations.

Everything here is about moving outside fights. Moves in a fight follow other rules, and this module doesn't cover them.

Cells and directions

A map has 560 cells, numbered 0 to 559. Every function takes cell ids as regular whole numbers: a BigInt or a string is refused.

A direction is a number from 0 to 7:

Number Direction on screen
0 East
1 South-east
2 South
3 South-west
4 West
5 North-west
6 North
7 North-east

findPath()

findPath(mapId, from, to, options?) returns a Path, or undefined.

Parameter Type Description
mapId BigInt, number or string The map's id: a BigInt such as currentMap().mapId, a whole number up to Number.MAX_SAFE_INTEGER, or the id written in digits, such as "154010883". Any map of the bot's game version works, not only the one the character stands on.
from number The cell the walk starts from
to number The cell to walk to
options.occupied number[] The cells other actors stand on, as described below. Default none.
options.cautious boolean The cautious flag the walk will be sent with. It changes how the character moves, and so the walk's times. Default false.
options.disableDiagonals boolean true only for a character whose look has no diagonal walking animations. Player characters have them, so leave it false.

It reads the map from the game data of the bot's game version and returns the route the Dofus client would take. When to can't be reached, the route ends on the reachable cell closest to it instead, and end tells you which. findPath() returns undefined only when the Dofus client itself would find no route at all, which doesn't happen on the game's maps.

Occupied cells

The Dofus client's router makes a cell with an actor on it more expensive to walk onto, so its routes tend to go around actors. To get the route the client would walk, pass in occupied the cell of every actor the server shows on the map except the bot's own character: other players, monster groups, NPCs, merchants, tax collectors, prisms and the like. Items on the ground, marks and glyphs don't count. currentMap() lists the actors:

import { currentMap } from "asterobot:bot";
import { findPath } from "asterobot:pathfinding";

const map = currentMap();

if (map?.cellId !== undefined) {
  const others = map.actors.filter((actor) => actor.id !== map.characterId);
  const path = findPath(map.mapId, map.cellId, 301, {
    occupied: others.map((actor) => actor.cellId),
  });
}

The path

Property Type Value
start number The cell the route starts from: from
end number The cell the route ends on: to when the router reached it, otherwise the reachable cell closest to to
steps array The route's steps, in walking order. Each one is an object with cell, the cell the character leaves, and direction, the direction it walks from there.
keyCells number[] What MapMovementRequest carries in keyCells for this route. Send them as they are. Empty when end is start: there's nowhere to walk, and the Dofus client sends nothing.
gait string "walk" or "run": how the character moves along the route
duration number How long the walk lasts, in milliseconds: from its start to the moment the Dofus client sends MapMovementConfirmRequest. 0 when end is start.
stepEnds number[] When each step ends, in milliseconds from the start of the walk. The last one is duration.

A character walks a route of 3 cells or fewer, the start included, and runs a longer one. With cautious: true it always walks.

duration is the earliest moment a Dofus client can confirm the walk. A real client only ends a step when it draws its next frame, so it confirms a little later: in walks recorded from the Dofus client, the confirmation left 10 to 48 ms after duration. The times are those of a character on foot. A mounted character runs at a speed Asterobot doesn't cover yet, so its duration can be wrong.

Errors

Error Type Cause
pathfinding.findPath mapId must be an integer Number, BigInt or decimal string TypeError mapId is a fraction, a number above Number.MAX_SAFE_INTEGER, a string that isn't a whole number written in digits, or another type
pathfinding.findPath from must be an integer cell id, and the same with to TypeError The cell isn't a whole number in the 32-bit range, or is a BigInt or a string
pathfinding.findPath options must be an object TypeError options is set, not to null or undefined, and isn't an object: an array or a number, for example
pathfinding.findPath options has no property "<name>" TypeError options has a key other than occupied, cautious and disableDiagonals, such as the misspelled ocupied
pathfinding.findPath options.occupied must be an array of cell ids TypeError occupied isn't an array
pathfinding.findPath options.occupied[<index>] must be an integer cell id TypeError That item isn't a whole number in the 32-bit range
pathfinding.findPath options.cautious must be a boolean, and the same with disableDiagonals TypeError The option is set to something other than true, false, null or undefined
pathfinding.findPath: map <mapId>, cell <from> to cell <to>: pathfinding: not a map cell, cell ids go from 0 to 559: <cell> TypeError from or to is a whole number outside 0 to 559. For a cell of occupied, the text ends with occupied cell <cell> instead.
failed to load map <mapId> for pathfinding: datacenter: no such record: maps/<mapId> Error The bot's game version has no map with that id
failed to open the datacenter: followed by the reason Error Asterobot can't read the game data of the bot's game version, for example because it isn't extracted. See Extract game data.

String(error) gives TypeError: or GoError: followed by the text.

cellToPoint()

cellToPoint(cell) returns { x, y }, the cell's position on the map's grid.

cellToPoint(300); // { x: 17, y: -4 }

The grid is the map turned 45 degrees, so both numbers change along a row of the screen. One cell to the east adds 1 to x and 1 to y. One cell to the south adds 1 to x and takes 1 from y.

Error Type Cause
pathfinding.cellToPoint cell must be an integer cell id TypeError cell isn't a whole number in the 32-bit range, or is a BigInt or a string
pathfinding.cellToPoint cell: pathfinding: not a map cell, cell ids go from 0 to 559 TypeError cell is outside 0 to 559

pointToCell()

pointToCell(x, y) returns the cell at that grid position, or undefined when the position is off the map.

pointToCell(18, -3); // 301
pointToCell(0, 1); // undefined

It throws a TypeError with pathfinding.pointToCell x and y must be integers when x or y isn't a whole number in the 32-bit range, or is a BigInt or a string.

distance()

distance(a, b) returns the grid distance between two cells, as the Dofus client measures it: how far apart their x are, plus how far apart their y are.

distance(300, 301); // 2

So the next cell to the south-east, south-west, north-east or north-west is 1 away, and the next cell to the east, west, north or south is 2 away.

Error Type Cause
pathfinding.distance a must be an integer cell id, and the same with b TypeError The cell isn't a whole number in the 32-bit range, or is a BigInt or a string
pathfinding.distance cells: pathfinding: not a map cell, cell ids go from 0 to 559 TypeError A cell is outside 0 to 559

direction()

direction(from, to) returns the direction from one cell to another, or undefined when the two cells aren't on one line.

direction(300, 301); // 0, east
direction(300, 316); // undefined

Two cells on one line give that line's direction, whatever their distance. The same cell twice gives 1, as it does in the Dofus client.

Error Type Cause
pathfinding.direction from must be an integer cell id, and the same with to TypeError The cell isn't a whole number in the 32-bit range, or is a BigInt or a string
pathfinding.direction cells: pathfinding: not a map cell, cell ids go from 0 to 559 TypeError A cell is outside 0 to 559

Walk along a path

A walk takes two exchanges with the game server:

  1. The script sends MapMovementRequest with the path's keyCells, the cautious flag and the map's id. The server grants the walk with MapMovementEvent, whose cells list every cell of the walk. The server sends that message for every actor that walks on the map, so compare its characterId with the character's. It can also grant a shorter walk than the one asked for.
  2. Once the walk is over, the character confirms it with MapMovementConfirmRequest, which has no field, and the server answers with MapMovementConfirmResponse. Until then, the server considers the character still walking.

Who sends the confirmation depends on the bot:

Bot Who sends MapMovementConfirmRequest
Full socket Your script, duration milliseconds after MapMovementEvent arrived. Nothing else will.
MITM, where session.shared is true The Dofus client, once it has walked the character on screen. Your script only waits for the server's answer.
import { currentMap, session } from "asterobot:bot";
import { findPath } from "asterobot:pathfinding";
import { send, wait } from "asterobot:protocol";
import { sleep } from "asterobot:timers";

async function walkTo(cell) {
  const map = currentMap();
  if (map?.cellId === undefined) return;

  const others = map.actors.filter((actor) => actor.id !== map.characterId);
  const path = findPath(map.mapId, map.cellId, cell, {
    occupied: others.map((actor) => actor.cellId),
  });
  if (!path || path.keyCells.length === 0) return;

  await Promise.all([
    wait(
      (traffic) =>
        traffic.type === "MapMovementEvent" && traffic.payload?.characterId === map.characterId,
      { timeout: 5000 },
    ),
    send("MapMovementRequest", { keyCells: path.keyCells, cautious: false, mapId: map.mapId }),
  ]);

  if (session.shared) {
    // The Dofus client confirms the walk once it has walked it.
    await wait("MapMovementConfirmResponse", { timeout: path.duration + 5000 });
    return;
  }

  await sleep(path.duration);
  await Promise.all([
    wait("MapMovementConfirmResponse", { timeout: 5000 }),
    send("MapMovementConfirmRequest", {}),
  ]);
}

wait() comes first in each Promise.all, so it's already listening when the message goes out, as Send messages explains.

This sample times the confirmation with the route it asked for. When the server grants a shorter walk, time the walk it granted instead, for example with findPath() from the first of its cells to the last. Start one walk at a time: a walk started before the previous one ends would start from a cell the character hasn't reached yet.

To stop a walk before its end, the Dofus client sends MapMovementCancelRequest with the cell the character stopped on, and the server doesn't answer it. stepEnds tells you which step the character has reached at a given moment.

move() does all of this in one call, shorter walks and both kinds of bots included.

asterobot:bot describes currentMap(), and the Dofus protocol reference lists the fields of the movement messages.

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.