This commit is contained in:
Oscar
2025-07-25 22:49:56 +03:00
parent 03af6d458c
commit 860be9ac4c
470 changed files with 308020 additions and 436 deletions

View File

@@ -0,0 +1,35 @@
#pragma once
#define M_PI 3.14159265358979323846
#define _CS_INTERNAL_CONCATENATE(LEFT, RIGHT) LEFT##RIGHT
#define CS_CONCATENATE(LEFT, RIGHT) _CS_INTERNAL_CONCATENATE(LEFT, RIGHT)
#define MEM_PAD(SIZE) \
private: \
char CS_CONCATENATE(pad_0, __COUNTER__)[SIZE]; \
public:
#define MAX_PATH 260
#define SCHEMASYSTEM_TYPE_SCOPES_OFFSET 0x188
#define SCHEMASYSTEMTYPESCOPE_OFF1 0x3F8
#define SCHEMASYSTEMTYPESCOPE_OFF2 0x8
#define _NUMBER_MAX_BASE 36;
#define CLIENT_DLL (L"client.dll")
#define SCENESYSTEM_DLL (L"scenesystem.dll")
#define ENGINE2_DLL (L"engine2.dll")
#define GAME_RESOURCE_SERVICE_CLIENT ("GameResourceServiceClientV00")
#define SOURCE2_ENGINE_TO_CLIENT ("Source2EngineToClient00")
#define SCHEMASYSTEM_DLL L"schemasystem.dll"
#define SCHEMA_SYSTEM "SchemaSystem_00"
#define TIER0_DLL (L"tier0.dll")
#define DBGHELP_DLL (L"dbghelp.dll")

View File

@@ -0,0 +1,26 @@
#pragma once
using FNV1A_t = std::uint64_t;
namespace FNV1A
{
using FNV1A_t = std::uint64_t;
constexpr FNV1A_t ullBasis = 0xCBF29CE484222325ULL;
constexpr FNV1A_t ullPrime = 0x100000001B3ULL;
consteval FNV1A_t HashConst(const char* szString, const FNV1A_t uKey = ullBasis) noexcept
{
return (szString[0] == '\0') ? uKey : HashConst(&szString[1], (uKey ^ static_cast<FNV1A_t>(szString[0])) * ullPrime);
}
inline FNV1A_t Hash(const char* szString, FNV1A_t uKey = ullBasis) noexcept
{
while (*szString)
{
uKey ^= static_cast<FNV1A_t>(*szString++);
uKey *= ullPrime;
}
return uKey;
}
}

View File

