Skip to content

Outdated Possibly. #2

@gamerchamper

Description

@gamerchamper

Trying to incorporate your code into my base. Your overlay system pattern seemed to be outdated so I just went with my own base instead. But I've stumbled upon this issue with KeyValues

[Internal DLL] Successfully loaded and connected!
[ManualMap] Manual mapping complete!
[MaterialEditor][INFO] === Received InitializeMaterialEditor command ===
[MaterialEditor][INFO] === MaterialEditor Integration Test Started ===
[MaterialEditor][INFO] Signature Manager initialized
[MaterialEditor][INFO] Interface Manager initialized
[MaterialEditor][INFO] === Initializing Material System ===
[MaterialEditor][INFO] --- Finding Signatures ---
[MaterialEditor][INFO] Scanning module 'materialsystem2.dll' (0x0x7FF93F860000 - 0x0x7FF93F9E3000)
[MaterialEditor][SUCCESS] Signature 'CreateMaterial' found at 0x0x7FF93F89BE30
[MaterialEditor][INFO] Scanning module 'client.dll' (0x0x7FF8E62E0000 - 0x0x7FF8E84C7000)
[MaterialEditor][SUCCESS] Signature 'FixupResourceClient' found at 0x0x7FF8E76AD870
[MaterialEditor][INFO] Scanning module 'client.dll' (0x0x7FF8E62E0000 - 0x0x7FF8E84C7000)
[MaterialEditor][SUCCESS] Signature 'SetTypeKV3' found at 0x0x7FF8E76E57D0
[MaterialEditor][INFO] Scanning module 'client.dll' (0x0x7FF8E62E0000 - 0x0x7FF8E84C7000)
[MaterialEditor][SUCCESS] Signature 'GetEntityByIndex' found at 0x0x7FF8E69BAE80
[MaterialEditor][SUCCESS] Signature 'UtlBufferInit' found at 0x0x7FF985FCF460
[MaterialEditor][SUCCESS] Signature 'UtlBufferPutString' found at 0x0x7FF985FD2870
[MaterialEditor][INFO] --- Finding Interfaces ---
[MaterialEditor][INFO] Found interface 'SchemaSystem_001' in register
[MaterialEditor][INFO] Found interface 'ResourceSystem013' in register
[MaterialEditor][SUCCESS] Interface 'ResourceSystem013' found at 0x0x7FF9CD05FDD0
[MaterialEditor][INFO] Found interface 'GameResourceServiceClientV001' in register
[MaterialEditor][SUCCESS] Interface 'GameResourceServiceClientV00' found at 0x0x7FF936657730
[MaterialEditor][INFO] ResourceSystem found, need to query ResourceHandleUtils
[MaterialEditor][INFO] Interface scanning complete
[MaterialEditor][INFO] Signatures:
[MaterialEditor][INFO] CreateMaterial: FOUND (0x0x7FF93F89BE30)
[MaterialEditor][INFO] FixupResourceClient: FOUND (0x0x7FF8E76AD870)
[MaterialEditor][INFO] SetTypeKV3: FOUND (0x0x7FF8E76E57D0)
[MaterialEditor][INFO] LoadKeyValues: FOUND (0x0x7FF985F618D0)
[MaterialEditor][INFO] GetEntityByIndex: FOUND (0x0x7FF8E69BAE80)
[MaterialEditor][INFO] UtlBufferInit: FOUND (0x0x7FF985FCF460)
[MaterialEditor][INFO] UtlBufferPutString: FOUND (0x0x7FF985FD2870)
[MaterialEditor][INFO] Interfaces:
[MaterialEditor][INFO] ResourceSystem: FOUND (0x0x7FF9CD05FDD0)
[MaterialEditor][INFO] GameResourceService: FOUND (0x0x7FF936657730)
[MaterialEditor][INFO] ===============================
[MaterialEditor] Initialization completed successfully
[MaterialEditor][INFO] === Received PrintStatus command ===
[MaterialEditor][INFO] Signatures:
[MaterialEditor][INFO] CreateMaterial: FOUND (0x0x7FF93F89BE30)
[MaterialEditor][INFO] SetTypeKV3: FOUND (0x0x7FF8E76E57D0)
[MaterialEditor][INFO] LoadKeyValues: FOUND (0x0x7FF985F618D0)
[MaterialEditor][INFO] UtlBufferInit: FOUND (0x0x7FF985FCF460)
[MaterialEditor][INFO] UtlBufferPutString: FOUND (0x0x7FF985FD2870)
[MaterialEditor][INFO] SchemaSystem: FOUND (0x0x7FF9CCC256F0)
[MaterialEditor][INFO] ResourceSystem: FOUND (0x0x7FF9CD05FDD0)
[MaterialEditor][INFO] ===============================
[MaterialEditor] Status printed to debug output
[MaterialEditor][SUCCESS] System verification PASSED
[MaterialEditor] System verification PASSED
[MaterialEditor][INFO] === Received TestMaterialCreation command ===
[MaterialEditor][INFO] Testing material creation for: test_material
[MaterialEditor][INFO] Creating CKeyValues3 object...
[MaterialEditor][INFO] CKeyValues3 memory zeroed
[MaterialEditor][SUCCESS] CKeyValues3 initialized with SetTypeKV3
[MaterialEditor][INFO] Creating CUtlBuffer and loading material data...
[MaterialEditor][INFO] CUtlBuffer size: 128, vmatLength: 649
[MaterialEditor][INFO] UtlBufferInit returned: 0x0x6DA66FC510 (should be same as buffer: 0x0x6DA66FC510)
[MaterialEditor][INFO] PutString called with 649 bytes
[MaterialEditor][INFO] Found likely Put at offset 3: value=687
[MaterialEditor][INFO] Resetting Get at offset 2 from 1140662784 to 0
[MaterialEditor][INFO] Buffer content preview (first 64 chars):
[MaterialEditor][INFO] <!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32a
[MaterialEditor][INFO] Loading KeyValues from buffer...
[MaterialEditor][INFO] Calling LoadKeyValues: kv=0x0x6DA66FC360, buf=0x0x6DA66FC510
[MaterialEditor][INFO] KV3ID: name=generic, id0=0xlX, id1=0xlX
[MaterialEditor][INFO] About to call LoadKeyValues function...
[MaterialEditor][INFO] LoadKeyValues returned: 0
[MaterialEditor][ERROR] Failed to load KeyValues from buffer (returned false)
[MaterialEditor][INFO] Buffer first 32 bytes check...
[MaterialEditor] Material creation test failed

