Probe GPS and traffic pathfinding hooks

This commit is contained in:
2026-06-19 22:08:58 -05:00
parent 37bf5e717f
commit bd4e2b574e
2 changed files with 231 additions and 1 deletions
+95 -1
View File
@@ -62,6 +62,12 @@ struct GameStates
bool (*Add)(PluginHandle aHandle, uint32_t aType, GameState* aState);
};
struct Hooking
{
bool (*Attach)(PluginHandle aHandle, void* aTarget, void* aDetour, void** aOriginal);
bool (*Detach)(PluginHandle aHandle, void* aTarget);
};
struct Scripts
{
bool (*Add)(PluginHandle aHandle, const wchar_t* aPath);
@@ -75,7 +81,7 @@ struct Sdk
{
SemVer* runtime;
Logger* logger;
void* hooking;
Hooking* hooking;
GameStates* gameStates;
Scripts* scripts;
};
@@ -84,6 +90,8 @@ struct Sdk
namespace
{
constexpr uint32_t kGameStateRunning = 2;
constexpr uintptr_t kGpsSystemTickRva = 0x0E6B62C;
constexpr uintptr_t kTrafficSystemPathfindingRva = 0x0AD1234;
HMODULE gModule = nullptr;
std::mutex gLogMutex;
@@ -91,6 +99,12 @@ RED4ext::v1::PluginHandle gHandle = nullptr;
const RED4ext::v1::Sdk* gSdk = nullptr;
uint32_t gUpdateLogCount = 0;
bool gScannedExecutable = false;
uint32_t gGpsTickLogCount = 0;
uint32_t gTrafficPathfindingLogCount = 0;
using ProbeFunc = void (*)(void* aThis, void* a2, void* a3, void* a4);
ProbeFunc gOriginalGpsSystemTick = nullptr;
ProbeFunc gOriginalTrafficSystemPathfinding = nullptr;
std::filesystem::path GetLogPath()
{
@@ -133,6 +147,14 @@ void LogRed4ext(std::string_view aMessage)
}
}
void LogHookCall(const char* aName, uint32_t aCount, void* aThis, void* a2, void* a3, void* a4)
{
std::ostringstream line;
line << "hook " << aName << " call=" << aCount << " this=" << aThis << " a2=" << a2 << " a3=" << a3
<< " a4=" << a4;
LogRed4ext(line.str());
}
const char* ReasonToString(RED4ext::v1::EMainReason aReason)
{
switch (aReason)
@@ -290,6 +312,66 @@ void ScanExecutableStrings()
LogRed4ext("exe-string scan end");
}
void DetourGpsSystemTick(void* aThis, void* a2, void* a3, void* a4)
{
if (gGpsTickLogCount < 16)
{
LogHookCall("GPSSystem/Tick", gGpsTickLogCount, aThis, a2, a3, a4);
++gGpsTickLogCount;
}
if (gOriginalGpsSystemTick)
{
gOriginalGpsSystemTick(aThis, a2, a3, a4);
}
}
void DetourTrafficSystemPathfinding(void* aThis, void* a2, void* a3, void* a4)
{
if (gTrafficPathfindingLogCount < 16)
{
LogHookCall("TrafficSystem_Pathfinding", gTrafficPathfindingLogCount, aThis, a2, a3, a4);
++gTrafficPathfindingLogCount;
}
if (gOriginalTrafficSystemPathfinding)
{
gOriginalTrafficSystemPathfinding(aThis, a2, a3, a4);
}
}
void AttachProbeHook(const char* aName, uintptr_t aRva, void* aDetour, void** aOriginal)
{
if (!gSdk || !gSdk->hooking || !gSdk->hooking->Attach)
{
LogRed4ext("hook attach skipped: RED4ext hooking API unavailable");
return;
}
auto* target = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(GetModuleHandleW(nullptr)) + aRva);
const auto attached = gSdk->hooking->Attach(gHandle, target, aDetour, aOriginal);
std::ostringstream line;
line << "hook attach " << aName << " target=" << target << " rva=0x" << std::hex << aRva << std::dec
<< " result=" << (attached ? "ok" : "failed") << " original=" << (aOriginal ? *aOriginal : nullptr);
LogRed4ext(line.str());
}
void DetachProbeHook(const char* aName, uintptr_t aRva)
{
if (!gSdk || !gSdk->hooking || !gSdk->hooking->Detach)
{
return;
}
auto* target = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(GetModuleHandleW(nullptr)) + aRva);
const auto detached = gSdk->hooking->Detach(gHandle, target);
std::ostringstream line;
line << "hook detach " << aName << " target=" << target << " result=" << (detached ? "ok" : "failed");
LogRed4ext(line.str());
}
bool OnRunningEnter(void* aApp)
{
std::ostringstream line;
@@ -355,6 +437,18 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
{
const auto added = aSdk->gameStates->Add(aHandle, kGameStateRunning, &gRunningState);
LogRed4ext(added ? "registered Running game-state callbacks" : "failed to register Running game-state callbacks");
AttachProbeHook("GPSSystem/Tick", kGpsSystemTickRva, reinterpret_cast<void*>(&DetourGpsSystemTick),
reinterpret_cast<void**>(&gOriginalGpsSystemTick));
AttachProbeHook("TrafficSystem_Pathfinding", kTrafficSystemPathfindingRva,
reinterpret_cast<void*>(&DetourTrafficSystemPathfinding),
reinterpret_cast<void**>(&gOriginalTrafficSystemPathfinding));
}
if (aReason == RED4ext::v1::EMainReason::Unload)
{
DetachProbeHook("GPSSystem/Tick", kGpsSystemTickRva);
DetachProbeHook("TrafficSystem_Pathfinding", kTrafficSystemPathfindingRva);
}
return true;