Track GPS query status lifecycle
This commit is contained in:
@@ -53,9 +53,14 @@ Current behavior:
|
|||||||
native registration cluster:
|
native registration cluster:
|
||||||
`0x29bd128` (`RunGPSQuery` body), `0x29bd254` (`UpdateGPSQuery` body),
|
`0x29bd128` (`RunGPSQuery` body), `0x29bd254` (`UpdateGPSQuery` body),
|
||||||
`0x70a42c` (shared query submitter), `0x70a570` (low-level query dispatch),
|
`0x70a42c` (shared query submitter), `0x70a570` (low-level query dispatch),
|
||||||
and `0x7094b8` (query result/path fetch).
|
`0x7094b8` (query result/path fetch), and `0xaa5704` (query status check).
|
||||||
- Logs query endpoints, returned query IDs, shared submitter return RVAs, query
|
- Logs query endpoints, returned query IDs, shared submitter return RVAs, query
|
||||||
state fields, result-fetch success, and summarized path buffers/point counts.
|
state fields, status values, result-fetch success, and summarized path
|
||||||
|
buffers/point counts.
|
||||||
|
- The active probe now records query IDs returned from `0x70a42c` and always
|
||||||
|
logs result/status polling for those tracked IDs. Startup polling of query
|
||||||
|
IDs `0`/`1` is sampled only briefly so it cannot exhaust the route-click log
|
||||||
|
budget.
|
||||||
- Resolves the native mappin system when one of those paths fires, logs relevant
|
- Resolves the native mappin system when one of those paths fires, logs relevant
|
||||||
vtable slot addresses, and temporarily hooks the route-adjacent slots.
|
vtable slot addresses, and temporarily hooks the route-adjacent slots.
|
||||||
|
|
||||||
@@ -79,7 +84,7 @@ Current route-probe focus:
|
|||||||
classified as journal metadata)
|
classified as journal metadata)
|
||||||
- route-build candidate called by the bridge: `0x5625a4`
|
- route-build candidate called by the bridge: `0x5625a4`
|
||||||
- GPS query lifecycle: `0x29bd128`, `0x29bd254`, `0x70a42c`, `0x70a570`,
|
- GPS query lifecycle: `0x29bd128`, `0x29bd254`, `0x70a42c`, `0x70a570`,
|
||||||
`0x7094b8`
|
`0x7094b8`, `0xaa5704`
|
||||||
|
|
||||||
Quest/objective pins did not fire the mappin tracking hooks in live tests. The
|
Quest/objective pins did not fire the mappin tracking hooks in live tests. The
|
||||||
REDscript decompile shows that those pins call `JournalManager.TrackEntry`
|
REDscript decompile shows that those pins call `JournalManager.TrackEntry`
|
||||||
@@ -134,6 +139,24 @@ Current static lead:
|
|||||||
so return RVAs and query IDs are important for separating map GPS from traffic
|
so return RVAs and query IDs are important for separating map GPS from traffic
|
||||||
or AI path requests.
|
or AI path requests.
|
||||||
|
|
||||||
|
Latest GPS-query finding:
|
||||||
|
|
||||||
|
- During a controlled route test, the normal world-map GPS path did not call
|
||||||
|
the script-native `RunGPSQuery`/`UpdateGPSQuery` bodies.
|
||||||
|
- Each deliberate quest/custom route click called the shared submitter
|
||||||
|
`0x70a42c` from return RVA `0x8d20d4`, then returned query IDs `3`, `4`, `5`,
|
||||||
|
and `6` for the three quest routes plus the custom pin.
|
||||||
|
- Each submitted route produced three `0x70a570` dispatches: current/player
|
||||||
|
position, a nearby snapped/lane position, then the destination position.
|
||||||
|
- The dense log stream immediately after Space-to-Continue was repeated
|
||||||
|
`0x7094b8` result polling for startup query IDs `0`/`1`, matching the HUD /
|
||||||
|
minimap route initialization delay. The next probe tracks submitted IDs so
|
||||||
|
route-click completion can be captured without being drowned by startup
|
||||||
|
polling.
|
||||||
|
- Static disassembly confirms `0xaa5704` takes `(manager, queryId)` and returns
|
||||||
|
a small status code; one caller checks for value `1` as the completed-query
|
||||||
|
state.
|
||||||
|
|
||||||
Build and install from the Fedora toolbox:
|
Build and install from the Fedora toolbox:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -92,6 +92,9 @@ struct Sdk
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
constexpr uint32_t kGameStateRunning = 2;
|
constexpr uint32_t kGameStateRunning = 2;
|
||||||
|
constexpr bool kEnableVerboseJournalListenerHooks = false;
|
||||||
|
constexpr bool kEnableVerboseRouteObserverHooks = false;
|
||||||
|
constexpr bool kEnableVerboseMappinRouteState = false;
|
||||||
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;
|
||||||
@@ -146,6 +149,7 @@ constexpr uintptr_t kUpdateGpsQueryBodyRva = 0x29BD254;
|
|||||||
constexpr uintptr_t kGpsQuerySubmitRva = 0x070A42C;
|
constexpr uintptr_t kGpsQuerySubmitRva = 0x070A42C;
|
||||||
constexpr uintptr_t kGpsQueryDispatchRva = 0x070A570;
|
constexpr uintptr_t kGpsQueryDispatchRva = 0x070A570;
|
||||||
constexpr uintptr_t kGpsQueryResultFetchRva = 0x07094B8;
|
constexpr uintptr_t kGpsQueryResultFetchRva = 0x07094B8;
|
||||||
|
constexpr uintptr_t kGpsQueryStatusRva = 0x0AA5704;
|
||||||
|
|
||||||
HMODULE gModule = nullptr;
|
HMODULE gModule = nullptr;
|
||||||
std::mutex gLogMutex;
|
std::mutex gLogMutex;
|
||||||
@@ -205,6 +209,7 @@ uint32_t gUpdateGpsQueryBodyLogCount = 0;
|
|||||||
uint32_t gGpsQuerySubmitLogCount = 0;
|
uint32_t gGpsQuerySubmitLogCount = 0;
|
||||||
uint32_t gGpsQueryDispatchLogCount = 0;
|
uint32_t gGpsQueryDispatchLogCount = 0;
|
||||||
uint32_t gGpsQueryResultFetchLogCount = 0;
|
uint32_t gGpsQueryResultFetchLogCount = 0;
|
||||||
|
uint32_t gGpsQueryStatusLogCount = 0;
|
||||||
uint64_t gLogStartTick = 0;
|
uint64_t gLogStartTick = 0;
|
||||||
uint64_t gLogFrequency = 0;
|
uint64_t gLogFrequency = 0;
|
||||||
void* gMappinSetTrackedTarget = nullptr;
|
void* gMappinSetTrackedTarget = nullptr;
|
||||||
@@ -219,6 +224,21 @@ void* gObserver1ServiceRouteLookupTarget = nullptr;
|
|||||||
bool gMappinSlotHookAttachAttempted = false;
|
bool gMappinSlotHookAttachAttempted = false;
|
||||||
bool gObserver1ServiceRouteLookupHookAttachAttempted = false;
|
bool gObserver1ServiceRouteLookupHookAttachAttempted = false;
|
||||||
|
|
||||||
|
struct TrackedGpsQuery
|
||||||
|
{
|
||||||
|
bool active = false;
|
||||||
|
uint32_t id = 0;
|
||||||
|
void* manager = nullptr;
|
||||||
|
uintptr_t submitReturnRva = 0;
|
||||||
|
uint32_t submitCall = 0;
|
||||||
|
uint32_t resultFetchCalls = 0;
|
||||||
|
uint32_t statusCalls = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::mutex gTrackedGpsQueryMutex;
|
||||||
|
std::array<TrackedGpsQuery, 32> gTrackedGpsQueries{};
|
||||||
|
uint32_t gTrackedGpsQueryNext = 0;
|
||||||
|
|
||||||
using ProbeFunc = void (*)(void* aThis, void* a2, void* a3, void* a4);
|
using ProbeFunc = void (*)(void* aThis, void* a2, void* a3, void* a4);
|
||||||
using JournalTrackEntryFunc = void (*)(void* aThis, void* aEntryHandle);
|
using JournalTrackEntryFunc = void (*)(void* aThis, void* aEntryHandle);
|
||||||
using ScriptNativeVoidFunc = void (*)(void* aThis, void* aStack, void* aResult);
|
using ScriptNativeVoidFunc = void (*)(void* aThis, void* aStack, void* aResult);
|
||||||
@@ -253,6 +273,7 @@ using UpdateGpsQueryBodyFunc = bool (*)(void* aThis, uint32_t aQueryId, void* aO
|
|||||||
using GpsQuerySubmitFunc = int32_t (*)(void* aManager, void* aQuery);
|
using GpsQuerySubmitFunc = int32_t (*)(void* aManager, void* aQuery);
|
||||||
using GpsQueryDispatchFunc = void (*)(void* aRuntimeQuery, void* aTargetPosition, void* aArg3, void* aArg4);
|
using GpsQueryDispatchFunc = void (*)(void* aRuntimeQuery, void* aTargetPosition, void* aArg3, void* aArg4);
|
||||||
using GpsQueryResultFetchFunc = bool (*)(void* aManager, uint32_t aQueryId, void* aOutPath);
|
using GpsQueryResultFetchFunc = bool (*)(void* aManager, uint32_t aQueryId, void* aOutPath);
|
||||||
|
using GpsQueryStatusFunc = int32_t (*)(void* aManager, uint32_t aQueryId);
|
||||||
ProbeFunc gOriginalGpsSystemTick = nullptr;
|
ProbeFunc gOriginalGpsSystemTick = nullptr;
|
||||||
JournalTrackEntryFunc gOriginalJournalTrackEntry = nullptr;
|
JournalTrackEntryFunc gOriginalJournalTrackEntry = nullptr;
|
||||||
ScriptNativeVoidFunc gOriginalFrameMappinPathWrapper = nullptr;
|
ScriptNativeVoidFunc gOriginalFrameMappinPathWrapper = nullptr;
|
||||||
@@ -303,6 +324,7 @@ UpdateGpsQueryBodyFunc gOriginalUpdateGpsQueryBody = nullptr;
|
|||||||
GpsQuerySubmitFunc gOriginalGpsQuerySubmit = nullptr;
|
GpsQuerySubmitFunc gOriginalGpsQuerySubmit = nullptr;
|
||||||
GpsQueryDispatchFunc gOriginalGpsQueryDispatch = nullptr;
|
GpsQueryDispatchFunc gOriginalGpsQueryDispatch = nullptr;
|
||||||
GpsQueryResultFetchFunc gOriginalGpsQueryResultFetch = nullptr;
|
GpsQueryResultFetchFunc gOriginalGpsQueryResultFetch = nullptr;
|
||||||
|
GpsQueryStatusFunc gOriginalGpsQueryStatus = nullptr;
|
||||||
|
|
||||||
std::filesystem::path GetLogPath()
|
std::filesystem::path GetLogPath()
|
||||||
{
|
{
|
||||||
@@ -390,6 +412,17 @@ bool IsInImage(const void* aPointer)
|
|||||||
return imageBase && imageEnd && address >= imageBase && address < imageEnd;
|
return imageBase && imageEnd && address >= imageBase && address < imageEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TryGetImageRva(const void* aPointer, uintptr_t& aRva)
|
||||||
|
{
|
||||||
|
if (!IsInImage(aPointer))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
aRva = reinterpret_cast<uintptr_t>(aPointer) - GetImageBase();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void AppendPointerWithRva(std::ostringstream& aLine, const char* aLabel, const void* aPointer)
|
void AppendPointerWithRva(std::ostringstream& aLine, const char* aLabel, const void* aPointer)
|
||||||
{
|
{
|
||||||
aLine << " " << aLabel << "=" << aPointer;
|
aLine << " " << aLabel << "=" << aPointer;
|
||||||
@@ -710,6 +743,81 @@ void AppendPathBufferSummary(std::ostringstream& aLine, const char* aPrefix, voi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TrackGpsQuery(uint32_t aQueryId, void* aManager, uintptr_t aSubmitReturnRva, uint32_t aSubmitCall)
|
||||||
|
{
|
||||||
|
if (aQueryId == UINT32_MAX)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard lock(gTrackedGpsQueryMutex);
|
||||||
|
|
||||||
|
for (auto& query : gTrackedGpsQueries)
|
||||||
|
{
|
||||||
|
if (query.active && query.id == aQueryId && query.manager == aManager)
|
||||||
|
{
|
||||||
|
query.submitReturnRva = aSubmitReturnRva;
|
||||||
|
query.submitCall = aSubmitCall;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& query = gTrackedGpsQueries[gTrackedGpsQueryNext++ % gTrackedGpsQueries.size()];
|
||||||
|
query.active = true;
|
||||||
|
query.id = aQueryId;
|
||||||
|
query.manager = aManager;
|
||||||
|
query.submitReturnRva = aSubmitReturnRva;
|
||||||
|
query.submitCall = aSubmitCall;
|
||||||
|
query.resultFetchCalls = 0;
|
||||||
|
query.statusCalls = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NoteTrackedGpsQueryResultFetch(uint32_t aQueryId, void* aManager, TrackedGpsQuery& aSnapshot,
|
||||||
|
uint32_t& aPerQueryCall)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(gTrackedGpsQueryMutex);
|
||||||
|
|
||||||
|
for (auto& query : gTrackedGpsQueries)
|
||||||
|
{
|
||||||
|
if (!query.active || query.id != aQueryId || query.manager != aManager)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
aPerQueryCall = query.resultFetchCalls++;
|
||||||
|
aSnapshot = query;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NoteTrackedGpsQueryStatus(uint32_t aQueryId, void* aManager, TrackedGpsQuery& aSnapshot,
|
||||||
|
uint32_t& aPerQueryCall)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(gTrackedGpsQueryMutex);
|
||||||
|
|
||||||
|
for (auto& query : gTrackedGpsQueries)
|
||||||
|
{
|
||||||
|
if (!query.active || query.id != aQueryId || query.manager != aManager)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
aPerQueryCall = query.statusCalls++;
|
||||||
|
aSnapshot = query;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppendTrackedGpsQuery(std::ostringstream& aLine, const TrackedGpsQuery& aQuery)
|
||||||
|
{
|
||||||
|
aLine << " submitCall=" << aQuery.submitCall << " submitRetRva=0x" << std::hex << aQuery.submitReturnRva
|
||||||
|
<< std::dec;
|
||||||
|
}
|
||||||
|
|
||||||
void AppendRouteRefFields(std::ostringstream& aLine, const char* aPrefix, void* aRouteRef)
|
void AppendRouteRefFields(std::ostringstream& aLine, const char* aPrefix, void* aRouteRef)
|
||||||
{
|
{
|
||||||
AppendPointerWithRva(aLine, aPrefix, aRouteRef);
|
AppendPointerWithRva(aLine, aPrefix, aRouteRef);
|
||||||
@@ -730,6 +838,11 @@ void AppendRouteRefFields(std::ostringstream& aLine, const char* aPrefix, void*
|
|||||||
|
|
||||||
void LogMappinRouteCollections(const char* aName, uint32_t aCount, void* aSystem)
|
void LogMappinRouteCollections(const char* aName, uint32_t aCount, void* aSystem)
|
||||||
{
|
{
|
||||||
|
if (!kEnableVerboseMappinRouteState)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!aSystem)
|
if (!aSystem)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -1133,7 +1246,6 @@ void DetourJournalTrackEntry(void* aThis, void* aEntryHandle)
|
|||||||
AppendReturnRva(line, __builtin_return_address(0));
|
AppendReturnRva(line, __builtin_return_address(0));
|
||||||
LogRed4ext(line.str());
|
LogRed4ext(line.str());
|
||||||
|
|
||||||
LogJournalListeners(callCount, aThis);
|
|
||||||
++gJournalTrackEntryLogCount;
|
++gJournalTrackEntryLogCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1906,6 +2018,10 @@ int32_t DetourGpsQuerySubmit(void* aManager, void* aQuery)
|
|||||||
{
|
{
|
||||||
constexpr uint32_t kMaxCalls = 128;
|
constexpr uint32_t kMaxCalls = 128;
|
||||||
|
|
||||||
|
const auto returnAddress = __builtin_return_address(0);
|
||||||
|
uintptr_t returnRva = 0;
|
||||||
|
TryGetImageRva(returnAddress, returnRva);
|
||||||
|
|
||||||
const auto callCount = gGpsQuerySubmitLogCount;
|
const auto callCount = gGpsQuerySubmitLogCount;
|
||||||
const auto shouldLog = callCount < kMaxCalls;
|
const auto shouldLog = callCount < kMaxCalls;
|
||||||
if (shouldLog)
|
if (shouldLog)
|
||||||
@@ -1920,7 +2036,7 @@ int32_t DetourGpsQuerySubmit(void* aManager, void* aQuery)
|
|||||||
AppendUint32Field(line, "query_f0c", aQuery, 0x0C);
|
AppendUint32Field(line, "query_f0c", aQuery, 0x0C);
|
||||||
AppendUint32Field(line, "query_fcc", aQuery, 0xCC);
|
AppendUint32Field(line, "query_fcc", aQuery, 0xCC);
|
||||||
AppendVector4Field(line, "query_pos58", aQuery, 0x58);
|
AppendVector4Field(line, "query_pos58", aQuery, 0x58);
|
||||||
AppendReturnRva(line, __builtin_return_address(0));
|
AppendReturnRva(line, returnAddress);
|
||||||
LogRed4ext(line.str());
|
LogRed4ext(line.str());
|
||||||
++gGpsQuerySubmitLogCount;
|
++gGpsQuerySubmitLogCount;
|
||||||
}
|
}
|
||||||
@@ -1931,6 +2047,11 @@ int32_t DetourGpsQuerySubmit(void* aManager, void* aQuery)
|
|||||||
result = gOriginalGpsQuerySubmit(aManager, aQuery);
|
result = gOriginalGpsQuerySubmit(aManager, aQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result >= 0)
|
||||||
|
{
|
||||||
|
TrackGpsQuery(static_cast<uint32_t>(result), aManager, returnRva, callCount);
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldLog)
|
if (shouldLog)
|
||||||
{
|
{
|
||||||
std::ostringstream line;
|
std::ostringstream line;
|
||||||
@@ -1969,20 +2090,11 @@ void DetourGpsQueryDispatch(void* aRuntimeQuery, void* aTargetPosition, void* aA
|
|||||||
|
|
||||||
bool DetourGpsQueryResultFetch(void* aManager, uint32_t aQueryId, void* aOutPath)
|
bool DetourGpsQueryResultFetch(void* aManager, uint32_t aQueryId, void* aOutPath)
|
||||||
{
|
{
|
||||||
constexpr uint32_t kMaxCalls = 128;
|
constexpr uint32_t kMaxUntrackedSamples = 32;
|
||||||
|
constexpr uint32_t kMaxTrackedSamplesPerQuery = 24;
|
||||||
|
|
||||||
const auto callCount = gGpsQueryResultFetchLogCount;
|
const auto callCount = gGpsQueryResultFetchLogCount++;
|
||||||
const auto shouldLog = callCount < kMaxCalls;
|
const auto returnAddress = __builtin_return_address(0);
|
||||||
if (shouldLog)
|
|
||||||
{
|
|
||||||
std::ostringstream line;
|
|
||||||
line << "hook GPSQueryResultFetch 0x7094b8 call=" << callCount << " queryId=" << aQueryId;
|
|
||||||
AppendPointerWithRva(line, "manager", aManager);
|
|
||||||
AppendPointerWithRva(line, "outPath", aOutPath);
|
|
||||||
AppendReturnRva(line, __builtin_return_address(0));
|
|
||||||
LogRed4ext(line.str());
|
|
||||||
++gGpsQueryResultFetchLogCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if (gOriginalGpsQueryResultFetch)
|
if (gOriginalGpsQueryResultFetch)
|
||||||
@@ -1990,10 +2102,25 @@ bool DetourGpsQueryResultFetch(void* aManager, uint32_t aQueryId, void* aOutPath
|
|||||||
result = gOriginalGpsQueryResultFetch(aManager, aQueryId, aOutPath);
|
result = gOriginalGpsQueryResultFetch(aManager, aQueryId, aOutPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TrackedGpsQuery trackedQuery{};
|
||||||
|
uint32_t perQueryCall = 0;
|
||||||
|
const auto isTracked = NoteTrackedGpsQueryResultFetch(aQueryId, aManager, trackedQuery, perQueryCall);
|
||||||
|
const auto shouldLog = (isTracked && (perQueryCall < kMaxTrackedSamplesPerQuery || result)) ||
|
||||||
|
(!isTracked && callCount < kMaxUntrackedSamples && aQueryId < 2);
|
||||||
|
|
||||||
if (shouldLog)
|
if (shouldLog)
|
||||||
{
|
{
|
||||||
std::ostringstream line;
|
std::ostringstream line;
|
||||||
line << "hook GPSQueryResultFetch result call=" << callCount << " value=" << static_cast<uint32_t>(result);
|
line << "hook GPSQueryResultFetch 0x7094b8 call=" << callCount << " queryId=" << aQueryId
|
||||||
|
<< " tracked=" << static_cast<uint32_t>(isTracked) << " perQueryCall=" << perQueryCall
|
||||||
|
<< " value=" << static_cast<uint32_t>(result);
|
||||||
|
if (isTracked)
|
||||||
|
{
|
||||||
|
AppendTrackedGpsQuery(line, trackedQuery);
|
||||||
|
}
|
||||||
|
AppendPointerWithRva(line, "manager", aManager);
|
||||||
|
AppendPointerWithRva(line, "outPath", aOutPath);
|
||||||
|
AppendReturnRva(line, returnAddress);
|
||||||
AppendPathBufferSummary(line, "outPath", aOutPath);
|
AppendPathBufferSummary(line, "outPath", aOutPath);
|
||||||
LogRed4ext(line.str());
|
LogRed4ext(line.str());
|
||||||
}
|
}
|
||||||
@@ -2001,6 +2128,44 @@ bool DetourGpsQueryResultFetch(void* aManager, uint32_t aQueryId, void* aOutPath
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t DetourGpsQueryStatus(void* aManager, uint32_t aQueryId)
|
||||||
|
{
|
||||||
|
constexpr uint32_t kMaxUntrackedSamples = 32;
|
||||||
|
constexpr uint32_t kMaxTrackedSamplesPerQuery = 24;
|
||||||
|
|
||||||
|
const auto callCount = gGpsQueryStatusLogCount++;
|
||||||
|
const auto returnAddress = __builtin_return_address(0);
|
||||||
|
|
||||||
|
int32_t result = 0;
|
||||||
|
if (gOriginalGpsQueryStatus)
|
||||||
|
{
|
||||||
|
result = gOriginalGpsQueryStatus(aManager, aQueryId);
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackedGpsQuery trackedQuery{};
|
||||||
|
uint32_t perQueryCall = 0;
|
||||||
|
const auto isTracked = NoteTrackedGpsQueryStatus(aQueryId, aManager, trackedQuery, perQueryCall);
|
||||||
|
const auto shouldLog = (isTracked && (perQueryCall < kMaxTrackedSamplesPerQuery || result != 0)) ||
|
||||||
|
(!isTracked && callCount < kMaxUntrackedSamples && aQueryId < 2);
|
||||||
|
|
||||||
|
if (shouldLog)
|
||||||
|
{
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "hook GPSQueryStatus 0xaa5704 call=" << callCount << " queryId=" << aQueryId
|
||||||
|
<< " tracked=" << static_cast<uint32_t>(isTracked) << " perQueryCall=" << perQueryCall
|
||||||
|
<< " value=" << result;
|
||||||
|
if (isTracked)
|
||||||
|
{
|
||||||
|
AppendTrackedGpsQuery(line, trackedQuery);
|
||||||
|
}
|
||||||
|
AppendPointerWithRva(line, "manager", aManager);
|
||||||
|
AppendReturnRva(line, returnAddress);
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void AttachProbeHook(const char* aName, uintptr_t aRva, void* aDetour, void** aOriginal)
|
void AttachProbeHook(const char* aName, uintptr_t aRva, void* aDetour, void** aOriginal)
|
||||||
{
|
{
|
||||||
if (!gSdk || !gSdk->hooking || !gSdk->hooking->Attach)
|
if (!gSdk || !gSdk->hooking || !gSdk->hooking->Attach)
|
||||||
@@ -2324,38 +2489,44 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
|||||||
AttachProbeHook("GPSQueryResultFetch 0x7094b8", kGpsQueryResultFetchRva,
|
AttachProbeHook("GPSQueryResultFetch 0x7094b8", kGpsQueryResultFetchRva,
|
||||||
reinterpret_cast<void*>(&DetourGpsQueryResultFetch),
|
reinterpret_cast<void*>(&DetourGpsQueryResultFetch),
|
||||||
reinterpret_cast<void**>(&gOriginalGpsQueryResultFetch));
|
reinterpret_cast<void**>(&gOriginalGpsQueryResultFetch));
|
||||||
|
AttachProbeHook("GPSQueryStatus 0xaa5704", kGpsQueryStatusRva,
|
||||||
|
reinterpret_cast<void*>(&DetourGpsQueryStatus),
|
||||||
|
reinterpret_cast<void**>(&gOriginalGpsQueryStatus));
|
||||||
AttachProbeHook("GPSSystem/Tick", kGpsSystemTickRva, reinterpret_cast<void*>(&DetourGpsSystemTick),
|
AttachProbeHook("GPSSystem/Tick", kGpsSystemTickRva, reinterpret_cast<void*>(&DetourGpsSystemTick),
|
||||||
reinterpret_cast<void**>(&gOriginalGpsSystemTick));
|
reinterpret_cast<void**>(&gOriginalGpsSystemTick));
|
||||||
AttachProbeHook("JournalManager::TrackEntry impl", kJournalTrackEntryImplRva,
|
AttachProbeHook("JournalManager::TrackEntry impl", kJournalTrackEntryImplRva,
|
||||||
reinterpret_cast<void*>(&DetourJournalTrackEntry),
|
reinterpret_cast<void*>(&DetourJournalTrackEntry),
|
||||||
reinterpret_cast<void**>(&gOriginalJournalTrackEntry));
|
reinterpret_cast<void**>(&gOriginalJournalTrackEntry));
|
||||||
AttachProbeHook("JournalListener::Objective vt28", kJournalListenerObjectiveVt28Rva,
|
if (kEnableVerboseJournalListenerHooks)
|
||||||
reinterpret_cast<void*>(&DetourJournalListenerObjectiveVt28),
|
{
|
||||||
reinterpret_cast<void**>(&gOriginalJournalListenerObjectiveVt28));
|
AttachProbeHook("JournalListener::Objective vt28", kJournalListenerObjectiveVt28Rva,
|
||||||
AttachProbeHook("JournalListener::Objective vt30", kJournalListenerObjectiveVt30Rva,
|
reinterpret_cast<void*>(&DetourJournalListenerObjectiveVt28),
|
||||||
reinterpret_cast<void*>(&DetourJournalListenerObjectiveVt30),
|
reinterpret_cast<void**>(&gOriginalJournalListenerObjectiveVt28));
|
||||||
reinterpret_cast<void**>(&gOriginalJournalListenerObjectiveVt30));
|
AttachProbeHook("JournalListener::Objective vt30", kJournalListenerObjectiveVt30Rva,
|
||||||
AttachProbeHook("JournalListener::Route vt28", kJournalListenerRouteVt28Rva,
|
reinterpret_cast<void*>(&DetourJournalListenerObjectiveVt30),
|
||||||
reinterpret_cast<void*>(&DetourJournalListenerRouteVt28),
|
reinterpret_cast<void**>(&gOriginalJournalListenerObjectiveVt30));
|
||||||
reinterpret_cast<void**>(&gOriginalJournalListenerRouteVt28));
|
AttachProbeHook("JournalListener::Route vt28", kJournalListenerRouteVt28Rva,
|
||||||
AttachProbeHook("JournalListener::Route vt30", kJournalListenerRouteVt30Rva,
|
reinterpret_cast<void*>(&DetourJournalListenerRouteVt28),
|
||||||
reinterpret_cast<void*>(&DetourJournalListenerRouteVt30),
|
reinterpret_cast<void**>(&gOriginalJournalListenerRouteVt28));
|
||||||
reinterpret_cast<void**>(&gOriginalJournalListenerRouteVt30));
|
AttachProbeHook("JournalListener::Route vt30", kJournalListenerRouteVt30Rva,
|
||||||
AttachProbeHook("JournalListener::RouteAlt vt28", kJournalListenerRouteAltVt28Rva,
|
reinterpret_cast<void*>(&DetourJournalListenerRouteVt30),
|
||||||
reinterpret_cast<void*>(&DetourJournalListenerRouteAltVt28),
|
reinterpret_cast<void**>(&gOriginalJournalListenerRouteVt30));
|
||||||
reinterpret_cast<void**>(&gOriginalJournalListenerRouteAltVt28));
|
AttachProbeHook("JournalListener::RouteAlt vt28", kJournalListenerRouteAltVt28Rva,
|
||||||
AttachProbeHook("JournalListener::RouteAlt vt30", kJournalListenerRouteAltVt30Rva,
|
reinterpret_cast<void*>(&DetourJournalListenerRouteAltVt28),
|
||||||
reinterpret_cast<void*>(&DetourJournalListenerRouteAltVt30),
|
reinterpret_cast<void**>(&gOriginalJournalListenerRouteAltVt28));
|
||||||
reinterpret_cast<void**>(&gOriginalJournalListenerRouteAltVt30));
|
AttachProbeHook("JournalListener::RouteAlt vt30", kJournalListenerRouteAltVt30Rva,
|
||||||
AttachProbeHook("JournalListener::UI vt28", kJournalListenerUiVt28Rva,
|
reinterpret_cast<void*>(&DetourJournalListenerRouteAltVt30),
|
||||||
reinterpret_cast<void*>(&DetourJournalListenerUiVt28),
|
reinterpret_cast<void**>(&gOriginalJournalListenerRouteAltVt30));
|
||||||
reinterpret_cast<void**>(&gOriginalJournalListenerUiVt28));
|
AttachProbeHook("JournalListener::UI vt28", kJournalListenerUiVt28Rva,
|
||||||
AttachProbeHook("JournalListener::UI vt30", kJournalListenerUiVt30Rva,
|
reinterpret_cast<void*>(&DetourJournalListenerUiVt28),
|
||||||
reinterpret_cast<void*>(&DetourJournalListenerUiVt30),
|
reinterpret_cast<void**>(&gOriginalJournalListenerUiVt28));
|
||||||
reinterpret_cast<void**>(&gOriginalJournalListenerUiVt30));
|
AttachProbeHook("JournalListener::UI vt30", kJournalListenerUiVt30Rva,
|
||||||
AttachProbeHook("JournalListener::Tracker vt28", kJournalListenerTrackerVt28Rva,
|
reinterpret_cast<void*>(&DetourJournalListenerUiVt30),
|
||||||
reinterpret_cast<void*>(&DetourJournalListenerTrackerVt28),
|
reinterpret_cast<void**>(&gOriginalJournalListenerUiVt30));
|
||||||
reinterpret_cast<void**>(&gOriginalJournalListenerTrackerVt28));
|
AttachProbeHook("JournalListener::Tracker vt28", kJournalListenerTrackerVt28Rva,
|
||||||
|
reinterpret_cast<void*>(&DetourJournalListenerTrackerVt28),
|
||||||
|
reinterpret_cast<void**>(&gOriginalJournalListenerTrackerVt28));
|
||||||
|
}
|
||||||
AttachProbeHook("JournalRouteBridge::Update candidate", kJournalRouteBridgeRva,
|
AttachProbeHook("JournalRouteBridge::Update candidate", kJournalRouteBridgeRva,
|
||||||
reinterpret_cast<void*>(&DetourJournalRouteBridge),
|
reinterpret_cast<void*>(&DetourJournalRouteBridge),
|
||||||
reinterpret_cast<void**>(&gOriginalJournalRouteBridge));
|
reinterpret_cast<void**>(&gOriginalJournalRouteBridge));
|
||||||
@@ -2374,24 +2545,27 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
|||||||
AttachProbeHook("RouteBuildCandidate 0x5625a4", kRouteBuildCandidateRva,
|
AttachProbeHook("RouteBuildCandidate 0x5625a4", kRouteBuildCandidateRva,
|
||||||
reinterpret_cast<void*>(&DetourRouteBuildCandidate),
|
reinterpret_cast<void*>(&DetourRouteBuildCandidate),
|
||||||
reinterpret_cast<void**>(&gOriginalRouteBuildCandidate));
|
reinterpret_cast<void**>(&gOriginalRouteBuildCandidate));
|
||||||
AttachProbeHook("RouteObserver0::Activate slot48", kRouteObserver0ActivateRva,
|
if (kEnableVerboseRouteObserverHooks)
|
||||||
reinterpret_cast<void*>(&DetourRouteObserver0Activate),
|
{
|
||||||
reinterpret_cast<void**>(&gOriginalRouteObserver0Activate));
|
AttachProbeHook("RouteObserver0::Activate slot48", kRouteObserver0ActivateRva,
|
||||||
AttachProbeHook("RouteObserver1::Activate slot48", kRouteObserver1ActivateRva,
|
reinterpret_cast<void*>(&DetourRouteObserver0Activate),
|
||||||
reinterpret_cast<void*>(&DetourRouteObserver1Activate),
|
reinterpret_cast<void**>(&gOriginalRouteObserver0Activate));
|
||||||
reinterpret_cast<void**>(&gOriginalRouteObserver1Activate));
|
AttachProbeHook("RouteObserver1::Activate slot48", kRouteObserver1ActivateRva,
|
||||||
AttachProbeHook("RouteObserver23::Activate slot48", kRouteObserver23ActivateRva,
|
reinterpret_cast<void*>(&DetourRouteObserver1Activate),
|
||||||
reinterpret_cast<void*>(&DetourRouteObserver23Activate),
|
reinterpret_cast<void**>(&gOriginalRouteObserver1Activate));
|
||||||
reinterpret_cast<void**>(&gOriginalRouteObserver23Activate));
|
AttachProbeHook("RouteObserver23::Activate slot48", kRouteObserver23ActivateRva,
|
||||||
AttachProbeHook("RouteObserver0::Deactivate slot50", kRouteObserver0DeactivateRva,
|
reinterpret_cast<void*>(&DetourRouteObserver23Activate),
|
||||||
reinterpret_cast<void*>(&DetourRouteObserver0Deactivate),
|
reinterpret_cast<void**>(&gOriginalRouteObserver23Activate));
|
||||||
reinterpret_cast<void**>(&gOriginalRouteObserver0Deactivate));
|
AttachProbeHook("RouteObserver0::Deactivate slot50", kRouteObserver0DeactivateRva,
|
||||||
AttachProbeHook("RouteObserver1::Deactivate slot50", kRouteObserver1DeactivateRva,
|
reinterpret_cast<void*>(&DetourRouteObserver0Deactivate),
|
||||||
reinterpret_cast<void*>(&DetourRouteObserver1Deactivate),
|
reinterpret_cast<void**>(&gOriginalRouteObserver0Deactivate));
|
||||||
reinterpret_cast<void**>(&gOriginalRouteObserver1Deactivate));
|
AttachProbeHook("RouteObserver1::Deactivate slot50", kRouteObserver1DeactivateRva,
|
||||||
AttachProbeHook("RouteObserver23::Deactivate slot50", kRouteObserver23DeactivateRva,
|
reinterpret_cast<void*>(&DetourRouteObserver1Deactivate),
|
||||||
reinterpret_cast<void*>(&DetourRouteObserver23Deactivate),
|
reinterpret_cast<void**>(&gOriginalRouteObserver1Deactivate));
|
||||||
reinterpret_cast<void**>(&gOriginalRouteObserver23Deactivate));
|
AttachProbeHook("RouteObserver23::Deactivate slot50", kRouteObserver23DeactivateRva,
|
||||||
|
reinterpret_cast<void*>(&DetourRouteObserver23Deactivate),
|
||||||
|
reinterpret_cast<void**>(&gOriginalRouteObserver23Deactivate));
|
||||||
|
}
|
||||||
AttachProbeHook("FrameMappinPathWrapper", kFrameMappinPathWrapperRva,
|
AttachProbeHook("FrameMappinPathWrapper", kFrameMappinPathWrapperRva,
|
||||||
reinterpret_cast<void*>(&DetourFrameMappinPathWrapper),
|
reinterpret_cast<void*>(&DetourFrameMappinPathWrapper),
|
||||||
reinterpret_cast<void**>(&gOriginalFrameMappinPathWrapper));
|
reinterpret_cast<void**>(&gOriginalFrameMappinPathWrapper));
|
||||||
@@ -2436,29 +2610,36 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
|||||||
DetachProbeHook("GPSQuerySubmit 0x70a42c", kGpsQuerySubmitRva);
|
DetachProbeHook("GPSQuerySubmit 0x70a42c", kGpsQuerySubmitRva);
|
||||||
DetachProbeHook("GPSQueryDispatch 0x70a570", kGpsQueryDispatchRva);
|
DetachProbeHook("GPSQueryDispatch 0x70a570", kGpsQueryDispatchRva);
|
||||||
DetachProbeHook("GPSQueryResultFetch 0x7094b8", kGpsQueryResultFetchRva);
|
DetachProbeHook("GPSQueryResultFetch 0x7094b8", kGpsQueryResultFetchRva);
|
||||||
|
DetachProbeHook("GPSQueryStatus 0xaa5704", kGpsQueryStatusRva);
|
||||||
DetachProbeHook("GPSSystem/Tick", kGpsSystemTickRva);
|
DetachProbeHook("GPSSystem/Tick", kGpsSystemTickRva);
|
||||||
DetachProbeHook("JournalManager::TrackEntry impl", kJournalTrackEntryImplRva);
|
DetachProbeHook("JournalManager::TrackEntry impl", kJournalTrackEntryImplRva);
|
||||||
DetachProbeHook("JournalListener::Objective vt28", kJournalListenerObjectiveVt28Rva);
|
if (kEnableVerboseJournalListenerHooks)
|
||||||
DetachProbeHook("JournalListener::Objective vt30", kJournalListenerObjectiveVt30Rva);
|
{
|
||||||
DetachProbeHook("JournalListener::Route vt28", kJournalListenerRouteVt28Rva);
|
DetachProbeHook("JournalListener::Objective vt28", kJournalListenerObjectiveVt28Rva);
|
||||||
DetachProbeHook("JournalListener::Route vt30", kJournalListenerRouteVt30Rva);
|
DetachProbeHook("JournalListener::Objective vt30", kJournalListenerObjectiveVt30Rva);
|
||||||
DetachProbeHook("JournalListener::RouteAlt vt28", kJournalListenerRouteAltVt28Rva);
|
DetachProbeHook("JournalListener::Route vt28", kJournalListenerRouteVt28Rva);
|
||||||
DetachProbeHook("JournalListener::RouteAlt vt30", kJournalListenerRouteAltVt30Rva);
|
DetachProbeHook("JournalListener::Route vt30", kJournalListenerRouteVt30Rva);
|
||||||
DetachProbeHook("JournalListener::UI vt28", kJournalListenerUiVt28Rva);
|
DetachProbeHook("JournalListener::RouteAlt vt28", kJournalListenerRouteAltVt28Rva);
|
||||||
DetachProbeHook("JournalListener::UI vt30", kJournalListenerUiVt30Rva);
|
DetachProbeHook("JournalListener::RouteAlt vt30", kJournalListenerRouteAltVt30Rva);
|
||||||
DetachProbeHook("JournalListener::Tracker vt28", kJournalListenerTrackerVt28Rva);
|
DetachProbeHook("JournalListener::UI vt28", kJournalListenerUiVt28Rva);
|
||||||
|
DetachProbeHook("JournalListener::UI vt30", kJournalListenerUiVt30Rva);
|
||||||
|
DetachProbeHook("JournalListener::Tracker vt28", kJournalListenerTrackerVt28Rva);
|
||||||
|
}
|
||||||
DetachProbeHook("JournalRouteBridge::Update candidate", kJournalRouteBridgeRva);
|
DetachProbeHook("JournalRouteBridge::Update candidate", kJournalRouteBridgeRva);
|
||||||
DetachProbeHook("MappinSystem::RouteEventEnqueue slot240", kMappinRouteEventEnqueueRva);
|
DetachProbeHook("MappinSystem::RouteEventEnqueue slot240", kMappinRouteEventEnqueueRva);
|
||||||
DetachProbeHook("MappinRouteEvent::Handle", kMappinRouteEventHandlerRva);
|
DetachProbeHook("MappinRouteEvent::Handle", kMappinRouteEventHandlerRva);
|
||||||
DetachProbeHook("MappinSystem::RouteActivate", kMappinRouteActivateRva);
|
DetachProbeHook("MappinSystem::RouteActivate", kMappinRouteActivateRva);
|
||||||
DetachProbeHook("MappinSystem::RouteDeactivate", kMappinRouteDeactivateRva);
|
DetachProbeHook("MappinSystem::RouteDeactivate", kMappinRouteDeactivateRva);
|
||||||
DetachProbeHook("RouteBuildCandidate 0x5625a4", kRouteBuildCandidateRva);
|
DetachProbeHook("RouteBuildCandidate 0x5625a4", kRouteBuildCandidateRva);
|
||||||
DetachProbeHook("RouteObserver0::Activate slot48", kRouteObserver0ActivateRva);
|
if (kEnableVerboseRouteObserverHooks)
|
||||||
DetachProbeHook("RouteObserver1::Activate slot48", kRouteObserver1ActivateRva);
|
{
|
||||||
DetachProbeHook("RouteObserver23::Activate slot48", kRouteObserver23ActivateRva);
|
DetachProbeHook("RouteObserver0::Activate slot48", kRouteObserver0ActivateRva);
|
||||||
DetachProbeHook("RouteObserver0::Deactivate slot50", kRouteObserver0DeactivateRva);
|
DetachProbeHook("RouteObserver1::Activate slot48", kRouteObserver1ActivateRva);
|
||||||
DetachProbeHook("RouteObserver1::Deactivate slot50", kRouteObserver1DeactivateRva);
|
DetachProbeHook("RouteObserver23::Activate slot48", kRouteObserver23ActivateRva);
|
||||||
DetachProbeHook("RouteObserver23::Deactivate slot50", kRouteObserver23DeactivateRva);
|
DetachProbeHook("RouteObserver0::Deactivate slot50", kRouteObserver0DeactivateRva);
|
||||||
|
DetachProbeHook("RouteObserver1::Deactivate slot50", kRouteObserver1DeactivateRva);
|
||||||
|
DetachProbeHook("RouteObserver23::Deactivate slot50", kRouteObserver23DeactivateRva);
|
||||||
|
}
|
||||||
DetachProbeHook("FrameMappinPathWrapper", kFrameMappinPathWrapperRva);
|
DetachProbeHook("FrameMappinPathWrapper", kFrameMappinPathWrapperRva);
|
||||||
DetachProbeHook("FrameMappinPathCore", kFrameMappinPathCoreRva);
|
DetachProbeHook("FrameMappinPathCore", kFrameMappinPathCoreRva);
|
||||||
DetachProbeHook("SetSelectedMappinWrapper", kSetSelectedMappinWrapperRva);
|
DetachProbeHook("SetSelectedMappinWrapper", kSetSelectedMappinWrapperRva);
|
||||||
|
|||||||
Reference in New Issue
Block a user