#include "MaterialEditorTest.h"
#include <Windows.h>
#include <cstdio>
#include <cstdarg>
#include <cstring>
#include "../../../../usermode/src/fast_ipc.h"

// External string functions (defined in dllmain.cpp)
extern "C" {
    int __cdecl custom_strncmp(const char* s1, const char* s2, size_t n);
    int __cdecl custom_strncpy_s(char* dest, size_t destSize, const char* src, size_t count);
}

// Wrapper macros to use custom functions
#define strncmp custom_strncmp
// Note: Don't define strncpy_s macro - call custom_strncpy_s directly to avoid conflicts

// IntelliSense suppressions for false positives
#ifdef __INTELLISENSE__
// Suppress IntelliSense errors - the code compiles fine, these are parser issues
#pragma diag_suppress 140  // too many arguments
#pragma diag_suppress 413  // no suitable conversion
#pragma diag_suppress 20   // identifier undefined
#pragma diag_suppress 135  // class has no member
#pragma diag_suppress 144  // value of type void
#pragma diag_suppress 167  // argument incompatible
#pragma diag_suppress 757  // not a type name

// Help IntelliSense understand the types
using MaterialEditorTest::CKeyValues3;
using MaterialEditorTest::CUtlBuffer;
using MaterialEditorTest::CMaterial2;
using MaterialEditorTest::KV3ID_t;
using MaterialEditorTest::CStrongHandle;
using MaterialEditorTest::MaterialSystemData;
#endif

// Safe string length
static size_t safe_strlen(const char* str) {
    if (!str) return 0;
    size_t len = 0;
    while (str[len] && len < 4096) len++;
    return len;
}

namespace MaterialEditorTest {

    // ========================================================================
    // IPC Debug Logger Implementation
    // ========================================================================

    bool IPCDebugLogger::initialized_ = false;

    void IPCDebugLogger::Initialize() {
        initialized_ = true;
        Log("=== MaterialEditor Integration Test Started ===");
    }

    // Simple sprintf with va_list (for variadic functions)
    static int simple_vsprintf(char* buffer, size_t bufSize, const char* format, va_list args) {
        size_t written = 0;
        const char* p = format;
        
        while (*p && written < bufSize - 1) {
            if (*p == '%') {
                p++;
                if (*p == 's') {
                    const char* str = va_arg(args, const char*);
                    if (str) {
                        while (*str && written < bufSize - 1) {
                            buffer[written++] = *str++;
                        }
                    }
                } else if (*p == 'p') {
                    void* ptr = va_arg(args, void*);
                    unsigned long long addr = (unsigned long long)ptr;
                    
                    // Directly write hex digits to buffer (no intermediate array)
                    if (written < bufSize - 1) buffer[written++] = '0';
                    if (written < bufSize - 1) buffer[written++] = 'x';
                    
                    // Only print significant digits (skip leading zeros except last one)
                    bool foundNonZero = false;
                    for (int i = 60; i >= 0; i -= 4) {
                        int digit = (addr >> i) & 0xF;
                        if (digit != 0 || foundNonZero || i == 0) {
                            if (written < bufSize - 1) {
                                buffer[written++] = digit < 10 ? '0' + digit : 'A' + digit - 10;
                            }
                            foundNonZero = true;
                        }
                    }
                } else if (*p == 'd' || *p == 'i') {
                    int num = va_arg(args, int);
                    char numBuf[32];
                    int numIdx = 0;
                    
                    if (num < 0) {
                        buffer[written++] = '-';
                        num = -num;
                    }
                    
                    // Convert to string (backwards)
                    if (num == 0) {
                        numBuf[numIdx++] = '0';
                    } else {
                        while (num > 0 && numIdx < 31) {
                            numBuf[numIdx++] = '0' + (num % 10);
                            num /= 10;
                        }
                    }
                    
                    // Reverse and copy
                    for (int i = numIdx - 1; i >= 0 && written < bufSize - 1; i--) {
                        buffer[written++] = numBuf[i];
                    }
                } else if (*p == 'x' || *p == 'X') {
                    unsigned int num = va_arg(args, unsigned int);
                    char hexBuf[16];
                    int hexIdx = 0;
                    
                    if (num == 0) {
                        buffer[written++] = '0';
                    } else {
                        while (num > 0 && hexIdx < 15) {
                            int digit = num % 16;
                            hexBuf[hexIdx++] = digit < 10 ? '0' + digit : 'A' + digit - 10;
                            num /= 16;
                        }
                        
                        // Reverse and copy
                        for (int i = hexIdx - 1; i >= 0 && written < bufSize - 1; i--) {
                            buffer[written++] = hexBuf[i];
                        }
                    }
                } else if (*p == '%') {
                    buffer[written++] = '%';
                }
                p++;
            } else {
                buffer[written++] = *p++;
            }
        }
        
        buffer[written] = 0;
        return written;
    }
    
