summaryrefslogtreecommitdiffstats
path: root/src/core.h
blob: 320b62b1751d3c995791b57c97db7ef78bafc8ea (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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#ifndef HL2H_CORE_H
#define HL2H_CORE_H

#include <cstdint>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>

#include <dlfcn.h>
#include <pthread.h>
#include <unistd.h>

// Shared float-precision constant. More digits than a float can hold are
// rounded at compile time and have no runtime cost; a coarse value would only
// hurt angular accuracy, never performance.
constexpr float PI_F = 3.14159265f;

// ---------------------------------------------------------------------------
// logging
// ---------------------------------------------------------------------------

void logf(const char *fmt, ...);
void logd(const char *fmt, ...); // debug-only (HL2H_DEBUG=1)

// ---------------------------------------------------------------------------
// init readiness
// ---------------------------------------------------------------------------
//
// setup_thread runs detached while the game threads are already live, and some
// hooks are installed lazily from the game thread. Hooks therefore always stay
// installed but pass straight through to the original until setup reaches
// INIT_LIVE, so the game can never observe half-initialised state. INIT_FAILED
// is terminal: the cheat stays inert instead of half-working.
enum {
  INIT_FAILED = -1,
  INIT_NONE = 0,
  INIT_INTERFACES = 1, // modules + interfaces + netvars resolved
  INIT_READY = 2,      // config loaded, ISurface/fonts resolved
  INIT_LIVE = 3        // hooks may run their bodies
};
void init_set_stage(int stage);
int init_stage(); // acquire load
inline bool init_live() { return init_stage() == INIT_LIVE; }

// Clone a vtable into a new array, preserving the Itanium ABI header at
// [-2]/[-1] (offset-to-top and typeinfo) so RTTI on the hooked object still
// works. Returns the slot-0 pointer to install (i.e. the clone + 2).
void **vtable_clone(void *iface, size_t slots);

// ---------------------------------------------------------------------------
// on-screen toasts
// ---------------------------------------------------------------------------

enum ToastLevel { TOAST_INFO = 0, TOAST_WARN, TOAST_ERROR };
void toastf(int level, const char *fmt, ...);
bool gui_toasts_active();
void gui_draw_toasts();

// ---------------------------------------------------------------------------
// module discovery
// ---------------------------------------------------------------------------

struct Module {
  struct Range {
    uintptr_t lo, hi;
    bool file;
  };
  std::vector<Range> ranges;
  std::string path;
  bool valid() const { return !ranges.empty(); }
  bool contains(uintptr_t p) const {
    for (auto &r : ranges)
      if (p >= r.lo && p < r.hi)
        return true;
    return false;
  }
};
// Immutable module snapshots. A reader gets a reference that stays valid for
// the whole process: find_modules() publishes a new snapshot instead of
// mutating the old one, and retired snapshots are intentionally never freed, so
// a concurrent refresh can never invalidate a reference already in use.
const Module &mod_client();
const Module &mod_engine();
const Module &mod_server();

// True only when the whole byte range [p, p+n) lies inside one known module
// range. Use before dereferencing pointers read out of engine memory.
bool module_range(uintptr_t p, size_t n);

// ---------------------------------------------------------------------------
// game interfaces
// ---------------------------------------------------------------------------

using CreateInterfaceFn = void *(*)(const char *, int *);

struct GameInterfaces {
  void *client = nullptr;
  void *entitylist = nullptr;
  void *engine = nullptr;
  void *modelinfo = nullptr;    // IVModelInfoClient006 (model index -> model name)
  void *engineserver = nullptr; // IVEngineServer021 (edict access, incl. server entities)
  void *debugoverlay = nullptr; // IVDebugOverlay003 (engine-accurate world->screen)
  void *enginetrace = nullptr;  // EngineTraceClient003 (world vischeck)
  void *cvar = nullptr;         // VEngineCvar004 (mat_fullbright etc.)
  void *modelrender = nullptr;  // VEngineModel016 (chams)
  void *renderview = nullptr;   // VEngineRenderView014 (alpha/color modulation)
};
extern GameInterfaces g_iface;

#define VTABLE(obj) (*(void ***)(obj))
template <typename Fn> inline Fn vfunc(void *obj, size_t idx) {
  return reinterpret_cast<Fn>(VTABLE(obj)[idx]);
}

// ---------------------------------------------------------------------------
// netvars
// ---------------------------------------------------------------------------
struct NetVars {
  int flags = -1;
  int velocity = -1;
  int movetype = -1;
  int health = -1;
  int maxhealth = -1;
  int teamnum = -1;
  int origin = -1;
  int viewoffset = -1;
  int mins = -1;
  int maxs = -1;
  int lifestate = -1;
  int modelindex = -1;
  int absvelocity = -1; // client C_BaseEntity::m_vecAbsVelocity (prediction)
  int activeweapon = -1; // client m_hActiveWeapon handle
  int owner = -1;        // client m_hOwnerEntity handle
  int weapon_owner = -1; // client m_hOwner handle (C_BaseCombatWeapon)
  int clr_render = -1;   // client m_clrRender (entity render colour)
  int punch = -1;        // client m_vecPunchAngle (aim punch)
  int default_fov = -1;  // client m_iDefaultFOV (camera fov)
  int dmg_radius = -1;   // client C_BaseGrenade::m_DmgRadius
  int my_weapons = -1;   // client m_hMyWeapons[48] array base
  int ammo = -1;         // client m_iAmmo[] array base
  // ponytail: mins/maxs may be absent from some HL2 netvar tables; esp.cpp falls back to h=72
  bool ok() const { return flags >= 0 && velocity >= 0 && movetype >= 0; }
  // ponytail: m_iMaxHealth isn't a netvar in HL2 SP; esp.cpp falls back to 100.
  // m_iHealth only ever updates for players — NPCs are detected via m_lifeState.
  bool esp_ok() const { return ok() && health >= 0 && teamnum >= 0 && origin >= 0 && viewoffset >= 0; }
};
extern NetVars g_net;

// ---------------------------------------------------------------------------
// CInput
// ---------------------------------------------------------------------------

extern uintptr_t g_input;

// ---------------------------------------------------------------------------
// console output
// ---------------------------------------------------------------------------

extern void (*g_conmsg)(const char *, ...);

// ---------------------------------------------------------------------------
// CUserCmd
// ---------------------------------------------------------------------------

struct CUserCmd {
  void *vtable;
  int command_number;
  int tick_count;
  float viewangles[3];
  float forwardmove;
  float sidemove;
  float upmove;
  int buttons;
  uint8_t impulse;
  int weaponselect;
  int weaponsubtype;
  int random_seed;
  short mousedx;
  short mousedy;
  bool hasbeenpredicted;
};

// ---------------------------------------------------------------------------
// engine constants
// ---------------------------------------------------------------------------

enum { IN_ATTACK = 1 << 0, IN_JUMP = 1 << 1, IN_DUCK = 1 << 2, IN_USE = 1 << 5, IN_ATTACK2 = 1 << 11, IN_SPEED = 1 << 17 };
enum { FL_ONGROUND = 1 << 0, FL_DUCKING = 1 << 1, FL_INWATER = 1 << 9 };
enum { MOVETYPE_WALK = 2, MOVETYPE_NOCLIP = 8, MOVETYPE_LADDER = 9 };

// ---------------------------------------------------------------------------
// vector math
// ---------------------------------------------------------------------------

struct Vector { float x, y, z; };
struct QAngle { float x, y, z; };
// camera state captured each CreateMove (used by ESP / future aimbot)
extern Vector g_cam_eye;
extern Vector g_cam_view;
QAngle vector_angles(const Vector &forward);
Vector angle_forward_vector(const QAngle &angles);
float getfov(const QAngle &my_view, const QAngle &aim_ang);

#endif