Welcome to hackvshack.net Forum!
Download Free HvH CS2/CS:GO Cheats, CFG, LUA/JS Scripts, and More!
Register

Backend Beginner Source Engine How to use Schemas to retrieve offsets dynamically in CS2

yowi0

yowio
User ID:
5497
Messages:
20
Reactions:
21
Badges:
11
REP:
−0/5+
Level:
81

🧐 What is the Schema System?

In CS2, the Schema System Interface is used to access game data structures dynamically. This is useful when developing cheats, tools, or modifications, as it allows retrieving class offsets without hardcoding them.

In this guide, I'll explain step by step how to use the schema system, including retrieving offsets and using them in your code.

🤔 Why is it useful?

When modifying or creating tools for CS2, you often need to access internal game variables, such as:

✅ Player health (m_iHealth)
✅ Team number (m_iTeamNum)
✅ Scoped state (m_bIsScoped)

In the past, you had to manually find offsets every time CS2 updated. With the Schema System, you can retrieve these values dynamically, avoiding the hassle of updating offsets constantly. 🚀

🔨 How the Schema System Works

Every value we want to retrieve in CS2 is structured as follows:
  • 📌 Module: The DLL module where the information is stored (e.g., "client.dll").
  • 📌 Class: The class name inside the game’s code (e.g., "C_BaseEntity").
  • 📌 Field: The variable name inside that class (e.g., "m_iHealth").
By using these three components, we can retrieve the offset of any field and access its value at runtime.

💡 Example: If we want the offset of m_iHealth inside "C_BaseEntity", we ask the Schema System to find it inside "client.dll".

⚙️ Understanding the Schema System Structures

Before implementing our retrieval function, let's define the necessary structs and classes that CS2 uses internally.

🧱 Schema Field Structure

Each variable (field) inside a class in the Schema System is represented by a SchemaField:
Schema Field Structure:
Expand Collapse Copy
class SchemaField
{
public:
    const char* name;      // Name of the variable (e.g., "m_iHealth")
    void* type;            // Pointer to the variable type
    uint32_t offset;       // Offset of the variable inside the class
    uint32_t metadataSize; // Metadata size
    void* metadata;        // Additional metadata
};

🧱 Schema Class Structure

Each class (such as "C_BaseEntity") contains an array of SchemaField, representing its variables.
Schema Class Structure:
Expand Collapse Copy
class SchemaClass
{
public:
    void* ptr;             // Pointer to the class data
    const char* name;      // Name of the class (e.g., "C_BaseEntity")
    const char* moduleName;// Name of the module (e.g., "client.dll")
    uint32_t size;         // Class size
    uint16_t numFields;    // Number of fields in the class

    char padding1[0x2]; 

    uint16_t staticSize;   
    uint16_t metadataSize;

    char padding2[0x4];

    SchemaField* fields;   // Pointer to an array of field data
};

🧱 Schema Declared Class Structure

This structure holds information about a class declared within a module (e.g., "client.dll").
Schema Declared Class Structure:
Expand Collapse Copy
class SchemaDeclaredClass
{
public:
    void* ptr;              // Pointer to class metadata
    const char* name;       // Class name
    const char* moduleName; // Module where the class is declared
    const char* unknownStr; // Unknown string (possibly related to debugging)
    SchemaClass* mClass;    // Pointer to the actual SchemaClass
};

🧱 Schema Declared Class Entry Structure

Each class entry contains a SchemaDeclaredClass.
Schema Declared Class Entry Structure:
Expand Collapse Copy
class SchemaDeclaredClassEntry
{
public:
    uint64_t hash[2];            // Hash of the class name
    SchemaDeclaredClass* declaredClass; // Pointer to the declared class
};

🧱 Schema System Type Scope Structure

Each module (e.g., "client.dll") has a SchemaSystemTypeScope, which contains all the declared classes.
Schema System Type Scope Structure:
Expand Collapse Copy
class SchemaSystemTypeScope
{
public:
    void* ptr;
    char name[256];               // Module name

    char padding1[0x338];

    SchemaDeclaredClassEntry* declaredClasses; // Pointer to the declared classes array

    char padding2[0xE];

    uint16_t numDeclaredClasses;  // Number of declared classes in the module
};

📜 Step 1: Implementing Schema Offset Retrieval

Now that we understand the internal structures, let's implement our Schema offset retrieval function.

