Skip to content

Commit

Permalink
Fix layout for CZDS worldmap.
Browse files Browse the repository at this point in the history
  • Loading branch information
hzqst committed Oct 14, 2024
1 parent ad96e32 commit e60add3
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 24 deletions.
191 changes: 189 additions & 2 deletions Plugins/VGUI2Extension/ClientVGUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ IClientVGUI* g_pClientVGUI = NULL;
CounterStrikeViewport* g_pCounterStrikeViewport = NULL;

static vgui::Panel* g_pCSBackGroundPanel = NULL;
static vgui::Panel* g_pWorldMapPanel = NULL;
static vgui::Panel* g_pWorldMapMissionSelectPanel = NULL;

static hook_t* g_phook_ClientVGUI_Panel_Init = NULL;
static hook_t* g_phook_ClientVGUI_KeyValues_LoadFromFile = NULL;
Expand Down Expand Up @@ -290,6 +292,65 @@ bool VGUI2_IsCSBackGroundPanelActivate(PVOID Candidate, int *pOffsetBase)
return false;
}

typedef struct
{
bool bFoundCall80h;
int iFoundPush255Count;
void* SurfaceGetScreenSize;
}VGUI2_IsCWorldMapPaintBackground_SearchContext;

bool VGUI2_IsCWorldMapPaintBackground(PVOID Candidate, void ** pSurfaceGetScreenSize)
{
VGUI2_IsCWorldMapPaintBackground_SearchContext ctx = { 0 };

g_pMetaHookAPI->DisasmRanges(Candidate, 0x500, [](void* inst, PUCHAR address, size_t instLen, int instCount, int depth, PVOID context) {
auto pinst = (cs_insn*)inst;
auto ctx = (VGUI2_IsCWorldMapPaintBackground_SearchContext*)context;

if (!ctx->bFoundCall80h &&
pinst->id == X86_INS_CALL &&
pinst->detail->x86.op_count == 1 &&
pinst->detail->x86.operands[0].type == X86_OP_MEM &&
pinst->detail->x86.operands[0].mem.base != 0 &&
pinst->detail->x86.operands[0].mem.disp == 0x80)
{
ctx->bFoundCall80h = true;
ctx->SurfaceGetScreenSize = address;
}

if (ctx->iFoundPush255Count < 4 &&
pinst->id == X86_INS_PUSH &&
pinst->detail->x86.op_count == 1 &&
pinst->detail->x86.operands[0].type == X86_OP_IMM &&
pinst->detail->x86.operands[0].imm == 0xFF)
{
ctx->iFoundPush255Count ++;
}

if (ctx->bFoundCall80h && ctx->iFoundPush255Count >= 4)
return TRUE;

if (address[0] == 0xCC)
return TRUE;

if (pinst->id == X86_INS_RET)
return TRUE;

return FALSE;

}, 0, &ctx);

if (ctx.bFoundCall80h && ctx.iFoundPush255Count >= 4)
{
if (pSurfaceGetScreenSize)
(*pSurfaceGetScreenSize) = ctx.SurfaceGetScreenSize;

return true;
}

return false;
}

typedef struct
{
PVOID CallCandidates[4];
Expand Down Expand Up @@ -535,6 +596,26 @@ void ClientVGUI_KeyValues_LoadFromFile_CounterStrike(KeyValues* pthis, const cha
}
}

void ClientVGUI_KeyValues_LoadFromFile_CZDS(KeyValues* pthis, const char* resourceName, const char* pathId)
{
if (!strcmp(resourceName, "resource/UI/WorldMap.res"))
{
auto pWorldMap = pthis->FindKey("WorldMap");

if (pWorldMap)
{
ClientVGUI_KeyValues_FitToFullScreen(pWorldMap);
}

auto pMissionSelect = pthis->FindKey("MissionSelect");

if (pMissionSelect)
{
ClientVGUI_KeyValues_FitToFullScreen(pMissionSelect);
}
}
}

void __fastcall CCSBackGroundPanel_Activate(vgui::Panel* pthis, int dummy)
{
gPrivateFuncs.CCSBackGroundPanel_Activate(pthis, dummy);
Expand All @@ -546,6 +627,38 @@ void __fastcall CCSBackGroundPanel_Activate(vgui::Panel* pthis, int dummy)
}
}

