Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/workflows/commit-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,15 @@ jobs:
tools/tests/ui_controller_menu_pump.py \
tools/tests/ui_retained_gate.py \
tools/tests/ui_player_identity.py \
tools/tests/mp_match_artifact_io_state.py \
tools/tests/network_fragment_state.py \
tools/tests/savegame_restore_resources.py \
tools/tests/renderer_vulkan_material_cache.py \
tools/tests/renderer_vulkan_presentation.py \
tools/tests/ui_player_targets.py \
tools/ui/capture_player_identity.py \
tools/ui/capture_text_queries.py \
tools/ui/capture_vote_targets.py \
tools/ui/capture_save_browser.py \
tools/tests/ui_stock_level_load.py \
tools/ui/build_retained_screens.py \
Expand Down Expand Up @@ -968,6 +976,12 @@ jobs:
python tools/tests/ui_controller_menu_pump.py
python tools/tests/ui_retained_gate.py
python tools/tests/ui_player_identity.py
python tools/tests/mp_match_artifact_io_state.py
python tools/tests/network_fragment_state.py
python tools/tests/savegame_restore_resources.py
python tools/tests/renderer_vulkan_material_cache.py
python tools/tests/renderer_vulkan_presentation.py --self-test
python tools/tests/ui_player_targets.py
python tools/tests/ui_stock_level_load.py
python tools/tests/ui_retained_resource_lifecycle.py
python tools/tests/ui_retained_adapter.py
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/push-verification.yml
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,15 @@ jobs:
tools/tests/ui_controller_menu_pump.py \
tools/tests/ui_retained_gate.py \
tools/tests/ui_player_identity.py \
tools/tests/mp_match_artifact_io_state.py \
tools/tests/network_fragment_state.py \
tools/tests/savegame_restore_resources.py \
tools/tests/renderer_vulkan_material_cache.py \
tools/tests/renderer_vulkan_presentation.py \
tools/tests/ui_player_targets.py \
tools/ui/capture_player_identity.py \
tools/ui/capture_text_queries.py \
tools/ui/capture_vote_targets.py \
tools/ui/capture_save_browser.py \
tools/tests/ui_stock_level_load.py \
tools/ui/build_retained_screens.py \
Expand Down Expand Up @@ -972,6 +980,12 @@ jobs:
python tools/tests/ui_controller_menu_pump.py
python tools/tests/ui_retained_gate.py
python tools/tests/ui_player_identity.py
python tools/tests/mp_match_artifact_io_state.py
python tools/tests/network_fragment_state.py
python tools/tests/savegame_restore_resources.py
python tools/tests/renderer_vulkan_material_cache.py
python tools/tests/renderer_vulkan_presentation.py --self-test
python tools/tests/ui_player_targets.py
python tools/tests/ui_stock_level_load.py
python tools/tests/ui_retained_resource_lifecycle.py
python tools/tests/ui_retained_adapter.py
Expand Down
559 changes: 486 additions & 73 deletions content/baseoq4/pak0/guis/menu/mp_escape.q4ui

Large diffs are not rendered by default.

