Open JohnWildkins opened 1 year ago
Fixed via detouring the fetching of a waypoint. Implemented method is identical to the original, except it returns a nullptr if the system of the waypoint and system of the player do not match.
To be implemented into the upcoming universal clienthook
PatchCallAddr((char*)hFreelancer, 0xF4141, (char*)WaypointCheckDetour);
void* WaypointCheckDetour(int index)
{
const static int* maxWaypoint = (int*)((char*)hFreelancer + 0x273374);
const static uint* playerSystem = (uint*)((char*)hFreelancer + 0x273354);
if (index < 0 || index >= *maxWaypoint)
{
return nullptr;
}
const uint* waypointSystem = (uint*)((24 * index) + 0x672984);
if (*waypointSystem != *playerSystem)
{
return nullptr;
}
return (void*)((24 * index) + 0x672978);
}
I'm personally not a big fan of reimplementing whole functions unless it's absolutely necessary. This way you're effectively rewriting code that already exists. Why not just call the original function in the detour and extend the check?
Initially I wrote the following inline assembly function which seems to work ok:
const DWORD WAYPOINT_CHECK_ADDR = 0x4C46A0;
#define PLAYER_SYSTEM_ADDR 0x673354
__declspec(naked) PDWORD WaypointCheckDetour(UINT index)
{
__asm {
mov esi, [esp+4]
push esi
call [WAYPOINT_CHECK_ADDR]
add esp, 4
test eax, eax
jz done
mov esi, PLAYER_SYSTEM_ADDR
mov esi, [esi]
cmp esi, [eax+12]
jz done
xor eax, eax
done:
ret
}
}
Alternatively, if you don't like inline assembly, here's the equivalent function in pure C++:
const DWORD WAYPOINT_CHECK_ADDR = 0x4C46A0;
#define PLAYER_SYSTEM_ADDR 0x673354
typedef PDWORD (WaypointCheck)(UINT index);
PDWORD WaypointCheckDetour(UINT index)
{
PDWORD origResult = ((WaypointCheck*) WAYPOINT_CHECK_ADDR)(index);
if (!origResult)
return NULL;
PUINT playerSystem = (PUINT) PLAYER_SYSTEM_ADDR;
PUINT waypointSystem = (PUINT) ((PBYTE) origResult + 12);
return *playerSystem == *waypointSystem ? origResult : NULL;
}
I mean, both approaches work, and the original method is very, VERY short, so I didn't really think much of it.
FL checks all waypoints in your current list and sets them as cleared if you get within 150.0f (300.0f if in a TL), regardless of the system they are in
relevant offsets:
impulse/cruise clear waypoint range: 150.0f, freelancer.exe+1d97b4 check against impulse/cruise clear range: freelancer.exe+f4058
tradelane clear waypoint range: 300.0f, freelancer.exe+1d7e80 check against tradelane clear range: freelancer.exe+f417f, (there are refs in freelancer.exe+d592b and freelancer.exe+d593e as well)
both checks goto freelancer.exe+f41c0 when they're true (i.e., you're in range to clear the waypoint)