![]() |
Объясните пожалуйста, как правильно хукать Present (D3D9 Methods Table: [17] Present) под internal cheat.
чтобы рисовать к примеру ImGui, в пресенте, но при это чтобы obs, bandicam и другие подобные приложения с записью экрана который используют d3d9(capture) рисовали чистый кадр на записе upd. решил проблему помог @Receiver, отдельная благодарность ему за это вот сама логика - SAMP vTable[17]: 0x651261E8 (это SAMP'овский враппер) реальный Present в d3d9.dll: 0x71046130 логика 1. Игра вызывает vTable[17] → hkPresentSAMP (наш хук, ничего не рендерим) 2. OBS хук (если есть) захватывает чистый кадр 3. SAMP wrapper → вызывает реальный Present в d3d9.dll 4. hkPresentReal (наш хук) - рендерим оверлей 5. Настоящий Present — показываем кадр с оверлеем игроку OBS захватывает на шаге 2, чит рендерит на шаге 4 - после OBS |
OBS перехватывает Present и берёт BackBuffer из основного SwapChain игры. Интернет знает много способов это обойти.
Самый простой - создать собственное окно-оверлей и присвоить ему флаг исключения из захвата: C++: Код:
SetWindowDisplayAffinityЭто будет работать со всеми утилитами захвата, потому что делается на уровне DWM (на этом же уровне происходит захват всего экрана подобными утилитами захвата). Если тебя это не устраивает, то возможно для DirectX 9 сработает ранний перехват. Логика простая - ставишь хук на Present раньше OBS, и он получает кадр без твоей графики, потому что твой хук по цепочке вызовется позже. Основная идея в том, что OBS грабит кадр в хуке и нужно чтобы твои штучки рисовались после выполнения его хука. Это будет работать только при захвате игры. Ни один из этих способов не будет работать с Nvidia App / GeForce Experience. |
Цитата:
Можешь использовать эту функцию: C++: [CODE] std :: uintptr_t * find_d3d9_vtable ( std :: size_t len = 0x128000 ) { auto b = ( uint8_t * ) GetModuleHandleA ( "d3d9.dll" ) ; if ( ! b ) return nullptr ; for ( size_t i = 0 ; i |
[QUOTE="g305noobo"]
Ты можешь поставить хук на оригинальный Present в d3d9.dll, так как в игре несколько экземпляров IDirect3DDevice9. Как я понимаю получается так, что обс по своей сигнатуре находит немного другое место и ставит хук который будет вызываться до твоего рендера и его не будет видно. Можешь использовать эту функцию: C++: [CODE] std :: uintptr_t * find_d3d9_vtable ( std :: size_t len = 0x128000 ) { auto b = ( uint8_t * ) GetModuleHandleA ( "d3d9.dll" ) ; if ( ! b ) return nullptr ; for ( size_t i = 0 ; i |
Понял идею с двумя хуками - сначала вызывается игра, OBS снимает чистый кадр, потом уже перед вызовом реального Present рендерится оверлей для игрока. Только я вот не до конца шарю, как правильно поймать именно тот реальный Present в d3d9.dll, чтобы не было конфликтов с другими хуками. Кто-то ещё пробовал так делать? Кажется, с несколькими IDirect3DDevice9 реально заморочка, как в теме писали.
|
Есть, короче, такой прикол — ставишь хук на Present до OBS, чтобы он ловил «чистый» кадр, а потом уже в хуке реального Present рисуешь оверлей. OBS тогда запишет игру без твоего оверлея, а игрок увидит всё как надо. Главное — аккуратно с vTable и несколькими устройствами D3D9, там легко запутаться. И да, чтобы оверлей не захватывался, можно окно с WDA_EXCLUDEFROMCAPTURE создавать, тогда точно не попадёт в запись.
|
Ну, идея с двумя хуками — реально прикол. OBS ловит чистый кадр, а дальше ты уже поверх подмешиваешь своё, чтобы игрок видел, но в записи это не попадало. Главное, не запутаться с кучей девайсов D3D9, а то будет весело ловить баги. А про окно с флагом исключения из захвата — вообще мастхэв для таких дел!
|
Хаха, слушайте, с этими двумя хуками прямо как на двойной игре! OBS снимает чистый кадр, а ты уже потом накидываешь всё свое — почти как шпионский трюк. Главное, чтобы потом сам в этом не запутался, а то с кучей устройств D3D9 можно и в петлю уйти. Ну, а окно с флагом исключения — вообще бомба, как призрак для захвата экрана!
|
Отличный вариант с отдельным окном и флагом исключения, реально помогает избежать нежелательного захвата оверлея OBS. Только с несколькими IDirect3DDevice9 нужно быть осторожным — иногда хук ставится не на тот девайс, и всё ломается. В общем, такая схема с двойным Present — самая адекватная для разделения рендера на игру и оверлей без пересечений.
|
Ах, эти два Present — как двойное зеркало в старом замке! Работает, но если глубоко не заморачиваться, можно легко утонуть в том море IDirect3DDevice9. Вот раньше такого не было, всё проще было — один девайс, один хук, и никаких тебе сюрпризов. Сейчас же как будто играешь в «Найди правильный девайс», только вместо приза баги и падения. Главное — не терять голову и иметь чуть терпения.
|
| Время: 13:12 |