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)
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)
add_executable(${test} "tests/${test}.cpp")
target_compile_features(${test} PRIVATE cxx_std_17)
target_compile_options(${test} PRIVATE /W4 /WX /UNDEBUG)
Expand Down
1 change: 1 addition & 0 deletions cmake/Sources.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ set(VGUI2EXTENSION_SOURCES
"${METAHOOK_SOURCE_PATH}/include/vgui_controls/MemoryBitmap.cpp"
"${METAHOOK_SOURCE_PATH}/include/SourceSDK/tier0/vcrmode.cpp"
"src/BaseUI.cpp"
"src/BuildModeDialogHooks.cpp"
"src/ClientVGUI.cpp"
"src/CounterStrikeViewport.cpp"
"src/CareerProfileStorage.cpp"
Expand Down
45 changes: 37 additions & 8 deletions docs/en/gamedata.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,30 @@ 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 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.
The native editor inherits Frame's scheme handler and already uses proportional
child fonts, so no shared Frame function is patched. Persisted window dimensions
remain pixels; only missing defaults and design constants are scaled. List item
IDs come from the two individually published `m_SortedItems` fields, without
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 **226 explicit records** across 5 modules, including the
initial `_0` records of **19 numbered patch sets**. Each numbered set can consume
additional records; 226 is not the total size of every installed catalog.
source calls. It contains **256 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
the total size of every installed catalog.

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

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 All @@ -143,7 +153,7 @@ API 115's `mh_gamesymbol_t::vfuncIndex`.

### Manifest conditions

`All` is the manifest's top-level `gameVersions` list. `G1` through `G26` identify the
`All` is the manifest's top-level `gameVersions` list. `G1` through `G28` identify the
current `conditionalGroups` entries in order. The `cl_time` exemption is explained under
[Runtime conditions and optional records](#runtime-conditions-and-optional-records).

Expand Down Expand Up @@ -175,7 +185,9 @@ current `conditionalGroups` entries in order. The `cl_time` exemption is explain
| G23 | `hl-10210` |
| G24 | `czero-10210`, `czero-8684` |
| G25 | `hl-10210` |
| G26 | `hl-10210` |
| G26 | `hl-10210`, `hl-8684`, `cstrikegameui-8684` |
| G27 | `cstrikegameui-8684` |
| G28 | `cof-5936`, `cstrikegameui-8684`, `hl-10210`, `hl-3248`, `hl-3266`, `hl-3329`, `hl-3647`, `hl-4554`, `hl-6153`, `hl-8684`, `svencoop-10257`, `svencoop-8948` |

## Symbols by module

Expand Down Expand Up @@ -249,7 +261,8 @@ Sources: [ClientVGUI.cpp](../../src/ClientVGUI.cpp) and [privatefuncs.cpp](../..

### gameui

Source: [GameUI.cpp](../../src/GameUI.cpp).
Sources: [GameUI.cpp](../../src/GameUI.cpp) and
[BuildModeDialogHooks.cpp](../../src/BuildModeDialogHooks.cpp).

| GameSymbol | Kind | Manifest condition |
| --- | --- | --- |
Expand Down Expand Up @@ -327,6 +340,22 @@ Source: [GameUI.cpp](../../src/GameUI.cpp).
| `vgui2_Panel_SetMinimumSize_Const_callsite_0` | `patch` | G16 |
| `vgui2_Panel_SetBounds_Const_callsite_0` | `patch` | G16 |
| `vgui2_Panel_SetBounds_Const_callsite_0` | `patch` | G18 |
| `vgui2::BuildModeDialog` | `vtable` | G28 |
| `vgui2::BuildModeDialog::BuildModeDialog(vgui2::BuildGroup*)` | `function` | G28 |
| `vgui2::BuildModeDialog::PerformLayout()` | `virtualFunction` | G28 |
| `vgui2::BuildModeDialog::SetActiveControl(vgui2::Panel*)` | `virtualFunction` | G28 |
| `vgui2::BuildModeDialog.m_pAddNewControlCombo` | `structMember` | G28 |
| `vgui2::Frame::GetClientArea(int&, int&, int&, int&)` | `virtualFunction` | G28 |
| `vgui2::Panel::GetVPanel()` | `virtualFunction` | G28 |
| `vgui2::PanelListPanel` | `vtable` | G28 |
| `vgui2::PanelListPanel::PerformLayout()` | `virtualFunction` | G28 |
| `vgui2::PanelListPanel::GetItemCount()` | `virtualFunction` | G28 |
| `vgui2::PanelListPanel::GetItemLabel(int)` | `virtualFunction` | G28 |
| `vgui2::PanelListPanel::GetItemPanel(int)` | `virtualFunction` | G28 |
| `vgui2::PanelListPanel.m_SortedItems_m_pMemory` | `structMember` | G28 |
| `vgui2::PanelListPanel.m_SortedItems_m_Size` | `structMember` | G28 |
| `vgui2::PanelListPanel.m_iFirstColumnWidth` | `structMember` | G28 |
| `vgui2::PanelListPanel.m_iPanelBuffer` | `structMember` | G28 |

### serverbrowser

Expand Down
39 changes: 32 additions & 7 deletions docs/zh-CN/gamedata.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,19 +84,25 @@ CRT locale,也不经过原有的 31 字节截断。无效 UTF-8 或缺失本
保留待确认的 Career 选择;业务命令继续由原生处理。这第四项记录已在 `v20261023b`
发布;最终 DLL 应搭配该版本或更新 catalog,`v20261023a` 不满足扩展后的 manifest。

原生构建编辑器 DPI hook 需要 `v20261025b` 或更新版本。它们 hook GameUI 构造入口和
编辑器/列表虚表,保留原生编辑、保存和所有权行为;行列布局及滚动条修正只作用于编辑器列表。
原生编辑器继承 Frame 的 scheme 处理,子控件已使用比例字体,因此不修改共享 Frame 函数。
已保存的窗口尺寸保持像素单位,仅缩放缺失的默认尺寸和设计常量。列表 item ID 通过独立发布的
两个 `m_SortedItems` 字段读取,不将原生容器或对话框强转为 SDK 私有类。

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

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

GameSymbol 由 module 与名称共同定位。`engine`、`client`、`gameui`、`serverbrowser`
中的同名符号是独立记录。下列条件表示 manifest 的 catalog 裁剪与校验范围;
Expand All @@ -120,7 +126,7 @@ GameSymbol 由 module 与名称共同定位。`engine`、`client`、`gameui`、`

### Manifest 条件

`All` 表示 manifest 顶层的 `gameVersions` 列表;`G1` 至 `G26` 按顺序对应当前
`All` 表示 manifest 顶层的 `gameVersions` 列表;`G1` 至 `G28` 按顺序对应当前
`conditionalGroups` 的条目。`cl_time` 的豁免见[运行条件与可选记录](#运行条件与可选记录)。

| 条件 | Manifest 中的 gameVersions |
Expand Down Expand Up @@ -151,7 +157,9 @@ GameSymbol 由 module 与名称共同定位。`engine`、`client`、`gameui`、`
| G23 | `hl-10210` |
| G24 | `czero-10210`, `czero-8684` |
| G25 | `hl-10210` |
| G26 | `hl-10210` |
| G26 | `hl-10210`, `hl-8684`, `cstrikegameui-8684` |
| G27 | `cstrikegameui-8684` |
| G28 | `cof-5936`, `cstrikegameui-8684`, `hl-10210`, `hl-3248`, `hl-3266`, `hl-3329`, `hl-3647`, `hl-4554`, `hl-6153`, `hl-8684`, `svencoop-10257`, `svencoop-8948` |

## 按 module 列出的符号

Expand Down Expand Up @@ -225,7 +233,8 @@ GameSymbol 由 module 与名称共同定位。`engine`、`client`、`gameui`、`

### gameui

源码:[GameUI.cpp](../../src/GameUI.cpp)。
源码:[GameUI.cpp](../../src/GameUI.cpp) 和
[BuildModeDialogHooks.cpp](../../src/BuildModeDialogHooks.cpp)。

| GameSymbol | Kind | Manifest 条件 |
| --- | --- | --- |
Expand Down Expand Up @@ -303,6 +312,22 @@ GameSymbol 由 module 与名称共同定位。`engine`、`client`、`gameui`、`
| `vgui2_Panel_SetMinimumSize_Const_callsite_0` | `patch` | G16 |
| `vgui2_Panel_SetBounds_Const_callsite_0` | `patch` | G16 |
| `vgui2_Panel_SetBounds_Const_callsite_0` | `patch` | G18 |
| `vgui2::BuildModeDialog` | `vtable` | G28 |
| `vgui2::BuildModeDialog::BuildModeDialog(vgui2::BuildGroup*)` | `function` | G28 |
| `vgui2::BuildModeDialog::PerformLayout()` | `virtualFunction` | G28 |
| `vgui2::BuildModeDialog::SetActiveControl(vgui2::Panel*)` | `virtualFunction` | G28 |
| `vgui2::BuildModeDialog.m_pAddNewControlCombo` | `structMember` | G28 |
| `vgui2::Frame::GetClientArea(int&, int&, int&, int&)` | `virtualFunction` | G28 |
| `vgui2::Panel::GetVPanel()` | `virtualFunction` | G28 |
| `vgui2::PanelListPanel` | `vtable` | G28 |
| `vgui2::PanelListPanel::PerformLayout()` | `virtualFunction` | G28 |
| `vgui2::PanelListPanel::GetItemCount()` | `virtualFunction` | G28 |
| `vgui2::PanelListPanel::GetItemLabel(int)` | `virtualFunction` | G28 |
| `vgui2::PanelListPanel::GetItemPanel(int)` | `virtualFunction` | G28 |
| `vgui2::PanelListPanel.m_SortedItems_m_pMemory` | `structMember` | G28 |
| `vgui2::PanelListPanel.m_SortedItems_m_Size` | `structMember` | G28 |
| `vgui2::PanelListPanel.m_iFirstColumnWidth` | `structMember` | G28 |
| `vgui2::PanelListPanel.m_iPanelBuffer` | `structMember` | G28 |

### serverbrowser

Expand Down
10 changes: 10 additions & 0 deletions memory/build_and_verification.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,13 @@ Chinese numeric-format follow-up: GetCurrentGameLanguage() values schinese/tchin
- Verification: Windows x86 Release build, 66-file format-check, all 8 existing CTests and staged install passed. Live czero build 10210 at 1280x720 used a task-only empty-Maps mission pack to exercise the same no-triplet branch without removing stock data: schinese title/body rendered correctly (HalfLife44.tga), English title/body rendered correctly (HalfLife46.tga), and a fresh schinese process with both plugin language files absent retained literal English without displaying keys (HalfLife48.tga). OK dismissed the modal back to profile selection. This validates the native error branch, not a direct deleted-Normal.vdf reproduction; checksum failure and other engine builds were not separately exercised.
- Cleanup: all task-owned game processes exited cleanly. Temporary fixture, profile and screenshots were moved into ignored `build/issue952-runtime/`; 21 preexisting game files were restored and SHA256-verified. Evidence screenshots remain under `build/issue952-runtime/screenshots/`.
- Scope: localization only; mission-data validation, fallback selection, modal behavior and storage are unchanged. Existing gamedata sync was disabled in the local cache; no claim is made about a newly downloaded online catalog.

## Issue 954: native BuildModeDialog high-DPI layout (2026-10-25)

- Trigger: czero engine10210 at2560x1440; native editor stayed300x400 while caption/scrollbar and scheme fonts scaled. The Options editor comes from GameUI, with an empty panel name and `vgui2` RTTI, rather than the plugin's compiled SDK editor.
- Root cause/constraints: native constructor and outer PerformLayout retain literal pixel dimensions/margins; its PanelListPanel additionally uses fixed horizontal insets, overflows its embedded content width and disables its scrollbar. The native editor inherits Frame::ApplySchemeSettings; SDK-only navigation/localization controls and the newer SDK scheme override are absent. Replacing SDK objects would cross incompatible private class/BuildGroup layouts.
- Implementation: BuildModeDialogHooks.{h,cpp} integrates with GameUI fill/install/uninstall. Resolve constructor, editor/list tables, slots and individually published fields through gamedata. Hook constructor for missing default dimensions/minimum size while preserving native pixel user config; hook only editor PerformLayout/SetActiveControl table slots and list PerformLayout filtered by exact parent editor table. Original layout runs first; row sizing runs before native list range calculation, then editor-specific row/scrollbar geometry accounts for actual insets. VPANEL/IPanel access avoids SDK private object/container casts, child-index guesses and TLS. Native proportional fonts remain native; measure font heights once as actual pixels. Failed hook installation rolls back all four hooks; shutdown removes them.
- Catalog: public GoldSrc_VibeSignatures v20261025b,16 consumed gameui records in G28 across12 Windows GameUI identities; two m_SortedItems field offsets provide row IDs, with native GetItemLabel/GetItemPanel. Frame::ApplySchemeSettings is not consumed because no shared base hook is needed. Manifest/bilingual inventory synchronized; current distinct explicit inventory256 (gameui195). Actual online sync/prune and validate-only/standalone validation passed for23 snapshots.
- 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.
36 changes: 36 additions & 0 deletions scripts/manifests/vgui2extension.json
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,42 @@
"prefix": "vgui2_Panel_SetBounds_Const_callsite"
}
]
},
{
"when": [
"cof-5936",
"cstrikegameui-8684",
"hl-10210",
"hl-3248",
"hl-3266",
"hl-3329",
"hl-3647",
"hl-4554",
"hl-6153",
"hl-8684",
"svencoop-10257",
"svencoop-8948"
],
"symbols": {
"gameui": {
"vgui2::BuildModeDialog": "vtable",
"vgui2::BuildModeDialog::BuildModeDialog(vgui2::BuildGroup*)": "function",
"vgui2::BuildModeDialog::PerformLayout()": "virtualFunction",
"vgui2::BuildModeDialog::SetActiveControl(vgui2::Panel*)": "virtualFunction",
"vgui2::BuildModeDialog.m_pAddNewControlCombo": "structMember",
"vgui2::Frame::GetClientArea(int&, int&, int&, int&)": "virtualFunction",
"vgui2::Panel::GetVPanel()": "virtualFunction",
"vgui2::PanelListPanel": "vtable",
"vgui2::PanelListPanel::PerformLayout()": "virtualFunction",
"vgui2::PanelListPanel::GetItemCount()": "virtualFunction",
"vgui2::PanelListPanel::GetItemLabel(int)": "virtualFunction",
"vgui2::PanelListPanel::GetItemPanel(int)": "virtualFunction",
"vgui2::PanelListPanel.m_SortedItems_m_pMemory": "structMember",
"vgui2::PanelListPanel.m_SortedItems_m_Size": "structMember",
"vgui2::PanelListPanel.m_iFirstColumnWidth": "structMember",
"vgui2::PanelListPanel.m_iPanelBuffer": "structMember"
}
}
}
]
}
Loading
Loading