98 changes: 49 additions & 49 deletions content/baseoq4/pak0/guis/menu/settings/controls.q4ui
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,55 @@
"canvas": {"height": 720, "minWidth": 960},
"state": {
"controls.capture": {"type": "number", "initial": -1},
"controls.0.keys": {"type": "string", "initial": ""},
"controls.1.keys": {"type": "string", "initial": ""},
"controls.2.keys": {"type": "string", "initial": ""},
"controls.3.keys": {"type": "string", "initial": ""},
"controls.4.keys": {"type": "string", "initial": ""},
"controls.5.keys": {"type": "string", "initial": ""},
"controls.6.keys": {"type": "string", "initial": ""},
"controls.7.keys": {"type": "string", "initial": ""},
"controls.8.keys": {"type": "string", "initial": ""},
"controls.9.keys": {"type": "string", "initial": ""},
"controls.10.keys": {"type": "string", "initial": ""},
"controls.11.keys": {"type": "string", "initial": ""},
"controls.12.keys": {"type": "string", "initial": ""},
"controls.13.keys": {"type": "string", "initial": ""},
"controls.14.keys": {"type": "string", "initial": ""},
"controls.15.keys": {"type": "string", "initial": ""},
"controls.16.keys": {"type": "string", "initial": ""},
"controls.17.keys": {"type": "string", "initial": ""},
"controls.18.keys": {"type": "string", "initial": ""},
"controls.19.keys": {"type": "string", "initial": ""},
"controls.20.keys": {"type": "string", "initial": ""},
"controls.21.keys": {"type": "string", "initial": ""},
"controls.22.keys": {"type": "string", "initial": ""},
"controls.23.keys": {"type": "string", "initial": ""},
"controls.24.keys": {"type": "string", "initial": ""},
"controls.25.keys": {"type": "string", "initial": ""},
"controls.26.keys": {"type": "string", "initial": ""},
"controls.27.keys": {"type": "string", "initial": ""},
"controls.28.keys": {"type": "string", "initial": ""},
"controls.29.keys": {"type": "string", "initial": ""},
"controls.30.keys": {"type": "string", "initial": ""},
"controls.31.keys": {"type": "string", "initial": ""},
"controls.32.keys": {"type": "string", "initial": ""},
"controls.33.keys": {"type": "string", "initial": ""},
"controls.34.keys": {"type": "string", "initial": ""},
"controls.35.keys": {"type": "string", "initial": ""},
"controls.36.keys": {"type": "string", "initial": ""},
"controls.37.keys": {"type": "string", "initial": ""},
"controls.38.keys": {"type": "string", "initial": ""},
"controls.39.keys": {"type": "string", "initial": ""},
"controls.40.keys": {"type": "string", "initial": ""},
"controls.41.keys": {"type": "string", "initial": ""},
"controls.42.keys": {"type": "string", "initial": ""},
"controls.43.keys": {"type": "string", "initial": ""},
"controls.44.keys": {"type": "string", "initial": ""},
"controls.45.keys": {"type": "string", "initial": ""},
"controls.46.keys": {"type": "string", "initial": ""},
"controls.47.keys": {"type": "string", "initial": ""},
"controls.48.keys": {"type": "string", "initial": ""},
"controls.0.keys": {"type": "string", "initial": "", "keyBinding": "_forward"},
"controls.1.keys": {"type": "string", "initial": "", "keyBinding": "_back"},
"controls.2.keys": {"type": "string", "initial": "", "keyBinding": "_moveleft"},
"controls.3.keys": {"type": "string", "initial": "", "keyBinding": "_moveright"},
"controls.4.keys": {"type": "string", "initial": "", "keyBinding": "_moveUp"},
"controls.5.keys": {"type": "string", "initial": "", "keyBinding": "_moveDown"},
"controls.6.keys": {"type": "string", "initial": "", "keyBinding": "_left"},
"controls.7.keys": {"type": "string", "initial": "", "keyBinding": "_right"},
"controls.8.keys": {"type": "string", "initial": "", "keyBinding": "_strafe"},
"controls.9.keys": {"type": "string", "initial": "", "keyBinding": "_speed"},
"controls.10.keys": {"type": "string", "initial": "", "keyBinding": "_impulse0"},
"controls.11.keys": {"type": "string", "initial": "", "keyBinding": "_impulse1"},
"controls.12.keys": {"type": "string", "initial": "", "keyBinding": "_impulse2"},
"controls.13.keys": {"type": "string", "initial": "", "keyBinding": "_impulse3"},
"controls.14.keys": {"type": "string", "initial": "", "keyBinding": "_impulse4"},
"controls.15.keys": {"type": "string", "initial": "", "keyBinding": "_impulse5"},
"controls.16.keys": {"type": "string", "initial": "", "keyBinding": "_impulse6"},
"controls.17.keys": {"type": "string", "initial": "", "keyBinding": "_impulse7"},
"controls.18.keys": {"type": "string", "initial": "", "keyBinding": "_impulse8"},
"controls.19.keys": {"type": "string", "initial": "", "keyBinding": "_impulse9"},
"controls.20.keys": {"type": "string", "initial": "", "keyBinding": "_impulse10"},
"controls.21.keys": {"type": "string", "initial": "", "keyBinding": "buymenu"},
"controls.22.keys": {"type": "string", "initial": "", "keyBinding": "_quickChat"},
"controls.23.keys": {"type": "string", "initial": "", "keyBinding": "_attack"},
"controls.24.keys": {"type": "string", "initial": "", "keyBinding": "_impulse15"},
"controls.25.keys": {"type": "string", "initial": "", "keyBinding": "_impulse14"},
"controls.26.keys": {"type": "string", "initial": "", "keyBinding": "_impulse13"},
"controls.27.keys": {"type": "string", "initial": "", "keyBinding": "_lookUp"},
"controls.28.keys": {"type": "string", "initial": "", "keyBinding": "_lookDown"},
"controls.29.keys": {"type": "string", "initial": "", "keyBinding": "_mlook"},
"controls.30.keys": {"type": "string", "initial": "", "keyBinding": "centerview"},
"controls.31.keys": {"type": "string", "initial": "", "keyBinding": "_zoom"},
"controls.32.keys": {"type": "string", "initial": "", "keyBinding": "_impulse19"},
"controls.33.keys": {"type": "string", "initial": "", "keyBinding": "_impulse50"},
"controls.34.keys": {"type": "string", "initial": "", "keyBinding": "screenshot"},
"controls.35.keys": {"type": "string", "initial": "", "keyBinding": "_weaponWheel"},
"controls.36.keys": {"type": "string", "initial": "", "keyBinding": "savegame quick"},
"controls.37.keys": {"type": "string", "initial": "", "keyBinding": "loadgame quick"},
"controls.38.keys": {"type": "string", "initial": "", "keyBinding": "clientMessageMode"},
"controls.39.keys": {"type": "string", "initial": "", "keyBinding": "clientMessageMode 1"},
"controls.40.keys": {"type": "string", "initial": "", "keyBinding": "_impulse28"},
"controls.41.keys": {"type": "string", "initial": "", "keyBinding": "_impulse29"},
"controls.42.keys": {"type": "string", "initial": "", "keyBinding": "_ingamestats"},
"controls.43.keys": {"type": "string", "initial": "", "keyBinding": "_impulse17"},
"controls.44.keys": {"type": "string", "initial": "", "keyBinding": "emote salute"},
"controls.45.keys": {"type": "string", "initial": "", "keyBinding": "emote cheer"},
"controls.46.keys": {"type": "string", "initial": "", "keyBinding": "emote taunt"},
"controls.47.keys": {"type": "string", "initial": "", "keyBinding": "emote grab_a"},
"controls.48.keys": {"type": "string", "initial": "", "keyBinding": "_voicechat"},
"page.tab": {"type": "number", "initial": 0},
"page.leaving": {"type": "number", "initial": -1},
"prompt.glyphs": {"type": "number", "initial": 0},
Expand Down
2 changes: 2 additions & 0 deletions content/baseoq4/pak0/strings/brazilian_openq4.lang
Original file line number Diff line number Diff line change
Expand Up @@ -1463,4 +1463,6 @@
"#str_230154" "Dispositivo indisponível"
"#str_230155" "Renderização"
"#str_230156" "O renderizador solicitado está indisponível. O substituto ativo aparece acima."
"#str_231577" "Atualize o servidor."
"#str_231578" "Selecione o jogador novamente."
}
2 changes: 2 additions & 0 deletions content/baseoq4/pak0/strings/czech_openq4.lang
Original file line number Diff line number Diff line change
Expand Up @@ -1463,4 +1463,6 @@
"#str_230154" "Zařízení není dostupné"
"#str_230155" "Vykreslování"
"#str_230156" "Požadovaný renderer není dostupný. Aktivní náhradní renderer je uveden výše."
"#str_231577" "Je nutná aktualizace serveru."
"#str_231578" "Vyberte hráče znovu."
}
2 changes: 2 additions & 0 deletions content/baseoq4/pak0/strings/english_openq4.lang
Original file line number Diff line number Diff line change
Expand Up @@ -1463,4 +1463,6 @@
"#str_230154" "Unavailable device"
"#str_230155" "Rendering"
"#str_230156" "The requested renderer is unavailable. The active fallback is shown above."
"#str_231577" "Server update required."
"#str_231578" "Select the player again."
}
2 changes: 2 additions & 0 deletions content/baseoq4/pak0/strings/french_openq4.lang
Original file line number Diff line number Diff line change
Expand Up @@ -1468,4 +1468,6 @@
"#str_230154" "Périphérique indisponible"
"#str_230155" "Rendu"
"#str_230156" "Le rendu demandé est indisponible. Le rendu de secours actif est indiqué ci-dessus."
"#str_231577" "Mise à jour du serveur requise."
"#str_231578" "Sélectionnez à nouveau le joueur."
}
2 changes: 2 additions & 0 deletions content/baseoq4/pak0/strings/german_openq4.lang
Original file line number Diff line number Diff line change
Expand Up @@ -1463,4 +1463,6 @@
"#str_230154" "Gerät nicht verfügbar"
"#str_230155" "Grafik"
"#str_230156" "Der gewünschte Renderer ist nicht verfügbar. Der aktive Ersatz wird oben angezeigt."
"#str_231577" "Serveraktualisierung erforderlich."
"#str_231578" "Spieler erneut auswählen."
}
2 changes: 2 additions & 0 deletions content/baseoq4/pak0/strings/hungarian_openq4.lang
Original file line number Diff line number Diff line change
Expand Up @@ -1463,4 +1463,6 @@
"#str_230154" "Nem elérhető eszköz"
"#str_230155" "Renderelés"
"#str_230156" "A kért renderelő nem érhető el. Az aktív tartalék renderelő fent látható."
"#str_231577" "Szerverfrissítés szükséges."
"#str_231578" "Válaszd ki újra a játékost."
}
2 changes: 2 additions & 0 deletions content/baseoq4/pak0/strings/italian_openq4.lang
Original file line number Diff line number Diff line change
Expand Up @@ -1468,4 +1468,6 @@
"#str_230154" "Dispositivo non disponibile"
"#str_230155" "Rendering"
"#str_230156" "Il renderer richiesto non è disponibile. Quello di riserva attivo è indicato sopra."
"#str_231577" "Aggiornamento del server richiesto."
"#str_231578" "Seleziona di nuovo il giocatore."
}
2 changes: 2 additions & 0 deletions content/baseoq4/pak0/strings/polish_openq4.lang
Original file line number Diff line number Diff line change
Expand Up @@ -1519,4 +1519,6 @@
"#str_230154" "Urządzenie niedostępne"
"#str_230155" "Renderowanie"
"#str_230156" "Żądany renderer jest niedostępny. Aktywny renderer zastępczy jest widoczny powyżej."
"#str_231577" "Wymagana aktualizacja serwera."
"#str_231578" "Wybierz gracza ponownie."
}
2 changes: 2 additions & 0 deletions content/baseoq4/pak0/strings/russian_openq4.lang
Original file line number Diff line number Diff line change
Expand Up @@ -1519,4 +1519,6 @@
"#str_230154" "Устройство недоступно"
"#str_230155" "Рендеринг"
"#str_230156" "Запрошенный рендерер недоступен. Активный резервный вариант показан выше."
"#str_231577" "Требуется обновление сервера."
"#str_231578" "Выберите игрока заново."
}
2 changes: 2 additions & 0 deletions content/baseoq4/pak0/strings/spanish_openq4.lang
Original file line number Diff line number Diff line change
Expand Up @@ -1463,4 +1463,6 @@
"#str_230154" "Dispositivo no disponible"
"#str_230155" "Renderizado"
"#str_230156" "El renderizador solicitado no está disponible. El alternativo activo se muestra arriba."
"#str_231577" "Se requiere actualizar el servidor."
"#str_231578" "Selecciona al jugador de nuevo."
}
2 changes: 2 additions & 0 deletions content/baseoq4/pak0/strings/turkish_openq4.lang
Original file line number Diff line number Diff line change
Expand Up @@ -1463,4 +1463,6 @@
"#str_230154" "Aygıt kullanılamıyor"
"#str_230155" "İşleme"
"#str_230156" "İstenen işleyici kullanılamıyor. Etkin yedek işleyici yukarıda gösteriliyor."
"#str_231577" "Sunucu güncellemesi gerekli."
"#str_231578" "Oyuncuyu yeniden seçin."
}
2 changes: 2 additions & 0 deletions content/baseoq4/pak0/strings/ukrainian_openq4.lang
Original file line number Diff line number Diff line change
Expand Up @@ -1463,4 +1463,6 @@
"#str_230154" "Пристрій недоступний"
"#str_230155" "Рендеринг"
"#str_230156" "Запитаний рендерер недоступний. Активний резервний варіант показано вище."
"#str_231577" "Потрібне оновлення сервера."
"#str_231578" "Виберіть гравця знову."
}
59 changes: 59 additions & 0 deletions docs/dev/release-completion.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,37 @@ Later implementation and validation entries below are unreleased development
work. Historical CI/publication success does not restore the withdrawn release.
See [player release status](../user/release-status.md).