void __fastcall CWorldMap_PaintBackground_SurfaceGetScreenSize(vgui::ISurface *pthis, int dummy, int& screenWide, int& screenTall)
{
//xScale = swide / 640.0;
//yScale = stall / 480.0;

//Let xScale = yScale
vgui::surface()->GetScreenSize(screenWide, screenTall);

screenWide = (double)screenTall * 640.0 / 480.0;
}

void __fastcall CWorldMap_PaintBackground(vgui::Panel* pthis, int dummy)
{
gPrivateFuncs.CWorldMap_PaintBackground(pthis, dummy);
}

void __fastcall CWorldMapMissionSelect_PaintBackground_SurfaceGetScreenSize(vgui::ISurface *pthis, int dummy, int& screenWide, int& screenTall)
{
//xScale = swide / 640.0;
//yScale = stall / 480.0;

//Let xScale = yScale
vgui::surface()->GetScreenSize(screenWide, screenTall);

screenWide = (double)screenTall * 640.0 / 480.0;
}

void __fastcall CWorldMapMissionSelect_PaintBackground(vgui::Panel* pthis, int dummy)
{
gPrivateFuncs.CWorldMapMissionSelect_PaintBackground(pthis, dummy);
}

#if 0
void ResizeWindowControls(vgui::Panel* pWindow, int offsetX, int offsetY)
{
Expand Down Expand Up @@ -704,9 +817,13 @@ bool __fastcall ClientVGUI_KeyValues_LoadFromFile(void* pthis, int dummy, IFileS
}
}

if (ret && g_bIsCounterStrike)
if (ret)
{
ClientVGUI_KeyValues_LoadFromFile_CounterStrike((KeyValues *)pthis, resourceName, pathId);
if (g_bIsCounterStrike)
ClientVGUI_KeyValues_LoadFromFile_CounterStrike((KeyValues *)pthis, resourceName, pathId);

if (g_bIsCZDS)
ClientVGUI_KeyValues_LoadFromFile_CZDS((KeyValues*)pthis, resourceName, pathId);
}

return ret;
Expand Down Expand Up @@ -788,9 +905,79 @@ void CClientVGUIProxy::Start(void)
break;
}
}

Sig_FuncNotFound(CCSBackGroundPanel_Activate);
}

if (g_bIsCZDS)
{
int offset_WorldMapPanel = 0x7A8;

g_pWorldMapPanel = *(vgui::Panel**)((PUCHAR)this + offset_WorldMapPanel);

gPrivateFuncs.CWorldMap_vftable = *(PVOID**)g_pWorldMapPanel;

if (
!((ULONG_PTR)gPrivateFuncs.CWorldMap_vftable > (ULONG_PTR)g_dwClientBase &&
(ULONG_PTR)gPrivateFuncs.CWorldMap_vftable < (ULONG_PTR)g_dwClientBase + g_dwClientSize))
{
Sig_NotFound("CWorldMap");
}

for (int index = 105; index <= 106; ++index)
{
PVOID SurfaceGetScreenSize = NULL;
if (VGUI2_IsCWorldMapPaintBackground(gPrivateFuncs.CWorldMap_vftable[index], &SurfaceGetScreenSize))
{
if (!SurfaceGetScreenSize)
{
Sig_NotFound("CWorldMap_PaintBackground_SurfaceGetScreenSize");
}
g_pMetaHookAPI->InlinePatchRedirectBranch(SurfaceGetScreenSize, CWorldMap_PaintBackground_SurfaceGetScreenSize, NULL);

gPrivateFuncs.CWorldMap_PaintBackground_vftable_index = index;
//g_pMetaHookAPI->VFTHook(g_pWorldMapPanel, 0, index, CWorldMap_PaintBackground, (void**)&gPrivateFuncs.CWorldMap_PaintBackground);
break;
}
}
}

