Fix OnStartRecording and OnStopRecording forwards on linux
CHLTVServer::StartRecording is called directly in tv_record on linux, ignoring the vtable. Add a detour on linux for these two functions, so we always notice when recording starts. Windows actually always uses the vtable to get the function address, so we don't need to detour anything on windows.
This commit is contained in:
parent
22c3803718
commit
7c4048690b
@ -36,6 +36,12 @@ for sdk_name in ['css', 'csgo']:
|
||||
binary = Extension.HL2Config(project, projectName + '.ext.' + sdk.ext, sdk)
|
||||
compiler = binary.compiler
|
||||
|
||||
if builder.target_platform == 'linux':
|
||||
binary.sources += [
|
||||
os.path.join(Extension.sm_root, 'public', 'CDetour', 'CDetour.cpp'),
|
||||
os.path.join(Extension.sm_root, 'public', 'asm', 'asm.c')
|
||||
]
|
||||
|
||||
if sdk.name == 'csgo':
|
||||
compiler.cxxincludes += [
|
||||
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
|
||||
|
@ -95,6 +95,10 @@ bool SourceTVManager::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
||||
|
||||
g_HLTVServers.InitHooks();
|
||||
|
||||
#ifndef WIN32
|
||||
CDetourManager::Init(smutils->GetScriptingEngine(), g_pGameConf);
|
||||
#endif
|
||||
|
||||
sharesys->AddNatives(myself, sourcetv_natives);
|
||||
sharesys->RegisterLibrary(myself, "sourcetvmanager");
|
||||
|
||||
|
@ -40,6 +40,9 @@
|
||||
#include "smsdk_ext.h"
|
||||
#include <IBinTools.h>
|
||||
#include <ISDKTools.h>
|
||||
#ifndef WIN32
|
||||
#include "CDetour\detours.h"
|
||||
#endif
|
||||
#include "ihltvdirector.h"
|
||||
#include "ihltv.h"
|
||||
#include "iserver.h"
|
||||
|
138
forwards.cpp
138
forwards.cpp
@ -35,12 +35,15 @@
|
||||
|
||||
CForwardManager g_pSTVForwards;
|
||||
|
||||
// Only windows always uses the vtable for these. Linux does direct calls, so we use detours there.
|
||||
#ifdef WIN32
|
||||
SH_DECL_HOOK2_void(IDemoRecorder, StartRecording, SH_NOATTRIB, 0, const char *, bool)
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
SH_DECL_HOOK1_void(IDemoRecorder, StopRecording, SH_NOATTRIB, 0, CGameInfo const *)
|
||||
#else
|
||||
SH_DECL_HOOK0_void(IDemoRecorder, StopRecording, SH_NOATTRIB, 0)
|
||||
#endif
|
||||
#endif // SOURCE_ENGINE == SE_CSGO
|
||||
#endif // !WIN32
|
||||
|
||||
#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);
|
||||
@ -126,14 +129,18 @@ void CForwardManager::Shutdown()
|
||||
|
||||
void CForwardManager::HookRecorder(IDemoRecorder *recorder)
|
||||
{
|
||||
#ifdef WIN32
|
||||
SH_ADD_HOOK(IDemoRecorder, StartRecording, recorder, SH_MEMBER(this, &CForwardManager::OnStartRecording_Post), true);
|
||||
SH_ADD_HOOK(IDemoRecorder, StopRecording, recorder, SH_MEMBER(this, &CForwardManager::OnStopRecording_Post), true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CForwardManager::UnhookRecorder(IDemoRecorder *recorder)
|
||||
{
|
||||
#ifdef WIN32
|
||||
SH_REMOVE_HOOK(IDemoRecorder, StartRecording, recorder, SH_MEMBER(this, &CForwardManager::OnStartRecording_Post), true);
|
||||
SH_REMOVE_HOOK(IDemoRecorder, StopRecording, recorder, SH_MEMBER(this, &CForwardManager::OnStopRecording_Post), true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CForwardManager::HookServer(HLTVServerWrapper *wrapper)
|
||||
@ -367,21 +374,12 @@ void CForwardManager::OnSpectatorPutInServer()
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
|
||||
// These two hooks are actually only hooked on windows.
|
||||
void CForwardManager::OnStartRecording_Post(const char *filename, bool bContinuously)
|
||||
{
|
||||
if (m_StartRecordingFwd->GetFunctionCount() == 0)
|
||||
RETURN_META(MRES_IGNORED);
|
||||
|
||||
IDemoRecorder *recorder = META_IFACEPTR(IDemoRecorder);
|
||||
HLTVServerWrapper *wrapper = g_HLTVServers.GetWrapper(recorder);
|
||||
int instance = -1;
|
||||
if (wrapper)
|
||||
instance = wrapper->GetInstanceNumber();
|
||||
|
||||
m_StartRecordingFwd->PushCell(instance);
|
||||
m_StartRecordingFwd->PushString(filename);
|
||||
m_StartRecordingFwd->Execute();
|
||||
|
||||
CallOnStartRecording(recorder, filename, bContinuously);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
@ -391,12 +389,33 @@ void CForwardManager::OnStopRecording_Post(CGameInfo const *info)
|
||||
void CForwardManager::OnStopRecording_Post()
|
||||
#endif
|
||||
{
|
||||
if (m_StopRecordingFwd->GetFunctionCount() == 0)
|
||||
RETURN_META(MRES_IGNORED);
|
||||
|
||||
IDemoRecorder *recorder = META_IFACEPTR(IDemoRecorder);
|
||||
CallOnStopRecording(recorder);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void CForwardManager::CallOnStartRecording(IDemoRecorder *recorder, const char *filename, bool bContinuously)
|
||||
{
|
||||
if (m_StartRecordingFwd->GetFunctionCount() == 0)
|
||||
return;
|
||||
|
||||
HLTVServerWrapper *wrapper = g_HLTVServers.GetWrapper(recorder);
|
||||
int instance = -1;
|
||||
if (wrapper)
|
||||
instance = wrapper->GetInstanceNumber();
|
||||
|
||||
m_StartRecordingFwd->PushCell(instance);
|
||||
m_StartRecordingFwd->PushString(filename);
|
||||
m_StartRecordingFwd->Execute();
|
||||
}
|
||||
|
||||
void CForwardManager::CallOnStopRecording(IDemoRecorder *recorder)
|
||||
{
|
||||
if (m_StopRecordingFwd->GetFunctionCount() == 0)
|
||||
return;
|
||||
|
||||
if (!recorder->IsRecording())
|
||||
RETURN_META(MRES_IGNORED);
|
||||
return;
|
||||
|
||||
char *pDemoFile = (char *)recorder->GetDemoFile();
|
||||
|
||||
@ -409,6 +428,87 @@ void CForwardManager::OnStopRecording_Post()
|
||||
m_StopRecordingFwd->PushString(pDemoFile);
|
||||
m_StopRecordingFwd->PushCell(recorder->GetRecordingTick());
|
||||
m_StopRecordingFwd->Execute();
|
||||
}
|
||||
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
// Only need to detour these on Linux. Windows always uses the vtable.
|
||||
#ifndef WIN32
|
||||
DETOUR_DECL_MEMBER2(DetourHLTVStartRecording, void, const char *, filename, bool, bContinuously)
|
||||
{
|
||||
// Call the original first.
|
||||
DETOUR_MEMBER_CALL(DetourHLTVStartRecording)(filename, bContinuously);
|
||||
|
||||
IDemoRecorder *recorder = (IDemoRecorder *)this;
|
||||
g_pSTVForwards.CallOnStartRecording(recorder, filename, bContinuously);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
DETOUR_DECL_MEMBER1(DetourHLTVStopRecording, void, CGameInfo const *, info)
|
||||
#else
|
||||
DETOUR_DECL_MEMBER0(DetourHLTVStopRecording, void)
|
||||
#endif
|
||||
{
|
||||
// Call the original first.
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
DETOUR_MEMBER_CALL(DetourHLTVStopRecording)(info);
|
||||
#else
|
||||
DETOUR_MEMBER_CALL(DetourHLTVStopRecording)();
|
||||
#endif
|
||||
|
||||
IDemoRecorder *recorder = (IDemoRecorder *)this;
|
||||
g_pSTVForwards.CallOnStopRecording(recorder);
|
||||
}
|
||||
|
||||
bool CForwardManager::CreateStartRecordingDetour()
|
||||
{
|
||||
if (m_bStartRecordingDetoured)
|
||||
return true;
|
||||
|
||||
m_DStartRecording = DETOUR_CREATE_MEMBER(DetourHLTVStartRecording, "CHLTVDemoRecorder::StartRecording");
|
||||
|
||||
if (m_DStartRecording != nullptr)
|
||||
{
|
||||
m_DStartRecording->EnableDetour();
|
||||
m_bStartRecordingDetoured = true;
|
||||
return true;
|
||||
}
|
||||
smutils->LogError(myself, "CHLTVDemoRecorder::StartRecording detour could not be initialized.");
|
||||
return false;
|
||||
}
|
||||
|
||||
void CForwardManager::RemoveStartRecordingDetour()
|
||||
{
|
||||
if (m_DStartRecording != nullptr)
|
||||
{
|
||||
m_DStartRecording->Destroy();
|
||||
m_DStartRecording = nullptr;
|
||||
}
|
||||
m_bStartRecordingDetoured = false;
|
||||
}
|
||||
|
||||
bool CForwardManager::CreateStopRecordingDetour()
|
||||
{
|
||||
if (m_bStopRecordingDetoured)
|
||||
return true;
|
||||
|
||||
m_DStopRecording = DETOUR_CREATE_MEMBER(DetourHLTVStopRecording, "CHLTVDemoRecorder::StopRecording");
|
||||
|
||||
if (m_DStopRecording != nullptr)
|
||||
{
|
||||
m_DStopRecording->EnableDetour();
|
||||
m_bStopRecordingDetoured = true;
|
||||
return true;
|
||||
}
|
||||
smutils->LogError(myself, "CHLTVDemoRecorder::StartRecording detour could not be initialized.");
|
||||
return false;
|
||||
}
|
||||
|
||||
void CForwardManager::RemoveStopRecordingDetour()
|
||||
{
|
||||
if (m_DStopRecording != nullptr)
|
||||
{
|
||||
m_DStopRecording->Destroy();
|
||||
m_DStopRecording = nullptr;
|
||||
}
|
||||
m_bStopRecordingDetoured = false;
|
||||
}
|
||||
#endif
|
18
forwards.h
18
forwards.h
@ -69,9 +69,19 @@ public:
|
||||
void HookServer(HLTVServerWrapper *server);
|
||||
void UnhookServer(HLTVServerWrapper *server);
|
||||
|
||||
#ifndef WIN32
|
||||
bool CreateStartRecordingDetour();
|
||||
void RemoveStartRecordingDetour();
|
||||
bool CreateStopRecordingDetour();
|
||||
void RemoveStopRecordingDetour();
|
||||
#endif
|
||||
|
||||
void CallOnServerStart(IHLTVServer *server);
|
||||
void CallOnServerShutdown(IHLTVServer *server);
|
||||
|
||||
void CallOnStartRecording(IDemoRecorder *recorder, const char *filename, bool bContinuously);
|
||||
void CallOnStopRecording(IDemoRecorder *recorder);
|
||||
|
||||
private:
|
||||
void HookClient(IClient *client);
|
||||
void UnhookClient(IClient *client);
|
||||
@ -106,6 +116,14 @@ private:
|
||||
bool m_bHasRejectConnectionOffset = false;
|
||||
bool m_bHasGetChallengeTypeOffset = false;
|
||||
bool m_bHasActivatePlayerOffset = false;
|
||||
|
||||
// Only need the detours on linux. Windows always uses its vtables..
|
||||
#ifndef WIN32
|
||||
bool m_bStartRecordingDetoured = false;
|
||||
CDetour *m_DStartRecording = nullptr;
|
||||
bool m_bStopRecordingDetoured = false;
|
||||
CDetour *m_DStopRecording = nullptr;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern CForwardManager g_pSTVForwards;
|
||||
|
@ -261,6 +261,11 @@ void HLTVServerWrapperManager::InitHooks()
|
||||
|
||||
void HLTVServerWrapperManager::ShutdownHooks()
|
||||
{
|
||||
#ifndef WIN32
|
||||
g_pSTVForwards.RemoveStartRecordingDetour();
|
||||
g_pSTVForwards.RemoveStopRecordingDetour();
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
if (m_bSendNetMsgHooked)
|
||||
{
|
||||
@ -272,6 +277,12 @@ void HLTVServerWrapperManager::ShutdownHooks()
|
||||
|
||||
void HLTVServerWrapperManager::AddServer(IHLTVServer *hltvserver)
|
||||
{
|
||||
#ifndef WIN32
|
||||
// Create the detours once the first sourcetv server is created.
|
||||
g_pSTVForwards.CreateStartRecordingDetour();
|
||||
g_pSTVForwards.CreateStopRecordingDetour();
|
||||
#endif
|
||||
|
||||
HLTVServerWrapper *wrapper = new HLTVServerWrapper(hltvserver);
|
||||
m_HLTVServers.append(wrapper);
|
||||
}
|
||||
|
@ -111,6 +111,20 @@
|
||||
"linux" "@_ZN11CHLTVServer24GetRecordingDemoFilenameEv"
|
||||
"windows" "\x81\xC1\x2A\x2A\x2A\x2A\x8B\x01\xFF\x20"
|
||||
}
|
||||
|
||||
// StartRecording and StopRecording are virtual, but get called directly in the linux binary..
|
||||
// Need to add a detour.
|
||||
"CHLTVDemoRecorder::StartRecording"
|
||||
{
|
||||
"library" "engine"
|
||||
"linux" "@_ZN17CHLTVDemoRecorder14StartRecordingEPKcb"
|
||||
}
|
||||
|
||||
"CHLTVDemoRecorder::StopRecording"
|
||||
{
|
||||
"library" "engine"
|
||||
"linux" "@_ZN17CHLTVDemoRecorder13StopRecordingEPK9CGameInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
"cstrike"
|
||||
@ -237,6 +251,20 @@
|
||||
// "HLTV server shutting down"
|
||||
"windows" "\x56\x8B\xF1\x8B\x86\x2A\x2A\x2A\x2A\x8D\x8E\x2A\x2A\x2A\x2A\xFF\x50\x2A\x8B\x86\x2A\x2A\x2A\x2A\x8D\x8E"
|
||||
}
|
||||
|
||||
// StartRecording and StopRecording are virtual, but get called directly in the linux binary..
|
||||
// Need to add a detour.
|
||||
"CHLTVDemoRecorder::StartRecording"
|
||||
{
|
||||
"library" "engine"
|
||||
"linux" "@_ZN17CHLTVDemoRecorder14StartRecordingEPKcb"
|
||||
}
|
||||
|
||||
"CHLTVDemoRecorder::StopRecording"
|
||||
{
|
||||
"library" "engine"
|
||||
"linux" "@_ZN17CHLTVDemoRecorder13StopRecordingEv"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user