Files
gMod/CLAUDE.md
2026-06-08 16:24:05 +00:00

97 lines
4.9 KiB
Markdown

# gMod
A 32-bit Windows DLL that hooks Direct3D 9 to load texture mods for Guild Wars. Continuation of uMod. Integrated with [GW Launcher](https://github.com/gwdevhub/gwlauncher) and [Daybreak](https://github.com/gwdevhub/Daybreak).
## Project structure
- `header/` — header files (D3D9Hooks, D3D9State, Defines, Error, Main, Utils)
- `source/` — implementation files (D3D9Hooks.cpp, dll_main.cpp, Error.cpp)
- `modules/` — C++23 module files (ModfileLoader, ModfileLoader_TpfReader, TextureClient, TextureFunction)
- `TpfConvert/` — standalone utility to fix broken .tpf files
- `cmake/` — CMake helper scripts
- `build/` — CMake build tree (generated, ignored)
- `bin/` — compiled output (generated, ignored)
## Build
Requires Visual Studio 2022, CMake 3.29+, and vcpkg — all via the VS 2022 Developer PowerShell.
```
cmake --preset=vcpkg
cmake --open build
# then compile inside Visual Studio, or:
cmake --build build --config Release
```
- Target: 32-bit only (`-A Win32` / `CMAKE_GENERATOR_PLATFORM=win32`)
- Standard: C++23
- 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
- `libzippp` / `libzip` / `zlib` — reading .tpf/.zip mod files
- `directxtex` — texture format conversion
- `Microsoft.GSL` — Guidelines Support Library
## How it works
1. `dll_main.cpp` — DLL entry point, hooks d3d9.dll via MinHook
2. `D3D9Hooks.cpp` — intercepts `Direct3DCreate9` and IDirect3DDevice9 methods
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
- Reshade > 5.0.1 causes glitches; recommend 5.0.1 or 4.9.1
- `modlist.txt` contains full paths to .tpf/.zip mod files, one per line