Merge pull request #5 from josh33901/core-add
Add math, vfunc and hooks and interface grabbing
This commit is contained in:
commit
340a2bf364
164
src/hooks.hh
Normal file
164
src/hooks.hh
Normal file
@ -0,0 +1,164 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.hh"
|
||||
#include "vfunc.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace Hooks {
|
||||
template <typename T, u32 offset>
|
||||
class HookInstance {
|
||||
|
||||
T * instance;
|
||||
void **original_table;
|
||||
void **new_table;
|
||||
|
||||
// pair from index to old function pointer
|
||||
std::vector<std::pair<u32, void *>> hooked_functions;
|
||||
|
||||
auto count_funcs() {
|
||||
u32 count = -1;
|
||||
do
|
||||
++count;
|
||||
while (original_table[count] != nullptr);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
auto get_table() {
|
||||
return *(reinterpret_cast<void ***>(instance) + offset);
|
||||
}
|
||||
|
||||
static auto create_table(u32 count) {
|
||||
return new void *[count];
|
||||
}
|
||||
|
||||
static auto replace_table_pointer(T *instance, void **new_pointer) {
|
||||
auto table = reinterpret_cast<void ***>(instance) + offset;
|
||||
*table = new_pointer;
|
||||
}
|
||||
|
||||
public:
|
||||
HookInstance(T *instance) : instance(instance) {
|
||||
|
||||
assert(instance);
|
||||
|
||||
original_table = get_table();
|
||||
assert(original_table);
|
||||
|
||||
auto num_funcs = count_funcs();
|
||||
assert(num_funcs != -1);
|
||||
|
||||
new_table = create_table(num_funcs);
|
||||
|
||||
// copy the original function pointers over
|
||||
memcpy(new_table, original_table, num_funcs * 4);
|
||||
|
||||
// replace the original with our own
|
||||
replace_table_pointer(instance, new_table);
|
||||
}
|
||||
|
||||
~HookInstance() {
|
||||
replace_table_pointer(instance, original_table);
|
||||
|
||||
assert(new_table);
|
||||
delete[] new_table;
|
||||
}
|
||||
|
||||
auto hook_function(u32 index, void *f) {
|
||||
assert(index < count_funcs());
|
||||
|
||||
hooked_functions.push_back(std::make_pair(index, f));
|
||||
new_table[index] = f;
|
||||
}
|
||||
|
||||
auto unhook_function(u32 index) -> void {
|
||||
assert(index < count_funcs());
|
||||
|
||||
auto found = false;
|
||||
for (auto &f : hooked_functions) {
|
||||
if (f.first == index) {
|
||||
found = true;
|
||||
|
||||
// remove from the hooked functions list
|
||||
std::swap(f, hooked_functions.back());
|
||||
hooked_functions.pop_back();
|
||||
|
||||
// swap the pointers
|
||||
new_table[index] = original_table[index];
|
||||
|
||||
// at this point there is no reason to swap the tables over
|
||||
// either the tables are already swapped in which case this
|
||||
// has an immediate effect, or they are not in which case its
|
||||
// not a problem anyway.
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(found);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
auto get_original_function(u32 index) {
|
||||
assert(index < count_funcs());
|
||||
return reinterpret_cast<F>(original_table[index]);
|
||||
}
|
||||
|
||||
auto get_instance() {
|
||||
return instance;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, u32 offset>
|
||||
class HookFunction {
|
||||
static std::vector<HookInstance<T, offset> *> hooks;
|
||||
|
||||
auto create_hook_instance(T *instance) {
|
||||
auto h = new HookInstance<T, offset>(instance);
|
||||
hooks.push_back(h);
|
||||
return h;
|
||||
}
|
||||
|
||||
T * instance;
|
||||
u32 index;
|
||||
|
||||
public:
|
||||
HookFunction(T *instance, u32 index, void *f) {
|
||||
assert(instance);
|
||||
HookInstance<T, offset> *val = nullptr;
|
||||
|
||||
for (auto &v : hooks) {
|
||||
if (v->get_instance() == instance) {
|
||||
val = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (val == nullptr) {
|
||||
// we havent hooked this instance yet, so do that now
|
||||
create_hook_instance(instance)->hook_function(index, f);
|
||||
return;
|
||||
}
|
||||
|
||||
this->instance = instance;
|
||||
this->index = index;
|
||||
|
||||
val->hook_function(index, f);
|
||||
}
|
||||
|
||||
~HookFunction() {
|
||||
for (auto &v : hooks) {
|
||||
if (v->get_instance() == instance) {
|
||||
v->unhook_function(index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, u32 offset>
|
||||
std::vector<HookInstance<T, offset> *> HookFunction<T, offset>::hooks;
|
||||
|
||||
} // namespace Hooks
|
44
src/interface.cc
Normal file
44
src/interface.cc
Normal file
@ -0,0 +1,44 @@
|
||||
#include "stdafx.hh"
|
||||
|
||||
#include "interface.hh"
|
||||
#include "signature.hh"
|
||||
|
||||
using InstantiateInterfaceFn = void *(*)();
|
||||
|
||||
class InterfaceReg {
|
||||
public:
|
||||
InterfaceReg() = delete;
|
||||
|
||||
public:
|
||||
InstantiateInterfaceFn create_fn;
|
||||
const char * name;
|
||||
|
||||
InterfaceReg *next;
|
||||
};
|
||||
|
||||
void *InterfaceHelpers::find_interface(const char *module_name, const char *interface_name) {
|
||||
|
||||
InterfaceReg *interface_reg_head;
|
||||
|
||||
if constexpr (DoghookPlatform::windows()) {
|
||||
interface_reg_head = **Signature::find_pattern<InterfaceReg ***>(module_name, "8B 35 ? ? ? ? 57 85 F6 74 38", 2);
|
||||
} else if constexpr (DoghookPlatform::linux()) {
|
||||
} else if constexpr (DoghookPlatform::osx()) {
|
||||
}
|
||||
|
||||
assert(interface_reg_head);
|
||||
|
||||
for (auto r = interface_reg_head; r != nullptr; r = r->next) {
|
||||
auto match = strstr(r->name, interface_name);
|
||||
|
||||
// Only match if the next character after the name is the number
|
||||
if (match != nullptr && !isalpha(*(match + strlen(interface_name)))) return r->create_fn();
|
||||
}
|
||||
|
||||
// if you get here either
|
||||
// 1: your interface name is wrong
|
||||
// 2: your dll name is wrong
|
||||
assert(0);
|
||||
|
||||
return nullptr;
|
||||
}
|
45
src/interface.hh
Normal file
45
src/interface.hh
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
namespace InterfaceHelpers {
|
||||
|
||||
// this auto-resolves the library using Signature::
|
||||
void *find_interface(const char *module_name, const char *interface_name);
|
||||
} // namespace InterfaceHelpers
|
||||
|
||||
template <typename T>
|
||||
class Interface {
|
||||
static T *value;
|
||||
|
||||
public:
|
||||
// interface name should be the name of the interface
|
||||
// without the version number
|
||||
// e.g. "VClient017" -> "VClient"
|
||||
static auto set_from_interface(const char *module_name, const char *interface_name) {
|
||||
value = static_cast<T *>(
|
||||
InterfaceHelpers::find_interface(module_name, interface_name));
|
||||
}
|
||||
|
||||
// set from a pointer (you should only do this for non-exported
|
||||
// interfaces e.g. IInput or CClientModeShared)
|
||||
static auto set_from_pointer(T *new_value) {
|
||||
value = new_value;
|
||||
}
|
||||
|
||||
auto operator-> () -> T *& {
|
||||
return value;
|
||||
}
|
||||
|
||||
auto get() -> T *& {
|
||||
return value;
|
||||
}
|
||||
|
||||
operator bool() {
|
||||
return value != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T *Interface<T>::value;
|
||||
|
||||
template <typename T>
|
||||
using IFace = Interface<T>;
|
353
src/math.hh
Normal file
353
src/math.hh
Normal file
@ -0,0 +1,353 @@
|
||||
#pragma once
|
||||
|
||||
#include "platform.hh"
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <float.h>
|
||||
|
||||
#undef max
|
||||
#undef min
|
||||
|
||||
namespace Math {
|
||||
constexpr auto PI = 3.14159265358979323846f;
|
||||
|
||||
inline auto to_radians(float x) {
|
||||
return x * (PI / 180.0f);
|
||||
}
|
||||
|
||||
inline auto to_degrees(float x) {
|
||||
return x * (180.0f / PI);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto lerp(float percent, T min, T max) {
|
||||
return min + ((max - min) * percent);
|
||||
}
|
||||
|
||||
class Vector {
|
||||
public:
|
||||
float x, y, z;
|
||||
|
||||
// sentinal values
|
||||
inline static auto origin() { return Vector(0); }
|
||||
inline static auto zero() { return Vector(0); }
|
||||
inline static auto invalid() { return Vector(FLT_MAX); }
|
||||
|
||||
inline Vector() {}
|
||||
inline Vector(float x, float y, float z) : x(x), y(y), z(z) {}
|
||||
inline Vector(float v) : x(v), y(v), z(v) {}
|
||||
inline Vector(const Vector &v) : x(v.x), y(v.y), z(v.z) {}
|
||||
|
||||
// equality
|
||||
inline auto operator==(const Vector &v) const {
|
||||
return (x == v.x) && (y == v.y) && (z == v.z);
|
||||
}
|
||||
inline auto operator!=(const Vector &v) const {
|
||||
return (x != v.x) || (y != v.y) || (z != v.z);
|
||||
}
|
||||
|
||||
// arithmetic operations
|
||||
inline auto operator+=(const Vector &v) {
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
z += v.z;
|
||||
return *this;
|
||||
}
|
||||
inline auto operator-=(const Vector &v) {
|
||||
x -= v.x;
|
||||
y -= v.y;
|
||||
z -= v.z;
|
||||
return *this;
|
||||
}
|
||||
inline auto operator*=(const Vector &v) {
|
||||
x *= v.x;
|
||||
y *= v.y;
|
||||
z *= v.z;
|
||||
return *this;
|
||||
}
|
||||
inline auto operator*=(float s) {
|
||||
x *= s;
|
||||
y *= s;
|
||||
z *= s;
|
||||
return *this;
|
||||
}
|
||||
inline auto operator/=(const Vector &v) {
|
||||
assert(v.x != 0.0f && v.y != 0.0f && v.z != 0.0f);
|
||||
x /= v.x;
|
||||
y /= v.y;
|
||||
z /= v.z;
|
||||
return *this;
|
||||
}
|
||||
inline auto operator/=(float s) {
|
||||
assert(s != 0.0f);
|
||||
float oofl = 1.0f / s;
|
||||
x *= oofl;
|
||||
y *= oofl;
|
||||
z *= oofl;
|
||||
return *this;
|
||||
}
|
||||
inline auto operator-(void) const {
|
||||
return Vector(-x, -y, -z);
|
||||
}
|
||||
inline auto operator+(const Vector &v) const {
|
||||
return Vector(*this) += v;
|
||||
}
|
||||
inline auto operator-(const Vector &v) const {
|
||||
return Vector(*this) -= v;
|
||||
}
|
||||
auto operator*(const Vector &v) const {
|
||||
return Vector(*this) *= v;
|
||||
}
|
||||
inline auto operator/(const Vector &v) const {
|
||||
return Vector(*this) /= v;
|
||||
}
|
||||
inline auto operator*(float s) const {
|
||||
return Vector(*this) *= s;
|
||||
}
|
||||
inline auto operator/(float s) const {
|
||||
return Vector(*this) /= s;
|
||||
}
|
||||
|
||||
inline auto length_sqr() const {
|
||||
return (x * x) + (y * y) + (z * z);
|
||||
}
|
||||
inline auto length() const {
|
||||
return std::sqrt(length_sqr());
|
||||
}
|
||||
inline auto distance(const Vector &b) const {
|
||||
auto d = *this - b;
|
||||
return d.length();
|
||||
}
|
||||
inline auto dot(Vector &b) const {
|
||||
return (x * b.x) + (y * b.y) + (z * b.z);
|
||||
}
|
||||
inline auto cross(Vector &v) const {
|
||||
auto res = Vector::invalid();
|
||||
res.x = y * v.z - z * v.y;
|
||||
res.y = z * v.x - x * v.z;
|
||||
res.z = x * v.y - y * v.x;
|
||||
return res;
|
||||
}
|
||||
|
||||
inline auto to_angle() const {
|
||||
float tmp, yaw, pitch;
|
||||
|
||||
if (y == 0 && x == 0) {
|
||||
yaw = 0;
|
||||
if (z > 0)
|
||||
pitch = 270;
|
||||
else
|
||||
pitch = 90;
|
||||
} else {
|
||||
yaw = (atan2(y, x) * 180 / PI);
|
||||
if (yaw < 0)
|
||||
yaw += 360;
|
||||
|
||||
tmp = sqrt(x * x + y * y);
|
||||
pitch = (atan2(-z, tmp) * 180 / PI);
|
||||
if (pitch < 0)
|
||||
pitch += 360;
|
||||
}
|
||||
|
||||
return Vector(pitch, yaw, 0);
|
||||
}
|
||||
|
||||
inline auto to_vector() const {
|
||||
float sp, sy, cp, cy;
|
||||
|
||||
sy = sinf(to_radians(y));
|
||||
cy = cosf(to_radians(y));
|
||||
|
||||
sp = sinf(to_radians(x));
|
||||
cp = cosf(to_radians(x));
|
||||
|
||||
return Vector(cp * cy, cp * sy, -sp);
|
||||
}
|
||||
|
||||
inline auto lerp(const Vector &other, float percent) const {
|
||||
Vector ret;
|
||||
|
||||
ret.x = x + (other.x - x) * percent;
|
||||
ret.y = y + (other.y - y) * percent;
|
||||
ret.z = z + (other.z - z) * percent;
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
class Matrix3x4 {
|
||||
public:
|
||||
Matrix3x4() {}
|
||||
Matrix3x4(
|
||||
float m00, float m01, float m02, float m03,
|
||||
float m10, float m11, float m12, float m13,
|
||||
float m20, float m21, float m22, float m23) {
|
||||
data[0][0] = m00;
|
||||
data[0][1] = m01;
|
||||
data[0][2] = m02;
|
||||
data[0][3] = m03;
|
||||
data[1][0] = m10;
|
||||
data[1][1] = m11;
|
||||
data[1][2] = m12;
|
||||
data[1][3] = m13;
|
||||
data[2][0] = m20;
|
||||
data[2][1] = m21;
|
||||
data[2][2] = m22;
|
||||
data[2][3] = m23;
|
||||
}
|
||||
|
||||
// Creates a matrix where the X axis = forward
|
||||
// the Y axis = left, and the Z axis = up
|
||||
void init(const Vector &x_axis, const Vector &y_axis, const Vector &z_axis, const Vector &origin) {
|
||||
data[0][0] = x_axis.x;
|
||||
data[0][1] = y_axis.x;
|
||||
data[0][2] = z_axis.x;
|
||||
data[0][3] = origin.x;
|
||||
data[1][0] = x_axis.y;
|
||||
data[1][1] = y_axis.y;
|
||||
data[1][2] = z_axis.y;
|
||||
data[1][3] = origin.y;
|
||||
data[2][0] = x_axis.z;
|
||||
data[2][1] = y_axis.z;
|
||||
data[2][2] = z_axis.z;
|
||||
data[2][3] = origin.z;
|
||||
}
|
||||
|
||||
// Creates a matrix where the X axis = forward
|
||||
// the Y axis = left, and the Z axis = up
|
||||
Matrix3x4(const Vector &x_axis, const Vector &y_axis, const Vector &z_axis, const Vector &origin) {
|
||||
init(x_axis, y_axis, z_axis, origin);
|
||||
}
|
||||
|
||||
inline void invalidate(void) {
|
||||
assert(0);
|
||||
// for (int i = 0; i < 3; i++) {
|
||||
// for (int j = 0; j < 4; j++) {
|
||||
// data[i][j] = VEC_T_NAN;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
float *operator[](int i) {
|
||||
assert((i >= 0) && (i < 3));
|
||||
return data[i];
|
||||
}
|
||||
const float *operator[](int i) const {
|
||||
assert((i >= 0) && (i < 3));
|
||||
return data[i];
|
||||
}
|
||||
float * base() { return &data[0][0]; }
|
||||
const float *base() const { return &data[0][0]; }
|
||||
|
||||
const auto get_column(u32 column, Vector &out) const {
|
||||
out.x = data[0][column];
|
||||
out.y = data[1][column];
|
||||
out.z = data[2][column];
|
||||
}
|
||||
|
||||
const auto get_row(u32 row, Vector &out) const {
|
||||
out.x = data[row][0];
|
||||
out.y = data[row][1];
|
||||
out.z = data[row][2];
|
||||
}
|
||||
|
||||
//
|
||||
auto rotate_vector(const Math::Vector &in) const {
|
||||
Vector out;
|
||||
Vector row;
|
||||
|
||||
out.x = in.dot((get_row(0, row), row));
|
||||
out.y = in.dot((get_row(1, row), row));
|
||||
out.z = in.dot((get_row(2, row), row));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
auto from_angle(const Vector &angles) {
|
||||
auto radian_pitch = to_radians(angles.x);
|
||||
auto radian_yaw = to_radians(angles.y);
|
||||
auto radian_roll = to_radians(angles.z);
|
||||
|
||||
auto sp = sin(radian_pitch);
|
||||
auto cp = cos(radian_pitch);
|
||||
|
||||
auto sy = sin(radian_yaw);
|
||||
auto cy = cos(radian_yaw);
|
||||
|
||||
auto sr = sin(radian_roll);
|
||||
auto cr = cos(radian_roll);
|
||||
|
||||
// matrix = (YAW * PITCH) * ROLL
|
||||
data[0][0] = cp * cy;
|
||||
data[1][0] = cp * sy;
|
||||
data[2][0] = -sp;
|
||||
|
||||
float crcy = cr * cy;
|
||||
float crsy = cr * sy;
|
||||
float srcy = sr * cy;
|
||||
float srsy = sr * sy;
|
||||
data[0][1] = sp * srcy - crsy;
|
||||
data[1][1] = sp * srsy + crcy;
|
||||
data[2][1] = sr * cp;
|
||||
|
||||
data[0][2] = (sp * crcy + srsy);
|
||||
data[1][2] = (sp * crsy - srcy);
|
||||
data[2][2] = cr * cp;
|
||||
|
||||
data[0][3] = 0.0f;
|
||||
data[1][3] = 0.0f;
|
||||
data[2][3] = 0.0f;
|
||||
}
|
||||
|
||||
float data[3][4];
|
||||
};
|
||||
|
||||
// TODO: make these member functions
|
||||
inline void matrix_angles(const Matrix3x4 &matrix, float *angles) {
|
||||
float forward[3];
|
||||
float left[3];
|
||||
float up[3];
|
||||
|
||||
//
|
||||
// Extract the basis vectors from the matrix. Since we only need the Z
|
||||
// component of the up vector, we don't get X and Y.
|
||||
//
|
||||
forward[0] = matrix[0][0];
|
||||
forward[1] = matrix[1][0];
|
||||
forward[2] = matrix[2][0];
|
||||
left[0] = matrix[0][1];
|
||||
left[1] = matrix[1][1];
|
||||
left[2] = matrix[2][1];
|
||||
up[2] = matrix[2][2];
|
||||
|
||||
float xyDist = std::sqrt(forward[0] * forward[0] + forward[1] * forward[1]);
|
||||
|
||||
// enough here to get angles?
|
||||
if (xyDist > 0.001f) {
|
||||
// (yaw) y = ATAN( forward.y, forward.x ); -- in our space, forward is the X axis
|
||||
angles[1] = to_degrees(atan2f(forward[1], forward[0]));
|
||||
|
||||
// (pitch) x = ATAN( -forward.z, sqrt(forward.x*forward.x+forward.y*forward.y) );
|
||||
angles[0] = to_degrees(atan2f(-forward[2], xyDist));
|
||||
|
||||
// (roll) z = ATAN( left.z, up.z );
|
||||
angles[2] = to_degrees(atan2f(left[2], up[2]));
|
||||
} else {
|
||||
// (yaw) y = ATAN( -left.x, left.y ); -- forward is mostly z, so use right for yaw
|
||||
angles[1] = to_degrees(atan2f(-left[0], left[1]));
|
||||
|
||||
// (pitch) x = ATAN( -forward.z, sqrt(forward.x*forward.x+forward.y*forward.y) );
|
||||
angles[0] = to_degrees(atan2f(-forward[2], xyDist));
|
||||
|
||||
// Assume no roll in this case as one degree of freedom has been lost (i.e. yaw == roll)
|
||||
angles[2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void matrix_angles(const Matrix3x4 &matrix, Vector &angles, Vector &position) {
|
||||
matrix.get_column(3, position);
|
||||
matrix_angles(matrix, &angles.x);
|
||||
}
|
||||
|
||||
} // namespace Math
|
@ -40,15 +40,15 @@
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
namespace DogHookPlatform {
|
||||
constexpr bool windows() { return doghook_platform_windows(); }
|
||||
constexpr bool linux() { return doghook_platform_linux(); }
|
||||
constexpr bool osx() { return doghook_platform_osx(); }
|
||||
namespace DoghookPlatform {
|
||||
inline constexpr bool windows() { return doghook_platform_windows(); }
|
||||
inline constexpr bool linux() { return doghook_platform_linux(); }
|
||||
inline constexpr bool osx() { return doghook_platform_osx(); }
|
||||
|
||||
constexpr bool msvc() { return doghook_platform_msvc(); }
|
||||
constexpr bool clang() { return doghook_platform_clang(); }
|
||||
constexpr bool gcc() { return doghook_platform_gcc(); }
|
||||
} // namespace DogHookPlatform
|
||||
inline constexpr bool msvc() { return doghook_platform_msvc(); }
|
||||
inline constexpr bool clang() { return doghook_platform_clang(); }
|
||||
inline constexpr bool gcc() { return doghook_platform_gcc(); }
|
||||
} // namespace DoghookPlatform
|
||||
|
||||
#include "types.hh"
|
||||
|
||||
|
@ -135,7 +135,7 @@ auto Signature::resolve_library(const char *name) -> void * {
|
||||
|
||||
auto dir = readdir(d);
|
||||
while (dir != nullptr) {
|
||||
if (dir->d_type == DT_REG && strstr(dir->d_name, to_find) != nullptr && strstr(dir->d_name, ".so") != nullptr) {
|
||||
if (dir->d_type == DT_REG && strstr(dir->d_name, to_find) && strstr(dir->d_name, ".so")) {
|
||||
sprintf(out, "%s/%s", dirname, dir->d_name);
|
||||
return true;
|
||||
}
|
||||
|
@ -16,37 +16,4 @@ auto find_pattern(const char *module, const char *pattern, u32 offset) {
|
||||
return reinterpret_cast<T>(find_pattern(module, pattern) + offset);
|
||||
}
|
||||
void *resolve_callgate(void *address);
|
||||
|
||||
// TODO: there must be some way we can do this at init time instead of using magic statics.
|
||||
// make a static chain and find them at level_init or at init_all
|
||||
class Pattern {
|
||||
const char *module;
|
||||
const char *signature;
|
||||
|
||||
public:
|
||||
Pattern(const char * module,
|
||||
[[maybe_unused]] const char *signature_windows,
|
||||
[[maybe_unused]] const char *signature_linux,
|
||||
[[maybe_unused]] const char *signature_osx)
|
||||
: module(module),
|
||||
#if doghook_platform_windows()
|
||||
signature(signature_windows)
|
||||
#elif doghook_platform_linux()
|
||||
signature(signature_linux)
|
||||
#elif doghook_platform_osx()
|
||||
signature(signature_osx)
|
||||
#endif
|
||||
{
|
||||
assert(signature[0] != '\0');
|
||||
}
|
||||
|
||||
auto find() -> u8 * {
|
||||
return ::Signature::find_pattern(module, signature);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto find(u32 offset) -> T {
|
||||
return ::Signature::find_pattern<T>(module, signature, offset);
|
||||
}
|
||||
};
|
||||
} // namespace Signature
|
||||
|
@ -13,3 +13,5 @@ using i16 = int16_t;
|
||||
using i32 = int32_t;
|
||||
using i64 = int64_t;
|
||||
using iptr = intptr_t;
|
||||
|
||||
#include "math.hh"
|
||||
|
91
src/vfunc.hh
Normal file
91
src/vfunc.hh
Normal file
@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "platform.hh"
|
||||
#include "types.hh"
|
||||
|
||||
// helpers for calling virtual functions
|
||||
namespace VFunc {
|
||||
inline auto get_table(void *inst, u32 offset) -> void ** {
|
||||
return *reinterpret_cast<void ***>(reinterpret_cast<u8 *>(inst) + offset);
|
||||
}
|
||||
|
||||
inline auto get_table(const void *inst, u32 offset) -> const void ** {
|
||||
return *reinterpret_cast<const void ***>(
|
||||
reinterpret_cast<u8 *>(
|
||||
const_cast<void *>(inst)) +
|
||||
offset);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
inline auto get_func(const void *inst, u32 index, u32 offset) {
|
||||
return reinterpret_cast<F>(get_table(inst, offset)[index]);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
inline auto get_func(void *inst, u32 index, u32 offset) {
|
||||
return reinterpret_cast<F>(get_table(inst, offset)[index]);
|
||||
}
|
||||
|
||||
template <typename>
|
||||
class Func;
|
||||
|
||||
template <typename ObjectType, typename Ret, typename... Args>
|
||||
class Func<Ret (ObjectType::*)(Args...)> {
|
||||
|
||||
using function_type = Ret(__thiscall *)(ObjectType *, Args...);
|
||||
function_type f;
|
||||
|
||||
// On windows this will take into account the offset
|
||||
// So we do not need to store that seperately
|
||||
ObjectType *instance;
|
||||
|
||||
public:
|
||||
// TODO: do any other platforms have this offset and is it useful?
|
||||
Func(ObjectType *instance,
|
||||
u32 index_windows,
|
||||
u32 index_linux,
|
||||
u32 index_osx,
|
||||
u32 offset_windows) {
|
||||
// NOTE: this assert is disabled as it is in some really tight loops!
|
||||
// This should never go off and if it does you will get a nice and obvious fatal crash...
|
||||
//assert(instance != nullptr);
|
||||
|
||||
auto index = 0u;
|
||||
if constexpr (BluePlatform::windows())
|
||||
index = index_windows;
|
||||
else if constexpr (BluePlatform::linux())
|
||||
index = index_linux;
|
||||
else if constexpr (BluePlatform::osx())
|
||||
index = index_osx;
|
||||
|
||||
auto offset = 0u;
|
||||
if constexpr (BluePlatform::windows()) {
|
||||
offset = offset_windows;
|
||||
|
||||
this->instance = reinterpret_cast<ObjectType *>(
|
||||
reinterpret_cast<u8 *>(instance) + offset);
|
||||
} else {
|
||||
this->instance = instance;
|
||||
}
|
||||
|
||||
f = get_func<function_type>(instance, index, offset);
|
||||
}
|
||||
|
||||
auto invoke(Args... args) -> Ret {
|
||||
return f(instance, args...);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace VFunc
|
||||
|
||||
// macro for easier definitions of wrapper calls
|
||||
// name is the name of the function
|
||||
// off is the windows offset
|
||||
// varags are the arguments of the parent function
|
||||
#define return_virtual_func(name, windows, linux, osx, off, ...) \
|
||||
using c = std::remove_reference<decltype(*this)>::type; \
|
||||
using t = decltype(&c::name); \
|
||||
return VFunc::Func<t>(this, windows, linux, osx, off).invoke(__VA_ARGS__)
|
Reference in New Issue
Block a user