This commit is contained in:
Oscar
2025-07-17 13:52:06 +03:00
commit 2f50c8a911
206 changed files with 246874 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
#pragma once
#include <stdint.h>
// FNV1a c++11 constexpr compile time hash functions, 32 and 64 bit
// str should be a null terminated string literal, value should be left out
// e.g hash_32_fnv1a_const("example")
// code license: public domain or equivalent
// post: https://notes.underscorediscovery.com/constexpr-fnv1a/
constexpr uint32_t val_32_const = 0x811c9dc5;
constexpr uint32_t prime_32_const = 0x1000193;
inline constexpr uint32_t hash_32_fnv1a_const(const char* const str, const uint32_t value = val_32_const) noexcept
{
return (str[0] == '\0') ? value : hash_32_fnv1a_const(&str[1], (value ^ uint32_t(str[0])) * prime_32_const);
}
// life do be like that
#define HASH hash_32_fnv1a_const

View File

@@ -0,0 +1,33 @@
#include "log.h"
#include "../../interfaces/interfaces.h"
// Temporary, will implement much more beautiful logging code wise (also I'm not really sorry for the watermark formatting :3)
void Logger::Log(const char* text, LogType logType) {
std::string message;
Color color(255, 255, 255, 255);
switch (logType) {
case LogType::Info:
message = "\n[*] ";
break;
case LogType::Warning:
message = "\n[?] ";
color = Color(255, 222, 105, 255);
break;
case LogType::Error:
message = "\n[!] ";
color = Color(255, 92, 87, 255);
break;
case LogType::None:
message = "\n";
}
message += text;
I::ConColorMsg(color, message.c_str());
}
void Logger::Watermark() {
const char* watermark = "\n /$$$$$$$$ /$$ /$$ /$$ \n|__ $$__/ | $$ | $$ /$ | $$ \n | $$ /$$$$$$ /$$$$$$/$$$$ /$$$$$$ | $$ /$$$$$$ | $$ /$$$| $$ /$$$$$$ /$$$$$$ /$$$$$$ \n | $$ /$$__ $$| $$_ $$_ $$ /$$__ $$| $$ /$$__ $$| $$/$$ $$ $$ |____ $$ /$$__ $$ /$$__ $$\n | $$| $$$$$$$$| $$ \\ $$ \\ $$| $$ \\ $$| $$| $$$$$$$$| $$$$_ $$$$ /$$$$$$$| $$ \\__/| $$$$$$$$\n | $$| $$_____/| $$ | $$ | $$| $$ | $$| $$| $$_____/| $$$/ \\ $$$ /$$__ $$| $$ | $$_____/\n | $$| $$$$$$$| $$ | $$ | $$| $$$$$$$/| $$| $$$$$$$| $$/ \\ $$| $$$$$$$| $$ | $$$$$$$\n |__/ \\_______/|__/ |__/ |__/| $$____/ |__/ \\_______/|__/ \\__/ \\_______/|__/ \\_______/\n | $$ \n | $$ \n |__/ \n";
I::ConColorMsg(Color(152, 52, 224, 255), watermark);
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include <string>
enum LogType {
Info,
Warning,
Error,
None
};
class Logger {
public:
// Using std::string for ease of use, overhead is practically non-existent
static void Log(const char* text, LogType = LogType::Info);
static void Watermark();
};

View File

@@ -0,0 +1,9 @@
#pragma once
#include <algorithm>
namespace Math {
template <typename T>
T clamp(T value, T min, T max) {
return std::min(std::max(value, min), max);
}
}

View File

@@ -0,0 +1,622 @@
#pragma once
#include <cstddef>
#define debug(EXPRESSION) static_cast<void>(0)
#pragma warning (disable:4100)
#pragma warning (disable:4514)
template <class T>
inline void V_swap(T& x, T& y)
{
T temp = x;
x = y;
y = temp;
}
template <class T, class N = size_t>
class CUtlMemory
{
enum
{
EXTERNAL_BUFFER_MARKER = -1,
EXTERNAL_CONST_BUFFER_MARKER = -2,
};
public:
class Iterator_t
{
public:
Iterator_t(const N nIndex) :
nIndex(nIndex) { }
bool operator==(const Iterator_t it) const
{
return nIndex == it.nIndex;
}
bool operator!=(const Iterator_t it) const
{
return nIndex != it.nIndex;
}
N nIndex;
};
CUtlMemory() :
pMemory(nullptr), nAllocationCount(0), nGrowSize(0) { }
CUtlMemory& operator=(const CUtlMemory& rhs)
{
if (this != &rhs)
{
pMemory = rhs.pMemory;
}
return *this;
}
CUtlMemory(const int nInitialGrowSize, const int nAllocationCount) :
pMemory(nullptr), nAllocationCount(nAllocationCount), nGrowSize(nInitialGrowSize)
{
if (nAllocationCount > 0)
pMemory = static_cast<T*>(alloca(nAllocationCount * sizeof(T)));
}
CUtlMemory(T* pMemory, const int nElements) :
pMemory(pMemory), nAllocationCount(nElements), nGrowSize(EXTERNAL_BUFFER_MARKER) { }
CUtlMemory(T* pMemory, const void* pElements, size_t size) :
pMemory(pMemory), nAllocationCount(static_cast<N>(pElements / sizeof(T))), nGrowSize(size)
{
if (pElements != nullptr)
{
memcpy(pMemory, pElements, size);
}
}
~CUtlMemory()
{
Purge();
}
template<class T, class N>
inline CUtlMemory(CUtlMemory&& moveFrom)
{
moveFrom.pMemory = nullptr;
moveFrom.nAllocationCount = 0;
moveFrom.nGrowSize = 0;
}
template<class T, class N>
inline CUtlMemory& operator=(CUtlMemory&& moveFrom)
{
T* pMemoryTemp = moveFrom.pMemory;
const int nAllocationCountTemp = moveFrom.nAllocationCount;
const int nGrowSizeTemp = moveFrom.nGrowSize;
moveFrom.pMemory = nullptr;
moveFrom.nAllocationCount = 0;
moveFrom.nGrowSize = 0;
Purge();
pMemory = pMemoryTemp;
nAllocationCount = nAllocationCountTemp;
nGrowSize = nGrowSizeTemp;
return *this;
}
[[nodiscard]] T& operator[](const N nIndex)
{
return pMemory[nIndex];
}
[[nodiscard]] const T& operator[](const N nIndex) const
{
return pMemory[nIndex];
}
[[nodiscard]] T& Element(const N nIndex)
{
return pMemory[nIndex];
}
[[nodiscard]] const T& Element(const N nIndex) const
{
return pMemory[nIndex];
}
[[nodiscard]] T* Base()
{
return pMemory;
}
[[nodiscard]] const T* Base() const
{
return pMemory;
}
[[nodiscard]] int AllocationCount() const
{
return nAllocationCount;
}
int AllocationNum() const
{
return nAllocationCount;
}
[[nodiscard]] bool IsExternallyAllocated() const
{
return nGrowSize <= EXTERNAL_BUFFER_MARKER;
}
[[nodiscard]] static N InvalidIndex()
{
return static_cast<N>(-1);
}
[[nodiscard]] bool IsValidIndex(N nIndex) const
{
return (nIndex >= 0) && (nIndex < nAllocationCount);
}
[[nodiscard]] Iterator_t First() const
{
return Iterator_t(IsValidIndex(0) ? 0 : InvalidIndex());
}
[[nodiscard]] Iterator_t Next(const Iterator_t& it) const
{
return Iterator_t(IsValidIndex(it.nIndex + 1) ? it.nIndex + 1 : InvalidIndex());
}
[[nodiscard]] N GetIndex(const Iterator_t& it) const
{
return it.nIndex;
}
[[nodiscard]] bool IsIndexAfter(N nIndex, const Iterator_t& it) const
{
return nIndex > it.nIndex;
}
[[nodiscard]] bool IsValidIterator(const Iterator_t& it) const
{
return IsValidIndex(it.index);
}
[[nodiscard]] Iterator_t InvalidIterator() const
{
return Iterator_t(InvalidIndex());
}
void Grow(const int nCount = 1)
{
if (IsExternallyAllocated())
return;
int nAllocationRequested = nAllocationCount + nCount;
int nNewAllocationCount = 0;
if (nGrowSize)
nAllocationCount = ((1 + ((nAllocationRequested - 1) / nGrowSize)) * nGrowSize);
else
{
if (nAllocationCount == 0)
nAllocationCount = (31 + sizeof(T)) / sizeof(T);
while (nAllocationCount < nAllocationRequested)
nAllocationCount <<= 1;
}
if (static_cast<int>(static_cast<N>(nNewAllocationCount)) < nAllocationRequested)
{
if (static_cast<int>(static_cast<N>(nNewAllocationCount)) == 0 && static_cast<int>(static_cast<N>(nNewAllocationCount - 1)) >= nAllocationRequested)
--nNewAllocationCount;
else
{
if (static_cast<int>(static_cast<N>(nAllocationRequested)) != nAllocationRequested)
return;
while (static_cast<int>(static_cast<N>(nNewAllocationCount)) < nAllocationRequested)
nNewAllocationCount = (nNewAllocationCount + nAllocationRequested) / 2;
}
}
nAllocationCount = nNewAllocationCount;
// @test: we can always call realloc, since it must allocate instead when passed null ptr
if (pMemory != nullptr)
pMemory = static_cast<T*>(realloc(pMemory, nAllocationCount * sizeof(T)));
else
pMemory = static_cast<T*>(alloca(nAllocationCount * sizeof(T)));
}
void EnsureCapacity(const int nCapacity)
{
if (nAllocationCount >= nCapacity)
return;
if (IsExternallyAllocated())
{
// can't grow a buffer whose memory was externally allocated
debug(false);
return;
}
nAllocationCount = nCapacity;
// @test: we can always call realloc, since it must allocate instead when passed null ptr
if (pMemory != nullptr)
pMemory = static_cast<T*>(realloc(pMemory, nAllocationCount * sizeof(T)));
else
pMemory = static_cast<T*>(alloca(nAllocationCount * sizeof(T)));
}
void ConvertToGrowableMemory(int nInitialGrowSize)
{
if (!IsExternallyAllocated())
return;
nGrowSize = nInitialGrowSize;
if (nAllocationCount > 0)
{
const int nByteCount = nAllocationCount * sizeof(T);
T* pGrowableMemory = static_cast<T*>(alloca(nByteCount));
memcpy(pGrowableMemory, pMemory, nByteCount);
pMemory = pGrowableMemory;
}
else
pMemory = nullptr;
}
void Purge()
{
if (IsExternallyAllocated())
return;
if (pMemory != nullptr)
{
free(static_cast<void*>(pMemory));
pMemory = nullptr;
}
nAllocationCount = 0;
}
void Init(size_t nGrowSize, size_t nInitSize);
void SetExternalBuffer(T* pMemory, size_t numElements);
void AssumeMemory(T* pMemory, size_t numElements);
void* DetachMemory();
T* Detach();
CUtlMemory(const T* pMemory, size_t numElements);
void Swap(CUtlMemory< T, N >& mem);
void Purge(const int nElements)
{
debug(nElements >= 0);
if (nElements > nAllocationCount)
{
// ensure this isn't a grow request in disguise
debug(nElements <= nAllocationCount);
return;
}
if (nElements == 0)
{
Purge();
return;
}
if (IsExternallyAllocated() || nElements == nAllocationCount)
return;
if (pMemory == nullptr)
{
// allocation count is non zero, but memory is null
debug(false);
return;
}
nAllocationCount = nElements;
pMemory = static_cast<T*>(realloc(pMemory, nAllocationCount * sizeof(T)));
}
public:
T* pMemory; // 0x00
int nAllocationCount; // 0x04
int nGrowSize;
// 0x08
};
//-----------------------------------------------------------------------------
// Attaches the buffer to external memory....
//-----------------------------------------------------------------------------
template< class T, class N >
void CUtlMemory<T, N>::SetExternalBuffer(T* pMemory, size_t numElements)
{
// Blow away any existing allocated memory
Purge();
pMemory = pMemory;
nAllocationCount = numElements;
// Indicate that we don't own the memory
nGrowSize = EXTERNAL_BUFFER_MARKER;
}
template< class T, class N >
void CUtlMemory<T, N>::AssumeMemory(T* pMemory, size_t numElements)
{
// Blow away any existing allocated memory
Purge();
// Simply take the pointer but don't mark us as external
pMemory = pMemory;
nAllocationCount = numElements;
}
template< class T, class N >
void* CUtlMemory<T, N>::DetachMemory()
{
if (IsExternallyAllocated())
return NULL;
void* pMemory = pMemory;
pMemory = 0;
nAllocationCount = 0;
return pMemory;
}
template< class T, class N >
inline T* CUtlMemory<T, N>::Detach()
{
return (T*)DetachMemory();
}
template<class T, class N>
inline CUtlMemory<T, N>::CUtlMemory(const T* pMemory, size_t numElements) : nAllocationCount(static_cast<N>(numElements))
{
// Special marker indicating externally supplied modifiable memory
this->pMemory = (T*)pMemory;
nGrowSize = -2;
}
template< class T, class I >
void CUtlMemory<T, I>::Init(size_t nGrowSize /*= 0*/, size_t nInitSize /*= 0*/)
{
Purge();
nGrowSize = nGrowSize;
nAllocationCount = nInitSize;
ConvertToGrowableMemory(nGrowSize);
if (nAllocationCount)
{
pMemory = (T*)malloc(nAllocationCount * sizeof(T));
}
}
template< class T, class N >
void CUtlMemory<T, N>::Swap(CUtlMemory<T, N>& mem)
{
V_swap(nGrowSize, mem.nGrowSize);
V_swap(pMemory, mem.pMemory);
V_swap(nAllocationCount, mem.nAllocationCount);
}
template <class T, int nAlignment>
class CUtlMemoryAligned : public CUtlMemory<T>
{
public:
// @note: not implemented
};
template <class T, std::size_t SIZE, class I = int>
class CUtlMemoryFixedGrowable : public CUtlMemory<T, I>
{
typedef CUtlMemory<T, I> BaseClass;
public:
CUtlMemoryFixedGrowable(int nInitialGrowSize = 0, int nInitialSize = SIZE) :
BaseClass(arrFixedMemory, SIZE)
{
debug(nInitialSize == 0 || nInitialSize == SIZE);
nMallocGrowSize = nInitialGrowSize;
}
void Grow(int nCount = 1)
{
if (this->IsExternallyAllocated())
this->ConvertToGrowableMemory(nMallocGrowSize);
BaseClass::Grow(nCount);
}
void EnsureCapacity(int nCapacity)
{
if (CUtlMemory<T>::nAllocationCount >= nCapacity)
return;
if (this->IsExternallyAllocated())
// can't grow a buffer whose memory was externally allocated
this->ConvertToGrowableMemory(nMallocGrowSize);
BaseClass::EnsureCapacity(nCapacity);
}
private:
int nMallocGrowSize;
T arrFixedMemory[SIZE];
};
template <typename T, std::size_t SIZE, int nAlignment = 0>
class CUtlMemoryFixed
{
public:
CUtlMemoryFixed(const int nGrowSize = 0, const int nInitialCapacity = 0)
{
debug(nInitialCapacity == 0 || nInitialCapacity == SIZE);
}
CUtlMemoryFixed(const T* pMemory, const int nElements)
{
debug(false);
}
[[nodiscard]] static constexpr bool IsValidIndex(const int nIndex)
{
return (nIndex >= 0) && (nIndex < SIZE);
}
// specify the invalid ('null') index that we'll only return on failure
static constexpr int INVALID_INDEX = -1;
[[nodiscard]] static constexpr int InvalidIndex()
{
return INVALID_INDEX;
}
[[nodiscard]] T* Base()
{
if (nAlignment == 0)
return reinterpret_cast<T*>(&pMemory[0]);
return reinterpret_cast<T*>((reinterpret_cast<std::uintptr_t>(&pMemory[0]) + nAlignment - 1) & ~(nAlignment - 1));
}
[[nodiscard]] const T* Base() const
{
if (nAlignment == 0)
return reinterpret_cast<T*>(&pMemory[0]);
return reinterpret_cast<T*>((reinterpret_cast<std::uintptr_t>(&pMemory[0]) + nAlignment - 1) & ~(nAlignment - 1));
}
[[nodiscard]] T& operator[](int nIndex)
{
debug(IsValidIndex(nIndex));
return Base()[nIndex];
}
[[nodiscard]] const T& operator[](int nIndex) const
{
debug(IsValidIndex(nIndex));
return Base()[nIndex];
}
[[nodiscard]] T& Element(int nIndex)
{
debug(IsValidIndex(nIndex));
return Base()[nIndex];
}
[[nodiscard]] const T& Element(int nIndex) const
{
debug(IsValidIndex(nIndex));
return Base()[nIndex];
}
[[nodiscard]] int AllocationCount() const
{
return SIZE;
}
[[nodiscard]] int Count() const
{
return SIZE;
}
void Grow(int nCount = 1)
{
debug(false);
}
void EnsureCapacity(const int nCapacity)
{
debug(nCapacity <= SIZE);
}
void Purge() { }
void Purge(const int nElements)
{
debug(false);
}
[[nodiscard]] bool IsExternallyAllocated() const
{
return false;
}
class Iterator_t
{
public:
Iterator_t(const int nIndex) :
nIndex(nIndex) { }
bool operator==(const Iterator_t it) const
{
return nIndex == it.nIndex;
}
bool operator!=(const Iterator_t it) const
{
return nIndex != it.nIndex;
}
int nIndex;
};
[[nodiscard]] Iterator_t First() const
{
return Iterator_t(IsValidIndex(0) ? 0 : InvalidIndex());
}
[[nodiscard]] Iterator_t Next(const Iterator_t& it) const
{
return Iterator_t(IsValidIndex(it.nIndex + 1) ? it.nIndex + 1 : InvalidIndex());
}
[[nodiscard]] int GetIndex(const Iterator_t& it) const
{
return it.nIndex;
}
[[nodiscard]] bool IsIndexAfter(int i, const Iterator_t& it) const
{
return i > it.nIndex;
}
[[nodiscard]] bool IsValidIterator(const Iterator_t& it) const
{
return IsValidIndex(it.nIndex);
}
[[nodiscard]] Iterator_t InvalidIterator() const
{
return Iterator_t(InvalidIndex());
}
private:
char pMemory[SIZE * sizeof(T) + nAlignment];
};

View File

@@ -0,0 +1,60 @@
#pragma once
template <size_t SIZE = 256>
struct String_t
{
char szBuffer[SIZE];
// Constructor for formatting a string
String_t(const char* szFormat, const char* arg1, const char* arg2)
{
CustomFormat(szFormat, arg1, arg2);
}
// Custom format function (simplified for two arguments)
void CustomFormat(const char* szFormat, const char* arg1, const char* arg2)
{
size_t idx = 0;
const char* ptr = szFormat;
// Loop through the format string
while (*ptr != '\0' && idx < SIZE - 1)
{
if (*ptr == '%' && *(ptr + 1) == 's') // Handle first "%s"
{
ptr += 2; // Skip "%s"
const char* strArg = arg1;
while (*strArg != '\0' && idx < SIZE - 1)
{
szBuffer[idx++] = *strArg++;
}
}
else if (*ptr == '%' && *(ptr + 1) == 's') // Handle second "%s"
{
ptr += 2; // Skip "%s"
const char* strArg = arg2;
while (*strArg != '\0' && idx < SIZE - 1)
{
szBuffer[idx++] = *strArg++;
}
}
else
{
szBuffer[idx++] = *ptr++; // Copy the current character
}
}
szBuffer[idx] = '\0'; // Null terminate the string
}
// Getter for the formatted data
const char* Data() const
{
return this->szBuffer;
}
// Clear the buffer
void Clear()
{
szBuffer[0] = '\0';
}
};

View File

@@ -0,0 +1,30 @@
#pragma once
struct ResourceBinding_t
{
void* pData;
};
template <typename T>
class CStrongHandle
{
public:
operator T* () const
{
if (pBinding == nullptr)
return nullptr;
return static_cast<T*>(pBinding->pData);
}
T* operator->() const
{
if (pBinding == nullptr)
return nullptr;
return static_cast<T*>(pBinding->pData);
}
const ResourceBinding_t* pBinding;
};

View File

@@ -0,0 +1,336 @@
#pragma once
#include <cstddef>
#include "..\utlmemory\utlmemory.h"
template <class T, class A = CUtlMemory<T>>
class CUtlVector
{
using CAllocator = A;
public:
explicit CUtlVector(const int nGrowSize = 0, const int nInitialCapacity = 0) :
memory(nGrowSize, nInitialCapacity), nSize(0), pElements(memory.Base()) { }
CUtlVector(T* pMemory, const int nInitialCapacity, const int nInitialCount = 0) :
memory(pMemory, nInitialCapacity), nSize(nInitialCount), pElements(memory.Base()) { }
CUtlVector(const CUtlVector&) = delete;
~CUtlVector()
{
Purge();
}
CUtlVector& operator=(const CUtlVector& vecOther)
{
debug(&vecOther != this);
const int nSourceCount = vecOther.Count();
SetCount(nSourceCount);
for (int i = 0; i < nSourceCount; i++)
(*this)[i] = vecOther[i];
return *this;
}
[[nodiscard]] T& operator[](const int nIndex)
{
debug(IsValidIndex(nIndex));
return memory[nIndex];
}
[[nodiscard]] const T& operator[](const int nIndex) const
{
debug(IsValidIndex(nIndex));
return memory[nIndex];
}
[[nodiscard]] T& Element2(int nIndex) const
{
debug(IsValidIndex(nIndex));
return memory[nIndex];
}
[[nodiscard]] T& Element(const int nIndex)
{
debug(IsValidIndex(nIndex));
return memory[nIndex];
}
[[nodiscard]] const T& Element(const int nIndex) const
{
debug(IsValidIndex(nIndex));
return memory[nIndex];
}
[[nodiscard]] T* Base()
{
return memory.Base();
}
[[nodiscard]] const T* Base() const
{
return memory.Base();
}
[[nodiscard]] int Count() const
{
return nSize;
}
[[nodiscard]] int& Size()
{
return nSize;
}
[[nodiscard]] bool IsValidIndex(const int nIndex) const
{
return (nIndex >= 0) && (nIndex < nSize);
}
void CopyFromArray(const T* pArraySource, int nArraySize)
{
debug(memory.Base() == nullptr || pArraySource == nullptr || begin() >= (pArraySource + nArraySize) || pArraySource >= end());
SetCount(nArraySize);
for (int i = 0; i < nArraySize; i++)
(*this)[i] = pArraySource[i];
}
void GrowVector(const int nCount = 1)
{
if (nSize + nCount > memory.AllocationCount())
memory.Grow(nSize + nCount - memory.AllocationCount());
nSize += nCount;
pElements = memory.Base();
}
void EnsureCapacity(int nCapacity)
{
memory.EnsureCapacity(nCapacity);
pElements = memory.Base();
}
void Purge()
{
RemoveAll();
memory.Purge();
pElements = memory.Base();
}
void ShiftElementsRight(const int nElement, const int nShift = 1)
{
debug(IsValidIndex(nElement) || nSize == 0 || nShift == 0);
if (const int nToMove = nSize - nElement - nShift; nToMove > 0 && nShift > 0)
memmove(&Element(nElement + nShift), &Element(nElement), nToMove * sizeof(T));
}
void ShiftElementsLeft(const int nElement, const int nShift = 1)
{
debug(IsValidIndex(nElement) || nSize == 0 || nShift == 0);
if (const int nToMove = nSize - nElement - nShift; nToMove > 0 && nShift > 0)
memmove(&Element(nElement), &Element(nElement + nShift), nToMove * sizeof(T));
}
int AddToHead()
{
return InsertBefore(0);
}
int AddToHead(const T& source)
{
// can't insert something that's in the list. reallocation may hose us
debug(memory.Base() == nullptr || &source < begin() || &source >= end());
return InsertBefore(0, source);
}
int AddMultipleToHead(const int nCount)
{
return InsertMultipleBefore(0, nCount);
}
int AddToTail()
{
return InsertBefore(nSize);
}
int AddToTail(const T& source)
{
// can't insert something that's in the list. reallocation may hose us
debug(memory.Base() == nullptr || &source < begin() || &source >= end());
return InsertBefore(nSize, source);
}
int AddMultipleToTail(const int nCount)
{
return InsertMultipleBefore(nSize, nCount);
}
void SetCount(const int nCount)
{
RemoveAll();
AddMultipleToTail(nCount);
}
int InsertBefore(const int nElement)
{
// can insert at the end
debug(nElement == nSize || IsValidIndex(nElement));
GrowVector();
ShiftElementsRight(nElement);
new (&Element(nElement)) T;
return nElement;
}
int InsertMultipleBefore(const int nElement, const int nCount)
{
if (nCount == 0)
return nElement;
debug(nElement == nSize || IsValidIndex(nElement));
GrowVector(nCount);
ShiftElementsRight(nElement, nCount);
for (int i = 0; i < nElement; ++i)
new (&Element(nElement + i)) T;
return nElement;
}
int InsertBefore(const int nElement, const T& source)
{
debug(memory.Base() == nullptr || &source < begin() || &source >= end());
debug(nElement == nSize || IsValidIndex(nElement));
GrowVector();
ShiftElementsRight(nElement);
new (&Element(nElement)) T(source);
return nElement;
}
int InsertMultipleBefore(const int nElement, const int nCount, const T* pSource)
{
if (nCount == 0)
return nElement;
debug(nElement == nSize || IsValidIndex(nElement));
GrowVector(nCount);
ShiftElementsRight(nElement, nCount);
if (pSource == nullptr)
{
for (int i = 0; i < nCount; ++i)
new (&Element(nElement + i)) T;
}
else
{
for (int i = 0; i < nCount; i++)
new (&Element(nElement)) T(pSource[i]);
}
return nElement;
}
[[nodiscard]] int Find(const T& source) const
{
for (int i = 0; i < nSize; ++i)
{
if (Element(i) == source)
return i;
}
return -1;
}
bool FindAndRemove(const T& source)
{
if (const int nElement = Find(source); nElement != -1)
{
Remove(nElement);
return true;
}
return false;
}
void Remove(const int nElement)
{
(&Element(nElement))->~T();
ShiftElementsLeft(nElement);
--nSize;
}
void RemoveAll()
{
for (int i = nSize; --i >= 0;)
(&Element(i))->~T();
nSize = 0;
}
[[nodiscard]] auto begin() noexcept
{
return memory.Base();
}
[[nodiscard]] auto end() noexcept
{
return memory.Base() + nSize;
}
[[nodiscard]] auto begin() const noexcept
{
return memory.Base();
}
[[nodiscard]] auto end() const noexcept
{
return memory.Base() + nSize;
}
protected:
int nSize;
CAllocator memory;
T* pElements;
};
template <class T>
class CUtlVectorAligned : public CUtlVector<T, CUtlMemoryAligned<T, alignof(T)>>
{
};
template <class T, std::size_t MAX_SIZE>
class CUtlVectorFixed : public CUtlVector<T, CUtlMemoryFixed<T, MAX_SIZE>>
{
using CBaseClass = CUtlVector<T, CUtlMemoryFixed<T, MAX_SIZE>>;
public:
explicit CUtlVectorFixed(int nGrowSize = 0, int nInitialCapacity = 0) :
CBaseClass(nGrowSize, nInitialCapacity) { }
CUtlVectorFixed(T* pMemory, int nElements) :
CBaseClass(pMemory, nElements) { }
};
template <typename T>
class C_NetworkUtlVectorBase
{
public:
std::uint32_t nSize;
T* pElements;
};

View File

@@ -0,0 +1 @@
#include "vector.h"

View File

@@ -0,0 +1,392 @@
#pragma once
#include "../../module/module.h"
#include <limits>
#include <cmath>
struct QAngle_t;
struct Matrix3x4_t;
struct Vector2D_t {
constexpr Vector2D_t(const float x = 0.0f, const float y = 0.0f) :
x(x), y(y) {
}
[[nodiscard]] bool IsZero() const {
return (this->x == 0.0f && this->y == 0.0f);
}
float x = 0.0f, y = 0.0f;
};
struct Vector_t {
public:
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) {
}
[[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];
}
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;
}
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;
}
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 };
}
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 };
}
Vector_t Normalize() const {
float len = Length();
if (len != 0)
return { x / len, y / len, z / len };
return { 0, 0, 0 };
}
float Length() const {
return std::sqrt(x * x + y * y + z * z);
}
float Distance(const Vector_t& other) const {
return std::sqrt((x - other.x) * (x - other.x) +
(y - other.y) * (y - other.y) +
(z - other.z) * (z - other.z));
}
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;
};
struct Matrix3x4_t;
struct QAngle_t {
constexpr QAngle_t(float x = 0.f, float y = 0.f, float z = 0.f) :
x(x), y(y), z(z) {
}
constexpr QAngle_t(const float* arrAngles) :
x(arrAngles[0]), y(arrAngles[1]), z(arrAngles[2]) {
}
#pragma region qangle_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 qangle_relational_operators
bool operator==(const QAngle_t& angBase) const {
return this->IsEqual(angBase);
}
bool operator!=(const QAngle_t& angBase) const {
return !this->IsEqual(angBase);
}
#pragma endregion
#pragma region qangle_assignment_operators
constexpr QAngle_t& operator=(const QAngle_t& angBase) {
this->x = angBase.x;
this->y = angBase.y;
this->z = angBase.z;
return *this;
}
#pragma endregion
#pragma region qangle_arithmetic_assignment_operators
constexpr QAngle_t& operator+=(const QAngle_t& angBase) {
this->x += angBase.x;
this->y += angBase.y;
this->z += angBase.z;
return *this;
}
constexpr QAngle_t& operator-=(const QAngle_t& angBase) {
this->x -= angBase.x;
this->y -= angBase.y;
this->z -= angBase.z;
return *this;
}
constexpr QAngle_t& operator*=(const QAngle_t& angBase) {
this->x *= angBase.x;
this->y *= angBase.y;
this->z *= angBase.z;
return *this;
}
constexpr QAngle_t& operator/=(const QAngle_t& angBase) {
this->x /= angBase.x;
this->y /= angBase.y;
this->z /= angBase.z;
return *this;
}
constexpr QAngle_t& operator+=(const float flAdd) {
this->x += flAdd;
this->y += flAdd;
this->z += flAdd;
return *this;
}
constexpr QAngle_t& operator-=(const float flSubtract) {
this->x -= flSubtract;
this->y -= flSubtract;
this->z -= flSubtract;
return *this;
}
constexpr QAngle_t& operator*=(const float flMultiply) {
this->x *= flMultiply;
this->y *= flMultiply;
this->z *= flMultiply;
return *this;
}
constexpr QAngle_t& operator/=(const float flDivide) {
this->x /= flDivide;
this->y /= flDivide;
this->z /= flDivide;
return *this;
}
#pragma endregion
#pragma region qangle_arithmetic_unary_operators
constexpr QAngle_t& operator-() {
this->x = -this->x;
this->y = -this->y;
this->z = -this->z;
return *this;
}
constexpr QAngle_t operator-() const {
return { -this->x, -this->y, -this->z };
}
#pragma endregion
#pragma region qangle_arithmetic_ternary_operators
constexpr QAngle_t operator+(const QAngle_t& angAdd) const {
return { this->x + angAdd.x, this->y + angAdd.y, this->z + angAdd.z };
}
constexpr QAngle_t operator-(const QAngle_t& angSubtract) const {
return { this->x - angSubtract.x, this->y - angSubtract.y, this->z - angSubtract.z };
}
constexpr QAngle_t operator*(const QAngle_t& angMultiply) const {
return { this->x * angMultiply.x, this->y * angMultiply.y, this->z * angMultiply.z };
}
constexpr QAngle_t operator/(const QAngle_t& angDivide) const {
return { this->x / angDivide.x, this->y / angDivide.y, this->z / angDivide.z };
}
constexpr QAngle_t operator+(const float flAdd) const {
return { this->x + flAdd, this->y + flAdd, this->z + flAdd };
}
constexpr QAngle_t operator-(const float flSubtract) const {
return { this->x - flSubtract, this->y - flSubtract, this->z - flSubtract };
}
constexpr QAngle_t operator*(const float flMultiply) const {
return { this->x * flMultiply, this->y * flMultiply, this->z * flMultiply };
}
constexpr QAngle_t operator/(const float flDivide) const {
return { this->x / flDivide, this->y / flDivide, this->z / flDivide };
}
#pragma endregion
[[nodiscard]] bool IsValid() const {
return (std::isfinite(this->x) && std::isfinite(this->y) && std::isfinite(this->z));
}
[[nodiscard]] bool IsEqual(const QAngle_t& angEqual, const float flErrorMargin = std::numeric_limits<float>::epsilon()) const {
return (std::fabsf(this->x - angEqual.x) < flErrorMargin && std::fabsf(this->y - angEqual.y) < flErrorMargin && std::fabsf(this->z - angEqual.z) < flErrorMargin);
}
[[nodiscard]] bool IsZero() const {
return (this->x == 0.0f && this->y == 0.0f && this->z == 0.0f);
}
/// @returns: length of hypotenuse
[[nodiscard]] float Length2D() const {
return std::sqrtf(x * x + y * y);
}
QAngle_t& Normalize() {
this->x = std::remainderf(this->x, 360.f);
this->y = std::remainderf(this->y, 360.f);
this->z = std::remainderf(this->z, 360.f);
return *this;
}
void ToDirections(Vector_t* pvecForward, Vector_t* pvecRight = nullptr, Vector_t* pvecUp = nullptr) const;
[[nodiscard]] Matrix3x4_t ToMatrix(const Vector_t& vecOrigin = {}) const;
public:
float x = 0.0f, y = 0.0f, z = 0.0f;
};

