Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Umbre11as committed Aug 15, 2024
0 parents commit 77728ca
Show file tree
Hide file tree
Showing 8 changed files with 342 additions and 0 deletions.
18 changes: 18 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.27)
project(Source2Schema)

include("cmake/global-flags.cmake")
if (MSVC)
include("cmake/msvc-flags.cmake")
endif()

set_property(GLOBAL PROPERTY USE_FOLDERS ON)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")

file(GLOB_RECURSE SOURCES "src/*.cpp")

add_library(Source2Schema STATIC ${SOURCES})

target_include_directories(Source2Schema PRIVATE headers)

target_compile_definitions(Source2Schema PRIVATE WIN32_LEAN_AND_MEAN) # Remove shit from Windows headers
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Source2 Schema Parser
WIP Schema parsing for Source2 Engine games

_Если че у меня фетиш на const_

### Advanced scopes
Define `SCHEMA_CS2` if you need to parse matchmaking.dll scope

### Example
```cpp
#include <SchemaSystem.h>

const SchemaSystem* schemaSystem = SchemaSystem::Create();
const SchemaScope* scope = schemaSystem->Get<Scopes::Client>();
printf("Scope: %s\n", scope->Name());

const CUtlVector<const SchemaClass*> classes = scope->Classes();
printf("Classes: %zu\n", classes.Size);
for (SIZE_T j = 0; j < classes.Size; j++) {
const SchemaClass* pClass = classes[j];
PCSTR className = pClass->Name();

const std::vector<SchemaField> fields = pClass->Fields();
for (SIZE_T n = 0; n < fields.size(); n++) {
const SchemaField field = fields[n];
PCSTR fieldName = field.Name();

printf("%s->%s = %X\n", className, fieldName, field.Offset());
}
}
```
### Pictures
![](assets/img.png)
Binary file added assets/img.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions cmake/global-flags.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/dist")
4 changes: 4 additions & 0 deletions cmake/msvc-flags.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
if (DEBUG)
add_link_options("/DEBUG:FULL") # Bigger PDB information (for debugging)
endif()
add_link_options("/SUBSYSTEM:WINDOWS")
24 changes: 24 additions & 0 deletions headers/Interface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include <Windows.h>

typedef PVOID(*InterfaceInstanceFn)();

struct InterfaceEntry {
InterfaceInstanceFn CreateFunction;
PCSTR Name;
InterfaceEntry* Next;
};

template<typename T>
__forceinline T* CreateInterface(const char* moduleName, const char* name) {
// Also can find export using GetProcAddress and call - CreateInterface("SchemaSystem_001", nullptr);
const HMODULE schemaSystemModuleHandle = GetModuleHandle(moduleName);
const auto createInterfaceAddress = reinterpret_cast<ULONGLONG>(GetProcAddress(schemaSystemModuleHandle, "CreateInterface"));
const ULONGLONG interfaces = createInterfaceAddress + *reinterpret_cast<int*>(createInterfaceAddress + 3) + 7;
for (const InterfaceEntry* current = *reinterpret_cast<InterfaceEntry**>(interfaces); current; current = current->Next)
if (strcmp(current->Name, name) == 0)
return reinterpret_cast<T*>(current->CreateFunction());

return nullptr;
}
164 changes: 164 additions & 0 deletions headers/SchemaSystem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#pragma once

#include "Interface.h"
#include <type_traits>
#include <exception>
#include <vector>

#define PADDING_INSERT(x, y) x ## y
#define PADDING_DEFINE(x, y) PADDING_INSERT(x, y)
#define PRIVATE_PADDING(size) private: \
BYTE PADDING_DEFINE(__pad_, __LINE__)[size];
#define PADDING(size) PRIVATE_PADDING(size) \
public: \

template<typename T>
struct CUtlVector {
public:
T& operator[](unsigned int index) {
return Buffer[index];
}

T& operator[](unsigned int index) const {
return Buffer[index];
}
public:
SIZE_T Size;
T* Buffer;
};

class SchemaField {
public:
PCSTR Name() const;

PVOID Type() const;

UINT Offset() const;

UINT MetadataSize() const;

PVOID Metadata() const;
private:
PCSTR name;
PVOID type;
UINT offset;
UINT metadataSize;
PVOID metadata;
};

class SchemaClass {
public:
PCSTR Name() const;

PCSTR ScopeName() const;

UINT Size() const;

std::vector<SchemaField> Fields() const;

template<typename T>
T Get(IN PCSTR name) const {
SchemaField field{};
if (!FindField(name, &field))
return {};

if constexpr (std::is_base_of_v<SchemaField, T>)
return field;
else if (std::is_same_v<UINT, T>)
return field.Offset();
else
throw std::exception("Type is not supported! Use one of: SchemaField or unsigned int\n");
}
private:
bool FindField(IN const char* name, OUT SchemaField* field) const;
private:
PVOID vfptr;
PCSTR name;
PCSTR scopeName;
UINT size;
WORD fieldCount;
WORD unknown0;
WORD unknown1;
WORD unknown2;
UINT unknown3;
SchemaField* declaredFields;
};

