- Статус
- Оффлайн
- Регистрация
- 13 Фев 2026
- Сообщения
- 703
- Реакции
- 20
В старых частях серии (BF3/4) с рейкастом было на порядок проще — почти всё было виртуальным, а очистка памяти шла автоматом. В Battlefield 6 (да и в 2042, скорее всего, тоже) ситуация поменялась. Функции заинлайнены, так что приходится вызывать всё руками. Сурс ниже не претендует на идеальность, но это рабочая база, которую можно допилить под свои задачи.
Зачем это нужно? Как минимум, это более продвинутая альтернатива стандартному occluded-чеку. Вы сможете понимать, простреливается ли стена, стекло это или бетон, и стоит ли вообще жать на гашетку.
Main Raycast Signature
Юзать основной метод напрямую не обязательно — в игре полно врапперов, где аргументов поменьше. Я использую вот этот:
HavokPhysicsWorld
Доступ к миру можно получить через глобальную функцию. Имейте в виду, что она завязана на Realm-структуры.
Важный нюанс по крашам
Если не очищать результат каждого вызова Raycast — игра отлетит через пару минут. Также крайне рекомендую вызывать рейкаст только в endframe DXRenderer'а, иначе получите рандомные BSOD или краш процесса из-за обращения к физическому миру в неподходящий момент.
Очистка (Cleanup)
Структуры и Выравнивание
Запомните: Vec3 должен быть выровнен по 16 байтам. Если проигнорируете alignas(16), физика Havok вас не простит.
Обработка прострелов
В примере кода ниже реализована логика проверки на "простреливаемость" (penetrability) и прозрачность материалов (see-through). Подойдет для кастомного аимбота или триггера, чтобы не палиться стрельбой в глухие стены.
Для проверки хумана или техники можно чекать ClassId: 12457 для солдата и 12454 для техники. Если пилите Internal — это мастхэв.
Если кто-то решит заморочиться с кастомными фильтрами (query filters) или вытащить более удобные врапперы — делитесь в треде.
Зачем это нужно? Как минимум, это более продвинутая альтернатива стандартному occluded-чеку. Вы сможете понимать, простреливается ли стена, стекло это или бетон, и стоит ли вообще жать на гашетку.
Main Raycast Signature
Код:
E8 ? ? ? ? 0F 10 45 ? 44 8B 7D ? 0F 11 45 ? 45 85 FF 0F 84
Код:
E8 ? ? ? ? BB ? ? ? ? 44 0F 28 AC 24
// Вызов:
addr::rayCastWrapped.as<int64_t(__fastcall*)(fb::HavokPhysicsWorld*, RawResult&, RayCastInput&, const char*)>()(havokWorld, out, input, "RayCast");
HavokPhysicsWorld
Доступ к миру можно получить через глобальную функцию. Имейте в виду, что она завязана на Realm-структуры.
Код:
E8 ? ? ? ? 48 8B F8 8B 46 ? 83 F8
Код:
class HavokPhysicsWorld
{
public:
static HavokPhysicsWorld* GetInstance()
{
auto func = addr::getPhysicWorldFunc.as<HavokPhysicsWorld * (__fastcall*)(int)>();
return func(0);
}
};
Важный нюанс по крашам
Если не очищать результат каждого вызова Raycast — игра отлетит через пару минут. Также крайне рекомендую вызывать рейкаст только в endframe DXRenderer'а, иначе получите рандомные BSOD или краш процесса из-за обращения к физическому миру в неподходящий момент.
Очистка (Cleanup)
Код:
E8 ? ? ? ? 4C 8B 4D ? 48 83 7D
auto cleanup = addr::cleanupRayWrapped.as<void(__fastcall*)(RawResult&)>();
Структуры и Выравнивание
Запомните: Vec3 должен быть выровнен по 16 байтам. Если проигнорируете alignas(16), физика Havok вас не простит.
Код:
struct alignas(16) RayCastInput
{
fb::Vec3 start;
fb::Vec3 end;
int queryFilter = 0;
int _unused = 0;
float latency = 0.0f;
int flags = 0;
int64_t allocator = 0;
eastl::fixed_vector<PhysicsHandle, 16> excludes;
};
Обработка прострелов
В примере кода ниже реализована логика проверки на "простреливаемость" (penetrability) и прозрачность материалов (see-through). Подойдет для кастомного аимбота или триггера, чтобы не палиться стрельбой в глухие стены.
Код:
RayResult RayCast(const fb::Vec3& from, const fb::Vec3& to, int query)
{
RayResult result{};
fb::HavokPhysicsWorld* havokWorld = fb::HavokPhysicsWorld::GetInstance();
if (!havokWorld) return result;
alignas(16) RayCastInput input {};
input.start = from;
input.end = to;
input.queryFilter = 0x81A0021; // Для триггера лучше юзать 0x4B010107
alignas(16) RawResult out {};
addr::rayCastWrapped(...)(havokWorld, out, input, "RayCast");
auto cleanup = addr::cleanupRayWrapped.as<void(__fastcall*)(RawResult&)>();
if (out.hitCount <= 0)
{
cleanup(out);
return result;
}
// Логика фильтрации попаданий по материалам
// ... (анализируем hit.matFlags на предмет MfSeeThrough и MfPenetrable)
cleanup(out);
return result;
}
Для проверки хумана или техники можно чекать ClassId: 12457 для солдата и 12454 для техники. Если пилите Internal — это мастхэв.
Если кто-то решит заморочиться с кастомными фильтрами (query filters) или вытащить более удобные врапперы — делитесь в треде.