Download

← All updates

Update

quark 1.18.11

Everything that changed in this version, and why.

Data-driven bot brains, for the owner's bot editor ("in the bot brain section it should have regular code and block code and graph network formats for the same thing ... what % they do X, Y, Z; what curves apply to certain things, values"). Edited brains have to change the real game's bots, so the bot code now reads every choice and number from a brain. No network protocol, map or demo format change; default bots are bit-identical to 1.18.10.

The brain (src/game/botbrain.h, src/game/botbrain.cpp, tools/bots/)

  • What a brain is: parameters (one value, or one per skill level), curves (linear, step or piecewise), weapon lists, an ideal-range table, and slots: the fixed decision points the bot code calls (react, hearing, targetScore, objective.<mode> for every mode, urgent, pickWeapon, idealRange, rejudge, fire, strafe, fightJump / fightDash / fightHook, pulledDash, look, routeHook, runDash, bhop, unstick and more). Each slot is a small program: expressions, if, weighted choices, roll / gauss / chance(rate).
  • What stays C++ (the body): navigation, the pit / lava / edge safety checks, the grapple's safeHook, the aim "hand" (turn speed, flick, settle, tracking error) and the air-strafe maths. A brain tunes their numbers but can't switch the safety off. Why: a brain file must never be able to make bots walk into the void or break movement rules.
  • Hidden switches made explicit: some behaviour used to be switched by unrelated numbers: leadMean >= 0.8 turned on leading targets, airStrafe > 0.8 expert hooking, skill == EXPERT the dash jump, predict set the flee time. They are now their own per-level parameters with the same values, so tuning one number no longer changes another behaviour by surprise.
  • Format: tools/bots/GRAMMAR.md (the text language and the JSON form the editor uses). Files start with version 1; like maps, a converter table (kBrainFormatVersion, static_assert on its size) upgrades older versions on load. Input caps (512 tokens per line, nesting depth 48) keep a hostile local file from overflowing the stack.
  • The built-in brain is tools/bots/default.qbrain, embedded at build time (tools/bots/embed_brain.py). It is written in the same language and parses to exactly the C++ values.

Speed (performance first)

  • Phase 1: every literal the bot code read is now a BrainParams field, filled per level from a C++ table with the 1.18.9 bot values (unchanged since 1.18.4). Measured against 1.18.7's bot: 1679 vs 1662 ns per think, within noise.
  • Phase 2: a brain file is compiled once to a flat 8-byte instruction array over a fixed 64-register file and run by an interpreter that allocates nothing per call. The built-in brain never uses the interpreter: it stays native. A file pays only for the slots it changes.
  • Cost (quark_tests brainbench, 230,010 thinks on 4 maps, 10-12 bots, 250 Hz): native 1339 ns per think (p99 7-14 us, p99.9 25-33 us); every slot interpreted 2129 ns (p99 10-17 us, p99.9 32-42 us). +790 ns per think = about 1.3% of one core at 16 bots and 1000 Hz, only for fully custom brains.

Picking a brain (src/game/server.cpp, src/server/main.cpp)

  • Console addbot [a|b] [skill] [brain=<name>] loads <user data>/bots/<name>.qbrain (cached by content). brain=default forces the built-in brain.
  • Dedicated server --botbrain <name> (ServerConfig::botBrain): every bot the server adds plays it. A file that fails to compile is refused with file:line:col: message; from the config the error goes to the server log and bots play the built-in brain.
  • A bot playing a brain file names it and the first 8 hex digits of its hash on the join line (BOT ANNA (EXPERT, mybrain#1a2b3c4d)), so players can tell. Built-in bots' join line is unchanged.
  • Where brains run: local, listen and unranked servers (owner's choice on 2026-10-24). Ranked and time trial never load them (they have no bots either).

Tests (tests/brain_tests.cpp, group brains)

  • default.qbrain round trip: print(parse(text)) == text, byte for byte; number printing cases.
  • The parsed default equals the C++ table at all 4 levels; every slot native; no warnings.
  • Converter: v1 unchanged; versions 0 and 2 refused with line:col.
  • 15 compile-error cases (line:col and message), the nesting and line-length caps, interpreter unit checks.
  • addbot brain=, cfg botBrain, brain=default and the ranked refusal.
  • Lockstep: the default brain run natively vs fully interpreted: 1,186,724 bot thinks over 11 maps/modes at 1000, 250 and 125 Hz, every UserCmd field and the whole bot state (rng included) compared bitwise each think: 0 mismatches. A negative control (one slot changed) is detected. (Before the temporary harness was removed, 1.18.7's bot vs the new native code: 1,187,874 thinks, 0 mismatches.)
  • Command-line tools for the bot editor: quark_tests exportbrain [out.json] (text, AST and a catalog of 122 params, 47 sensors and the slot kinds), checkbrain <file> (diagnostics as JSON, exit 1 on errors), brainast, printbrain, brainbench.

The bot editor (tools/bot_editor/, tooling; not in the game download)

  • A local web tool (run.cmd / run.sh, serve.py on 127.0.0.1:8769, stdlib Python) for placing bots on any map (the shipped maps and the player's own, including the map editor's), giving each an objective (go to, hold an area, follow a route, attack or defend the mode's objective), watching live runs with the game's real bots (paths, goals, targets, view cones, the decision behind each goal; pause, step, speed, timeline), and batch runs that compare brains (wins, K/D, damage, objective time per brain and per bot).
  • The brain editor shows one brain as text code, blocks, a node graph and a values view with draggable curves; each view is drawn from the same tree, so they never disagree. Saving writes a .qbrain holding only what differs from the default, checked by the game's own compiler (quark_tests checkbrain).
  • The simulator is in the shared quark_maptool helper: new sim, simbatch and simcheck commands (tools/bot_editor/native/SIM.md), built on the map editor's BotSim, which now also runs several matches per process. Objective overrides steer the game's own botThink (no game code change); measured 100-880x real time per match and about 27 matches/s for 4-bot FFA batches on 4 threads.