Загрузка данных


#include "pch.h"
#include <Windows.h>
#include <MinHook.h>
#include <d3d11.h>
#include <dxgi.h>
#include <iostream>

// Подключаем ImGui
#include "imgui.h"
#include "imgui_impl_win32.h"
#include "imgui_impl_dx11.h"

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")

// ==================== ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ ====================
typedef HRESULT(WINAPI* tPresent)(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags);
tPresent fpPresent = NULL;

ID3D11Device* g_pd3dDevice = NULL;
ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
ID3D11RenderTargetView* g_mainRenderTargetView = NULL;
HWND g_hWnd = NULL;

// Настройки нашего мода
bool show_menu = true;
bool show_stats = true;

// ==================== ФУНКЦИИ IMGUI ====================
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

// Обработчик сообщений окна
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
        return true;

    switch (msg) {
    case WM_SIZE:
        if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED) {
            // Обработка изменения размера окна
        }
        return 0;
    case WM_SYSCOMMAND:
        if ((wParam & 0xfff0) == SC_KEYMENU) // Отключаем меню по Alt
            return 0;
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return CallWindowProc(ImGui_ImplWin32_GetWndProc(), hWnd, msg, wParam, lParam);
}

// Инициализация ImGui
void InitImGui() {
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO();
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;

    ImGui::StyleColorsDark(); // Темная тема (как в игре)

    ImGui_ImplWin32_Init(g_hWnd);
    ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
}

// Отрисовка меню (Виджет Боевая эффективность)
void RenderMenu() {
    if (!show_menu) return;

    // Стиль окна как на скриншотах
    ImGui::SetNextWindowSize(ImVec2(400, 450), ImGuiCond_FirstUseEver);
    ImGui::Begin("Боевая эффективность (Stats Mod)", &show_menu);

    // Левая колонка с иконками (имитация)
    ImGui::BeginChild("LeftPanel", ImVec2(50, 0), true);
    ImGui::Text("X"); // Иконка мечей
    ImGui::Text("O"); // Иконка монеты
    ImGui::Text("S"); // Иконка звезды
    ImGui::Text("Z"); // Иконка молнии
    ImGui::EndChild();

    ImGui::SameLine();

    // Правая колонка с контентом
    ImGui::BeginChild("RightPanel", ImVec2(0, 0), false);

    ImGui::Text("Статистика за сессию");
    ImGui::Separator();

    // Чекбоксы для выбора отображения
    static bool show_battles = true;
    static bool show_wins = true;
    static bool show_winrate = true;
    static bool show_avg_damage = true;
    static bool show_avg_exp = true;

    ImGui::Checkbox("Проведено боёв", &show_battles);
    ImGui::Checkbox("Победы", &show_wins);
    ImGui::Checkbox("Процент побед", &show_winrate);
    ImGui::Checkbox("Средний урон", &show_avg_damage);
    ImGui::Checkbox("Средний опыт", &show_avg_exp);

    ImGui::Separator();
    ImGui::Text("Показатели:");

    // ЗДЕСЬ ВЫВОДЯТСЯ ДАННЫЕ. ПОКА ЭТО ЗАГЛУШКИ (ЦИФРЫ С ТВОИХ СКРИНШОТОВ)
    // Чтобы подтянуть реальные данные, нужно заменить цифры на переменные из памяти игры
    if (show_battles) ImGui::Text("Проведено боёв: 9");
    if (show_wins) ImGui::Text("Победы: 6");
    if (show_winrate) ImGui::Text("Процент побед: 66.67%%");
    if (show_avg_damage) ImGui::Text("Средний урон: 1913");
    if (show_avg_exp) ImGui::Text("Средний опыт: 782");

    ImGui::EndChild();
    ImGui::End();
}

