Download

← All updates

Update

quark 1.18.12

Everything that changed in this version, and why.

The owner asked for a model editor: a local tool to look at every model the way the game draws it and replace it. The editor itself is a tool outside the game. The game changes make its exports draw exactly like the built-in models, let every model the game draws be replaced, and keep a player's own model files out of ranked. Gameplay, the network protocol (43) and demos are unchanged: 1.18.12 plays with 1.18.7 and newer games and servers.

Ranked fairness: your own model files stay out of ranked (src/client/gltf.cpp, src/client/models.h, src/client/overrides.*, src/client/game.cpp)

  • Why: a player's own overrides/models/... files (the user overrides folder, %APPDATA%\quark\overrides on Windows) applied in ranked too. Ranked forces the STANDARD player model, so one models/player/STANDARD.glb was enough to make every enemy huge or neon for that player alone; projectiles and the crown worked the same way.
  • What: both sets of model overrides are loaded once at startup (ModelOverrides: the shipped set from assets/overrides/ and yours, loadModelOverrides). drawWorld picks one set once a frame: a player in a ranked match or a time trial (MS_RANKED | MS_TIMETRIAL, rankedPlayer()) gets the shipped set (or the default boxes where nothing is shipped); everyone else, including spectators of a ranked match, gets yours over the shipped ones, as before.
  • Cost: the same as before: one pointer pick per model drawn, decided once a frame. No file is read during a match.
  • overrides::find / readRelative take where to look: FROM_ANY (yours, then the shipped ones; the default), FROM_SHIPPED or FROM_USER. Sounds and the font are unchanged (they don't change what you can see of other players).
  • Test (testOverrides): a user STANDARD.gltf loads and is drawn, and never in ranked; every model's ranked pick is the shipped one.

Every model replaceable: the props (src/client/models.cpp, src/client/game.cpp)

  • Why: the arms, the bomb and the payload objective were drawn box by box inline in drawWorld / drawHeldWeapon, so they had no export and couldn't be overridden. Every other model already could.
  • What: a new model kind, MODEL_PROP (models/prop/<NAME>), built by propParts and drawn through the same parts + override path as players, weapons, projectiles and the crown:
    • GUN_ARM: the arm and gun every other player holds out.
    • ARM: the arm a weapon model is held on in hide and seek and tag.
    • BOMB_PACK: the bomb on a carrier's back (player space).
    • BOMB: the dropped or planted bomb.
    • CART: the payload cart (11 boxes).
    • GATE: a checkpoint gate (both posts).
  • Position, aim, crouch and body size stay transforms in game.cpp (drawProp, drawArm). Colours that change at run time are slots: the bomb's blink is glow (reference: its dark grey); the cart's team, metal, glow and a new accent slot (the map's accent colour, the cart's rim); the gate's team (reference: the unreached grey).
  • Reference palettes are per model (referencePalette(kind, idx)), and overrideTints takes the model, because a prop's reference colours aren't a player's.
  • Defaults are pixel-identical: the same box calls with the same floats. Before / after screenshots of the cart, both gates, the bomb and its backpack, the gun arms and the held-weapon arms compare identical. Same number of boxes per frame.
  • The asset export now writes 30 models (was 24: 5 players, 11 weapons, 7 projectiles, the crown and the 6 props). The provenance registry lists the 6 new ones as AI-made (assets/provenance/models.json). docs/ASSETS.md documents them and fixes stale counts (11 weapons).

Box model files (src/client/gltf.cpp, src/client/models.*, tests)

  • Why: an override was drawn as a plain lit mesh. A model editor export of a player had no outlines, a crouch squashed the whole body, the face plates showed in first person, and the default players' constant-offset colours turned into a plain multiply (the HEAVY / ROBOT / KNIGHT grey is team x 0.6 + 0.06, the SCOUT visor team x 1.8 + 0.3, the ROBOT eye team x 2 + 0.4).
  • What: an override whose first mesh carries its box list (meshes[0].extras.quark, version 2) is drawn by the game's own box path, exactly like a built-in model: 1 px outlines, a crouch squashing only the boxes marked crouch, visOnly boxes (face plates) hidden on your own body, per-box shadows, the same colour formula.
    • ModelPart carries mul / add / teamMul (drawn colour = slot colour x mul + team colour x teamMul + add) and crouch. exportModelParts derives them from the builders (each slot set to black, then white, with the team white; crouch from a half-height build). The export writes them with shadow, visOnly and alpha, at 9 significant digits so the floats come back exactly. An unchanged export put back as an override draws pixel-identically to the default (all 30 checked in screenshots).
    • The triangles in the file are then only for other viewers (Blender, the website, the editor).
  • Checks (once at startup, when the file loads): 1 to 256 boxes, every number finite, centres within 64 m, half sizes over 0 and at most 32 m, colours / mul / add / teamMul from 0 to 16, alpha over 0 and at most 1, known slot names, booleans. A bad box list fails the file and keeps the default (logged). No extras, or another version (the editor's early version 1 notes), is drawn as a mesh as before.
  • Cost: parsed once at startup; drawing goes through overrideBoxParts into the reused box list, so a box override costs what the built-in boxes cost. Not animated in a box override: the rocket's flame flicker, the sticky's core blink and the bubble's wobble (it still spins and turns).
  • Override tints: slots a model's drawing doesn't colour (glow, metal, base, accent on a player or the crown, and so on) now draw as authored (tint 1) on a mesh override. Before, they were tinted by white / reference: a player's glow came out x (1, 1.82, 6.67).
  • Tests: every default model's file round-trips to identical boxes and draws (any palette, crouched) as the built-in model does; 17 bad box lists are refused; the editor's version 1 extras load as a mesh; undriven slots keep the reference.
  • docs/ASSETS.md has the schema ("Box models").

Drawing: the box list reserved once (src/client/models.h, src/client/game.cpp)

  • The list every model is drawn from (parts_) is reserved once at startup for the larger of kMaxDefaultParts = 32 (the tests check no default model has more) and the biggest box override, so drawing never grows it. Why: the props moved into it (up to 11 boxes for the cart), and a growth mid-frame is an allocation on the frame path (a 1% low risk). Per-frame work is unchanged apart from filling that reused list.

Screenshot tooling (src/client/main.cpp, src/client/game.cpp)

  • --cam now also places the camera in a match (the late aim re-read is skipped then), and --models in bomb mode has the lineup carry the bomb (turned away, backpacks showing) with a dropped bomb in front. Why: exact before / after pixel comparisons of the objective props (the cart, the gates, the bomb and its backpack) for the change above.

Model editor (tools/model_editor)

  • A local page that runs from disk (file://) in Chrome or Edge, with no server, no network and no libraries. python3 tools/model_editor/build.py <export> <out> (or build.cmd, default output %USERPROFILE%\Desktop\Quark\model-editor) builds it from quark_tests exportassets: the page plus data/manifest.js (every model with its box list, the shipped model overrides, each map's palette and sun), about 400 KB, Python 3 standard library only. On Windows, tools\model_editor\install.cmd [output folder] does it all from a repository checkout: it builds only quark_tests with MinGW in build-model-editor\, exports the assets and runs build.cmd (non-interactive, opens no browser, safe to re-run).
  • Drawing: a WebGL2 port of the game's dynamic object shader (lighting, shadow map, outlines, translucent pass, sky) in orbit, first-person viewmodel, third-person (gun arm, held weapon, crown), projectile in flight, the --models lineup and a track view with the cart and gates. Checked against the game's own screenshots: model faces match to 0 to 1 of 255, viewmodels 97 to 99% of pixels within 3 / 255.
  • Editing: box by box with fields, picking, a move / resize gizmo, undo / redo; recolouring rewrites mul (keeping add / teamMul while they fit); mul / add / teamMul and the crouch flag are editable; boxes are checked against the game's limits before export. .glb / .gltf import, read as the game's loader reads it.
  • Export: models/<kind>/<NAME>.glb overrides to a folder (File System Access) or a zip, with the box list in the extras, plus a provenance.json sidecar (docs/PROVENANCE.md). Problem checks: the 20 000 triangle limit, bounds, slots the game doesn't drive.