#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(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(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(pid, visualStateAddr + Offsets::Common::DirectionX, dirX); mem.TryReadValue(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; }