> ## Documentation Index
> Fetch the complete documentation index at: https://lastwar.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Go client implementation roadmap

> The recommended build order for a from-scratch Go client, plus a step-by-step guide to building, configuring, and actually running the researcher's own Go implementation.

Everything documented elsewhere in this dossier translated into a build order. Bootstrap first, core loop second, everything else is additive.

## Phase 1: Bootstrap (nothing else works without this)

1. `GET getlsu3dversion.php`, extract `resMsg` (RSA pubkey) and the answering host.
2. Implement the GSL RSA-PKCS1v15 + AES-256-ECB-PKCS7 envelope ([Gate-server RSA+AES handshake](/gate-server-crypto)), Go has no stdlib ECB mode, write the trivial 16-byte-block loop.
3. `POST getserverlist.php`, parse `serverList[]`, pick a server, persist `at`/`rt` tokens.
4. Open a plain TCP socket to `ip:port`. Implement the packet envelope, the length-derived XOR "encryption," zlib compression, and the `SFSObject` codec ([SFS2X wire protocol](/wire-protocol)).
5. Send SFS `Login` with the \~50-field parameter object ([Identity, login & session](/auth)), including the `SecurityCode`/`OneCode`/`CoreV` MD5 constructions.
6. Wait for `init.before` → `init` → `init.after`. Capture `chatToken` if chat is needed later.
7. Start a 4-second `PingPongRequest` heartbeat.

## Phase 2: Core loop