    // Simple sprintf with variadic arguments (for direct calls)
    static int simple_sprintf(char* buffer, size_t bufSize, const char* format, ...) {
        va_list args;
        va_start(args, format);
        int result = simple_vsprintf(buffer, bufSize, format, args);
        va_end(args);
        return result;
    }

    void IPCDebugLogger::SendIPC(const char* prefix, const char* message) {
        // External IPC (declared outside namespace)
        extern FastIPC::InternalIPC* g_internal_ipc;
        extern bool g_ipc_connected;
        // Format: [MaterialEditor][PREFIX] message
        char buffer[512];
        size_t pos = 0;
        
        // Copy "[MaterialEditor]["
        const char* start = "[MaterialEditor][";
        while (*start && pos < sizeof(buffer) - 1) {
            buffer[pos++] = *start++;
        }
        
        // Copy prefix
        while (*prefix && pos < sizeof(buffer) - 1) {
            buffer[pos++] = *prefix++;
        }
        
        // Copy "] "
        buffer[pos++] = ']';
        buffer[pos++] = ' ';
        
        // Copy message
        while (*message && pos < sizeof(buffer) - 1) {
            buffer[pos++] = *message++;
        }
        
        buffer[pos] = 0;
        
        // Send to usermode via IPC
        if (g_ipc_connected && g_internal_ipc) {
            g_internal_ipc->Send(buffer, 0);
            // Small delay to let usermode read the message before sending next one
            Sleep(5); // 5ms delay between messages
        }
        
        // Also send to OutputDebugString as backup
        OutputDebugStringA(buffer);
    }

    void IPCDebugLogger::Log(const char* format, ...) {
        char buffer[512];
        va_list args;
        va_start(args, format);
        simple_vsprintf(buffer, sizeof(buffer), format, args);
        va_end(args);
        SendIPC("INFO", buffer);
    }

    void IPCDebugLogger::Success(const char* format, ...) {
        char buffer[512];
        va_list args;
        va_start(args, format);
        simple_vsprintf(buffer, sizeof(buffer), format, args);
        va_end(args);
        SendIPC("SUCCESS", buffer);
    }

    void IPCDebugLogger::Error(const char* format, ...) {
        char buffer[512];
        va_list args;
        va_start(args, format);
        simple_vsprintf(buffer, sizeof(buffer), format, args);
        va_end(args);
        SendIPC("ERROR", buffer);
    }

    void IPCDebugLogger::Warning(const char* format, ...) {
        char buffer[512];
        va_list args;
        va_start(args, format);
        simple_vsprintf(buffer, sizeof(buffer), format, args);
        va_end(args);
        SendIPC("WARNING", buffer);
    }

    void IPCDebugLogger::SignatureFound(const char* name, void* address) {
        char buffer[512];
        simple_sprintf(buffer, sizeof(buffer), "Signature '%s' found at 0x%p", name, address);
        SendIPC("SUCCESS", buffer);
    }

    void IPCDebugLogger::SignatureFailed(const char* name) {
        char buffer[512];
        simple_sprintf(buffer, sizeof(buffer), "Failed to find signature '%s'", name);
        SendIPC("ERROR", buffer);
    }

    void IPCDebugLogger::InterfaceFound(const char* name, void* address) {
        char buffer[512];
        simple_sprintf(buffer, sizeof(buffer), "Interface '%s' found at 0x%p", name, address);
        SendIPC("SUCCESS", buffer);
    }

    void IPCDebugLogger::InterfaceFailed(const char* name) {
        char buffer[512];
        simple_sprintf(buffer, sizeof(buffer), "Failed to find interface '%s'", name);
        SendIPC("ERROR", buffer);
    }

    // ========================================================================
    // Pattern Scanner Implementation
    // ========================================================================

    void* PatternScanner::GetModuleEnd(void* moduleBase) {
        auto dosHeader = reinterpret_cast<IMAGE_DOS_HEADER*>(moduleBase);
        auto ntHeaders = reinterpret_cast<IMAGE_NT_HEADERS*>(
            reinterpret_cast<uint8_t*>(moduleBase) + dosHeader->e_lfanew);
        return reinterpret_cast<uint8_t*>(moduleBase) + ntHeaders->OptionalHeader.SizeOfImage;
    }

    void* PatternScanner::Scan(void* start, void* end, const int16_t* pattern, size_t patternSize,
                               int pre_offset, int post_offset) {
        uint64_t rangeEnd = reinterpret_cast<uint64_t>(end) - patternSize;
        
        for (uint64_t address = reinterpret_cast<uint64_t>(start); address <= rangeEnd; ++address) {
            bool match = true;
            
            for (size_t i = 0; i < patternSize; ++i) {
                if (pattern[i] == -1) continue; // Wildcard
                
                if (*reinterpret_cast<uint8_t*>(address + i) != pattern[i]) {
                    match = false;
                    break;
                }
            }

            if (match) {
                // Handle relative addressing
                if (pre_offset != 0) {
                    address += pre_offset;
                    address += sizeof(int32_t) + *reinterpret_cast<int32_t*>(address);
                }
                address += post_offset;

                return reinterpret_cast<void*>(address);
            }
        }

        return nullptr;
    }

