From 5b50c6fb898bf8da575a302a993f7d0e4cd52772 Mon Sep 17 00:00:00 2001 From: dreamstalker Date: Wed, 8 Jul 2015 23:50:25 +0400 Subject: [PATCH] Hitbox tracking --- rehlds/msvc/ReHLDS.vcxproj | 12 +++- rehlds/msvc/ReHLDS.vcxproj.filters | 9 +++ rehlds/public/rehlds/rehlds_api.h | 3 +- rehlds/rehlds/math_utils.cpp | 81 +++++++++++++++++++++++++ rehlds/rehlds/math_utils.h | 28 +++++++++ rehlds/rehlds/precompiled.h | 3 + rehlds/rehlds/rehlds_api_impl.cpp | 49 ++++++++++++++- rehlds/rehlds/rehlds_api_impl.h | 2 + rehlds/unittests/math_util_tests.cpp | 91 ++++++++++++++++++++++++++++ 9 files changed, 275 insertions(+), 3 deletions(-) create mode 100644 rehlds/rehlds/math_utils.cpp create mode 100644 rehlds/rehlds/math_utils.h create mode 100644 rehlds/unittests/math_util_tests.cpp diff --git a/rehlds/msvc/ReHLDS.vcxproj b/rehlds/msvc/ReHLDS.vcxproj index 834c912..0dd2b0c 100644 --- a/rehlds/msvc/ReHLDS.vcxproj +++ b/rehlds/msvc/ReHLDS.vcxproj @@ -185,6 +185,7 @@ + @@ -269,6 +270,14 @@ true true + + true + true + true + true + true + true + true @@ -538,6 +547,7 @@ + @@ -833,7 +843,7 @@ Level3 Disabled true - REHLDS_FIXES;REHLDS_FLIGHT_REC;REHLDS_OPT_PEDANTIC;REHLDS_SELF;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + REHLDS_FLIGHT_REC;REHLDS_OPT_PEDANTIC;REHLDS_SELF;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) Precise /arch:IA32 %(AdditionalOptions) MultiThreadedDebug diff --git a/rehlds/msvc/ReHLDS.vcxproj.filters b/rehlds/msvc/ReHLDS.vcxproj.filters index 29382ae..0559a24 100644 --- a/rehlds/msvc/ReHLDS.vcxproj.filters +++ b/rehlds/msvc/ReHLDS.vcxproj.filters @@ -346,6 +346,12 @@ rehlds + + rehlds + + + unittests + @@ -1065,6 +1071,9 @@ rehlds + + rehlds + diff --git a/rehlds/public/rehlds/rehlds_api.h b/rehlds/public/rehlds/rehlds_api.h index b25364b..3bb74c7 100644 --- a/rehlds/public/rehlds/rehlds_api.h +++ b/rehlds/public/rehlds/rehlds_api.h @@ -35,7 +35,7 @@ #include "model.h" #define REHLDS_API_VERSION_MAJOR 1 -#define REHLDS_API_VERSION_MINOR 2 +#define REHLDS_API_VERSION_MINOR 3 //Steam_NotifyClientConnect hook typedef IHookChain IRehldsHook_Steam_NotifyClientConnect; @@ -199,6 +199,7 @@ struct RehldsFuncs_t { void(*MSG_WriteBitVec3Coord)(const float *fa); void(*MSG_EndBitWriting)(sizebuf_t *buf); void*(*SZ_GetSpace)(sizebuf_t *buf, int length); + bool(*GetHitboxCorners)(int hitboxId, float* /* [8*3] */ corners); }; class IRehldsApi { diff --git a/rehlds/rehlds/math_utils.cpp b/rehlds/rehlds/math_utils.cpp new file mode 100644 index 0000000..df93fe3 --- /dev/null +++ b/rehlds/rehlds/math_utils.cpp @@ -0,0 +1,81 @@ +#include "precompiled.h" + +double CalculateDeterminant(matrix33_t &matrix) { + return + matrix[0][0] * matrix[1][1] * matrix[2][2] + - matrix[0][0] * matrix[1][2] * matrix[2][1] + + matrix[1][0] * matrix[2][1] * matrix[0][2] + - matrix[1][0] * matrix[2][2] * matrix[0][1] + + matrix[2][0] * matrix[0][1] * matrix[1][2] + - matrix[2][0] * matrix[0][2] * matrix[1][1]; +} + +equation_sys_resolve_res ResolveEq3Sys(equation3_t* eqs, double* res) { + matrix33_t mainDtMtx = { + { eqs[0].a, eqs[0].b, eqs[0].c }, + { eqs[1].a, eqs[1].b, eqs[1].c }, + { eqs[2].a, eqs[2].b, eqs[2].c } + }; + + matrix33_t dtxMtx = { + { eqs[0].h, eqs[0].b, eqs[0].c }, + { eqs[1].h, eqs[1].b, eqs[1].c }, + { eqs[2].h, eqs[2].b, eqs[2].c } + }; + + matrix33_t dtyMtx = { + { eqs[0].a, eqs[0].h, eqs[0].c }, + { eqs[1].a, eqs[1].h, eqs[1].c }, + { eqs[2].a, eqs[2].h, eqs[2].c } + }; + + matrix33_t dtzMtx = { + { eqs[0].a, eqs[0].b, eqs[0].h }, + { eqs[1].a, eqs[1].b, eqs[1].h }, + { eqs[2].a, eqs[2].b, eqs[2].h } + }; + + double mainDt = CalculateDeterminant(mainDtMtx); + double dtx = CalculateDeterminant(dtxMtx); + double dty = CalculateDeterminant(dtyMtx); + double dtz = CalculateDeterminant(dtzMtx); + + if (abs(mainDt) > 0.000001) { + res[0] = dtx / mainDt; + res[1] = dty / mainDt; + res[2] = dtz / mainDt; + + return EQSR_1; + } + + return (abs(dtx) > 0.000001) ? EQSR_NONE : EQSR_INF; +} + +plane_itx_res CalcPlanesIntersection(mplane_t* p1, mplane_t* p2, mplane_t* p3, float* res) { + equation3_t eqs[] = { + { p1->normal[0], p1->normal[1], p1->normal[2], p1->dist }, + { p2->normal[0], p2->normal[1], p2->normal[2], p2->dist }, + { p3->normal[0], p3->normal[1], p3->normal[2], p3->dist }, + }; + + double dblRes[3]; + + auto resKind = ResolveEq3Sys(eqs, dblRes); + switch (resKind) { + case EQSR_1: + res[0] = dblRes[0]; + res[1] = dblRes[1]; + res[2] = dblRes[2]; + return PIR_1; + + case EQSR_INF: + return PIR_INF; + + case EQSR_NONE: + return PIR_NONE; + + default: + rehlds_syserror(__FUNCTION__": invalid resKind %d", resKind); + return PIR_NONE; + } +} diff --git a/rehlds/rehlds/math_utils.h b/rehlds/rehlds/math_utils.h new file mode 100644 index 0000000..0fcf3bb --- /dev/null +++ b/rehlds/rehlds/math_utils.h @@ -0,0 +1,28 @@ +#pragma once + +#include "engine.h" + +typedef float matrix33_t[3][3]; + +//ax + by + cz = h +struct equation3_t { + double a, b, c, h; +}; + +enum equation_sys_resolve_res { + EQSR_1, + EQSR_NONE, + EQSR_INF, +}; + +enum plane_itx_res { + PIR_1, + PIR_NONE, + PIR_INF, +}; + +extern double CalculateDeterminant(matrix33_t &matrix); +extern equation_sys_resolve_res ResolveEq3Sys(equation3_t* eqs, double* res); +extern plane_itx_res CalcPlanesIntersection(mplane_t* p1, mplane_t* p2, mplane_t* p3, float* res); + + diff --git a/rehlds/rehlds/precompiled.h b/rehlds/rehlds/precompiled.h index 401c661..1393cca 100644 --- a/rehlds/rehlds/precompiled.h +++ b/rehlds/rehlds/precompiled.h @@ -19,6 +19,8 @@ #include "RehldsRuntimeConfig.h" #include "rehlds_debug.h" +#include "math_utils.h" + #ifdef HOOK_ENGINE #include "hooker.h" #endif @@ -35,6 +37,7 @@ #include "iosutil.h" + //testsuite #include "testsuite.h" #include "funccalls.h" diff --git a/rehlds/rehlds/rehlds_api_impl.cpp b/rehlds/rehlds/rehlds_api_impl.cpp index 5a6b070..3c34ea4 100644 --- a/rehlds/rehlds/rehlds_api_impl.cpp +++ b/rehlds/rehlds/rehlds_api_impl.cpp @@ -65,6 +65,52 @@ DLL_FUNCTIONS* EXT_FUNC GetEntityInterface_api() { return &gEntityInterface; } +bool EXT_FUNC GetHitboxCorners(int hitboxId, float* /* [8*3] */ corners) { + mplane_t* right = &studio_planes[hitboxId * 6 + 0 * 2 + 0]; + mplane_t* left = &studio_planes[hitboxId * 6 + 0 * 2 + 1]; + mplane_t* rear = &studio_planes[hitboxId * 6 + 1 * 2 + 0]; + mplane_t* front = &studio_planes[hitboxId * 6 + 1 * 2 + 1]; + mplane_t* top = &studio_planes[hitboxId * 6 + 2 * 2 + 0]; + mplane_t* bottom = &studio_planes[hitboxId * 6 + 2 * 2 + 1]; + + float p[3]; + + if (PIR_1 != CalcPlanesIntersection(left, front, bottom, p)) + return false; + corners[0 * 3 + 0] = p[0]; corners[0 * 3 + 1] = p[1]; corners[0 * 3 + 1] = p[2]; + + if (PIR_1 != CalcPlanesIntersection(left, front, top, p)) + return false; + corners[1 * 3 + 0] = p[0]; corners[1 * 3 + 1] = p[1]; corners[1 * 3 + 1] = p[2]; + + if (PIR_1 != CalcPlanesIntersection(right, front, top, p)) + return false; + corners[2 * 3 + 0] = p[0]; corners[2 * 3 + 1] = p[1]; corners[2 * 3 + 1] = p[2]; + + if (PIR_1 != CalcPlanesIntersection(right, front, bottom, p)) + return false; + corners[3 * 3 + 0] = p[0]; corners[3 * 3 + 1] = p[1]; corners[3 * 3 + 1] = p[2]; + + + if (PIR_1 != CalcPlanesIntersection(left, rear, bottom, p)) + return false; + corners[4 * 3 + 0] = p[0]; corners[4 * 3 + 1] = p[1]; corners[4 * 3 + 1] = p[2]; + + if (PIR_1 != CalcPlanesIntersection(left, rear, top, p)) + return false; + corners[5 * 3 + 0] = p[0]; corners[5 * 3 + 1] = p[1]; corners[5 * 3 + 1] = p[2]; + + if (PIR_1 != CalcPlanesIntersection(right, rear, top, p)) + return false; + corners[6 * 3 + 0] = p[0]; corners[6 * 3 + 1] = p[1]; corners[6 * 3 + 1] = p[2]; + + if (PIR_1 != CalcPlanesIntersection(right, rear, bottom, p)) + return false; + corners[7 * 3 + 0] = p[0]; corners[7 * 3 + 1] = p[1]; corners[7 * 3 + 1] = p[2]; + + return true; +} + CRehldsServerStatic g_RehldsServerStatic; CRehldsServerData g_RehldsServerData; CRehldsHookchains g_RehldsHookchains; @@ -99,7 +145,8 @@ RehldsFuncs_t g_RehldsApiFuncs = &MSG_WriteBits, &MSG_WriteBitVec3Coord, &MSG_EndBitWriting, - &SZ_GetSpace + &SZ_GetSpace, + &GetHitboxCorners }; sizebuf_t* EXT_FUNC GetNetMessage_api() diff --git a/rehlds/rehlds/rehlds_api_impl.h b/rehlds/rehlds/rehlds_api_impl.h index fdfdc9b..5362878 100644 --- a/rehlds/rehlds/rehlds_api_impl.h +++ b/rehlds/rehlds/rehlds_api_impl.h @@ -31,6 +31,8 @@ #include "rehlds_api.h" #include "rehlds_interfaces_impl.h" +extern bool GetHitboxCorners(int hitboxId, float* /* [8*3] */ corners); + //Steam_NotifyClientConnect typedef IHookChainImpl CRehldsHook_Steam_NotifyClientConnect; typedef IHookChainRegistryImpl CRehldsHookRegistry_Steam_NotifyClientConnect; diff --git a/rehlds/unittests/math_util_tests.cpp b/rehlds/unittests/math_util_tests.cpp new file mode 100644 index 0000000..f2f2e1e --- /dev/null +++ b/rehlds/unittests/math_util_tests.cpp @@ -0,0 +1,91 @@ +#include "precompiled.h" +#include "rehlds_tests_shared.h" +#include "cppunitlite/TestHarness.h" + +TEST(CalculateDeterminant, MathUtils, 1000) { + + struct testdata_t { + matrix33_t mtx; + double d; + }; + + testdata_t testdata[] = { + { + { + { 2.0, 5.0, -2.0 }, + { 3.0, 8.0, 0.0 }, + { 1.0, 3.0, 5.0 }, + }, + 3.0 + }, + { + { + { 4.0, -3.0, 2.0 }, + { 6.0, 11.0, 1.0 }, + { 0.0, 3.0, 0.0 }, + }, + 24.0 + } + }; + + for (int i = 0; i < ARRAYSIZE(testdata); i++) { + testdata_t* t = &testdata[i]; + + double dt = CalculateDeterminant(t->mtx); + DOUBLES_EQUAL("Determinant mismatch", t->d, dt, 0.001); + } +} + +TEST(ResolveEq3Sys, MathUtils, 1000) { + + struct testdata_t { + equation3_t eqs[3]; + equation_sys_resolve_res resKind; + double res[3]; + }; + + testdata_t testdata[] = { + { + { + { 3.0, 4.0, 2.0, 5.0 }, + { 5.0, -6.0, -4.0, -3.0 }, + { -4.0, 5.0, 3.0, 1.0 } + }, + EQSR_1, + { 1.0, -2.0, 5.0 } + }, + { + { + { 1.0, 1.0, 1.0, 5.0 }, + { 1.0, -1.0, 1.0, 1.0 }, + { 1.0, 0.0, 1.0, 2.0 } + }, + EQSR_NONE, + { 0.0, 0.0, 0.0 } + }, + { + { + { 1.0, 1.0, 1.0, 5.0 }, + { 1.0, -1.0, 1.0, 1.0 }, + { 1.0, 0.0, 1.0, 3.0 } + }, + EQSR_INF, + { 0.0, 0.0, 0.0 } + } + }; + + for (int i = 0; i < ARRAYSIZE(testdata); i++) { + testdata_t* t = &testdata[i]; + + double res[3]; + equation_sys_resolve_res resKind = ResolveEq3Sys(t->eqs, res); + UINT32_EQUALS("resKind mismatch", (uint32)t->resKind, (uint32)resKind); + + if (resKind == EQSR_1) { + DOUBLES_EQUAL("res[0] mismatch", t->res[0], res[0], 0.00001); + DOUBLES_EQUAL("res[1] mismatch", t->res[1], res[1], 0.00001); + DOUBLES_EQUAL("res[2] mismatch", t->res[2], res[2], 0.00001); + } + } + +} \ No newline at end of file