Probe mappin route event dispatch
This commit is contained in:
@@ -26,6 +26,12 @@ Current behavior:
|
|||||||
`0x8d136c`, `0x431a34`, `0x55a4e4`, and `0x14de238`.
|
`0x8d136c`, `0x431a34`, `0x55a4e4`, and `0x14de238`.
|
||||||
- For those listener callbacks, logs the listener object, event pointer, common
|
- For those listener callbacks, logs the listener object, event pointer, common
|
||||||
object fields, and vtable slots on candidate nested owner/service objects.
|
object fields, and vtable slots on candidate nested owner/service objects.
|
||||||
|
- Hooks the route handoff found from the journal listener bridge:
|
||||||
|
`0x598250`, `0x13763d8`, `0xaa62d0`, `0xaa6330`, `0x27abd7c`, and
|
||||||
|
`0x5625a4`.
|
||||||
|
- Logs mappin route-event fields, active/deactive route refs, the mappin
|
||||||
|
active-route map at `system + 0x1a0`, and the route observer list at
|
||||||
|
`system + 0x280`.
|
||||||
- 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.
|
||||||
|
|
||||||
@@ -38,6 +44,11 @@ Current route-probe focus:
|
|||||||
- mappin-system slots `0x1f0`, `0x280`, and `0x2f0`
|
- mappin-system slots `0x1f0`, `0x280`, and `0x2f0`
|
||||||
- `JournalManager.TrackEntry` implementation: `0x5944fc`
|
- `JournalManager.TrackEntry` implementation: `0x5944fc`
|
||||||
- non-default `TrackEntry` listener callbacks listed above
|
- non-default `TrackEntry` listener callbacks listed above
|
||||||
|
- journal/mappin route bridge candidate: `0x598250`
|
||||||
|
- mappin route-event enqueue: `0x13763d8`
|
||||||
|
- mappin route-event handler: `0xaa62d0`
|
||||||
|
- mappin route activate/deactivate: `0xaa6330`, `0x27abd7c`
|
||||||
|
- route-build candidate called by the bridge: `0x5625a4`
|
||||||
|
|
||||||
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`
|
||||||
|
|||||||
@@ -258,9 +258,57 @@ Static disassembly of these callbacks suggests the following split:
|
|||||||
slots such as `0x218`, `0x230`, `0x240`, `0x340`, and `0x348`.
|
slots such as `0x218`, `0x230`, `0x240`, `0x340`, and `0x348`.
|
||||||
|
|
||||||
The installed probe now hooks those non-default callbacks directly and logs the
|
The installed probe now hooks those non-default callbacks directly and logs the
|
||||||
nested owner/service vtables. The next target is to identify which nested vtable
|
nested owner/service vtables. A later controlled run narrowed the quest route
|
||||||
slot performs the route query or route cache update, then disassemble or patch
|
handoff further:
|
||||||
that function.
|
|
||||||
|
```text
|
||||||
|
JournalManager.TrackEntry
|
||||||
|
-> JournalListener::Route callbacks at 0xe63f80 / 0xe63e6c
|
||||||
|
-> journal/mappin route bridge candidate at 0x598250
|
||||||
|
-> MappinSystem route-event enqueue at 0x13763d8
|
||||||
|
-> route-event handler at 0xaa62d0
|
||||||
|
-> activate route ref at 0xaa6330
|
||||||
|
-> or deactivate route ref at 0x27abd7c
|
||||||
|
```
|
||||||
|
|
||||||
|
The route listener object has two important nested service pointers in the live
|
||||||
|
logs:
|
||||||
|
|
||||||
|
```text
|
||||||
|
listener + 0x70: mappin system, vtable 0x14310e300
|
||||||
|
listener + 0x78: journal manager, vtable 0x1430f0890
|
||||||
|
```
|
||||||
|
|
||||||
|
The mappin system slot `0x240` points to RVA `0x13763d8`. Static disassembly
|
||||||
|
shows it is not the solver. It builds a small queued event with vtable
|
||||||
|
`0x14310e1c0`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
event + 0x08: event type byte, value 5
|
||||||
|
event + 0x18: route/journal id
|
||||||
|
event + 0x20: mappin system pointer
|
||||||
|
event + 0x28: active/unactive bool
|
||||||
|
```
|
||||||
|
|
||||||
|
The event handler at `0xaa62d0` reads that bool and calls either `0xaa6330` or
|
||||||
|
`0x27abd7c` with the mappin system and a route reference taken from the event
|
||||||
|
payload. Both target functions look like active-route state toggles: they look
|
||||||
|
up a route ref in a map at `mappinSystem + 0x1a0`, set a byte at route object
|
||||||
|
offset `0x84`, then notify observers from the list at `mappinSystem + 0x280`
|
||||||
|
through virtual callbacks at offsets `0x48`/`0x50`.
|
||||||
|
|
||||||
|
Static xrefs also expose a shared route-change helper at `0x27aa2d8`, which
|
||||||
|
deactivates an old route ref and activates a new route ref. That is likely the
|
||||||
|
common mappin state transition path for both journal/objective routes and
|
||||||
|
custom/player pins.
|
||||||
|
|
||||||
|
The most route-building-looking static candidate currently in this chain is
|
||||||
|
`0x5625a4`, called once from the bridge at `0x5984ec`. The bridge resolves
|
||||||
|
journal route ids through virtual journal-manager calls, collects several route
|
||||||
|
descriptor/data pointers, and passes them to `0x5625a4`. The current RED4ext
|
||||||
|
probe hooks this function with a 12-argument inferred signature to determine
|
||||||
|
whether it builds GPS/path display data or merely updates UI-facing route
|
||||||
|
metadata.
|
||||||
|
|
||||||
## Native False Positives
|
## Native False Positives
|
||||||
|
|
||||||
|
|||||||
@@ -125,6 +125,12 @@ constexpr uintptr_t kJournalListenerRouteAltVt30Rva = 0x08D136C;
|
|||||||
constexpr uintptr_t kJournalListenerUiVt28Rva = 0x0431A34;
|
constexpr uintptr_t kJournalListenerUiVt28Rva = 0x0431A34;
|
||||||
constexpr uintptr_t kJournalListenerUiVt30Rva = 0x055A4E4;
|
constexpr uintptr_t kJournalListenerUiVt30Rva = 0x055A4E4;
|
||||||
constexpr uintptr_t kJournalListenerTrackerVt28Rva = 0x14DE238;
|
constexpr uintptr_t kJournalListenerTrackerVt28Rva = 0x14DE238;
|
||||||
|
constexpr uintptr_t kJournalRouteBridgeRva = 0x0598250;
|
||||||
|
constexpr uintptr_t kMappinRouteEventEnqueueRva = 0x13763D8;
|
||||||
|
constexpr uintptr_t kMappinRouteEventHandlerRva = 0x0AA62D0;
|
||||||
|
constexpr uintptr_t kMappinRouteActivateRva = 0x0AA6330;
|
||||||
|
constexpr uintptr_t kMappinRouteDeactivateRva = 0x27ABD7C;
|
||||||
|
constexpr uintptr_t kRouteBuildCandidateRva = 0x05625A4;
|
||||||
|
|
||||||
HMODULE gModule = nullptr;
|
HMODULE gModule = nullptr;
|
||||||
std::mutex gLogMutex;
|
std::mutex gLogMutex;
|
||||||
@@ -165,6 +171,12 @@ uint32_t gJournalListenerRouteAltVt30LogCount = 0;
|
|||||||
uint32_t gJournalListenerUiVt28LogCount = 0;
|
uint32_t gJournalListenerUiVt28LogCount = 0;
|
||||||
uint32_t gJournalListenerUiVt30LogCount = 0;
|
uint32_t gJournalListenerUiVt30LogCount = 0;
|
||||||
uint32_t gJournalListenerTrackerVt28LogCount = 0;
|
uint32_t gJournalListenerTrackerVt28LogCount = 0;
|
||||||
|
uint32_t gJournalRouteBridgeLogCount = 0;
|
||||||
|
uint32_t gMappinRouteEventEnqueueLogCount = 0;
|
||||||
|
uint32_t gMappinRouteEventHandlerLogCount = 0;
|
||||||
|
uint32_t gMappinRouteActivateLogCount = 0;
|
||||||
|
uint32_t gMappinRouteDeactivateLogCount = 0;
|
||||||
|
uint32_t gRouteBuildCandidateLogCount = 0;
|
||||||
uint64_t gLogStartTick = 0;
|
uint64_t gLogStartTick = 0;
|
||||||
uint64_t gLogFrequency = 0;
|
uint64_t gLogFrequency = 0;
|
||||||
void* gMappinSetTrackedTarget = nullptr;
|
void* gMappinSetTrackedTarget = nullptr;
|
||||||
@@ -194,6 +206,15 @@ using MappinCreateCustomPositionFunc = void* (*)(void* aSystem, void* aName, voi
|
|||||||
using MappinReleaseQueryFunc = void (*)(void* aSystem, void* aHandle);
|
using MappinReleaseQueryFunc = void (*)(void* aSystem, void* aHandle);
|
||||||
using MappinActiveRouteFunc = void* (*)(void* aSystem);
|
using MappinActiveRouteFunc = void* (*)(void* aSystem);
|
||||||
using JournalListenerCallbackFunc = void (*)(void* aListener, void* aEvent);
|
using JournalListenerCallbackFunc = void (*)(void* aListener, void* aEvent);
|
||||||
|
using JournalRouteBridgeFunc = bool (*)(void* aThis, void* aEntryHandle);
|
||||||
|
using MappinRouteEventEnqueueFunc = void (*)(void* aSystem, uint32_t aRouteId, uint8_t aActive);
|
||||||
|
using MappinRouteEventHandlerFunc = void (*)(void* aEvent, void* aRouteHandle);
|
||||||
|
using MappinRouteToggleFunc = void (*)(void* aSystem, void* aRouteRef);
|
||||||
|
using RouteBuildCandidateFunc = void (*)(void* aThis, uint32_t aRouteId, uint32_t aAltRouteId,
|
||||||
|
uint32_t aPreviousRouteId, void* aRoutePositionData,
|
||||||
|
void* aPrimaryDescriptor, void* aSecondaryDescriptor, void* aRouteData88,
|
||||||
|
void* aRouteData108, void* aRouteData114, uint8_t aFlag,
|
||||||
|
uint32_t aMode);
|
||||||
ProbeFunc gOriginalGpsSystemTick = nullptr;
|
ProbeFunc gOriginalGpsSystemTick = nullptr;
|
||||||
JournalTrackEntryFunc gOriginalJournalTrackEntry = nullptr;
|
JournalTrackEntryFunc gOriginalJournalTrackEntry = nullptr;
|
||||||
ScriptNativeVoidFunc gOriginalFrameMappinPathWrapper = nullptr;
|
ScriptNativeVoidFunc gOriginalFrameMappinPathWrapper = nullptr;
|
||||||
@@ -225,6 +246,12 @@ JournalListenerCallbackFunc gOriginalJournalListenerRouteAltVt30 = nullptr;
|
|||||||
JournalListenerCallbackFunc gOriginalJournalListenerUiVt28 = nullptr;
|
JournalListenerCallbackFunc gOriginalJournalListenerUiVt28 = nullptr;
|
||||||
JournalListenerCallbackFunc gOriginalJournalListenerUiVt30 = nullptr;
|
JournalListenerCallbackFunc gOriginalJournalListenerUiVt30 = nullptr;
|
||||||
JournalListenerCallbackFunc gOriginalJournalListenerTrackerVt28 = nullptr;
|
JournalListenerCallbackFunc gOriginalJournalListenerTrackerVt28 = nullptr;
|
||||||
|
JournalRouteBridgeFunc gOriginalJournalRouteBridge = nullptr;
|
||||||
|
MappinRouteEventEnqueueFunc gOriginalMappinRouteEventEnqueue = nullptr;
|
||||||
|
MappinRouteEventHandlerFunc gOriginalMappinRouteEventHandler = nullptr;
|
||||||
|
MappinRouteToggleFunc gOriginalMappinRouteActivate = nullptr;
|
||||||
|
MappinRouteToggleFunc gOriginalMappinRouteDeactivate = nullptr;
|
||||||
|
RouteBuildCandidateFunc gOriginalRouteBuildCandidate = nullptr;
|
||||||
|
|
||||||
std::filesystem::path GetLogPath()
|
std::filesystem::path GetLogPath()
|
||||||
{
|
{
|
||||||
@@ -508,16 +535,142 @@ void AppendObjectVtableSlots(std::ostringstream& aLine, void* aObject, std::init
|
|||||||
{
|
{
|
||||||
auto* vtable = ReadPointerField(aObject, 0);
|
auto* vtable = ReadPointerField(aObject, 0);
|
||||||
AppendPointerWithRva(aLine, "vtable", vtable);
|
AppendPointerWithRva(aLine, "vtable", vtable);
|
||||||
|
if (!IsInImage(vtable))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto slot : aSlots)
|
for (const auto slot : aSlots)
|
||||||
{
|
{
|
||||||
auto* target = vtable ? ReadPointerField(vtable, slot) : nullptr;
|
auto* target = vtable ? ReadPointerField(vtable, slot) : nullptr;
|
||||||
std::ostringstream label;
|
std::ostringstream label;
|
||||||
label << "slot" << std::hex << slot;
|
label << "slot" << std::hex << slot;
|
||||||
AppendPointerWithRva(aLine, label.str().c_str(), target);
|
const auto labelText = label.str();
|
||||||
|
AppendPointerWithRva(aLine, labelText.c_str(), target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppendPointerField(std::ostringstream& aLine, const char* aLabel, void* aObject, uintptr_t aOffset)
|
||||||
|
{
|
||||||
|
AppendPointerWithRva(aLine, aLabel, ReadPointerField(aObject, aOffset));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppendUint32Field(std::ostringstream& aLine, const char* aLabel, void* aObject, uintptr_t aOffset)
|
||||||
|
{
|
||||||
|
uint32_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)
|
||||||
|
{
|
||||||
|
uint8_t value = 0;
|
||||||
|
const auto hasValue = aObject && TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aObject) + aOffset),
|
||||||
|
value);
|
||||||
|
aLine << " " << aLabel << "=";
|
||||||
|
if (hasValue)
|
||||||
|
{
|
||||||
|
aLine << static_cast<uint32_t>(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
aLine << "<unreadable>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppendRouteRefFields(std::ostringstream& aLine, const char* aPrefix, void* aRouteRef)
|
||||||
|
{
|
||||||
|
AppendPointerWithRva(aLine, aPrefix, aRouteRef);
|
||||||
|
if (!aRouteRef)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<uintptr_t, 7> offsets{0x00, 0x08, 0x10, 0x18, 0x30, 0x40, 0x48};
|
||||||
|
for (const auto offset : offsets)
|
||||||
|
{
|
||||||
|
std::ostringstream label;
|
||||||
|
label << aPrefix << "_f" << std::hex << offset;
|
||||||
|
const auto labelText = label.str();
|
||||||
|
AppendPointerField(aLine, labelText.c_str(), aRouteRef, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogMappinRouteCollections(const char* aName, uint32_t aCount, void* aSystem)
|
||||||
|
{
|
||||||
|
if (!aSystem)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* activeRouteMap = nullptr;
|
||||||
|
uint32_t activeRouteCount = 0;
|
||||||
|
uint32_t activeRouteFlags = 0;
|
||||||
|
void* observerBase = nullptr;
|
||||||
|
uint32_t observerCount = 0;
|
||||||
|
TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aSystem) + 0x1A0), activeRouteMap);
|
||||||
|
TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aSystem) + 0x1AC), activeRouteCount);
|
||||||
|
TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aSystem) + 0x1B0), activeRouteFlags);
|
||||||
|
TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aSystem) + 0x288), observerBase);
|
||||||
|
TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aSystem) + 0x294), observerCount);
|
||||||
|
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "mappin-route-state " << aName << " call=" << aCount;
|
||||||
|
AppendPointerWithRva(line, "system", aSystem);
|
||||||
|
AppendPointerWithRva(line, "activeRouteMap", activeRouteMap);
|
||||||
|
line << " activeRouteCount=" << activeRouteCount << " activeRouteFlags=0x" << std::hex << activeRouteFlags
|
||||||
|
<< std::dec;
|
||||||
|
AppendPointerWithRva(line, "observerBase", observerBase);
|
||||||
|
line << " observerCount=" << observerCount;
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
|
||||||
|
if (!observerBase || observerCount == 0 || observerCount > 128)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto cappedCount = std::min(observerCount, 4u);
|
||||||
|
for (uint32_t index = 0; index < cappedCount; ++index)
|
||||||
|
{
|
||||||
|
auto* observer = ReadPointerField(observerBase, index * 0x10);
|
||||||
|
std::ostringstream observerLine;
|
||||||
|
observerLine << "mappin-route-observer " << aName << " call=" << aCount << " index=" << index;
|
||||||
|
AppendPointerWithRva(observerLine, "observer", observer);
|
||||||
|
AppendObjectVtableSlots(observerLine, observer, {0x48, 0x50, 0x210, 0x260});
|
||||||
|
LogRed4ext(observerLine.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogRouteEventFields(const char* aName, uint32_t aCount, void* aEvent)
|
||||||
|
{
|
||||||
|
uint32_t routeId = 0;
|
||||||
|
uint8_t active = 0;
|
||||||
|
void* system = nullptr;
|
||||||
|
if (aEvent)
|
||||||
|
{
|
||||||
|
TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aEvent) + 0x18), routeId);
|
||||||
|
TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aEvent) + 0x20), system);
|
||||||
|
TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aEvent) + 0x28), active);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "route-event-fields " << aName << " call=" << aCount << " routeId=" << routeId << " active="
|
||||||
|
<< static_cast<uint32_t>(active);
|
||||||
|
AppendPointerWithRva(line, "event", aEvent);
|
||||||
|
AppendPointerWithRva(line, "system", system);
|
||||||
|
AppendObjectVtableSlots(line, aEvent, {0x20, 0x28, 0x30});
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
}
|
||||||
|
|
||||||
void LogJournalListenerContext(const char* aName, uint32_t aCount, void* aListener, void* aEvent)
|
void LogJournalListenerContext(const char* aName, uint32_t aCount, void* aListener, void* aEvent)
|
||||||
{
|
{
|
||||||
std::ostringstream line;
|
std::ostringstream line;
|
||||||
@@ -863,6 +1016,177 @@ void DetourJournalListenerTrackerVt28(void* aListener, void* aEvent)
|
|||||||
gOriginalJournalListenerTrackerVt28, aListener, aEvent);
|
gOriginalJournalListenerTrackerVt28, aListener, aEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DetourJournalRouteBridge(void* aThis, void* aEntryHandle)
|
||||||
|
{
|
||||||
|
constexpr uint32_t kMaxCalls = 64;
|
||||||
|
|
||||||
|
const auto callCount = gJournalRouteBridgeLogCount;
|
||||||
|
const auto shouldLog = callCount < kMaxCalls;
|
||||||
|
if (shouldLog)
|
||||||
|
{
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "hook JournalRouteBridge::Update candidate call=" << callCount;
|
||||||
|
AppendPointerWithRva(line, "this", aThis);
|
||||||
|
AppendPointerWithRva(line, "entryHandle", aEntryHandle);
|
||||||
|
AppendReturnRva(line, __builtin_return_address(0));
|
||||||
|
AppendPointerField(line, "field10", aThis, 0x10);
|
||||||
|
AppendPointerField(line, "field18", aThis, 0x18);
|
||||||
|
AppendPointerField(line, "field20", aThis, 0x20);
|
||||||
|
AppendByteField(line, "field30", aThis, 0x30);
|
||||||
|
AppendUint32Field(line, "field34", aThis, 0x34);
|
||||||
|
AppendUint32Field(line, "field38", aThis, 0x38);
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
++gJournalRouteBridgeLogCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
if (gOriginalJournalRouteBridge)
|
||||||
|
{
|
||||||
|
result = gOriginalJournalRouteBridge(aThis, aEntryHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldLog)
|
||||||
|
{
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "hook JournalRouteBridge::Update candidate result call=" << callCount << " value="
|
||||||
|
<< static_cast<uint32_t>(result);
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetourMappinRouteEventEnqueue(void* aSystem, uint32_t aRouteId, uint8_t aActive)
|
||||||
|
{
|
||||||
|
constexpr uint32_t kMaxCalls = 64;
|
||||||
|
|
||||||
|
if (gMappinRouteEventEnqueueLogCount < kMaxCalls)
|
||||||
|
{
|
||||||
|
const auto callCount = gMappinRouteEventEnqueueLogCount;
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "hook MappinSystem::RouteEventEnqueue slot240 call=" << callCount << " routeId=" << aRouteId
|
||||||
|
<< " active=" << static_cast<uint32_t>(aActive);
|
||||||
|
AppendPointerWithRva(line, "system", aSystem);
|
||||||
|
AppendReturnRva(line, __builtin_return_address(0));
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
LogMappinRouteCollections("enqueue-before", callCount, aSystem);
|
||||||
|
++gMappinRouteEventEnqueueLogCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gOriginalMappinRouteEventEnqueue)
|
||||||
|
{
|
||||||
|
gOriginalMappinRouteEventEnqueue(aSystem, aRouteId, aActive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetourMappinRouteEventHandler(void* aEvent, void* aRouteHandle)
|
||||||
|
{
|
||||||
|
constexpr uint32_t kMaxCalls = 64;
|
||||||
|
|
||||||
|
if (gMappinRouteEventHandlerLogCount < kMaxCalls)
|
||||||
|
{
|
||||||
|
const auto callCount = gMappinRouteEventHandlerLogCount;
|
||||||
|
void* routeOwner = ReadPointerField(aRouteHandle, 0);
|
||||||
|
void* routeRef = ReadPointerField(routeOwner, 0x40);
|
||||||
|
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "hook MappinRouteEvent::Handle call=" << callCount;
|
||||||
|
AppendPointerWithRva(line, "event", aEvent);
|
||||||
|
AppendPointerWithRva(line, "routeHandle", aRouteHandle);
|
||||||
|
AppendPointerWithRva(line, "routeOwner", routeOwner);
|
||||||
|
AppendRouteRefFields(line, "routeRef", routeRef);
|
||||||
|
AppendReturnRva(line, __builtin_return_address(0));
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
LogRouteEventFields("handler-before", callCount, aEvent);
|
||||||
|
++gMappinRouteEventHandlerLogCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gOriginalMappinRouteEventHandler)
|
||||||
|
{
|
||||||
|
gOriginalMappinRouteEventHandler(aEvent, aRouteHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetourMappinRouteActivate(void* aSystem, void* aRouteRef)
|
||||||
|
{
|
||||||
|
constexpr uint32_t kMaxCalls = 64;
|
||||||
|
|
||||||
|
if (gMappinRouteActivateLogCount < kMaxCalls)
|
||||||
|
{
|
||||||
|
const auto callCount = gMappinRouteActivateLogCount;
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "hook MappinSystem::RouteActivate call=" << callCount;
|
||||||
|
AppendPointerWithRva(line, "system", aSystem);
|
||||||
|
AppendRouteRefFields(line, "routeRef", aRouteRef);
|
||||||
|
AppendReturnRva(line, __builtin_return_address(0));
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
LogMappinRouteCollections("activate-before", callCount, aSystem);
|
||||||
|
++gMappinRouteActivateLogCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gOriginalMappinRouteActivate)
|
||||||
|
{
|
||||||
|
gOriginalMappinRouteActivate(aSystem, aRouteRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetourMappinRouteDeactivate(void* aSystem, void* aRouteRef)
|
||||||
|
{
|
||||||
|
constexpr uint32_t kMaxCalls = 64;
|
||||||
|
|
||||||
|
if (gMappinRouteDeactivateLogCount < kMaxCalls)
|
||||||
|
{
|
||||||
|
const auto callCount = gMappinRouteDeactivateLogCount;
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "hook MappinSystem::RouteDeactivate call=" << callCount;
|
||||||
|
AppendPointerWithRva(line, "system", aSystem);
|
||||||
|
AppendRouteRefFields(line, "routeRef", aRouteRef);
|
||||||
|
AppendReturnRva(line, __builtin_return_address(0));
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
LogMappinRouteCollections("deactivate-before", callCount, aSystem);
|
||||||
|
++gMappinRouteDeactivateLogCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gOriginalMappinRouteDeactivate)
|
||||||
|
{
|
||||||
|
gOriginalMappinRouteDeactivate(aSystem, aRouteRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetourRouteBuildCandidate(void* aThis, uint32_t aRouteId, uint32_t aAltRouteId, uint32_t aPreviousRouteId,
|
||||||
|
void* aRoutePositionData, void* aPrimaryDescriptor, void* aSecondaryDescriptor,
|
||||||
|
void* aRouteData88, void* aRouteData108, void* aRouteData114, uint8_t aFlag,
|
||||||
|
uint32_t aMode)
|
||||||
|
{
|
||||||
|
constexpr uint32_t kMaxCalls = 64;
|
||||||
|
|
||||||
|
if (gRouteBuildCandidateLogCount < kMaxCalls)
|
||||||
|
{
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "hook RouteBuildCandidate 0x5625a4 call=" << gRouteBuildCandidateLogCount
|
||||||
|
<< " routeId=" << aRouteId << " altRouteId=" << aAltRouteId
|
||||||
|
<< " previousRouteId=" << aPreviousRouteId << " flag=" << static_cast<uint32_t>(aFlag)
|
||||||
|
<< " mode=" << aMode;
|
||||||
|
AppendPointerWithRva(line, "this", aThis);
|
||||||
|
AppendPointerWithRva(line, "routePositionData", aRoutePositionData);
|
||||||
|
AppendPointerWithRva(line, "primaryDescriptor", aPrimaryDescriptor);
|
||||||
|
AppendPointerWithRva(line, "secondaryDescriptor", aSecondaryDescriptor);
|
||||||
|
AppendPointerWithRva(line, "routeData88", aRouteData88);
|
||||||
|
AppendPointerWithRva(line, "routeData108", aRouteData108);
|
||||||
|
AppendPointerWithRva(line, "routeData114", aRouteData114);
|
||||||
|
AppendReturnRva(line, __builtin_return_address(0));
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
++gRouteBuildCandidateLogCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gOriginalRouteBuildCandidate)
|
||||||
|
{
|
||||||
|
gOriginalRouteBuildCandidate(aThis, aRouteId, aAltRouteId, aPreviousRouteId, aRoutePositionData,
|
||||||
|
aPrimaryDescriptor, aSecondaryDescriptor, aRouteData88, aRouteData108,
|
||||||
|
aRouteData114, aFlag, aMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DetourFrameMappinPathWrapper(void* aThis, void* aStack, void* aResult)
|
void DetourFrameMappinPathWrapper(void* aThis, void* aStack, void* aResult)
|
||||||
{
|
{
|
||||||
if (gFrameMappinPathWrapperLogCount < 64)
|
if (gFrameMappinPathWrapperLogCount < 64)
|
||||||
@@ -1487,6 +1811,24 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
|||||||
AttachProbeHook("JournalListener::Tracker vt28", kJournalListenerTrackerVt28Rva,
|
AttachProbeHook("JournalListener::Tracker vt28", kJournalListenerTrackerVt28Rva,
|
||||||
reinterpret_cast<void*>(&DetourJournalListenerTrackerVt28),
|
reinterpret_cast<void*>(&DetourJournalListenerTrackerVt28),
|
||||||
reinterpret_cast<void**>(&gOriginalJournalListenerTrackerVt28));
|
reinterpret_cast<void**>(&gOriginalJournalListenerTrackerVt28));
|
||||||
|
AttachProbeHook("JournalRouteBridge::Update candidate", kJournalRouteBridgeRva,
|
||||||
|
reinterpret_cast<void*>(&DetourJournalRouteBridge),
|
||||||
|
reinterpret_cast<void**>(&gOriginalJournalRouteBridge));
|
||||||
|
AttachProbeHook("MappinSystem::RouteEventEnqueue slot240", kMappinRouteEventEnqueueRva,
|
||||||
|
reinterpret_cast<void*>(&DetourMappinRouteEventEnqueue),
|
||||||
|
reinterpret_cast<void**>(&gOriginalMappinRouteEventEnqueue));
|
||||||
|
AttachProbeHook("MappinRouteEvent::Handle", kMappinRouteEventHandlerRva,
|
||||||
|
reinterpret_cast<void*>(&DetourMappinRouteEventHandler),
|
||||||
|
reinterpret_cast<void**>(&gOriginalMappinRouteEventHandler));
|
||||||
|
AttachProbeHook("MappinSystem::RouteActivate", kMappinRouteActivateRva,
|
||||||
|
reinterpret_cast<void*>(&DetourMappinRouteActivate),
|
||||||
|
reinterpret_cast<void**>(&gOriginalMappinRouteActivate));
|
||||||
|
AttachProbeHook("MappinSystem::RouteDeactivate", kMappinRouteDeactivateRva,
|
||||||
|
reinterpret_cast<void*>(&DetourMappinRouteDeactivate),
|
||||||
|
reinterpret_cast<void**>(&gOriginalMappinRouteDeactivate));
|
||||||
|
AttachProbeHook("RouteBuildCandidate 0x5625a4", kRouteBuildCandidateRva,
|
||||||
|
reinterpret_cast<void*>(&DetourRouteBuildCandidate),
|
||||||
|
reinterpret_cast<void**>(&gOriginalRouteBuildCandidate));
|
||||||
AttachProbeHook("FrameMappinPathWrapper", kFrameMappinPathWrapperRva,
|
AttachProbeHook("FrameMappinPathWrapper", kFrameMappinPathWrapperRva,
|
||||||
reinterpret_cast<void*>(&DetourFrameMappinPathWrapper),
|
reinterpret_cast<void*>(&DetourFrameMappinPathWrapper),
|
||||||
reinterpret_cast<void**>(&gOriginalFrameMappinPathWrapper));
|
reinterpret_cast<void**>(&gOriginalFrameMappinPathWrapper));
|
||||||
@@ -1537,6 +1879,12 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
|||||||
DetachProbeHook("JournalListener::UI vt28", kJournalListenerUiVt28Rva);
|
DetachProbeHook("JournalListener::UI vt28", kJournalListenerUiVt28Rva);
|
||||||
DetachProbeHook("JournalListener::UI vt30", kJournalListenerUiVt30Rva);
|
DetachProbeHook("JournalListener::UI vt30", kJournalListenerUiVt30Rva);
|
||||||
DetachProbeHook("JournalListener::Tracker vt28", kJournalListenerTrackerVt28Rva);
|
DetachProbeHook("JournalListener::Tracker vt28", kJournalListenerTrackerVt28Rva);
|
||||||
|
DetachProbeHook("JournalRouteBridge::Update candidate", kJournalRouteBridgeRva);
|
||||||
|
DetachProbeHook("MappinSystem::RouteEventEnqueue slot240", kMappinRouteEventEnqueueRva);
|
||||||
|
DetachProbeHook("MappinRouteEvent::Handle", kMappinRouteEventHandlerRva);
|
||||||
|
DetachProbeHook("MappinSystem::RouteActivate", kMappinRouteActivateRva);
|
||||||
|
DetachProbeHook("MappinSystem::RouteDeactivate", kMappinRouteDeactivateRva);
|
||||||
|
DetachProbeHook("RouteBuildCandidate 0x5625a4", kRouteBuildCandidateRva);
|
||||||
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