Hey, decided to write a small guide as well (inspired by Jadd's post today) on how to use the games CWorld::GetIntersection function.
Type declarations and structs first:
Code:
typedef bool (__stdcall* CWorld__GetIntersection_t) (const Game::CWorld *pInstance, const Math::Vector4& start, const Math::Vector4& end,
const Math::Vector4& up, Game::WorldIntersectionResult** intersectionResult, const Game::WorldIntersectionParams& params);
Code:
namespace Game {
enum class WorldIntersectionFlags : uint32 {
None = 0,
All = ~None,
Terrain = 0x1,
Structure = 0x10
};
#pragma pack(push, 1)
struct WorldIntersectionParams {
typedef int (__stdcall *callback_t) (void*, int);
uint32 flags; // @0
uint32 unk1; // @4 - 0
uint32 unk2; // @8 - 0 (bool?)
callback_t callback; // @C - function
void *classPtr; // @10 - gameMgr
uint32 unk4; // @14 - 0
uint32 unk5; // @18 - 0 (used if unk2 is set)
};
struct WorldIntersectionResult {
struct {
void(__stdcall* unk)(void*);
void(__stdcall* destruct)(void*);
void(__stdcall* initialize)(void*);
} *vftbl; // @0 - vftable
uint32 unk2; // @4 - 1
float distance; // @8 - lerp from start
};
#pragma pack(pop)
}
The game offsets you need (VTable shouldn't change much, should be easy to update).
Code:
class OffsetsX86 {
public:
struct SGameManager {
uint32 Ptr = 0x00872098; // 6745.10
uint32 WorldPtr = 0x00005FDC; // 6745.10
} GameManager;
struct SWorld {
struct SVMT {
uint32 GetIntersection = 51; // 6745.10
} VMT;
} World;
}
Usage (result will contain the hitpoint, if any):
Code:
bool CWorld::getIntersection(const Math::Vector3& start,
const Math::Vector3& end,
uint32 intersectionFlags,
Math::Vector3* result) const
{
__declspec(align(16))
Math::Vector4 startPt(start, 1.0f); // needs to be 16-byte aligned because of SIMD (they use aligned vectors for this)
__declspec(align(16))
Math::Vector4 endPt(end, 1.0f); // needs to be 16-byte aligned because of SIMD (they use aligned vectors for this)
__declspec(align(16))
Math::Vector4 unkVec(0, 1, 1, 0); // needs to be 16-byte aligned because of SIMD (they use aligned vectors for this)
WorldIntersectionParams intersectParams = { 0 };
WorldIntersectionResult *intersectResult = nullptr;
intersectParams.flags = intersectionFlags;
Delegates::CWorld__GetIntersection_t pGetIntersection = sMemory.getVFunc<Delegates::
CWorld__GetIntersection_t>(getPointer(), sOffsets.GameData.World.VMT.GetIntersection);
bool hasHit = pGetIntersection(this, startPt, endPt, unkVec, &intersectResult, intersectParams);
if (intersectResult != nullptr) {
intersectResult->vftbl->initialize(intersectResult);
if (result != nullptr)
*result = start + (end - start) * intersectResult->distance;
intersectResult->vftbl->destruct(intersectResult); // need to do this or you will leak memory and crash the game at some point
}
return hasHit;
}
To get a pointer to the current CWorld instance, just use the GameMgr Ptr and add the WorldPtr.
Greets!