Summarize GPS route edge costs
This commit is contained in:
@@ -150,6 +150,7 @@ constexpr uintptr_t kGpsQuerySubmitRva = 0x070A42C;
|
||||
constexpr uintptr_t kGpsQueryDispatchRva = 0x070A570;
|
||||
constexpr uintptr_t kGpsQueryResultFetchRva = 0x07094B8;
|
||||
constexpr uintptr_t kGpsQueryStatusRva = 0x0AA5704;
|
||||
constexpr uintptr_t kGpsRouteProducerRva = 0x044CC7C;
|
||||
constexpr uintptr_t kGpsSearchRva = 0x044F054;
|
||||
constexpr uintptr_t kGpsEdgeCostRva = 0x044F838;
|
||||
|
||||
@@ -212,6 +213,7 @@ uint32_t gGpsQuerySubmitLogCount = 0;
|
||||
uint32_t gGpsQueryDispatchLogCount = 0;
|
||||
uint32_t gGpsQueryResultFetchLogCount = 0;
|
||||
uint32_t gGpsQueryStatusLogCount = 0;
|
||||
uint32_t gGpsRouteProducerLogCount = 0;
|
||||
uint32_t gGpsSearchLogCount = 0;
|
||||
uint32_t gGpsEdgeCostLogCount = 0;
|
||||
std::array<uint32_t, 64> gGpsEdgeCostClassLogCounts{};
|
||||
@@ -245,6 +247,36 @@ std::mutex gTrackedGpsQueryMutex;
|
||||
std::array<TrackedGpsQuery, 32> gTrackedGpsQueries{};
|
||||
uint32_t gTrackedGpsQueryNext = 0;
|
||||
|
||||
struct GpsEdgeCostSample
|
||||
{
|
||||
uint64_t currentHandle = 0;
|
||||
uint64_t neighborHandle = 0;
|
||||
uintptr_t returnRva = 0;
|
||||
float cost = 0.0f;
|
||||
uint8_t sourceClass = 0xFF;
|
||||
uint8_t neighborClass = 0xFF;
|
||||
};
|
||||
|
||||
struct GpsEdgeCostStats
|
||||
{
|
||||
uint32_t total = 0;
|
||||
uint32_t invalidSourceClass = 0;
|
||||
uint32_t invalidNeighborClass = 0;
|
||||
float costSum = 0.0f;
|
||||
float minCost = 0.0f;
|
||||
float maxCost = 0.0f;
|
||||
std::array<uint32_t, 64> sourceClasses{};
|
||||
std::array<uint32_t, 64> neighborClasses{};
|
||||
std::array<uintptr_t, 8> returnRvas{};
|
||||
std::array<uint32_t, 8> returnRvaCounts{};
|
||||
uint32_t otherReturnRvas = 0;
|
||||
std::array<GpsEdgeCostSample, 8> samples{};
|
||||
uint32_t sampleCount = 0;
|
||||
};
|
||||
|
||||
thread_local GpsEdgeCostStats* gActiveGpsEdgeCostStats = nullptr;
|
||||
thread_local uint32_t gActiveGpsRouteProducerCall = UINT32_MAX;
|
||||
|
||||
using ProbeFunc = void (*)(void* aThis, void* a2, void* a3, void* a4);
|
||||
using JournalTrackEntryFunc = void (*)(void* aThis, void* aEntryHandle);
|
||||
using ScriptNativeVoidFunc = void (*)(void* aThis, void* aStack, void* aResult);
|
||||
@@ -280,6 +312,7 @@ using GpsQuerySubmitFunc = int32_t (*)(void* aManager, void* aQuery);
|
||||
using GpsQueryDispatchFunc = void (*)(void* aRuntimeQuery, void* aTargetPosition, void* aArg3, void* aArg4);
|
||||
using GpsQueryResultFetchFunc = bool (*)(void* aManager, uint32_t aQueryId, void* aOutPath);
|
||||
using GpsQueryStatusFunc = int32_t (*)(void* aManager, uint32_t aQueryId);
|
||||
using GpsRouteProducerFunc = int32_t (*)(void* aGraph, void* aQuery, void* aOutResult);
|
||||
using GpsSearchFunc = int32_t (*)(void* aGraph, uint64_t aStartHandle, uint64_t aTargetHandle, void* aStartPoint,
|
||||
void* aTargetPoint, void* aCostProvider, void* aOutPath, uint32_t* aOutCount);
|
||||
using GpsEdgeCostFunc = float (*)(void* aCostProvider, void* aCurrentState, void* aNeighborState,
|
||||
@@ -337,6 +370,7 @@ GpsQuerySubmitFunc gOriginalGpsQuerySubmit = nullptr;
|
||||
GpsQueryDispatchFunc gOriginalGpsQueryDispatch = nullptr;
|
||||
GpsQueryResultFetchFunc gOriginalGpsQueryResultFetch = nullptr;
|
||||
GpsQueryStatusFunc gOriginalGpsQueryStatus = nullptr;
|
||||
GpsRouteProducerFunc gOriginalGpsRouteProducer = nullptr;
|
||||
GpsSearchFunc gOriginalGpsSearch = nullptr;
|
||||
GpsEdgeCostFunc gOriginalGpsEdgeCost = nullptr;
|
||||
|
||||
@@ -837,6 +871,25 @@ bool TryReadFloatField(void* aObject, uintptr_t aOffset, float& aValue)
|
||||
aValue);
|
||||
}
|
||||
|
||||
void AppendFloatField(std::ostringstream& aLine, const char* aLabel, void* aObject, uintptr_t aOffset)
|
||||
{
|
||||
float value = 0.0f;
|
||||
const auto hasValue = TryReadFloatField(aObject, aOffset, value);
|
||||
aLine << " " << aLabel << "=";
|
||||
if (hasValue)
|
||||
{
|
||||
const auto flags = aLine.flags();
|
||||
const auto precision = aLine.precision();
|
||||
aLine << std::fixed << std::setprecision(3) << value;
|
||||
aLine.flags(flags);
|
||||
aLine.precision(precision);
|
||||
}
|
||||
else
|
||||
{
|
||||
aLine << "<unreadable>";
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ReadGpsPointClass(void* aPoint)
|
||||
{
|
||||
uint8_t value = 0xFF;
|
||||
@@ -932,6 +985,260 @@ void AppendGpsCostProviderSummary(std::ostringstream& aLine, const char* aPrefix
|
||||
aLine.precision(precision);
|
||||
}
|
||||
|
||||
void AppendGpsCostProviderCompact(std::ostringstream& aLine, const char* aPrefix, void* aProvider)
|
||||
{
|
||||
const auto prefix = std::string(aPrefix);
|
||||
AppendPointerWithRva(aLine, prefix.c_str(), aProvider);
|
||||
if (!aProvider)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto* vtable = ReadPointerField(aProvider, 0x00);
|
||||
AppendPointerWithRva(aLine, (prefix + "_vtable").c_str(), vtable);
|
||||
if (IsInImage(vtable))
|
||||
{
|
||||
AppendPointerWithRva(aLine, (prefix + "_slot08").c_str(), ReadPointerField(vtable, 0x08));
|
||||
AppendPointerWithRva(aLine, (prefix + "_slot10").c_str(), ReadPointerField(vtable, 0x10));
|
||||
}
|
||||
|
||||
AppendUint16Field(aLine, (prefix + "_mask108").c_str(), aProvider, 0x108);
|
||||
AppendUint16Field(aLine, (prefix + "_mask10a").c_str(), aProvider, 0x10A);
|
||||
|
||||
const auto flags = aLine.flags();
|
||||
const auto precision = aLine.precision();
|
||||
aLine << " " << prefix << "_nonunitMul=[";
|
||||
bool first = true;
|
||||
for (uint32_t index = 0; index < 64; ++index)
|
||||
{
|
||||
float value = 0.0f;
|
||||
if (!TryReadFloatField(aProvider, 0x08 + static_cast<uintptr_t>(index) * sizeof(float), value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value > 0.999f && value < 1.001f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!first)
|
||||
{
|
||||
aLine << ",";
|
||||
}
|
||||
first = false;
|
||||
aLine << index << ":" << std::fixed << std::setprecision(3) << value;
|
||||
}
|
||||
if (first)
|
||||
{
|
||||
aLine << "none";
|
||||
}
|
||||
aLine << "]";
|
||||
aLine.flags(flags);
|
||||
aLine.precision(precision);
|
||||
}
|
||||
|
||||
void AppendClassCounts(std::ostringstream& aLine, const char* aLabel, const std::array<uint32_t, 64>& aCounts,
|
||||
uint32_t aInvalidCount)
|
||||
{
|
||||
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 (aInvalidCount > 0)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
aLine << ",";
|
||||
}
|
||||
first = false;
|
||||
aLine << "invalid:" << aInvalidCount;
|
||||
}
|
||||
|
||||
if (first)
|
||||
{
|
||||
aLine << "none";
|
||||
}
|
||||
|
||||
aLine << "]";
|
||||
}
|
||||
|
||||
void AppendGpsEdgeCostStats(std::ostringstream& aLine, const GpsEdgeCostStats& aStats)
|
||||
{
|
||||
aLine << " edgeCostCalls=" << aStats.total;
|
||||
if (aStats.total > 0)
|
||||
{
|
||||
const auto flags = aLine.flags();
|
||||
const auto precision = aLine.precision();
|
||||
aLine << " edgeCostMin=" << std::fixed << std::setprecision(3) << aStats.minCost;
|
||||
aLine << " edgeCostMax=" << std::fixed << std::setprecision(3) << aStats.maxCost;
|
||||
aLine << " edgeCostAvg=" << std::fixed << std::setprecision(3)
|
||||
<< (aStats.costSum / static_cast<float>(aStats.total));
|
||||
aLine.flags(flags);
|
||||
aLine.precision(precision);
|
||||
}
|
||||
|
||||
AppendClassCounts(aLine, "edgeSrcClasses", aStats.sourceClasses, aStats.invalidSourceClass);
|
||||
AppendClassCounts(aLine, "edgeDstClasses", aStats.neighborClasses, aStats.invalidNeighborClass);
|
||||
|
||||
aLine << " edgeRetRvas=[";
|
||||
bool first = true;
|
||||
for (uint32_t index = 0; index < aStats.returnRvas.size(); ++index)
|
||||
{
|
||||
if (aStats.returnRvas[index] == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!first)
|
||||
{
|
||||
aLine << ",";
|
||||
}
|
||||
first = false;
|
||||
aLine << "0x" << std::hex << aStats.returnRvas[index] << std::dec << ":" << aStats.returnRvaCounts[index];
|
||||
}
|
||||
if (aStats.otherReturnRvas > 0)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
aLine << ",";
|
||||
}
|
||||
first = false;
|
||||
aLine << "other:" << aStats.otherReturnRvas;
|
||||
}
|
||||
if (first)
|
||||
{
|
||||
aLine << "none";
|
||||
}
|
||||
aLine << "]";
|
||||
|
||||
aLine << " edgeSamples=[";
|
||||
const auto sampleCount = std::min<uint32_t>(aStats.sampleCount, static_cast<uint32_t>(aStats.samples.size()));
|
||||
for (uint32_t index = 0; index < sampleCount; ++index)
|
||||
{
|
||||
const auto& sample = aStats.samples[index];
|
||||
if (index > 0)
|
||||
{
|
||||
aLine << ";";
|
||||
}
|
||||
|
||||
const auto flags = aLine.flags();
|
||||
const auto precision = aLine.precision();
|
||||
aLine << index << ":" << static_cast<uint32_t>(sample.sourceClass) << ">"
|
||||
<< static_cast<uint32_t>(sample.neighborClass) << " cost=" << std::fixed << std::setprecision(3)
|
||||
<< sample.cost << " ret=0x" << std::hex << sample.returnRva << " cur=0x" << sample.currentHandle
|
||||
<< " dst=0x" << sample.neighborHandle << std::dec;
|
||||
aLine.flags(flags);
|
||||
aLine.precision(precision);
|
||||
}
|
||||
if (sampleCount == 0)
|
||||
{
|
||||
aLine << "none";
|
||||
}
|
||||
aLine << "]";
|
||||
}
|
||||
|
||||
void NoteGpsEdgeCostStats(GpsEdgeCostStats& aStats, uint8_t aSourceClass, uint8_t aNeighborClass, float aCost,
|
||||
uintptr_t aReturnRva, uint64_t aCurrentHandle, uint64_t aNeighborHandle)
|
||||
{
|
||||
++aStats.total;
|
||||
aStats.costSum += aCost;
|
||||
if (aStats.total == 1)
|
||||
{
|
||||
aStats.minCost = aCost;
|
||||
aStats.maxCost = aCost;
|
||||
}
|
||||
else
|
||||
{
|
||||
aStats.minCost = std::min(aStats.minCost, aCost);
|
||||
aStats.maxCost = std::max(aStats.maxCost, aCost);
|
||||
}
|
||||
|
||||
if (aSourceClass < aStats.sourceClasses.size())
|
||||
{
|
||||
++aStats.sourceClasses[aSourceClass];
|
||||
}
|
||||
else
|
||||
{
|
||||
++aStats.invalidSourceClass;
|
||||
}
|
||||
|
||||
if (aNeighborClass < aStats.neighborClasses.size())
|
||||
{
|
||||
++aStats.neighborClasses[aNeighborClass];
|
||||
}
|
||||
else
|
||||
{
|
||||
++aStats.invalidNeighborClass;
|
||||
}
|
||||
|
||||
if (aReturnRva != 0)
|
||||
{
|
||||
bool recorded = false;
|
||||
for (uint32_t index = 0; index < aStats.returnRvas.size(); ++index)
|
||||
{
|
||||
if (aStats.returnRvas[index] == aReturnRva)
|
||||
{
|
||||
++aStats.returnRvaCounts[index];
|
||||
recorded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (aStats.returnRvas[index] == 0)
|
||||
{
|
||||
aStats.returnRvas[index] = aReturnRva;
|
||||
aStats.returnRvaCounts[index] = 1;
|
||||
recorded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!recorded)
|
||||
{
|
||||
++aStats.otherReturnRvas;
|
||||
}
|
||||
}
|
||||
|
||||
if (aStats.sampleCount < aStats.samples.size())
|
||||
{
|
||||
auto& sample = aStats.samples[aStats.sampleCount++];
|
||||
sample.currentHandle = aCurrentHandle;
|
||||
sample.neighborHandle = aNeighborHandle;
|
||||
sample.returnRva = aReturnRva;
|
||||
sample.cost = aCost;
|
||||
sample.sourceClass = aSourceClass;
|
||||
sample.neighborClass = aNeighborClass;
|
||||
}
|
||||
}
|
||||
|
||||
void AppendGpsRouteProducerQuerySummary(std::ostringstream& aLine, void* aQuery)
|
||||
{
|
||||
AppendVector4Field(aLine, "query_start00", aQuery, 0x00);
|
||||
AppendVector4Field(aLine, "query_end10", aQuery, 0x10);
|
||||
AppendFloatField(aLine, "query_f68", aQuery, 0x68);
|
||||
AppendFloatField(aLine, "query_f78", aQuery, 0x78);
|
||||
AppendFloatField(aLine, "query_f88", aQuery, 0x88);
|
||||
AppendUint32Field(aLine, "query_f8c", aQuery, 0x8C);
|
||||
AppendUint32Field(aLine, "query_f90", aQuery, 0x90);
|
||||
AppendUint32Field(aLine, "query_f94", aQuery, 0x94);
|
||||
AppendPointerField(aLine, "query_ptr98", aQuery, 0x98);
|
||||
AppendPointerField(aLine, "query_ptra0", aQuery, 0xA0);
|
||||
AppendUint32Field(aLine, "query_flagsa8", aQuery, 0xA8);
|
||||
}
|
||||
|
||||
void AppendVector3ListCandidate(std::ostringstream& aLine, const char* aPrefix, void* aObject, uintptr_t aDataOffset,
|
||||
uintptr_t aCountOffset, uintptr_t aStride)
|
||||
{
|
||||
@@ -2534,10 +2841,70 @@ int32_t DetourGpsQueryStatus(void* aManager, uint32_t aQueryId)
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t DetourGpsRouteProducer(void* aGraph, void* aQuery, void* aOutResult)
|
||||
{
|
||||
constexpr uint32_t kMaxCalls = 512;
|
||||
|
||||
uint32_t callCount = 0;
|
||||
bool shouldLog = false;
|
||||
{
|
||||
std::lock_guard lock(gGpsCostLogMutex);
|
||||
callCount = gGpsRouteProducerLogCount++;
|
||||
shouldLog = callCount < kMaxCalls;
|
||||
}
|
||||
|
||||
if (shouldLog)
|
||||
{
|
||||
std::ostringstream line;
|
||||
line << "hook GPSRouteProducer 0x44cc7c call=" << callCount;
|
||||
AppendPointerWithRva(line, "graph", aGraph);
|
||||
AppendPointerWithRva(line, "query", aQuery);
|
||||
AppendPointerWithRva(line, "outResult", aOutResult);
|
||||
AppendGpsRouteProducerQuerySummary(line, aQuery);
|
||||
AppendReturnRva(line, __builtin_return_address(0));
|
||||
LogRed4ext(line.str());
|
||||
}
|
||||
|
||||
GpsEdgeCostStats stats{};
|
||||
auto* previousStats = gActiveGpsEdgeCostStats;
|
||||
const auto previousRouteProducerCall = gActiveGpsRouteProducerCall;
|
||||
gActiveGpsEdgeCostStats = &stats;
|
||||
gActiveGpsRouteProducerCall = callCount;
|
||||
|
||||
int32_t result = 0x80000008;
|
||||
if (gOriginalGpsRouteProducer)
|
||||
{
|
||||
result = gOriginalGpsRouteProducer(aGraph, aQuery, aOutResult);
|
||||
}
|
||||
|
||||
gActiveGpsEdgeCostStats = previousStats;
|
||||
gActiveGpsRouteProducerCall = previousRouteProducerCall;
|
||||
|
||||
if (shouldLog)
|
||||
{
|
||||
std::ostringstream line;
|
||||
line << "hook GPSRouteProducer result call=" << callCount << " value=0x" << std::hex
|
||||
<< static_cast<uint32_t>(result) << std::dec;
|
||||
AppendUint32Field(line, "out_u0c", aOutResult, 0x0C);
|
||||
AppendUint32Field(line, "out_u1c", aOutResult, 0x1C);
|
||||
AppendUint32Field(line, "out_u20", aOutResult, 0x20);
|
||||
AppendUint32Field(line, "out_u24", aOutResult, 0x24);
|
||||
AppendUint32Field(line, "out_u2c", aOutResult, 0x2C);
|
||||
AppendUint32Field(line, "out_u30lo", aOutResult, 0x30);
|
||||
AppendUint32Field(line, "out_u34hi", aOutResult, 0x34);
|
||||
AppendUint16Field(line, "out_flags40", aOutResult, 0x40);
|
||||
AppendByteField(line, "out_state42", aOutResult, 0x42);
|
||||
AppendGpsEdgeCostStats(line, stats);
|
||||
LogRed4ext(line.str());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t DetourGpsSearch(void* aGraph, uint64_t aStartHandle, uint64_t aTargetHandle, void* aStartPoint,
|
||||
void* aTargetPoint, void* aCostProvider, void* aOutPath, uint32_t* aOutCount)
|
||||
{
|
||||
constexpr uint32_t kMaxCalls = 96;
|
||||
constexpr uint32_t kMaxCalls = 384;
|
||||
|
||||
uint32_t callCount = 0;
|
||||
bool shouldLog = false;
|
||||
@@ -2557,7 +2924,11 @@ int32_t DetourGpsSearch(void* aGraph, uint64_t aStartHandle, uint64_t aTargetHan
|
||||
AppendVector3Pointer(line, "targetPoint", aTargetPoint);
|
||||
AppendPointerWithRva(line, "outPath", aOutPath);
|
||||
AppendPointerWithRva(line, "outCount", aOutCount);
|
||||
AppendGpsCostProviderSummary(line, "provider", aCostProvider);
|
||||
AppendGpsCostProviderCompact(line, "provider", aCostProvider);
|
||||
if (gActiveGpsRouteProducerCall != UINT32_MAX)
|
||||
{
|
||||
line << " routeProducerCall=" << gActiveGpsRouteProducerCall;
|
||||
}
|
||||
AppendReturnRva(line, __builtin_return_address(0));
|
||||
LogRed4ext(line.str());
|
||||
}
|
||||
@@ -2591,6 +2962,10 @@ float DetourGpsEdgeCost(void* aCostProvider, void* aCurrentState, void* aNeighbo
|
||||
void* aPreviousSegment, void* aPreviousPoint, uint64_t aCurrentHandle, void* aCurrentSegment,
|
||||
void* aCurrentPoint, uint64_t aNeighborHandle, void* aNeighborSegment, void* aNeighborPoint)
|
||||
{
|
||||
const auto returnAddress = __builtin_return_address(0);
|
||||
uintptr_t returnRva = 0;
|
||||
TryGetImageRva(returnAddress, returnRva);
|
||||
|
||||
float result = 0.0f;
|
||||
if (gOriginalGpsEdgeCost)
|
||||
{
|
||||
@@ -2602,6 +2977,12 @@ float DetourGpsEdgeCost(void* aCostProvider, void* aCurrentState, void* aNeighbo
|
||||
const auto sourceClass = ReadGpsPointClass(aCurrentPoint);
|
||||
const auto neighborClass = ReadGpsPointClass(aNeighborPoint);
|
||||
|
||||
if (gActiveGpsEdgeCostStats)
|
||||
{
|
||||
NoteGpsEdgeCostStats(*gActiveGpsEdgeCostStats, sourceClass, neighborClass, result, returnRva, aCurrentHandle,
|
||||
aNeighborHandle);
|
||||
}
|
||||
|
||||
float multiplier = 0.0f;
|
||||
const auto hasMultiplier = sourceClass < 64 &&
|
||||
TryReadFloatField(aCostProvider, 0x08 + static_cast<uintptr_t>(sourceClass) * sizeof(float),
|
||||
@@ -2617,7 +2998,7 @@ float DetourGpsEdgeCost(void* aCostProvider, void* aCurrentState, void* aNeighbo
|
||||
{
|
||||
classCallCount = gGpsEdgeCostClassLogCounts[sourceClass]++;
|
||||
}
|
||||
shouldLog = callCount < 256 || (sourceClass < 64 && classCallCount < 4);
|
||||
shouldLog = callCount < 32 || (sourceClass < 64 && classCallCount < 1);
|
||||
}
|
||||
|
||||
if (shouldLog)
|
||||
@@ -2647,7 +3028,7 @@ float DetourGpsEdgeCost(void* aCostProvider, void* aCurrentState, void* aNeighbo
|
||||
AppendGpsPointSummary(line, "currentPoint", aCurrentPoint);
|
||||
AppendPointerWithRva(line, "neighborSegment", aNeighborSegment);
|
||||
AppendGpsPointSummary(line, "neighborPoint", aNeighborPoint);
|
||||
AppendReturnRva(line, __builtin_return_address(0));
|
||||
AppendReturnRva(line, returnAddress);
|
||||
LogRed4ext(line.str());
|
||||
}
|
||||
|
||||
@@ -2980,6 +3361,9 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
||||
AttachProbeHook("GPSQueryStatus 0xaa5704", kGpsQueryStatusRva,
|
||||
reinterpret_cast<void*>(&DetourGpsQueryStatus),
|
||||
reinterpret_cast<void**>(&gOriginalGpsQueryStatus));
|
||||
AttachProbeHook("GPSRouteProducer 0x44cc7c", kGpsRouteProducerRva,
|
||||
reinterpret_cast<void*>(&DetourGpsRouteProducer),
|
||||
reinterpret_cast<void**>(&gOriginalGpsRouteProducer));
|
||||
AttachProbeHook("GPSSearch 0x44f054", kGpsSearchRva, reinterpret_cast<void*>(&DetourGpsSearch),
|
||||
reinterpret_cast<void**>(&gOriginalGpsSearch));
|
||||
AttachProbeHook("GPSEdgeCost 0x44f838", kGpsEdgeCostRva, reinterpret_cast<void*>(&DetourGpsEdgeCost),
|
||||
@@ -3103,6 +3487,7 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
||||
DetachProbeHook("GPSQueryDispatch 0x70a570", kGpsQueryDispatchRva);
|
||||
DetachProbeHook("GPSQueryResultFetch 0x7094b8", kGpsQueryResultFetchRva);
|
||||
DetachProbeHook("GPSQueryStatus 0xaa5704", kGpsQueryStatusRva);
|
||||
DetachProbeHook("GPSRouteProducer 0x44cc7c", kGpsRouteProducerRva);
|
||||
DetachProbeHook("GPSSearch 0x44f054", kGpsSearchRva);
|
||||
DetachProbeHook("GPSEdgeCost 0x44f838", kGpsEdgeCostRva);
|
||||
DetachProbeHook("GPSSystem/Tick", kGpsSystemTickRva);
|
||||
|
||||
Reference in New Issue
Block a user