Smooth
Administrateurs
-
Adhésion
-
Dernière visite
-
Actuellement
Ajout d'un article de blog dans : c25f89372458901ba5ba2ca865bdbe9d
Tout ce qui a été publié par Smooth
-
ServerChallengeEvent
The server's challenge in the proof-of-identity handshake. The one message in that chain whose contents you must read. Kind eventArea Game.Client.VerificationNamed by beta, gamemapping Arrives because you sent ClientChallengeInitRequest, and must be answered with ClientChallengeProofRequest. THE HANDSHAKE DOES NOT COMPLETE UNTIL YOU DO. WHEN IT ARRIVES Shortly after your init request, and only then - the server does not send it on its own schedule. But it is delivered as an ordinary event: the client matches it BY TYPE, not by the envelope id it allocated for the init. There is only ever one of these exchanges in flight, so nothing needs correlating, and you should not sit waiting for a uid to come back. It is the third of four steps. ClientIdRequest and ClientChallengeInitRequest publish the two values this challenge is checked against; if you have not sent both, there is nothing here you can usefully answer. READ THE PAYLOAD - THIS IS THE ONE STEP WHERE IT MATTERS PARSE IT AS AN ARBITRARY-PRECISION INTEGER. The value is a decimal string and the real client parses it as a big integer, multiplies it by its private exponent and reduces the result. It is not bounded by anything you can hold in 64 bits, and truncating or overflowing it produces a proof that is silently wrong rather than an error you can see. ABSENT IS NOT EMPTY, AND ABSENT DOES NOT MEAN SKIP IT. The field has explicit presence and the client tests for it. When the value is missing the client does NOT stay silent and does not fail - it computes a challenge of its own by hashing its handshake values together with a device fingerprint, and answers with that. Treating a missing value as "nothing to do here" leaves the handshake open, which is exactly the state the exchange exists to detect. ClientChallengeProofRequest gives the full recipe for both branches. WHERE THE ANSWER GOES ON THE MAIN GAME CONNECTION, even when a second one is open. While a fight-server transfer is active the client holds two sockets (see IdentificationRequest) and routes outbound traffic between them by message type. All three verification requests are on the short list pinned to the FIRST connection - ordinary gameplay traffic is what goes to the fight server. Answering on the wrong socket is a mistake the real client cannot make. 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 You must then send ClientChallengeProofRequest proven — the client's handler combines this value with its state and returns the proof Arrives after ClientChallengeInitRequest Fields #FieldTypeMeaningYou set it 1valuestringThe server's challenge, as a decimal string, combined with your handshake state to derive the proof. Explicit presence: absent is not the same as zero. Parse it as an arbitrary-precision integer. It is not bounded to 64 bits, and a truncated value yields a wrong proof rather than a visible error. Absent means "no challenge given" - and that is an instruction, not a rest: the client derives its own challenge and answers anyway. See ClientChallengeProofRequest.never; inbound only Recovered with score 144, confidence 0.92, margin 144 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.
-
SequenceNumberEvent
Empty server poll asking the client how many events it has received. Kind eventArea Game.BasicNamed by beta, gamemapping Carries no payload - the message IS the question. Answer it with SequenceNumberRequest carrying how many of these polls have reached you on this connection, the one you are answering included. COUNT THE POLLS, NOT YOUR INBOUND TRAFFIC. The real client keeps one counter per connection that nothing but this poll touches: zeroed when the socket becomes active, incremented once per arrival, so the first reply carries 1 and never 0. See SequenceNumberRequest for the full rule. In a capture the real client replies in the same millisecond, and this poll arrives in the same frame as BasicLatencyStatsEvent. When you may send it Requires authenticated observed Related messages You must then send SequenceNumberRequest observed — the poll is unanswered until the client reports its counter Unsolicited - nothing you send causes this the server polls on its own schedule; nothing you send asks for it Sequence Step server_poll.1 observed — the server emits both polls in the same frame; of 2 observations Recovered with score 90, confidence 0.95, margin 90 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.
-
Rights
Five account permission booleans whose individual meanings are not recovered. Kind structArea Game.AccountNamed by stringtable Five booleans, and we do not know which is which. THIS IS A DELIBERATE GAP, NOT AN OVERSIGHT. The reference build has no account-level rights type in the game protocol, the early 3.x name map has none, and the client never branches on an individual flag - only on whether the block is present at all. There is nothing to prove a mapping with, so nothing is claimed. Read them positionally as opaque flags if you must, and expect their order to be meaningless across builds. The safe answer is to ignore this record. The type name itself is real: it comes from the current build's own protocol type-name table. Not sent on its own — it is only ever carried by AccountRightsEvent. inferred Used by AccountRightsEvent No fields you may set. Recovered with score 130, confidence 0.89, 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: 0 of 5.
-
ReloginTokenEvent
Grants or refuses the token that skips full authentication on the next connection. Check the flag before the token. Kind eventArea Game.ConnectionNamed by beta, gamemapping Answers ReloginRequest, and it is the only thing worth waiting for in that exchange. CHECK THE FLAG BEFORE YOU READ THE TOKEN A REFUSAL IS NOT AN ERROR MESSAGE, and it is not silence - the server answers, the flag is simply clear. Read the flag first. If you read the token unconditionally you will carry an empty string into the next connection and fail authentication there, far from the cause and looking nothing like this exchange. THE REAL CLIENT OVERWRITES ON REFUSAL. It does not keep the token it already had: on the refusal branch it stores an empty string over it, deliberately. Do the same. A stale token from an earlier session is worse than none, because it will be presented and rejected. WHAT THE TOKEN IS FOR The next connection presents it instead of a full authentication round. Store it, then proceed with whatever you were doing - the real client stores it and only then replays the menu action that asked for it. If you act first and store second, you can leave the server before the value is in hand. READ IT BY ROLE, NOT BY NUMBER The message is padded, and the padding is different in every build - a nested message here, a spare bool there, a map somewhere else - while the two members that matter keep swapping field numbers between builds. Two members are live: one bool that says whether a token was granted, and one string that carries it. Everything else in the declaration is padding no client has ever read. IT ARRIVES BY TYPE. The request went out uncorrelated, so nothing links this event back to it by uid. There is only ever one of these exchanges in flight, so nothing needs correlating. When you may send it Requires authenticated observed Related messages Arrives after ReloginRequest Fields #FieldTypeMeaningYou set it 1valid_tokenboolWhether the server granted a token. Gates the token below.never 2tokenstringThe relogin token, empty when refused.never Recovered with score 220, confidence 0.89, 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: 2 of 2.
-
QueueStatusEvent
Your position in the login queue while the server is full. Kind eventArea Game.Character.ManagementNamed by beta, gamemapping Arrives repeatedly while the account waits in the login queue, and stops once you are through. In a capture of an uncongested sign-in it still appears a few times in quick succession with a shrinking payload. WAIT, DO NOT RETRY. Receiving this means the server has your connection and is holding it; re-sending CharacterListRequest or reconnecting only puts you back at the end. When you may send it Requires authenticated observed Related messages Unsolicited - nothing you send causes this the server pushes queue progress on its own; nothing you send asks for it Fields #FieldTypeMeaningYou set it 1positionint32Your place in the queue.never 2totalint32How many accounts are queued in total.never Recovered with score 126, confidence 0.97, margin 126 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 2.
-
QuestStepInformationEvent
The current step of one quest and its objectives. Kind eventArea Game.QuestNamed by beta, gamemapping The answer to QuestStepInformationRequest. The real content is information - a QuestActive carrying the quest and the step it is on. player_id is USUALLY ABSENT, because the answer goes to the character who asked. Do not require it to be present, and do not use it as the key to match the reply against your request - use the quest id inside information. When you may send it Requires character_loaded observed Related messages Arrives after QuestStepInformationRequest Fields #FieldTypeMeaningYou set it 1player_idint64Whose journal the reply concerns. Explicit presence: absent is not the same as zero. (character id) Usually absent - the answer goes to whoever asked.never 2informationQuestActiveThe quest and the step it is currently on. A QuestActive. This is the actual answer.never Recovered with score 200, confidence 0.79, 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 2.
-
QuestActive
One quest the character has under way, with the detail of the step it is currently on. Kind structArea Game.QuestNamed by beta, gamemapping, stringtable A shared carrier, not a message anyone sends: the journal embeds a list of these and QuestStepInformationEvent embeds exactly one. details carries the current step and its objectives. That nesting is the point of the record - the quest id alone tells you nothing about progress. The current build declares a SECOND int32 and a SECOND message member beside the real ones. This signature names its members only on builds where each is unambiguous, so on a padded build they stand obfuscated rather than being guessed at from position. Not sent on its own — it is embedded in the quest journal and in QuestStepInformationEvent. inferred Used by QuestStepInformationEvent Fields #FieldTypeMeaningYou set it 1quest_idint32Which quest is under way. (quest id)never 2detailstype not documented yetThe step the quest is currently on, and its objectives.never Recovered with score 190, confidence 0.84, margin 190 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.
-
PopupWarningEvent
A moderator's warning: who sent it and what it says, shown to the player. Kind eventArea Game.ModerationNamed by gamemapping, beta A MODERATOR IS TALKING TO YOU. The server pushes this unprompted and the client renders the moderator's name and their message. If you are running anything automated, this arriving means a human has looked at your account and acted. Treat it as a stop signal, not as chat. WHAT IT CARRIES author the moderator's displayed name content the warning text itself lock_duration an int32 NO CLIENT READS - see below DO NOT BUILD ANYTHING ON lock_duration. The name is Ankama's, but it is carried across from the reference build by elimination: it is the message's only int32 there and its only int32 here. NO DUMPED CLIENT READS IT - not this build, not any 3.x build, and not the unobfuscated reference build either, whose five handlers touch author_ and content_ and nothing else. Whatever the server puts in it, the game ignores it, so a value of zero is entirely normal and no client behaviour depends on it. It is named because the name is real, not because the field does anything observable. WHAT THE CLIENT ACTUALLY DOES It reads the two strings and hands them to the popup service. That is all. WHAT FOLLOWS The family completes with an acknowledgement round trip, and this part IS verified in the dumps: the client builds and sends a close request when the popup is dismissed, and consumes a closed event in return. On 3.2.7.15 both were empty; by 3.6.10.10 the close request carries a four-value enum - presumably how the popup was dismissed - while the closed event is still empty. Neither is recovered yet. So the server can tell whether the warning was actually seen and closed. Failing to acknowledge is itself a signal. When you may send it Requires character_loaded inferred Related messages Unsolicited - nothing you send causes this no client code builds it; it is pushed by the server Fields #FieldTypeMeaningYou set it 1authorstringThe moderator's displayed name.never 2lock_durationint32An int32 no dumped client reads. Name carried from the reference build. NOT VERIFIED AT RUNTIME. The name is the reference build's and is assigned by type-elimination - one int32 there, one int32 here. No client in any dumped build reads this member, including the unobfuscated reference build, so nothing confirms it is a duration or that it has any effect. Expect zero and do not depend on it.never 3contentstringThe warning text shown to the player.never Recovered with score 195, confidence 0.88, margin 195 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.
-
PongEvent
Server reply to a ping; the client turns it into a round-trip latency sample. Kind eventArea Game.ConnectionNamed by beta, gamemapping Answers PingRequest. On receipt the real client takes the clock again, enqueues the round-trip delta into a bounded sample queue, and exposes average, maximum and sample count from it. THOSE SAMPLES ARE NOT SELF-CONTAINED. They are the source of the value reported when the server polls with BasicLatencyStatsEvent, so skipping the ping exchange leaves you with nothing honest to report in BasicLatencyStatsRequest - a self-reported number the server can compare against how long you actually took to answer. Nothing else consumes this exchange, and no protocol decision depends on it. Two of its declared members are never read by any dumped build. When you may send it Requires authenticated observed Related messages Arrives after PingRequest Fields #FieldTypeMeaningYou set it 1quietboolThe quiet flag echoed back from the originating request.never; inbound only Recovered with score 192, confidence 0.94, margin 192 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.
-
PlayerStatusUpdatedEvent
Somebody's availability changed - a contact's, or your own echoed back. Kind eventArea Game.SocialNamed by beta, gamemapping Broadcast for any player whose status you can see - friends, guild and alliance members, party members - and for your own character, as the echo of PlayerStatusUpdateRequest. TWO IDS, AND THEY ARE DIFFERENT WIDTHS. player_id is the CHARACTER (int64); account_id is the ACCOUNT behind it (int32). Use the account id to track a person across their characters and the player id to address one character. The differing widths are the only thing separating them on the wire. status carries the state and the player's own free text, which is untrusted input - see CharacterStatus.message. When you may send it Requires character_loaded observed Related messages Arrives after PlayerStatusUpdateRequest Fields #FieldTypeMeaningYou set it 1statusCharacterStatusThe new availability state plus its optional free text. A CharacterStatus. Its message is untrusted player text.never 2player_idint64The character whose status changed. (character id)never 3account_idint32The account behind that character. (account id) 32-bit, where the character id is 64-bit - that width difference is what separates them.never Recovered with score 220, confidence 0.95, 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: 3 of 4.
-
OptionalFeaturesEvent
The set of optional features the server has enabled, replacing any held set. Kind eventArea Game.ConnectionNamed by beta, gamemapping Pushed in the burst after a successful IdentificationRequest. THIS REPLACES, IT DOES NOT MERGE. The client swaps its whole enabled-feature set for this list and re-evaluates what is available; keeping stale ids from an earlier connection would enable features the server has since turned off. When you may send it Requires authenticated observed Related messages Arrives after IdentificationRequest Fields #FieldTypeMeaningYou set it 1featuresrepeated int32Identifiers of the optional features currently enabled. (feature id)never Recovered with score 148, confidence 0.94, margin 146 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.
-
ObjectsQuantityEvent
New absolute quantities for stacks the character already holds, several at once. Kind eventArea Game.InventoryNamed by beta, gamemapping Quantity updates for stacks that are ALREADY in your inventory, batched. EACH ENTRY IS AN ABSOLUTE TOTAL, NOT A DELTA. The client looks the stack up by ObjectUidWithQuantity.object_uid and SETS its size to ObjectUidWithQuantity.quantity; it never adds. Treating it as a delta double-counts every update. THIS MESSAGE NEVER INTRODUCES A STACK. If the uid is not already known the client logs an error and drops the entry -- so a uid you have not seen means you missed an earlier add, not that a new item appeared. Recover by asking for a fresh snapshot rather than inventing the stack. A quantity of zero is a real value here; the stack is emptied but the server still announces removal separately. The singular counterpart carries one entry plus an origin; this one is the bulk form and carries no origin at all. When you may send it Requires character_selected inferred Related messages Unsolicited - nothing you send causes this the server pushes it whenever stack sizes change; no request asks for it Fields #FieldTypeMeaningYou set it 1objectrepeated ObjectUidWithQuantityThe (uid, new quantity) pairs being applied. Ankama names it in the singular although it is repeated. Each element is an ObjectUidWithQuantity whose quantity is the stack's NEW TOTAL.never Recovered with score 195, confidence 0.90, margin 195 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.
-
ObjectUidWithQuantity
A quantity of one item stack, addressed by its unique handle. Reused wherever the protocol acts on part of a stack. Kind structArea Game.CommonNamed by beta Names a stack and an amount. Ankama reuses this one record across the inventory protocol - destroying, dropping, and the server's own quantity-changed event all wrap it - so the record itself carries no intent. THE MEANING IS ENTIRELY IN THE MESSAGE THAT CONTAINS IT. See ObjectDeleteRequest for the destructive one. The uid is ObjectItem.uid, the per-stack handle - never the template gid. The two members are proven to exist and carry these roles, but this signature does not yet name them individually, so they stand with their obfuscated names. Match them by reading the stack you are acting on out of InventoryContentEvent first. Not sent on its own — it is only ever reached as the payload of a request or event. proven Used by ObjectDeleteRequest ObjectQuantityEvent ObjectsQuantityEvent Fields #FieldTypeMeaningYou set it 2quantityint32How many units of that stack the record applies to. On a request this is how many units to act on; on a quantity event it is the stack's new total.required 3object_uidint32Unique id of the stack this record is about. Identifies one existing stack in the inventory, not the item template. The client uses it as the lookup key when applying the record.required Recovered with score 230, confidence 0.94, 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: 2 of 3.
-
ObjectStorageQuantity
How many of one item sit in one of the character's storages, so a single stack can be reported per location. Kind structArea Game.CommonNamed by invented This name is not Ankama's. It was chosen for this documentation from proven client behaviour, and is a label rather than protocol documentation. WE CHOSE EVERY NAME HERE. The record, both members and ObjectStorageKind with all of its values are our descriptive labels, derived from proven client behaviour. Beta, the 3.2 name map and the current type-name table all fail to name this record. The BEHAVIOUR below is proven; the SPELLING is not, and a future official schema may well use different words. ObjectItem carries a repeated list of these, which is how one stack is reported as, say, 3 in the inventory and 20 in the bank at the same time. The client sums nothing for you: it switches on storage and folds each count into a separate counter. AN ENTRY WHOSE STORAGE IS UNSPECIFIED IS SILENTLY DROPPED by the client, so do not treat the list as exhaustive of the item's true total. Not sent on its own — it is only ever reached as an element of ObjectItem.storage_quantities. proven Used by ObjectItem ObjectQuantityEvent Fields #FieldTypeMeaningYou set it 2storageObjectStorageKindWhich of the character's storages this count belongs to. WE CHOSE THIS NAME. See ObjectStorageKind.never 3quantityint32How many units of the item are held in the storage named beside it. WE CHOSE THIS NAME. Proven as the count the client folds into one of three tooltip counters.never Recovered with score 240, confidence 0.86, 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: 2 of 3.
-
ObjectStorageKind
Which of the character's storages a per-item count belongs to: bag, bank, or haven bag. Kind enumArea Game.CommonNamed by invented This name is not Ankama's. It was chosen for this documentation from proven client behaviour, and is a label rather than protocol documentation. THE TYPE NAME AND ALL FOUR VALUE NAMES ARE OURS. Nothing here is attested by any naming oracle. THE NUMBERS ARE THE REAL CONTRACT and are what this signature pins; the labels are descriptions of what each number provably does. Each value was proven by following the count into the tooltip slot the client renders it in, so the meanings are solid even though the spellings are not. Switch on this, never on position. An unrecognised value should be ignored the way the client ignores the unspecified one, not folded into a default bucket. Not sent on its own — an enum is never sent on its own. inferred Used by ObjectStorageQuantity Values ValueNumberMeaning STORAGE_UNSPECIFIED0The proto3 zero value. The client assigns nothing for it and the entry is silently dropped. WE CHOSE THIS NAME. STORAGE_INVENTORY1The character's own bag. WE CHOSE THIS NAME. Proven: this count feeds the tooltip slot captioned 'ui.item.inventoryQuantity'. STORAGE_BANK2The account bank. WE CHOSE THIS NAME. Proven: this count feeds the slot captioned 'ui.item.bankQuantity'. STORAGE_HAVEN_BAG3The haven bag's storage. WE CHOSE THIS NAME. Proven: this count feeds the slot captioned 'ui.item.havenBagQuantity'. Recovered with score 182, confidence 0.83, margin 182 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: 4 of 4.
-
ObjectQuantityEvent
The new quantity of one stack you already hold, and where the change came from. Kind eventArea Game.InventoryNamed by beta, gamemapping The singular form of ObjectsQuantityEvent: one stack, its new quantity, and an origin. THE QUANTITY IS THE NEW TOTAL, NOT A DELTA. The client looks the stack up by ObjectUidWithQuantity.object_uid and SETS its size to ObjectUidWithQuantity.quantity. If you want "how many did I just get", subtract what you held before - which is exactly what the client does for its quest message. IT NEVER INTRODUCES A STACK. It updates one you already hold; an unknown uid means you missed an earlier add. THE ORIGIN SAYS WHY. When it is ObjectOrigin.ORIGIN_QUEST and the stack grew, the client also posts the "item obtained" chat line with the gained amount. With any other origin the update is silent. TWO DECLARED MEMBERS ARE PADDING the client never reads. When you may send it Requires character_selected inferred Related messages Unsolicited - nothing you send causes this the server pushes it whenever one stack's size changes; no request asks for it Fields #FieldTypeMeaningYou set it 1originObjectOriginWhy the quantity changed. ObjectOrigin.ORIGIN_QUEST makes the client announce the gained amount in chat; other values change nothing visible.never 3objectObjectUidWithQuantityThe stack being updated and its new quantity. An ObjectUidWithQuantity whose quantity is the stack's NEW TOTAL, not a delta.never Recovered with score 310, confidence 0.91, margin 310 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 4.
-
ObjectOrigin
Why an inventory stack changed; the client only acts on the quest origin. Kind enumArea Game.CommonNamed by beta The origin carried by ObjectQuantityEvent (and by the item-added event). WHAT THE CLIENT DOES WITH IT. Exactly one thing: when the origin is ORIGIN_QUEST it announces the gained amount in chat. Every other value - ORIGIN_UNDEFINED and the two unnamed ones - is treated identically: the inventory is updated silently. TWO VALUES HAVE NO NAME. The protocol has grown: two values in the reference build, a third by 3.2, a fourth by 3.4. No dumped client, string table, type table or descriptor names the two newer ones, so they keep their obfuscated names. If you meet one, treat it like ORIGIN_UNDEFINED; that is what the client does. ORIGIN_UNDEFINED is the default: an update whose origin is absent from the wire arrives as this value. Not sent on its own — an enum is never sent on its own. inferred Used by ObjectQuantityEvent Values ValueNumberMeaning ORIGIN_UNDEFINED0No particular origin; the client updates the inventory silently. Named from beta's numbering, not client behaviour. It is the default when the origin is absent. ORIGIN_QUEST1The stack changed because of a quest; the client announces the gained amount in chat. Recovered with score 115, confidence 0.91, 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: 2 of 4.
-
ObjectItemInventory
One item as it sits in the inventory: the item itself, where it is, and how the player tagged it. Kind structArea Game.InventoryNamed by beta The element type of InventoryContentEvent.objects. It wraps an ObjectItem with the three things that are true of the item HERE rather than of the item in general. position IS NOT A BAG INDEX. It is the equipment slot when the item is worn, and a bag marker otherwise. Do not treat it as an ordinal you can iterate: two unequipped items can carry the same position, and the value only becomes meaningful once you know whether the item is equipped. tag_storage_uuids is the player's own tagging, not a server concept. It is a set of opaque strings; compare them, do not parse them. Not sent on its own — it is only ever reached as an element of InventoryContentEvent.objects. proven Used by InventoryContentEvent Fields #FieldTypeMeaningYou set it 3positionint32The equipment slot when the item is worn, and a bag marker otherwise. Not an inventory ordinal. Unequipped items share values.never 4tag_storage_uuidsrepeated stringThe player's own storage tags for this item, as opaque identifiers. The client loads them into a set; order carries no meaning.never 5itemObjectItemThe item itself. The current build declares this type twice in the record and only this copy is ever populated.never 6favoriteboolWhether the player marked this item as a favourite.never Recovered with score 280, confidence 0.90, margin 280 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: 4 of 6.
-
ObjectItem
One item stack: which item it is, how many, its unique handle, and the effects rolled onto it. Kind structArea Game.InventoryNamed by beta One item instance. The same record is reused across the inventory, exchange and storage protocols, so everything below applies wherever it appears. THE TWO IDS ARE BOTH INT32 AND ARE TRIVIAL TO SWAP. THIS IS THE EASIEST BUG TO WRITE AGAINST THIS PROTOCOL. gid the TEMPLATE id - WHAT KIND of item this is. Every copy of the same item in the game shares one gid. Use it to look the item up in your own data. uid the handle for THIS stack, unique within the character. This is the value a destroy, drop, move or exchange request wants. Send a gid where a uid belongs and you address a different stack or none at all. Nothing in the declaration separates them: on the current build both are int32 and the field numbers were shuffled, so read by NAME, never by position. effects is the roll on this instance - see ObjectEffect. It is a oneof: branch on which member is set, never read positionally. storage_quantities is not an Ankama name - see ObjectStorageQuantity. Not sent on its own — it is only ever reached as a member of another message. proven Used by Metadata ObjectItemInventory Fields #FieldTypeMeaningYou set it 1uidint32The unique handle for this stack, and the value later requests address it by. (item instance id) Unique within one character's storages, not globally. This is what ObjectUidWithQuantity.uid wants.never 2quantityint32How many units are in this stack. Range: 1 or more for a stack that existsnever 3effectsrepeated ObjectEffectThe effects rolled onto this particular instance. Element type ObjectEffect, a oneof - branch on it.never 4storage_quantitiesrepeated ObjectStorageQuantityHow this stack is split across the character's storages, counted per storage. WE CHOSE THIS NAME. The beta build predates the field, so there is no Ankama name to check it against. See ObjectStorageQuantity for what the element actually carries.never 5gidint32The item template id: what kind of item this is. (item template id) Declared int64 in the beta build and int32 here; the value is the same id. Shared by every instance of that item. NOT a handle - see uid.never Recovered with score 325, confidence 0.93, margin 325 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.
-
ObjectHarvestedEvent
You just harvested this many of an item; the client shows the amount with the item's icon. Kind eventArea Game.InventoryNamed by beta, gamemapping A harvest finished and produced items. object_gid is the item (an id from the items table) and quantity is how many this harvest gave. IT IS A NOTIFICATION, NOT AN INVENTORY UPDATE. The client only displays it: it looks the item up for its icon and shows the gained amount over your character. The stack itself changes through the inventory messages - for an item you already hold that is ObjectQuantityEvent, whose quantity is the new total. Do not add this quantity to your inventory as well, or you will count the harvest twice. A harvest that also produced bonus items arrives as the "with bonus" variant instead, which carries a third number the client shows in a second colour. When you may send it Requires character_selected inferred Related messages Unsolicited - nothing you send causes this it arrives when a harvest completes; the client does not ask for it Fields #FieldTypeMeaningYou set it 1object_gidint32The item that was harvested, as an id from the items table. The client resolves it with the items table to show the item's icon.never 2quantityint32How many of the item this harvest produced. A gain, not a stack total; the inventory change arrives in its own message.never Recovered with score 265, confidence 0.90, margin 265 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 2.
-
ObjectEffectMinMaxValue
The low and high bounds of an effect that rolls within a range. Kind structArea Game.InventoryNamed by beta The min_max branch of ObjectEffect. Two numbers, in semantic order: the lower bound first. The order is recovered from where the client copies each value, not from the field numbers, so read by name. Nothing guarantees min <= max on the wire; the server has never been observed sending them inverted, but a script that subtracts them should not assume a non-negative result. Not sent on its own — it is only ever reached as the min_max branch of ObjectEffect. inferred Used by ObjectEffect Fields #FieldTypeMeaningYou set it 1maxint32The upper bound of the effect's range.never 2minint32The lower bound of the effect's range.never Recovered with score 140, confidence 0.97, 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: 2 of 3.
-
ObjectEffectDiceValue
An effect expressed as a dice roll: how many dice, how many sides, plus a flat constant. Kind structArea Game.InventoryNamed by beta The dice branch of ObjectEffect, read as num dice of side sides plus const. num IS DECLARED 64-BIT ON THIS BUILD even though the client stores it in a narrower slot. Read the declared width, not the client's. The record declares a fourth integer that neither direction of the client's own conversion touches. It has no recovered meaning - it may be a decoy or a field the game has not started using. It stands with its obfuscated name; do not guess at it. Not sent on its own — it is only ever reached as the dice branch of ObjectEffect. inferred Used by ObjectEffect Fields #FieldTypeMeaningYou set it 1numint64How many dice are rolled. Declared 64-bit here; the client narrows it on the way in.never 2sideint32How many sides each die has.never 3constint32A flat value added to the roll.never Recovered with score 140, confidence 0.97, 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: 3 of 4.
-
ObjectEffect
One effect on an item, as a oneof over every shape an effect's value can take. Kind structArea Game.InventoryNamed by beta One rolled or intrinsic effect. action says WHICH effect this is; the oneof says what its value looks like. BRANCH ON THE ONEOF. NEVER READ A MEMBER POSITIONALLY. In protobuf an unset branch reads back as a zero, not as an absence, so a script that reads value_int unconditionally sees 0 for every string, dice and date effect and cannot tell that apart from a genuine zero. Ask which branch is set first. action IS AN OPAQUE EFFECT ID, NOT AN ENUM IN THIS SCHEMA. Its meaning lives in the game's own data centre, not in the protocol; the same number carries the same meaning across builds, but nothing here tells you what it is. Look it up in your own data. The branches, and what each is for: value_int a single number - the ordinary case value_string a text value min_max a range - see ObjectEffectMinMaxValue dice a roll - see ObjectEffectDiceValue date a point in time duration_minute a duration, counted in minutes creature_family a creature family id monster_count a creature family plus a count TWO OF THESE HAVE CHANGED SINCE THE 2.x PROTOCOL AND OLD NOTES WILL MISLEAD YOU. date is now a structured five-integer message, not a string. The historical mount branch is gone from the current build entirely. Not sent on its own — it is only ever reached as an element of an item or an action. inferred Used by ItemMinimalInformation ObjectItem SetUpdateEvent Fields #FieldTypeMeaningYou set it 1actionint32Which effect this is: an opaque effect id resolved against the game's data centre. (effect id) Present on every branch. It is the only member you can read without first checking the oneof.never 2creature_familyint32The effect's value when it is a creature family. The branch is only meaningful when it is the one that is set; reading it otherwise yields a zero value, not an absent one. (creature family id)never 3monster_countMonsterCountThe effect's value when it is a creature family together with a count. The branch is only meaningful when it is the one that is set; reading it otherwise yields a zero value, not an absent one.never 4diceObjectEffectDiceValueThe effect's value when it is a dice roll. The branch is only meaningful when it is the one that is set; reading it otherwise yields a zero value, not an absent one. See ObjectEffectDiceValue.never 6duration_minuteint64The effect's value when it is a duration. The branch is only meaningful when it is the one that is set; reading it otherwise yields a zero value, not an absent one. (minutes) The client converts it through a minute-valued time span in both directions, which is what fixes the unit.never 8min_maxObjectEffectMinMaxValueThe effect's value when it is a range. The branch is only meaningful when it is the one that is set; reading it otherwise yields a zero value, not an absent one. See ObjectEffectMinMaxValue.never 9value_stringstringThe effect's value when it is text. The branch is only meaningful when it is the one that is set; reading it otherwise yields a zero value, not an absent one.never 10value_intint32The effect's value when it is a single number. The branch is only meaningful when it is the one that is set; reading it otherwise yields a zero value, not an absent one.never 12datetype not documented yetThe effect's value when it is a point in time, as five integer components. The branch is only meaningful when it is the one that is set; reading it otherwise yields a zero value, not an absent one. A STRUCTURED MESSAGE ON THIS BUILD. The 2.x protocol carried a string here; notes written against that schema are wrong.never Recovered with score 270, confidence 0.99, margin 270 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: 9 of 12.
-
ObjectAveragePricesEvent
The market average price of every tradeable item, as one list of item-and-price pairs. Kind eventArea Game.ExchangeNamed by beta, gamemapping The answer to ObjectAveragePricesRequest: one entry per tradeable item, carrying the item's template gid and its average market price. It is what the client shows in item tooltips and in the auction house. IT ARRIVES AS AN EVENT, NOT A RESPONSE. There is no correlation id to match on - match it by arrival after your request. THE LIST IS HUGE. The observed reply carried 9711 entries with gids running consecutively from 16384, i.e. the whole catalogue. Build a lookup table once and keep it; do not scan the list per item. Prices are 64-bit and genuinely exceed the 32-bit range. See ObjectAveragePrice. When you may send it Requires character_loaded inferred Related messages Arrives after ObjectAveragePricesRequest Fields #FieldTypeMeaningYou set it 1objects_average_pricesrepeated ObjectAveragePriceEvery tradeable item's average market price, as item-and-price pairs. Element type ObjectAveragePrice. Observed at 9711 entries in one 3.6.10.10 capture.never 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 2.
-
ObjectAveragePrice
One item and what it currently sells for on average. Kind structArea Game.ExchangeNamed by beta One entry of ObjectAveragePricesEvent, declared nested inside it. READ BOTH MEMBERS BY NAME. Their field numbers and their declared types move between builds: across the seven dumped builds the gid is number 1, 2 or 3 and the price is 1, 2 or 3, and on four of them a decoy of the SAME scalar type sits next to the real member. Position, number and type are all worthless here; only the recovered names are stable. The gid is the same template id as ObjectItem.gid, so this list joins directly onto inventory contents. Not sent on its own — it is only ever reached as an element of ObjectAveragePricesEvent.objects_average_prices. inferred Used by ObjectAveragePricesEvent Fields #FieldTypeMeaningYou set it 3object_gidint32The item's template id, as used everywhere else in the protocol. (item template id) Observed: 16384 - the lowest gid in the observed cataloguenever 5average_priceint64The item's average market price. (kamas) 64-bit because prices exceed the 32-bit range. Do not narrow it.never Recovered with score 140, confidence 0.91, 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: 2 of 5.