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 // Stuff to print to demo console
SH_DECL_HOOK0_void_vafmt(IClient, ClientPrintf, SH_NOATTRIB, 0); 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. // This should be large enough.
#define FAKE_VTBL_LENGTH 70 #define FAKE_VTBL_LENGTH 70
static void *FakeNetChanVtbl[FAKE_VTBL_LENGTH]; 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), false);
SH_ADD_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand_Post), true); SH_ADD_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand_Post), true);
#if SOURCE_ENGINE != SE_CSGO #if SOURCE_ENGINE != SE_CSGO
SH_ADD_HOOK(IClient, ClientPrintf, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotClientPrintf_Post), false); SH_ADD_HOOK(IClient, ClientPrintf, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnIClient_ClientPrintf_Post), false);
#endif #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), false);
SH_REMOVE_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand_Post), true); SH_REMOVE_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand_Post), true);
#if SOURCE_ENGINE != SE_CSGO #if SOURCE_ENGINE != SE_CSGO
SH_REMOVE_HOOK(IClient, ClientPrintf, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotClientPrintf_Post), false); SH_REMOVE_HOOK(IClient, ClientPrintf, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnIClient_ClientPrintf_Post), false);
#endif #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 #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 // Craft our own "NetChan" pointer
static int offset = -1; static int offset = -1;
if (!g_pGameConf->GetOffset("CBaseClient::m_NetChannel", &offset) || 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."); 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); void *pNetChannel = (void *)((char *)pClient + offset);
#else
void *pNetChannel = (void *)((char *)pClient + offset - 4);
#endif
// Set our fake netchannel // Set our fake netchannel
*(void **)pNetChannel = &FakeNetChan; *(void **)pNetChannel = &FakeNetChan;
// Call ClientPrintf again, this time with a "Netchannel" set on the bot. // 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); SH_CALL(pClient, &IClient::ClientPrintf)("%s", buf);
// Set the fake netchannel back to 0. // Set the fake netchannel back to 0.
*(void **)pNetChannel = nullptr; *(void **)pNetChannel = nullptr;
RETURN_META(MRES_IGNORED);
} }
#endif #endif
@ -232,6 +268,18 @@ void HLTVServerWrapperManager::InitHooks()
} }
#if SOURCE_ENGINE != SE_CSGO #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 (g_pGameConf->GetOffset("CNetChan::SendNetMsg", &offset))
{ {
if (offset >= FAKE_VTBL_LENGTH) if (offset >= FAKE_VTBL_LENGTH)
@ -390,6 +438,11 @@ bool HLTVServerWrapperManager::HasShutdownOffset()
return m_bHasShutdownOffset; return m_bHasShutdownOffset;
} }
bool HLTVServerWrapperManager::HasClientPrintfOffset()
{
return m_bHasClientPrintfOffset;
}
#if SOURCE_ENGINE != SE_CSGO #if SOURCE_ENGINE != SE_CSGO
bool HLTVServerWrapperManager::OnHLTVBotNetChanSendNetMsg(INetMessage &msg, bool bForceReliable, bool bVoice) bool HLTVServerWrapperManager::OnHLTVBotNetChanSendNetMsg(INetMessage &msg, bool bForceReliable, bool bVoice)
{ {

View File

@ -57,7 +57,9 @@ private:
void OnHLTVServerShutdown(); void OnHLTVServerShutdown();
#if SOURCE_ENGINE != SE_CSGO #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 #endif
private: private:
@ -80,6 +82,7 @@ public:
int GetInstanceNumber(IHLTVServer *hltvserver); int GetInstanceNumber(IHLTVServer *hltvserver);
IDemoRecorder *GetDemoRecorderPtr(IHLTVServer *hltv); IDemoRecorder *GetDemoRecorderPtr(IHLTVServer *hltv);
bool HasClientPrintfOffset();
bool HasShutdownOffset(); bool HasShutdownOffset();
#if SOURCE_ENGINE != SE_CSGO #if SOURCE_ENGINE != SE_CSGO
@ -90,6 +93,7 @@ private:
#if SOURCE_ENGINE != SE_CSGO #if SOURCE_ENGINE != SE_CSGO
bool m_bSendNetMsgHooked = false; bool m_bSendNetMsgHooked = false;
#endif #endif
bool m_bHasClientPrintfOffset = false;
bool m_bHasShutdownOffset = false; bool m_bHasShutdownOffset = false;
ke::Vector<ke::AutoPtr<HLTVServerWrapper>> m_HLTVServers; ke::Vector<ke::AutoPtr<HLTVServerWrapper>> m_HLTVServers;
}; };

View File

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