Вопрос Skill Issue

  • Автор темы Автор темы Trna
  • Дата начала Дата начала
Начинающий
Начинающий
Статус
Оффлайн
Регистрация
16 Авг 2022
Сообщения
51
Реакции
4
Hello,
I'm currently handling rendering in D3D11Window::HookPresent, but I'm encountering a problem. I'm retrieving game entities directly inside the HookPresent function, which sometimes causes crashes. This seems to happen because entities might be getting deleted or becoming invalid during the call.
To fix this, I tried caching entities in FrameStageNotify. (By the way, which FrameStage is generally considered best for cheat-related logic? I'm currently using stage 5 — which is case 4 in the game's switch statement, since the game uses stage - 1.)
After caching the entities in FrameStageNotify and then using them inside HookPresent just for drawing, I noticed a significant FPS drop. I suspect it's due to locking or possibly because a new std::vector is created on every frame.

What would be the best approach here?
 
Hello,
I'm currently handling rendering in D3D11Window::HookPresent, but I'm encountering a problem. I'm retrieving game entities directly inside the HookPresent function, which sometimes causes crashes. This seems to happen because entities might be getting deleted or becoming invalid during the call.
To fix this, I tried caching entities in FrameStageNotify. (By the way, which FrameStage is generally considered best for cheat-related logic? I'm currently using stage 5 — which is case 4 in the game's switch statement, since the game uses stage - 1.)
After caching the entities in FrameStageNotify and then using them inside HookPresent just for drawing, I noticed a significant FPS drop. I suspect it's due to locking or possibly because a new std::vector is created on every frame.

What would be the best approach here?
simple - directx is for rendering, not for anything else. do not use present hook for interacting with the game. period. (applies to any game)
try doing everything in FrameStageNotify(stage 9 or smth, called by CNetworkClientService::OnClientFrameSimulate (iirc)).
save rendering context(viewmatrix, projmatrix, etc.), add your primitives to the drawlist(a bunch of serialized "render commands" - i.e. draw a line at some coords, draw text, whatever) in the main thread, then in present you get that drawlist, transform vertices and draw objects according to rendering context. that's how games themselves do things. (obv synchronize access to the drawlist so that only one thread is either reading or writing at a time) (I think ImGui has drawlists so you could fool around with that if you're using it)
 
Thanks to both of you!

simple - directx is for rendering, not for anything else. do not use present hook for interacting with the game. period. (applies to any game)
try doing everything in FrameStageNotify(stage 9 or smth, called by CNetworkClientService::OnClientFrameSimulate (iirc)).
save rendering context(viewmatrix, projmatrix, etc.), add your primitives to the drawlist(a bunch of serialized "render commands" - i.e. draw a line at some coords, draw text, whatever) in the main thread, then in present you get that drawlist, transform vertices and draw objects according to rendering context. that's how games themselves do things. (obv synchronize access to the drawlist so that only one thread is either reading or writing at a time) (I think ImGui has drawlists so you could fool around with that if you're using it)

Afaik maximum stage number is 8.
I tried calling all imgui function inside FrameStageNotify:

Код:
Expand Collapse Copy
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
g_Menu->Draw();
ImGui::PushFont(InterMedium);
ImGui::RenderNotifications();
Hud::Draw();
ImGui::PopFont();
ImGui::EndFrame();
ImGui::Render();

Then I stored ImGui::GetDrawData() in a global variable and called ImGui_ImplDX11_RenderDrawData() with that global variable inside HookPresent. However, this caused flickering. (I guess because of this is unsupported. ImGui assumes a single-threaded render lifecycle)
 
Последнее редактирование:
I found a hack around ImGui flickering, but I guess it's worst solution ever:

C++:
Expand Collapse Copy
ImDrawData* CloneDrawData(const ImDrawData* src)
{
    if (!src || src->CmdListsCount == 0)
        return nullptr;

    ImDrawData* dst = new ImDrawData(*src);
    dst->CmdLists = new ImDrawList * [src->CmdListsCount];

    for (int i = 0; i < src->CmdListsCount; i++)
    {
        const ImDrawList* src_list = src->CmdLists[i];
        ImDrawList* dst_list = new ImDrawList(src_list->_Data);

        // Deep copy vertex/index/cmd buffers
        dst_list->CmdBuffer = src_list->CmdBuffer;
        dst_list->IdxBuffer = src_list->IdxBuffer;
        dst_list->VtxBuffer = src_list->VtxBuffer;

        dst->CmdLists[i] = dst_list;
    }

    return dst;
}

