Probe GPS route cost multipliers
This commit is contained in:
@@ -159,6 +159,8 @@ constexpr uintptr_t kGpsRouteJobBuildRva = 0x0818BA8;
|
||||
constexpr uintptr_t kGpsRouteProducerRva = 0x044CC7C;
|
||||
constexpr uintptr_t kGpsSearchRva = 0x044F054;
|
||||
constexpr uintptr_t kGpsEdgeCostRva = 0x044F838;
|
||||
constexpr uintptr_t kGpsAuxMultiplierRva = 0x040BB00;
|
||||
constexpr uintptr_t kGpsNodeMultiplierRva = 0x040BB40;
|
||||
|
||||
HMODULE gModule = nullptr;
|
||||
std::mutex gLogMutex;
|
||||
@@ -228,6 +230,8 @@ uint32_t gGpsRouteJobBuildLogCount = 0;
|
||||
uint32_t gGpsRouteProducerLogCount = 0;
|
||||
uint32_t gGpsSearchLogCount = 0;
|
||||
uint32_t gGpsEdgeCostLogCount = 0;
|
||||
uint32_t gGpsAuxMultiplierLogCount = 0;
|
||||
uint32_t gGpsNodeMultiplierLogCount = 0;
|
||||
std::array<uint32_t, 64> gGpsEdgeCostClassLogCounts{};
|
||||
std::mutex gGpsCostLogMutex;
|
||||
std::mutex gGpsAsyncLogMutex;
|
||||
@@ -287,8 +291,28 @@ struct GpsEdgeCostStats
|
||||
uint32_t sampleCount = 0;
|
||||
};
|
||||
|
||||
struct GpsMultiplierSignature
|
||||
{
|
||||
bool active = false;
|
||||
bool auxiliary = false;
|
||||
uint32_t mode = 0;
|
||||
uint32_t retry = 0;
|
||||
uint32_t flagsC0 = 0;
|
||||
uint8_t c8 = 0;
|
||||
uint16_t node86 = 0;
|
||||
uint16_t flags88 = 0;
|
||||
uint16_t node8c = 0;
|
||||
uint16_t node8e = 0;
|
||||
uint8_t node90 = 0;
|
||||
uint8_t node93 = 0;
|
||||
uint32_t valueBits = 0;
|
||||
uint32_t count = 0;
|
||||
};
|
||||
|
||||
thread_local GpsEdgeCostStats* gActiveGpsEdgeCostStats = nullptr;
|
||||
thread_local uint32_t gActiveGpsRouteProducerCall = UINT32_MAX;
|
||||
std::array<GpsMultiplierSignature, 256> gGpsMultiplierSignatures{};
|
||||
uint32_t gGpsMultiplierOverflowCount = 0;
|
||||
|
||||
using ProbeFunc = void (*)(void* aThis, void* a2, void* a3, void* a4);
|
||||
using JournalTrackEntryFunc = void (*)(void* aThis, void* aEntryHandle);
|
||||
@@ -339,6 +363,7 @@ using GpsEdgeCostFunc = float (*)(void* aCostProvider, void* aCurrentState, void
|
||||
uint64_t aPreviousHandle, void* aPreviousSegment, void* aPreviousPoint,
|
||||
uint64_t aCurrentHandle, void* aCurrentSegment, void* aCurrentPoint,
|
||||
uint64_t aNeighborHandle, void* aNeighborSegment, void* aNeighborPoint);
|
||||
using GpsMultiplierFunc = float (*)(void* aJob, void* aNode);
|
||||
ProbeFunc gOriginalGpsSystemTick = nullptr;
|
||||
JournalTrackEntryFunc gOriginalJournalTrackEntry = nullptr;
|
||||
ScriptNativeVoidFunc gOriginalFrameMappinPathWrapper = nullptr;
|
||||
@@ -399,6 +424,8 @@ GpsRouteJobBuildFunc gOriginalGpsRouteJobBuild = nullptr;
|
||||
GpsRouteProducerFunc gOriginalGpsRouteProducer = nullptr;
|
||||
GpsSearchFunc gOriginalGpsSearch = nullptr;
|
||||
GpsEdgeCostFunc gOriginalGpsEdgeCost = nullptr;
|
||||
GpsMultiplierFunc gOriginalGpsAuxMultiplier = nullptr;
|
||||
GpsMultiplierFunc gOriginalGpsNodeMultiplier = nullptr;
|
||||
|
||||
std::filesystem::path GetLogPath()
|
||||
{
|
||||
@@ -531,6 +558,13 @@ float FloatFromBits(uint32_t aBits)
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t FloatToBits(float aValue)
|
||||
{
|
||||
uint32_t bits = 0;
|
||||
std::memcpy(&bits, &aValue, sizeof(bits));
|
||||
return bits;
|
||||
}
|
||||
|
||||
void LogHookCall(const char* aName, uint32_t aCount, void* aThis, void* a2, void* a3, void* a4)
|
||||
{
|
||||
std::ostringstream line;
|
||||
@@ -1250,6 +1284,96 @@ void NoteGpsEdgeCostStats(GpsEdgeCostStats& aStats, uint8_t aSourceClass, uint8_
|
||||
}
|
||||
}
|
||||
|
||||
bool ReadGpsMultiplierSignature(bool aAuxiliary, void* aJob, void* aNode, float aValue,
|
||||
GpsMultiplierSignature& aSignature)
|
||||
{
|
||||
if (!aJob || !aNode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
aSignature = {};
|
||||
aSignature.active = true;
|
||||
aSignature.auxiliary = aAuxiliary;
|
||||
aSignature.valueBits = FloatToBits(aValue);
|
||||
|
||||
const auto jobAddress = reinterpret_cast<uintptr_t>(aJob);
|
||||
const auto nodeAddress = reinterpret_cast<uintptr_t>(aNode);
|
||||
if (!TryReadMemory(reinterpret_cast<const void*>(jobAddress + 0xC4), aSignature.mode) ||
|
||||
aSignature.mode != 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TryReadMemory(reinterpret_cast<const void*>(jobAddress + 0x54), aSignature.retry);
|
||||
TryReadMemory(reinterpret_cast<const void*>(jobAddress + 0xC0), aSignature.flagsC0);
|
||||
TryReadMemory(reinterpret_cast<const void*>(jobAddress + 0xC8), aSignature.c8);
|
||||
TryReadMemory(reinterpret_cast<const void*>(nodeAddress + 0x86), aSignature.node86);
|
||||
TryReadMemory(reinterpret_cast<const void*>(nodeAddress + 0x88), aSignature.flags88);
|
||||
TryReadMemory(reinterpret_cast<const void*>(nodeAddress + 0x8C), aSignature.node8c);
|
||||
TryReadMemory(reinterpret_cast<const void*>(nodeAddress + 0x8E), aSignature.node8e);
|
||||
TryReadMemory(reinterpret_cast<const void*>(nodeAddress + 0x90), aSignature.node90);
|
||||
TryReadMemory(reinterpret_cast<const void*>(nodeAddress + 0x93), aSignature.node93);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SameGpsMultiplierSignature(const GpsMultiplierSignature& aLeft, const GpsMultiplierSignature& aRight)
|
||||
{
|
||||
return aLeft.active == aRight.active && aLeft.auxiliary == aRight.auxiliary &&
|
||||
aLeft.mode == aRight.mode && aLeft.retry == aRight.retry && aLeft.flagsC0 == aRight.flagsC0 &&
|
||||
aLeft.c8 == aRight.c8 && aLeft.node86 == aRight.node86 && aLeft.flags88 == aRight.flags88 &&
|
||||
aLeft.node8c == aRight.node8c && aLeft.node8e == aRight.node8e &&
|
||||
aLeft.node90 == aRight.node90 && aLeft.node93 == aRight.node93 &&
|
||||
aLeft.valueBits == aRight.valueBits;
|
||||
}
|
||||
|
||||
bool NoteGpsMultiplierSignature(GpsMultiplierSignature aSignature, uint32_t& aCallCount, uint32_t& aSignatureCount)
|
||||
{
|
||||
std::lock_guard lock(gGpsCostLogMutex);
|
||||
|
||||
auto& logCount = aSignature.auxiliary ? gGpsAuxMultiplierLogCount : gGpsNodeMultiplierLogCount;
|
||||
aCallCount = logCount++;
|
||||
|
||||
for (auto& existing : gGpsMultiplierSignatures)
|
||||
{
|
||||
if (!existing.active || !SameGpsMultiplierSignature(existing, aSignature))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
aSignatureCount = ++existing.count;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& existing : gGpsMultiplierSignatures)
|
||||
{
|
||||
if (existing.active)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
existing = aSignature;
|
||||
existing.count = 1;
|
||||
aSignatureCount = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
++gGpsMultiplierOverflowCount;
|
||||
return false;
|
||||
}
|
||||
|
||||
void AppendGpsMultiplierSignature(std::ostringstream& aLine, const GpsMultiplierSignature& aSignature)
|
||||
{
|
||||
aLine << " mode=" << aSignature.mode << " retry=" << aSignature.retry << " flagsC0=0x" << std::hex
|
||||
<< aSignature.flagsC0 << " c8=0x" << static_cast<uint32_t>(aSignature.c8)
|
||||
<< " node86=0x" << aSignature.node86 << " flags88=0x" << aSignature.flags88
|
||||
<< " node8c=0x" << aSignature.node8c << " node8e=0x" << aSignature.node8e
|
||||
<< " node90=0x" << static_cast<uint32_t>(aSignature.node90)
|
||||
<< " node93=0x" << static_cast<uint32_t>(aSignature.node93) << std::dec
|
||||
<< " value=" << FloatFromBits(aSignature.valueBits);
|
||||
}
|
||||
|
||||
void AppendGpsRouteProducerQuerySummary(std::ostringstream& aLine, void* aQuery)
|
||||
{
|
||||
AppendVector4Field(aLine, "query_start00", aQuery, 0x00);
|
||||
@@ -3403,6 +3527,60 @@ float DetourGpsEdgeCost(void* aCostProvider, void* aCurrentState, void* aNeighbo
|
||||
return result;
|
||||
}
|
||||
|
||||
void LogGpsMultiplierSignature(const char* aName, uintptr_t aRva, bool aAuxiliary, void* aJob, void* aNode,
|
||||
float aValue, const void* aReturnAddress)
|
||||
{
|
||||
GpsMultiplierSignature signature{};
|
||||
if (!ReadGpsMultiplierSignature(aAuxiliary, aJob, aNode, aValue, signature))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t callCount = 0;
|
||||
uint32_t signatureCount = 0;
|
||||
const auto isNew = NoteGpsMultiplierSignature(signature, callCount, signatureCount);
|
||||
const auto shouldLog = isNew || signatureCount == 8 || signatureCount == 64 || signatureCount == 512;
|
||||
if (!shouldLog)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::ostringstream line;
|
||||
line << "hook " << aName << " 0x" << std::hex << aRva << std::dec << " call=" << callCount
|
||||
<< " signatureCount=" << signatureCount << " new=" << static_cast<uint32_t>(isNew);
|
||||
AppendPointerWithRva(line, "job", aJob);
|
||||
AppendPointerWithRva(line, "node", aNode);
|
||||
AppendGpsMultiplierSignature(line, signature);
|
||||
AppendReturnRva(line, aReturnAddress);
|
||||
LogRed4ext(line.str());
|
||||
}
|
||||
|
||||
float DetourGpsAuxMultiplier(void* aJob, void* aNode)
|
||||
{
|
||||
float result = 1.0f;
|
||||
if (gOriginalGpsAuxMultiplier)
|
||||
{
|
||||
result = gOriginalGpsAuxMultiplier(aJob, aNode);
|
||||
}
|
||||
|
||||
LogGpsMultiplierSignature("GPSAuxMultiplier", kGpsAuxMultiplierRva, true, aJob, aNode, result,
|
||||
__builtin_return_address(0));
|
||||
return result;
|
||||
}
|
||||
|
||||
float DetourGpsNodeMultiplier(void* aJob, void* aNode)
|
||||
{
|
||||
float result = 1.0f;
|
||||
if (gOriginalGpsNodeMultiplier)
|
||||
{
|
||||
result = gOriginalGpsNodeMultiplier(aJob, aNode);
|
||||
}
|
||||
|
||||
LogGpsMultiplierSignature("GPSNodeMultiplier", kGpsNodeMultiplierRva, false, aJob, aNode, result,
|
||||
__builtin_return_address(0));
|
||||
return result;
|
||||
}
|
||||
|
||||
void AttachProbeHook(const char* aName, uintptr_t aRva, void* aDetour, void** aOriginal)
|
||||
{
|
||||
if (!gSdk || !gSdk->hooking || !gSdk->hooking->Attach)
|
||||
@@ -3754,6 +3932,12 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
||||
reinterpret_cast<void**>(&gOriginalGpsSearch));
|
||||
AttachProbeHook("GPSEdgeCost 0x44f838", kGpsEdgeCostRva, reinterpret_cast<void*>(&DetourGpsEdgeCost),
|
||||
reinterpret_cast<void**>(&gOriginalGpsEdgeCost));
|
||||
AttachProbeHook("GPSAuxMultiplier 0x40bb00", kGpsAuxMultiplierRva,
|
||||
reinterpret_cast<void*>(&DetourGpsAuxMultiplier),
|
||||
reinterpret_cast<void**>(&gOriginalGpsAuxMultiplier));
|
||||
AttachProbeHook("GPSNodeMultiplier 0x40bb40", kGpsNodeMultiplierRva,
|
||||
reinterpret_cast<void*>(&DetourGpsNodeMultiplier),
|
||||
reinterpret_cast<void**>(&gOriginalGpsNodeMultiplier));
|
||||
AttachProbeHook("GPSSystem/Tick", kGpsSystemTickRva, reinterpret_cast<void*>(&DetourGpsSystemTick),
|
||||
reinterpret_cast<void**>(&gOriginalGpsSystemTick));
|
||||
AttachProbeHook("JournalManager::TrackEntry impl", kJournalTrackEntryImplRva,
|
||||
@@ -3876,6 +4060,8 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
||||
DetachProbeHook("GPSRouteProducer 0x44cc7c", kGpsRouteProducerRva);
|
||||
DetachProbeHook("GPSSearch 0x44f054", kGpsSearchRva);
|
||||
DetachProbeHook("GPSEdgeCost 0x44f838", kGpsEdgeCostRva);
|
||||
DetachProbeHook("GPSAuxMultiplier 0x40bb00", kGpsAuxMultiplierRva);
|
||||
DetachProbeHook("GPSNodeMultiplier 0x40bb40", kGpsNodeMultiplierRva);
|
||||
DetachProbeHook("GPSSystem/Tick", kGpsSystemTickRva);
|
||||
DetachProbeHook("JournalManager::TrackEntry impl", kJournalTrackEntryImplRva);
|
||||
if (kEnableVerboseJournalListenerHooks)
|
||||
|
||||
Reference in New Issue
Block a user