# Text Client Operator Guide

This guide covers operating the Eagle text client against a running Eagle server. It does not cover game strategy.

## Authentication And Startup

The text client can request and refresh its own tokens. GitHub is the recommended OAuth provider:

Start the production client with:

```bash
bazel run //src/main/scala/net/eagle0/eagle/text_client:eagle_text_client -- --tls --host prod.eagle0.net --port 443 --oauth
```

On the first run, or when no usable refresh token remains, the client prints a GitHub login URL. Paste that URL to the user and wait for them to authenticate in their browser. The callback returns to a temporary loopback listener in the text client, not to the Unity client. Never open the URL or choose an account on the user's behalf.

The client stores the access and refresh tokens in `~/.eagle0/text-client/` with owner-only permissions and refreshes the access token automatically. For an existing token location, pass both `--bearer-token-file <path>` and `--refresh-token-file <path>`. Use `--oauth-provider <provider>` only if the account uses `google`, `discord`, `apple`, `steam`, or `twitch` instead of the recommended `github` provider.

At the `eagle0>` prompt, use `lobby` to list running games and available new-game leaders. To resume a game, use:

```text
stream <game-id>
```

Wait for `subscription: success=true` before posting a command.

## Inspecting State

Use these commands before acting:

```text
status
state
commands
commands-json
```

`state` is the concise map and owned-province view. `state-json` prints the complete view. `commands-json` includes the exact fields, IDs, resource amounts, and command choices currently accepted by the server. Each entry also includes a `post-json` template for its corresponding selected command.

Generated text is stored locally during the client process. Use `text <text-id>` for a text ID without spaces, such as `text hn_105`. Province leaders in `state` are resolved through this store when their names have been received.

## Posting Eagle Commands

Use the available-command data from `commands-json` to select a command, then post a matching selected command:

```text
post-json <province-id> <SelectedCommandType> <JSON>
```

Templates contain the accepted JSON field names and default values. Replace zero
IDs, `UNKNOWN` enum values, empty collections, and other placeholders with a legal
choice from the available-command payload before posting. Where a selected command
must echo server data, such as a ransom offer, the client copies that data into the
template automatically.

For example:

```text
post-json 13 ImproveSelectedCommand {"improvementType":"ECONOMY","actingHeroId":105,"lockType":true}
post-rest 13
post-feast 13
```

The client has shortcuts for `post-rest`, `post-return`, `post-feast`, riot decisions, and battle aftermath. The authoritative selected-command schemas are defined in:

```text
src/main/protobuf/net/eagle0/eagle/api/selected_command.proto
```

Only post a selected command that is currently listed as available. A successful request prints `post-command: SUCCESS`; do not assume a command was accepted until that response or a later game update arrives.

Some actions enter a temporary subcommand state. For example, trading is operated as:

```text
post-json <province-id> VisitTownSelectedCommand {}
post-json <province-id> TradeSelectedCommand {"tradeType":"BUY_FOOD","amount":<amount>}
post-return <province-id>
```

After each step, run `commands-json` again. The server will reject a nested command, such as `TradeSelectedCommand`, if its parent state has not been entered.

## March Warnings

Marches may produce a warning before being sent. Review it, then resubmit only when intentional:

```text
post-json --force <province-id> MarchSelectedCommand <JSON>
```

`MarchSelectedCommand.marchingUnits` contains combat units. Each selected battalion is paired with a distinct hero in the same combat-unit entry; do not submit battalion-only entries.

## Shardok Battles

When a battle is active, inspect it with:

```text
shardok-units
shardok-commands
```

Post one of the currently listed command indices with:

```text
post-shardok <index>
```

Omit the optional roll value during normal play. The server then generates any
roll required by the selected command. To override that roll for deterministic
testing, append an integer value:

```text
post-shardok <index> <integer-roll>
```

`roll` is a placeholder in command usage, not a literal argument. Only an
integer is accepted, and the override has an effect only for Shardok commands
that support a client-supplied roll.

For a specific active battle:

```text
post-shardok <shardok-game-id> <index>
post-shardok <shardok-game-id> <index> <integer-roll>
```

The battle ID may be omitted only when exactly one outstanding battle currently
has postable commands. If multiple battles have commands, the client refuses the
ambiguous shorthand; use the battle ID printed by `shardok-commands`. Battles
removed from Eagle's outstanding-battle list are no longer postable, and a
Shardok update with no available commands clears the previous command list.

Use `shardok-commands-json` or `shardok-units-json` when the concise output omits a needed field.

The initial Eagle state includes the complete strategic province graph. Inspect it with:

```text
eagle-map
eagle-map-json
```

Both forms list every province and all of its neighbors by ID and name. Use the JSON form when exact IDs or
machine-readable relationships are needed; unlike March destinations, this is the complete map graph and is not
filtered by the commands currently available.

During battle setup, `shardok-commands` prints any server-recommended unit placements in order and identifies the
ordinary current command index for the next recommendation:

```text
recommended-starting-positions (ordered):
  [0] unit=12 target=(3,4)
  [1] unit=15 target=(4,4)
use next: post-shardok <shardok-game-id> 17
```

The list is advice, not an automatic placement batch. Review it against `shardok-map`, choose whether to use the first
recommendation, and submit that one placement with the printed `post-shardok` command. After every placement, wait for
the updated state and run `shardok-commands` again; the legal command indices and remaining recommendations may change.

The client synchronizes Shardok map definitions when it connects. To inspect the
base terrain together with current tile modifiers and occupying units, use:

```text
shardok-map <shardok-game-id>
shardok-map-json <shardok-game-id>
```

The battle ID may be omitted when the client knows about exactly one Shardok
battle. The concise map prints every coordinate's terrain plus fire, castle,
bridge, ice, and snow state. The JSON form includes the complete base map,
dynamic tile modifiers, and current active units.

## Reconnects And Shutdown

The client automatically recreates a failed gRPC stream and re-subscribes to the active game. It retains its in-process `ClientTextStore`, so a reconnect should announce:

```text
Reconnecting to game <game-id> with saved text state.
```

Followed by a successful subscription without replaying the full generated-text catalog. Do not start a second client merely because a stream reports `GOAWAY`, `UNAVAILABLE`, or `RST_STREAM`; wait for the automatic reconnect and subscription acknowledgment.

The text store is in memory. A newly launched process performs an initial text sync once, then retains byte offsets for reconnects during that process.

Use `quit` to close the client cleanly. Use `drop <game-id>` only when intentionally abandoning that game.