void FreeClonedDrawData(ImDrawData* draw_data)
{
    if (!draw_data)
        return;

    for (int i = 0; i < draw_data->CmdListsCount; i++)
    {
        delete draw_data->CmdLists[i];
    }

    delete[] draw_data->CmdLists;
    delete draw_data;
}
C++:
Expand Collapse Copy
    if (frameStage == 8)
    {
        std::scoped_lock lock(g_DrawDataLock);

        if (g_DrawData)
        {
            FreeClonedDrawData(g_DrawData);
            g_DrawData = nullptr;
        }

        ImGui_ImplDX11_NewFrame();
        ImGui_ImplWin32_NewFrame();
        ImGui::NewFrame();

        GUI::g_Menu->Draw();
        Hud::Draw();

        ImGui::EndFrame();
        ImGui::Render();

        g_DrawData = CloneDrawData(ImGui::GetDrawData());
    }

HookPresent:

C++:
Expand Collapse Copy
    std::scoped_lock lock(g_DrawDataLock);
    if (g_DrawData)
    {
        m_DeviceContext->OMSetRenderTargets(1, &m_RenderTargetView, NULL);
        ImGui_ImplDX11_RenderDrawData(g_DrawData);
    }
 
I found a hack around ImGui flickering, but I guess it's worst solution ever:

C++:
Expand Collapse Copy
ImDrawData* CloneDrawData(const ImDrawData* src)
{
    if (!src || src->CmdListsCount == 0)
        return nullptr;

    ImDrawData* dst = new ImDrawData(*src);
    dst->CmdLists = new ImDrawList * [src->CmdListsCount];

    for (int i = 0; i < src->CmdListsCount; i++)
    {
        const ImDrawList* src_list = src->CmdLists[i];
        ImDrawList* dst_list = new ImDrawList(src_list->_Data);

        // Deep copy vertex/index/cmd buffers
        dst_list->CmdBuffer = src_list->CmdBuffer;
        dst_list->IdxBuffer = src_list->IdxBuffer;
        dst_list->VtxBuffer = src_list->VtxBuffer;

        dst->CmdLists[i] = dst_list;
    }

    return dst;
}

void FreeClonedDrawData(ImDrawData* draw_data)
{
    if (!draw_data)
        return;

    for (int i = 0; i < draw_data->CmdListsCount; i++)
    {
        delete draw_data->CmdLists[i];
    }

    delete[] draw_data->CmdLists;
    delete draw_data;
}
C++:
Expand Collapse Copy
    if (frameStage == 8)
    {
        std::scoped_lock lock(g_DrawDataLock);

        if (g_DrawData)
        {
            FreeClonedDrawData(g_DrawData);
            g_DrawData = nullptr;
        }

        ImGui_ImplDX11_NewFrame();
        ImGui_ImplWin32_NewFrame();
        ImGui::NewFrame();

        GUI::g_Menu->Draw();
        Hud::Draw();

        ImGui::EndFrame();
        ImGui::Render();

        g_DrawData = CloneDrawData(ImGui::GetDrawData());
    }

HookPresent:

C++:
Expand Collapse Copy
    std::scoped_lock lock(g_DrawDataLock);
    if (g_DrawData)
    {
        m_DeviceContext->OMSetRenderTargets(1, &m_RenderTargetView, NULL);
        ImGui_ImplDX11_RenderDrawData(g_DrawData);
    }
typically people(and game developers themselves) only prepare untransformed, raw-ish data(render commands - draw lists - lists of things that you need to draw(but you don't actually draw them yet you just collect them into a list)) in the main thread(s) and then do the transforming/rendering in the render thread(s) (aka multithreaded/multicore rendering)
 
Thanks to both of you!
 
Последнее редактирование:
Назад
Сверху Снизу