## Kick votes keep their selected player, 4 November 2026

- A changing player list can no longer redirect a retained kick choice or a
delayed kick-vote request to someone who reused the connection slot.
- If the selected player leaves, the Vote page asks you to select again.
Other drafted changes wait too, so a mixed vote cannot silently lose its kick.
- Install matching engine, multiplayer module and menus. Remote kick votes
require an updated server; ordinary non-kick votes keep their existing format.

## Retained interface text queries, 4 November 2026

- Interface authors can request localized key-binding labels and measure how
much plain text fits a retained label. Measurements follow its font, text
size and available width and preserve complete UTF-8 characters.
- CONTROLS uses the shared binding-name path for its existing capture, clear
and rebind behavior. Install matching engine and menu content together.
- This is a toolkit increment; full IME, complex-script shaping and the visual
editor remain in development. See [the text and binding contract](ui/bindings.md#public-key-binding-refresh-4-november-2026).

## Multiplayer menu player targets, 3 November 2026

- Mute and unmute requests and the Admin menu's player actions stay attached
to the player selected, even if someone else takes that connection slot
before the request arrives. Kick votes are cancelled if their target leaves
before execution.
- Install the matching engine, multiplayer module and menu package together.
On older servers, muting remains local and remote menu player administration
requires an updated server; direct console administration is unchanged.
- The remaining vote-request and Match Control identity work stays open under
UI-03. See [the implementation contract](ui/player-identity.md#mute-vote-and-admin-targets-3-november-2026).

## Immediate resaves and interrupted loads, 3 November 2026

- **Saving immediately after loading now produces a loadable save.** This also
Expand All @@ -31,6 +62,34 @@ See [player release status](../user/release-status.md).
11 existing 0.9–0.13 release fixtures restore with their inputs unchanged.
The engine's save readers have not changed.

## Vulkan shader editing and engine captures, 3 November 2026

- **Long shader-editing sessions keep working.** Vulkan now reclaims obsolete
compiled sources when their storage fills, avoiding missing material stages
after repeated edits to large shaders. Programs still used by the current
frame remain protected.
- **HDR cubemap captures preserve the intended brightness.** In-frame engine
captures now use the same floating-point scene target as an ordinary HDR
view, with correct viewport size and main-view recovery. This extends the
internal linear-HDR laboratory; it does not add HDR monitor output.
- **Failed captures report failure.** An incomplete screenshot write no longer
reports success. Cubemap capture stops at the failed face, and incomplete
reflection probes are not reloaded.
- Developer evidence: live shader-edit tests cover both the 256-version and
32 MiB limits with exact image recovery. The 4x and 8x MSAA capture suites each
pass 121 GL/Vulkan pairs, and the HDR post/cubemap suite passes 42, all within one
display level. Native cache/compiler/device/report contracts pass. See
[authored programs](vulkan-material-programs.md), [captures](vulkan-captures.md)
and [HDR](vulkan-hdr.md) for scope and retained failing controls.
- Opt-in resource counters and a visible, input-disabled pacing harness now
collect the evidence needed for later Vulkan optimization and presentation
qualification. They do not promote another driver/platform or claim a
performance improvement. Open gates remain in [the roadmap](roadmap.md).
Current visible diagnostics retained a missed NVIDIA presentation budget,
unavailable Intel presentation timing and unsuccessful foreground checks;
these remain failures. The harness now pins one performance preset across
GPUs and verifies both its saved settings and CPU/GPU evidence identity.

## Saves tested between Windows and Linux, 3 November 2026

- **New saves made on Windows restore on Linux, and the other way round.** The
Expand Down
Loading
Loading