Expand CLAUDE.md with build constraints, hooking model, and conventions

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc
2026-06-08 16:24:05 +00:00
parent 55e36db265
commit 18d650a422
+47
View File
@@ -28,6 +28,12 @@ cmake --build build --config Release
- Output: `bin/` (gMod.dll, TpfConvert.exe)
- Version: set in `CMakeLists.txt` (`VERSION_MAJOR/MINOR/PATCH/TWEAK`)
> **Cannot be built or run in this agent environment** (Linux, no MSVC, no 32-bit
> D3D9, no Guild Wars to inject into). Don't burn turns attempting `cmake`/builds
> here — validate changes by reading and matching existing patterns, and lean on
> Windows CI (`ci.yaml`) for the real build. When an actual compile/test is needed,
> ask the user to do it in Visual Studio rather than trying locally.
## Key dependencies (via vcpkg)
- `minhook` — D3D9 function hooking
@@ -42,6 +48,47 @@ cmake --build build --config Release
3. `ModfileLoader` — reads `modlist.txt`, loads .tpf/.zip mod archives
4. `TextureClient` / `TextureFunction` — matches and replaces textures by hash at runtime
### Hooking model (read before touching D3D9 code)
gMod uses **MinHook vtable hooks**, not proxy/subclass wrappers (the old uMod model
was replaced — see `git log` "Replace D3D9 proxy wrappers with vtable hooks"). The
game keeps the **real** `IDirect3D9` / `IDirect3DDevice9` / texture objects byte-for-byte
untouched; gMod patches only the individual vtable slots it cares about (CreateDevice,
CreateTexture/Volume/Cube, UpdateTexture, BeginScene, Set/GetTexture, Release).
- Per-texture side-state lives **out of band** in `header/D3D9State.h` (`TexState`,
keyed by the real texture pointer), so reverting the hooks fully detaches gMod.
- `RemoveAllD3D9Hooks()` must leave the host process pristine — preserve that invariant.
- A vtable is shared by all instances of a class, so each slot is hooked once; texture
Release slots are hooked lazily on first instance. Don't double-hook.
## Conventions
- **Formatting is CI-enforced** by clang-format `22.1.5` (`.clang-format`, applied by
`lint.yaml` on push to `dev`). Don't hand-reformat or "tidy" whole files — it just
churns the diff. Notable rules: `ColumnLimit: 0` (never reflow long D3D signatures /
vtable typedefs), `SortIncludes: Never` (include order is load-bearing in Windows
headers — never reorder), 4-space indent, braces on their own line after functions.
- **C++23 named modules** (`modules/*.ixx`). Editing a module *interface* triggers wide
rebuilds; prefer changing implementation over interface when possible.
- **Public exported API is a fixed surface** — four `extern "C" __declspec(dllexport)`
functions in `dll_main.cpp`: `SetDevice`, `AddFile`, `RemoveFile`, `GetFiles`. These
are consumed by GW Launcher and Daybreak; do **not** change their names, signatures,
or calling convention (`__cdecl`) without coordinating downstream.
- **Commits**: short imperative summaries, lowercase, no trailing period
(e.g. "Keep loaded_files in load order so GetFiles returns priority order").
- **Branching**: `dev` is the integration branch; PRs target `master`. CI builds on
push to `dev` and on PRs to `master`.
### Where things live (by size / how often they change)
- `modules/TextureClient.ixx` (~670 lines) — texture match/replace bookkeeping, hot
- `source/D3D9Hooks.cpp` (~580) — the vtable detours and install/remove
- `modules/TextureFunction.ixx` (~380) — texture creation/conversion helpers
- `source/dll_main.cpp` (~345) — entry point + exported C API
- `modules/ModfileLoader*.ixx` — .tpf/.zip parsing
- `header/Defines.h` — shared structs/constants (`TextureFileStruct`, `HashTuple`, etc.)
## Notes
- Must be injected before d3d9.dll loads, or renamed to d3d9.dll in the GW folder