99 lines
3.6 KiB
C++
99 lines
3.6 KiB
C++
#include "Resolvers/LocalPlayerResolver.h"
|
|
|
|
#include "Offsets.h"
|
|
#include "Memory/MemoryValidation.h"
|
|
|
|
bool LocalPlayerResolver::TryResolve(VmmAccessor& mem,
|
|
const RuntimeSession& session,
|
|
LocalPlayerData& player)
|
|
{
|
|
const uint32_t pid = session.processId;
|
|
|
|
// -----------------------------------------------------------------
|
|
// 1. Read the local player pointer from the world object
|
|
// -----------------------------------------------------------------
|
|
uint64_t localPlayerPointer = 0;
|
|
if (!mem.TryReadPointer(pid,
|
|
session.worldAddress + Offsets::World::LocalPlayer,
|
|
localPlayerPointer))
|
|
{
|
|
m_lastFailureReason = "Failed to read LocalPlayer pointer from world";
|
|
return false;
|
|
}
|
|
|
|
// -----------------------------------------------------------------
|
|
// 2. Second hop — the actual entity sits 0xA8 bytes before the
|
|
// pointed-to structure.
|
|
// -----------------------------------------------------------------
|
|
uint64_t secondHop = 0;
|
|
if (!mem.TryReadValue<uint64_t>(pid, localPlayerPointer + 0x8, secondHop)) {
|
|
m_lastFailureReason = "Failed to read secondHop from LocalPlayer";
|
|
return false;
|
|
}
|
|
|
|
if (secondHop <= 0xA8) {
|
|
m_lastFailureReason = "secondHop value too small";
|
|
return false;
|
|
}
|
|
|
|
uint64_t chainedEntity = secondHop - 0xA8;
|
|
|
|
if (!MemoryValidation::IsValidUserAddress(chainedEntity)) {
|
|
m_lastFailureReason = "chainedEntity address is not a valid user address";
|
|
return false;
|
|
}
|
|
|
|
// -----------------------------------------------------------------
|
|
// 3. VisualState pointer
|
|
// -----------------------------------------------------------------
|
|
uint64_t visualStateAddr = 0;
|
|
if (!mem.TryReadPointer(pid,
|
|
chainedEntity + Offsets::Common::VisualState,
|
|
visualStateAddr))
|
|
{
|
|
m_lastFailureReason = "Failed to read VisualState pointer";
|
|
return false;
|
|
}
|
|
|
|
// -----------------------------------------------------------------
|
|
// 4. Position
|
|
// -----------------------------------------------------------------
|
|
Vector3 pos{};
|
|
if (!mem.TryReadValue<Vector3>(pid,
|
|
visualStateAddr + Offsets::Common::Position,
|
|
pos))
|
|
{
|
|
m_lastFailureReason = "Failed to read position from VisualState";
|
|
return false;
|
|
}
|
|
|
|
if (!MemoryValidation::IsValidVector(pos)) {
|
|
m_lastFailureReason = "Position vector is not valid";
|
|
return false;
|
|
}
|
|
|
|
// -----------------------------------------------------------------
|
|
// 5. Heading from direction vector
|
|
// -----------------------------------------------------------------
|
|
float dirX = 0.0f;
|
|
float dirY = 0.0f;
|
|
mem.TryReadValue<float>(pid, visualStateAddr + Offsets::Common::DirectionX, dirX);
|
|
mem.TryReadValue<float>(pid, visualStateAddr + Offsets::Common::DirectionY, dirY);
|
|
|
|
float heading = 0.0f;
|
|
MemoryValidation::TryGetCorrectedHeadingFromDirection(dirX, dirY, heading);
|
|
|
|
// -----------------------------------------------------------------
|
|
// 6. Commit
|
|
// -----------------------------------------------------------------
|
|
player = LocalPlayerData{
|
|
.entityAddress = chainedEntity,
|
|
.visualStateAddress = visualStateAddr,
|
|
.position = pos,
|
|
.lookDirection = heading,
|
|
};
|
|
|
|
m_lastFailureReason.clear();
|
|
return true;
|
|
}
|