    void* PatternScanner::Scan(const char* moduleName, const int16_t* pattern, size_t patternSize,
                               int pre_offset, int post_offset) {
        HMODULE hModule = GetModuleHandleA(moduleName);
        if (!hModule) {
            char buffer[512];
            simple_sprintf(buffer, sizeof(buffer), "Module '%s' not found", moduleName);
            IPCDebugLogger::SendIPC("ERROR", buffer);
            return nullptr;
        }

        void* moduleBase = reinterpret_cast<void*>(hModule);
        void* moduleEnd = GetModuleEnd(moduleBase);

        char buffer[512];
        simple_sprintf(buffer, sizeof(buffer), "Scanning module '%s' (0x%p - 0x%p)", moduleName, moduleBase, moduleEnd);
        IPCDebugLogger::SendIPC("INFO", buffer);

        return Scan(moduleBase, moduleEnd, pattern, patternSize, pre_offset, post_offset);
    }

    // ========================================================================
    // Signature Manager Implementation
    // ========================================================================

    static LoadedSignature g_signatures[32];
    static int g_signature_count = 0;
    bool SignatureManager::failed_ = false;

    void SignatureManager::Initialize() {
        g_signature_count = 0;
        failed_ = false;
        IPCDebugLogger::Log("Signature Manager initialized");
    }

    void SignatureManager::AddSignatureImpl(const char* name, const char* module, 
                                           const SignatureData& sig, void** out, 
                                           int post_offset) {
        // Decrypt signature pattern into stack array (no heap allocation)
        int16_t pattern[256]; // Max pattern size
        if (sig.nLength > 256) {
            IPCDebugLogger::SendIPC("ERROR", "Signature pattern too large");
            failed_ = true;
            return;
        }
        
        for (size_t i = 0; i < sig.nLength; i++) {
            pattern[i] = sig.pData[i] ^ sig.nKey;
        }

        // Log pattern for debugging
        char buffer[512];
        simple_sprintf(buffer, sizeof(buffer), "Scanning for signature '%s' in '%s'", name, module);
        IPCDebugLogger::SendIPC("INFO", buffer);
        
        // Scan for pattern
        void* address = PatternScanner::Scan(module, pattern, sig.nLength, sig.nPreOffset, post_offset);

        if (!address) {
            IPCDebugLogger::SignatureFailed(name);
            failed_ = true;
            return;
        }

        IPCDebugLogger::SignatureFound(name, address);

        if (out) {
            *out = address;
        }

        // Add to signature list
        if (g_signature_count < 32) {
            LoadedSignature& newsig = g_signatures[g_signature_count++];
            custom_strncpy_s(newsig.name, sizeof(newsig.name), name, sizeof(newsig.name) - 1);
            newsig.address = address;
        }
    }

    void SignatureManager::GetImpl(const char* name, void** out) {
        *out = nullptr;

        for (int i = 0; i < g_signature_count; i++) {
            if (strncmp(g_signatures[i].name, name, sizeof(g_signatures[i].name)) == 0) {
                *out = g_signatures[i].address;
                return;
            }
        }

        char buffer[512];
        simple_sprintf(buffer, sizeof(buffer), "Signature '%s' not found in loaded signatures", name);
        IPCDebugLogger::SendIPC("ERROR", buffer);
    }

    // ========================================================================
    // Interface Manager Implementation
    // ========================================================================

    void InterfaceManager::Initialize() {
        IPCDebugLogger::Log("Interface Manager initialized");
    }

    InterfaceReg* InterfaceManager::GetModuleRegister(const char* moduleName) {
        HMODULE hModule = GetModuleHandleA(moduleName);
        if (!hModule) {
            char buffer[512];
            simple_sprintf(buffer, sizeof(buffer), "Module '%s' not loaded", moduleName);
            IPCDebugLogger::SendIPC("ERROR", buffer);
            return nullptr;
        }

        // Get CreateInterface export
        auto createInterface = reinterpret_cast<void*>(GetProcAddress(hModule, "CreateInterface"));
        if (!createInterface) {
            char buffer[512];
            simple_sprintf(buffer, sizeof(buffer), "CreateInterface not found in '%s'", moduleName);
            IPCDebugLogger::SendIPC("ERROR", buffer);
            return nullptr;
        }

        // Resolve relative address to get interface register
        // Pattern: mov rax, qword ptr [rip + offset]
        // At offset 0x3, read 4-byte relative offset
        uint8_t* addr = reinterpret_cast<uint8_t*>(createInterface);
        int32_t offset = *reinterpret_cast<int32_t*>(addr + 0x3);
        InterfaceReg** pRegister = reinterpret_cast<InterfaceReg**>(addr + 0x7 + offset);

        return *pRegister;
    }

    void* InterfaceManager::CaptureInterface(const InterfaceReg* reg, const char* interfaceName) {
        size_t len = safe_strlen(interfaceName);

        for (const InterfaceReg* current = reg; current != nullptr; current = current->pNext) {
            if (strncmp(current->szName, interfaceName, len) == 0) {
                void* pInterface = current->fnCreate();
                char msg[256];
                simple_sprintf(msg, sizeof(msg), "Found interface '%s' in register", current->szName);
                IPCDebugLogger::Log(msg);
                return pInterface;
            }
        }

        return nullptr;
    }

