Sword and Shield

Pokemon Sword and Shield exchange protocol-buffer messages over a publish/subscribe framework running directly on Pia.

Static readings are from a Shield 1.3.2 EUR image (01008db008c2c000, update NCA, SDK 7.7.0.0); measurements are against a French Sword 1.3.2. The two share their network code.

page contents
The cartridge and the session keys, the image, Pia 4, association to the first application data
The sync framework message ids, contents, holders, routing, the party payload
Trading the trade screen, the box state machine, the confirmation ladder
Mystery Gift the Mystery Gift menu’s local-wireless branch
Max Raid Battles the den lobby, its advertisement, hosting a raid one or several consoles join, the battle a guest fights, Dynamax Adventures, leaving

Sources

Ids, offsets and addresses come from Shield’s main or the air unless a section names a client. SYNC_ANSWERS in pokeldn/swsh/trade.py is andyjusa/nxldn-lab’s reading of a console-to-console capture (messages 97 and 60000 match pokeldn’s byte for byte). kwsch/PokePiaSWSH, lincoln-lm/swsh-lan-client, andyjusa/nxldn-lab and Slashcash/PSD speak the LAN mode from the Pia station handshake up; none covers LDN or host migration.

The field scripts

bin/script/amx/*.amx (953 in 1.3.2) are Pawn 3.x with 64-bit cells: magic 0xF1E1, version 10, flags 0x1C (compact code, sleep, no checks). Compact encoding: 7 bits per byte, high group first, sign in bit 6 of the first byte. Non-branch one-parameter opcodes are also packed as (param << 32) | op, numbered from 162 in 3.x order (LOAD.pri 162, LOAD.S.pri 164, PUSH.C 188, PUSH.S 190, STACK 191, ADD.C 197, ZERO.S 200, EQ.C.pri 201, INC.S 204, HALT 210, PUSH.ADR 212); halt 0 at offset 0 pins it.

A native is twelve bytes, u64 0 and a u32 name hash, resolved by amx_Register (0x0066d970):

h = 0; for each byte c: h = (h * 0x83) ^ c        (32-bit)

Binding tables are (name, function) pairs in .data, one per module (getters such as 0x014aea00): 777 names, 512 of the 513 hashes used. Items: ItemAdd (0x014acea0), ItemSub (0x014acf40), ItemGetNum, ItemAddCheck, ItemGetCategory, GetPocketNumberFromItemNumber_. Variables: WorkGet/WorkSet (hashed 64-bit keys), TempWorkGet/TempWorkSet (indices the UI fills before the script resumes). A call is PUSH per argument, right to left, then SYSREQ.N native, bytes.

Unresolved

  • Player profile: which role sample states 3 and 4 stand for in a Pokemon Camp session (StateCreateSession, StateConnect). a_wr0301 as the Crown Tundra wild area is read from the numbering only.
  • Battle Stadium: which save block 0x01430670 reads for a stored team record, and what a save team’s descriptor holds at +0x30..+0x135 before the v1/validate signature replaces +0x36 (the entry at [sp+0x28] after 0x015039f0).
  • Sword against Shield: binary readings are Shield’s, the console is Sword; the session constants hold across the pair. Sword testing bit 0 of a card’s version mask is inferred from Shield’s code, where the test is 1 << (v == 0x2D) and eleven of the 31 call sites of 0x007d4270 compare against both 0x2C and 0x2D, and from PKHeX RestrictVersion (1 Sword, 2 Shield, 3 both); two retail Sword snapshots carry 0x2C at MyStatus +0xA4. Sword’s own 0x007d4270 and its communication id literal are unread.
  • Mystery Gift: whether a retail console takes a kind-1 gift whose species is absent from the game as an emulated Shield does, as a bad egg named “Egg”; and what such an egg does on hatching or in a trade.

Table of contents