Download

← All updates

Update

quark 1.18.25

Everything that changed in this version, and why.

A tests-only update (the "Discuss and improve release tests" work). No game, server, protocol or file format change: 1.18.25 plays with 1.18.22 to 1.18.24 (protocol 44). Three lines in src/ exist only for the tests and cost nothing at run time (see "src/: test-only hooks"). Numbers are from a 4-core cloud box.

Map grading removed; the map safety checks kept

  • Owner: "The maps test will soon be irrelevant with the addition of real human designed maps, so get rid of it."
  • Removed: tests/mapreport.cpp (the decor / layout / movement / creativity / mode fit / balance scores, the >= 7 bar, the attack/defend -1..+1 s timing band, originality, # exempt), quark_tests mapreport, docs/MAP_REPORT.md, docs/MAP_METRICS.md, and the report's shot sheets (docs/map_shots/, tools/map_shots.sh). The suite no longer writes .cams files into the source tree.
  • Kept, every check that fails a broken map: spawns, routes, nav from every spawn to every objective, ladders, stairs, cart sweep, symmetry, the map format tests. "Built for one mode" (a for line) moved into testAllMaps. Human-made maps keep their report-only grace (misses print as HUMAN-MADE).
  • The out-of-bounds check stays: it lived in the report's bar, and moved to tests/mapbounds.cpp with the movement envelope and tech graph trimmed to what it needs (same sampling, same numbers on every map; 1.18.7's dash rules, dashReady, carried over). It runs as the mapbounds and mapbounds2 groups (every other map each) and as quark_tests bounds; OOB_TRACE=<map> lists what's out.
  • The map editor keeps the measurement: tools/map_editor/native carries its own copy (measure_impl.h, from 07ef254), now the only one; its comments and README say so. The old metric definitions are in git at 07ef254.
  • Docs: RELEASE_CHECKLIST, HANDOVER, ASSETS, MAP_STRUCTURES, JUDGMENT_CALLS.

Faster tests: full local run ~279 s -> ~107 s

What each check asserts is unchanged; only waiting that isn't part of a check went, and real-time checks re-run only when the machine itself stalled.

  • Bots-only tests on a manual clock (ffaVsExperts, the every-mode loop, testBotAim, testBotFalls, testGrappleBots): a test clock that moves only when the test steps it to the server's next tick. Every tick runs, none is waited for, and a seeded match is the same every run (the old wall-clock runs skipped ticks on a loaded box, the cause of the flaky hooks >= 1). bots 64 -> 9 s, botaim 62 -> 1.3 s, botfalls 46 -> 1.3 s. 1v1 and duel in the every-mode loop have a joining player since 1.18.21 (F7), so those two stay on the real clock.
  • brains: the native-vs-interpreted lockstep steps every tick (Server::stepTick, as the mode lockstep does) instead of playing 396 s of game time in real time: 101 -> ~5 s, the same 1.19 million thinks compared.
  • Tick-rate tests on 1-1.5 s windows (were 3 s), the window holding the connect dropped unjudged, and a re-run only when this machine stalled a tick past the threshold itself: group tickrate 96 -> ~63 s, and 3 passes in 10 -> 10 in 10. testing's timingTest (1.18.22) wraps them as well.
  • Netcode re-runs only on real machine stalls: pump() can measure how long the machine left its loop unrun (wall time minus the thread's CPU time: the game's own slowness never counts). The uptime clock, interpolation delay and input backlog checks run again (3 tries, the last counts) only after such a stall, never with a looser threshold: 8 passes in 10 -> 30 in 30. testClockWrap (the same view-tick lag through the 2^32 ms wrap) moved from "server" into "netcode" beside them, with the same re-run: under the busy parallel phase it read 14-35 ms in 2 of 3 full runs.
  • Waits a check doesn't need: countdowns, freeze and round ends skipped where a test doesn't check them (tourney 25 -> 1 s, duel 24 -> 3 s), weapons tests start once both players have spawned, the vote / rejoin / ranked tests poll for what they wait on, the hello retry is 0.5 s in tests.
  • Groups: governor, resetmaps and userdata run with the others; only tickrate, netcode and weaponpredict run after them, one at a time. rules, maps and mapbounds, and the mode lockstep (~41 s of CPU) are split in two so no group bounds the run; groups are listed longest first. 3 group processes per core (the groups mostly wait on real-time play: with one per core the cores sat ~70% idle). Groups that only compute run at nice 10 so the real-time groups beside them get the cores (without it, 2 of 3 full runs failed a real-time check after 1.18.22).
  • Rules halves: tests whose ports overlap stay in one half (the halves run at once on one port block): hudclock takes 29280-29291, which hide, shorthanded and rps reach too. 1.18.23's mode calls test (one bomb match, ~2 s) joins the second half.
  • weaponpredict (the client's weapon prediction over a 40 ms network) runs alone after the others, inside timingTest: in the rules group it missed its 0.8 s window in 1 full run of 3, and in 10 of 20 runs beside 8 busy loops on 1.18.17's own build (about 1 in 30 even idle).
  • quark_tests NAME runs the whole group (as group NAME does). The 38 subset shortcuts are gone (some shared a group's name and ran less of it). Kept: playtest, serverbench, snapbench, ffaexperts, racefloors, bounds, exportassets, rules NAME (one rules test), signing, launcher, bot, groups, group, serial, and the brain / mode / weapon tools and benches (exportbrain ... modebench, exportweapons ..., exprbench, navbench). An unknown name is an error listing them. 1.18.24's nav and navstuck shortcuts went too: both tests run in the botaim group.
  • Group times print in real seconds (they were game seconds, 4x).

Sanitizer fixes (CI's final-test job)

  • quark_tests replaces operator new / delete; the nothrow forms now go through it too. Under ASan they were ASan's own, so std::stable_sort's buffer was freed by the wrong allocator: 16 of 17 sanitizer reports.
  • Server tests are noinline: inlined into serverTests() their Servers (~1.2 MB each) shared one ~17 MB frame under ASan, past Linux's 8 MB stack.
  • tests/lsan.supp: the per-thread rules tables are kept on purpose (a thread_local with a destructor crashed at thread exit under MinGW).
  • release.yml (sanitizer step only): ulimit -s 65536 (ASan gives every local its own slot: votes ~7.5 MB) and LSAN_OPTIONS with the suppressions file.

src/: test-only hooks (no run-time cost)

  • Server::rateStalls_ (default true): the loss / bandwidth rate tests leave stalls out of the verdict. One member read where the verdict is made, once per rate window.
  • RankService::helloRetryScale (1.0): a static read only when a ranked hello failed.
  • MasterAnnouncer::queuedPosts(): an accessor the game never calls.
  • The manual clock (net.cpp): timeNow() keeps its one compare against 1.0 on the game's path; a manual clock uses the existing scaled path with a zero rate, no new branch. Server::nextTickForTest() is an inline accessor.

Tools

  • Tests editor: the brain / mode tools and bounds count as tools, mapreport is gone; a list's parallel flag comes from the scheduler call; rewriting the group lists keeps a group's comment lines with it; its tests follow the new tests.cpp (test_serve.py 23/23, run.mjs 47/47).
  • release_check.sh's list of groups run alone: tickrate, netcode, weaponpredict.