Skip to content

Commit

Permalink
Host-side RTA timer, IL mode, Nihilanth/changelevel autostop, etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
ScriptedSnark committed Aug 1, 2024
1 parent 5c1ed5b commit 6c5580a
Show file tree
Hide file tree
Showing 20 changed files with 2,201 additions and 5 deletions.
22 changes: 22 additions & 0 deletions licenses/BXT_LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
The MIT License (MIT)

Copyright (c) 2014-2020 Ivan Molodetskikh
Copyright (c) 2015-2018 Chong Jiang Wei

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
15 changes: 15 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,16 @@ add_library(SvenBXT SHARED
cl_dll/hud_origin.h
cl_dll/hud_speedometer.cpp
cl_dll/hud_speedometer.h
cl_dll/hud_timer.cpp
cl_dll/hud_timer.h
cl_dll/hud_viewangles.cpp
cl_dll/hud_viewangles.h
cl_dll/parsemsg.cpp
cl_dll/parsemsg.h
cl_dll/view.cpp
cl_dll/view.h
dlls/server.cpp
dlls/server.h
SvenBXT.cpp
SvenBXT.h
Utils.cpp
Expand Down Expand Up @@ -69,6 +75,15 @@ elseif( COMPILER_MSVC )
)
endif()

if (COMPILER_GNU)
set_target_properties(SvenBXT PROPERTIES
C_VISIBILITY_PRESET hidden
CXX_VISIBILITY_PRESET hidden
COMPILE_FLAGS "${COMPILE_FLAGS} -fvisibility=hidden"
LINKER_FLAGS "${LINKER_FLAGS} -fvisibility=hidden"
)
endif()

target_compile_definitions( SvenBXT PUBLIC
${COMMON_DEFINES}
)
Expand Down
139 changes: 139 additions & 0 deletions src/CTimer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#ifdef CTIMER_H_RECURSE_GUARD
#error Recursive header files inclusion detected in CTimer.h
#else //CTIMER_H_RECURSE_GUARD

#define CTIMER_H_RECURSE_GUARD

#ifndef CTIMER_H_GUARD
#define CTIMER_H_GUARD
#pragma once

#ifdef __cplusplus

class CTimer
{
public:
CTimer()
{
Init();
}

void Init()
{
ResetTimer();
}

void StartTimer()
{
m_bStarted = true;
if (!m_bRunning)
{
m_startTime = std::chrono::steady_clock::now();
m_bRunning = true;
}
}

void StopTimer()
{
if (m_bRunning)
{
auto now = std::chrono::steady_clock::now();
m_elapsedTime += std::chrono::duration_cast<std::chrono::milliseconds>(now - m_startTime).count();
m_bRunning = false;
}
}

void ResetTimer()
{
m_bRunning = false;
m_elapsedTime = 0;
}

void SetTime(long long time)
{
m_elapsedTime = time;
}


void SyncTimer(long long serverTime, bool stop)
{
if (stop)
{
StopTimer();
SetTime(serverTime);
}
else
{
if (m_bRunning)
{
auto now = std::chrono::steady_clock::now();
long long currentElapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_startTime).count() + m_elapsedTime;
long long adjustment = serverTime - currentElapsedTime;
m_startTime += std::chrono::milliseconds(adjustment);
}
else
{
SetTime(serverTime);
StartTimer();
}
}
}

long long GetTime() const
{
if (m_bRunning)
{
auto now = std::chrono::steady_clock::now();
return m_elapsedTime + std::chrono::duration_cast<std::chrono::milliseconds>(now - m_startTime).count();
}
return m_elapsedTime;
}

int GetMilliseconds() const
{
return static_cast<int>(fmod(GetTime(), 1000.0));
}

int GetSeconds() const
{
double seconds = GetTime() / 1000.0;
return static_cast<int>(fmod(seconds, 60.0));
}

int GetMinutes() const
{
double minutes = GetTime() / 60000.0;
return static_cast<int>(fmod(minutes, 60.0));
}

int GetHours() const
{
double hours = GetTime() / 3600000.0;
return static_cast<int>(fmod(hours, 24.0));
}

int GetDays() const
{
double days = GetTime() / 86400000.0;
return static_cast<int>(days);
}