First we will need to get the SchemaSystem interface in order to retrieve the schemas. For that we will create a class where we will be able to get the instance of the interface and also define the functions we will need.
SchemaSystem.h:
Expand Collapse Copy
class SchemaSystem
{
public:
    static SchemaSystem* Get();  // Function to get the instance of the SchemaSystem interface
    SchemaSystemTypeScope* FindTypeScopeForModule(const char* moduleName);  // Function to find the type scope for a specific module
};
SchemaSystem.cpp:
Expand Collapse Copy
SchemaSystem* SchemaSystem::Get()
{
    static const uintptr_t instance = Interfaces::GetInterface("schemasystem.dll", "SchemaSystem_001");
    return reinterpret_cast<SchemaSystem*>(instance);
}

SchemaSystemTypeScope* SchemaSystem::FindTypeScopeForModule(const char* moduleName)
{
    return Memory::CallVFunc<SchemaSystemTypeScope*, 13U>(this, moduleName, nullptr);
}

Once we have the SchemaSystem class we will define our function to retrieve offsets.
C++:
Expand Collapse Copy
// Function to find a declared class within a given module's type scope
bool FindDeclaredClass(SchemaSystemTypeScope* typeScope, const char* className, SchemaDeclaredClass** outClass)
{
    // Check if the provided type scope, class name, or output class pointer is null
    if (!typeScope || !className || !outClass)
        return false;

    // Loop through all the declared classes in the type scope
    for (uint16_t i = 0; i < typeScope->numDeclaredClasses; ++i)
    {
        // Retrieve the current declared class from the type scope
        SchemaDeclaredClass* declaredClass = typeScope->declaredClasses[i].declaredClass;

        // Check if the class is valid and its name matches the provided className
        if (declaredClass && declaredClass->name && strcmp(declaredClass->name, className) == 0)
        {
            // If a match is found, set outClass to the found declared class and return true
            *outClass = declaredClass;
            return true;
        }
    }

    // Return false if no matching class is found
    return false;
}

// Function to retrieve the offset of a field from a given module, class, and field name
uint32_t GetOffset(const char* moduleName, const char* className, const char* fieldName)
{
    uint32_t res = 0;  // Variable to hold the resulting offset

    // Retrieve the SchemaSystem instance (this is the interface to interact with schema data)
    SchemaSystem* schemaSystem = SchemaSystem::Get();
    if (!schemaSystem)
        return res;  // Return 0 if SchemaSystem cannot be obtained

    // Find the type scope for the specified module (e.g., "client.dll")
    SchemaSystemTypeScope* typeScope = schemaSystem->FindTypeScopeForModule(moduleName);
    if (!typeScope)
        return res;  // Return 0 if type scope is not found for the module

    // Declare a pointer to hold the declared class
    SchemaDeclaredClass* declaredClass = nullptr;

    // Use the FindDeclaredClass function to search for the class within the type scope
    if (!FindDeclaredClass(typeScope, className, &declaredClass) || !declaredClass)
        return res;  // Return 0 if the class is not found

    // Retrieve the SchemaClass from the declared class
    SchemaClass* schemaClass = declaredClass->mClass;

    // Check if the class and its fields are valid
    if (!schemaClass || !schemaClass->fields)
        return res;  // Return 0 if the class or its fields are invalid

    // Loop through all the fields in the schema class
    for (uint16_t i = 0; i < schemaClass->numFields; ++i)
    {
        // Retrieve the current field
        SchemaField& field = schemaClass->fields[i];

        // Check if the field name matches the provided fieldName
        if (field.name && strcmp(field.name, fieldName) == 0)
        {
            // If a match is found, store the field's offset in the result variable
            res = field.offset;
            break;  // Exit the loop since the field has been found
        }
    }

    // Return the found offset (or 0 if the field was not found)
    return res;
}

🔍 Explanation:​

  • FindDeclaredClass Function:
    • This function looks for a class with a given name inside a module's type scope.
    • It returns true and sets outClass if the class is found, or false if it isn't.
  • GetOffset Function:
    • This function retrieves the offset of a specified field (e.g., m_iHealth) inside a class (e.g., C_BaseEntity) within a module (e.g., client.dll).
    • It performs a series of checks and looks for the class and field, returning the offset when found. If any step fails, it returns 0.

🚀 Step 2: Using the Schema System to Read Data

Now, let’s create a macro to simplify offset retrieval.
C++:
Expand Collapse Copy
#define SCHEMA(type, name, className, fieldName) \
    type& name() { \
        static auto offset = GetOffset("client.dll", className, fieldName); \
        return *reinterpret_cast<type*>(reinterpret_cast<uintptr_t>(this) + offset); \
    }

🔥 Example Usage: Retrieve Player’s Health
C++:
Expand Collapse Copy
class C_BaseEntity {
public:
    SCHEMA(int, GetHealth, "C_BaseEntity", "m_iHealth");
};

Now, we can get the player’s health like this:

C++:
Expand Collapse Copy
C_BaseEntity* entity = GetLocalPlayer();
int health = entity->GetHealth();
printf("Player Health: %d\n", health);