View File

@@ -0,0 +1,22 @@
#include "viewmatrix.h"
#include "../../../../../external/imgui/imgui.h"
#include <iostream>
bool ViewMatrix::WorldToScreen(const Vector_t& position, Vector_t& out) const {
const float w = viewMatrix->matrix[3][0] * position.x + viewMatrix->matrix[3][1] * position.y + viewMatrix->matrix[3][2] * position.z + viewMatrix->matrix[3][3];
if (w <= 0.001f)
return false;
const float invW = 1.0f / w;
ImVec2 wS = ImGui::GetIO().DisplaySize;
const float centerX = static_cast<float>(wS.x) / 2;
const float centerY = static_cast<float>(wS.y) / 2;
out.x = centerX + ((viewMatrix->matrix[0][0] * position.x + viewMatrix->matrix[0][1] * position.y + viewMatrix->matrix[0][2] * position.z + viewMatrix->matrix[0][3]) * invW * centerX);
out.y = centerY - ((viewMatrix->matrix[1][0] * position.x + viewMatrix->matrix[1][1] * position.y + viewMatrix->matrix[1][2] * position.z + viewMatrix->matrix[1][3]) * invW * centerY);
return true;
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include "../../../../cs2/datatypes/viewmatrix/viewmatrix.h"
#include "../vector/vector.h"
class ViewMatrix {
public:
//Vector_t WorldToScreen(const Vector_t& position) const;
bool WorldToScreen(const Vector_t& position, Vector_t& out) const;
viewmatrix_t* viewMatrix;
};

View File

@@ -0,0 +1,39 @@
#pragma once
#include <windows.h>
#include <cstddef>
#include <cstdint>
#include <string_view>
namespace I {
using InstantiateInterfaceFn = void* (*)();
class CInterfaceReg
{
public:
InstantiateInterfaceFn m_create_fn;
const char* m_name;
CInterfaceReg* m_next;
};
inline const CInterfaceReg* Find(const char* module_name)
{
const HMODULE module_base = GetModuleHandleA(module_name);
if (module_base == nullptr)
return nullptr;
const auto symbol = reinterpret_cast<std::uintptr_t>(GetProcAddress(module_base, "CreateInterface"));
const std::uintptr_t list = symbol + *reinterpret_cast<std::int32_t*>(symbol + 3) + 7;
return *reinterpret_cast<CInterfaceReg**>(list);
}
template <typename T = void*>
T* Get(const char* module_name, const char* interface_partial_version)
{
for (const CInterfaceReg* current = Find(module_name); current; current = current->m_next)
{
if (std::string_view(current->m_name).find(interface_partial_version) != std::string_view::npos)
{
return reinterpret_cast<T*>(current->m_create_fn());
}
}
return nullptr;
}
}

View File

@@ -0,0 +1,8 @@
#include "gaa.h"
uintptr_t M::getAbsoluteAddress(uintptr_t addr, const int nPreOffset, const int nPostOffset) {
addr += nPreOffset;
int32_t nRva = *reinterpret_cast<int32_t*>(addr);
addr += nPostOffset + sizeof(uint32_t) + nRva;
return addr;
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include <cstdint>
namespace M {
uintptr_t getAbsoluteAddress(uintptr_t addr, const int nPreOffset, const int nPostOffset = 0);
}

View File

@@ -0,0 +1,9 @@
#pragma once
#define CS_CONCATENATE_DETAIL(x, y) x##y
#define CS_CONCATENATE(x, y) CS_CONCATENATE_DETAIL(x, y)
#define MEM_PAD(SIZE) \
private: \
char CS_CONCATENATE(pad_, __COUNTER__)[SIZE]; \
public:

View File

@@ -0,0 +1,132 @@
#include "patternscan.h"
#include "../../module/module.h"
#include <Windows.h>
#include <vector>
#include <string>
#include <iostream>
#include <span>
#include <sstream>
#include <Psapi.h>
#include <algorithm>
#include <string_view>
#include <cstdint>
#include <functional>
#include <string>
std::vector<std::pair<uint8_t, bool>> PatternToBytes(const std::string& pattern) {
std::vector<std::pair<uint8_t, bool>> patternBytes;
const char* start = pattern.c_str();
const char* end = start + pattern.size();
for (const char* current = start; current < end; ++current) {
if (*current == ' ') continue;
if (*current == '?') {
patternBytes.emplace_back(0, false);
if (*(current + 1) == '?') ++current;
}
else {
patternBytes.emplace_back(strtoul(current, nullptr, 16), true);
if (*(current + 1) != ' ') ++current;
}
}
return patternBytes;
}
uintptr_t M::patternScan(const std::string& module, const std::string& pattern) {
uintptr_t baseAddress = modules.getModule(module);
HMODULE hModule = reinterpret_cast<HMODULE>(baseAddress);
if (!hModule) return 0;
MODULEINFO moduleInfo;
GetModuleInformation(GetCurrentProcess(), hModule, &moduleInfo, sizeof(MODULEINFO));
size_t moduleSize = moduleInfo.SizeOfImage;
std::vector<std::pair<uint8_t, bool>> patternBytes = PatternToBytes(pattern);
size_t patternLength = patternBytes.size();
for (size_t i = 0; i < moduleSize - patternLength; ++i) {
bool found = true;
for (size_t j = 0; j < patternLength; ++j) {
if (patternBytes[j].second && patternBytes[j].first != *reinterpret_cast<uint8_t*>(baseAddress + i + j)) {
found = false;
break;
}
}
if (found) {
return baseAddress + i;
}
}
return 0;
}
std::uint8_t* M::FindPattern(const char* module_name, const std::string& byte_sequence)
{
// retrieve the handle to the specified module
const HMODULE module = GetModuleHandleA(module_name);
if (module == nullptr)
return nullptr;
// retrieve the DOS header of the module
const auto dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>(module);
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
return nullptr;
// retrieve the NT headers of the module
const auto nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS>(reinterpret_cast<std::uint8_t*>(module) + dos_header->e_lfanew);
if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
return nullptr;
// get the size and base address of the code section
DWORD m_size = nt_headers->OptionalHeader.SizeOfCode;
std::uint8_t* m_base = reinterpret_cast<std::uint8_t*>(module) + nt_headers->OptionalHeader.BaseOfCode;
using SeqByte_t = std::pair< std::uint8_t, bool >;
std::string str{ };
std::vector< std::pair< std::uint8_t, bool > > byte_sequence_vec{ };
std::stringstream stream(byte_sequence);
// parse the byte sequence string into a vector of byte sequence elements
while (stream >> str)
{
// wildcard byte
if (str[0u] == '?')
{
byte_sequence_vec.emplace_back(0u, true);
continue;
}
// invalid hex digit, skip this byte
if (!std::isxdigit(str[0u]) || !std::isxdigit(str[1u]))
continue;
byte_sequence_vec.emplace_back(static_cast<std::uint8_t>(std::strtoul(str.data(), nullptr, 16)), false);
}
// end pointer of the code section
const auto end = reinterpret_cast<std::uint8_t*>(m_base + m_size);
// search for the byte sequence within the code section
const auto ret = std::search(reinterpret_cast<std::uint8_t*>(m_base), end, byte_sequence_vec.begin(), byte_sequence_vec.end(),
[](const std::uint8_t byte, const std::pair< std::uint8_t, bool >& seq_byte)
{
return std::get< bool >(seq_byte) || byte == std::get< std::uint8_t >(seq_byte);
});
// byte sequence found, return the pointer
if (ret)
return ret;
#ifdef _DEBUG
// failed to find byte sequence, log error and return
std::cout<< "failed to find pattern:" << byte_sequence.c_str() << " | inside: " << module_name << std::endl;
#endif
return nullptr;
}

View File

@@ -0,0 +1,18 @@
#pragma once
#include <cstdint>
#include <vector>
#include <string>
namespace M {
template <typename T = std::uint8_t>
T* abs(T* relative_address, int pre_offset = 0x0, int post_offset = 0x0)
{
relative_address += pre_offset;
relative_address += sizeof(std::int32_t) + *reinterpret_cast<std::int32_t*>(relative_address);
relative_address += post_offset;
return relative_address;
}
std::uint8_t* FindPattern(const char* module_name, const std::string& byte_sequence);
uintptr_t patternScan(const std::string& module, const std::string& pattern);
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <cstddef>
#include <cstdint>
namespace M {
template <typename T, std::size_t nIndex, class CBaseClass, typename... Args_t>
static inline T vfunc(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...);
}
}

View File

@@ -0,0 +1,38 @@
#include "module.h"
#include <Windows.h>
Module::Module(uintptr_t moduleAddress, const std::string &moduleName) : address(moduleAddress), name(moduleName) {}
void Modules::init() {
registerModule("client.dll", "client");
registerModule("scenesystem.dll", "scenesystem");
registerModule("particles.dll", "particles");
registerModule("materialsystem2.dll", "materialsystem2");
registerModule("tier0.dll", "tier0");
registerModule("engine2.dll", "engine2");
}
// Completely acceptable solution because there simply just aren't that many modules :)
uintptr_t Modules::getModule(const std::string &moduleName) {
for (const Module &m : modules) {
if (m.name == moduleName) {
return m.address;
}
}
// No module found
return 0;
}
bool Modules::registerModule(const std::string &aModuleName, const std::string &moduleName) {
uintptr_t moduleHandle = reinterpret_cast<uintptr_t>(GetModuleHandle(aModuleName.c_str()));
if (!moduleHandle)
return false;
Module module(moduleHandle, moduleName);
modules.emplace_back(module);
return true;
}
Modules modules;

View File

@@ -0,0 +1,28 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
// Class names might be too broad ngl -- just namespace them if someones ever really cares
class Module {
public:
Module(uintptr_t moduleAddress, const std::string &moduleName);
uintptr_t address;
std::string name;
};
class Modules {
public:
void init();
uintptr_t getModule(const std::string &moduleName);
private:
// example usage: registerModule("client.dll", "client")
bool registerModule(const std::string &aModuleName, const std::string &moduleName);
std::vector<Module> modules;
};
// We luv global state
extern Modules modules;

View File

@@ -0,0 +1,88 @@
#include "schema.h"
#include <vector>
#include <algorithm>
#include <Shlobj.h>
#include <shlobj_core.h>
#include "../fnv1a/fnv1a.h"
#include "../math/utlstring/utlstring.h"
#include "../memory/Interface/Interface.h"
struct SchemaDumpedData_t
{
uint32_t hashedName = 0x0ULL;
std::uint32_t uOffset = 0x0U;
};
static std::vector<SchemaDumpedData_t> dumped_data;
bool Schema::init(const char* ModuleName, int module_type)
{
schema_system = I::Get<ISchemaSystem>("schemasystem.dll", "SchemaSystem_00");
if (!schema_system)
return false;
CSchemaSystemTypeScope* pTypeScope = schema_system->FindTypeScopeForModule(ModuleName);
if (pTypeScope == nullptr)
return false;
const int nTableSize = pTypeScope->hashClasses.Count();
UtlTSHashHandle_t* pElements = new UtlTSHashHandle_t[nTableSize + 1U];
const auto nElements = pTypeScope->hashClasses.GetElements(0, nTableSize, pElements);
for (int i = 0; i < nElements; i++)
{
const UtlTSHashHandle_t hElement = pElements[i];
if (hElement == 0)
continue;
CSchemaClassBinding* pClassBinding = pTypeScope->hashClasses[hElement];
if (pClassBinding == nullptr)
continue;
SchemaClassInfoData_t* pDeclaredClassInfo;
pTypeScope->FindDeclaredClass(&pDeclaredClassInfo, pClassBinding->szBinaryName);
if (pDeclaredClassInfo == nullptr)
continue;
if (pDeclaredClassInfo->nFieldSize == 0)
continue;
for (auto j = 0; j < pDeclaredClassInfo->nFieldSize; j++)
{
SchemaClassFieldData_t* pFields = pDeclaredClassInfo->pFields;
std::string szFieldClassBuffer = std::string(pDeclaredClassInfo->szName) + "->" + std::string(pFields[j].szName);
dumped_data.emplace_back(hash_32_fnv1a_const(szFieldClassBuffer.c_str()), pFields[j].nSingleInheritanceOffset);
}
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
printf("[Schema] ");
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
printf("Dumped Class: %s fields: %i \n", pDeclaredClassInfo->szName, pDeclaredClassInfo->nFieldSize);
}
delete[] pElements;
return true;
}
std::uint32_t SchemaFinder::Get(const uint32_t hashedName)
{
if (const auto it = std::ranges::find_if(dumped_data, [hashedName](const SchemaDumpedData_t& data)
{ return data.hashedName == hashedName; });
it != dumped_data.end())
return it->uOffset;
return 0U;
}

View File

@@ -0,0 +1,41 @@
#pragma once
#include <memory>
#include "..\fnv1a\fnv1a.h"
#include "..\memory\vfunc\vfunc.h"
#include "..\math\utlmemory\utlmemory.h"
#include "..\math\utlvector\utlvector.h"
#include "..\..\..\cs2\datatypes\schema\ISchemaClass\ISchemaClass.h"
#define SCHEMA_ADD_OFFSET(TYPE, NAME, OFFSET) \
[[nodiscard]] inline std::add_lvalue_reference_t<TYPE> NAME() \
{ \
static const std::uint32_t uOffset = OFFSET; \
return *reinterpret_cast<std::add_pointer_t<TYPE>>(reinterpret_cast<std::uint8_t*>(this) + (uOffset)); \
}
#define SCHEMA_ADD_POFFSET(TYPE, NAME, OFFSET) \
[[nodiscard]] inline std::add_pointer_t<TYPE> NAME() \
{ \
const static std::uint32_t uOffset = OFFSET; \
return reinterpret_cast<std::add_pointer_t<TYPE>>(reinterpret_cast<std::uint8_t*>(this) + (uOffset)); \
}
#define schema(TYPE, NAME, FIELD) SCHEMA_ADD_OFFSET(TYPE, NAME, SchemaFinder::Get(hash_32_fnv1a_const(FIELD)) + 0u)
#define schema_pfield(TYPE, NAME, FIELD, ADDITIONAL) SCHEMA_ADD_POFFSET(TYPE, NAME, SchemaFinder::Get(hash_32_fnv1a_const(FIELD)) + ADDITIONAL)
class Schema {
public:
bool init( const char* module_name, int module_type);
ISchemaSystem* schema_system = nullptr;
};
namespace SchemaFinder {
[[nodiscard]] std::uint32_t Get(const uint32_t hashed);
[[nodiscard]] std::uint32_t GetExternal(const char* moduleName, const uint32_t HashedClass, const uint32_t HashedFieldName);
}