bool IsStopped() const
{
return m_bRunning ? false : true;
}

private:
std::chrono::time_point<std::chrono::steady_clock> m_startTime;
long long m_elapsedTime; // elapsed time in milliseconds
bool m_bRunning, m_bStarted;
};

#else //!__cplusplus
#error C++ compiler required to compile CTimer.h
#endif //__cplusplus

#endif //CTIMER_H_GUARD

#undef CTIMER_H_RECURSE_GUARD
#endif //CTIMER_H_RECURSE_GUARD
146 changes: 143 additions & 3 deletions src/SvenBXT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,93 @@

#ifdef PLATFORM_WINDOWS
Utils utils = Utils::Utils(NULL, NULL, NULL);
Utils sv_utils = Utils::Utils(NULL, NULL, NULL);
#endif

funchook_t* g_lpFuncHook_Server;
funchook_t* g_lpFuncHook_Engine;
funchook_t* g_lpFuncHook_Client;

dllhandle_t g_lpEngine;
dllhandle_t g_lpServer;
dllhandle_t g_lpClient;

cl_enginefunc_t* g_lpEngfuncs;
enginefuncs_t* g_engfuncs;
globalvars_t* gpGlobals;
server_t* sv;

bool g_bHasLoaded = false;

void SvenBXT_HookClient();

// TODO: move to separate file
typedef void (*_SCR_BeginLoadingPlaque)(qboolean reconnect);
typedef void (*_SCR_EndLoadingPlaque)();
_SCR_BeginLoadingPlaque ORIG_SCR_BeginLoadingPlaque = NULL;
_SCR_EndLoadingPlaque ORIG_SCR_EndLoadingPlaque = NULL;

void HOOKED_SCR_BeginLoadingPlaque(qboolean reconnect)
{
ORIG_SCR_BeginLoadingPlaque(reconnect);

if (g_lpHUDTimer->IsInILMode())
g_lpHUDTimer->TimerStop();
}

void HOOKED_SCR_EndLoadingPlaque()
{
ORIG_SCR_EndLoadingPlaque();

if (g_lpHUDTimer->IsInILMode() && g_RTATimer.GetMilliseconds() <= 0)
g_lpHUDTimer->TimerStart();
}

void SvenBXT_FindEngineStuff()
{
TRACE("Finding engine stuff...\n");

g_lpFuncHook_Engine = funchook_create();

int status;
#ifdef PLATFORM_LINUX
g_lpEngfuncs = (cl_enginefunc_t*)Sys_GetProcAddress(g_lpEngine, "cl_enginefuncs");

if (!g_lpEngfuncs)
{
Sys_Printf("[hw dll] Failed to get \"cl_enginefuncs\".\n");
Sys_Printf("[hw so] Failed to get \"cl_enginefuncs\".\n");
return;
}
else
{
Sys_Printf("[hw dll] Found cl_enginefuncs at %p.\n", g_lpEngfuncs);
Sys_Printf("[hw so] Found cl_enginefuncs at %p.\n", g_lpEngfuncs);
SvenBXT_HookClient();
}

// TODO: use GET_VARIABLE define
enginefuncs_t** p_engfuncs = (enginefuncs_t**)Sys_GetProcAddress(g_lpEngine, "g_pengfuncsExportedToDlls");
g_engfuncs = (*p_engfuncs);
gpGlobals = (globalvars_t*)Sys_GetProcAddress(g_lpEngine, "gGlobalVariables");
sv = (server_t*)Sys_GetProcAddress(g_lpEngine, "sv");

if (!gpGlobals)
{
Sys_Printf("[hw so] Failed to get \"gGlobalVariables\".\n");
}

if (!g_engfuncs)
{
Sys_Printf("[hw so] Failed to get \"g_engfuncsExportedToDlls\".\n[hw dll] Sharing time to clients is not available.\n");
}

if (!sv)
{
Sys_Printf("[hw so] Failed to get \"sv\".\n");
}

GET_VARIABLE(Engine, ORIG_LoadThisDll, _Z11LoadThisDllPc);
GET_VARIABLE(Engine, ORIG_SCR_BeginLoadingPlaque, _Z22SCR_BeginLoadingPlaquei);
GET_VARIABLE(Engine, ORIG_SCR_EndLoadingPlaque, _Z20SCR_EndLoadingPlaquev);
#else
void* handle;
static void* base;
Expand Down Expand Up @@ -70,7 +127,86 @@ void SvenBXT_FindEngineStuff()
break;
}
});