Build the command dispatch table directly from the extracted `cmd-data` catalog (see [Command reference](/command-reference) for the row schema and how to regenerate it, don't hand-transcribe the \~3,178 rows by hand). Implement, in order: **City/Building** → **Military/Army** (the base-building + troop loop) → **World Map** (needed for march/PVE) → **Alliance + Chat + Mail** (high command-count payoff) → **Hero** → **Shop/Economy**.

## Phase 3: Defer

Season (754 cmds) and Activity (900 cmds) are recurring/time-limited live-ops content, 54% of the entire protocol surface by command count, and it churns every patch. Implement only if a specific feature is explicitly wanted; treating either as a monolith is not advisable given how fragmented each sub-feature's schema is.

## Crypto primitives checklist

| Primitive                                       | Go path                                                               |
| ----------------------------------------------- | --------------------------------------------------------------------- |
| RSA PKCS1v15 encrypt                            | `crypto/rsa.EncryptPKCS1v15`, drop-in                                 |
| AES-256-ECB-PKCS7                               | `crypto/aes` + hand-rolled block loop (stdlib omits ECB deliberately) |
| MD5-hex-as-key                                  | `hex.EncodeToString(md5.Sum(...))`, exact match                       |
| URL-safe base64, no padding                     | `base64.URLEncoding.WithPadding(base64.NoPadding)`                    |
| ChaCha8 (patch obfuscation)                     | hand-rolled, `x/crypto/chacha20` is hardcoded to 20 rounds            |
| zlib inflate/deflate                            | `compress/zlib`, stdlib                                               |
| Zstandard (battle reports, LZ4-flagged packets) | `github.com/klauspost/compress/zstd`                                  |
| bsdiff/bspatch (table/asset patches)            | `github.com/gabstv/go-bsdiff` or similar                              |

***

## Running the Go client

The roadmap above was actually built, the repository root is a from-scratch Go reimplementation of this protocol, live-tested against production (see [Live validation against production](/live-validation) for the full writeup of what's confirmed against live production servers). It's **fully working and live-confirmed** for GSL crypto, SFS2X packet framing (including Zstandard decompression), the SFSObject codec, brand-new-guest-account login, email-verification account binding, resource collection across 13 confirmed building types (Farmland, Iron Mine, Gold Mine, Smelter, Material Workshop, Training Base, Oil Well, Drone Parts Workshop, Component Factory, and the four Season 6 Spore Factory tiers, 7 more building types are wired in but still unconfirmed, see the building-type table), and a growing set of account-level automations, none of which are building-`uuid`-scoped: the "Armed Truck"/"Overlord" idle rewards (`lw.pve.idle.reward`), greeting city visitors (`visitor.operate`), bulk-helping alliance members (`al.help.all`), claiming all alliance gifts (`alliance.reward.allreceive`), claiming all mail (`chat.get.system.mails` + `mail.reward.batch`), donating to the alliance's currently-recommended tech (`science.data.refresh` + `al.science.donate`), and both once-a-day VIP claims (`vip.add.login.score`, `vip.get.every.day.reward`), see [Live validation against production](/live-validation) for the full writeup of each. Reconnecting into an *established* real account's live game state was proven working end-to-end when first captured; that capture used the `ta` analytics blob's real device/anti-fraud sub-fields, which a later security fix replaced with empty-string placeholders, and reconnect is now **re-confirmed still working with those placeholders** (an unattended cron reconnected and collected real resources over multiple days, August 2026). What remains open is the *minimal* required `ta` content and a fully from-scratch login without a captured token; see [Live validation against production](/live-validation) for the current state.

<Note>
  **Not yet general-purpose.** The reconnect path currently needs a session config captured from a real client login (see below) rather than deriving one from scratch. A from-scratch login using `-cs-ios`-equivalent identity from the very first GSL call hasn't been tried yet.
</Note>

This section walks through going from a clean checkout to a working `-collect` run.

<Steps>
  <Step title="Build">
    ```bash theme={null}
    go build -o lastwar-client ./cmd/lastwar-client
    go test ./...
    ```
  </Step>

  <Step title="Set up a session config (recommended)">
    Reconnecting into an established account needs several values that can only come from a real client's own login (device ID, access token, ShuMei fingerprint, ...). Rather than typing them on the command line every time, put them in a JSON file:

    ```bash theme={null}
    cp config.example.json ~/.lastwar_goclient_session.json
    chmod 600 ~/.lastwar_goclient_session.json
    # then edit it with your own real values
    ```

    `~/.lastwar_goclient_session.json` is auto-loaded on every run if present, no flag needed. To use a different file, pass `-config /path/to/file.json`. Individual `-cs-*` flags still override whatever the config file says, for one-off tests.

    ```json theme={null}
    {
      "ip": "203.0.113.10",
      "port": 17783,
      "zone": "your-real-zone-e.g.-APS1234",
      "gameUid": "your-real-composite-gameUid",
      "deviceId": "your-real-device-id_n3d",
      "shumeiBoxId": "your-real-shumei-fingerprint-token",
      "accessToken": "your-real-access-token-from-a-captured-login",
      "iosMode": true
    }
    ```

    **Where these values come from:** capture a real login (e.g. `tcpdump` while the real app logs in, since the SFS2X game socket is plain TCP with no TLS) and decode the `Login` request, see [Capturing and decoding traffic](/capturing-and-decoding-traffic) for the exact, reproducible pipeline. `gameUid`/`ip`/`port`/`zone` also show up in a GSL `getserverlist` response's `serverList[]` entries. The access token is not single-use, but it *is* bound to the platform identity (`iosMode`) it was issued under, and it will eventually need refreshing from a fresh capture.

    <Warning>
      This file contains live credentials for a real account, keep it out of version control. It's already outside the repo, in your home directory, and `chmod 600`'d above; don't move it into this repo or commit it anywhere.
    </Warning>
  </Step>

  <Step title="Run a collection pass">
    ```bash theme={null}
    # One-time setup above, then everything below just works with no flags.

    # Collect resources from all confirmed buildings, the Armed Truck/Overlord idle rewards, greet visitors,
    # help alliance members, claim all mail and alliance gifts, donate to the recommended alliance tech,
    # and claim both daily VIP bonuses:
    ./lastwar-client -collect

    # Just list buildings without collecting:
    ./lastwar-client -list-buildings
    ```
  </Step>
</Steps>

### Other ways to run it

```bash theme={null}
# Stay connected and issue ad-hoc test commands without re-authenticating:
mkfifo /tmp/lw_cmd_pipe
./lastwar-client -interactive /tmp/lw_cmd_pipe &
echo 'building.production.collect {"uuid":123}' > /tmp/lw_cmd_pipe

# Override specific config fields for a one-off test (e.g. a different captured token):
./lastwar-client -collect -cs-at <a-different-access-token>

# Brand-new guest account instead (always works, no email or config needed):
./lastwar-client -list-buildings -no-config

# Bind a guest session to a real account via email verification (only needed once,
# to obtain a fresh config -- see the dossier for turning that into a session config):
mkfifo /tmp/lw_code_pipe
./lastwar-client -email you@example.com -code-pipe /tmp/lw_code_pipe &
echo 123456 > /tmp/lw_code_pipe
```

Device identity also persists across runs in `~/.lastwar_goclient_*` (deviceId, username, gameUid, loginKey) independent of the session config, so repeated guest/email-flow runs present a consistent device to the server. Delete those files to start fully fresh.

### Flags reference

The definitive, always-current flag list lives in the code itself, run `./lastwar-client -h`,
or read the flag definitions directly in `main.go`. A duplicated table here has already drifted
out of sync with the real flags more than once; the root `README.md`'s Usage section covers the
common cases with a live-tested example for each.

### Project layout

See the `README.md`'s "Project layout" section at the repository root for the current package map
(`internal/{sfs,crypto,gsl,session,game,auth,app}` plus the `cmd/lastwar-client` entry point),
keeping a second copy here is exactly what caused it to drift out of sync.
