305c3977a6
- AGENTS.md: mark PLAN.md as user-owned (never modify; it stays tracked) - move the .env ignore rule to the garage root so it covers any depth - drop the hardcoded "port 7654" hint from the no-server message; the target is now reported from the resolved SERVER_URL. The 7654 fallback remains only as the upstream TR default.
214 lines
9.7 KiB
Markdown
214 lines
9.7 KiB
Markdown
# DevControlBot
|
|
|
|
Control skeleton bot: it boots, participates in the battle, and does **nothing**
|
|
per tick except `go()` — no movement logic, no scanning, no firing.
|
|
|
|
Body, gun and radar are plain **white**, which by team convention means "this part
|
|
is not programmed yet". Colors are set **once at initialization** (`newDevControlBot`),
|
|
never inside the tick loop.
|
|
|
|
## Layout
|
|
|
|
```
|
|
DevControlBot_garage/
|
|
├── AGENTS.md
|
|
├── README.md
|
|
└── DevControlBot/
|
|
├── DevControlBot.nim # bot type + entry point (isMainModule)
|
|
├── DevControlBot.json # bot metadata
|
|
├── DevControlBot.nimble # the single `runBot` task
|
|
├── DevControlBot.sh # BotLauncher entry point
|
|
└── .env # OPTIONAL local config (secrets; never commit)
|
|
```
|
|
|
|
There is no `src/`, no `tests/`, no `out/`, no `config.nim`, no `nimble.paths`
|
|
and no vendor directory. `DevControlBot.nim` is both the bot implementation and
|
|
the program entry point.
|
|
|
|
## Dependencies
|
|
|
|
Only two, both installed **globally** with Nimble and resolved from the global
|
|
package store — nothing vendored, no `nimble.paths`, no `nimble develop`:
|
|
|
|
- `robocode_tankroyale_botapi >= 1.0.7` (the renamed `tankroyale_botapi`)
|
|
- `jsony >= 1.1.5`
|
|
|
|
```sh
|
|
nimble install robocode_tankroyale_botapi
|
|
```
|
|
|
|
The `runBot` task asks Nimble where each of those packages actually lives
|
|
(`nimble path <pkg>`) and passes explicit `--path:` flags to `nim c`. This is
|
|
required because the compiler's own `nimblepath="$home/.nimble/pkgs2/"` only
|
|
works when `$HOME` is set — with an empty environment (`env -i`, Nix build
|
|
sandbox, CI) the packages are otherwise not on the search path. If a package is
|
|
not installed, the build stops with `run: nimble install <pkg>` instead of a
|
|
compiler error.
|
|
|
|
## Run
|
|
|
|
```sh
|
|
./DevControlBot/DevControlBot.sh
|
|
```
|
|
|
|
`DevControlBot.sh` is the **BotLauncher entry point**. It is a thin wrapper: it
|
|
locates itself, `chdir`s to the directory holding the `.nimble` file, forwards
|
|
arguments and signals to `nimble runBot`, and propagates the real exit code.
|
|
All build/run/cleanup logic lives in the `runBot` task of `DevControlBot.nimble`,
|
|
which creates a throwaway `mktemp -d` build dir, compiles there, runs, and always
|
|
removes the dir via an `EXIT`/`INT`/`TERM` trap. **Nothing is left behind** — this
|
|
bot never creates an `out/` directory.
|
|
|
|
`runBot` also accepts a metadata path: **as the first positional argument**. If it
|
|
ends in `.json` it is used instead of the bundled `DevControlBot.json`; there is
|
|
no `--json` flag (an argument that does not end in `.json` is forwarded to the bot
|
|
as-is).
|
|
|
|
```sh
|
|
./DevControlBot/DevControlBot.sh # bundled metadata (default)
|
|
./DevControlBot/DevControlBot.sh /path/to/my.json # alt metadata
|
|
./DevControlBot/DevControlBot.sh --debug /path/to/my.json # alt metadata, debug build
|
|
```
|
|
|
|
With **no arguments at all** the wrapper does *not* print usage: it performs a
|
|
quiet RELEASE build and runs the bot with the bundled `DevControlBot.json`,
|
|
exactly as if that path had been passed. Usage is printed **only** for an
|
|
explicit `-h` / `--help` (exit 0, nothing is built).
|
|
|
|
## Configuration comes from the environment — the API's own mechanism
|
|
|
|
No configuration code exists in `DevControlBot.nim`, and none is needed. The
|
|
bot API reads its own environment variables inside `start()`:
|
|
|
|
| variable | read at | default |
|
|
|---|---|---|
|
|
| `SERVER_URL` | `robocode_tankroyale_botapi.nim:424` (documented at `:396`) | `ws://localhost:7654` |
|
|
| `SERVER_SECRET` | `robocode_tankroyale_botapi.nim:425` | `""` |
|
|
| `BOT_NAME`, `BOT_VERSION`, `BOT_AUTHORS`, … | `bot_info.nim:117-130`, used only when no JSON is found | see that file |
|
|
|
|
This is the supported mechanism the official BotLauncher uses: it puts those
|
|
variables in the bot's process environment before starting the binary. So the
|
|
only thing the build/run wrapper does is make sure the variables are *present*
|
|
in the bot's environment for local runs.
|
|
|
|
## Optional `.env` (a convenience for local runs only)
|
|
|
|
`DevControlBot/.env` is **optional**. If it is absent nothing happens: no error,
|
|
no warning beyond one informational line, the run behaves exactly as before and
|
|
the API defaults apply. It is not required, not generated, and not committed.
|
|
|
|
When present it is loaded by the **`runBot` task**, not by `DevControlBot.sh`, so
|
|
it applies identically to `./DevControlBot.sh` and to a direct `nimble runBot`
|
|
and the wrapper stays a thin wrapper. Properties:
|
|
|
|
- **Format:** plain `NAME=value` and `export NAME=value` lines; blank lines and
|
|
`#` comments ignored; anything that is not a simple `NAME=value` identifier
|
|
assignment is ignored (a `.env` can never smuggle in a command).
|
|
- **CRLF tolerant:** `CR` characters are stripped, so a Windows-edited file does
|
|
not turn the value into `bar\r`.
|
|
- **Nothing is ever printed.** Only the *names* taken from the file are reported,
|
|
never a value, and `set -x` is not used.
|
|
- **Overridable path:** `$DEVCONTROLBOT_ENV_FILE` points the loader at a
|
|
different file (useful for testing).
|
|
|
|
### Precedence: the environment always wins
|
|
|
|
A variable **already present in the environment is never overridden** by the
|
|
`.env` file. This matters because the official BotLauncher's values must win:
|
|
if a `.env` sitting in the checkout could overwrite them, this convenience would
|
|
silently break a real BotLauncher run.
|
|
|
|
The `.env` file is therefore **not** simply sourced — sourcing it would do the
|
|
opposite, because an assignment in a sourced file overwrites an already-exported
|
|
variable of the same name. Instead the file is **filtered line by line**: a
|
|
`NAME=value` line is dropped when `NAME` is already set in the environment
|
|
(tested with `[ -n "${NAME+x}" ]`, i.e. *set but possibly empty*, not merely
|
|
non-empty), and only the still-unset names are then exported with `set -a` and
|
|
sourced. The filtering is what implements the precedence.
|
|
|
|
```sh
|
|
SERVER_URL=ws://host:1234 ./DevControlBot.sh # shell wins, .env ignored for SERVER_URL
|
|
./DevControlBot.sh # .env supplies SERVER_URL
|
|
```
|
|
|
|
`.env` contains secrets, so it must never be committed; see the note in
|
|
[AGENTS.md](AGENTS.md) about the root `.gitignore`.
|
|
|
|
## Build modes: release by default, `--debug` for the classic build
|
|
|
|
| invocation | build | output |
|
|
|---|---|---|
|
|
| `DevControlBot.sh …` (default) | `nim c -d:release --hints:off` | quiet: dependency lines, one `build ok (release)`, one `running` line |
|
|
| `DevControlBot.sh --debug …` | plain `nim c` | classic diagnostics: `Hint: used config file …`, dot-progress line, `DEBUG BUILD` hint |
|
|
|
|
`--debug` is stripped by the wrapper wherever it appears in the arguments (a
|
|
repeated `--debug` is harmless) and is handed to the `runBot` task via the
|
|
exported env var `$DEVCONTROLBOT_DEBUG` (`debug` / `release`) rather than as a
|
|
task argument: an env var can never be mistaken for a bot argument, cannot
|
|
collide with the `$DEVCONTROLBOT_STATUS_FILE` exit-code mechanism, and leaves the
|
|
task's argument parsing untouched. Every other argument is forwarded verbatim.
|
|
|
|
In release mode the compiler's stdout/stderr is captured to a log and replayed
|
|
**only if the build fails**, so a failed build is always loud in both modes while
|
|
a successful release build stays short (10 lines including the no-server report,
|
|
vs 16 with `--debug`). `--help` / `-h` prints usage and exits 0 **without
|
|
building**; no arguments does the opposite — it builds and runs.
|
|
|
|
The bot needs a running Tank Royale server at `SERVER_URL` (the API's documented
|
|
default is `ws://localhost:7654`); without one the run fails with
|
|
`[start] Cannot connect to <SERVER_URL>` and exits 1 (expected during local
|
|
verification).
|
|
|
|
## Failure reporting and exit codes
|
|
|
|
Nimble's `exec` raises a NimScript exception — stack trace, escaped copy of the
|
|
whole script — for *any* non-zero exit, which made "no game server" look like a
|
|
catastrophic build crash. The `runBot` shell therefore always exits 0 and writes
|
|
the real code to the status file named by `$DEVCONTROLBOT_STATUS_FILE`, which
|
|
`DevControlBot.sh` exports and then re-exits with. The real code is preserved,
|
|
not masked.
|
|
|
|
| exit | meaning |
|
|
|---|---|
|
|
| `0` | clean run |
|
|
| `1` | bot could not connect to the game server at `SERVER_URL` (expected locally) |
|
|
| `2` | a dependency is not installed — `nimble install <pkg>` |
|
|
| `3` | compilation failed — the compiler's own errors are printed above |
|
|
| other | the bot's own exit code (runtime crash, bad metadata) |
|
|
|
|
Each mode prints its own short line, e.g.
|
|
|
|
```
|
|
[start] Cannot connect to ws://localhost:4567: Connection refused
|
|
[devcontrolbot] bot exited with code 1.
|
|
[devcontrolbot] No game server on ws://localhost:4567 (SERVER_URL).
|
|
[devcontrolbot] Start the Tank Royale server, or point SERVER_URL at a running one.
|
|
```
|
|
|
|
No `Exception raised during nimble script execution`, no stack trace, no source
|
|
dump. `nimble runBot` run directly (no status file) keeps the old behaviour and
|
|
still raises.
|
|
|
|
Interrupt handling is unchanged: SIGINT/SIGTERM are forwarded, the build dir is
|
|
removed by the `EXIT` trap and the wrapper exits 143 (SIGTERM) / 130 (SIGINT).
|
|
|
|
## Gotcha: `nimble runBot` must be run from `DevControlBot/`
|
|
|
|
The `.nimble` file lives in `DevControlBot/`, so the task is only visible from
|
|
there:
|
|
|
|
```sh
|
|
cd DevControlBot && nimble runBot # works
|
|
cd DevControlBot_garage && nimble runBot
|
|
# Error: Could not find a file with a .nimble extension inside the specified
|
|
# directory: .../DevControlBot_garage
|
|
```
|
|
|
|
`DevControlBot.sh` handles this for you by `cd`-ing itself. Note also that
|
|
`compile`/`build` are reserved Nimble builtin names — hence the `runBot` name.
|
|
|
|
## Test
|
|
|
|
There are **no tests** in this garage. The `test` task and the `tests/` directory
|
|
were removed along with the old build layout; see
|
|
[AGENTS.md](AGENTS.md) for the convention to follow when tests are added. |