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.

Protocole Dofus

Le protocole Dofus actuellement pris en charge par Asterobot
Claims the reward for a finished achievement, or every claimable reward at once.
Kind request · Area Game.Achievement
Claims one achievement's reward.
achievement_id OF -1 CLAIMS EVERYTHING CLAIMABLE AT ONCE. That is a real value, not a sentinel for "unset": the client sends exactly that when the player accepts all rewards. Be sure you meant it - there is no per-item confirmation.
The current build pads the message with a nested four-member message that no dumped build writes. Leave it alone.
When you may send it
Requires character_loaded observed Raised by: the player accepts a reward in the rewards menu proven Related messages
Reply not yet recovered: the reward arrives as items - watch GameActionItemListEvent and your inventory - but the acknowledgement message itself has no signature here yet. Fields
#FieldTypeMeaningYou set it 1achievement_idint32Which achievement's reward to claim, or -1 for every claimable reward at once. (achievement id)
Range: a real achievement id, or -1 for all
-1 IS MEANINGFUL, not a placeholder.required
  • summary: Claims the reward for a finished achievement, or every claimable reward at once.
  • area: Game.Achievement
  • 162 vues
Asks for the players the character has recently met or grouped with, as distinct from added friends.
Kind request · Area Game.Social
It is one of a FIXED FOUR-REQUEST BURST the client fires once per entry into the world, straight after asking for the game context. The client's own name for the routine survives obfuscation: SendRequestAfterCharacterLoaded. The order is constant:
ContextCreationRequest (the context first) 1. FriendListRequest 2. AcquaintanceListRequest 3. SpouseInformationRequest 4. GuildInformationRequest That order is not guessed from traffic: it is the order the routine allocates the four objects in, and a live capture reproduces it exactly - the first three land inside the same millisecond, the guild request three milliseconds later.
SEND IT ONCE, AT THAT POINT. NEVER POLL IT. The trigger is "the character finished loading", not a timer.
ACQUAINTANCES ARE NOT FRIENDS. These are players the character has recently met or grouped with; explicitly added friends come from FriendListRequest. The two lists overlap but neither contains the other.
Carries nothing.
When you may send it
Requires character_loaded observed Related messages
Reply not yet recovered: the acquaintance list arrives as an event that has no signature here yet. Sequence
Step post_character_load.2 observed — of 4 requests, in the order the client's own routine allocates them
  • summary: Asks for the players the character has recently met or grouped with, as distinct from added friends.
  • area: Game.Social
  • 115 vues
Asks for the whole anomaly board: every subarea, whether an anomaly is there and what it pays. Empty payload.
Kind request · Area Game.Anomaly
Carries nothing. One request returns the entire board - there is no per-subarea form.
THIS IS THE MESSAGE A FARMING SCRIPT WANTS. The board says which subareas currently carry an anomaly and what reward bonus each grants, which is exactly the input for deciding where to go.
Ask when you need to choose, not on a loop. The board changes when anomalies open and close, and AnomalyOpenedEvent and AnomalyStateEvent tell you about those as they happen - so you can keep your copy current without asking again.
Three builds pad this message; no writer in any dumped build populates anything. Send it empty.
When you may send it
Requires character_loaded observed Raised by: one internal client notification, once per session - not a timer, not per subarea, not per map change. The bus hides what raises it, so send it once the session can render the map and zaap UIs inferred Related messages
You will then receive AnomalySubareaInformationEvent inferred — the server answers with the whole board
  • summary: Asks for the whole anomaly board: every subarea, whether an anomaly is there and what it pays. Empty payload.
  • area: Game.Anomaly
  • 107 vues
Asks for a fresh API token for the in-client shop back end. Empty payload, sent on a timer.
Kind request · Area Game.Bak
Refreshes the key for Ankama's in-client shop back end. Carries nothing.
THE TRIGGER IS TOKEN LIFECYCLE, NEVER USER ACTION, and the client's state machine has three parts worth reproducing:
in-flight latch one request at a time. The send routine sets a latch and will not send a second while one is outstanding. 5,000 ms retry when it cannot send yet - the connection is not up - it re-arms on a 5 second delay and tries again. A real repeating cadence during bring-up. 3,600,000 ms after a successful answer, EXACTLY ONE HOUR before the next refresh. A long session re-sends this hourly, indefinitely. Both constants are read straight out of the client, one in the send routine and one in the receive routine.
IT APPEARS DURING BRING-UP ALONGSIDE THE SOCIAL BURST, AND IT IS NOT PART OF IT. A capture shows it in the same handful of milliseconds as ContextCreationRequest and the four-request burst described under FriendListRequest - but it comes from a different service on a different trigger. Do not fold it into that sequence.
Nothing in gameplay depends on having the key.
When you may send it
Requires authenticated observed Raised by: token lifecycle, never a user action: 3,600,000ms after each successful key, and a 5,000ms retry whenever the send cannot proceed; one in flight at a time proven Related messages
You will then receive BakApiKeyEvent observed — the server answers with the key; observed in a live session
  • summary: Asks for a fresh API token for the in-client shop back end. Empty payload, sent on a timer.
  • area: Game.Bak
  • 93 vues