@@ -0,0 +1,196 @@
#pragma once
#include <cstdint>
#include <limits>
#include <cstdint>
#include "Defines.h"
class CUtlMemoryPool
{
public:
int Count() const
{
return nBlocksAllocated;
}
int PeakCount() const
{
return nPeakAlloc;
}
int BlockSize() const
{
return nBlockSize;
}
protected:
class CBlob
{
public:
CBlob* pPrev;
CBlob* pNext;
int nNumBytes;
char Data[1];
char Padding[3];
};
int nBlockSize;
int nBlocksPerBlob;
int nGrowMode;
int nBlocksAllocated;
int nPeakAlloc;
unsigned short nAlignment;
unsigned short nNumBlobs;
void* pHeadOfFreeList;
void* pAllocOwner;
CBlob BlobHead;
};
using UtlTSHashHandle_t = std::uintptr_t;
inline unsigned HashIntConventional(const int n)
{
unsigned hash = 0xAAAAAAAA + (n & 0xFF);
hash = (hash << 5) + hash + ((n >> 8) & 0xFF);
hash = (hash << 5) + hash + ((n >> 16) & 0xFF);
hash = (hash << 5) + hash + ((n >> 24) & 0xFF);
return hash;
}
template <int nBucketCount, class tKey = std::uintptr_t>
class CUtlTSHashGenericHash
{
public:
static int Hash(const tKey& Key, int nBucketMask)
{
int nHash = HashIntConventional(std::uintptr_t(Key));
if (nBucketCount <= UINT16_MAX)
{
nHash ^= (nHash >> 16);
}
if (nBucketCount <= UINT8_MAX)
{
nHash ^= (nHash >> 8);
}
return (nHash & nBucketMask);
}
static bool Compare(const tKey& lhs, const tKey& rhs)
{
return lhs == rhs;
}
};
template <class tElement, int nBucketCount, class tKey = std::uintptr_t, class tHashFuncs = CUtlTSHashGenericHash<nBucketCount, tKey>, int nAlignment = 0>
class CUtlTSHash
{
static constexpr int nBucketMask = nBucketCount - 1;
public:
static constexpr UtlTSHashHandle_t InvalidHandle()
{
return static_cast<UtlTSHashHandle_t>(0);
}
UtlTSHashHandle_t Find(tKey uiKey)
{
int iBucket = tHashFuncs::Hash(uiKey, nBucketCount);
const HashBucket_t& hashBucket = aBuckets[iBucket];
const UtlTSHashHandle_t hHash = Find(uiKey, hashBucket.pFirst, nullptr);
return hHash ? hHash : Find(uiKey, hashBucket.pFirstUncommited, hashBucket.pFirst);
}
int Count() const
{
return EntryMemory.Count();
}
int GetElements(int nFirstElement, int nCount, UtlTSHashHandle_t* pHandles) const
{
int nIndex = 0;
for (int nBucketIndex = 0; nBucketIndex < nBucketCount; nBucketIndex++)
{
const HashBucket_t& hashBucket = aBuckets[nBucketIndex];
HashFixedData_t* pElement = hashBucket.pFirstUncommited;
for (; pElement; pElement = pElement->pNext)
{
if (--nFirstElement >= 0)
continue;
pHandles[nIndex++] = reinterpret_cast<UtlTSHashHandle_t>(pElement);
if (nIndex >= nCount)
return nIndex;
}
}
return nIndex;
}
tElement Element(UtlTSHashHandle_t hHash)
{
return ((HashFixedData_t*)(hHash))->Data;
}
const tElement& Element(UtlTSHashHandle_t hHash) const
{
return reinterpret_cast<HashFixedData_t*>(hHash)->Data;
}
tElement& operator[](UtlTSHashHandle_t hHash)
{
return reinterpret_cast<HashFixedData_t*>(hHash)->Data;
}
const tElement& operator[](UtlTSHashHandle_t hHash) const
{
return reinterpret_cast<HashFixedData_t*>(hHash)->Data;
}
tKey GetID(UtlTSHashHandle_t hHash) const
{
return reinterpret_cast<HashFixedData_t*>(hHash)->uiKey;
}
private:
template <typename tData>
struct HashFixedDataInternal_t
{
tKey uiKey;
HashFixedDataInternal_t<tData>* pNext;
tData Data;
};
using HashFixedData_t = HashFixedDataInternal_t<tElement>;
struct HashBucket_t
{
private:
[[maybe_unused]] std::byte pad0[0x18];
public:
HashFixedData_t* pFirst;
HashFixedData_t* pFirstUncommited;
};
UtlTSHashHandle_t Find(tKey uiKey, HashFixedData_t* pFirstElement, HashFixedData_t* pLastElement)
{
for (HashFixedData_t* pElement = pFirstElement; pElement != pLastElement; pElement = pElement->pNext)
{
if (tHashFuncs::Compare(pElement->uiKey, uiKey))
return reinterpret_cast<UtlTSHashHandle_t>(pElement);
}
return InvalidHandle();
}
CUtlMemoryPool EntryMemory;
MEM_PAD(0x40);
HashBucket_t aBuckets[nBucketCount];
bool bNeedsCommit;
};

View File

