Clean up some SDK calls to use SourceHook directly

Don't use IBinTools to call virtual functions. We're in C++! Use
SourceHook right away. This reduces in less and readable code.
This commit is contained in:
Peace-Maker 2016-03-03 09:13:59 +01:00
parent 7dd6897067
commit 4d62d77e55
5 changed files with 89 additions and 142 deletions

View File

@ -31,6 +31,7 @@
#include "extension.h" #include "extension.h"
#include "forwards.h" #include "forwards.h"
#include "natives.h"
IHLTVDirector *hltvdirector = nullptr; IHLTVDirector *hltvdirector = nullptr;
IHLTVServer *hltvserver = nullptr; IHLTVServer *hltvserver = nullptr;
@ -152,6 +153,7 @@ void SourceTVManager::SDK_OnAllLoaded()
SM_GET_LATE_IFACE(SDKTOOLS, sdktools); SM_GET_LATE_IFACE(SDKTOOLS, sdktools);
g_pSTVForwards.Init(); g_pSTVForwards.Init();
SetupNativeCalls();
iserver = sdktools->GetIServer(); iserver = sdktools->GetIServer();
if (!iserver) if (!iserver)
@ -396,6 +398,16 @@ void SourceTVManager::OnSetHLTVServer_Post(IHLTVServer *hltv)
} }
#endif #endif
// When bots issue a command that would print stuff to their console,
// the server might crash, because ExecuteStringCommand doesn't set the
// global host_client pointer to the client on whom the command is run.
// Host_Client_Printf blatantly tries to call host_client->ClientPrintf
// while the pointer might point to some other player or garbage.
// This leads to e.g. the output of the "status" command not being
// recorded in the SourceTV demo.
// The approach here is to set host_client correctly for the SourceTV
// bot and reset it to the old value after command execution.
bool SourceTVManager::OnHLTVBotExecuteStringCommand(const char *s) bool SourceTVManager::OnHLTVBotExecuteStringCommand(const char *s)
{ {
if (!hltvserver || !iserver || !host_client) if (!hltvserver || !iserver || !host_client)

View File

@ -43,9 +43,11 @@ SH_DECL_HOOK0_void(IDemoRecorder, StopRecording, SH_NOATTRIB, 0)
#if SOURCE_ENGINE == SE_CSGO #if SOURCE_ENGINE == SE_CSGO
SH_DECL_MANUALHOOK13(CHLTVServer_ConnectClient, 0, 0, 0, IClient *, const netadr_t &, int, int, int, const char *, const char *, const char *, int, CUtlVector<NetMsg_SplitPlayerConnect *> &, bool, CrossPlayPlatform_t, const unsigned char *, int); SH_DECL_MANUALHOOK13(CHLTVServer_ConnectClient, 0, 0, 0, IClient *, const netadr_t &, int, int, int, const char *, const char *, const char *, int, CUtlVector<NetMsg_SplitPlayerConnect *> &, bool, CrossPlayPlatform_t, const unsigned char *, int);
SH_DECL_MANUALHOOK1_void_vafmt(CHLTVServer_RejectConnection, 0, 0, 0, const netadr_t &);
SH_DECL_HOOK1_void(IClient, Disconnect, SH_NOATTRIB, 0, const char *); SH_DECL_HOOK1_void(IClient, Disconnect, SH_NOATTRIB, 0, const char *);
#else #else
SH_DECL_MANUALHOOK9(CHLTVServer_ConnectClient, 0, 0, 0, IClient *, netadr_t &, int, int, int, int, const char *, const char *, const char *, int); SH_DECL_MANUALHOOK9(CHLTVServer_ConnectClient, 0, 0, 0, IClient *, netadr_t &, int, int, int, int, const char *, const char *, const char *, int);
SH_DECL_MANUALHOOK3_void(CHLTVServer_RejectConnection, 0, 0, 0, const netadr_t &, int, const char *);
SH_DECL_HOOK0_void_vafmt(IClient, Disconnect, SH_NOATTRIB, 0); SH_DECL_HOOK0_void_vafmt(IClient, Disconnect, SH_NOATTRIB, 0);
#endif #endif
SH_DECL_MANUALHOOK0_void(CBaseClient_ActivatePlayer, 0, 0, 0); SH_DECL_MANUALHOOK0_void(CBaseClient_ActivatePlayer, 0, 0, 0);
@ -65,6 +67,16 @@ void CForwardManager::Init()
m_bHasClientConnectOffset = true; m_bHasClientConnectOffset = true;
} }
if (!g_pGameConf->GetOffset("CHLTVServer::RejectConnection", &offset) || offset == -1)
{
smutils->LogError(myself, "Failed to get CHLTVServer::RejectConnection offset.");
}
else
{
SH_MANUALHOOK_RECONFIGURE(CHLTVServer_RejectConnection, offset, 0, 0);
m_bHasRejectConnectionOffset = true;
}
if (!g_pGameConf->GetOffset("CHLTVServer::GetChallengeType", &offset) || offset == -1) if (!g_pGameConf->GetOffset("CHLTVServer::GetChallengeType", &offset) || offset == -1)
{ {
smutils->LogError(myself, "Failed to get CHLTVServer::GetChallengeType offset."); smutils->LogError(myself, "Failed to get CHLTVServer::GetChallengeType offset.");
@ -177,59 +189,6 @@ void CForwardManager::UnhookClient(IClient *client)
} }
#if SOURCE_ENGINE == SE_CSGO #if SOURCE_ENGINE == SE_CSGO
// CBaseServer::RejectConnection(ns_address const&, char const*, ...)
static void RejectConnection(IServer *server, const netadr_t &address, const char *pchReason)
{
static ICallWrapper *pRejectConnection = nullptr;
if (!pRejectConnection)
{
int offset = -1;
if (!g_pGameConf->GetOffset("CHLTVServer::RejectConnection", &offset) || offset == -1)
{
smutils->LogError(myself, "Failed to get CHLTVServer::RejectConnection offset.");
return;
}
PassInfo pass[4];
pass[0].flags = PASSFLAG_BYVAL;
pass[0].type = PassType_Basic;
pass[0].size = sizeof(void *);
pass[1].flags = PASSFLAG_BYVAL;
pass[1].type = PassType_Basic;
pass[1].size = sizeof(void *);
pass[2].flags = PASSFLAG_BYVAL;
pass[2].type = PassType_Basic;
pass[2].size = sizeof(char *);
pass[3].flags = PASSFLAG_BYVAL;
pass[3].type = PassType_Basic;
pass[3].size = sizeof(char *);
void **vtable = *(void ***)server;
void *func = vtable[offset];
pRejectConnection = bintools->CreateCall(func, CallConv_Cdecl, NULL, pass, 4);
}
static char fmt[] = "%s";
if (pRejectConnection)
{
unsigned char vstk[sizeof(void *) * 2 + sizeof(char *) * 2];
unsigned char *vptr = vstk;
*(void **)vptr = (void *)server;
vptr += sizeof(void *);
*(void **)vptr = (void *)&address;
vptr += sizeof(void *);
*(char **)vptr = fmt;
vptr += sizeof(char *);
*(const char **)vptr = pchReason;
pRejectConnection->Execute(vstk, NULL);
}
}
static bool ExtractPlayerName(CUtlVector<NetMsg_SplitPlayerConnect *> &pSplitPlayerConnectVector, char *name, int maxlen) static bool ExtractPlayerName(CUtlVector<NetMsg_SplitPlayerConnect *> &pSplitPlayerConnectVector, char *name, int maxlen)
{ {
for (int i = 0; i < pSplitPlayerConnectVector.Count(); i++) for (int i = 0; i < pSplitPlayerConnectVector.Count(); i++)
@ -254,50 +213,6 @@ static bool ExtractPlayerName(CUtlVector<NetMsg_SplitPlayerConnect *> &pSplitPla
} }
return false; return false;
} }
#else
static void RejectConnection(IServer *server, netadr_t &address, int iClientChallenge, char *pchReason)
{
static ICallWrapper *pRejectConnection = nullptr;
if (!pRejectConnection)
{
int offset = -1;
if (!g_pGameConf->GetOffset("CHLTVServer::RejectConnection", &offset) || offset == -1)
{
smutils->LogError(myself, "Failed to get CHLTVServer::RejectConnection offset.");
return;
}
PassInfo pass[3];
pass[0].flags = PASSFLAG_BYVAL;
pass[0].type = PassType_Basic;
pass[0].size = sizeof(netadr_t *);
pass[1].flags = PASSFLAG_BYVAL;
pass[1].type = PassType_Basic;
pass[1].size = sizeof(int);
pass[2].flags = PASSFLAG_BYVAL;
pass[2].type = PassType_Basic;
pass[2].size = sizeof(char *);
pRejectConnection = bintools->CreateVCall(offset, 0, 0, NULL, pass, 3);
}
if (pRejectConnection)
{
unsigned char vstk[sizeof(void *) + sizeof(netadr_t *) + sizeof(int) + sizeof(char *)];
unsigned char *vptr = vstk;
*(void **)vptr = (void *)server;
vptr += sizeof(void *);
*(netadr_t **)vptr = &address;
vptr += sizeof(netadr_t *);
*(int *)vptr = iClientChallenge;
vptr += sizeof(int);
*(char **)vptr = pchReason;
pRejectConnection->Execute(vstk, NULL);
}
}
#endif #endif
// Mimic Connect extension https://forums.alliedmods.net/showthread.php?t=162489 // Mimic Connect extension https://forums.alliedmods.net/showthread.php?t=162489
@ -340,11 +255,14 @@ IClient *CForwardManager::OnSpectatorConnect(netadr_t & address, int nProtocol,
IServer *server = META_IFACEPTR(IServer); IServer *server = META_IFACEPTR(IServer);
if (retVal == 0) if (retVal == 0)
{ {
if (m_bHasRejectConnectionOffset)
{
#if SOURCE_ENGINE == SE_CSGO #if SOURCE_ENGINE == SE_CSGO
RejectConnection(server, address, rejectReason); SH_MCALL(server, CHLTVServer_RejectConnection)(address, rejectReason);
#else #else
RejectConnection(server, address, iClientChallenge, rejectReason); SH_MCALL(server, CHLTVServer_RejectConnection)(address, iClientChallenge, rejectReason);
#endif #endif
}
RETURN_META_VALUE(MRES_SUPERCEDE, nullptr); RETURN_META_VALUE(MRES_SUPERCEDE, nullptr);
} }

View File

@ -98,6 +98,7 @@ private:
IForward *m_SpectatorPutInServerFwd; IForward *m_SpectatorPutInServerFwd;
bool m_bHasClientConnectOffset = false; bool m_bHasClientConnectOffset = false;
bool m_bHasRejectConnectionOffset = false;
bool m_bHasGetChallengeTypeOffset = false; bool m_bHasGetChallengeTypeOffset = false;
bool m_bHasActivatePlayerOffset = false; bool m_bHasActivatePlayerOffset = false;
}; };