Answers the server's latency poll with the mean of the client's last 50 round-trip measurements, in milliseconds.
Kind request · Area Game.Basic
Answers BasicLatencyStatsEvent. One integer: how long your round trips are taking, in milliseconds.
WHEN TO SEND IT
ONCE PER POLL, IMMEDIATELY, AND FROM NOWHERE ELSE. The client builds this message in exactly one place - inside the handler for the poll - and replies unconditionally. There is no timer, no threshold and no proactive path. If you did not just receive the poll, do not send it.
REPLY ON THE SOCKET THE POLL ARRIVED ON. The client answers on the originating connection, which only matters once you hold two at the same time (see IdentificationRequest): the measurement buffer is shared between them, the reply is not.
WHAT TO PUT IN IT
THE VALUE IS A MEAN, NOT A LAST READING. The client averages the round trips it has stored - at most the last 50 - and rounds to the nearest millisecond, ties going to the even value. It is not the most recent sample, and it is not smoothed or weighted. Those samples come from the PingRequest / PongEvent exchange and from nothing else.
WITH NO SAMPLES IT REPORTS 0. There is no guard for an empty buffer: a client that has never completed a ping exchange reports zero. That is faithful, but over a long session it is also a tell - real latency is never exactly and permanently zero. If you are going to answer these polls, ping often enough to have something true to say.
KEEP IT IN A PLAUSIBLE RANGE. The client casts its average through a signed 16-bit integer before writing this 32-bit field, so a value above 32767 would go out negative and one above 65535 would wrap. No real latency comes near that ceiling, which is the point: a number outside roughly 0-2000 is not something a real client can produce.
IT IS SELF-REPORTED, AND CHECKABLE. The server can compare what you claim against how long you actually took to answer this very poll.
THE TWO REPLIES TO ONE FRAME DO NOT LOOK ALIKE
This poll arrives in the same frame as SequenceNumberEvent, and the two replies leave with different envelopes. This one travels as a correlated request: the client allocates a uid from a counter that cycles 0-65534 and puts it on the envelope. SequenceNumberRequest does not - it goes out with the uid set to -1. Giving both a normal uid, or neither, is a shape no real client produces.
When you may send it
Requires authenticated observed Related messages
Answers BasicLatencyStatsEvent Fields
#FieldTypeMeaningYou set it 1latencyint32The mean of the client's stored round-trip measurements. (ms)
Range: 0 upward in practice; the client truncates through a signed 16-bit integer, so anything above 32767 goes out negative
Averaged over at most the last 50 samples and rounded to the nearest millisecond, ties to even. Not the latest round trip.
A client with no samples yet reports 0 - there is no guard for an empty buffer.required
  • summary: Answers the server's latency poll with the mean of the client's last 50 round-trip measurements, in milliseconds.
  • area: Game.Basic
  • 100 vues
Creates a character on the current server. One wrapper field carrying the whole appearance.
Kind request · Area Game.Character.Management
ONE FIELD, AND EVERYTHING IS INSIDE IT. The request is a thin wrapper: the whole character - name, class, gender, colours, head - travels in CharacterRemodelingInformation. Read that record before building this one; it is where every rule about the payload lives.
WHEN TO SEND IT
ONCE, WHEN YOU HAVE CHOSEN EVERYTHING. The real client sends it from the creation screen's confirm button and from nowhere else. It is not idempotent in any useful sense: a second identical request is a second character, or a refusal.
YOU MUST ALREADY BE ON A SERVER. This is game-server traffic, not connection traffic - you send it after you have picked a server and the game context is up.
THE CLIENT VALIDATES BEFORE IT SENDS. It refuses to build the request at all when the name box is empty or the name fails its local check, and it fills the colour list to six entries first. None of that is enforced by the wire format, so a script that skips it simply gets refused by the server instead - see CharacterCreationResultEvent, which distinguishes the two.
WHAT COMES BACK
CharacterCreationResultEvent, always - success and every kind of refusal use the same message. It is uncorrelated, so its envelope uid is -1 and there is nothing to match against; watch for the event by type.
ON SUCCESS the character list is what changes; the client re-reads it rather than being told the new character inline.
When you may send it
Requires authenticated observed Raised by: a client-side state change: the player confirming character creation on the creation screen. The screen builds one internal notification carrying the name, the class, the chosen head, the gender and the colour list, and the character service turns that notification into this request inferred Related messages
You will then receive CharacterCreationResultEvent observed — the server answers with a result code, and a name reason when the name is what it rejected Fields
#FieldTypeMeaningYou set it 1modeling_informationCharacterRemodelingInformationThe whole character you are asking for: name, class, gender, colours and head.required
  • summary: Creates a character on the current server. One wrapper field carrying the whole appearance.
  • area: Game.Character.Management
  • 125 vues
Destroys a character. This is irreversible and there is no further confirmation exchange.
Kind request · Area Game.Character
STEP 3 OF 3, AND THE DESTRUCTIVE ONE. THE CHARACTER IS GONE. There is no undo, no grace period, and no second confirmation on the wire - the moment this is sent the decision is made.
If you are writing automation, the honest answer is that THIS MESSAGE HAS NO LEGITIMATE AUTOMATED USE. Deleting a character is a decision a person makes once; put it behind a human, not behind a script.
secret_answer_hash IS NEVER THE PLAINTEXT ANSWER. The client sends the lowercase hex MD5 of the UTF-8 bytes of:
<character_id>~<secret_answer> with a literal tilde between them. The separator, the digest and the hex casing were all read out of the client rather than assumed. Send the plaintext and it will not match; hash without the id prefix and it will not match either.
Whether the hash is required at all comes from CharacterDeletionPrepareEvent.need_secret_answer. Read that first.
Two builds declare a second int64 beside character_id; the named one is the one the hashing writer actually stores.
When you may send it
Requires authenticated observed Related messages
Answers CharacterDeletionPrepareEvent Reply not yet recovered: the character list is re-sent afterwards; the deletion's own acknowledgement has no signature here yet. Sequence
Step character_deletion.3 inferred — of 3 steps; the flow is a fixed ask / terms / confirm exchange
If you get it wrong
the hash must be MD5 of <character_id>~<secret_answer>; sending the plaintext answer, or hashing without the id prefix, produces a value that cannot match inferred Fields
#FieldTypeMeaningYou set it 1secret_answer_hashstringLowercase hex MD5 of the UTF-8 string <character_id>~<secret_answer>.
NEVER the plaintext answer.
The tilde separator, the digest algorithm and the hex casing were all read out of the client.required when the prepare event asked for it 2character_idint64The character to destroy. (character id)
Also the prefix of the hashed string - the two must agree.required
  • summary: Destroys a character. This is irreversible and there is no further confirmation exchange.
  • area: Game.Character
  • 109 vues