if (g_bIsCZDS)
{
g_pWorldMapMissionSelectPanel = g_pWorldMapPanel->FindChildByName("MissionSelect");

if (!g_pWorldMapMissionSelectPanel)
{
Sig_NotFound("WorldMapMissionSelectPanel");
}

gPrivateFuncs.CWorldMapMissionSelect_vftable = *(PVOID**)g_pWorldMapMissionSelectPanel;

if (
!((ULONG_PTR)gPrivateFuncs.CWorldMapMissionSelect_vftable > (ULONG_PTR)g_dwClientBase &&
(ULONG_PTR)gPrivateFuncs.CWorldMapMissionSelect_vftable < (ULONG_PTR)g_dwClientBase + g_dwClientSize))
{
Sig_NotFound("CWorldMapMissionSelect_vftable");
}

for (int index = 105; index <= 106; ++index)
{
PVOID SurfaceGetScreenSize = NULL;
if (VGUI2_IsCWorldMapPaintBackground(gPrivateFuncs.CWorldMapMissionSelect_vftable[index], &SurfaceGetScreenSize))
{
if (!SurfaceGetScreenSize)
{
Sig_NotFound("CWorldMapMissionSelect_PaintBackground_SurfaceGetScreenSize");
}
g_pMetaHookAPI->InlinePatchRedirectBranch(SurfaceGetScreenSize, CWorldMapMissionSelect_PaintBackground_SurfaceGetScreenSize, NULL);

gPrivateFuncs.CWorldMapMissionSelect_PaintBackground_vftable_index = index;
//g_pMetaHookAPI->VFTHook(g_pWorldMapMissionSelectPanel, 0, index, CWorldMapMissionSelect_PaintBackground, (void**)&gPrivateFuncs.CWorldMapMissionSelect_PaintBackground);
break;
}
}
}

VGUI2ExtensionInternal()->ClientVGUI_Start();

g_NativeClientHasVGUI1 = UseVGUI1();
Expand Down
8 changes: 8 additions & 0 deletions Plugins/VGUI2Extension/privatefuncs.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ typedef struct
void** CCSBackGroundPanel_vftable;
int CCSBackGroundPanel_XOffsetBase;

int CWorldMap_PaintBackground_vftable_index;
void(__fastcall* CWorldMap_PaintBackground)(void* pthis, int dummy);
void** CWorldMap_vftable;

int CWorldMapMissionSelect_PaintBackground_vftable_index;
void(__fastcall* CWorldMapMissionSelect_PaintBackground)(void* pthis, int dummy);
void** CWorldMapMissionSelect_vftable;

//void* (__fastcall* CClientMOTD_ctor)(void* pthis, int, void* parent);
//void (__fastcall* CClientMOTD_PerformLayout)(void* pthis, int dummy);
//void (__fastcall* CClientMOTD_ApplySettings)(void* pthis, int dummy, void* inResourceData);
Expand Down
68 changes: 46 additions & 22 deletions src/metahook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2495,38 +2495,62 @@ bool MH_IsBogusVFTableEntry(PVOID pVirtualFuncAddr, PVOID pOldFuncAddr)

hook_t* MH_InlinePatchRedirectBranch(void* pInstructionAddress, void* pNewFuncAddr, void** pOrginalCall)
{
auto pSourceCode = (PUCHAR)pInstructionAddress;
typedef struct
{
PUCHAR pSourceCode;
PUCHAR pNewFuncAddr;
ULONG PatchLength;
UCHAR NewCodeBytes[8];
}MH_InlinePatchRedirectBranch_PatchContext;

ULONG PatchLength = 0;
UCHAR NewCodeBytes[8];
MH_InlinePatchRedirectBranch_PatchContext ctx = { 0 };

ctx.pSourceCode = (PUCHAR)pInstructionAddress;
ctx.pNewFuncAddr = (PUCHAR)pNewFuncAddr;
memset(ctx.NewCodeBytes, 0x90, sizeof(ctx.NewCodeBytes));

if (pSourceCode[0] == 0xE9 || pSourceCode[0] == 0xE8)
if (ctx.pSourceCode[0] == 0xE9 || ctx.pSourceCode[0] == 0xE8)
{
PatchLength = 5;
NewCodeBytes[0] = pSourceCode[0];
*(int*)(NewCodeBytes + 1) = (PUCHAR)pNewFuncAddr - ((PUCHAR)pInstructionAddress + 5);
ctx.PatchLength = 5;
ctx.NewCodeBytes[0] = ctx.pSourceCode[0];
*(int*)(ctx.NewCodeBytes + 1) = ctx.pNewFuncAddr - (ctx.pSourceCode + 5);
}
else if (pSourceCode[0] == 0xFF && pSourceCode[1] == 0x15)
else if (ctx.pSourceCode[0] == 0xFF && ctx.pSourceCode[1] == 0x15)
{
//indirect call
PatchLength = 6;
NewCodeBytes[0] = 0xE8;
NewCodeBytes[5] = 0x90;
*(int*)(NewCodeBytes + 1) = (PUCHAR)pNewFuncAddr - ((PUCHAR)pInstructionAddress + 5);
ctx.PatchLength = 6;
ctx.NewCodeBytes[0] = 0xE8;
*(int*)(ctx.NewCodeBytes + 1) = ctx.pNewFuncAddr - (ctx.pSourceCode + 5);
}
else if (pSourceCode[0] == 0xFF && pSourceCode[1] == 0x25)
else if (ctx.pSourceCode[0] == 0xFF && ctx.pSourceCode[1] == 0x25)
{
//indirect jmp
PatchLength = 6;
NewCodeBytes[0] = 0xE9;
NewCodeBytes[5] = 0x90;
*(int*)(NewCodeBytes + 1) = (PUCHAR)pNewFuncAddr - ((PUCHAR)pInstructionAddress + 5);
ctx.PatchLength = 6;
ctx.NewCodeBytes[0] = 0xE9;
*(int*)(ctx.NewCodeBytes + 1) = ctx.pNewFuncAddr - (ctx.pSourceCode + 5);
}
else
{
return NULL;
MH_DisasmSingleInstruction(pInstructionAddress, [](void* inst, PUCHAR address, size_t instLen, PVOID context) {

auto pinst = (cs_insn*)inst;
auto ctx = (MH_InlinePatchRedirectBranch_PatchContext*)context;

if (pinst->id == X86_INS_CALL &&
pinst->detail->x86.op_count == 1 &&
pinst->detail->x86.operands[0].type == X86_OP_MEM && instLen >= 5)
{
ctx->PatchLength = instLen;
ctx->NewCodeBytes[0] = 0xE8;
*(int*)(ctx->NewCodeBytes + 1) = ctx->pNewFuncAddr - (ctx->pSourceCode + 5);
}

}, &ctx);
}

if (!ctx.PatchLength)
return NULL;

hook_t* h = MH_NewHook(MH_HOOK_INLINEPATCH);

if (!h)
Expand All @@ -2538,17 +2562,17 @@ hook_t* MH_InlinePatchRedirectBranch(void* pInstructionAddress, void* pNewFuncAd
h->pNewFuncAddr = pNewFuncAddr;
h->pOrginalCall = pOrginalCall;
h->hookData.inlinepatch.pInstructionAddress = pInstructionAddress;
h->hookData.inlinepatch.PatchLength = PatchLength;
memcpy(h->hookData.inlinepatch.NewCodeBytes, NewCodeBytes, PatchLength);
memcpy(h->hookData.inlinepatch.OriginalBytes, (PUCHAR)pInstructionAddress, PatchLength);
h->hookData.inlinepatch.PatchLength = ctx.PatchLength;
memcpy(h->hookData.inlinepatch.NewCodeBytes, ctx.NewCodeBytes, ctx.PatchLength);
memcpy(h->hookData.inlinepatch.OriginalBytes, (PUCHAR)pInstructionAddress, ctx.PatchLength);

if (g_bTransactionHook)
{
h->bCommitted = false;
}
else
{
MH_WriteMemory(pInstructionAddress, NewCodeBytes, PatchLength);
MH_WriteMemory(pInstructionAddress, ctx.NewCodeBytes, ctx.PatchLength);

if (h->pOrginalCall)
(*h->pOrginalCall) = h->pOldFuncAddr;
Expand Down

0 comments on commit e60add3

Please sign in to comment.