    void InterfaceManager::GetInterfaceImpl(const char* moduleName, const char* interfaceName, void** out) {
        *out = nullptr;

        InterfaceReg* reg = GetModuleRegister(moduleName);
        if (!reg) {
            IPCDebugLogger::InterfaceFailed(interfaceName);
            return;
        }

        void* pInterface = CaptureInterface(reg, interfaceName);
        if (!pInterface) {
            IPCDebugLogger::InterfaceFailed(interfaceName);
            return;
        }

        IPCDebugLogger::InterfaceFound(interfaceName, pInterface);
        *out = pInterface;
    }

    // ========================================================================
    // Material System Data Implementation
    // ========================================================================

    void MaterialSystemData::Initialize() {
        IPCDebugLogger::Log("=== Initializing Material System ===");
        FindSignatures();
        FindInterfaces();
        PrintDebugInfo();
    }

    void MaterialSystemData::FindSignatures() {
        IPCDebugLogger::Log("--- Finding Signatures ---");

        // CreateMaterial signature
        SignatureManager::AddSignature(
            "CreateMaterial",
            "materialsystem2.dll",
            SignatureString("48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 56 48 81 EC ? ? ? ? 48 8B 05"),
            (void**)&fnCreateMaterial
        );

        // FixupResourceClient signature
        SignatureManager::AddSignature(
            "FixupResourceClient",
            "client.dll",
            SignatureString("E8 {} 48 8B D3 C7 85"),
            (void**)&fnFixupResourceClient
        );

        // SetTypeKV3 signature
        SignatureManager::AddSignature(
            "SetTypeKV3",
            "client.dll",
            SignatureString("E8 {} 48 8B 5E ? 41 8B 06"),
            (void**)&fnSetTypeKV3
        );

        // GetEntityByIndex signature
        SignatureManager::AddSignature(
            "GetEntityByIndex",
            "client.dll",
            SignatureString("4C 8D 49 ? 81 FA"),
            (void**)&fnGetEntityByIndex
        );
        
        // LoadKeyValues - Use exported function from tier0.dll
        // Signature: ?LoadKV3@@YA_NPEAVKeyValues3@@PEAVCUtlString@@PEAVCUtlBuffer@@AEBUKV3ID_t@@PEBDI@Z
        HMODULE tier0 = GetModuleHandleA("tier0.dll");
        if (tier0) {
            fnLoadKeyValues = (LoadKeyValues_t)GetProcAddress(tier0, "?LoadKV3@@YA_NPEAVKeyValues3@@PEAVCUtlString@@PEAVCUtlBuffer@@AEBUKV3ID_t@@PEBDI@Z");
            if (fnLoadKeyValues) {
                IPCDebugLogger::SignatureFound("LoadKeyValues", fnLoadKeyValues);
            } else {
                IPCDebugLogger::SignatureFailed("LoadKeyValues");
                SignatureManager::SetFailed();
            }
        }
        
        // CUtlBuffer::Init - Use exported constructor from tier0.dll
        // Signature: ??0CUtlBuffer@@QEAA@HHW4BufferFlags_t@0@@Z
        if (tier0) {
            fnUtlBufferInit = (UtlBufferInit_t)GetProcAddress(tier0, "??0CUtlBuffer@@QEAA@HHW4BufferFlags_t@0@@Z");
            if (fnUtlBufferInit) {
                IPCDebugLogger::SignatureFound("UtlBufferInit", fnUtlBufferInit);
            } else {
                IPCDebugLogger::SignatureFailed("UtlBufferInit");
                SignatureManager::SetFailed();
            }
        }
        
        // CUtlBuffer::PutString - Use exported function from tier0.dll
        // Signature: ?PutString@CUtlBuffer@@QEAAXPEBD@Z
        if (tier0) {
            fnUtlBufferPutString = (UtlBufferPutString_t)GetProcAddress(tier0, "?PutString@CUtlBuffer@@QEAAXPEBD@Z");
            if (fnUtlBufferPutString) {
                IPCDebugLogger::SignatureFound("UtlBufferPutString", fnUtlBufferPutString);
            } else {
                IPCDebugLogger::SignatureFailed("UtlBufferPutString");
                SignatureManager::SetFailed();
            }
        }

        if (SignatureManager::HasFailed()) {
            IPCDebugLogger::Warning("Some signatures failed to find");
        } else {
            IPCDebugLogger::Success("All signatures found successfully");
        }
    }

    void MaterialSystemData::FindInterfaces() {
        IPCDebugLogger::Log("--- Finding Interfaces ---");

        // SchemaSystem
        pSchemaSystem = InterfaceManager::GetInterface<ISchemaSystem>(
            "schemasystem.dll", "SchemaSystem_00");

        // InputSystem - not critical for material testing
        // pInputSystem = InterfaceManager::GetInterface<CInputSystem>(
        //     "inputsystem.dll", "InputSystemVersion00");

        // ResourceSystem
        pResourceSystem = InterfaceManager::GetInterface<CResourceSystem>(
            "resourcesystem.dll", "ResourceSystem013");

        // GameResourceService
        pGameResourceService = InterfaceManager::GetInterface<CGameResourceService>(
            "engine2.dll", "GameResourceServiceClientV00");

        // Get ResourceHandleUtils from ResourceSystem
        if (pResourceSystem) {
            // QueryInterface is typically at vtable offset 0 or 1
            // For now, we'll log that we need to implement this
            IPCDebugLogger::Log("ResourceSystem found, need to query ResourceHandleUtils");
        }

        IPCDebugLogger::Log("Interface scanning complete");
    }

