summaryrefslogtreecommitdiffstats
path: root/CONTEXT.md
blob: 21128f7e9bbff7779008090dd493f2019a838347 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# Context: HL2 Linux Internal Cheat (`hl2hake`)

## What is this project?

A minimal, featureless cheat for Half-Life 2 (native Linux build, 32-bit `hl2_linux`). Originally ported from a Windows reference (`hake`) that implemented auto-bhop, auto-ABH, and auto-climb via a `CHLClient::CreateMove` vtable hook.

## Resolved terms

- **Build**: LD_PRELOAD a 32-bit `.so` into `hl2_linux` via Steam's bundled 32-bit runtime (`steam-runtime/run.sh`).
- **Hook**: Copy-and-swap vtable on the `CHLClient` instance (slot 21 = `CreateMove`). 256-slot copy to cover all dispatched virtuals.
- **Netvars**: RecvTable walk from `IBaseClientDLL::GetAllClasses` (vtable slot 8). Prediction datamap scan for `CBaseEntity::m_MoveType` (networked `movetype` is a virtual proxy with offset 0).
- **CInput**: Discovered via byte-scan of `CHLClient::CreateMove` prologue (gcc PIC `call thunk; add $imm,%esi` idiom), resolving the module-level `IInput*` variable.
- **UserCMD CRC**: Standard CRC-32 (IEEE reflected, poly `0xEDB88320`, init `0xFFFFFFFF`). Field set and offsets verified against the binary's `CInput::ValidateUserCmd` disassembly.
- **Module discovery**: `/proc/self/maps` scan for `client.so` / `engine.so` basenames (exact match at `/` boundary). PROT_NONE (`---p`) entries excluded. Merged file-backed ranges absorb one directly-adjacent anonymous `.bss` tail; anon-to-anon chaining is prohibited.
- **Calling convention**: All game virtuals use **cdecl** with `this` as first stack arg (`0x8(%ebp)` in prologues, bare `ret`). No MSVC `__thiscall`.

## Netvar offsets (this build, verified via both RecvTable walk and pred-TD scan)

| Field | Offset | Source |
|---|---|---|
| `m_fFlags` | `0x33C` | RecvTable + pred TD |
| `m_vecVelocity[0]` | `0xE0` | RecvTable (array, FIELD_VECTOR) |
| `m_MoveType` | `0x164` | pred-TD only (networked `movetype` has offset 0) |

## Key engine index table (IVEngineClient014, this build)

| Index | Method | Verification |
|---|---|---|
| 8 | *(not ClientCmd)* | Disasm: per-player index bounds check on `(arg-1)` — likely `GetPlayerInfo` |
| 9 | *(not ClientCmd_Unrestricted)* | Disasm: loop over split-screen players — no-op'd in single-player |
| 12 | `GetLocalPlayer` | Disasm: `return *(CClientState + 0x1b0) + 1` — confirmed in-game |
| 65 | `HudUpdate`-family | Crash-site (256-slot bump): `call *(this, float)` |

Console output uses `ConMsg` from `libtier0.so` (resolved via `dlsym(RTLD_DEFAULT, "_Z6ConMsgPKcz")`), not `IVEngineClient::ClientCmd`.

## Menu system

- **Toggle architecture**: each feature is runtime-toggleable, ON by default. A `MenuState` struct holds per-feature `active` bool and `bind` (key code or None).
- **Rendering**: hook `IEngineVGui::Paint` via `VEngineVGui001` — draws every frame including the main menu. Text-only overlay in top-left corner.
- **Persistence**: INI-style plain text config; one line per setting (`climb_active=1`, `climb_bind=MOUSE3`). Config written on every state change; loaded before hooks install.
- **Input model**: Insert toggles menu open/closed; arrow keys navigate the tree; Enter expands/collapses nodes and toggles boolean fields; Escape closes the menu. Modal while open (all game input blocked). Long-term: selective pass-through for unused inputs.
- **Bind assignment UX**: selecting a Bind node enters bind-select mode; any key press becomes the new bind; Escape sets bind to None (disabling the feature); Enter cancels bind change and reverts.
- **Tree layout**: HL2hake (root) → Climb (Active + Bind), Bunnyhop (Active), ABH (Active). Children indented. All nodes expanded by default when the menu opens.

## Open questions

None currently.