mirror of
https://github.com/gwdevhub/gMod.git
synced 2026-07-15 15:09:30 +00:00
18d650a422
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
97 lines
4.9 KiB
Markdown
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
|