    void MaterialSystemData::PrintDebugInfo() {
        char buffer[512];
        
        IPCDebugLogger::Log("=== Material System Status ===");
        
        IPCDebugLogger::Log("Signatures:");
        
        simple_sprintf(buffer, sizeof(buffer), "  CreateMaterial:       %s (0x%p)", 
            fnCreateMaterial ? "FOUND" : "MISSING", fnCreateMaterial);
        IPCDebugLogger::SendIPC("INFO", buffer);
        
        simple_sprintf(buffer, sizeof(buffer), "  FixupResourceClient:  %s (0x%p)", 
            fnFixupResourceClient ? "FOUND" : "MISSING", fnFixupResourceClient);
        IPCDebugLogger::SendIPC("INFO", buffer);
        
        simple_sprintf(buffer, sizeof(buffer), "  SetTypeKV3:           %s (0x%p)", 
            fnSetTypeKV3 ? "FOUND" : "MISSING", fnSetTypeKV3);
        IPCDebugLogger::SendIPC("INFO", buffer);
        
        simple_sprintf(buffer, sizeof(buffer), "  LoadKeyValues:        %s (0x%p)", 
            fnLoadKeyValues ? "FOUND" : "MISSING", fnLoadKeyValues);
        IPCDebugLogger::SendIPC("INFO", buffer);
        
        simple_sprintf(buffer, sizeof(buffer), "  GetEntityByIndex:     %s (0x%p)", 
            fnGetEntityByIndex ? "FOUND" : "MISSING", fnGetEntityByIndex);
        IPCDebugLogger::SendIPC("INFO", buffer);
        
        simple_sprintf(buffer, sizeof(buffer), "  UtlBufferInit:        %s (0x%p)", 
            fnUtlBufferInit ? "FOUND" : "MISSING", fnUtlBufferInit);
        IPCDebugLogger::SendIPC("INFO", buffer);
        
        simple_sprintf(buffer, sizeof(buffer), "  UtlBufferPutString:   %s (0x%p)", 
            fnUtlBufferPutString ? "FOUND" : "MISSING", fnUtlBufferPutString);
        IPCDebugLogger::SendIPC("INFO", buffer);

        IPCDebugLogger::Log("Interfaces:");
        
        simple_sprintf(buffer, sizeof(buffer), "  SchemaSystem:         %s (0x%p)", 
            pSchemaSystem ? "FOUND" : "MISSING", pSchemaSystem);
        IPCDebugLogger::SendIPC("INFO", buffer);
        
        simple_sprintf(buffer, sizeof(buffer), "  ResourceSystem:       %s (0x%p)", 
            pResourceSystem ? "FOUND" : "MISSING", pResourceSystem);
        IPCDebugLogger::SendIPC("INFO", buffer);
        
        simple_sprintf(buffer, sizeof(buffer), "  GameResourceService:  %s (0x%p)", 
            pGameResourceService ? "FOUND" : "MISSING", pGameResourceService);
        IPCDebugLogger::SendIPC("INFO", buffer);

        IPCDebugLogger::Log("===============================");
    }

    // ========================================================================
    // Main Test Interface Implementation
    // ========================================================================

    bool MaterialEditorIntegration::initialized_ = false;

    bool MaterialEditorIntegration::Initialize() {
        if (initialized_) {
            IPCDebugLogger::Warning("MaterialEditorIntegration already initialized");
            return true;
        }

        IPCDebugLogger::Initialize();
        
        SignatureManager::Initialize();
        InterfaceManager::Initialize();
        
        MaterialSystemData::Initialize();

        initialized_ = true;
        return !SignatureManager::HasFailed();
    }

    bool MaterialEditorIntegration::VerifySystem() {
        if (!initialized_) {
            IPCDebugLogger::Error("System not initialized");
            return false;
        }

        bool allGood = true;

        // Check critical signatures
        if (!MaterialSystemData::fnCreateMaterial) {
            IPCDebugLogger::Error("VERIFY FAILED: CreateMaterial not found");
            allGood = false;
        }

        // Check critical interfaces
        if (!MaterialSystemData::pSchemaSystem) {
            IPCDebugLogger::Error("VERIFY FAILED: SchemaSystem not found");
            allGood = false;
        }

        if (!MaterialSystemData::pResourceSystem) {
            IPCDebugLogger::Error("VERIFY FAILED: ResourceSystem not found");
            allGood = false;
        }

        if (allGood) {
            IPCDebugLogger::Success("System verification PASSED");
        } else {
            IPCDebugLogger::Error("System verification FAILED");
        }

        return allGood;
    }

    void MaterialEditorIntegration::PrintStatus() {
        MaterialSystemData::PrintDebugInfo();
    }

