Matches the deployed config: 120s graceful stop, and HISCORES_HIDDEN_NAMES
covering the imported local test saves.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MAX_PLAYERS_PER_IP is now 100 on Fly (code default stays 200 for local load
tests). getIp only trusts Fly-Client-IP behind Fly and the socket peer
elsewhere; the old cf-connecting-ip / X-Forwarded-For lookup took the first,
client-supplied entry, so a swarm could claim a new IP per connection and walk
past the cap.
The gateway no longer fans out a state frame that repeats the last one sent
to subscribers apart from its publication revision (same tick, same content:
a post-action publish where the action changed nothing visible yet).
Subscribers get the next tick's frame instead; any difference still goes out.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The gateway can also listen on GATEWAY_PUBLIC_PORT (on Fly:
wss://rs-sdk-demo.fly.dev:7443 -> 7781) with permessage-deflate. On live
bot state frames that is ~16% of the uncompressed bytes at ~6 ms CPU per MB,
spent in the gateway process rather than on the game server's tick thread.
The main port is unchanged and uncompressed, so the engine's /gateway relay
and every existing SDK and runner behave exactly as before.
SDK connect() and the lite runner check the direct port (3 s) and use it when
it answers, otherwise they keep wss://.../gateway; a failed connect checks
again. GATEWAY_DIRECT=false opts out. HTTP endpoints keep the relayed origin.
GATEWAY_HOSTNAME lets a fleet run a private loopback gateway (sdk/README.md).
sdk/chat.ts and the MCP server now honor a bot.env GATEWAY_URL, as cli.ts and
runScript already did. The Dockerfile sed that forced 0.0.0.0 is replaced by
that option's default.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agents hit SDK papercuts constantly - a method returns success:true and
nothing happened, a dialog option isn't where the docs say it is - and
there was nowhere to put that. Filing one is now a single command:
bun sdk/bug-report.ts "walkTo returns success at closed gates"
The SDK's git commit is stamped on every report, so a report points at the
code that produced it.
Server side, POST /bug-report appends JSONL to the mounted volume
(BUG_REPORTS_FILE in fly.toml, so reports survive deploys). The endpoint is
deliberately write-only: nothing is served back over HTTP, and reports are
read off the machine with
fly ssh console -C "cat /opt/server/data/bug-reports.jsonl"
Reports always go to rs-sdk-demo.fly.dev, never to whatever SERVER a bot is
playing on - a bug found against a local server is still a bug in the SDK.
Telemetry is on by default; TELEMETRY=false in bot.env or the environment
turns it off.
Also renames claude.md -> CLAUDE.md and agents.md -> AGENTS.md. Those names
only resolved on macOS: the filesystem is case-insensitive here, so git had
recorded lowercase names that no tool would find on a case-sensitive
checkout. Verified on a case-sensitive volume - before the rename, lookups
for CLAUDE.md and AGENTS.md both missed; after, all three resolve to the one
real file.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Persist telemetry regardless of LOGGER_SERVER (moderation log stream stays opt-in;
fly no longer enables it - 1800 bots x 15s check-ins would fill the volume)
- Skills blob only on base level change; total_xp still on every row
- Snapshot every 200 ticks (60s)
- Hourly prune in LoggerServer: after 2 days keep 10-min granularity + level changes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- New player_telemetry table (sqlite migration + prisma + kysely types)
- World snapshots all online players every 100 ticks via logger worker
- Full skills JSON only written when xp changed since last snapshot
- Enable LOGGER_SERVER on fly (was off, so session logs weren't persisting)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>