Enters the game with a character for the first time, and asks for the tutorial.
Kind request · Area Game.Character.Management
USE THIS FOR A CHARACTER YOU JUST CREATED, and CharacterSelectionRequest for one you have already played. Both enter the game with a character; this one additionally tells the server to run the tutorial.
WHEN TO SEND IT
WHEN YOU VALIDATE A CHARACTER THAT HAS NEVER BEEN PLAYED. In the real client both messages come from the same screen action - validating your choice on the character-selection screen - and the screen decides which of them applies from a first-selection flag it raises with the character id. You are choosing between them on the same signal it uses.
SENDING THE WRONG ONE IS NOT A NO-OP. Send this for an existing character and you are asking the server to run the tutorial flow for someone who has already played. Send the ordinary one for a fresh character and you skip the tutorial the server would have set up.
DO_TUTORIAL IS ALWAYS TRUE IN THE REAL CLIENT. It writes a hardcoded true into that member on every dumped build - it is never a player choice. False is a legal wire value that no client has ever sent, so treat it as untested.
THE THIRD BRANCH. The same screen action has one more outcome, CharacterReplayRequest, for a character in a state that needs replaying rather than selecting. If you are implementing the screen, all three come from one place.
WHAT COMES BACK
The ordinary game-entry sequence, exactly as for CharacterSelectionRequest - there is no dedicated reply to this message. It is uncorrelated, so its envelope uid is -1 and there is nothing to match against.
READ THE MEMBERS BY ROLE. Both have moved field number across builds, and some builds pad the message with a second bool beside the real one.
When you may send it
Requires authenticated observed Raised by: a client-side state change: the player validating their character choice on the selection screen for a character that has not been played yet. The screen raises one intent carrying the character id and a first-selection flag, and the selection dispatcher turns the flag into this message instead of the ordinary one inferred Related messages
Reply not yet recovered: the game-entry burst follows, the same as for an ordinary selection. Those messages are recovered but not documented yet. Fields
#FieldTypeMeaningYou set it 1character_idint64The character to enter with.required 3do_tutorialboolWhether to run the tutorial. The client always sends true here.required
  • summary: Enters the game with a character for the first time, and asks for the tutorial.
  • area: Game.Character.Management
  • 94 vues
Asks for the account's characters on this server.
Kind request · Area Game.Character.Management
Carries no payload. Send it once, straight after authentication is accepted - in a capture it goes out ~35ms after AuthenticationTicketAcceptedEvent.
NOTHING PUSHES THE CHARACTER LIST. If you never send this you never learn what characters exist, and you cannot select one, because the id required by CharacterSelectionRequest is only obtainable from the answer.
When you may send it
Requires authenticated observed Forbidden while character_selected observed Related messages
Answers AuthenticationTicketAcceptedEvent You will then receive CharacterListEvent observed — the server answers with the list ~30ms later
  • summary: Asks for the account's characters on this server.
  • area: Game.Character.Management
  • 114 vues
Asks the server to propose a character name. Empty payload.
Kind request · Area Game.Character
Carries nothing - it is a pure "give me a name".
Any field the current build declares here is unused by the client and is left unresolved; send it empty.
One request yields one suggestion. Asking repeatedly to fish for a name you like is a traffic pattern a human clicking a button does not produce at machine speed.
When you may send it
Requires authenticated observed Raised by: the player asks the creation screen for a name suggestion inferred Related messages
You will then receive CharacterNameSuggestionEvent inferred — the server answers with one proposed name
  • summary: Asks the server to propose a character name. Empty payload.
  • area: Game.Character
  • 96 vues
Enters the game with a character as a replay rather than an ordinary selection.
Kind request · Area Game.Character.Management
THE THIRD WAY INTO THE GAME. CharacterSelectionRequest enters with a character you have played, CharacterFirstSelectionRequest with one you just created, and this one with a character the client resolves to a replay instead.
WHEN TO SEND IT
FROM THE SAME SCREEN ACTION AS THE OTHER TWO. All three come out of one method in the real client, chosen by two flags the character-selection screen passes with the character id: no flags means the ordinary selection, one means first selection, the other means this. The replay path is raised from a closure inside the screen's own choose-a-character handler, so it is a decision the screen makes about the character you picked, not a separate menu.
IF YOU ARE SCRIPTING SELECTION, the safe default is CharacterSelectionRequest. Reach for this one only when you are reproducing a client that resolved the character to the replay path; there is no server-side signal in this exchange telling you that you should have.
WHAT TO PUT IN IT
THE CHARACTER ID - AND ON SOME BUILDS THE REAL CLIENT SENDS NOTHING AT ALL. That is not a guess: on three of the seven dumped builds the client allocates this message, populates no member, and sends it. On the other four it writes the character id. The member is therefore recovered where the client proves it and left unnamed where it does not.
The practical reading: send the character id. It is what the message is for according to the reference build, and what the more recent clients do.
WHAT COMES BACK
The ordinary game-entry sequence - there is no dedicated reply. Uncorrelated, so the envelope uid is -1 and there is nothing to match against.
When you may send it
Requires authenticated observed Raised by: a client-side state change: the character-selection screen resolving a chosen character to the replay path rather than an ordinary selection. A closure inside the same screen method that handles an ordinary choice raises an intent carrying only the character id inferred Related messages
Reply not yet recovered: the game-entry burst follows, the same as for an ordinary selection. Those messages are recovered but not documented yet. No fields you may set.
  • summary: Enters the game with a character as a replay rather than an ordinary selection.
  • area: Game.Character.Management
  • 98 vues
Asks to enter the world with one of the account's characters.
Kind request · Area Game.Character.Management
Sent after reading CharacterListEvent. The id MUST come from that list.
The real client also sends it automatically for the first listed character when the player has enabled auto-selection, so a capture may show it without any visible interaction.
SELECTING WITHIN A FEW MILLISECONDS OF RECEIVING THE LIST IS FASTER THAN ANY HUMAN. In a capture of a real sign-in the gap is about two seconds - the time a person takes to look at the screen and click. Add a plausible delay.
On success the server starts the session and pushes a long burst of character state, ending with CharacterLoadingCompleteEvent.
When you may send it
Requires authenticated observed Forbidden while character_selected observed Raised by: the player picking a character from the list proven Related messages
You will then receive CharacterSelectionEvent observed — the server answers with success or an error You will then receive CharacterLoadingCompleteEvent observed — closes the long inbound burst the selection opens; 1 of 1 login capture Fields
#FieldTypeMeaningYou set it 1character_idint64Id of the character to play, taken from CharacterListEvent. (character id)required
  • summary: Asks to enter the world with one of the account's characters.
  • area: Game.Character.Management
  • 123 vues
