From e70e4d1a8cba2e5640cf1ec1f7f9871e77cc47a8 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 15 Jun 2022 01:24:29 +0200 Subject: [PATCH] Add DebugOverlay implementation --- r5dev/core/init.cpp | 4 +- r5dev/engine/debugoverlay.cpp | 259 ++++++++++++++++++++++++++ r5dev/engine/debugoverlay.h | 50 +++-- r5dev/tier1/IConVar.cpp | 1 + r5dev/tier1/cvar.cpp | 1 + r5dev/tier1/cvar.h | 1 + r5dev/vproj/clientsdk.vcxproj | 1 + r5dev/vproj/clientsdk.vcxproj.filters | 3 + r5dev/vproj/gamesdk.vcxproj | 1 + r5dev/vproj/gamesdk.vcxproj.filters | 3 + 10 files changed, 302 insertions(+), 22 deletions(-) create mode 100644 r5dev/engine/debugoverlay.cpp diff --git a/r5dev/core/init.cpp b/r5dev/core/init.cpp index 9fedfde5..3d553e04 100644 --- a/r5dev/core/init.cpp +++ b/r5dev/core/init.cpp @@ -202,7 +202,7 @@ void Systems_Init() #ifndef DEDICATED HCVideoMode_Common_Attach(); - //DebugOverlays_Attach(); + DebugOverlays_Attach(); RSurf_Attach(); #endif // !DEDICATED @@ -319,7 +319,7 @@ void Systems_Shutdown() #ifndef DEDICATED HCVideoMode_Common_Detach(); - //DebugOverlays_Detach(); + DebugOverlays_Detach(); RSurf_Detach(); #endif // !DEDICATED diff --git a/r5dev/engine/debugoverlay.cpp b/r5dev/engine/debugoverlay.cpp new file mode 100644 index 00000000..9d92899c --- /dev/null +++ b/r5dev/engine/debugoverlay.cpp @@ -0,0 +1,259 @@ +//============================================================================// +// +// Purpose: Debug interface functions +// +//============================================================================// + +#include "core/stdafx.h" +#include "tier0/tslist.h" +#include "tier0/basetypes.h" +#include "tier1/cvar.h" +#include "common/pseudodefs.h" +#include "engine/client/clientstate.h" +#include "engine/host_cmd.h" +#include "engine/debugoverlay.h" +#include "materialsystem/cmaterialsystem.h" + + +//------------------------------------------------------------------------------ +// Purpose: checks if overlay should be decayed +//------------------------------------------------------------------------------ +bool OverlayBase_t::IsDead() const +{ + if (r_debug_overlay_nodecay->GetBool()) + { + // Keep rendering the overlay if nodecay is set. + return false; + } + + if (g_pClientState->IsPaused()) + { + // Keep rendering the overlay if the client simulation is paused. + return false; + } + + if (m_nCreationTick == -1) + { + if (m_nOverlayTick == -1) + { + if (m_flEndTime == NDEBUG_PERSIST_TILL_NEXT_SERVER) + { + return false; + } + return g_pClientState->GetClientTime() >= m_flEndTime; + } + else + { + return m_nOverlayTick < *overlay_tickcount; + } + return false; + } + else + { + return m_nCreationTick < *render_tickcount; + } + return g_pClientState->GetClientTime() >= m_flEndTime; +} + +//------------------------------------------------------------------------------ +// Purpose: destroys the overlay +//------------------------------------------------------------------------------ +void HDestroyOverlay(OverlayBase_t* pOverlay) +{ + std::int64_t pOverlayType; + + EnterCriticalSection(&*s_OverlayMutex); + switch (pOverlay->m_Type) + { + case OverlayType_t::OVERLAY_BOX: + pOverlayType = 128i64; + goto LABEL_MALLOC; + case OverlayType_t::OVERLAY_SPHERE: + pOverlayType = 72i64; + goto LABEL_MALLOC; + case OverlayType_t::OVERLAY_LINE: + pOverlayType = 80i64; + goto LABEL_MALLOC; + case OverlayType_t::OVERLAY_TRIANGLE: + pOverlayType = 6200i64; + goto LABEL_MALLOC; + case OverlayType_t::OVERLAY_SWEPT_BOX: + pOverlay->m_Type = OverlayType_t::OVERLAY_UNK1; + LeaveCriticalSection(&*s_OverlayMutex); + return; + case OverlayType_t::OVERLAY_BOX2: + break; + case OverlayType_t::OVERLAY_CAPSULE: + pOverlayType = 112i64; + break; + case OverlayType_t::OVERLAY_UNK0: + pOverlayType = 88i64; + goto LABEL_MALLOC; + LABEL_MALLOC: + pOverlay->m_Type = OverlayType_t::OVERLAY_UNK1; + v_MemAlloc_Internal(pOverlay, pOverlayType); + break; + default: + break; + } + + LeaveCriticalSection(&*s_OverlayMutex); +} + +//------------------------------------------------------------------------------ +// Purpose: draws a generic overlay +//------------------------------------------------------------------------------ +void DrawOverlay(OverlayBase_t* pOverlay) +{ + //void* pRenderContext = nullptr; // ptr to CMatQueuedRenderContext vtable. + + EnterCriticalSection(&*s_OverlayMutex); + + //pRenderContext = (*(void*(__fastcall**)(void*))(**(std::int64_t**)g_pMaterialSystem + MATERIALSYSTEM_VCALL_OFF_0))((void*)g_pMaterialSystem); + //(*(void(__fastcall**)(void*, std::int64_t))(*(std::int64_t*)pRenderContext + CMATQUEUEDRENDERCONTEXT_VCALL_OFS_0))((void*)pRenderContext, 0x1); + + switch (pOverlay->m_Type) + { + case OverlayType_t::OVERLAY_BOX: + { + OverlayBox_t* pBox = static_cast(pOverlay); // TODO: debug this since it doesn't work but does compute something.. + + // for testing, since RenderWireframeBox doesn't seem to work properly + //RenderWireframeSphere({ pBox->origin_X, pBox->origin_Y, pBox->origin_Z }, pBox->maxs.x, 8, 8, Color(pBox->r, pBox->g, pBox->b, 255), false); + //RenderLine({ pBox->origin_X, pBox->origin_Y, pBox->origin_Z }, { pBox->origin_X, pBox->origin_Y, pBox->origin_Z+pBox->maxs.z }, Color(pBox->r, pBox->g, pBox->b, 255), false); + + //if (pBox->a < 255) + //{ + // RenderWireframeBox({ pBox->origin_X, pBox->origin_Y, pBox->origin_Z }, pBox->angles, pBox->maxs, Color(pBox->r, pBox->g, pBox->b, 255), false); + //} + //else { + // RenderBox({ pBox->origin_X, pBox->origin_Y, pBox->origin_Z }, pBox->angles, pBox->mins, pBox->maxs, Color(pBox->r, pBox->g, pBox->b, pBox->a), false); + //} + break; + } + case OverlayType_t::OVERLAY_SPHERE: + { + OverlaySphere_t* pSphere = static_cast(pOverlay); + v_RenderWireframeSphere(pSphere->vOrigin, pSphere->flRadius, pSphere->nTheta, pSphere->nPhi, Color(pSphere->r, pSphere->g, pSphere->b, pSphere->a), false); + break; + } + case OverlayType_t::OVERLAY_LINE: + { + OverlayLine_t* pLine = static_cast(pOverlay); + v_RenderLine(pLine->origin, pLine->dest, Color(pLine->r, pLine->g, pLine->b, pLine->a), pLine->noDepthTest); + break; + } + case OverlayType_t::OVERLAY_TRIANGLE: + { + break; + } + case OverlayType_t::OVERLAY_SWEPT_BOX: + { + break; + } + case OverlayType_t::OVERLAY_BOX2: + { + break; + } + case OverlayType_t::OVERLAY_CAPSULE: + { + break; + } + case OverlayType_t::OVERLAY_UNK0: + { + break; + } + case OverlayType_t::OVERLAY_UNK1: + { + break; + } + } + //(*(void(__fastcall**)(void*))(*(_QWORD*)pRenderContext + CMATQUEUEDRENDERCONTEXT_VCALL_OFS_1))(pRenderContext); + //(*(void(__fastcall**)(void*))(*(_QWORD*)pRenderContext + CMATQUEUEDRENDERCONTEXT_VCALL_OFS_2))(pRenderContext); + + LeaveCriticalSection(&*s_OverlayMutex); +} + +//------------------------------------------------------------------------------ +// Purpose : overlay drawing entrypoint +//------------------------------------------------------------------------------ +void DrawAllOverlays(char pOverlay) +{ + if (!enable_debug_overlays->GetBool()) + { + return; + } + EnterCriticalSection(&*s_OverlayMutex); + + OverlayBase_t* pCurrOverlay = *s_pOverlays; // rdi + OverlayBase_t* pPrevOverlay = nullptr; // rsi + OverlayBase_t* pNextOverlay = nullptr; // rbx + + while (pCurrOverlay) + { + if (pCurrOverlay->IsDead()) + { + if (pPrevOverlay) + { + // If I had a last overlay reset it's next pointer + pPrevOverlay->m_pNextOverlay = pCurrOverlay->m_pNextOverlay; + } + else + { + // If the first line, reset the s_pOverlays pointer + *s_pOverlays = pCurrOverlay->m_pNextOverlay; + } + + pNextOverlay = pCurrOverlay->m_pNextOverlay; + v_DestroyOverlay(pCurrOverlay); + pCurrOverlay = pNextOverlay; + } + else + { + bool bDraw{ }; + if (pCurrOverlay->m_nCreationTick == -1) + { + if (pCurrOverlay->m_nOverlayTick == *overlay_tickcount) + { + // Draw overlay if unk0 == *overlay_tickcount + bDraw = true; + } + if (pCurrOverlay->m_nOverlayTick == -1) + { + // Draw overlay if unk0 == -1 + bDraw = true; + } + } + else + { + bDraw = pCurrOverlay->m_nCreationTick == *render_tickcount; + } + if (bDraw) + { + if (pOverlay) + { + DrawOverlay(pCurrOverlay); + } + } + pPrevOverlay = pCurrOverlay; + pCurrOverlay = pCurrOverlay->m_pNextOverlay; + } + } + LeaveCriticalSection(&*s_OverlayMutex); +} + +/////////////////////////////////////////////////////////////////////////////// +void DebugOverlays_Attach() +{ +//#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) +// p_DrawAllOverlays.Offset(0x189).Patch({ 0x83, 0x3F, 0x02 }); // Default value in memory is 0x2, condition is 0x4. Patch to fullfill condition. +//#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) +// p_DrawAllOverlays.Offset(0x188).Patch({ 0x83, 0x3F, 0x02 }); // Default value in memory is 0x2, condition is 0x4. Patch to fullfill condition. +//#endif + DetourAttach((LPVOID*)&v_DrawAllOverlays, &DrawAllOverlays); +} + +void DebugOverlays_Detach() +{ + DetourDetach((LPVOID*)&v_DrawAllOverlays, &DrawAllOverlays); +} diff --git a/r5dev/engine/debugoverlay.h b/r5dev/engine/debugoverlay.h index 5e30ac10..51092220 100644 --- a/r5dev/engine/debugoverlay.h +++ b/r5dev/engine/debugoverlay.h @@ -37,20 +37,20 @@ struct OverlayBase_t OverlayBase_t(void) { m_Type = OverlayType_t::OVERLAY_BOX; - m_nServerCount = -1; m_nCreationTick = -1; m_flEndTime = 0.0f; + m_nServerCount = -1; m_pNextOverlay = NULL; - unk0 = NULL; + m_nOverlayTick = NULL; } bool IsDead(void) const; OverlayType_t m_Type {}; // What type of overlay is it? int m_nCreationTick{}; // Duration -1 means go away after this frame # - float m_nServerCount {}; // Latch server count, too float m_flEndTime {}; // When does this box go away + int m_nServerCount {}; // Latch server count, too OverlayBase_t* m_pNextOverlay {}; // 16 - int64_t unk0 {}; // 24 + int m_nOverlayTick {}; // 24 }; struct OverlayLine_t : public OverlayBase_t @@ -70,10 +70,14 @@ struct OverlayBox_t : public OverlayBase_t { OverlayBox_t(void) { m_Type = OverlayType_t::OVERLAY_BOX; } - Vector3 origin{}; - Vector3 mins{}; - Vector3 maxs{}; - QAngle angles{}; + QAngle angles{}; //0x0020 - this isn't angles but idrk where it is + float origin_X{}; //0x002C + Vector3 unk30{}; //0x0030 + float origin_Y{}; //0x003C + Vector3 unk40{}; //0x0040 + float origin_Z{}; //0x004C + Vector3 mins{}; //0x0050 + Vector3 maxs{}; //0x005C int r{}; int g{}; int b{}; @@ -100,16 +104,19 @@ void DebugOverlays_Attach(); void DebugOverlays_Detach(); inline CMemory p_DrawAllOverlays; -inline auto DrawAllOverlays = p_DrawAllOverlays.RCast(); +inline auto v_DrawAllOverlays = p_DrawAllOverlays.RCast(); -inline CMemory p_RenderBox; -inline auto RenderBox = p_RenderBox.RCast(); +inline CMemory p_RenderWireframeBox; +inline auto v_RenderWireframeBox = p_RenderWireframeBox.RCast(); inline CMemory p_RenderLine; -inline auto RenderLine = p_RenderLine.RCast(); +inline auto v_RenderLine = p_RenderLine.RCast(); + +inline CMemory p_RenderWireframeSphere; +inline auto v_RenderWireframeSphere = p_RenderWireframeSphere.RCast(); inline CMemory p_DestroyOverlay; -inline auto DestroyOverlay = p_DestroyOverlay.RCast(); +inline auto v_DestroyOverlay = p_DestroyOverlay.RCast(); inline int* client_debugdraw_int_unk = nullptr; inline float* client_debugdraw_float_unk = nullptr; @@ -126,7 +133,8 @@ class VDebugOverlay : public IDetour virtual void GetAdr(void) const { spdlog::debug("| FUN: DrawAllOverlays : {:#18x} |\n", p_DrawAllOverlays.GetPtr()); - spdlog::debug("| FUN: RenderBox : {:#18x} |\n", p_RenderBox.GetPtr()); + spdlog::debug("| FUN: RenderWireframeBox : {:#18x} |\n", p_RenderWireframeBox.GetPtr()); + spdlog::debug("| FUN: RenderWireframeSphere : {:#18x} |\n", p_RenderWireframeSphere.GetPtr()); spdlog::debug("| FUN: RenderLine : {:#18x} |\n", p_RenderLine.GetPtr()); spdlog::debug("| FUN: DestroyOverlay : {:#18x} |\n", p_DestroyOverlay.GetPtr()); spdlog::debug("| VAR: s_pOverlays : {:#18x} |\n", reinterpret_cast(s_pOverlays)); @@ -144,15 +152,17 @@ class VDebugOverlay : public IDetour p_RenderBox = g_mGameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x44\x89\x4C\x24\x00"), "xxxx?xxxx?xxxx?"); #elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) p_DrawAllOverlays = g_mGameDll.FindPatternSIMD(reinterpret_cast("\x40\x55\x48\x83\xEC\x30\x48\x8B\x05\x00\x00\x00\x00\x0F\xB6\xE9"), "xxxxxxxxx????xxx"); - p_RenderBox = g_mGameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x44\x89\x4C\x24\x00"), "xxxx?xxxx?xxxx?"); + p_RenderWireframeBox = g_mGameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x44\x89\x4C\x24\x00"), "xxxx?xxxx?xxxx?"); #endif - p_RenderLine = g_mGameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x74\x24\x00\x44\x89\x44\x24\x00\x57\x41\x56"), "xxxx?xxxx?xxx"); p_DestroyOverlay = g_mGameDll.FindPatternSIMD(reinterpret_cast("\x40\x53\x48\x83\xEC\x20\x48\x8B\xD9\x48\x8D\x0D\x00\x00\x00\x00\xFF\x15\x00\x00\x00\x00\x48\x63\x03"), "xxxxxxxxxxxx????xx????xxx"); + p_RenderWireframeSphere = g_mGameDll.FindPatternSIMD(reinterpret_cast("\x40\x56\x41\x54\x41\x55\x48\x81\xEC\x00\x00\x00\x00"), "xxxxxxxxx????"); + p_RenderLine = g_mGameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x74\x24\x00\x44\x89\x44\x24\x00\x57\x41\x56"), "xxxx?xxxx?xxx"); - DrawAllOverlays = p_DrawAllOverlays.RCast(); /*40 55 48 83 EC 30 48 8B 05 ?? ?? ?? ?? 0F B6 E9*/ - DestroyOverlay = p_DestroyOverlay.RCast(); /*40 53 48 83 EC 20 48 8B D9 48 8D 0D ?? ?? ?? ?? FF 15 ?? ?? ?? ?? 48 63 03 */ - RenderBox = p_RenderBox.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 44 89 4C 24 ??*/ - RenderLine = p_RenderLine.RCast(); /*48 89 74 24 ?? 44 89 44 24 ?? 57 41 56*/ + v_DrawAllOverlays = p_DrawAllOverlays.RCast(); /*40 55 48 83 EC 30 48 8B 05 ?? ?? ?? ?? 0F B6 E9*/ + v_DestroyOverlay = p_DestroyOverlay.RCast(); /*40 53 48 83 EC 20 48 8B D9 48 8D 0D ?? ?? ?? ?? FF 15 ?? ?? ?? ?? 48 63 03 */ + v_RenderWireframeBox = p_RenderWireframeBox.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 44 89 4C 24 ??*/ + v_RenderWireframeSphere = p_RenderWireframeSphere.RCast(); /*40 56 41 54 41 55 48 81 EC ?? ?? ?? ??*/ + v_RenderLine = p_RenderLine.RCast(); /*48 89 74 24 ?? 44 89 44 24 ?? 57 41 56*/ } virtual void GetVar(void) const { diff --git a/r5dev/tier1/IConVar.cpp b/r5dev/tier1/IConVar.cpp index 5ef64b5c..fca670b6 100644 --- a/r5dev/tier1/IConVar.cpp +++ b/r5dev/tier1/IConVar.cpp @@ -169,6 +169,7 @@ void ConVar::Init(void) const void ConVar::InitShipped(void) const { single_frame_shutdown_for_reload = g_pCVar->FindVar("single_frame_shutdown_for_reload"); + enable_debug_overlays = g_pCVar->FindVar("enable_debug_overlays"); model_defaultFadeDistScale = g_pCVar->FindVar("model_defaultFadeDistScale"); model_defaultFadeDistMin = g_pCVar->FindVar("model_defaultFadeDistMin"); staticProp_no_fade_scalar = g_pCVar->FindVar("staticProp_no_fade_scalar"); diff --git a/r5dev/tier1/cvar.cpp b/r5dev/tier1/cvar.cpp index 8a7f018b..2e8c021f 100644 --- a/r5dev/tier1/cvar.cpp +++ b/r5dev/tier1/cvar.cpp @@ -7,6 +7,7 @@ // ENGINE | ConVar* single_frame_shutdown_for_reload = nullptr; ConVar* old_gather_props = nullptr; +ConVar* enable_debug_overlays = nullptr; ConVar* staticProp_defaultBuildFrustum = nullptr; ConVar* staticProp_no_fade_scalar = nullptr; diff --git a/r5dev/tier1/cvar.h b/r5dev/tier1/cvar.h index 07c01f0a..683c6637 100644 --- a/r5dev/tier1/cvar.h +++ b/r5dev/tier1/cvar.h @@ -5,6 +5,7 @@ // ENGINE | extern ConVar* single_frame_shutdown_for_reload; extern ConVar* old_gather_props; +extern ConVar* enable_debug_overlays; extern ConVar* staticProp_defaultBuildFrustum; extern ConVar* staticProp_no_fade_scalar; diff --git a/r5dev/vproj/clientsdk.vcxproj b/r5dev/vproj/clientsdk.vcxproj index a81fafeb..5044f214 100644 --- a/r5dev/vproj/clientsdk.vcxproj +++ b/r5dev/vproj/clientsdk.vcxproj @@ -32,6 +32,7 @@ + diff --git a/r5dev/vproj/clientsdk.vcxproj.filters b/r5dev/vproj/clientsdk.vcxproj.filters index 09db07e5..fca17929 100644 --- a/r5dev/vproj/clientsdk.vcxproj.filters +++ b/r5dev/vproj/clientsdk.vcxproj.filters @@ -507,6 +507,9 @@ sdk\mathlib + + sdk\engine + diff --git a/r5dev/vproj/gamesdk.vcxproj b/r5dev/vproj/gamesdk.vcxproj index 96922216..80060b67 100644 --- a/r5dev/vproj/gamesdk.vcxproj +++ b/r5dev/vproj/gamesdk.vcxproj @@ -32,6 +32,7 @@ + diff --git a/r5dev/vproj/gamesdk.vcxproj.filters b/r5dev/vproj/gamesdk.vcxproj.filters index 9c7830a7..f45143bd 100644 --- a/r5dev/vproj/gamesdk.vcxproj.filters +++ b/r5dev/vproj/gamesdk.vcxproj.filters @@ -537,6 +537,9 @@ sdk\mathlib + + sdk\engine +