// ==================== ХУК DIRECTX 11 ====================
HRESULT WINAPI hkPresent(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags) {
    static bool init = false;

    if (!init) {
        if (SUCCEEDED(pSwapChain->GetDevice(__uuidof(ID3D11Device), (void**)&g_pd3dDevice))) {
            g_pd3dDevice->GetImmediateContext(&g_pd3dDeviceContext);
            DXGI_SWAP_CHAIN_DESC sd;
            pSwapChain->GetDesc(&sd);
            g_hWnd = sd.OutputWindow;

            // Создаем Render Target
            ID3D11Texture2D* pBackBuffer = NULL;
            pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
            if (pBackBuffer) {
                g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_mainRenderTargetView);
                pBackBuffer->Release();
            }

            // Подменяем WndProc
            ImGui_ImplWin32_SetWndProc((WNDPROC)SetWindowLongPtr(g_hWnd, GWLP_WNDPROC, (LONG_PTR)WndProc));
            InitImGui();
            init = true;
        }
    }

    if (init) {
        ImGui_ImplDX11_NewFrame();
        ImGui_ImplWin32_NewFrame();
        ImGui::NewFrame();

        // Рисуем наше меню
        RenderMenu();

        ImGui::Render();
        g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL);
        ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
    }

    return fpPresent(pSwapChain, SyncInterval, Flags);
}

// ==================== ПОТОК МОДА ====================
DWORD WINAPI MainThread(LPVOID lpParam) {
    // Выделяем консоль для отладки
    AllocConsole();
    FILE* fDummy;
    freopen_s(&fDummy, "CONOUT$", "w", stdout);
    std::cout << "[stats_mod] Загрузка мода..." << std::endl;

    // Ждем загрузки dxgi.dll
    HMODULE hDxgi = NULL;
    while (!hDxgi) {
        hDxgi = GetModuleHandleA("dxgi.dll");
        Sleep(100);
    }

    // Создаем фиктивное устройство для поиска VTable
    DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory(&sd, sizeof(sd));
    sd.BufferCount = 1;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.OutputWindow = GetForegroundWindow();
    sd.SampleDesc.Count = 1;
    sd.Windowed = TRUE;
    sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

    IDXGISwapChain* pSwapChain = NULL;
    ID3D11Device* pDevice = NULL;
    ID3D11DeviceContext* pContext = NULL;
    D3D_FEATURE_LEVEL featureLevel;

    if (FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &sd, &pSwapChain, &pDevice, &featureLevel, &pContext))) {
        std::cout << "[!] Ошибка создания фиктивного устройства DX11" << std::endl;
        return 1;
    }

    // Получаем адрес Present из виртуальной таблицы (индекс 8)
    void** pVTable = *reinterpret_cast<void***>(pSwapChain);
    void* pPresentAddr = pVTable[8];

    // Освобождаем фиктивные объекты
    pSwapChain->Release();
    pDevice->Release();
    pContext->Release();

    // Инициализируем MinHook
    if (MH_Initialize() != MH_OK) {
        std::cout << "[!] Ошибка MinHook" << std::endl;
        return 1;
    }

    // Ставим хук на Present
    if (MH_CreateHook(pPresentAddr, &hkPresent, reinterpret_cast<LPVOID*>(&fpPresent)) != MH_OK) {
        std::cout << "[!] Не удалось захукать Present" << std::endl;
        return 1;
    }

    if (MH_EnableHook(pPresentAddr) != MH_OK) {
        std::cout << "[!] Не удалось включить хук Present" << std::endl;
        return 1;
    }

    std::cout << "[+] Мод успешно загружен! Нажми INSERT для скрытия меню." << std::endl;

    // Цикл обработки нажатий клавиш
    while (true) {
        if (GetAsyncKeyState(VK_INSERT) & 1) {
            show_menu = !show_menu;
        }
        Sleep(50);
    }

    return 0;
}

// ==================== ТОЧКА ВХОДА ====================
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    switch (ul_reason_for_call) {
    case DLL_PROCESS_ATTACH:
        DisableThreadLibraryCalls(hModule);
        CreateThread(nullptr, 0, MainThread, hModule, 0, nullptr);
        break;
    case DLL_PROCESS_DETACH:
        MH_DisableHook(MH_ALL_HOOKS);
        MH_Uninitialize();
        break;
    }
    return TRUE;
}