✅ No need to manually update offsets! 🚀

And that should be it! Thank you for reading, hope this is helpful and good luck!
 

🧐What is the Schema System?

In CS2, the Schema System Interface is used to access game data structures dynamically. This is useful when developing cheats, tools, or modifications, as it allows retrieving class offsets without hardcoding them.

In this guide, I'll explain step by step how to use the schema system, including retrieving offsets and using them in your code.

🤔 Why is it useful?

When modifying or creating tools for CS2, you often need to access internal game variables, such as:

✅ Player health (m_iHealth)
✅ Team number (m_iTeamNum)
✅ Scoped state (m_bIsScoped)

In the past, you had to manually find offsets every time CS2 updated. With the Schema System, you can retrieve these values dynamically, avoiding the hassle of updating offsets constantly. 🚀

🔨 How the Schema System Works

Every value we want to retrieve in CS2 is structured as follows:
  • 📌 Module: The DLL module where the information is stored (e.g., "client.dll").
  • 📌 Class: The class name inside the game’s code (e.g., "C_BaseEntity").
  • 📌 Field: The variable name inside that class (e.g., "m_iHealth").
By using these three components, we can retrieve the offset of any field and access its value at runtime.

💡 Example: If we want the offset of m_iHealth inside "C_BaseEntity", we ask the Schema System to find it inside "client.dll".

⚙️ Understanding the Schema System Structures

Before implementing our retrieval function, let's define the necessary structs and classes that CS2 uses internally.

🧱 Schema Field Structure

Each variable (field) inside a class in the Schema System is represented by a SchemaField:
Schema Field Structure:
Expand Collapse Copy
class SchemaField
{
public:
    const char* name;      // Name of the variable (e.g., "m_iHealth")
    void* type;            // Pointer to the variable type
    uint32_t offset;       // Offset of the variable inside the class
    uint32_t metadataSize; // Metadata size
    void* metadata;        // Additional metadata
};

🧱 Schema Class Structure

Each class (such as "C_BaseEntity") contains an array of SchemaField, representing its variables.
Schema Class Structure:
Expand Collapse Copy
class SchemaClass
{
public:
    void* ptr;             // Pointer to the class data
    const char* name;      // Name of the class (e.g., "C_BaseEntity")
    const char* moduleName;// Name of the module (e.g., "client.dll")
    uint32_t size;         // Class size
    uint16_t numFields;    // Number of fields in the class

    char padding1[0x2];

    uint16_t staticSize;  
    uint16_t metadataSize;

    char padding2[0x4];

    SchemaField* fields;   // Pointer to an array of field data
};

🧱 Schema Declared Class Structure

This structure holds information about a class declared within a module (e.g., "client.dll").
Schema Declared Class Structure:
Expand Collapse Copy
class SchemaDeclaredClass
{
public:
    void* ptr;              // Pointer to class metadata
    const char* name;       // Class name
    const char* moduleName; // Module where the class is declared
    const char* unknownStr; // Unknown string (possibly related to debugging)
    SchemaClass* mClass;    // Pointer to the actual SchemaClass
};

🧱 Schema Declared Class Entry Structure

Each class entry contains a SchemaDeclaredClass.
Schema Declared Class Entry Structure:
Expand Collapse Copy
class SchemaDeclaredClassEntry
{
public:
    uint64_t hash[2];            // Hash of the class name
    SchemaDeclaredClass* declaredClass; // Pointer to the declared class
};

🧱 Schema System Type Scope Structure

Each module (e.g., "client.dll") has a SchemaSystemTypeScope, which contains all the declared classes.
Schema System Type Scope Structure:
Expand Collapse Copy
class SchemaSystemTypeScope
{
public:
    void* ptr;
    char name[256];               // Module name

    char padding1[0x338];

    SchemaDeclaredClassEntry* declaredClasses; // Pointer to the declared classes array

    char padding2[0xE];

    uint16_t numDeclaredClasses;  // Number of declared classes in the module
};

📜 Step 1: Implementing Schema Offset Retrieval

Now that we understand the internal structures, let's implement our Schema offset retrieval function.

First we will need to get the SchemaSystem interface in order to retrieve the schemas. For that we will create a class where we will be able to get the instance of the interface and also define the functions we will need.
SchemaSystem.h:
Expand Collapse Copy
class SchemaSystem
{
public:
    static SchemaSystem* Get();  // Function to get the instance of the SchemaSystem interface
    SchemaSystemTypeScope* FindTypeScopeForModule(const char* moduleName);  // Function to find the type scope for a specific module
};
SchemaSystem.cpp:
Expand Collapse Copy
SchemaSystem* SchemaSystem::Get()
{
    static const uintptr_t instance = Interfaces::GetInterface("schemasystem.dll", "SchemaSystem_001");
    return reinterpret_cast<SchemaSystem*>(instance);
}