@@ -0,0 +1,73 @@
#pragma once
#include "Memory.h"
using InstantiateInterfaceFn_t = void* (*)();
class ISchemaSystem;
class IGameResourceService;
class IEngineClient;
class IEngineCVar;
class Tracing;
class IMemAlloc;
class CInterfaceRegister
{
public:
InstantiateInterfaceFn_t fnCreate;
const char* szName;
CInterfaceRegister* pNext;
};
namespace I
{
static const CInterfaceRegister* GetRegisterList(const wchar_t* wszModuleName)
{
void* hModule = M::GetModuleBaseHandle(wszModuleName);
if (hModule == nullptr)
return nullptr;
std::uint8_t* pCreateInterface = reinterpret_cast<std::uint8_t*>(M::GetExportAddress(hModule, "CreateInterface"));
if (pCreateInterface == nullptr)
{
return nullptr;
}
return *reinterpret_cast<CInterfaceRegister**>(M::ResolveRelativeAddress(pCreateInterface, 0x3, 0x7));
}
template <typename T = void*>
T* Capture(const CInterfaceRegister* pModuleRegister, const char* szInterfaceName)
{
std::size_t nInterfaceNameLength = std::strlen(szInterfaceName);
for (const CInterfaceRegister* pRegister = pModuleRegister; pRegister != nullptr; pRegister = pRegister->pNext)
{
std::size_t nRegisterNameLength = std::strlen(pRegister->szName);
if (std::strncmp(szInterfaceName, pRegister->szName, nInterfaceNameLength) == 0 &&
(nRegisterNameLength == nInterfaceNameLength ||
std::strtol(pRegister->szName + nInterfaceNameLength, nullptr, 10) > 0))
{
void* pInterface = pRegister->fnCreate();
return static_cast<T*>(pInterface);
}
}
return nullptr;
}
inline ISchemaSystem* SchemaSystem = nullptr;
inline Tracing* Trace = nullptr;
inline IGameResourceService* GameResourceService = nullptr;
inline IEngineClient* Engine = nullptr;
inline IEngineCVar* Cvar = nullptr;
inline IMemAlloc* MemAlloc = nullptr;
}

View File