void* LoadThisDll;
auto fLoadThisDll = utils.FindAsync(
LoadThisDll,
patterns::engine::LoadThisDll,
[&](auto pattern)
{
switch (pattern - patterns::engine::LoadThisDll.cbegin())
{
default:
case 0: // Sven-5.25
Sys_Printf("Searching g_engfuncs in Sven-5.25 pattern...\n");
enginefuncs_t** p_engfuncs = *reinterpret_cast<enginefuncs_t***>(reinterpret_cast<uintptr_t>(LoadThisDll) + 109);
g_engfuncs = (*p_engfuncs);
gpGlobals = *reinterpret_cast<globalvars_t**>(reinterpret_cast<uintptr_t>(LoadThisDll) + 67);

if (g_engfuncs)
Sys_Printf("[hw dll] Found g_engfuncs at 0x%p.\n", g_engfuncs);

if (gpGlobals)
Sys_Printf("[hw dll] Found gpGlobals at 0x%p.\n", gpGlobals);
break;
}
});

void* Host_ClearMemory;
auto fHost_ClearMemory = utils.FindAsync(
Host_ClearMemory,
patterns::engine::Host_ClearMemory,
[&](auto pattern)
{
switch (pattern - patterns::engine::Host_ClearMemory.cbegin())
{
default:
case 0: // HL-9920
Sys_Printf("Searching sv in HL-9920 pattern...\n");
sv = *reinterpret_cast<server_t**>(reinterpret_cast<uintptr_t>(Host_ClearMemory) + 0xA4);

if (sv)
{
Sys_Printf("[hw dll] Found sv at 0x%p.\n", sv);
}
break;
case 1: // HL-8684
Sys_Printf("Searching sv in HL-8684 pattern...\n");
sv = *reinterpret_cast<server_t**>(reinterpret_cast<uintptr_t>(Host_ClearMemory) + 0x5E);
if (sv)
{
Sys_Printf("[hw dll] Found sv at 0x%p.\n", sv);
}
break;
case 2: // HL-4554
Sys_Printf("Searching sv in HL-4554 pattern...\n");
sv = *reinterpret_cast<server_t**>(reinterpret_cast<uintptr_t>(Host_ClearMemory) + 0x5C);
if (sv)
{
Sys_Printf("[hw dll] Found sv at 0x%p.\n", sv);
}
break;
case 3: // Sven-5.25
Sys_Printf("Searching sv in Sven-5.25 pattern...\n");
sv = *reinterpret_cast<server_t**>(reinterpret_cast<uintptr_t>(Host_ClearMemory) + 0x98);
if (sv)
{
Sys_Printf("[hw dll] Found sv at 0x%p.\n", sv);
}
break;
}
});

SPTEngineFind(LoadThisDll);
SPTEngineFind(SCR_BeginLoadingPlaque);
SPTEngineFind(SCR_EndLoadingPlaque);
#endif

CreateHook(Engine, LoadThisDll);
CreateHook(Engine, SCR_BeginLoadingPlaque);
CreateHook(Engine, SCR_EndLoadingPlaque);

funchook_install(g_lpFuncHook_Engine, 0);
}

void SvenBXT_HookClient()
Expand Down Expand Up @@ -119,6 +255,11 @@ void SvenBXT_UnhookClient()

void SvenBXT_UnhookEngine()
{
if (g_lpFuncHook_Engine)
{
funchook_uninstall(g_lpFuncHook_Engine, 0);
funchook_destroy(g_lpFuncHook_Engine);
}
}

//-----------------------------------------------------------------------------
Expand All @@ -137,7 +278,6 @@ void WaitUntilClientLoads()
{
SvenBXT_HookEngine();
g_bHasLoaded = true;
// SvenBXT_HookClient();
}
else
goto lbl_waitFor;
Expand Down
Loading

0 comments on commit 6c5580a

Please sign in to comment.