Patch GPS route cost table during jobs
This commit is contained in:
@@ -96,6 +96,7 @@ constexpr bool kEnableVerboseJournalListenerHooks = false;
|
|||||||
constexpr bool kEnableVerboseRouteObserverHooks = false;
|
constexpr bool kEnableVerboseRouteObserverHooks = false;
|
||||||
constexpr bool kEnableVerboseMappinRouteState = false;
|
constexpr bool kEnableVerboseMappinRouteState = false;
|
||||||
constexpr bool kEnableGpsMultiplierHooks = false;
|
constexpr bool kEnableGpsMultiplierHooks = false;
|
||||||
|
constexpr bool kEnableGpsCostTablePatch = true;
|
||||||
constexpr uintptr_t kGpsSystemTickRva = 0x0E6B62C;
|
constexpr uintptr_t kGpsSystemTickRva = 0x0E6B62C;
|
||||||
constexpr uintptr_t kJournalTrackEntryImplRva = 0x05944FC;
|
constexpr uintptr_t kJournalTrackEntryImplRva = 0x05944FC;
|
||||||
constexpr uintptr_t kJournalListenerArrayOffset = 0x210;
|
constexpr uintptr_t kJournalListenerArrayOffset = 0x210;
|
||||||
@@ -162,6 +163,10 @@ constexpr uintptr_t kGpsSearchRva = 0x044F054;
|
|||||||
constexpr uintptr_t kGpsEdgeCostRva = 0x044F838;
|
constexpr uintptr_t kGpsEdgeCostRva = 0x044F838;
|
||||||
constexpr uintptr_t kGpsAuxMultiplierRva = 0x040BB00;
|
constexpr uintptr_t kGpsAuxMultiplierRva = 0x040BB00;
|
||||||
constexpr uintptr_t kGpsNodeMultiplierRva = 0x040BB40;
|
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;
|
HMODULE gModule = nullptr;
|
||||||
std::mutex gLogMutex;
|
std::mutex gLogMutex;
|
||||||
@@ -233,9 +238,11 @@ uint32_t gGpsSearchLogCount = 0;
|
|||||||
uint32_t gGpsEdgeCostLogCount = 0;
|
uint32_t gGpsEdgeCostLogCount = 0;
|
||||||
uint32_t gGpsAuxMultiplierLogCount = 0;
|
uint32_t gGpsAuxMultiplierLogCount = 0;
|
||||||
uint32_t gGpsNodeMultiplierLogCount = 0;
|
uint32_t gGpsNodeMultiplierLogCount = 0;
|
||||||
|
uint32_t gGpsCostTablePatchLogCount = 0;
|
||||||
std::array<uint32_t, 64> gGpsEdgeCostClassLogCounts{};
|
std::array<uint32_t, 64> gGpsEdgeCostClassLogCounts{};
|
||||||
std::mutex gGpsCostLogMutex;
|
std::mutex gGpsCostLogMutex;
|
||||||
std::mutex gGpsAsyncLogMutex;
|
std::mutex gGpsAsyncLogMutex;
|
||||||
|
std::mutex gGpsCostTablePatchMutex;
|
||||||
uint64_t gLogStartTick = 0;
|
uint64_t gLogStartTick = 0;
|
||||||
uint64_t gLogFrequency = 0;
|
uint64_t gLogFrequency = 0;
|
||||||
void* gMappinSetTrackedTarget = nullptr;
|
void* gMappinSetTrackedTarget = nullptr;
|
||||||
@@ -1577,6 +1584,126 @@ bool TryReadUint32FieldValue(void* aObject, uintptr_t aOffset, uint32_t& aValue)
|
|||||||
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)
|
void AppendRouteJobSummary(std::ostringstream& aLine, const char* aPrefix, void* aJob)
|
||||||
{
|
{
|
||||||
const auto prefix = std::string(aPrefix);
|
const auto prefix = std::string(aPrefix);
|
||||||
@@ -3211,7 +3338,16 @@ bool DetourGpsRouteJobStart(void* aRouteSystem, void* aActiveEntry, float aDelta
|
|||||||
bool result = false;
|
bool result = false;
|
||||||
if (gOriginalGpsRouteJobStart)
|
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)
|
if (shouldLog)
|
||||||
|
|||||||
Reference in New Issue
Block a user