class SchemaScope {
public:
PCSTR Name() const;

const CUtlVector<const SchemaClass*> Classes() const;

const SchemaClass* Get(IN const char* className) const;
private:
class SchemaDeclaredClass {
public:
constexpr SchemaClass* Class() const {
return pClass;
}
private:
PVOID vfptr;
PCSTR name;
PCSTR unknown0;
PCSTR unknown1;
SchemaClass* pClass;
};

class SchemaDeclaredClassEntry {
public:
constexpr SchemaDeclaredClass* DeclaredClass() const {
return declaredClass;
}
private:
ULONGLONG hash[2];
SchemaDeclaredClass* declaredClass;
};
private:
PVOID vfptr;
CHAR name[256];
PRIVATE_PADDING(0x338);
SchemaDeclaredClassEntry* declaredClasses;
PRIVATE_PADDING(0xE);
WORD declaredClassesCount;
};

enum class Scopes {
Client,
Engine2,
SchemaSystem,
Tier0,
#if defined(SCHEMA_CS2)
Matchmaking,
#endif
};

class SchemaSystem {
public:
CUtlVector<const SchemaScope*> Scopes() const;

const SchemaScope* Get(IN const char* scopeName) const;

template<enum Scopes scope>
const SchemaScope* Get() const {
if constexpr (scope == Scopes::Client)
return Get("client.dll");
else if constexpr (scope == Scopes::Engine2)
return Get("engine2.dll");
else if constexpr (scope == Scopes::Tier0)
return Get("tier0.dll");
#if defined(SCHEMA_CS2)
else if constexpr (scope == Scopes::Matchmaking)
return Get("matchmaking.dll");
#endif
else
return nullptr;
}
private:
PRIVATE_PADDING(0x188); // @ida: sigscan 41 0F B7 BD + 4
CUtlVector<const SchemaScope*> scopes{};
public:
static const SchemaSystem* Create() {
return CreateInterface<SchemaSystem>("schemasystem.dll", "SchemaSystem_001");
}
};
95 changes: 95 additions & 0 deletions src/SchemaSystem.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#include "SchemaSystem.h"

CUtlVector<const SchemaScope*> SchemaSystem::Scopes() const {
return scopes;
}

const SchemaScope* SchemaSystem::Get(const char* scopeName) const {
for (SIZE_T i = 0; i < scopes.Size; i++)
if (strcmp(scopes[i]->Name(), scopeName) == 0)
return scopes[i];

return nullptr;
}

PCSTR SchemaScope::Name() const {
return name;
}

const CUtlVector<const SchemaClass*> SchemaScope::Classes() const {
static CUtlVector<const SchemaClass*> classes{};
classes.Size = declaredClassesCount;
classes.Buffer = new const SchemaClass*[declaredClassesCount];

for (WORD i = 0; i < declaredClassesCount; i++) {
const SchemaDeclaredClassEntry entry = declaredClasses[i];
const SchemaDeclaredClass* declaredClass = entry.DeclaredClass();
SchemaClass* pClass = declaredClass->Class();

classes.Buffer[i] = pClass;
}

return classes;
}

const SchemaClass* SchemaScope::Get(const char* className) const {
const CUtlVector<const SchemaClass*> classes = Classes();
for (SIZE_T i = 0; i < classes.Size; i++)
if (strcmp(classes.Buffer[i]->Name(), className) == 0)
return classes.Buffer[i];

return nullptr;
}

bool SchemaClass::FindField(const char* name, SchemaField* field) const {
const std::vector<SchemaField> fields = Fields();
for (SIZE_T i = 0; i < fields.size(); i++) {
if (strcmp(fields[i].Name(), name) == 0) {
*field = fields[i];
return true;
}
}

return false;
}

PCSTR SchemaClass::Name() const {
return name;
}

PCSTR SchemaClass::ScopeName() const {
return scopeName;
}

UINT SchemaClass::Size() const {
return size;
}

std::vector<SchemaField> SchemaClass::Fields() const {
std::vector<SchemaField> fields(fieldCount);

for (WORD i = 0; i < fieldCount; i++)
fields[i] = declaredFields[i];

return fields;
}

PCSTR SchemaField::Name() const {
return name;
}

PVOID SchemaField::Type() const {
return type;
}

UINT SchemaField::Offset() const {
return offset;
}

UINT SchemaField::MetadataSize() const {
return metadataSize;
}

PVOID SchemaField::Metadata() const {
return metadata;
}

0 comments on commit 77728ca

Please sign in to comment.