Skip to content

Bot Intelligence Server ​

Bots in Washiki Washoi run as a separate Node.js process that connects to game servers as real WebSocket clients. At the protocol level, a bot is indistinguishable from a human player.

The bot system lives at src/bot/ in the engine repo (not in this submodule).

Running ​

bash
npm run bot:server

The bot server boots an interactive console. It can register itself with a lobby, queue for matches like a human player, and play autonomously.

The lobby and the shared secret ​

The lobby, the bot server and the game servers run on one machine and share a secret:

  • Where it comes from: BOT_SECRET when it's set. Otherwise the first process to start writes one to <data-dir>/bot-secret (the data directory is --data-dir, else SERVER_DATA_DIR, else server-data/ at the repo root). Start both from the same folder, or give them the same --data-dir.
  • The control port: the lobby sends the secret when it asks for a bot. The bot server's control port (9100) listens on 127.0.0.1 only and closes any connection without it.
  • Bot logins: lobby bots authenticate with the shared service secret, not a human account key. Standard difficulty presets have rating identities for private matches. Players cannot claim a bot's reserved name.

Architecture ​

ComponentResponsibility
BotServer.tsTop-level orchestrator; manages a fleet of bot clients
BotClient.tsA single headless network client; one per bot
BotBrain.tsAI base class; subclassed for different difficulty / strategy
BotGameState.tsParses incoming snapshots into a queryable world model
BotVision.tsBSP raytracing — line-of-sight, cover evaluation, spatial awareness
BotNavGraph.tsA* pathfinding on a BSP-derived Smart Waypoint Network
BotConfig.tsDifficulty presets; hands out bot names; default goal-arbiter mode
BotNames.tsBot name pool, reserved from players by the lobby
BotMovementProfile.tsKnowledge of movement mechanics (strafe jump, wall jump, etc.)
BotMovementAnalyzer.tsReads back what the movement actually did
BotWeaponProfile.tsKnowledge of weapon stats
BotFireSafety.tsRefuses shots that would hurt the bot or a teammate
BotNavCache.tsCaches the derived navigation graph per map on disk
BotSequence.ts, sequences/Multi-tick manoeuvres: strafe-jump routes, crouch-slides, jumppads, teleporters, validated jumps
goals/Goal sources, considerations and the arbiter that scores them
StateMachineBrain.tsThe rule-based brain
HybridBrain.ts, TFBackend.tsThe optional neural brain and its backend
BotInputNormalizer.tsConverts game state to neural-network input vectors
BotEpisodeRecorder.tsRecords training episodes
BotRewardComputer.tsComputes reinforcement-learning rewards
BotTrainer.tsAutonomous self-play training loop
DemoTrainingExtractor.tsTurns a .shagdemo recording into training frames
BotLobbyClient.tsLobby integration — bots join rooms and ready up like humans

Difficulty Tiers ​

Four presets in BotConfig.ts, each a set of skill dials rather than a single number. The values below are the committed presets; aimAccuracy and the other skills run 0 to 1, and mistakeRate is how often a bot is allowed to be wrong.

PresetAimReactionTrackingPredictionItem timingStrafe jumpDodgeMistakes
Easy0.25450 ms1.50.20.10.10.158
Medium0.5280 ms3.00.50.40.40.43
Hard0.75150 ms5.00.750.70.70.71
Insane0.9260 ms8.00.90.90.90.90.2

Read the preset in source rather than a percentage here: these are the numbers the bot is actually built from.

Two AI Modes ​

BotBrain is the interface; two brains implement it.

  1. StateMachineBrain — the rule-based brain, always available. What it wants at any moment comes from the goal layer in goals/: goal sources propose candidates (acquire an item, hunt, hold an area, defend, escort, move to a place), each is scored by considerations, and GoalArbiter picks one. It combines them as gate × attraction × discount, taking the best reason rather than summing every reason, so a goal that is mediocre at everything cannot outscore a goal that is decisive about one thing. The arbiter's mode comes from BOT_GOAL_ARBITER: on by default, legacy to fall back to the older scoring, verbose to have it explain itself. Movement that takes more than a tick — a strafe-jump route, a crouch-slide into an item, a jumppad or teleporter traversal — runs as a sequence from sequences/, which the brain can interrupt.
  2. HybridBrain — optional TensorFlow.js networks layered on the rules. Inputs come from BotInputNormalizer; outputs influence move, aim and fire.

The neural mode is opt-in per bot. Without it, bots run the rules and the goal layer, and play competitively at Medium and Hard.

Training ​

Two sources, one set of labels. Recorded human matches are where playing like a person comes from; self-play sharpens what is already there. Both are covered in Bot Training, including what a demo has to hold to be worth training on, how a corpus is built, and how trained weights reach a bot in a room.

The short version: --models <dir> tells the bot server where the weights are, and every bot it creates inherits that directory — including a bot a player adds from a room. A bot whose models will not load plays the rules.

Joining a room ​

The lobby flow is live: BotLobbyClient connects to the lobby with the shared secret, and either queues like a human or joins one exact room when the lobby hands it a room id and, for a private room, that room's invite token. It then readies up on its own. From the room's side this is the Add bot key; from the lobby's side it is an invitation acknowledged only once the bot is actually seated.

The player-facing Add bot action is available only in private rooms. Without an explicit preset, the lobby chooses one near the player's private rating for that mode; new players fall back to medium. Standard presets have rating accounts used by the private ladder. A bot client still authenticates with its service secret, not a human account key; see Ranked matches.

TODO ​

  • Per-difficulty weapon profile overrides
  • Configuration file format
  • Logging + telemetry expectations
  • Production deployment patterns

Built on the SHAG Engine.