Says something on a chat channel. This is the message a script sends to talk.
Kind request · Area Game.Chat
Talk on a channel. The server echoes your own line back as ChatChannelMessageEvent, so do not render it locally - wait for the echo, as the client does.
channel DECIDES WHO HEARS YOU AND IT IS EASY TO GET WRONG. It has no explicit presence, so leaving it unset does not mean "default channel" in any safe sense: it means the enum's zero value, which is Channel.GLOBAL - the loudest channel in the game. Set it deliberately every time.
TO WHISPER ONE PERSON, THIS IS THE WRONG MESSAGE. Use ChatPrivateMessageRequest.
metadata carries rich attachments - item and monster-group links - and stays present but empty for an ordinary line. The visible words always go in content; the link data rides alongside so the recipient's client can render and hover it. To link an item, put {chatitem,<uid>,<gid>} in content and the item in Metadata.objects; for a monster group, use Metadata.monster_groups.
Leave every other member unset. The request also declares an optional int32 that no client code sets (3.7.12.12: hay.bncc sets content, channel and metadata, fzq.mac sets only content, and nothing calls that member's setter or stores it), and a captured request never carries it.
Chat is the most visible thing a script does. Rate, timing and repetition here are what a human moderator looks at first.
When you may send it
Requires character_loaded observed Raised by: the player types a line in the chat window and presses enter observed Related messages
You will receive one of ChatChannelMessageEvent observed — the server echoes the line back to the sender as well as to everyone else on the channel You will receive one of ChatErrorEvent inferred — instead of the echo when the server refuses the line (unknown recipient, channel unavailable, ...) Fields
#FieldTypeMeaningYou set it 2channelChannelWhich channel to say it on.
A Channel value.
NO EXPLICIT PRESENCE: unset means the zero value, Channel.GLOBAL, not 'unspecified'.required 3contentstringThe text being said.
The only string the message carries.required 4metadataMetadataRich content attached to the line - item and monster-group links.
Present but empty for an ordinary text message. See Metadata.
Name ours, after its type Metadata: beta has no such field and no build names it.optional
  • summary: Says something on a chat channel. This is the message a script sends to talk.
  • area: Game.Chat
  • 110 vues
Sends a private message to one player, addressed either by character name or by account tag.
Kind request · Area Game.Chat
Talks to one player rather than a channel.
THE RECIPIENT IS A ONEOF - SET EXACTLY ONE BRANCH. name addresses a CHARACTER by its displayed name; tag addresses an ACCOUNT by its tag, which is a name plus a numeric discriminator and reaches the person whichever character they are playing. Setting neither sends a whisper to nobody; the message is not rejected for it.
content is the text. It is the singular string that is NOT inside the oneof - worth saying, because the name branch is also a string.
metadata carries the same rich attachments as a channel line; see Metadata.
UNSOLICITED WHISPERS ARE THE FASTEST WAY TO GET A SCRIPT REPORTED. Whatever you do here is read by a human on the other end.
When you may send it
Requires character_loaded observed Raised by: the player sends a private message from the chat window observed Related messages
You will receive one of ChatPrivateCopyMessageEvent inferred — the server echoes the whisper back to the sender with the recipient's name and id; the client prints it as your side of the conversation You will receive one of ChatErrorEvent inferred — instead of the echo when the server refuses the line (unknown recipient, channel unavailable, ...) Fields
#FieldTypeMeaningYou set it 1metadataMetadataRich content attached to the whisper.
See Metadata. Beta called this field object.
Name ours, after its type Metadata: beta has no such field and no build names it.optional 2contentstringThe text to whisper.
The singular string outside the target oneof.required 3tagAccountTagThe recipient, addressed by account tag - a name plus its numeric discriminator.
Reaches the account rather than one character.one of the two target branches 5namestringThe recipient, addressed by character name.one of the two target branches
  • summary: Sends a private message to one player, addressed either by character name or by account tag.
  • area: Game.Chat
  • 90 vues
Publishes the client's long-lived public key, opening the session half of the proof-of-identity handshake.
Kind request · Area Game.Client.Verification
Answers ServerSessionReadyEvent. It carries your PUBLIC KEY - the value the server will check your proof against.
WHEN TO SEND IT
IMMEDIATELY ON ServerSessionReadyEvent, once, unconditionally. One construction site, no timer, no other path. That event closes the burst that follows a successful IdentificationRequest, so in practice this is the first thing you send once the session exists.
WHAT TO PUT IN IT
x = your private exponent, drawn ONCE at start-up challenge_key = decimal string of G^x mod P P and G are not secret, not negotiated and not per-session: the client hard-codes the RFC 2409 768-bit MODP group - "Oakley group 1" - which is a published constant, with G = 2 and Q = (P - 1) / 2. The whole handshake lives in that one group.
x IS PER-PROCESS, NOT PER-CONNECTION. The real client draws it once, when its verification service starts, and keeps it for the life of the process: 1024 random bytes read as a LITTLE-endian unsigned integer, then reduced modulo P. Every connection that process makes publishes the SAME challenge_key. Redrawing it per connection is not what the client does, and it is a difference a server can see across reconnects.
x IS THE SECRET THE WHOLE EXCHANGE PROTECTS. It never travels. Anyone who learns it can answer any challenge in your name, so treat it like a password rather than like a session value.
DO NOT CONFUSE IT WITH THE OTHER EXPONENT. ClientIdRequest publishes G^k for a throwaway k that changes on every poll; this one publishes G^x for the long-lived x. Both are decimal strings in the same group and they look identical on the wire. Sending the wrong one makes the proof fail with no useful error.
IT IS A CORRELATED REQUEST: the client allocates an envelope uid for it. Do not read too much into that - when ServerChallengeEvent comes back the client matches it by message type and never looks at the uid.
The server answers with ServerChallengeEvent, which you close with ClientChallengeProofRequest.
IT STAYS ON THE MAIN CONNECTION. While a fight-server transfer has a second socket open (see IdentificationRequest) the client routes outbound traffic by message type, and all three verification requests are pinned to the FIRST connection. Gameplay traffic is what moves to the fight server, not this.
THE COMPLETE ALGORITHM IS ON ONE PAGE. Constants, both exponents, both branches, what the server checks and the ways an implementation goes wrong are written out in full under ClientChallengeProofRequest. Read that before implementing any part of this exchange.
When you may send it
Requires authenticated observed Related messages
Answers ServerSessionReadyEvent You will then receive ServerChallengeEvent observed — the server answers the init with its own challenge Fields
#FieldTypeMeaningYou set it 1challenge_keystringDecimal string of G^x mod P - the client's public key for the proof exchange.
x is drawn once per process, not per connection, so this value is stable across every connection the same client makes.required
  • summary: Publishes the client's long-lived public key, opening the session half of the proof-of-identity handshake.
  • area: Game.Client.Verification
  • 121 vues
Closes the proof-of-identity handshake by answering the server's challenge with a Schnorr response.
Kind request · Area Game.Client.Verification
Answers ServerChallengeEvent and ends the three-step exchange opened by ClientIdRequest and ClientChallengeInitRequest.
WHEN TO SEND IT
IMMEDIATELY ON ServerChallengeEvent, once, unconditionally. One construction site and no other path.
THE WHOLE SCHEME, END TO END
This is the one page that carries the complete algorithm. It is a Schnorr proof of identity, and everything below is read out of the client rather than guessed:
CONSTANTS the client hard-codes one group and never negotiates it P the RFC 2409 section 6.1 prime, 768-bit MODP, "Oakley group 1" G 2 Q (P - 1) / 2 SECRETS neither ever travels x int(1024 random bytes, unsigned, LITTLE-endian) mod P drawn ONCE per process, kept for its whole life k int( 50 random bytes, unsigned, LITTLE-endian) drawn afresh for every verification poll THE FOUR STEPS 1 ServerVerificationEvent -> ClientIdRequest id = decimal string of G^k mod P (commitment R) 2 ServerSessionReadyEvent -> ClientChallengeInitRequest challenge_key = decimal string of G^x mod P (public key A) 3 ServerChallengeEvent carries c, a decimal string 4 this message proof = decimal string of (k + c*x) mod Q and if that came out negative, add Q back WHAT THE SERVER CHECKS
It recomputes G^proof mod P and compares it with (id * challenge_key^c) mod P. Those agree exactly when you knew both secrets, which is the entire point of the exchange. The arithmetic works because 2 generates the order-Q subgroup of that prime. If you skipped either earlier message there is nothing to compare against, and no amount of guessing here will pass.
FOUR WAYS TO GET THIS WRONG, ALL OF THEM SILENT
Each of these produces a well-formed message that simply fails, with no error you can see and nothing in the traffic to tell you which one you hit.
ENDIANNESS. Both random values are read LITTLE-endian and unsigned. Most big-integer libraries default to big-endian, and the number you get is completely different.
DECIMAL, NOT HEX. Every value on the wire is a base-10 string. There is no hex, no base64 and no binary anywhere in this exchange.
P VERSUS Q. The two exponentiations reduce modulo P; the proof reduces modulo Q. Swapping them is easy and fatal.
THE SIGN. The client reduces modulo Q and then adds Q back if the result came out negative. Languages disagree about the sign of a remainder, so normalise explicitly rather than trusting your own operator.
IF THE CHALLENGE IS ABSENT, YOU ANSWER YOURSELF
The challenge field has explicit presence, and the client checks whether it is there. If the event arrives with NO value, the client does not skip the reply and does not error - it derives its own challenge and answers anyway:
c = SHA-256 of the decimal strings of G, G^x mod P and G^k mod P, concatenated with the client's device fingerprint, and read back as a big-endian integer proof = (k + c*x) mod Q, forced non-negative, exactly as above THAT BRANCH SIGNS A MACHINE IDENTIFIER. The device fingerprint is the uppercase hex SHA-256 of the machine's unique device id concatenated with the MAC addresses of every network interface. So two machines answering the same value-less event produce different proofs, and the same fingerprint is also sent during login on the separate connection-server exchange. If you are reproducing the client's behaviour you have to reproduce this too, and if you are not, be aware of what it identifies.
THE NUMBERING GAP IS PADDING. This message also declares a six-value enum that no dumped build ever writes; proto3 leaves a zero-valued enum off the wire entirely. There is nothing for you to set there.
IT IS A CORRELATED REQUEST, like the other two steps.
WHAT IS READ AND WHAT IS INFERRED
The constants, the byte counts, both formulas and the value-less branch are read out of the client's own code, and the same structure is present in every dumped build. Two things are NOT: the verification equation above is what the server must be doing for this arithmetic to mean anything, but nothing in a client dump can see the server; and no capture has been observed of a challenge arriving without a value, so that branch is code that certainly exists rather than behaviour that has certainly been seen.
THIS IS AN ANTI-TAMPER HANDSHAKE, NOT A SECURITY BOUNDARY. A 768-bit MODP group has been below recommended strength for many years, and nothing here is encrypted - the exchange proves that whoever is talking held a key across three messages, and that is all it proves. Do not read more assurance into it than that, in either direction.
IT STAYS ON THE MAIN CONNECTION. While a fight-server transfer has a second socket open (see IdentificationRequest) the client routes outbound traffic by message type, and all three verification requests are pinned to the FIRST connection. Gameplay traffic is what moves to the fight server, not this.
When you may send it
Requires authenticated observed Related messages
Answers ServerChallengeEvent Fields
#FieldTypeMeaningYou set it 1proofstringDecimal string of (k + c*x) mod Q, normalised non-negative.
k is the nonce from ClientIdRequest, x the private exponent behind ClientChallengeInitRequest, c the server's challenge, Q = (P-1)/2 for the RFC 2409 768-bit group.
When the challenge arrives with no value the client hashes its own, including a device fingerprint - see the description.required
  • summary: Closes the proof-of-identity handshake by answering the server's challenge with a Schnorr response.
  • area: Game.Client.Verification
  • 119 vues
Answers the server's verification poll with a fresh cryptographic commitment - step 1 of a three-step proof of identity.
Kind request · Area Game.Client.Verification
Answers ServerVerificationEvent. It opens a three-step proof that you hold a private key, and the value it carries is a COMMITMENT - not an identifier, not something you own, and not something you can look up.
WHEN TO SEND IT
IMMEDIATELY, ONCE PER POLL, AND FROM NOWHERE ELSE. The client builds it in exactly one place - the handler for the poll - and answers unconditionally. It reads NOTHING out of the poll; the event's arrival is the entire instruction.
IT COMES EARLY. The poll can arrive on the bare connection, before the ticket exchange has finished, so this is one of the first things you ever send. Do not gate it on being logged in.
WHAT TO PUT IN IT
k = a fresh 400-bit random integer (50 random bytes, read little-endian) id = decimal string of G^k mod P P and G are not secret, not negotiated and not per-session: the client hard-codes the RFC 2409 768-bit MODP group - "Oakley group 1" - which is a published constant, with G = 2 and Q = (P - 1) / 2. The whole handshake lives in that one group.
KEEP k. IT IS THE POINT OF THIS MESSAGE. Only G^k travels; k itself never does, and ClientChallengeProofRequest cannot be computed without it. Generate it here, store it, and use that exact value later.
NEVER REUSE k. A Schnorr nonce answered against two different challenges leaks the private key by simple arithmetic - this is the classic way these schemes are broken. The real client draws a new one on every poll and overwrites the old, so a second poll silently invalidates any proof you had not yet sent. Recompute, do not cache.
USE A REAL RANDOM SOURCE. The client uses a cryptographic generator. A predictable k is as bad as a reused one.
IT IS A CORRELATED REQUEST. The client allocates an envelope uid for it, which most of the protocol does not - all three messages of this handshake do.
The value is derived, never stored: it differs on every poll and on every run.
IT STAYS ON THE MAIN CONNECTION. While a fight-server transfer has a second socket open (see IdentificationRequest) the client routes outbound traffic by message type, and all three verification requests are pinned to the FIRST connection. Gameplay traffic is what moves to the fight server, not this.
THE COMPLETE ALGORITHM IS ON ONE PAGE. Constants, both exponents, both branches, what the server checks and the ways an implementation goes wrong are written out in full under ClientChallengeProofRequest. Read that before implementing any part of this exchange.
When you may send it
Requires transport_established observed Related messages
Answers ServerVerificationEvent Fields
#FieldTypeMeaningYou set it 1idstringDecimal string of G^k mod P - a commitment to a fresh secret, not an identity.
k is 50 random bytes read as a little-endian unsigned integer. Keep it: ClientChallengeProofRequest needs it and it never travels.required; recomputed on every poll, never reused
  • summary: Answers the server's verification poll with a fresh cryptographic commitment - step 1 of a three-step proof of identity.
  • area: Game.Client.Verification
  • 119 vues
Turns on or off the notification shown when a friend, guild member or nearby character unlocks an achievement.
Kind request · Area Game.Social
One of the social "warn me when..." toggles the client mirrors to the server. THE SERVER HAS TO BE TOLD because it is the side that decides whether to push the notification; the client cannot honour the setting locally.
IT IS SENT IMMEDIATELY ON EVERY FLIP, WITH NO DEBOUNCE. The option lives in Options -> General, in the Social block. Flipping it publishes a one-boolean event that a writer turns straight into this message. A script that toggles this in a loop produces a burst of requests that no human interaction could.
SEND IT ONLY WHEN THE SETTING ACTUALLY CHANGES. It is a persisted client option replayed verbatim, not a query and not a subscription.
When you may send it
Requires character_loaded observed Raised by: the player flips the toggle in Options -> General, Social block proven Related messages
Nothing answers it - send it and move on it mirrors a stored client option to the server; no dumped build has a matching acknowledgement message Fields
#FieldTypeMeaningYou set it 1enableboolTrue to receive the achievement notification for friends, guild members and characters on the current map; false to suppress it.
The persisted client option, replayed verbatim.required
  • summary: Turns on or off the notification shown when a friend, guild member or nearby character unlocks an achievement.
  • area: Game.Social
  • 84 vues
Turns on or off the notification shown when a contact dies permanently on an epic server.
Kind request · Area Game.Social
One of the social "warn me when..." toggles the client mirrors to the server. THE SERVER HAS TO BE TOLD because it is the side that decides whether to push the notification; the client cannot honour the setting locally.
IT IS SENT IMMEDIATELY ON EVERY FLIP, WITH NO DEBOUNCE. The option lives in Options -> General, in the Social block. Flipping it publishes a one-boolean event that a writer turns straight into this message. A script that toggles this in a loop produces a burst of requests that no human interaction could.
SEND IT ONLY WHEN THE SETTING ACTUALLY CHANGES. It is a persisted client option replayed verbatim, not a query and not a subscription.
It only means anything on a server with permanent death - see ServerType.EPIC.
When you may send it
Requires character_loaded observed Raised by: the player flips the toggle in Options -> General, Social block proven Related messages
Nothing answers it - send it and move on it mirrors a stored client option to the server; no dumped build has a matching acknowledgement message Fields
#FieldTypeMeaningYou set it 1enableboolTrue to be notified when a friend, guild member or character on the current map dies permanently; false to suppress it.
The persisted client option, replayed verbatim.required
  • summary: Turns on or off the notification shown when a contact dies permanently on an epic server.
  • area: Game.Social
  • 83 vues
Asks the server to create the character's game context. Sent once per game entry, not once per map.
Kind request · Area Game.Context
THIS IS THE STEP THAT PUTS YOU IN THE WORLD. Before it, the server knows who you are and which character you picked, but you have no map, no entities and no context. After it, everything gated on a game context becomes legal. It carries no payload - the message IS the ask.
WHEN TO SEND IT
ONCE PER GAME ENTRY. NOT ONCE PER MAP. This is the single most expensive mistake you can make with this message. Map changes, teleports, zaaps and fight transitions do NOT re-create the context and the real client does not re-send this - what it re-sends on every map is ContextReadyRequest and MapInformationRequest. The client has exactly two places that build this message, and neither of them is on the map-change path.
PATH 1 - ENTERING THE GAME. The chain starts at a successful CharacterSelectionEvent and runs entirely inside the client:
CharacterSelectionEvent (success) -> the client starts its enter-game routine -> it shows the loading screen and WAITS ONE FULL SECOND -> it loads the character-selection-to-game data set -> it waits for the account options to be loaded -> it switches on the first batch of gameplay services -> ContextCreationRequest <-- here -> it switches on the rest of the gameplay services So the honest rule is: send it after the selection succeeded, and after a delay. A capture shows it about 1.4 seconds behind the character finishing loading, and the one-second wait above is a literal constant in the client, not jitter. Firing it in the same millisecond as the selection result is a timing no real client produces.
CharacterLoadingCompleteEvent arrives during that window, which is why a capture makes it look like the cue. On this path it is not: the client does not key on it. It is still a good practical checkpoint, because it always lands before the request does.
PATH 2 - ARRIVING ON A FIGHT SERVER. When the client is handed over to an arena server it opens a SECOND game connection beside the first (see IdentificationRequest), and on that connection the rule is different: the moment CharacterLoadingCompleteEvent arrives there, the client sends this request immediately, with no delay and no gate. The check is on which socket the event arrived on - the same event on the ordinary game connection does nothing.
So: once when you enter the world, and once more per fight-server hand-over, on the new socket.
WHAT COMES BACK
About 30ms later the server pushes a context-creation event carrying the context kind (roleplay or fight), followed by the map and character state. Only then is anything gated on a game context legal. Nothing about this exchange is correlated: the request goes out on the plain send path, so its envelope uid is -1 and there is no response to match against it. Watch for the inbound burst, not for a reply.
THE CONTEXT IS NOT PERMANENT. The server tears it down and rebuilds it during the session - entering and leaving a fight is the obvious case - and it does so on its own initiative, by pushing destroy and create events. Treat the context as a state the server owns and announces, not as a latch you set once. What you must not do is try to drive those rebuilds yourself by re-sending this request.
When you may send it
Requires character_loaded observed Raised by: a client-side state change: the enter-game routine reaching its network step. That routine is started by a successful CharacterSelectionEvent, then waits a fixed one second, loads the character-selection-to-game data set, and only sends once the account options are loaded - so it lands roughly 1-1.5s after the selection result, never immediately. The fight-server transfer has its own second path inferred State it changes
Establishes context_ready observed — the server answers with the map and character state that world messages depend on Related messages
You will then receive ContextCreationEvent observed — about 30ms later, as the first message of the burst that answers this request, naming the roleplay context You will receive one of MapCurrentEvent inferred — the same burst carries the map state, and the map the character stands on is announced by that message You will receive one of MapCurrentInstanceEvent inferred — the map announcement in its instanced form, for a character entering the world on an instanced map; the client routes it into the same map-loading routine. Not observed Reply not yet recovered: the character-state messages of the same burst are not linked here. No fields you may set.
  • summary: Asks the server to create the character's game context. Sent once per game entry, not once per map.
  • area: Game.Context
  • 122 vues
Tells the server the client has finished loading a map and is ready to play in it. Once per map, every map.
Kind request · Area Game.Context
THE SERVER GATES THE WORLD ON THIS. Until it arrives your character is loaded but not live: actors do not move for you, interactive elements do not respond, and the map's contents are not sent. It is the second half of being on a map, and the half you have to do yourself.
WHEN TO SEND IT
ONCE PER MAP LOAD, EVERY MAP LOAD. This is not a session handshake and it is not the same kind of thing as ContextCreationRequest, which you send once for the whole session. This one fires again on every teleport, every zaap, every map change and every fight transition, for as long as you are connected.
THE CUE IS YOUR OWN LOADING, NOT THE SERVER'S MESSAGE. The client does not send this when the map data arrives on the wire; it sends it when its map renderer picks up the loaded map asset and announces it internally. Everything that cares about "a new map is here" hangs off that one announcement - the grid generator, the interactive-cell manager, several gameplay services, and two outbound requests:
map asset finished loading -> ContextReadyRequest (this message) -> MapInformationRequest -> the client's own map-dependent services wake up That is why MapInformationRequest and this message go out together, in the same millisecond in a capture. They are two subscribers to one event, not a sequence. For a script the practical translation is: whatever you treat as "I have the map now", send both from that same point.
WHAT TO PUT IN IT
SEND THE ID YOU WERE JUST GIVEN, NOT ONE YOU REMEMBER. The client copies the map id off the notification that carries the freshly loaded map and writes it unmodified. It never consults a cached "current map", and that matters: during a transition your idea of the current map and the map that just finished loading are different for a while.
WHAT COMES BACK
The map's contents: actors, interactive elements, stated elements. There is no Response and nothing acknowledges the request itself - the traffic that follows IS the answer. The envelope is uncorrelated, so its uid goes out as -1; do not allocate one and do not wait to match anything against it.
IF YOU NEVER SEND IT you stay connected, the connection looks healthy, and nothing arrives. That silence is the symptom.
ON THE WIRE, THE CAUSE IS MapCurrentEvent - or its instanced form MapCurrentInstanceEvent, which the client feeds into the same map load. The map load this request follows is started by that message: the client's map service receives it, the map renderer loads the map it names, and the loaded-map notification this request hangs off is raised at the end of that load. A script that loads nothing should send this right after either message, with its map id.
When you may send it
Requires context_ready observed Raised by: a client-side state change: the client's own map-loaded notification, published by the map renderer the moment it starts handling a freshly loaded map asset. It fires once per map load - every teleport, zaap, map change and fight transition - and the writer copies the id straight off that notification proven Related messages
Answers MapCurrentEvent Answers MapCurrentInstanceEvent Reply not yet recovered: the map's contents arrive immediately: actors, interactive elements and stated elements. Those messages are recovered but not documented yet. Fields
#FieldTypeMeaningYou set it 1map_idint64The map that just finished loading on the client. (map id)
Take it from the load you are reporting, not from a cached "current map" - the client copies it unmodified off its own map-loaded notification, and during a transition the two are not the same value.required
  • summary: Tells the server the client has finished loading a map and is ready to play in it. Once per map, every map.
  • area: Game.Context
  • 118 vues
Closes whatever dialog you are in. No payload - the server knows which one.
Kind request · Area Game.Dialog
CARRIES NOTHING, AND DOES NOT NEED TO. There is one dialog open at a time and the server knows which; you are saying "I am done with it", not naming it.
WHEN TO SEND IT
WHEN THE DIALOG WINDOW GOES AWAY - and that is a wider condition than "the player clicked close". In the real client most of these windows raise the leave intent from Unity's OnDisable hook, which runs however the window disappeared: the bank, the exchange, the NPC shop, the auction house and the craft window all do exactly that. A few add explicit paths on top - the zaap picker also raises it from its close button AND its Esc shortcut, the house window from its own CloseWindow, the NPC dialogue from its close handler and from the reply that ends the conversation rather than continuing it.
So the honest rule for a script is not "send it when I press close", it is SEND IT WHEN YOU STOP BEING IN THE DIALOG, whatever ended it on your side.
ONE PER CLOSE. Fourteen different windows raise the same intent and several services listen for it, but only the service of the feature you are actually in is subscribed at the time, so exactly one request goes out. Do not send one per window you think might be open.
NOTHING GATES IT. The handlers do no checking at all - they construct the empty message and hand it to the connection. If you reach the condition, it goes.
WHEN NOT TO SEND IT
DO NOT ANSWER DialogLeaveEvent WITH THIS. This is the one that will bite you. When the SERVER closes the dialog - you walked away, the NPC ended it, it timed out - it announces the close, and the natural-looking reaction is to confirm with a leave request. The real client cannot do that, and it is not an accident: on that event the feature's service disables itself FIRST and only then asks the UI to close, so by the time the window's OnDisable fires there is nobody subscribed to raise the intent. The close the server caused produces no request.
Echoing it means asking the server to close a dialog that is already gone.
DO NOT SEND IT WHEN NO DIALOG IS OPEN. Nothing in the client does, and there is nothing to close.
WHAT COMES BACK
DialogLeaveEvent, carrying the DialogType that closed - but read that record before you rely on it. It is a broadcast, not a receipt: the same message arrives when the server closes a dialog on its own, so a script that blocks waiting for "my" answer can be woken by someone else's.
IT IS UNCORRELATED. Envelope uid -1, nothing to match. If you need to know your dialog is gone, key on the TYPE in the event, not on the timing.
THE DECLARED MEMBER IS PADDING. Some builds give this message a field. No client has ever written it, and neither should you.
When you may send it
Requires context_ready observed Raised by: a client-side state change: the dialog's window going away. For most windows the intent is raised from Unity's OnDisable hook, so it fires however the window disappeared; the zaap picker adds an explicit close button and an Esc shortcut, and the NPC dialogue adds its close path and the reply that ends the conversation. Only the active feature's service is subscribed, so one close produces exactly one request inferred Related messages
You will then receive DialogLeaveEvent observed — the server answers by announcing which dialog closed No fields you may set.
  • summary: Closes whatever dialog you are in. No payload - the server knows which one.
  • area: Game.Dialog
  • 102 vues
The measurement of the file the server asked about, returned with the algorithm it asked for.
Kind request · Area Game.Client.Verification
The answer to FileCheckEvent. It carries the measurement as a STRING - a decimal byte count or a checksum, depending on which CheckType the challenge selected - and the same check type echoed back.
COPY THE CHECK TYPE THROUGH UNCHANGED. The client does exactly that: the value from the event is written into the reply without transformation.
The current build declares a SECOND field of the same CheckType type that no writer ever populates. It is a decoy; leave it at its default. The live one is the field named here.
When you may send it
Requires authenticated observed Related messages
Answers FileCheckEvent Fields
#FieldTypeMeaningYou set it 2check_typeCheckTypeThe check type from the challenge, copied through unchanged.
A CheckType value.
The record declares a second field of this type that is never populated - leave it default.required 3valuestringThe measurement, as a string: a decimal byte length or a checksum.
Which of the two it is depends on the CheckType the challenge selected.required
  • summary: The measurement of the file the server asked about, returned with the algorithm it asked for.
  • area: Game.Client.Verification
  • 86 vues
Asks for the character's friend list. Empty payload - the server knows who is asking.
Kind request · Area Game.Social
It is one of a FIXED FOUR-REQUEST BURST the client fires once per entry into the world, straight after asking for the game context. The client's own name for the routine survives obfuscation: SendRequestAfterCharacterLoaded. The order is constant:
ContextCreationRequest (the context first) 1. FriendListRequest 2. AcquaintanceListRequest 3. SpouseInformationRequest 4. GuildInformationRequest That order is not guessed from traffic: it is the order the routine allocates the four objects in, and a live capture reproduces it exactly - the first three land inside the same millisecond, the guild request three milliseconds later.
SEND IT ONCE, AT THAT POINT. NEVER POLL IT. The trigger is "the character finished loading", not a timer.
THERE IS A SECOND TRIGGER, AND IT IS A UI ONE. The client also sends this every time the friends panel is shown - the panel's OnEnable refreshes its data, which the contact service turns into this request. A script with no friends panel has no reason to reproduce that one.
Carries nothing.
There is a name collision worth knowing about: a DIFFERENT FriendListRequest exists in the Connection protocol. This is the Game one.
When you may send it
Requires character_loaded observed Related messages
Reply not yet recovered: the friend list arrives as an event that has no signature here yet. Sequence
Step post_character_load.1 observed — of 4 requests, in the order the client's own routine allocates them
  • summary: Asks for the character's friend list. Empty payload - the server knows who is asking.
  • area: Game.Social
  • 103 vues
Turns on or off sharing your online status and activity with your contacts.
Kind request · Area Game.Social
The wire half of the client's "share my status" setting. With sharing on, your contacts see that you are connected and what you are doing; with it off you appear as not sharing.
THE SERVER HAS TO BE TOLD because it is the side that answers other players' contact-list queries - the client cannot honour this locally.
It travels the same machinery as the four warn-toggles and is sent immediately on every flip, with no debounce. Send it only when the setting actually changes.
When you may send it
Requires character_loaded observed Raised by: the player flips the status-sharing control proven Related messages
Nothing answers it - send it and move on it mirrors a stored client option to the server; no dumped build has a matching acknowledgement message Fields
#FieldTypeMeaningYou set it 1shareboolTrue to share your online status and activity with your contacts; false to withhold it.
The stored client option, copied straight through.required
  • summary: Turns on or off sharing your online status and activity with your contacts.
  • area: Game.Social
  • 86 vues

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.