    bool MaterialEditorIntegration::TestMaterialCreation(const char* materialName) {
        if (!initialized_) {
            IPCDebugLogger::SendIPC("ERROR", "Cannot test material creation - system not initialized");
            return false;
        }

        if (!MaterialSystemData::fnCreateMaterial) {
            IPCDebugLogger::SendIPC("ERROR", "Cannot test material creation - CreateMaterial function not found");
            return false;
        }
        
        if (!MaterialSystemData::fnSetTypeKV3) {
            IPCDebugLogger::SendIPC("ERROR", "Cannot test material creation - SetTypeKV3 function not found");
            return false;
        }
        
        if (!MaterialSystemData::fnLoadKeyValues) {
            IPCDebugLogger::SendIPC("ERROR", "Cannot test material creation - LoadKeyValues function not found");
            return false;
        }
        
        if (!MaterialSystemData::fnUtlBufferInit) {
            IPCDebugLogger::SendIPC("ERROR", "Cannot test material creation - UtlBufferInit function not found");
            return false;
        }
        
        if (!MaterialSystemData::fnUtlBufferPutString) {
            IPCDebugLogger::SendIPC("ERROR", "Cannot test material creation - UtlBufferPutString function not found");
            return false;
        }

        char buffer[512];
        simple_sprintf(buffer, sizeof(buffer), "Testing material creation for: %s", materialName);
        IPCDebugLogger::SendIPC("INFO", buffer);
        
        // KV3 signature header
        const char* kv3_signature = R"(<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:generic:version{7412167c-06e9-4698-aff2-e63eb59037e7} -->
{
)";
        
        // Test material definition (simple white unlit material)
        const char* material_content = R"(shader = "csgo_unlitgeneric.vfx"

F_PAINT_VERTEX_COLORS = 1
F_TRANSLUCENT = 1
F_BLEND_MODE = 1

g_vColorTint = [1, 1, 1, 1]

TextureAmbientOcclusion = resource:"materials/default/default_mask_tga_fde710a5.vtex"
g_tAmbientOcclusion = resource:"materials/default/default_mask_tga_fde710a5.vtex"
g_tColor = resource:"materials/default/default_mask_tga_fde710a5.vtex"
g_tNormal = resource:"materials/default/default_mask_tga_fde710a5.vtex"
g_tTintMask = resource:"materials/default/default_mask_tga_fde710a5.vtex"
})";

        // Build full vmat string
        char vmatBuffer[2048];
        size_t offset = 0;
        
        // Copy KV3 signature
        const char* src = kv3_signature;
        while (*src && offset < sizeof(vmatBuffer) - 1) {
            vmatBuffer[offset++] = *src++;
        }
        
        // Copy material content
        src = material_content;
        while (*src && offset < sizeof(vmatBuffer) - 1) {
            vmatBuffer[offset++] = *src++;
        }
        
        // Add closing brace
        if (offset < sizeof(vmatBuffer) - 2) {
            vmatBuffer[offset++] = '\n';
            vmatBuffer[offset++] = '}';
        }
        vmatBuffer[offset] = '\0';
        
        IPCDebugLogger::SendIPC("INFO", "Creating CKeyValues3 object...");
        
        // Create CKeyValues3 object and zero the memory
        CKeyValues3 keyValues;
        memset(&keyValues, 0, sizeof(CKeyValues3));
        IPCDebugLogger::SendIPC("INFO", "CKeyValues3 memory zeroed");
        
        // Initialize KV3 (SetTypeKV3) - THIS IS REQUIRED
        void* kvResult = MaterialSystemData::fnSetTypeKV3(&keyValues, 1u, 6u);
        if (!kvResult) {
            IPCDebugLogger::SendIPC("ERROR", "Failed to initialize CKeyValues3 (SetTypeKV3 returned null)");
            return false;
        }
        
        IPCDebugLogger::SendIPC("SUCCESS", "CKeyValues3 initialized with SetTypeKV3");
        IPCDebugLogger::SendIPC("INFO", "Creating CUtlBuffer and loading material data...");
        
        // Create CUtlBuffer - try using Init directly with text mode
        CUtlBuffer utlBuffer;
        int vmatLength = static_cast<int>(offset);
        
        char debugMsg[256];
        simple_sprintf(debugMsg, sizeof(debugMsg), "CUtlBuffer size: %d, vmatLength: %d", sizeof(CUtlBuffer), vmatLength);
        IPCDebugLogger::SendIPC("INFO", debugMsg);
        
        // Call Init as constructor (returns 'this')
        void* initResult = MaterialSystemData::fnUtlBufferInit(&utlBuffer, 0, vmatLength + 10, 1);
        simple_sprintf(debugMsg, sizeof(debugMsg), "UtlBufferInit returned: 0x%p (should be same as buffer: 0x%p)", initResult, &utlBuffer);
        IPCDebugLogger::SendIPC("INFO", debugMsg);
        
        MaterialSystemData::fnUtlBufferPutString(&utlBuffer, vmatBuffer);
        simple_sprintf(debugMsg, sizeof(debugMsg), "PutString called with %d bytes", vmatLength);
        IPCDebugLogger::SendIPC("INFO", debugMsg);
        
        // CRITICAL: After PutString, the write position (m_Put) is at the end
        // But LoadKeyValues needs to read from position 0
        // CUtlBuffer structure (approximately):
        //   +0x00: char* m_Memory
        //   +0x08: int m_nAllocationCount (or maxput)
        //   +0x0C: int m_Get (read position)
        //   +0x10: int m_Put (write position)
        // We need to reset m_Get to 0
        
        // Try to find and reset the read position to 0
        // Let's check multiple offsets to find the right one
        int* pBufferInternals = (int*)&utlBuffer;
        
        // Log first few ints to understand structure
        simple_sprintf(debugMsg, sizeof(debugMsg), "Buffer internals: [0]=%d [1]=%d [2]=%d [3]=%d [4]=%d [5]=%d", 
                      pBufferInternals[0], pBufferInternals[1], pBufferInternals[2], 
                      pBufferInternals[3], pBufferInternals[4], pBufferInternals[5]);
        IPCDebugLogger::SendIPC("INFO", debugMsg);
        
        // The Put value should be around 649-660 (our data size + overhead)
        // Find which offset has that value
        for (int i = 0; i < 10; i++) {
            if (pBufferInternals[i] > 640 && pBufferInternals[i] < 700) {
                simple_sprintf(debugMsg, sizeof(debugMsg), "Found likely Put at offset %d: value=%d", i, pBufferInternals[i]);
                IPCDebugLogger::SendIPC("INFO", debugMsg);
                // Get should be just before Put
                if (i > 0) {
                    simple_sprintf(debugMsg, sizeof(debugMsg), "Resetting Get at offset %d from %d to 0", i-1, pBufferInternals[i-1]);
                    IPCDebugLogger::SendIPC("INFO", debugMsg);
                    pBufferInternals[i-1] = 0;
                }
                break;
            }
        }
        
        IPCDebugLogger::SendIPC("INFO", "Buffer populated and reset, ready for LoadKeyValues");
        
        // Verify buffer content (first 64 chars)
        char bufferPreview[80];
        int previewLen = (vmatLength < 64) ? vmatLength : 64;
        for (int i = 0; i < previewLen; i++) {
            char c = vmatBuffer[i];
            bufferPreview[i] = (c >= 32 && c < 127) ? c : '.';
        }
        bufferPreview[previewLen] = '\0';
        
        // Send preview in chunks since simple_sprintf might not handle it well
        IPCDebugLogger::SendIPC("INFO", "Buffer content preview (first 64 chars):");
        IPCDebugLogger::SendIPC("INFO", bufferPreview);
        
        IPCDebugLogger::SendIPC("SUCCESS", "CUtlBuffer created and populated");
        IPCDebugLogger::SendIPC("INFO", "Loading KeyValues from buffer...");
        
        // Load KeyValues from buffer
        simple_sprintf(debugMsg, sizeof(debugMsg), "Calling LoadKeyValues: kv=0x%p, buf=0x%p", &keyValues, &utlBuffer);
        IPCDebugLogger::SendIPC("INFO", debugMsg);
        
        KV3ID_t kv3ID = { "generic", 0x41B818518343427E, 0xB5F447C23C0CDF8C };
        simple_sprintf(debugMsg, sizeof(debugMsg), "KV3ID: name=%s, id0=0x%llX, id1=0x%llX", kv3ID.szName, kv3ID.unk0, kv3ID.unk1);
        IPCDebugLogger::SendIPC("INFO", debugMsg);
        
        // Call LoadKeyValues
        IPCDebugLogger::SendIPC("INFO", "About to call LoadKeyValues function...");
        
        bool loadResult = MaterialSystemData::fnLoadKeyValues(
            &keyValues,
            nullptr,
            &utlBuffer,
            &kv3ID,
            nullptr,
            nullptr,
            nullptr,
            nullptr,
            "",
            0
        );
        
        simple_sprintf(debugMsg, sizeof(debugMsg), "LoadKeyValues returned: %d", loadResult ? 1 : 0);
        IPCDebugLogger::SendIPC("INFO", debugMsg);
        
        if (!loadResult) {
            IPCDebugLogger::SendIPC("ERROR", "Failed to load KeyValues from buffer (returned false)");
            
            // Try to get more info about the buffer state
            simple_sprintf(debugMsg, sizeof(debugMsg), "Buffer first 32 bytes check...");
            IPCDebugLogger::SendIPC("INFO", debugMsg);
            
            return false;
        }
        
        IPCDebugLogger::SendIPC("SUCCESS", "KeyValues loaded from buffer successfully");
        IPCDebugLogger::SendIPC("INFO", "Creating material...");
        
        // Create the material
        CStrongHandle<CMaterial2> materialHandle;
        void* result = MaterialSystemData::fnCreateMaterial(
            nullptr,
            &materialHandle,
            materialName,
            &keyValues,
            0,
            1
        );
        
        if (!result) {
            IPCDebugLogger::SendIPC("ERROR", "CreateMaterial function returned null");
            return false;
        }
        
        if (!materialHandle.pBinding) {
            IPCDebugLogger::SendIPC("ERROR", "Material handle binding is null");
            return false;
        }
        
        if (!materialHandle.pBinding->pData) {
            IPCDebugLogger::SendIPC("ERROR", "Material data pointer is null");
            return false;
        }
        
        IPCDebugLogger::SendIPC("SUCCESS", "Material created successfully!");
        
        char infoBuffer[512];
        simple_sprintf(infoBuffer, sizeof(infoBuffer), "Material handle: 0x%p", materialHandle.pBinding);
        IPCDebugLogger::SendIPC("INFO", infoBuffer);
        
        simple_sprintf(infoBuffer, sizeof(infoBuffer), "Material data: 0x%p", materialHandle.pBinding->pData);
        IPCDebugLogger::SendIPC("INFO", infoBuffer);
        
        simple_sprintf(infoBuffer, sizeof(infoBuffer), "Material ref count: %d", materialHandle.pBinding->nRefCount);
        IPCDebugLogger::SendIPC("INFO", infoBuffer);
        
        // Access CMaterial2 properties
        CMaterial2* pMaterial = static_cast<CMaterial2*>(materialHandle.pBinding->pData);
        simple_sprintf(infoBuffer, sizeof(infoBuffer), "Material parameter count: %d", pMaterial->m_nParameterCount);
        IPCDebugLogger::SendIPC("INFO", infoBuffer);
        
        IPCDebugLogger::SendIPC("SUCCESS", "Material creation test PASSED!");
        
        return true;
    }

} // namespace MaterialEditorTest

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions