Fix printing to demo console on CS:S linux

This is getting rediculous.
Our own native calls IClient::ClientPrintf to print stuff to the demo
console.
The engine's Host_Client_Printf uses the CGameClient vtable's
ClientPrintf. To catch the output of the "status" command, we have to
hook both vtables on linux...
Windows casts to IClient in Host_Client_Printf, so no need to do that
there.
This commit is contained in:
Peace-Maker 2016-03-14 18:47:20 +01:00
parent 7b8f2a73f8
commit 9ae2431375
3 changed files with 74 additions and 12 deletions

View File

@ -11,6 +11,13 @@ SH_DECL_MANUALHOOK0_void(CHLTVServer_Shutdown, 0, 0, 0);
// Stuff to print to demo console
SH_DECL_HOOK0_void_vafmt(IClient, ClientPrintf, SH_NOATTRIB, 0);
// Linux has the ClientPrintf method in both CGameClient and IClient's vtables
// and uses both.. Need to hook both....... i guess?
#ifndef WIN32
SH_DECL_MANUALHOOK0_void_vafmt(CGameClient_ClientPrintf, 0, 0, 0);
#endif
// This should be large enough.
#define FAKE_VTBL_LENGTH 70
static void *FakeNetChanVtbl[FAKE_VTBL_LENGTH];
@ -107,8 +114,14 @@ void HLTVServerWrapper::Hook()
SH_ADD_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand), false);
SH_ADD_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand_Post), true);
#if SOURCE_ENGINE != SE_CSGO
SH_ADD_HOOK(IClient, ClientPrintf, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotClientPrintf_Post), false);
#endif
SH_ADD_HOOK(IClient, ClientPrintf, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnIClient_ClientPrintf_Post), false);
#ifndef WIN32
// The IClient vtable is +4 from the CBaseClient vtable due to multiple inheritance.
void *pGameClient = (void *)((intptr_t)pClient - 4);
if (g_HLTVServers.HasClientPrintfOffset())
SH_ADD_MANUALHOOK(CGameClient_ClientPrintf, pGameClient, SH_MEMBER(this, &HLTVServerWrapper::OnCGameClient_ClientPrintf_Post), false);
#endif // !WIN32
#endif // SOURCE_ENGINE != SE_CSGO
}
}
}
@ -133,8 +146,14 @@ void HLTVServerWrapper::Unhook()
SH_REMOVE_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand), false);
SH_REMOVE_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand_Post), true);
#if SOURCE_ENGINE != SE_CSGO
SH_REMOVE_HOOK(IClient, ClientPrintf, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotClientPrintf_Post), false);
#endif
SH_REMOVE_HOOK(IClient, ClientPrintf, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnIClient_ClientPrintf_Post), false);
#ifndef WIN32
// The IClient vtable is +4 from the CBaseClient vtable due to multiple inheritance.
void *pGameClient = (void *)((intptr_t)pClient - 4);
if (g_HLTVServers.HasClientPrintfOffset())
SH_REMOVE_MANUALHOOK(CGameClient_ClientPrintf, pGameClient, SH_MEMBER(this, &HLTVServerWrapper::OnCGameClient_ClientPrintf_Post), false);
#endif // !WIN32
#endif // SOURCE_ENGINE != SE_CSGO
}
}
}
@ -190,19 +209,38 @@ bool HLTVServerWrapper::OnHLTVBotExecuteStringCommand_Post(const char *s)
}
#if SOURCE_ENGINE != SE_CSGO
void HLTVServerWrapper::OnHLTVBotClientPrintf_Post(const char* buf)
void HLTVServerWrapper::OnCGameClient_ClientPrintf_Post(const char* buf)
{
void *pGameClient = META_IFACEPTR(void);
IClient *pClient = (IClient *)((intptr_t)pGameClient + 4);
HandleClientPrintf(pClient, buf);
RETURN_META(MRES_IGNORED);
}
void HLTVServerWrapper::OnIClient_ClientPrintf_Post(const char* buf)
{
IClient *pClient = META_IFACEPTR(IClient);
HandleClientPrintf(pClient, buf);
RETURN_META(MRES_IGNORED);
}
void HLTVServerWrapper::HandleClientPrintf(IClient *pClient, const char* buf)
{
// Craft our own "NetChan" pointer
static int offset = -1;
if (!g_pGameConf->GetOffset("CBaseClient::m_NetChannel", &offset) || offset == -1)
{
smutils->LogError(myself, "Failed to find CBaseClient::m_NetChannel offset. Can't print to demo console.");
RETURN_META(MRES_IGNORED);
return;
}
IClient *pClient = META_IFACEPTR(IClient);
#ifdef WIN32
void *pNetChannel = (void *)((char *)pClient + offset);
#else
void *pNetChannel = (void *)((char *)pClient + offset - 4);
#endif
// Set our fake netchannel
*(void **)pNetChannel = &FakeNetChan;
// Call ClientPrintf again, this time with a "Netchannel" set on the bot.
@ -210,8 +248,6 @@ void HLTVServerWrapper::OnHLTVBotClientPrintf_Post(const char* buf)
SH_CALL(pClient, &IClient::ClientPrintf)("%s", buf);
// Set the fake netchannel back to 0.
*(void **)pNetChannel = nullptr;
RETURN_META(MRES_IGNORED);
}
#endif
@ -232,6 +268,18 @@ void HLTVServerWrapperManager::InitHooks()
}
#if SOURCE_ENGINE != SE_CSGO
#ifndef WIN32
if (g_pGameConf->GetOffset("CGameClient::ClientPrintf", &offset))
{
SH_MANUALHOOK_RECONFIGURE(CGameClient_ClientPrintf, offset, 0, 0);
m_bHasClientPrintfOffset = true;
}
else
{
smutils->LogError(myself, "Failed to find CGameClient::ClientPrintf offset. Won't catch \"status\" console output.");
}
#endif // !WIN32
if (g_pGameConf->GetOffset("CNetChan::SendNetMsg", &offset))
{
if (offset >= FAKE_VTBL_LENGTH)
@ -390,6 +438,11 @@ bool HLTVServerWrapperManager::HasShutdownOffset()
return m_bHasShutdownOffset;
}
bool HLTVServerWrapperManager::HasClientPrintfOffset()
{
return m_bHasClientPrintfOffset;
}
#if SOURCE_ENGINE != SE_CSGO
bool HLTVServerWrapperManager::OnHLTVBotNetChanSendNetMsg(INetMessage &msg, bool bForceReliable, bool bVoice)
{

View File

@ -57,7 +57,9 @@ private:
void OnHLTVServerShutdown();
#if SOURCE_ENGINE != SE_CSGO
void OnHLTVBotClientPrintf_Post(const char *buf);
void OnIClient_ClientPrintf_Post(const char *buf);
void OnCGameClient_ClientPrintf_Post(const char *buf);
void HandleClientPrintf(IClient *pClient, const char* buf);
#endif
private:
@ -80,6 +82,7 @@ public:
int GetInstanceNumber(IHLTVServer *hltvserver);
IDemoRecorder *GetDemoRecorderPtr(IHLTVServer *hltv);
bool HasClientPrintfOffset();
bool HasShutdownOffset();
#if SOURCE_ENGINE != SE_CSGO
@ -90,6 +93,7 @@ private:
#if SOURCE_ENGINE != SE_CSGO
bool m_bSendNetMsgHooked = false;
#endif
bool m_bHasClientPrintfOffset = false;
bool m_bHasShutdownOffset = false;
ke::Vector<ke::AutoPtr<HLTVServerWrapper>> m_HLTVServers;
};

View File

@ -174,7 +174,12 @@
"CBaseClient::m_NetChannel"
{
"windows" "192"
"linux" "164"
"linux" "196"
}
"CGameClient::ClientPrintf"
{
"linux" "24"
}
"CBaseServer::BroadcastPrintf"