@@ -0,0 +1,200 @@
#pragma once
#include "Windows.h"
#include "string"
#include "vector"
#include "cVector.h"
#include "../qAngles.h"
#include "Defines.h"
#ifndef DEG2RAD
#define DEG2RAD(x) ((x) * (M_PI / 180.0f))
#endif
class CUtlBuffer;
namespace M
{
inline void* GetModuleBaseHandle(const wchar_t* wszModuleName)
{
if (wszModuleName == nullptr)
return GetModuleHandle(nullptr);
HMODULE hModule = GetModuleHandleW(wszModuleName);
return hModule;
}
template <typename C>
inline constexpr int StringCompare(const C* tszLeft, const C* tszRight)
{
if constexpr (std::is_same_v<C, char>)
{
return std::strcmp(tszLeft, tszRight);
}
else if constexpr (std::is_same_v<C, wchar_t>)
{
return std::wcscmp(tszLeft, tszRight);
}
}
inline void* GetExportAddress(const void* hModuleBase, const char* szProcedureName)
{
const auto pBaseAddress = static_cast<const std::uint8_t*>(hModuleBase);
const auto pIDH = static_cast<const IMAGE_DOS_HEADER*>(hModuleBase);
if (pIDH->e_magic != IMAGE_DOS_SIGNATURE)
return nullptr;
const auto pINH = reinterpret_cast<const IMAGE_NT_HEADERS64*>(pBaseAddress + pIDH->e_lfanew);
if (pINH->Signature != IMAGE_NT_SIGNATURE)
return nullptr;
const IMAGE_OPTIONAL_HEADER64* pIOH = &pINH->OptionalHeader;
const std::uintptr_t nExportDirectorySize = pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
const std::uintptr_t uExportDirectoryAddress = pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (nExportDirectorySize == 0U || uExportDirectoryAddress == 0U)
{
return nullptr;
}
const auto pIED = reinterpret_cast<const IMAGE_EXPORT_DIRECTORY*>(pBaseAddress + uExportDirectoryAddress);
const auto pNamesRVA = reinterpret_cast<const std::uint32_t*>(pBaseAddress + pIED->AddressOfNames);
const auto pNameOrdinalsRVA = reinterpret_cast<const std::uint16_t*>(pBaseAddress + pIED->AddressOfNameOrdinals);
const auto pFunctionsRVA = reinterpret_cast<const std::uint32_t*>(pBaseAddress + pIED->AddressOfFunctions);
// Perform binary search to find the export by name
std::size_t nRight = pIED->NumberOfNames, nLeft = 0U;
while (nRight != nLeft)
{
// Avoid INT_MAX/2 overflow
const std::size_t uMiddle = nLeft + ((nRight - nLeft) >> 1U);
const int iResult = StringCompare(szProcedureName, reinterpret_cast<const char*>(pBaseAddress + pNamesRVA[uMiddle]));
if (iResult == 0)
{
const std::uint32_t uFunctionRVA = pFunctionsRVA[pNameOrdinalsRVA[uMiddle]];
// Check if it's a forwarded export
if (uFunctionRVA >= uExportDirectoryAddress && uFunctionRVA - uExportDirectoryAddress < nExportDirectorySize)
{
// Forwarded exports are not supported
break;
}
return const_cast<std::uint8_t*>(pBaseAddress) + uFunctionRVA;
}
if (iResult > 0)
nLeft = uMiddle + 1;
else
nRight = uMiddle;
}
return nullptr;
}
inline std::uint8_t* ResolveRelativeAddress(std::uint8_t* nAddressBytes, std::uint32_t nRVAOffset, std::uint32_t nRIPOffset)
{
std::uint32_t nRVA = *reinterpret_cast<std::uint32_t*>(nAddressBytes + nRVAOffset);
std::uint64_t nRIP = reinterpret_cast<std::uint64_t>(nAddressBytes) + nRIPOffset;
return reinterpret_cast<std::uint8_t*>(nRVA + nRIP);
}
template <typename T, std::size_t nIndex, class CBaseClass, typename... Args_t>
static inline T CallVFunc(CBaseClass* thisptr, Args_t... argList)
{
using VirtualFn_t = T(__thiscall*)(const void*, decltype(argList)...);
return (*reinterpret_cast<VirtualFn_t* const*>(reinterpret_cast<std::uintptr_t>(thisptr)))[nIndex](thisptr, argList...);
}
inline std::vector<int> PatternToBytes(const char* pattern) {
std::vector<int> bytes;
const char* current = pattern;
while (*current) {
if (*current == '?') {
bytes.push_back(-1); // Wildcard
current++;
if (*current == '?') current++; // Skip second '?'
}
else {
bytes.push_back(static_cast<int>(std::strtoul(current, nullptr, 16)));
current += 2;
}
if (*current == ' ') current++; // Skip spaces
}
return bytes;
}
inline uintptr_t FindPattern(const wchar_t* moduleName, const char* pattern)
{
HMODULE hModule = GetModuleHandleW(moduleName);
if (!hModule) return 0;
std::uint8_t* moduleBase = reinterpret_cast<std::uint8_t*>(hModule);
PIMAGE_NT_HEADERS ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(moduleBase + reinterpret_cast<PIMAGE_DOS_HEADER>(moduleBase)->e_lfanew);
std::size_t moduleSize = ntHeaders->OptionalHeader.SizeOfImage;
std::vector<int> patternBytes = PatternToBytes(pattern);
std::size_t patternLength = patternBytes.size();
for (std::size_t i = 0; i <= moduleSize - patternLength; i++) {
bool found = true;
for (std::size_t j = 0; j < patternLength; j++) {
if (patternBytes[j] != -1 && patternBytes[j] != moduleBase[i + j]) {
found = false;
break;
}
}
if (found)
return reinterpret_cast<uintptr_t>(moduleBase + i);
}
return 0;
}
template <typename T = uintptr_t>
T GetAbsoluteAddress(T pRelativeAddress, int nPreOffset = 0x0, int nPostOffset = 0x0) {
std::int32_t relativeOffset = *reinterpret_cast<std::int32_t*>(reinterpret_cast<std::uint8_t*>(pRelativeAddress) + nPreOffset);
return pRelativeAddress + relativeOffset + sizeof(std::int32_t) + nPreOffset + nPostOffset;
}
inline void** CopyVirtualTable(void** Original)
{
constexpr int Entries = 8192 / sizeof(void*);
void** NewVTable = new void* [Entries];
for (int i = 0; i < Entries; ++i)
NewVTable[i] = Original[i];
return NewVTable;
}
inline Vector_t AngleToDirection(const QAngle_t& Angles)
{
Vector_t Direction;
float Pitch = DEG2RAD(Angles.x);
float Yaw = DEG2RAD(Angles.y);
Direction.x = cos(Pitch) * cos(Yaw);
Direction.y = cos(Pitch) * sin(Yaw);
Direction.z = -sin(Pitch);
return Direction;
}
inline void(__fastcall* fnUtlBufferInit)(CUtlBuffer*, int, int, int);
inline void(__fastcall* fnUtlBufferPutString)(CUtlBuffer*, const char*);
inline void(__fastcall* fnUtlBufferEnsureCapacity)(CUtlBuffer*, int);
}