View File

@ -30,12 +30,31 @@
*/ */
#include "extension.h" #include "extension.h"
#include "natives.h"
#define TICK_INTERVAL (gpGlobals->interval_per_tick) #define TICK_INTERVAL (gpGlobals->interval_per_tick)
#define TIME_TO_TICKS( dt ) ( (int)( 0.5f + (float)(dt) / TICK_INTERVAL ) ) #define TIME_TO_TICKS( dt ) ( (int)( 0.5f + (float)(dt) / TICK_INTERVAL ) )
extern const sp_nativeinfo_t sourcetv_natives[]; extern const sp_nativeinfo_t sourcetv_natives[];
SH_DECL_MANUALHOOK0_void_vafmt(CBaseServer_BroadcastPrintf, 0, 0, 0);
bool g_bHasClientPrintfOffset = false;
void SetupNativeCalls()
{
int offset = -1;
if (!g_pGameConf->GetOffset("CBaseServer::BroadcastPrintf", &offset) || offset == -1)
{
smutils->LogError(myself, "Failed to get CBaseServer::BroadcastPrintf offset.");
}
else
{
SH_MANUALHOOK_RECONFIGURE(CBaseServer_BroadcastPrintf, offset, 0, 0);
g_bHasClientPrintfOffset = true;
}
}
// native SourceTV_GetServerInstanceCount(); // native SourceTV_GetServerInstanceCount();
static cell_t Native_GetServerInstanceCount(IPluginContext *pContext, const cell_t *params) static cell_t Native_GetServerInstanceCount(IPluginContext *pContext, const cell_t *params)
{ {
@ -238,34 +257,8 @@ static cell_t Native_BroadcastConsoleMessage(IPluginContext *pContext, const cel
if (hltvserver == nullptr) if (hltvserver == nullptr)
return 0; return 0;
static ICallWrapper *pBroadcastPrintf = nullptr; if (!g_bHasClientPrintfOffset)
return 0;
if (!pBroadcastPrintf)
{
int offset = -1;
if (!g_pGameConf->GetOffset("CBaseServer::BroadcastPrintf", &offset) || offset == -1)
{
pContext->ReportError("Failed to get CBaseServer::BroadcastPrintf offset.");
return 0;
}
PassInfo pass[3];
pass[0].flags = PASSFLAG_BYVAL;
pass[0].type = PassType_Basic;
pass[0].size = sizeof(void *);
pass[1].flags = PASSFLAG_BYVAL;
pass[1].type = PassType_Basic;
pass[1].size = sizeof(char *);
pass[2].flags = PASSFLAG_BYVAL;
pass[2].type = PassType_Basic;
pass[2].size = sizeof(char *);
void *iserver = (void *)hltvserver->GetBaseServer();
void **vtable = *(void ***)iserver;
void *func = vtable[offset];
pBroadcastPrintf = bintools->CreateCall(func, CallConv_Cdecl, NULL, pass, 3);
}
char buffer[1024]; char buffer[1024];
size_t len; size_t len;
@ -276,21 +269,7 @@ static cell_t Native_BroadcastConsoleMessage(IPluginContext *pContext, const cel
return 0; return 0;
} }
static char fmt[] = "%s\n"; SH_MCALL(hltvserver->GetBaseServer(), CBaseServer_BroadcastPrintf)("%s\n", buffer);
if (pBroadcastPrintf)
{
unsigned char vstk[sizeof(void *) + sizeof(char *) * 2];
unsigned char *vptr = vstk;
*(void **)vptr = (void *)hltvserver->GetBaseServer();
vptr += sizeof(void *);
*(char **)vptr = fmt;
vptr += sizeof(char *);
*(char **)vptr = buffer;
pBroadcastPrintf->Execute(vstk, NULL);
}
return 1; return 1;
} }

37
natives.h Normal file
View File

@ -0,0 +1,37 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod SourceTV Manager Extension
* Copyright (C) 2004-2016 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_NATIVES_H_
#define _INCLUDE_SOURCEMOD_EXTENSION_NATIVES_H_
void SetupNativeCalls();
#endif // _INCLUDE_SOURCEMOD_EXTENSION_NATIVES_H_