Patch GPS route cost table during jobs

This commit is contained in:
2026-06-20 15:10:18 -05:00
parent 56bfa2460c
commit 4dde0b8579
+137 -1
View File
@@ -96,6 +96,7 @@ constexpr bool kEnableVerboseJournalListenerHooks = false;
constexpr bool kEnableVerboseRouteObserverHooks = false;
constexpr bool kEnableVerboseMappinRouteState = false;
constexpr bool kEnableGpsMultiplierHooks = false;
constexpr bool kEnableGpsCostTablePatch = true;
constexpr uintptr_t kGpsSystemTickRva = 0x0E6B62C;
constexpr uintptr_t kJournalTrackEntryImplRva = 0x05944FC;
constexpr uintptr_t kJournalListenerArrayOffset = 0x210;
@@ -162,6 +163,10 @@ constexpr uintptr_t kGpsSearchRva = 0x044F054;
constexpr uintptr_t kGpsEdgeCostRva = 0x044F838;
constexpr uintptr_t kGpsAuxMultiplierRva = 0x040BB00;
constexpr uintptr_t kGpsNodeMultiplierRva = 0x040BB40;
constexpr uintptr_t kGpsCostMultiplierTableRva = 0x3154D28;
constexpr std::array<float, 7> kGpsPatchedCostMultipliers = {
25.0f, 18.0f, 8.0f, 0.0f, 0.35f, 0.50f, 0.75f,
};
HMODULE gModule = nullptr;
std::mutex gLogMutex;
@@ -233,9 +238,11 @@ uint32_t gGpsSearchLogCount = 0;
uint32_t gGpsEdgeCostLogCount = 0;
uint32_t gGpsAuxMultiplierLogCount = 0;
uint32_t gGpsNodeMultiplierLogCount = 0;
uint32_t gGpsCostTablePatchLogCount = 0;
std::array<uint32_t, 64> gGpsEdgeCostClassLogCounts{};
std::mutex gGpsCostLogMutex;
std::mutex gGpsAsyncLogMutex;
std::mutex gGpsCostTablePatchMutex;
uint64_t gLogStartTick = 0;
uint64_t gLogFrequency = 0;
void* gMappinSetTrackedTarget = nullptr;
@@ -1577,6 +1584,126 @@ bool TryReadUint32FieldValue(void* aObject, uintptr_t aOffset, uint32_t& aValue)
aValue);
}
bool IsDrivingRouteJob(void* aRouteSystem, void* aActiveEntry)
{
uint32_t mode = 0;
if (TryReadUint32FieldValue(aActiveEntry, 0x80, mode) && mode == 2)
{
return true;
}
auto* job = ReadPointerField(aRouteSystem, 0x90D0);
return TryReadUint32FieldValue(job, 0xC4, mode) && mode == 2;
}
void AppendFloatArray(std::ostringstream& aLine, const char* aLabel, const float* aValues, size_t aCount)
{
const auto flags = aLine.flags();
const auto precision = aLine.precision();
aLine << " " << aLabel << "=[";
for (size_t index = 0; index < aCount; ++index)
{
if (index > 0)
{
aLine << ",";
}
aLine << std::fixed << std::setprecision(2) << aValues[index];
}
aLine << "]";
aLine.flags(flags);
aLine.precision(precision);
}
class ScopedGpsCostTablePatch
{
public:
ScopedGpsCostTablePatch(bool aShouldPatch, uint32_t aRouteJobStartCall)
: m_routeJobStartCall(aRouteJobStartCall)
{
if (!kEnableGpsCostTablePatch || !aShouldPatch)
{
return;
}
m_table = reinterpret_cast<float*>(GetImageBase() + kGpsCostMultiplierTableRva);
if (!IsReadableMemory(m_table, sizeof(m_original)))
{
LogPatch("gps-cost-table-patch skipped", "reason=unreadable-table");
return;
}
std::memcpy(m_original.data(), m_table, sizeof(m_original));
DWORD oldProtect = 0;
if (!VirtualProtect(m_table, sizeof(m_original), PAGE_EXECUTE_READWRITE, &oldProtect))
{
LogPatch("gps-cost-table-patch skipped", "reason=protect-failed");
return;
}
std::memcpy(m_table, kGpsPatchedCostMultipliers.data(), sizeof(m_original));
DWORD ignoredProtect = 0;
VirtualProtect(m_table, sizeof(m_original), oldProtect, &ignoredProtect);
FlushInstructionCache(GetCurrentProcess(), m_table, sizeof(m_original));
m_active = true;
LogPatch("gps-cost-table-patch applied", nullptr);
}
~ScopedGpsCostTablePatch()
{
if (!m_active || !m_table)
{
return;
}
DWORD oldProtect = 0;
if (!VirtualProtect(m_table, sizeof(m_original), PAGE_EXECUTE_READWRITE, &oldProtect))
{
LogPatch("gps-cost-table-patch restore-failed", "reason=protect-failed");
return;
}
std::memcpy(m_table, m_original.data(), sizeof(m_original));
DWORD ignoredProtect = 0;
VirtualProtect(m_table, sizeof(m_original), oldProtect, &ignoredProtect);
FlushInstructionCache(GetCurrentProcess(), m_table, sizeof(m_original));
LogPatch("gps-cost-table-patch restored", nullptr);
}
private:
void LogPatch(const char* aMessage, const char* aReason)
{
const auto patchLogCall = NextGpsAsyncLogCall(gGpsCostTablePatchLogCount);
if (patchLogCall >= 64)
{
return;
}
std::ostringstream line;
line << aMessage << " patchCall=" << patchLogCall << " routeJobStartCall=" << m_routeJobStartCall;
AppendPointerWithRva(line, "table", m_table);
if (aReason)
{
line << " " << aReason;
}
if (m_table && IsReadableMemory(m_table, sizeof(m_original)))
{
AppendFloatArray(line, "current", m_table, m_original.size());
}
AppendFloatArray(line, "original", m_original.data(), m_original.size());
AppendFloatArray(line, "patched", kGpsPatchedCostMultipliers.data(), kGpsPatchedCostMultipliers.size());
LogRed4ext(line.str());
}
uint32_t m_routeJobStartCall = 0;
bool m_active = false;
float* m_table = nullptr;
std::array<float, kGpsPatchedCostMultipliers.size()> m_original{};
};
void AppendRouteJobSummary(std::ostringstream& aLine, const char* aPrefix, void* aJob)
{
const auto prefix = std::string(aPrefix);
@@ -3211,7 +3338,16 @@ bool DetourGpsRouteJobStart(void* aRouteSystem, void* aActiveEntry, float aDelta
bool result = false;
if (gOriginalGpsRouteJobStart)
{
result = gOriginalGpsRouteJobStart(aRouteSystem, aActiveEntry, aDelta, aOutLocal);
if (kEnableGpsCostTablePatch && IsDrivingRouteJob(aRouteSystem, aActiveEntry))
{
std::lock_guard patchLock(gGpsCostTablePatchMutex);
ScopedGpsCostTablePatch patch(true, callCount);
result = gOriginalGpsRouteJobStart(aRouteSystem, aActiveEntry, aDelta, aOutLocal);
}
else
{
result = gOriginalGpsRouteJobStart(aRouteSystem, aActiveEntry, aDelta, aOutLocal);
}
}
if (shouldLog)