Tout ce qui a été publié par Smooth
-
AlignmentInformation
The character's alignment and honour standing, carried on the character sheet. Kind structArea Game.CommonNamed by beta The alignment half of the character sheet. TWO MEMBERS THE REFERENCE BUILD DECLARED ARE GONE. It had a character id and a character level here and NO DUMPED BUILD CARRIES EITHER. That is a real schema reduction; do not go looking for them, and do not read the surviving members positionally on the assumption that they are still there. alignment is which side the character is on - see Alignment. extended_information carries honour standing and attackability, and its members are not individually recovered. Not sent on its own — it is only ever carried by CharacterCharacteristics. inferred Used by CharacterCharacteristics Fields #FieldTypeMeaningYou set it 2alignmentAlignmentWhich alignment the character belongs to. An Alignment value.never 3extended_informationtype not documented yetHonour standing and attackability. Its members are not individually recovered and stand obfuscated.never Recovered with score 160, confidence 0.79, margin 160 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 2 of 6.
-
Alignment
Which alignment a character belongs to: none, neutral, Bonta or Brakmar. Kind enumArea Game.CommonNamed by beta The five alignment values, carried by AlignmentInformation. Every dumped build declares exactly five values numbered 0 to 4 in this order, so the numbering is the real wire contract. ALIGNMENT DECIDES WHO MAY ATTACK YOU. A script that walks through contested territory should read this on other characters, not just on its own. A live capture of an ordinary character carried NEUTRAL. Not sent on its own — an enum is never sent on its own. inferred Used by AlignmentInformation Values ValueNumberMeaning UNKNOWN0Unset or unrepresentable. WITHOUT1No alignment. NEUTRAL2Neutral. This is what a live capture of an ordinary character carried. ANGEL3Aligned with Bonta. EVIL4Aligned with Brakmar. Recovered with score 125, confidence 0.83, margin 125 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 5 of 5.
-
ActorPositionInformation
One visible actor: who it is, where it stands, and what it looks like. Kind structArea Game.CommonNamed by beta, gamemapping The element of GameRolePlayShowActorsEvent, and reused by the map-complementary snapshot and by fight synchronisation - so the same record describes an actor in roleplay and in combat. actor_id IS THE HANDLE FOR EVERYTHING AFTERWARDS. Every later event that moves, turns, animates, addresses or removes this actor names it by this id. Index your world model by it. disposition is where the actor stands and faces - see EntityDisposition. actor_information carries the appearance (EntityLook) plus a oneof selecting what KIND of actor it is: a named character, a monster group, an NPC, a prism, a portal, a tax collector, or a fighter. Branch on that oneof; it is what tells a monster apart from a player. NOTHING ABOUT THE LAYOUT IS STABLE. Field numbers move in every direction across the dumped builds and the record is padded with live-looking decoys. Read by name. Not sent on its own — it travels inside the actor-list events. proven Used by GameRolePlayShowActorsEvent MapComplementaryInformationEvent Fields #FieldTypeMeaningYou set it 1actor_informationtype not documented yetThe actor's appearance and what kind of actor it is. Carries an EntityLook plus a oneof selecting a roleplay actor or a fighter - branch on it.never 2actor_idint64Server-assigned id of this actor, unique within the current context. (actor id) Every later event about this actor names it by this id.never 3dispositionEntityDispositionWhere the actor stands and which way it faces. See EntityDisposition.never Recovered with score 370, confidence 0.93, margin 370 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 3 of 3.
-
AccountRightsEvent
The account's permission flags for this session, as an opaque block of five booleans. Kind eventArea Game.AccountNamed by stringtable Pushed during account setup. You receive it, record it, and never reply - nothing in the protocol is gated on having processed it. THE FIVE FLAGS ARE NOT INDIVIDUALLY RECOVERED and are deliberately left unnamed. Every line of evidence that names things elsewhere in this catalogue fails here: the unobfuscated reference build has no account-rights type in the game protocol, the early 3.x name map has none either, and the client's handlers branch only on the BLOCK's presence, never on an individual flag. Read them positionally as opaque flags, or ignore them - see Rights. THE DECLARATION CARRIES TWO FIELDS OF THE SAME NESTED TYPE and only one is ever read. Five consumers across two services all read the same member and never touch the other, which is what makes the named one the real one. This record describes the current build. Earlier builds either lack the message or carry a different shape. When you may send it Requires authenticated observed Related messages Unsolicited - nothing you send causes this no client writer constructs it in any dumped build and there is no matching request message Fields #FieldTypeMeaningYou set it 1rightsRightsThe account's permission-flag block. See Rights. The only member any client consumer reads. The declaration carries a second field of the identical type that nothing reads.never Recovered with score 220, confidence 0.87, margin 220 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 1 of 2.
-
AccountInformationUpdateEvent
An account information update, carrying the subscription end date. Kind eventArea Game.AccountNamed by beta, gamemapping Carries the subscription end date, which the client copies straight into its player-state service. ZERO IS THE PROTOBUF DEFAULT HERE, so a zero does not distinguish "no subscription" from "the field was not sent". If your logic depends on subscription state, treat zero as unknown rather than as expired. The message carries further members that no dumped build reads; they stand with their obfuscated names. When you may send it Requires authenticated observed Related messages Unsolicited - nothing you send causes this the server pushes account state; no request asks for it Fields #FieldTypeMeaningYou set it 1subscription_end_dateint64When the account's subscription ends. Zero is the protobuf default and is indistinguishable from an absent field.never Recovered with score 131, confidence 0.98, margin 131 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 1 of 1.
-
AccountCapabilitiesEvent
What the account is allowed to do: whether it may create a character, whether the tutorial is offered, and its staff role. Kind eventArea Game.AccountNamed by beta, gamemapping Read-only session state describing what this account may do. Nothing is gated on having processed it - you record it and move on. can_create_new_character USED TO BE A BOOL AND IS NOW A THREE-STATE ENUM. Measured across the dumped builds: 3.5.3.1 bool, bool, Hierarchy 3.5.17.26 bool, bool, Hierarchy, int64 3.6.10.10 CanCreateNewCharacter, bool, Hierarchy That is a real protocol change, verified against what the client reads, not a recovery gap - which is why this record is documented for the current build and does not describe the older ones. Code written against the boolean will misread the enum: value 1 is a REFUSAL, and as a boolean it reads as true. status is the account's staff role - see Hierarchy. On an ordinary account it is the player role and stays that way. When you may send it Requires authenticated observed Related messages Unsolicited - nothing you send causes this the server pushes it during login and character selection; there is no request for it Fields #FieldTypeMeaningYou set it 1tutorial_availableboolWhether the tutorial is offered to this account.never 3statusHierarchyThe account's role in the staff hierarchy. A Hierarchy value. Ordinary accounts carry the player role.never 4can_create_new_characterCanCreateNewCharacterWhether the account may create another character, and if not, why. A CanCreateNewCharacter value. WAS A BOOL BEFORE THIS BUILD. Do not read it as one - value 1 means refused.never Recovered with score 112, confidence 0.97, margin 112 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 3 of 4.
-
YoshiRequest
The client telling the server it found a mod loader. Empty on purpose. Kind requestArea Game.Client.VerificationNamed by gamemapping THE CLIENT'S ANTI-TAMPER TELLING THE SERVER IT FOUND A MOD LOADER. It is sent ONLY on a positive detection and it carries no payload at all: the fact that it was sent IS the whole report. ========================================================================= WHAT THE CLIENT ACTUALLY LOOKS FOR ========================================================================= Everything below is decompiled from 3.6.10.10, not inferred. The scan runs against the GAME INSTALL ROOT, computed as Application.streamingAssetsPath + "/../../" CHECK 1 - LOADER DIRECTORIES. It tests whether any of these exists directly under that root, and stops at the first hit: MelonLoader BepInEx dotnet MelonLoader and BepInEx are the two mainstream Unity mod loaders; dotnet is the runtime folder they install beside themselves. CHECK 2 - MANAGED PROXY ASSEMBLIES. If no directory matched, it recursively enumerates *.dll under the same root (SearchOption.AllDirectories) and flags any file whose name without extension is one of: Core Animator2D Il2Cpp__Generated UnityEngine THIS IS THE CLEVER HALF, AND IT IS WORTH UNDERSTANDING. Dofus is an IL2CPP build: it ships ONE native GameAssembly.dll and no managed assemblies with those names. Those four files are what an IL2CPP interop layer GENERATES when someone attaches a loader to the game - the managed proxies a modder needs in order to write code against Core, UnityEngine and the generated glue. Their presence on disk is therefore evidence of tooling rather than of a modified game, and the check finds a prepared modding environment even when nothing is injected at run time. The scan is deliberately gentle: it awaits UniTask.NextFrame() between files, so it walks the tree one entry per frame rather than stalling the game. ========================================================================= WHEN IT IS SENT, AND WHEN IT IS NOT ========================================================================= Either check firing calls the same reporter, which sends this message and stops. Neither check firing sends nothing at all. A clean install is therefore SILENT - which is why this message will not appear in an ordinary capture, and why its absence carries no information. The whole routine is also gated on a configuration value read from the client's configuration service: if that value is 4 or greater the scan returns immediately without checking anything. ========================================================================= IT DELIBERATELY TELLS THE SERVER NOTHING ELSE ========================================================================= The client computes a reason internally - "detected dir" or "detected DLLs" - and then DISCARDS it. The reporter takes that string as a parameter and the async method that actually sends this message has no string field at all, so the reason never reaches the wire. So the server learns exactly one bit: this client tripped the check. It does not learn which loader, which file, or which of the two checks fired. That is consistent with the message having no members in the first place - it is not an empty message that happens to mean something, it is a deliberate one-bit signal. ========================================================================= WHERE IT SITS IN THE PROTOCOL ========================================================================= It belongs to Game.Client.Verification, and it is the ODD ONE OUT. Every other member of that area is a REPLY or a server-driven prompt: ServerVerificationEvent server obliges the client to identify itself ClientIdRequest client answers with a fresh commitment ClientChallengeInitRequest client publishes its long-lived public key ServerChallengeEvent server's challenge ClientChallengeProofRequest client's proof, closing the handshake FileCheckEvent server names a game file to measure FileCheckRequest client returns the measurement CheckType which measurement: byte length, or a checksum Those are a three-step proof-of-identity handshake plus an on-demand file-integrity probe, and every one of them is started by the server. THIS message is the only one the client raises on its own initiative, unprompted, and the only one that reports an observation rather than answering a question. ServerSessionReadyEvent shares the same generated .proto file but is documented under Game.Connection, because it belongs to the connection handshake rather than to verification. ========================================================================= IF YOU ARE WRITING A CLIENT ========================================================================= There is nothing to fill in and nothing to wait for - the send is fire-and-forget from an async void, and no client code awaits a reply. A well-behaved client never sends it. Sending it volunteers a report about yourself, so the correct behaviour for a reimplementation is simply to never emit it. Note also what it does NOT do: it does not scan process memory, does not enumerate loaded modules, and does not hash anything - it is a filesystem check and nothing more. File integrity is a separate channel, and the server drives that one through FileCheckEvent. When you may send it Requires transport_established inferred Related messages Nothing answers it - send it and move on nothing in the client waits on a reply; the send is fire-and-forget from an async void Recovered with score 140, confidence 0.85, margin 140 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 0 of 0.
-
SubscribeMultipleChannelRequest
Asserts the complete set of chat channels the character is on, as a subscribe list and an unsubscribe list. Kind requestArea Game.ChatNamed by gamemapping A COMPLETE STATE ASSERTION, NOT A DELTA. The client enumerates every channel it can map and puts each one into exactly one of the two lists. A channel you leave out of both is not "unchanged" as far as the real client's traffic shape is concerned - it simply never happens. So: build both lists from your full channel model, every time. Sending a one-element subscribe list is a shape the real client does not produce. subscribe is what you want on, unsubscribe what you want off, and together they partition the mappable channels. The roles are read from the writer's own branch polarity, not from field order. The reference build had a singular subscribe-one-channel request instead; the batch form replaced it before the earliest dumped 3.x build, so there is no unobfuscated declaration for this one. When you may send it Requires character_loaded observed Raised by: the channel set changing; the writer always walks every mappable channel, so there is no incremental form proven Related messages Reply not yet recovered: the server re-states the resulting subscriptions through ChannelUpdateEvent and ChatChannelsEnabledEvent; whether both arrive depends on what actually changed, so react to what comes rather than waiting. Fields #FieldTypeMeaningYou set it 2unsubscriberepeated ChannelThe channels the character wants off. Element type Channel. Together with subscribe this is a complete partition.required 3subscriberepeated ChannelThe channels the character wants to be on. Element type Channel.required Recovered with score 235, confidence 0.84, margin 235 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 2 of 3.
-
SpouseInformationRequest
Asks for the married partner's identity, status and map position. Kind requestArea Game.SocialNamed by beta, gamemapping 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. The client sends it unconditionally, married or not - it does not check first. Carries nothing. When you may send it Requires character_loaded observed Related messages Reply not yet recovered: the spouse information arrives as an event that has no signature here yet. Sequence Step post_character_load.3 observed — of 4 requests, in the order the client's own routine allocates them Recovered with score 175, confidence 0.92, margin 175 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 0 of 0.
-
SetCommunityChannelRequest
Tells the server which language community the character chats on. Kind requestArea Game.SocialNamed by beta, gamemapping DOFUS segregates the public chat by language, and this picks which segment you are in. It decides which community channel you read and write on - see Channel.COMMUNITY. The server answers with CommunityChannelEvent carrying the value it ACCEPTED, which is not necessarily the one you asked for. Read the answer rather than assuming. A VOLLEY OF ChannelUpdateEvent FOLLOWS IMMEDIATELY. Changing community re-states the character's channel subscriptions, so expect your channel mask to be rewritten right after. Do not race it. When you may send it Requires character_loaded observed Raised by: the player changing the chat-language control, and once on entering the world with the persisted account option. One user decision, one request; never on a timer proven Related messages You will then receive CommunityChannelEvent observed — the server states back the community it accepted, then re-states the character's channel subscriptions Fields #FieldTypeMeaningYou set it 1communityint32The community to chat on. Range: -1 to 4 -1 unset, 0 French, 1 English/international, 2 Spanish, 3 Portuguese, 4 German.required Recovered with score 165, confidence 0.88, margin 165 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 1 of 1.
-
SequenceNumberRequest
Answers the server's sequence poll with how many of those polls this connection has received. Kind requestArea Game.BasicNamed by beta, gamemapping Answers SequenceNumberEvent. One integer: a counter this connection keeps. 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, before anything else looks at the event. There is no timer and no proactive path. WHAT THE COUNTER ACTUALLY COUNTS NOT INBOUND MESSAGES. NOT EVENTS OF EVERY KIND. It counts the SequenceNumberEvent polls that have arrived on THIS connection, and nothing else touches it. The whole rule is two lines: when the socket becomes active: n = 0 when a poll arrives: n = n + 1, then reply with n Three consequences, all of them visible to the server: IT RESTARTS AT EVERY RECONNECTION. The reset is bound to the socket becoming active, not to logging in, so a reconnect starts again from zero. Carrying a count across connections is wrong. THE FIRST REPLY CARRIES 1, NEVER 0. The counter is incremented before the reply is built. EACH CONNECTION HAS ITS OWN. If you hold two game sockets at once (see IdentificationRequest), each counts its own polls independently. There is no shared total. A bot that hard-codes a constant, counts the wrong thing, restarts mid-connection or carries the number across a reconnect is producing traffic no real client produces - and this is the one number in the exchange the server can recompute exactly, because it sent every poll itself. THIS COUNTER IS NOT THE ENVELOPE UID They are different numbers living in different places, and confusing them is the easy mistake here. The counter is the payload. The uid is transport-level - and for this particular message the client does not allocate one at all: it writes the reply straight down the connection rather than through the normal request path, so the envelope goes out with the uid set to -1. BasicLatencyStatsRequest, answering the poll that arrives in the same frame, does carry a real uid. Two replies to one frame, two different envelope shapes. When you may send it Requires authenticated observed Related messages Answers SequenceNumberEvent Fields #FieldTypeMeaningYou set it 1numberint32How many sequence polls this connection has received, counting the one being answered. (poll count) Range: starts at 1 on each new connection and increases by one per poll It counts THESE polls only, not inbound messages in general, and it is reset when the socket becomes active rather than when you log in.required Recovered with score 85, confidence 0.95, margin 85 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 1 of 1.
-
ReloginRequest
Asks for a one-shot token that lets the next connection skip full authentication. Empty - the message is the ask. Kind requestArea Game.ConnectionNamed by beta, gamemapping CARRIES NO PAYLOAD. There is nothing to fill in - constructing it and sending it IS the request. Send it BEFORE you hand this connection over, then read ReloginTokenEvent. WHEN TO SEND IT WHEN YOU ARE ABOUT TO LEAVE THIS GAME SERVER, and not otherwise. In the real client every path into it is a menu confirmation: go back to server choice -> ReloginRequest confirm a change of server -> ReloginRequest confirm a change of character -> ReloginRequest confirm server + character -> ReloginRequest Nothing in gameplay sends it. It is not a keepalive, it is not periodic, and it has nothing to do with PingRequest despite sitting beside it in the protocol. ONE AT A TIME. The client refuses to send a second request while an answer is still outstanding - it raises an error popup instead of asking again. Do not pipeline this and do not retry it while you are still waiting; if you never got an answer to the first one, the connection is the problem, not the request. THE CLIENT PARKS WHAT YOU ASKED FOR. It remembers the action that provoked the request, sends this, and only replays that action once the token has been stored. That ordering is the whole point of the exchange: if you act on the server change before the answer lands, you leave without the token you asked for and gain nothing. WHAT COMES BACK ReloginTokenEvent, with a grant flag and a token. Both branches are real - read that record before implementing either. MATCH IT BY TYPE, NOT BY UID. This goes out on the uncorrelated send path, so its envelope uid is -1 and there is no response to pair against it. Watch for the event. SENDING IT IS OPTIONAL. Skip it and nothing breaks here; the next connection simply has to authenticate in full instead of presenting a token. What is not optional, if you do send it, is waiting for the answer before you move. When you may send it Requires authenticated observed Raised by: a client-side state change: one of three 'leave this game server' intents raised by the menu screens - go back to server choice, go to a chosen server, or go to a chosen server to play a named character. The writer parks the intent, sends this request, and replays it only once the answer has been stored inferred Related messages You will then receive ReloginTokenEvent observed — the server answers with a token grant or refusal Recovered with score 165, confidence 0.88, margin 165 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 0 of 0.
-
QuestStepInformationRequest
Asks which step of one quest the character is on, and what that step's objectives are. Kind requestArea Game.QuestNamed by beta, gamemapping, stringtable Asks about ONE quest. There is no "give me every quest's current step" form - the journal listing and this per-quest detail are separate exchanges. quest_id is the quest to ask about. Take it from the journal rather than hardcoding it. The answer is an EVENT, not a Response, so there is nothing to correlate against - match QuestStepInformationEvent by arrival and by the quest id it carries. When you may send it Requires character_loaded observed Raised by: asking about one quest - and again whenever its step changes, if you want the new objectives inferred Related messages You will then receive QuestStepInformationEvent inferred — the quest service's handler treats that event as the answer Fields #FieldTypeMeaningYou set it 2quest_idint32Which quest to ask about. (quest id)required Recovered with score 130, confidence 0.91, margin 130 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 1 of 2.
-
QuestObjectiveFollowRequest
Adds a quest, or one objective of it, to the followed list shown in the quest tracker. Kind requestArea Game.QuestNamed by beta, gamemapping ADDS A QUEST TO THE TRACKER. Its opposite number removes one, and the two are the only difference between two otherwise identical messages - read the section below before you pick one. WHEN TO SEND IT WHEN YOU START FOLLOWING SOMETHING YOU ARE NOT ALREADY FOLLOWING. That second half matters. The real client keeps its own list of followed quest ids and checks it before sending: if the quest is already there it sends the UNFOLLOW message instead, and if it is not, it sends this one and adds the id. So the client never sends a follow for a quest it already follows. Do the same. Track what you follow, and send this only for a quest you are not tracking - otherwise you and the server disagree about the list, and the client UI that reads it back will disagree with both. ONE INTENT, TWO MESSAGES. Both come out of the same UI action and the same client method; which one goes out is decided by that list check. There is no "toggle" message. WHAT TO PUT IN IT THE QUEST, AND OPTIONALLY ONE OBJECTIVE. Send -1 as the objective to follow the quest as a whole rather than a specific step - that is the sentinel the client itself tests against, and it is what a capture of "follow this quest" shows. Both values are 32-bit on the wire but the client carries them as 16-bit internally, so they are small ids, not handles. WHAT COMES BACK NOTHING DEDICATED. The followed list is state the server mirrors; no dumped client waits for a reply to this message. If you need confirmation, it arrives as the quest data the server pushes, not as an answer to this request. When you may send it Requires context_ready observed Raised by: a client-side state change: the player turning tracking ON for a quest or one of its objectives in the quest UI. The screen raises one intent carrying the quest, the objective and an on/off flag, and the writer checks its own followed-list first - it sends this only when the quest is not already in that list inferred Related messages Nothing answers it - send it and move on no dumped client waits for a reply; the followed list is client state the server mirrors Fields #FieldTypeMeaningYou set it 2quest_idint32The quest to follow.required 3objective_idint32Which objective of it to follow, or -1 to follow the quest itself.required Recovered with score 200, confidence 0.88, margin 200 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 2 of 3.
-
PrepareCharacterDeletionRequest
Opens the character-deletion flow and asks what the server needs to confirm it. Deletes nothing. Kind requestArea Game.CharacterNamed by beta, gamemapping STEP 1 OF 3. IT DELETES NOTHING. It asks the server what confirming the deletion will require. 1. PrepareCharacterDeletionRequest you ask 2. CharacterDeletionPrepareEvent the server states the terms 3. CharacterDeletionRequest the deletion actually happens Do not send step 3 without reading step 2: whether a secret answer is required is decided there, per character. Padding varies between builds; the id is the member named here. When you may send it Requires authenticated observed Raised by: the player chooses to delete a character on the selection screen proven Related messages You will then receive CharacterDeletionPrepareEvent inferred — the server answers with the character's name and whether a secret answer is required Sequence Step character_deletion.1 inferred — of 3 steps; the flow is a fixed ask / terms / confirm exchange Fields #FieldTypeMeaningYou set it 4character_idint64The character the player asked to delete. (character id)required Recovered with score 165, confidence 0.91, margin 165 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 1 of 4.
-
PlayerStatusUpdateRequest
Sets the character's own availability, with an optional free-text message. Kind requestArea Game.SocialNamed by beta, gamemapping Sets your own availability - see Status for what the values mean. DO NOT APPLY IT LOCALLY AND ASSUME IT TOOK. The server echoes the change back as PlayerStatusUpdatedEvent; that echo is what makes it real. There is a sibling error event in the naming oracles for a rejected change, declared empty and not recovered here. status carries both the state and the optional free text; see CharacterStatus. STATUS_IDLE IS THE CLIENT'S TO SET, NOT YOURS. The real client sets idle when it notices inactivity. Announcing AFK is a deliberate player action; announcing idle while actively playing is a claim the real client does not make. When you may send it Requires character_loaded observed Raised by: the player picks an availability from the status control inferred Related messages You will then receive PlayerStatusUpdatedEvent inferred — the server broadcasts the new status, echoing it back to the sender as well Fields #FieldTypeMeaningYou set it 1statusCharacterStatusThe availability state to adopt, plus its optional free text. A CharacterStatus.required Recovered with score 185, confidence 0.81, margin 185 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 1 of 2.
-
PingRequest
Latency probe. Its automatic sender only fires when the player has touched an input device, so it is not a heartbeat. Kind requestArea Game.ConnectionNamed by beta, gamemapping Measures round-trip time to the game server: send it, wait for PongEvent, keep the delta. TWO SENDERS, AND ONLY ONE OF THEM IS A TIMER. THE AUTOMATIC PROBE sends quiet = true. A timer re-arms itself every INTERVAL ms, but a tick only sends if the player touched an input device since the previous tick: every INTERVAL ms: if input_seen_since_last_tick: input_seen_since_last_tick = false send PingRequest(quiet = true) re-arm INTERVAL is 5 seconds when the client's fast-ping option is on and 10 minutes when it is off. There is no third value, no jitter and no back-off. THE CHAT CONSOLE COMMAND 'ping' sends quiet = false, once, immediately, with no gate at all. Its sibling 'aping' prints the stored average and sends nothing. THREE PROPERTIES OF THE INPUT GATE DECIDE WHAT YOUR TRAFFIC LOOKS LIKE. It is a LATCH, not a counter - ten thousand input events between two ticks produce one ping, not ten thousand. It is CONSUMED by the tick, so two consecutive pings need input in two separate intervals. And it is read BEFORE the send, so the first tick after an idle stretch is silent. WHAT COUNTS AS INPUT IS NARROWER THAN IT LOOKS. The latch is set only while a keyboard key or a mouse button is held, or a movement axis is off centre. Moving the mouse without pressing anything does not set it, and neither does giving the window focus back. Gameplay does not set it either: a character walking a route under script control produces no input at all. A CLEAN PERIODIC PING STREAM IS A STRONGER ANOMALY THAN SILENCE. A real client cannot produce one - with the input devices untouched it sends almost never. A capture of an active session shows pings roughly ten seconds apart while the player was moving: irregular, not clockwork. If your script never touches an input device, the faithful behaviour is to send this rarely, or not at all. The gate is a traffic-shape rule, not a legality rule - the server answers a ping sent at any moment. ONE PING AT A TIME. The client keeps a single outstanding send timestamp: stamped on send, cleared by the reply. A reply that arrives with no outstanding send is discarded and produces no sample, so pipelining pings gets you fewer measurements, not more. WHAT HAPPENS IF NOTHING COMES BACK. One second after each send the client raises its lag indicator, and lowers it again when the reply lands. Nothing is retransmitted and nothing is torn down - the exchange simply stays unanswered. THE SAMPLES ARE NOT DECORATIVE. Each round trip is appended to a rolling buffer of the last 50, and the average of that buffer is the number a real client reports when the server polls with BasicLatencyStatsEvent. A script that never pings has no honest value to put in BasicLatencyStatsRequest. When you may send it Requires authenticated observed Raised by: two independent senders. A timer that re-arms itself every 5s (fast ping on) or 10min (off) and sends ONLY if raw input arrived since the previous tick, clearing that latch as it fires; and the chat console command 'ping', which sends once, immediately, with no gate inferred Related messages You will then receive PongEvent observed — the reply that closes the measurement; answered ~30ms later, 2 of 2 observations in one session Fields #FieldTypeMeaningYou set it 2quietboolWhether the measurement stays silent. The server echoes it back unchanged in the reply. The automatic probe sends true; the chat console command sends false. The difference is not server-side - the flag comes back in PongEvent.quiet, and a client that receives false PRINTS the measured round-trip into the chat window. Send false only if you mean to imitate a player who typed the command.required Recovered with score 115, confidence 0.99, margin 115 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 1 of 2.
-
ObjectDeleteRequest
Destroys a quantity of one inventory item. The item is gone; there is no undo and no confirmation step on the wire. Kind requestArea Game.InventoryNamed by beta DESTRUCTIVE AND IRREVERSIBLE. This is the destroy-item action, not a move and not a drop. The items are consumed by the server with no confirmation exchange: by the time you could change your mind the message is already sent. IT HAS A TWIN THAT DROPS THE ITEM ON THE GROUND INSTEAD. A sibling request in the same file wraps the identical ObjectUidWithQuantity payload and means something completely different. Their wire shapes are indistinguishable, so verify you are constructing THIS message by name; a mistake here is not caught by any type checker. Address the stack by ObjectItem.uid, never by ObjectItem.gid. A gid either names no stack or names a different one, and the request is not rejected for being nonsense. quantity is how many to destroy, not how many to leave. Sending the stack's full quantity destroys the stack. When you may send it Requires character_loaded inferred Raised by: the player confirms the destroy prompt on an inventory item proven Related messages Reply not yet recovered: the server acknowledges with an inventory update naming the new quantity. That message has no signature yet, so treat the destroy as unconfirmed until the next InventoryContentEvent or quantity update you can read. Fields #FieldTypeMeaningYou set it 2objectObjectUidWithQuantityWhich stack to destroy and how many units of it. The current build declares this type twice in the record; only this member is ever populated.required Recovered with score 185, confidence 0.93, margin 185 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 1 of 2.
-
ObjectAveragePricesRequest
Asks for the market average price of every tradeable item. Empty payload, and the answer is the whole catalogue. Kind requestArea Game.ExchangeNamed by beta, gamemapping Carries nothing. One request fetches the average price of EVERY tradeable item - the protocol offers no per-item form. SEND IT ON A SCHEDULE, NOT ON DEMAND. The client runs it from a background loop that fires once at start and then hourly, gated on a persisted timestamp. The staleness test is a CALENDAR-DAY comparison, not an elapsed-hours one: the client stores the last refresh as a UTC tick count and considers the cache stale when the stored date differs from today in year, month or day. A cache written at 23:59 is therefore stale one minute later, and a bot that re-asks on every login regardless is producing a traffic pattern the real client does not. EXPECT A VERY LARGE ANSWER. The observed reply carried 9711 (gid, price) pairs - effectively the whole catalogue. Asking in a loop is expensive at both ends and unmistakable in a capture. DO NOT SET A CORRELATION ID. The client sends this uncorrelated, leaving the envelope id at -1, and the answer comes back as an EVENT rather than a response - so there is nothing to correlate against. Match ObjectAveragePricesEvent by arrival. There is a failure event in the naming oracles that would answer this instead, but it is not recovered and has no signature here. Watch for an unexpectedly empty reply after asking. When you may send it Requires character_loaded inferred Raised by: a background loop that fires at start and then hourly, gated on a persisted timestamp compared by CALENDAR DAY - a cache written at 23:59 is stale a minute later inferred Related messages You will then receive ObjectAveragePricesEvent observed — the answer to this request; the observed reply carried 9711 price pairs No fields you may set. Recovered with score 150, confidence 0.89, margin 150 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 0 of 1.
-
NpcGenericActionRequest
Ask an NPC on the current map to run one of its actions. Kind requestArea Game.NpcNamed by gamemapping, beta WHEN TO SEND IT Send it when the player picks one of the actions an NPC offers - talk, open its shop, and so on. You need three things, and all three must agree: the NPC's id the contextual id of the NPC ON THIS MAP, not a data id. It is the id the map sent you for that actor, and it is routinely NEGATIVE. Do not invent it and do not carry it across maps. the action id which of that NPC's actions you want. Small integer. the map id the map you are on RIGHT NOW. Sending it before the map is loaded, with an NPC that is not on that map, or with an action that NPC does not offer, is refused. WHAT COMES BACK Nothing, when it works - the action itself answers. Opening a dialogue answers with the dialogue's own messages; opening a shop answers with the shop's. On refusal the server sends a failure event that carries no payload, so it tells you THAT it failed and never why. SO DO NOT WAIT ON A REPLY TO THIS MESSAGE. Wait on the action you asked for, and treat the empty failure as your only negative. WHY THE MAP ID IS IN HERE It is the server's guard against a stale click: the NPC id alone is ambiguous once you have changed map, and this pins the request to the map the player was actually looking at. When you may send it Requires context_ready observed Requires character_loaded inferred Related messages You will then receive NpcGenericActionFailureEvent inferred — the ONLY answer this request gets, and only on refusal; success is answered by the action itself Fields #FieldTypeMeaningYou set it 1npc_map_idint64The map the player is on. Guards against a stale click.required 2npc_action_idint32Which of that NPC's actions to run. Small integer.required 3npc_idint32The NPC's contextual id on the current map. Usually negative.required Recovered with score 310, confidence 0.88, margin 240 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 3 of 3.
-
NpcDialogReplyRequest
Answers an NPC by picking one of the replies it offered. Kind requestArea Game.NpcNamed by beta, gamemapping ANSWERS THE QUESTION THE NPC JUST ASKED. One id: the reply you picked. WHEN TO SEND IT ONLY WHILE A DIALOGUE QUESTION IS OPEN, and only with a reply id that question actually offered. The reply ids are not global constants you can hardcode - each question arrives carrying its own list, and the client never invents one. Sending an id the current question did not offer is not a different answer, it is an invalid one. THREE WAYS IN, ONE MESSAGE. The real client sends this from a reply button, from confirming the highlighted reply, and from taking the first reply when the dialogue validates itself. All three raise the same intent with the same single value, so a script only needs one path: decide which reply, send its id. ONE ANSWER PER QUESTION. The dialogue is a turn-taking exchange - answer, wait for what comes back, answer again. Do not queue several replies ahead; the ids of the next question do not exist yet when you send this one. WHAT COMES BACK EITHER THE NEXT QUESTION OR THE DIALOG CLOSING - and which one you get is the NPC's decision, not yours. A reply that ends the conversation produces a dialog close rather than another question, so treat "no new question" as a normal outcome and watch for DialogLeaveEvent with the dialogue type, which is how the client learns the exchange is over. Nothing here is correlated: the envelope uid goes out as -1 and there is no response to match against. THE SECOND DECLARED MEMBER IS PADDING. No dumped client has ever written it. When you may send it Requires context_ready observed Raised by: a client-side state change: the player choosing one of the replies the NPC dialogue is showing - by clicking a reply button, by confirming the highlighted one, or by taking the first reply when the UI validates itself. All three raise one intent carrying the reply id inferred Related messages Reply not yet recovered: either the next dialogue question or the dialog closing. Those messages are recovered but not documented yet. Fields #FieldTypeMeaningYou set it 1reply_idint32The reply you picked, by the id the question offered.required Recovered with score 230, confidence 0.90, margin 230 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 1 of 2.
-
MapMovementRequest
Asks the server to walk the character along a path of map cells. Kind requestArea Game.GamemapNamed by beta, gamemapping Asks to move. YOU ARE ASKING, NOT MOVING - the server decides what actually happens and answers with MapMovementEvent. WALK THE PATH THE SERVER SENDS BACK, NOT THE ONE YOU ASKED FOR. The granted path can be shorter than the requested one, and applying your own path optimistically desynchronises your position from the server's. Everything else you do on the map - reading interactives, attacking, using a zaap - is validated against the server's idea of where you stand. key_cells is the path as map cell ids, in order, starting from the cell ADJACENT to where you are, not from your current cell. Cell ids are single grid indexes, not coordinate pairs. map_id must be the map you are actually on. The client reads it from live map state at send time rather than from a cache, and so should you: after a teleport, a stale map id is the difference between a move and a rejected one. cautious is the careful-walking mode the client derives from its own movement options. It is not a speed setting. When the walk finishes, close the handshake with MapMovementConfirmRequest. When you may send it Requires context_ready inferred Raised by: the player choosing a destination. Two producers build it: the roleplay movement service (four sites, working from EntityPhysics and a validated MapPoint path) and the fight movement service (two sites, built around FightTurn) proven Related messages You will then receive MapMovementEvent inferred — the client's handler treats that event as the grant for this request Fields #FieldTypeMeaningYou set it 1key_cellsrepeated int32The requested path, as an ordered list of map cell ids. (map cell ids) A cell id is a single grid index, not an x/y pair. The client derives these from an already-validated path, so it never asks for a route it believes is impassable.required 2cautiousboolWhether to move in the client's cautious walking mode. Derived from the player's movement and input options, not from the path.required 3map_idint64The map the movement is requested on. (map id) Read from live map state at send time, not from a cached current map.required Recovered with score 110, confidence 0.96, margin 110 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 3 of 3.
-
MapMovementConfirmRequest
Tells the server the character has finished walking the path it was granted. Empty payload. Kind requestArea Game.GamemapNamed by gamemapping Closes the movement handshake: the walk you were granted is done. CARRIES NOTHING - SEND IT EMPTY. Four of the dumped builds declare it with no fields at all; the current one pads it with a nine-value enum that NO writer in any dumped build populates. The client constructs this message, sets nothing, and submits it. Watch that padding rather than dismissing it. If a later build starts populating that enum, this message stops being a bare acknowledgement and becomes a "why did the move end" report - and a script that has hardcoded an empty payload will be sending the wrong thing rather than nothing. The name comes from one oracle only: Ankama's own type map in an early 3.x build. This message postdates the unobfuscated reference build, so unlike most of this catalogue there is no second source to cross-check the spelling. When you may send it Requires context_ready inferred Related messages Answers MapMovementEvent You will then receive MapMovementConfirmResponse inferred — the server acknowledges and the handshake closes Recovered with score 180, confidence 0.76, margin 180 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 0 of 0.
-
MapMovementCancelRequest
Stops a walk in progress and tells the server where you actually ended up. Kind requestArea Game.RoleplayNamed by beta, gamemapping STOPS A WALK AND SAYS WHERE YOU ACTUALLY ARE. It is not "cancel my request" - by the time you send it you have already moved partway, and the one value it carries is where you came to rest. WHEN TO SEND IT WHEN A WALK YOU ALREADY STARTED IS INTERRUPTED BEFORE IT FINISHES. You send MapMovementRequest with a path, the server accepts it, and then something stops you early - the player clicked elsewhere, a fight started, an obstacle appeared, the player pressed the stop control. That is this message. DO NOT SEND IT FOR A WALK THAT COMPLETED. A finished walk needs nothing; the server already knows the destination it approved. SEND THE CELL YOU ARE ACTUALLY ON, NOT THE ONE YOU AIMED AT. This is the whole point of the message and the easiest thing to get wrong. The real client does not send the destination from the path it requested, nor the cell it last announced - it asks the moving entity's own physics for its current position and sends that. If you send the intended destination you are telling the server you completed a walk you interrupted, and your position and its position diverge from that moment on. A script that walks by sending a path and then aborts must therefore track where it stopped. If you cannot compute that, do not send this message at all - diverging silently is worse than not cancelling. WHAT COMES BACK NOTHING DEDICATED. No dumped client waits for a reply. The server reconciles your position through the ordinary actor traffic that follows, so watch your own actor's position rather than expecting an acknowledgement. BE HONEST ABOUT THE CELL and the correction will be invisible; be optimistic about it and the server will move you back, visibly, later. When you may send it Requires context_ready observed Raised by: a client-side state change: a walk being interrupted before it reaches its destination. The client stops the moving entity, asks its physics where it actually is, and reports that cell inferred Related messages Nothing answers it - send it and move on no dumped client waits for a reply; the server corrects the position through ordinary actor traffic Fields #FieldTypeMeaningYou set it 1cell_idint32The cell you stopped on.required Recovered with score 235, confidence 0.88, margin 235 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 1 of 1.
-
MapInformationRequest
Asks the server what is standing on a map. Without it the map loads empty. Kind requestArea Game.GamemapNamed by beta, gamemapping Turns a loaded map into a playable one. A script that never sends this sees an empty world: no actors, no interactive elements, nothing to walk to. SEND IT ON EVERY MAP LOAD, ONCE PER MAP - NOT ONCE PER SESSION. The client raises it from its internal map-loaded notification, so it fires again on every teleport, zaap, map change and fight exit. SEND IT TOGETHER WITH ContextReadyRequest. They live in different protocol areas but the client raises both from the SAME notification, and in a capture they leave back to back carrying the same map id. Sending only one is not something the real client ever does. TAKE THE MAP ID FROM THE LOAD EVENT, NOT FROM YOUR OWN STATE. The client copies it straight out of the notification and never consults a cached current map. Note the type mismatch with its sibling: map_id is int32 here and the same value travels as an int64 in ContextReadyRequest. A capture shows both leaving in the same millisecond with 153356290 in each. A width difference is not a different map. DO NOT SET A CORRELATION ID. The client dispatches this uncorrelated, leaving the envelope id at -1. When you may send it Requires character_loaded observed Raised by: the client's map-loaded notification, which fires on every teleport, zaap, map change and fight exit - the writer copies that notification's id straight into the request proven Related messages You will then receive MapComplementaryInformationEvent inferred — the client asks for a map's contents with this request, and the contents arrive as that event; it is an Event, so match it by arrival rather than by correlation id Reply not yet recovered: on an unknown map id the area declares MapErrorNotFoundRequest, also not recovered. Fields #FieldTypeMeaningYou set it 1map_idint32The map whose contents are being asked for. (map id) Range: int32 here; the same id is int64 in ContextReadyRequest Observed: 153356290 Copied from the client's map-loaded notification, not from cached state.required Recovered with score 220, confidence 0.88, margin 220 over the runner-up. A margin close to the score means nothing else came near; a thin margin means a decoy nearly won. Members recovered: 1 of 1.