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
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ install(DIRECTORY "${VGUI2EXTENSION_GAMEDATA_DIR}/" DESTINATION svencoop/metahoo
option(VGUI2EXTENSION_BUILD_TESTS "Build existing language and IME regression tests" OFF)
if(VGUI2EXTENSION_BUILD_TESTS)
enable_testing()
foreach(test language_registry_tests ime_window_message_test combobox_unicode_tests career_player_name_tests teammenu_hook_tests default_server_name_tests career_popup_order_tests career_profile_storage_tests buildmode_layout_tests)
foreach(test language_registry_tests ime_window_message_test combobox_unicode_tests career_player_name_tests teammenu_hook_tests default_server_name_tests career_popup_order_tests career_profile_storage_tests buildmode_layout_tests career_end_menu_tests)
add_executable(${test} "tests/${test}.cpp")
target_compile_features(${test} PRIVATE cxx_std_17)
target_compile_options(${test} PRIVATE /W4 /WX /UNDEBUG)
Expand Down
22 changes: 17 additions & 5 deletions docs/en/gamedata.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ The Career round-end ESC fix additionally requires the client `CCSCareerRoundEnd
vtable and the virtual slots of `vgui2::Frame::OnKeyCodePressed(vgui2::KeyCode)` and
`vgui2::Frame::OnKeyCodeTyped(vgui2::KeyCode)`, requested in
[GoldSrc_VibeSignatures #397](https://github.com/HLND2T/GoldSrc_VibeSignatures/issues/397).
Only the RoundEnd table is hooked: ESC leaves the pending choice intact while the
The RoundEnd table is hooked: ESC leaves the pending choice intact while the
engine toggles GameUI; other keys and the original button commands are forwarded.
Both key-code paths are protected, including the Typed app-modal close path.
These three records are published in `v20261023a`. An older catalog fails the
Expand All @@ -104,6 +104,16 @@ retain their native handlers. This fourth record is published in `v20261023b`;
deploy the final DLL with that catalog or newer. `v20261023a` does not satisfy
the extended manifest.

The MatchEnd ESC fix also requires the client `CCSCareerMatchEndMenu` vtable and
`CCSCareerMatchEndMenu::OnCommand(char const*)` virtual slot. It applies the same
key and generic-command guards to MatchEnd's own table, preserving the current
music and pending choice while GameUI toggles. Finish, retry and Credits retain
their native handlers. Both Frame key slots are shared with RoundEnd; no shared
Frame implementation or music handler is patched. These two MatchEnd records,
requested in [GoldSrc_VibeSignatures #409](https://github.com/HLND2T/GoldSrc_VibeSignatures/issues/409),
are published in `v20261026a`. Deploy that catalog or newer with this DLL on
`czero`; older catalogs fail the extended manifest.

The native build editor DPI hooks require `v20261025b` or newer. They hook the
GameUI constructor and the editor/list vtables, retaining native editing, saving
and ownership. Only editor lists receive the row/column and scrollbar correction.
Expand All @@ -115,19 +125,19 @@ casting native containers or the dialog to the SDK's private classes.

The declaration is [scripts/manifests/vgui2extension.json](../../scripts/manifests/vgui2extension.json).
The list below follows its exact module, name and kind and has been checked against the
source calls. It contains **256 distinct explicit records** across 5 modules,
source calls. It contains **258 distinct explicit records** across 5 modules,
including the initial `_0` records of the conditional numbered patch sets
(23 declarations). Each numbered set can consume additional records; 256 is not
(23 declarations). Each numbered set can consume additional records; 258 is not
the total size of every installed catalog.

| Module | Explicit entries |
| --- | ---: |
| `engine` | 14 |
| `client` | 37 |
| `client` | 39 |
| `gameui` | 195 |
| `serverbrowser` | 9 |
| `vgui2` | 1 |
| Total | 256 |
| Total | 258 |

A GameSymbol is identified by its module and name. Identical names in `engine`, `client`,
`gameui` and `serverbrowser` refer to separate records. Conditions below describe the
Expand Down Expand Up @@ -227,6 +237,8 @@ Sources: [ClientVGUI.cpp](../../src/ClientVGUI.cpp) and [privatefuncs.cpp](../..
| `CCareerBaseBox::s_currentBox` | `global` | G24 |
| `CCSCareerRoundEndMenu` | `vtable` | G24 |
| `CCSCareerRoundEndMenu::OnCommand(char const*)` | `virtualFunction` | G24 |
| `CCSCareerMatchEndMenu` | `vtable` | G24 |
| `CCSCareerMatchEndMenu::OnCommand(char const*)` | `virtualFunction` | G24 |
| `vgui2::Frame::OnKeyCodePressed(vgui2::KeyCode)` | `virtualFunction` | G24 |
| `vgui2::Frame::OnKeyCodeTyped(vgui2::KeyCode)` | `virtualFunction` | G24 |
| `CounterStrikeViewport.m_pCSBackGround` | `structMember` | G8 |
Expand Down
20 changes: 15 additions & 5 deletions docs/zh-CN/gamedata.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ CRT locale,也不经过原有的 31 字节截断。无效 UTF-8 或缺失本
`vgui2::Frame::OnKeyCodePressed(vgui2::KeyCode)`、
`vgui2::Frame::OnKeyCodeTyped(vgui2::KeyCode)` 的虚槽位,已通过
[GoldSrc_VibeSignatures #397](https://github.com/HLND2T/GoldSrc_VibeSignatures/issues/397)
请求补齐。仅修改 RoundEnd 的虚表:ESC 保留待确认窗口,引擎仍切换主菜单;其他按键与
请求补齐。修改 RoundEnd 的虚表:ESC 保留待确认窗口,引擎仍切换主菜单;其他按键与
原有按钮命令照常处理。两个 KeyCode 入口均受保护,包括 Typed 的 app-modal 关闭路径。
这三项记录已在 `v20261023a` 发布,旧 catalog 无法通过扩展后的 manifest,也无法在
`czero` 中运行此 DLL;应搭配匹配 catalog 部署。其他游戏不解析或安装这组 hook。
Expand All @@ -84,6 +84,14 @@ CRT locale,也不经过原有的 31 字节截断。无效 UTF-8 或缺失本
保留待确认的 Career 选择;业务命令继续由原生处理。这第四项记录已在 `v20261023b`
发布;最终 DLL 应搭配该版本或更新 catalog,`v20261023a` 不满足扩展后的 manifest。

MatchEnd 的 ESC 修复还需要 client 的 `CCSCareerMatchEndMenu` 虚表与
`CCSCareerMatchEndMenu::OnCommand(char const*)` 虚槽位。相同的按键和通用命令保护安装在
MatchEnd 自己的虚表上,切换 GameUI 时保留当前音乐和待确认选择;完成、重试、Credits
继续交给原生处理。两个 Frame 按键槽位与 RoundEnd 共用,不修改共享 Frame 实现或音乐处理。
这两项记录已通过 [GoldSrc_VibeSignatures #409](https://github.com/HLND2T/GoldSrc_VibeSignatures/issues/409)
请求补齐,已在 `v20261026a` 发布。在 `czero` 使用此 DLL 时,应部署该版本或更新的
catalog;旧版本无法通过扩展后的 manifest 校验。

原生构建编辑器 DPI hook 需要 `v20261025b` 或更新版本。它们 hook GameUI 构造入口和
编辑器/列表虚表,保留原生编辑、保存和所有权行为;行列布局及滚动条修正只作用于编辑器列表。
原生编辑器继承 Frame 的 scheme 处理,子控件已使用比例字体,因此不修改共享 Frame 函数。
Expand All @@ -92,17 +100,17 @@ CRT locale,也不经过原有的 31 字节截断。无效 UTF-8 或缺失本

声明来源为 [scripts/manifests/vgui2extension.json](../../scripts/manifests/vgui2extension.json)。
以下清单保留 manifest 中的完整 module、名称与 kind,并已对照源码调用核对。
共 5 个 module、**256 条不同的显式记录**,其中包含条件编号补丁组的首条 `_0` 记录
(共 23 处声明)。每组编号补丁还可能消费后续记录,因此 256 不是每份安装 catalog 的记录总数。
共 5 个 module、**258 条不同的显式记录**,其中包含条件编号补丁组的首条 `_0` 记录
(共 23 处声明)。每组编号补丁还可能消费后续记录,因此 258 不是每份安装 catalog 的记录总数。

| Module | 显式记录数 |
| --- | ---: |
| `engine` | 14 |
| `client` | 37 |
| `client` | 39 |
| `gameui` | 195 |
| `serverbrowser` | 9 |
| `vgui2` | 1 |
| 合计 | 256 |
| 合计 | 258 |

GameSymbol 由 module 与名称共同定位。`engine`、`client`、`gameui`、`serverbrowser`
中的同名符号是独立记录。下列条件表示 manifest 的 catalog 裁剪与校验范围;
Expand Down Expand Up @@ -199,6 +207,8 @@ GameSymbol 由 module 与名称共同定位。`engine`、`client`、`gameui`、`
| `CCareerBaseBox::s_currentBox` | `global` | G24 |
| `CCSCareerRoundEndMenu` | `vtable` | G24 |
| `CCSCareerRoundEndMenu::OnCommand(char const*)` | `virtualFunction` | G24 |
| `CCSCareerMatchEndMenu` | `vtable` | G24 |
| `CCSCareerMatchEndMenu::OnCommand(char const*)` | `virtualFunction` | G24 |
| `vgui2::Frame::OnKeyCodePressed(vgui2::KeyCode)` | `virtualFunction` | G24 |
| `vgui2::Frame::OnKeyCodeTyped(vgui2::KeyCode)` | `virtualFunction` | G24 |
| `CounterStrikeViewport.m_pCSBackGround` | `structMember` | G8 |
Expand Down
14 changes: 14 additions & 0 deletions memory/build_and_verification.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,17 @@ Chinese numeric-format follow-up: GetCurrentGameLanguage() values schinese/tchin
- Verification: MSVC x86 Release build,9 CTests (new geometry bounds/font/resize/repeated-calculation tests),11 Python tests, pinned70-file format-check and git diff --check passed. Live final layout:720p300x400/row24,1080p450x600/row36,1440p600x800/row48, no horizontal row overflow or clipped scrollbar. Native mouse resized600x800 to780x940, moved to[780,220], and Exit/reopen retained that exact pixel geometry. Selecting Options ApplyButton rebuilt rows at48px; native button drag/save wrote xpos614/ypos391/wide72/tall24 for a144x48px button, and subsequent launches loaded the saved resource. Scroll drag reached the last rows. Final source cleanup only named the same design constants and removed a duplicate idempotent row-sizing pass; compilation/tests reran afterward, the full live matrix preceded that cleanup.
- Verification limits: activation used the existing Options BuildGroup SetEnabled on the main RunFrame thread, then debugger detachment; physical Shift+Ctrl+Alt+B routing remains unverified because CLI injection did not trigger creation. Requested3840x2160 was clamped to3440x1440, so4K is not runtime verified. Existing DpiManagerInternal::InitClient forces support true for HL25 after command-line flags; -no_high_dpi therefore did not test an actual disabled-DPI path. Other builds/custom schemes have catalog coverage only.
- Cleanup/evidence: ten task-owned processes exited normally via RCON code0; no debugger sessions remain.72 original DLL/PDB/catalog/config/resource/appid files restored with SHA256 verification;11 task screenshots moved into ignored build/issue954-fix-runtime/screenshots. Evidence includes installed-hooks.txt,matrix.json,result.md,saved-options-dialog.res and restoration.json. Do not publish config backups or screenshots automatically. Original game deployment is restored.


## Issue 957: MatchEnd ESC replays MatchWin (2026-10-26)

- Trigger: czero engine10210 Career match victory; repeated ESC/GameUI round trips replay MatchWin. MatchEnd is outside bea92c5's RoundEnd-only hooks.
- Root cause/constraint: inherited Frame ESC posts Cancel (Pressed) and has an app-modal Close path (Typed). MatchEnd::OnCommand treats generic commands as native completion: unpause, OnClose, OnMatchEndMenuClose(false). GameUI sets canUnpause=true and calls FadeOutTrack, which immediately resets currentTrack=INVALID while issuing cd fadeout. The completed server match keeps its due m_fCareerMatchMenuTime; Think resends CZCareer/MATCH and CZCareerHUD/MATCH after unpause. MatchEnd::Update -> OnMatchEndMenuOpen -> StartTrack(5,false) then restarts because the current-track identity was reset. Engine ESC toggling can still cause repeated MATCH after this fix; preserving currentTrack=5 lets the native same-track guard suppress actual playback.
- Static evidence: requested Windows/Linux10210 client/GameUI IDBs plus czero10210/server/cs.so.i64 inspected read-only. Windows MatchEnd AP0x100C8688, OnCommand0x1002B810, Update0x1002B9C0; Linux AP0x17F34C, OnCommand0x82610, Update0x81CE0. GameUI MatchClose0x10014490/0x624F0, FadeOut0x10030820/0x8A990, MatchOpen0x100144F0/0x62490, StartTrack0x10030AB0/0x8A7E0. Server send/pause block0xACE50-0xACF68 leaves the deadline intact. Addresses are analysis observations, not runtime hardcodes. All task IDA workers closed without saving.
- Correct implementation: czero excluding CZDS; three hooks on MatchEnd's own primary table share ForwardCareerEndMenuKey/Command with RoundEnd. Ignore ESC Pressed/Typed and exact case-insensitive generic Close/Cancel; forward other keys/business commands unchanged. Six-hook rollback/shutdown restores slots and resets pointers. Resolve shared Frame key slots and new MatchEnd table/OnCommand through required host gamedata. No music/server/global Frame patch. Manifest and bilingual inventory258 explicit records (client39).
- Published dependency: user-authorized upstream request GoldSrc_VibeSignatures #409 (https://github.com/HLND2T/GoldSrc_VibeSignatures/issues/409), fulfilled by v20261026a. Official Pages sync now downloads23 snapshots; real sync/prune and manifest validation all23 pass. Reconfigured VGUI2EXTENSION_SYNC_GAMEDATA=ON (local cache had been OFF), then normal MSVC x86 Release build of VGUI2Extension and career_end_menu_tests passed with project dependencies enabled. Old catalog remains incompatible. No local fake records or hand-patched runtime catalog.
- Local verification: forwarding test red before helper, then green; all10 CTests and11 Python tests passed, pinned clang-format checked72 files with zero differences, git diff --check passed. Existing signedness and /UNDEBUG warnings remain. Mock tests prove filtering and original argument/callback forwarding only.
- Runtime verification: official catalog + final code on Windows czero10210. Actual native table inspection verified all six installed slots. Independent temporary profile and backed-up Easy first-map fixture (one win/one margin, no task) used native Career menus and real server round completion, not injected MATCH. First victory baseline counters [StartTrack5 entry=1, Fade=1, Update=2, native MatchCommand=1, ESC pressed/typed=0/0, actual play=1]; prior Fade/MatchCommand came from defeat Retry. After6 ESC round trips: [7,1,8,1,6/6,1], currentTrack=5. Thus updates/StartTrack entries repeat but actual playback, fade and native completion do not. Second victory plus4 later ESC round trips: total actual plays2 (one per match), currentTrack5. Track file duration29.276188s; later switching occurred after that duration. Earlier process tested4 early round trips with currentTrack5 and zero fade/native command; actual-play trace was installed afterward, so do not attribute that counter to the earlier run.
- Business/lifecycle verification: native defeat Retry forwarded career_restart and restarted; victory Enter default forwarded disconnect and returned CareerMapFrame. At shutdown, breakpoint after UninstallCareerEndMenuHooks confirmed all six slots restored to native client functions (Match command RVA0x2B810; Round command0x2CBC0; both pressed0x7BFB0/typed0x7C0A0). All three task processes16768/34656/35904 exited normally, code0. Debuggers detached/closed.
- Cleanup/evidence:44 original DLL/PDB/catalog/config/profile/appid files restored and SHA256 verified. Task-created selected files and BMPs moved into ignored build/issue957-runtime, preserving original files/screenshots. Evidence result.json, restoration.json and screenshots remain local; do not publish backups automatically. Only the plugin source, regression tests, manifest, documentation and this verification note belong in the change; ignored runtime evidence and game backups remain local.
- Limits/applicability: no captured audio or stream-position trace; playback-command instrumentation establishes no additional play call, not audible output quality. Credits and RoundEnd choice/default-button/surrender branches were not reached in live verification (normal campaign trial did not show RoundEnd); forwarding unit tests and static boundary cover those commands only. Windows8684 has official catalog validation; Linux has static evidence; neither has runtime qualification. No broader compatibility claim.
2 changes: 2 additions & 0 deletions scripts/manifests/vgui2extension.json
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,8 @@
"CCareerBaseBox::s_currentBox": "global",
"CCSCareerRoundEndMenu": "vtable",
"CCSCareerRoundEndMenu::OnCommand(char const*)": "virtualFunction",
"CCSCareerMatchEndMenu": "vtable",
"CCSCareerMatchEndMenu::OnCommand(char const*)": "virtualFunction",
"vgui2::Frame::OnKeyCodePressed(vgui2::KeyCode)": "virtualFunction",
"vgui2::Frame::OnKeyCodeTyped(vgui2::KeyCode)": "virtualFunction"
}
Expand Down
22 changes: 22 additions & 0 deletions src/CareerEndMenuInput.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <cstring>

//ESC only switches GameUI. Keep the pending Career choice and music state
//intact when the completed match sends MATCH again.
template <typename Handler, typename KeyCode>
void ForwardCareerEndMenuKey(Handler original, void* self, int dummy, KeyCode key, KeyCode escapeKey)
{
if (key != escapeKey)
original(self, dummy, key);
}

template <typename Handler>
void ForwardCareerEndMenuCommand(Handler original, void* self, int dummy, const char* command)
{
//Child dialogs can forward the same generic close commands as Frame.
if (command && (!_stricmp(command, "Close") || !_stricmp(command, "Cancel")))
return;

original(self, dummy, command);
}
Loading
Loading