View File

@@ -0,0 +1,113 @@
#pragma once
#include <type_traits>
namespace detail {
extern "C" void* _spoofer_stub();
template <typename Ret, typename... Args>
static auto shellcode_stub_helper(
const void* shell,
Args... args
) -> Ret {
auto fn = (Ret(*)(Args...))(shell);
return fn(args...);
}
template <std::size_t Argc, typename>
struct argument_remapper {
// At least 5 params
template<
typename Ret,
typename First,
typename Second,
typename Third,
typename Fourth,
typename... Pack
>
static auto do_call(
const void* shell,
void* shell_param,
First first,
Second second,
Third third,
Fourth fourth,
Pack... pack
) -> Ret {
return shellcode_stub_helper<
Ret,
First,
Second,
Third,
Fourth,
void*,
void*,
Pack...
>(
shell,
first,
second,
third,
fourth,
shell_param,
nullptr,
pack...
);
}
};
template <std::size_t Argc>
struct argument_remapper<Argc, std::enable_if_t<Argc <= 4>> {
// 4 or less params
template<
typename Ret,
typename First = void*,
typename Second = void*,
typename Third = void*,
typename Fourth = void*
>
static auto do_call(
const void* shell,
void* shell_param,
First first = First{},
Second second = Second{},
Third third = Third{},
Fourth fourth = Fourth{}
) -> Ret {
return shellcode_stub_helper<
Ret,
First,
Second,
Third,
Fourth,
void*,
void*
>(
shell,
first,
second,
third,
fourth,
shell_param,
nullptr
);
}
};
}
template <typename result, typename... arguments>
static auto FakeReturnAddress(
const void* trampoline,
result(*fn)(arguments...),
arguments... args
) -> result {
struct shell_params {
const void* trampoline;
void* function;
void* register_; // originally rbx, currently rdx
};
shell_params p = { trampoline, reinterpret_cast<void*>(fn) };
using mapper = detail::argument_remapper<sizeof...(arguments), void>;
return mapper::template do_call<result, arguments...>((const void*)&detail::_spoofer_stub, &p, args...);
}

View File

