Dump GPS result object fields
This commit is contained in:
@@ -144,18 +144,29 @@ Latest GPS-query finding:
|
|||||||
- During a controlled route test, the normal world-map GPS path did not call
|
- During a controlled route test, the normal world-map GPS path did not call
|
||||||
the script-native `RunGPSQuery`/`UpdateGPSQuery` bodies.
|
the script-native `RunGPSQuery`/`UpdateGPSQuery` bodies.
|
||||||
- Each deliberate quest/custom route click called the shared submitter
|
- Each deliberate quest/custom route click called the shared submitter
|
||||||
`0x70a42c` from return RVA `0x8d20d4`, then returned query IDs `3`, `4`, `5`,
|
`0x70a42c` from return RVA `0x8d20d4`. In the 2026-06-20 19:03 run, the
|
||||||
and `6` for the three quest routes plus the custom pin.
|
deliberately plotted routes returned query IDs `17`, `18`, `19`, and `20`
|
||||||
|
for the side job, Sinnerman, Claire's Garage, and a custom pin.
|
||||||
- Each submitted route produced three `0x70a570` dispatches: current/player
|
- Each submitted route produced three `0x70a570` dispatches: current/player
|
||||||
position, a nearby snapped/lane position, then the destination position.
|
position, a nearby snapped/lane position, then the destination position.
|
||||||
- The dense log stream immediately after Space-to-Continue was repeated
|
- The dense log stream immediately after Space-to-Continue is repeated
|
||||||
`0x7094b8` result polling for startup query IDs `0`/`1`, matching the HUD /
|
`0x7094b8` result polling for startup/minimap route queries, matching the HUD
|
||||||
minimap route initialization delay. The next probe tracks submitted IDs so
|
route initialization delay.
|
||||||
route-click completion can be captured without being drowned by startup
|
- `GPSQueryResultFetch 0x7094b8` returning `1` is the route-solve completion
|
||||||
polling.
|
signal. The caller at return RVA `0x52069c` starts handling a completed
|
||||||
|
result, then the caller at return RVA `0x520783` drains result records.
|
||||||
|
The visible route record currently appears as a packed point/count pair in
|
||||||
|
the object passed as `outPath`: the deliberate routes produced `11`, `16`,
|
||||||
|
`15`, and `14` point-like counts.
|
||||||
- Static disassembly confirms `0xaa5704` takes `(manager, queryId)` and returns
|
- Static disassembly confirms `0xaa5704` takes `(manager, queryId)` and returns
|
||||||
a small status code; one caller checks for value `1` as the completed-query
|
a small status code; one caller checks for value `1`. Runtime logging shows
|
||||||
state.
|
this is HUD/display lifecycle polling rather than solve completion: it polls
|
||||||
|
the currently displayed query once per second and pauses when the minimap is
|
||||||
|
not rendered.
|
||||||
|
- The current installed probe adds a read-only dump of suspected result-object
|
||||||
|
fields around offsets `0x20` through `0x5f` on successful active-route
|
||||||
|
fetches. This is intended to identify whether the returned route is a raw
|
||||||
|
solver path, a smoothed draw path, or both.
|
||||||
|
|
||||||
Build and install from the Fedora toolbox:
|
Build and install from the Fedora toolbox:
|
||||||
|
|
||||||
|
|||||||
@@ -665,6 +665,38 @@ void AppendUint32Field(std::ostringstream& aLine, const char* aLabel, void* aObj
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppendUint16Field(std::ostringstream& aLine, const char* aLabel, void* aObject, uintptr_t aOffset)
|
||||||
|
{
|
||||||
|
uint16_t value = 0;
|
||||||
|
const auto hasValue = aObject && TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aObject) + aOffset),
|
||||||
|
value);
|
||||||
|
aLine << " " << aLabel << "=";
|
||||||
|
if (hasValue)
|
||||||
|
{
|
||||||
|
aLine << value << "/0x" << std::hex << value << std::dec;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
aLine << "<unreadable>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppendUint64Field(std::ostringstream& aLine, const char* aLabel, void* aObject, uintptr_t aOffset)
|
||||||
|
{
|
||||||
|
uint64_t value = 0;
|
||||||
|
const auto hasValue = aObject && TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aObject) + aOffset),
|
||||||
|
value);
|
||||||
|
aLine << " " << aLabel << "=";
|
||||||
|
if (hasValue)
|
||||||
|
{
|
||||||
|
aLine << value << "/0x" << std::hex << value << std::dec;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
aLine << "<unreadable>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AppendByteField(std::ostringstream& aLine, const char* aLabel, void* aObject, uintptr_t aOffset)
|
void AppendByteField(std::ostringstream& aLine, const char* aLabel, void* aObject, uintptr_t aOffset)
|
||||||
{
|
{
|
||||||
uint8_t value = 0;
|
uint8_t value = 0;
|
||||||
@@ -681,6 +713,28 @@ void AppendByteField(std::ostringstream& aLine, const char* aLabel, void* aObjec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppendBytesField(std::ostringstream& aLine, const char* aLabel, void* aObject, uintptr_t aOffset, size_t aSize)
|
||||||
|
{
|
||||||
|
const auto* address = aObject ? reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aObject) + aOffset) : nullptr;
|
||||||
|
aLine << " " << aLabel << "=";
|
||||||
|
if (!address || !IsReadableMemory(address, aSize))
|
||||||
|
{
|
||||||
|
aLine << "<unreadable>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto flags = aLine.flags();
|
||||||
|
const auto fill = aLine.fill();
|
||||||
|
aLine << std::hex << std::setfill('0');
|
||||||
|
for (size_t index = 0; index < aSize; ++index)
|
||||||
|
{
|
||||||
|
const auto byte = *(reinterpret_cast<const uint8_t*>(address) + index);
|
||||||
|
aLine << std::setw(2) << static_cast<uint32_t>(byte);
|
||||||
|
}
|
||||||
|
aLine.flags(flags);
|
||||||
|
aLine.fill(fill);
|
||||||
|
}
|
||||||
|
|
||||||
struct Vector4Value
|
struct Vector4Value
|
||||||
{
|
{
|
||||||
float x;
|
float x;
|
||||||
@@ -714,6 +768,32 @@ void AppendVector4Field(std::ostringstream& aLine, const char* aLabel, void* aOb
|
|||||||
AppendVector4Pointer(aLine, aLabel, reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aObject) + aOffset));
|
AppendVector4Pointer(aLine, aLabel, reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aObject) + aOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppendVectorListCandidate(std::ostringstream& aLine, const char* aPrefix, void* aObject, uintptr_t aDataOffset,
|
||||||
|
uintptr_t aCountOffset, uintptr_t aStride)
|
||||||
|
{
|
||||||
|
uint32_t count = 0;
|
||||||
|
auto* data = ReadPointerField(aObject, aDataOffset);
|
||||||
|
TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aObject) + aCountOffset), count);
|
||||||
|
|
||||||
|
const auto dataLabel = std::string(aPrefix) + "_data";
|
||||||
|
const auto countLabel = std::string(aPrefix) + "_count";
|
||||||
|
AppendPointerWithRva(aLine, dataLabel.c_str(), data);
|
||||||
|
aLine << " " << countLabel << "=" << count;
|
||||||
|
|
||||||
|
if (!data || reinterpret_cast<uintptr_t>(data) < 0x10000 || count == 0 || count > 10000)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppendVector4Pointer(aLine, (std::string(aPrefix) + "_first").c_str(), data);
|
||||||
|
if (count > 1)
|
||||||
|
{
|
||||||
|
AppendVector4Pointer(aLine, (std::string(aPrefix) + "_last").c_str(),
|
||||||
|
reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(data) +
|
||||||
|
static_cast<uintptr_t>(count - 1) * aStride));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AppendPathBufferSummary(std::ostringstream& aLine, const char* aPrefix, void* aPathBuffer)
|
void AppendPathBufferSummary(std::ostringstream& aLine, const char* aPrefix, void* aPathBuffer)
|
||||||
{
|
{
|
||||||
AppendPointerWithRva(aLine, aPrefix, aPathBuffer);
|
AppendPointerWithRva(aLine, aPrefix, aPathBuffer);
|
||||||
@@ -743,6 +823,28 @@ void AppendPathBufferSummary(std::ostringstream& aLine, const char* aPrefix, voi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppendGpsResultObjectSummary(std::ostringstream& aLine, const char* aPrefix, void* aResultObject)
|
||||||
|
{
|
||||||
|
if (!aResultObject)
|
||||||
|
{
|
||||||
|
aLine << " " << aPrefix << "_result=<null>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppendBytesField(aLine, (std::string(aPrefix) + "_bytes20").c_str(), aResultObject, 0x20, 0x40);
|
||||||
|
AppendVectorListCandidate(aLine, (std::string(aPrefix) + "_vec20").c_str(), aResultObject, 0x20, 0x2C, 12);
|
||||||
|
AppendVectorListCandidate(aLine, (std::string(aPrefix) + "_vec20s16").c_str(), aResultObject, 0x20, 0x2C, 16);
|
||||||
|
AppendUint32Field(aLine, (std::string(aPrefix) + "_u2c").c_str(), aResultObject, 0x2C);
|
||||||
|
AppendUint64Field(aLine, (std::string(aPrefix) + "_u30").c_str(), aResultObject, 0x30);
|
||||||
|
AppendUint32Field(aLine, (std::string(aPrefix) + "_u30lo").c_str(), aResultObject, 0x30);
|
||||||
|
AppendUint32Field(aLine, (std::string(aPrefix) + "_u34hi").c_str(), aResultObject, 0x34);
|
||||||
|
AppendVectorListCandidate(aLine, (std::string(aPrefix) + "_vec38").c_str(), aResultObject, 0x38, 0x3C, 12);
|
||||||
|
AppendUint16Field(aLine, (std::string(aPrefix) + "_flags40").c_str(), aResultObject, 0x40);
|
||||||
|
AppendByteField(aLine, (std::string(aPrefix) + "_state42").c_str(), aResultObject, 0x42);
|
||||||
|
AppendUint64Field(aLine, (std::string(aPrefix) + "_u48").c_str(), aResultObject, 0x48);
|
||||||
|
AppendUint64Field(aLine, (std::string(aPrefix) + "_u50").c_str(), aResultObject, 0x50);
|
||||||
|
}
|
||||||
|
|
||||||
void TrackGpsQuery(uint32_t aQueryId, void* aManager, uintptr_t aSubmitReturnRva, uint32_t aSubmitCall)
|
void TrackGpsQuery(uint32_t aQueryId, void* aManager, uintptr_t aSubmitReturnRva, uint32_t aSubmitCall)
|
||||||
{
|
{
|
||||||
if (aQueryId == UINT32_MAX)
|
if (aQueryId == UINT32_MAX)
|
||||||
@@ -2122,6 +2224,10 @@ bool DetourGpsQueryResultFetch(void* aManager, uint32_t aQueryId, void* aOutPath
|
|||||||
AppendPointerWithRva(line, "outPath", aOutPath);
|
AppendPointerWithRva(line, "outPath", aOutPath);
|
||||||
AppendReturnRva(line, returnAddress);
|
AppendReturnRva(line, returnAddress);
|
||||||
AppendPathBufferSummary(line, "outPath", aOutPath);
|
AppendPathBufferSummary(line, "outPath", aOutPath);
|
||||||
|
if (result && isTracked && trackedQuery.submitReturnRva == 0x8D20D4)
|
||||||
|
{
|
||||||
|
AppendGpsResultObjectSummary(line, "gpsResult", aOutPath);
|
||||||
|
}
|
||||||
LogRed4ext(line.str());
|
LogRed4ext(line.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user