Trace GPS provider filters
This commit is contained in:
@@ -97,11 +97,12 @@ constexpr bool kEnableVerboseRouteObserverHooks = false;
|
||||
constexpr bool kEnableVerboseMappinRouteState = false;
|
||||
constexpr bool kEnableGpsMultiplierHooks = false;
|
||||
constexpr bool kEnableGpsCostTablePatch = false;
|
||||
constexpr bool kEnableGpsProviderClassPatch = true;
|
||||
constexpr bool kEnableGpsProviderClassPatchTrace = true;
|
||||
constexpr bool kEnableGpsTraceHooks = false;
|
||||
constexpr bool kEnableGpsProviderClassPatch = false;
|
||||
constexpr bool kEnableGpsProviderClassPatchTrace = false;
|
||||
constexpr bool kEnableGpsTraceHooks = true;
|
||||
constexpr bool kEnableGpsQueryLifecycleHooks = false;
|
||||
constexpr bool kEnableGpsRouteJobStartTrace = false;
|
||||
constexpr bool kEnableGpsLocalSearchHooks = false;
|
||||
constexpr bool kEnableGpsLocalSearchHooks = true;
|
||||
constexpr bool kEnableRouteUiTraceHooks = false;
|
||||
constexpr uintptr_t kGpsSystemTickRva = 0x0E6B62C;
|
||||
constexpr uintptr_t kJournalTrackEntryImplRva = 0x05944FC;
|
||||
@@ -167,6 +168,8 @@ constexpr uintptr_t kGpsRouteJobBuildRva = 0x0818BA8;
|
||||
constexpr uintptr_t kGpsRouteProducerRva = 0x044CC7C;
|
||||
constexpr uintptr_t kGpsSearchRva = 0x044F054;
|
||||
constexpr uintptr_t kGpsEdgeCostRva = 0x044F838;
|
||||
constexpr uintptr_t kGpsFilteredProviderFilterRva = 0x044FF68;
|
||||
constexpr uintptr_t kGpsBaseProviderFilterRva = 0x0450B08;
|
||||
constexpr uintptr_t kGpsBaseCostProviderVtableRva = 0x2AE6120;
|
||||
constexpr uintptr_t kGpsFilteredCostProviderVtableRva = 0x2AE60F8;
|
||||
constexpr uintptr_t kGpsAuxMultiplierRva = 0x040BB00;
|
||||
@@ -325,6 +328,21 @@ struct GpsEdgeCostStats
|
||||
uint32_t sampleCount = 0;
|
||||
};
|
||||
|
||||
struct GpsProviderFilterStats
|
||||
{
|
||||
uint32_t total = 0;
|
||||
uint32_t passed = 0;
|
||||
uint32_t failed = 0;
|
||||
uint32_t baseTotal = 0;
|
||||
uint32_t filteredTotal = 0;
|
||||
std::array<uint32_t, 64> passClasses{};
|
||||
std::array<uint32_t, 64> failClasses{};
|
||||
uint32_t passInvalidClass = 0;
|
||||
uint32_t failInvalidClass = 0;
|
||||
std::array<uint32_t, 16> passMaskBits{};
|
||||
std::array<uint32_t, 16> failMaskBits{};
|
||||
};
|
||||
|
||||
struct GpsMultiplierSignature
|
||||
{
|
||||
bool active = false;
|
||||
@@ -344,6 +362,7 @@ struct GpsMultiplierSignature
|
||||
};
|
||||
|
||||
thread_local GpsEdgeCostStats* gActiveGpsEdgeCostStats = nullptr;
|
||||
thread_local GpsProviderFilterStats* gActiveGpsProviderFilterStats = nullptr;
|
||||
thread_local uint32_t gActiveGpsRouteProducerCall = UINT32_MAX;
|
||||
std::array<GpsMultiplierSignature, 256> gGpsMultiplierSignatures{};
|
||||
uint32_t gGpsMultiplierOverflowCount = 0;
|
||||
@@ -397,6 +416,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 GpsProviderFilterFunc = bool (*)(void* aCostProvider, uint64_t aHandle, void* aSegment, void* aPoint);
|
||||
using GpsMultiplierFunc = float (*)(void* aJob, void* aNode);
|
||||
ProbeFunc gOriginalGpsSystemTick = nullptr;
|
||||
JournalTrackEntryFunc gOriginalJournalTrackEntry = nullptr;
|
||||
@@ -458,6 +478,8 @@ GpsRouteJobBuildFunc gOriginalGpsRouteJobBuild = nullptr;
|
||||
GpsRouteProducerFunc gOriginalGpsRouteProducer = nullptr;
|
||||
GpsSearchFunc gOriginalGpsSearch = nullptr;
|
||||
GpsEdgeCostFunc gOriginalGpsEdgeCost = nullptr;
|
||||
GpsProviderFilterFunc gOriginalGpsFilteredProviderFilter = nullptr;
|
||||
GpsProviderFilterFunc gOriginalGpsBaseProviderFilter = nullptr;
|
||||
GpsMultiplierFunc gOriginalGpsAuxMultiplier = nullptr;
|
||||
GpsMultiplierFunc gOriginalGpsNodeMultiplier = nullptr;
|
||||
|
||||
@@ -1170,6 +1192,44 @@ void AppendClassCounts(std::ostringstream& aLine, const char* aLabel, const std:
|
||||
aLine << "]";
|
||||
}
|
||||
|
||||
void AppendMaskBitCounts(std::ostringstream& aLine, const char* aLabel, const std::array<uint32_t, 16>& aCounts)
|
||||
{
|
||||
aLine << " " << aLabel << "=[";
|
||||
bool first = true;
|
||||
for (uint32_t index = 0; index < aCounts.size(); ++index)
|
||||
{
|
||||
if (aCounts[index] == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!first)
|
||||
{
|
||||
aLine << ",";
|
||||
}
|
||||
first = false;
|
||||
aLine << index << ":" << aCounts[index];
|
||||
}
|
||||
|
||||
if (first)
|
||||
{
|
||||
aLine << "none";
|
||||
}
|
||||
|
||||
aLine << "]";
|
||||
}
|
||||
|
||||
void AppendGpsProviderFilterStats(std::ostringstream& aLine, const GpsProviderFilterStats& aStats)
|
||||
{
|
||||
aLine << " filterCalls=" << aStats.total << " filterPass=" << aStats.passed
|
||||
<< " filterFail=" << aStats.failed << " filterBase=" << aStats.baseTotal
|
||||
<< " filterFiltered=" << aStats.filteredTotal;
|
||||
AppendClassCounts(aLine, "filterPassClasses", aStats.passClasses, aStats.passInvalidClass);
|
||||
AppendClassCounts(aLine, "filterFailClasses", aStats.failClasses, aStats.failInvalidClass);
|
||||
AppendMaskBitCounts(aLine, "filterPassMaskBits", aStats.passMaskBits);
|
||||
AppendMaskBitCounts(aLine, "filterFailMaskBits", aStats.failMaskBits);
|
||||
}
|
||||
|
||||
void AppendGpsEdgeCostStats(std::ostringstream& aLine, const GpsEdgeCostStats& aStats)
|
||||
{
|
||||
aLine << " edgeCostCalls=" << aStats.total;
|
||||
@@ -1245,6 +1305,49 @@ void AppendGpsEdgeCostStats(std::ostringstream& aLine, const GpsEdgeCostStats& a
|
||||
aLine << "]";
|
||||
}
|
||||
|
||||
void NoteGpsProviderFilterStats(GpsProviderFilterStats& aStats, bool aFilteredProvider, bool aPassed,
|
||||
uint8_t aPointClass, uint16_t aPointMask)
|
||||
{
|
||||
++aStats.total;
|
||||
if (aPassed)
|
||||
{
|
||||
++aStats.passed;
|
||||
}
|
||||
else
|
||||
{
|
||||
++aStats.failed;
|
||||
}
|
||||
|
||||
if (aFilteredProvider)
|
||||
{
|
||||
++aStats.filteredTotal;
|
||||
}
|
||||
else
|
||||
{
|
||||
++aStats.baseTotal;
|
||||
}
|
||||
|
||||
auto& classCounts = aPassed ? aStats.passClasses : aStats.failClasses;
|
||||
auto& invalidClassCount = aPassed ? aStats.passInvalidClass : aStats.failInvalidClass;
|
||||
if (aPointClass < classCounts.size())
|
||||
{
|
||||
++classCounts[aPointClass];
|
||||
}
|
||||
else
|
||||
{
|
||||
++invalidClassCount;
|
||||
}
|
||||
|
||||
auto& maskCounts = aPassed ? aStats.passMaskBits : aStats.failMaskBits;
|
||||
for (uint32_t bit = 0; bit < maskCounts.size(); ++bit)
|
||||
{
|
||||
if ((aPointMask & (1u << bit)) != 0)
|
||||
{
|
||||
++maskCounts[bit];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NoteGpsEdgeCostStats(GpsEdgeCostStats& aStats, uint8_t aSourceClass, uint8_t aNeighborClass, float aCost,
|
||||
uintptr_t aReturnRva, uint64_t aCurrentHandle, uint64_t aNeighborHandle)
|
||||
{
|
||||
@@ -3733,6 +3836,10 @@ int32_t DetourGpsSearch(void* aGraph, uint64_t aStartHandle, uint64_t aTargetHan
|
||||
LogRed4ext(line.str());
|
||||
}
|
||||
|
||||
GpsProviderFilterStats filterStats{};
|
||||
auto* previousFilterStats = gActiveGpsProviderFilterStats;
|
||||
gActiveGpsProviderFilterStats = &filterStats;
|
||||
|
||||
int32_t result = 0x80000008;
|
||||
if (gOriginalGpsSearch)
|
||||
{
|
||||
@@ -3741,6 +3848,8 @@ int32_t DetourGpsSearch(void* aGraph, uint64_t aStartHandle, uint64_t aTargetHan
|
||||
aOutPath, aOutCount);
|
||||
}
|
||||
|
||||
gActiveGpsProviderFilterStats = previousFilterStats;
|
||||
|
||||
if (shouldLog)
|
||||
{
|
||||
uint32_t outCount = 0;
|
||||
@@ -3753,12 +3862,47 @@ int32_t DetourGpsSearch(void* aGraph, uint64_t aStartHandle, uint64_t aTargetHan
|
||||
{
|
||||
line << " outCount=" << outCount;
|
||||
}
|
||||
AppendGpsProviderFilterStats(line, filterStats);
|
||||
LogRed4ext(line.str());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DetourGpsFilteredProviderFilter(void* aCostProvider, uint64_t aHandle, void* aSegment, void* aPoint)
|
||||
{
|
||||
bool result = false;
|
||||
if (gOriginalGpsFilteredProviderFilter)
|
||||
{
|
||||
result = gOriginalGpsFilteredProviderFilter(aCostProvider, aHandle, aSegment, aPoint);
|
||||
}
|
||||
|
||||
if (gActiveGpsProviderFilterStats)
|
||||
{
|
||||
NoteGpsProviderFilterStats(*gActiveGpsProviderFilterStats, true, result, ReadGpsPointClass(aPoint),
|
||||
ReadGpsPointMask(aPoint));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DetourGpsBaseProviderFilter(void* aCostProvider, uint64_t aHandle, void* aSegment, void* aPoint)
|
||||
{
|
||||
bool result = false;
|
||||
if (gOriginalGpsBaseProviderFilter)
|
||||
{
|
||||
result = gOriginalGpsBaseProviderFilter(aCostProvider, aHandle, aSegment, aPoint);
|
||||
}
|
||||
|
||||
if (gActiveGpsProviderFilterStats)
|
||||
{
|
||||
NoteGpsProviderFilterStats(*gActiveGpsProviderFilterStats, false, result, ReadGpsPointClass(aPoint),
|
||||
ReadGpsPointMask(aPoint));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float DetourGpsEdgeCost(void* aCostProvider, void* aCurrentState, void* aNeighborState, uint64_t aPreviousHandle,
|
||||
void* aPreviousSegment, void* aPreviousPoint, uint64_t aCurrentHandle, void* aCurrentSegment,
|
||||
void* aCurrentPoint, uint64_t aNeighborHandle, void* aNeighborSegment, void* aNeighborPoint)
|
||||
@@ -4198,7 +4342,7 @@ 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");
|
||||
|
||||
if (kEnableGpsTraceHooks)
|
||||
if (kEnableGpsQueryLifecycleHooks)
|
||||
{
|
||||
AttachProbeHook("RunGPSQuery body 0x29bd128", kRunGpsQueryBodyRva,
|
||||
reinterpret_cast<void*>(&DetourRunGpsQueryBody),
|
||||
@@ -4252,6 +4396,12 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
||||
reinterpret_cast<void**>(&gOriginalGpsRouteProducer));
|
||||
AttachProbeHook("GPSEdgeCost 0x44f838", kGpsEdgeCostRva, reinterpret_cast<void*>(&DetourGpsEdgeCost),
|
||||
reinterpret_cast<void**>(&gOriginalGpsEdgeCost));
|
||||
AttachProbeHook("GPSFilteredProviderFilter 0x44ff68", kGpsFilteredProviderFilterRva,
|
||||
reinterpret_cast<void*>(&DetourGpsFilteredProviderFilter),
|
||||
reinterpret_cast<void**>(&gOriginalGpsFilteredProviderFilter));
|
||||
AttachProbeHook("GPSBaseProviderFilter 0x450b08", kGpsBaseProviderFilterRva,
|
||||
reinterpret_cast<void*>(&DetourGpsBaseProviderFilter),
|
||||
reinterpret_cast<void**>(&gOriginalGpsBaseProviderFilter));
|
||||
}
|
||||
if (kEnableGpsMultiplierHooks)
|
||||
{
|
||||
@@ -4378,7 +4528,7 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
||||
|
||||
if (aReason == RED4ext::v1::EMainReason::Unload)
|
||||
{
|
||||
if (kEnableGpsTraceHooks)
|
||||
if (kEnableGpsQueryLifecycleHooks)
|
||||
{
|
||||
DetachProbeHook("RunGPSQuery body 0x29bd128", kRunGpsQueryBodyRva);
|
||||
DetachProbeHook("UpdateGPSQuery body 0x29bd254", kUpdateGpsQueryBodyRva);
|
||||
@@ -4404,6 +4554,8 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
||||
{
|
||||
DetachProbeHook("GPSRouteProducer 0x44cc7c", kGpsRouteProducerRva);
|
||||
DetachProbeHook("GPSEdgeCost 0x44f838", kGpsEdgeCostRva);
|
||||
DetachProbeHook("GPSFilteredProviderFilter 0x44ff68", kGpsFilteredProviderFilterRva);
|
||||
DetachProbeHook("GPSBaseProviderFilter 0x450b08", kGpsBaseProviderFilterRva);
|
||||
}
|
||||
if (kEnableGpsMultiplierHooks)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user