SchemaSystemTypeScope* SchemaSystem::FindTypeScopeForModule(const char* moduleName)
{
    return Memory::CallVFunc<SchemaSystemTypeScope*, 13U>(this, moduleName, nullptr);
}

Once we have the SchemaSystem class we will define our function to retrieve offsets.
C++:
Expand Collapse Copy
// Function to find a declared class within a given module's type scope
bool FindDeclaredClass(SchemaSystemTypeScope* typeScope, const char* className, SchemaDeclaredClass** outClass)
{
    // Check if the provided type scope, class name, or output class pointer is null
    if (!typeScope || !className || !outClass)
        return false;

    // Loop through all the declared classes in the type scope
    for (uint16_t i = 0; i < typeScope->numDeclaredClasses; ++i)
    {
        // Retrieve the current declared class from the type scope
        SchemaDeclaredClass* declaredClass = typeScope->declaredClasses[i].declaredClass;

        // Check if the class is valid and its name matches the provided className
        if (declaredClass && declaredClass->name && strcmp(declaredClass->name, className) == 0)
        {
            // If a match is found, set outClass to the found declared class and return true
            *outClass = declaredClass;
            return true;
        }
    }

    // Return false if no matching class is found
    return false;
}

// Function to retrieve the offset of a field from a given module, class, and field name
uint32_t GetOffset(const char* moduleName, const char* className, const char* fieldName)
{
    uint32_t res = 0;  // Variable to hold the resulting offset

    // Retrieve the SchemaSystem instance (this is the interface to interact with schema data)
    SchemaSystem* schemaSystem = SchemaSystem::Get();
    if (!schemaSystem)
        return res;  // Return 0 if SchemaSystem cannot be obtained

    // Find the type scope for the specified module (e.g., "client.dll")
    SchemaSystemTypeScope* typeScope = schemaSystem->FindTypeScopeForModule(moduleName);
    if (!typeScope)
        return res;  // Return 0 if type scope is not found for the module

    // Declare a pointer to hold the declared class
    SchemaDeclaredClass* declaredClass = nullptr;

    // Use the FindDeclaredClass function to search for the class within the type scope
    if (!FindDeclaredClass(typeScope, className, &declaredClass) || !declaredClass)
        return res;  // Return 0 if the class is not found

    // Retrieve the SchemaClass from the declared class
    SchemaClass* schemaClass = declaredClass->mClass;

    // Check if the class and its fields are valid
    if (!schemaClass || !schemaClass->fields)
        return res;  // Return 0 if the class or its fields are invalid

    // Loop through all the fields in the schema class
    for (uint16_t i = 0; i < schemaClass->numFields; ++i)
    {
        // Retrieve the current field
        SchemaField& field = schemaClass->fields[i];

        // Check if the field name matches the provided fieldName
        if (field.name && strcmp(field.name, fieldName) == 0)
        {
            // If a match is found, store the field's offset in the result variable
            res = field.offset;
            break;  // Exit the loop since the field has been found
        }
    }

    // Return the found offset (or 0 if the field was not found)
    return res;
}

🔍 Explanation:​

  • FindDeclaredClass Function:
    • This function looks for a class with a given name inside a module's type scope.
    • It returns true and sets outClass if the class is found, or false if it isn't.
  • GetOffset Function:
    • This function retrieves the offset of a specified field (e.g., m_iHealth) inside a class (e.g., C_BaseEntity) within a module (e.g., client.dll).
    • It performs a series of checks and looks for the class and field, returning the offset when found. If any step fails, it returns 0.

🚀 Step 2: Using the Schema System to Read Data

Now, let’s create a macro to simplify offset retrieval.
C++:
Expand Collapse Copy
#define SCHEMA(type, name, className, fieldName) \
    type& name() { \
        static auto offset = GetOffset("client.dll", className, fieldName); \
        return *reinterpret_cast<type*>(reinterpret_cast<uintptr_t>(this) + offset); \
    }

🔥 Example Usage: Retrieve Player’s Health
C++:
Expand Collapse Copy
class C_BaseEntity {
public:
    SCHEMA(int, GetHealth, "C_BaseEntity", "m_iHealth");
};

Now, we can get the player’s health like this:

C++:
Expand Collapse Copy
C_BaseEntity* entity = GetLocalPlayer();
int health = entity->GetHealth();
printf("Player Health: %d\n", health);

✅ No need to manually update offsets! 🚀

And that should be it! Thank you for reading, hope this is helpful and good luck!
I found a girlfriend for you
 

Who has read this thread (Total: 0) in last 1 hours View details