@@ -0,0 +1,400 @@
#pragma once
// used: [stl] numeric_limits
#include <limits>
// used: [crt] isfinite, fmodf, sqrtf
#include <cmath>
// forward declarations
struct QAngle_t;
struct Matrix3x4_t;
// @source: master/public/mathlib/vector.h
struct Vector2D_t
{
constexpr Vector2D_t(const float x = 0.0f, const float y = 0.0f) :
x(x), y(y) { }
[[nodiscard]] bool IsZero() const
{
// @note: to make this implementation right, we should use fpclassify here, but game aren't doing same, probably it's better to keep this same, just ensure that it will be compiled same
return (this->x == 0.0f && this->y == 0.0f);
}
float DistanceTo(const Vector2D_t& other) const
{
float dx = x - other.x;
float dy = y - other.y;
return sqrt(dx * dx + dy * dy);
}
float x = 0.0f, y = 0.0f;
};
struct Vector_t
{
constexpr Vector_t(const float x = 0.0f, const float y = 0.0f, const float z = 0.0f) :
x(x), y(y), z(z) { }
constexpr Vector_t(const float* arrVector) :
x(arrVector[0]), y(arrVector[1]), z(arrVector[2]) { }
constexpr Vector_t(const Vector2D_t& vecBase2D) :
x(vecBase2D.x), y(vecBase2D.y) { }
#pragma region vector_array_operators
[[nodiscard]] float& operator[](const int nIndex)
{
return reinterpret_cast<float*>(this)[nIndex];
}
[[nodiscard]] const float& operator[](const int nIndex) const
{
return reinterpret_cast<const float*>(this)[nIndex];
}
#pragma endregion
#pragma region vector_relational_operators
bool operator==(const Vector_t& vecBase) const
{
return this->IsEqual(vecBase);
}
bool operator!=(const Vector_t& vecBase) const
{
return !this->IsEqual(vecBase);
}
#pragma endregion
#pragma region vector_assignment_operators
constexpr Vector_t& operator=(const Vector_t& vecBase)
{
this->x = vecBase.x;
this->y = vecBase.y;
this->z = vecBase.z;
return *this;
}
constexpr Vector_t& operator=(const Vector2D_t& vecBase2D)
{
this->x = vecBase2D.x;
this->y = vecBase2D.y;
this->z = 0.0f;
return *this;
}
#pragma endregion
#pragma region vector_arithmetic_assignment_operators
constexpr Vector_t& operator+=(const Vector_t& vecBase)
{
this->x += vecBase.x;
this->y += vecBase.y;
this->z += vecBase.z;
return *this;
}
constexpr Vector_t& operator-=(const Vector_t& vecBase)
{
this->x -= vecBase.x;
this->y -= vecBase.y;
this->z -= vecBase.z;
return *this;
}
constexpr Vector_t& operator*=(const Vector_t& vecBase)
{
this->x *= vecBase.x;
this->y *= vecBase.y;
this->z *= vecBase.z;
return *this;
}
constexpr Vector_t& operator/=(const Vector_t& vecBase)
{
this->x /= vecBase.x;
this->y /= vecBase.y;
this->z /= vecBase.z;
return *this;
}
constexpr Vector_t& operator+=(const float flAdd)
{
this->x += flAdd;
this->y += flAdd;
this->z += flAdd;
return *this;
}
constexpr Vector_t& operator-=(const float flSubtract)
{
this->x -= flSubtract;
this->y -= flSubtract;
this->z -= flSubtract;
return *this;
}
constexpr Vector_t& operator*=(const float flMultiply)
{
this->x *= flMultiply;
this->y *= flMultiply;
this->z *= flMultiply;
return *this;
}
constexpr Vector_t& operator/=(const float flDivide)
{
this->x /= flDivide;
this->y /= flDivide;
this->z /= flDivide;
return *this;
}
#pragma endregion
#pragma region vector_arithmetic_unary_operators
constexpr Vector_t& operator-()
{
this->x = -this->x;
this->y = -this->y;
this->z = -this->z;
return *this;
}
constexpr Vector_t operator-() const
{
return { -this->x, -this->y, -this->z };
}
#pragma endregion
#pragma region vector_arithmetic_ternary_operators
Vector_t operator+(const Vector_t& vecAdd) const
{
return { this->x + vecAdd.x, this->y + vecAdd.y, this->z + vecAdd.z };
}
Vector_t operator-(const Vector_t& vecSubtract) const
{
return { this->x - vecSubtract.x, this->y - vecSubtract.y, this->z - vecSubtract.z };
}
Vector_t operator*(const Vector_t& vecMultiply) const
{
return { this->x * vecMultiply.x, this->y * vecMultiply.y, this->z * vecMultiply.z };
}
Vector_t operator/(const Vector_t& vecDivide) const
{
return { this->x / vecDivide.x, this->y / vecDivide.y, this->z / vecDivide.z };
}
Vector_t operator+(const float flAdd) const
{
return { this->x + flAdd, this->y + flAdd, this->z + flAdd };
}
Vector_t operator-(const float flSubtract) const
{
return { this->x - flSubtract, this->y - flSubtract, this->z - flSubtract };
}
Vector_t operator*(const float flMultiply) const
{
return { this->x * flMultiply, this->y * flMultiply, this->z * flMultiply };
}
Vector_t operator/(const float flDivide) const
{
return { this->x / flDivide, this->y / flDivide, this->z / flDivide };
}
#pragma endregion
/// @returns: true if each component of the vector is finite, false otherwise
[[nodiscard]] bool IsValid() const
{
return std::isfinite(this->x) && std::isfinite(this->y) && std::isfinite(this->z);
}
constexpr void Invalidate()
{
this->x = this->y = this->z = std::numeric_limits<float>::infinity();
}
/// @returns: true if each component of the vector equals to another, false otherwise
[[nodiscard]] bool IsEqual(const Vector_t& vecEqual, const float flErrorMargin = std::numeric_limits<float>::epsilon()) const
{
return (std::fabsf(this->x - vecEqual.x) < flErrorMargin && std::fabsf(this->y - vecEqual.y) < flErrorMargin && std::fabsf(this->z - vecEqual.z) < flErrorMargin);
}
/// @returns: true if each component of the vector equals to zero, false otherwise
[[nodiscard]] bool IsZero() const
{
// @note: to make this implementation right, we should use fpclassify here, but game aren't doing same, probably it's better to keep this same, just ensure that it will be compiled same
return (this->x == 0.0f && this->y == 0.0f && this->z == 0.0f);
}
[[nodiscard]] float Length() const
{
return std::sqrtf(this->LengthSqr());
}
[[nodiscard]] constexpr float LengthSqr() const
{
return DotProduct(*this);
}
[[nodiscard]] float Length2D() const
{
return std::sqrtf(this->Length2DSqr());
}
[[nodiscard]] constexpr float Length2DSqr() const
{
return (this->x * this->x + this->y * this->y);
}
[[nodiscard]] float DistTo(const Vector_t& vecEnd) const
{
return (*this - vecEnd).Length();
}
[[nodiscard]] constexpr float DistToSqr(const Vector_t& vecEnd) const
{
return (*this - vecEnd).LengthSqr();
}
/// normalize magnitude of each component of the vector
/// @returns: length of the vector
float NormalizeInPlace()
{
const float flLength = this->Length();
const float flRadius = 1.0f / (flLength + std::numeric_limits<float>::epsilon());
this->x *= flRadius;
this->y *= flRadius;
this->z *= flRadius;
return flLength;
}
/// normalize magnitude of each component of the vector
/// @returns: copy of the vector with normalized components
[[nodiscard]] Vector_t Normalized() const
{
Vector_t vecOut = *this;
vecOut.NormalizeInPlace();
return vecOut;
}
[[nodiscard]] constexpr float DotProduct(const Vector_t& vecDot) const
{
return (this->x * vecDot.x + this->y * vecDot.y + this->z * vecDot.z);
}
[[nodiscard]] constexpr Vector_t CrossProduct(const Vector_t& vecCross) const
{
return { this->y * vecCross.z - this->z * vecCross.y, this->z * vecCross.x - this->x * vecCross.z, this->x * vecCross.y - this->y * vecCross.x };
}
/// @returns: transformed vector by given transformation matrix
[[nodiscard]] Vector_t Transform(const Matrix3x4_t& matTransform) const;
[[nodiscard]] Vector2D_t ToVector2D() const
{
return { this->x, this->y };
}
/// convert forward direction vector to other direction vectors
/// @param[out] pvecRight [optional] output for converted right vector
/// @param[out] pvecUp [optional] output for converted up vector
void ToDirections(Vector_t* pvecRight, Vector_t* pvecUp) const
{
if (std::fabsf(this->x) < 1e-6f && std::fabsf(this->y) < 1e-6f)
{
// pitch 90 degrees up/down from identity
if (pvecRight != nullptr)
{
pvecRight->x = 0.0f;
pvecRight->y = -1.0f;
pvecRight->z = 0.0f;
}
if (pvecUp != nullptr)
{
pvecUp->x = -this->z;
pvecUp->y = 0.0f;
pvecUp->z = 0.0f;
}
}
else
{
if (pvecRight != nullptr)
{
pvecRight->x = this->y;
pvecRight->y = -this->x;
pvecRight->z = 0.0f;
pvecRight->NormalizeInPlace();
}
if (pvecUp != nullptr)
{
pvecUp->x = (-this->x) * this->z;
pvecUp->y = -(this->y * this->z);
pvecUp->z = this->y * this->y - (-this->x) * this->x;
pvecUp->NormalizeInPlace();
}
}
}
/// @returns: 2D angles converted from direction vector
[[nodiscard]] QAngle_t ToAngles() const;
/// @returns: matrix converted from forward direction vector
[[nodiscard]] Matrix3x4_t ToMatrix() const;
float x = 0.0f, y = 0.0f, z = 0.0f;
};
struct Vector4D_t
{
constexpr Vector4D_t(const float x = 0.0f, const float y = 0.0f, const float z = 0.0f, const float w = 0.0f) :
x(x), y(y), z(z), w(w) { }
float x = 0.0f, y = 0.0f, z = 0.0f, w = 0.0f;
};
struct alignas(16) VectorAligned_t : Vector_t
{
VectorAligned_t() = default;
explicit VectorAligned_t(const Vector_t& vecBase)
{
this->x = vecBase.x;
this->y = vecBase.y;
this->z = vecBase.z;
this->w = 0.0f;
}
constexpr VectorAligned_t& operator=(const Vector_t& vecBase)
{
this->x = vecBase.x;
this->y = vecBase.y;
this->z = vecBase.z;
this->w = 0.0f;
return *this;
}
float w = 0.0f;
};
static_assert(alignof(VectorAligned_t) == 16);

View File

@@ -0,0 +1,32 @@
PUBLIC _spoofer_stub
option casemap :none
; if the line is labelled as MODIFY you need to modify the register it reads or writes to
; valid registers include: rbx, rbp+0x0, rdi, rsi, r12, r13+0x0, r14, r15
_TEXT SEGMENT
_spoofer_stub PROC
pop r11 ; poping without setting up stack frame, r11 is the return address (the one in our code)
add rsp, 8 ; skipping callee reserved space
mov rax, [rsp + 24] ; dereference shell_param
mov r10, [rax] ; load shell_param.trampoline
mov [rsp], r10 ; store address of trampoline as return address
mov r10, [rax + 8] ; load shell_param.function
mov [rax + 8], r11 ; store the original return address in shell_param.function
mov [rax + 16], rdi ; preserve register in shell_param.register_ | MODIFY
lea rdi, fixup ; load fixup address in register | MODIFY
mov [rax], rdi ; store address of fixup label in shell_param.trampoline | MODIFY
mov rdi, rax ; preserve address of shell_param in register | MODIFY
jmp r10 ; call shell_param.function
fixup:
sub rsp, 16
mov rcx, rdi ; restore address of shell_param | MODIFY
mov rdi, [rcx + 16] ; restore register from shell_param.register_ | MODIFY
jmp QWORD PTR [rcx + 8] ; jmp to the original return address
_spoofer_stub ENDP
_TEXT ENDS
END