221 lines
7.4 KiB
C++
221 lines
7.4 KiB
C++
//
|
|
// Created by Michal Přikryl on 30.08.2025.
|
|
// Copyright (c) 2025 slynxcz. All rights reserved.
|
|
//
|
|
#include "raytrace.h"
|
|
#include <shared.h>
|
|
#include "schema/CBaseModelEntity.h"
|
|
#include "vectorextends.h"
|
|
#include "dynlibutils/memaddr.h"
|
|
#include "dynlibutils/module.h"
|
|
#include "colors.h"
|
|
#include "log.h"
|
|
|
|
namespace RayTracePlugin::RayTrace
|
|
{
|
|
CRayTrace g_CRayTrace;
|
|
|
|
using TraceShapeFn = bool(*)(void* pThis,
|
|
Ray_t& ray,
|
|
Vector& start,
|
|
Vector& end,
|
|
CTraceFilter* filter,
|
|
CGameTrace* trace);
|
|
static TraceShapeFn s_TraceShape = nullptr;
|
|
|
|
bool Initialize()
|
|
{
|
|
void* pCNavPhysicsInterfaceVTable =
|
|
DynLibUtils::CModule(shared::g_pServer).GetVirtualTableByName("CNavPhysicsInterface");
|
|
|
|
if (!pCNavPhysicsInterfaceVTable)
|
|
{
|
|
FP_ERROR("Failed to find CNavPhysicsInterface vtable!");
|
|
return false;
|
|
}
|
|
|
|
auto table = static_cast<void**>(pCNavPhysicsInterfaceVTable);
|
|
s_TraceShape = reinterpret_cast<TraceShapeFn>(table[shared::g_pGameConfig->GetOffset("CNavPhysicsInterface_TraceShape")]);
|
|
|
|
return true;
|
|
}
|
|
|
|
static void DrawBeam(const Vector& start, const Vector& end, const Color& color)
|
|
{
|
|
CBeam* beam = UTIL_CreateEntityByName<CBeam>("env_beam");
|
|
if (!beam) return;
|
|
|
|
beam->m_clrRender().SetColor(color.r(), color.g(), color.b(), color.a());
|
|
beam->m_fWidth() = 1.5f;
|
|
beam->m_nRenderMode() = kRenderNormal;
|
|
beam->m_nRenderFX() = kRenderFxNone;
|
|
|
|
beam->Teleport(&start, &VectorExtends::RotationZero, &VectorExtends::VectorZero);
|
|
beam->m_vecEndPos() = end;
|
|
beam->DispatchSpawn();
|
|
}
|
|
|
|
std::optional<TraceResult> TraceShapeEx(
|
|
const Vector& start,
|
|
const Vector& end,
|
|
CTraceFilter& filterInc,
|
|
Ray_t rayInc)
|
|
{
|
|
if (!s_TraceShape) {
|
|
FP_ERROR("CNavPhysicsInterface::TraceShape is not bound!");
|
|
return std::nullopt;
|
|
}
|
|
|
|
CGameTrace tr{};
|
|
Vector startCopy = start;
|
|
Vector endCopy = end;
|
|
s_TraceShape(nullptr, rayInc, startCopy, endCopy,
|
|
&filterInc, &tr);
|
|
|
|
TraceResult r{};
|
|
r.StartPosX = tr.m_vStartPos.x;
|
|
r.StartPosY = tr.m_vStartPos.y;
|
|
r.StartPosZ = tr.m_vStartPos.z;
|
|
r.EndPosX = tr.m_vEndPos.x;
|
|
r.EndPosY = tr.m_vEndPos.y;
|
|
r.EndPosZ = tr.m_vEndPos.z;
|
|
r.HitPointX = tr.m_vHitPoint.x;
|
|
r.HitPointY = tr.m_vHitPoint.y;
|
|
r.HitPointZ = tr.m_vHitPoint.z;
|
|
r.NormalX = tr.m_vHitNormal.x;
|
|
r.NormalY = tr.m_vHitNormal.y;
|
|
r.NormalZ = tr.m_vHitNormal.z;
|
|
r.Fraction = tr.m_flFraction;
|
|
r.HitOffset = tr.m_flHitOffset;
|
|
|
|
r.TriangleIndex = tr.m_nTriangle;
|
|
r.HitboxBoneIndex = tr.m_nHitboxBoneIndex;
|
|
r.Contents = tr.m_nContents;
|
|
r.RayType = static_cast<int>(tr.m_eRayType);
|
|
r.AllSolid = tr.m_bStartInSolid;
|
|
r.ExactHitPoint = tr.m_bExactHitPoint;
|
|
|
|
r.HitEntity = tr.m_pEnt;
|
|
r.Hitbox = const_cast<CHitBox *>(tr.m_pHitbox);
|
|
r.SurfaceProps = const_cast<CPhysSurfaceProperties *>(tr.m_pSurfaceProperties);
|
|
r.BodyHandle = tr.m_hBody;
|
|
r.ShapeHandle = tr.m_hShape;
|
|
r.BodyTransform = tr.m_BodyTransform;
|
|
r.ShapeAttributes = tr.m_ShapeAttributes;
|
|
|
|
return r;
|
|
}
|
|
|
|
std::optional<TraceResult> TraceShape(
|
|
const Vector& origin,
|
|
const QAngle& viewangles,
|
|
CEntityInstance* ignoreEntity,
|
|
const TraceOptions* opts)
|
|
{
|
|
Vector forward;
|
|
AngleVectors(viewangles, &forward);
|
|
Vector endOrigin{
|
|
origin.x + forward.x * 8192.f,
|
|
origin.y + forward.y * 8192.f,
|
|
origin.z + forward.z * 8192.f
|
|
};
|
|
|
|
CTraceFilterEx filter = ignoreEntity ? CTraceFilterEx(static_cast<CBaseEntity*>(ignoreEntity)) : CTraceFilterEx();
|
|
|
|
filter.m_nInteractsAs = 0;
|
|
filter.m_nInteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS);
|
|
filter.m_nInteractsExclude = 0;
|
|
|
|
if (opts)
|
|
{
|
|
if (opts->InteractsAs != 0)
|
|
filter.m_nInteractsAs = opts->InteractsAs;
|
|
|
|
if (opts->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS))
|
|
filter.m_nInteractsWith = opts->InteractsWith;
|
|
|
|
if (opts->InteractsExclude != 0)
|
|
filter.m_nInteractsExclude = opts->InteractsExclude;
|
|
}
|
|
|
|
Ray_t ray;
|
|
auto res = TraceShapeEx(origin, endOrigin, filter, ray);
|
|
|
|
if (opts && opts->DrawBeam)
|
|
{
|
|
Color col = res.has_value() ? colors::Red().ToValveColor() : colors::Green().ToValveColor();
|
|
DrawBeam(origin, res ? Vector(res->EndPosX, res->EndPosY, res->EndPosZ) : endOrigin, col);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
std::optional<TraceResult> TraceEndShape(
|
|
const Vector& origin,
|
|
const Vector& endOrigin,
|
|
CEntityInstance* ignoreEntity,
|
|
const TraceOptions* opts)
|
|
{
|
|
CTraceFilterEx filter = ignoreEntity ? CTraceFilterEx(static_cast<CBaseEntity*>(ignoreEntity)) : CTraceFilterEx();
|
|
|
|
filter.m_nInteractsAs = 0;
|
|
filter.m_nInteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS);
|
|
filter.m_nInteractsExclude = 0;
|
|
|
|
if (opts)
|
|
{
|
|
if (opts->InteractsAs != 0)
|
|
filter.m_nInteractsAs = opts->InteractsAs;
|
|
|
|
if (opts->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS))
|
|
filter.m_nInteractsWith = opts->InteractsWith;
|
|
|
|
if (opts->InteractsExclude != 0)
|
|
filter.m_nInteractsExclude = opts->InteractsExclude;
|
|
}
|
|
|
|
Ray_t ray;
|
|
auto res = TraceShapeEx(origin, endOrigin, filter, ray);
|
|
|
|
if (opts && opts->DrawBeam)
|
|
{
|
|
Color col = res.has_value() ? colors::Red().ToValveColor() : colors::Green().ToValveColor();
|
|
DrawBeam(origin, res ? Vector(res->EndPosX, res->EndPosY, res->EndPosZ) : endOrigin, col);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
std::optional<TraceResult> TraceHullShape(const Vector &vecStart, const Vector &vecEnd, const Vector &hullMins,
|
|
const Vector &hullMaxs, CEntityInstance *ignoreEntity, const TraceOptions *opts) {
|
|
CTraceFilterEx filter = ignoreEntity ? CTraceFilterEx(static_cast<CBaseEntity*>(ignoreEntity)) : CTraceFilterEx();
|
|
|
|
filter.m_nInteractsAs = 0;
|
|
filter.m_nInteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS);
|
|
filter.m_nInteractsExclude = 0;
|
|
|
|
if (opts)
|
|
{
|
|
if (opts->InteractsAs != 0)
|
|
filter.m_nInteractsAs = opts->InteractsAs;
|
|
|
|
if (opts->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS))
|
|
filter.m_nInteractsWith = opts->InteractsWith;
|
|
|
|
if (opts->InteractsExclude != 0)
|
|
filter.m_nInteractsExclude = opts->InteractsExclude;
|
|
}
|
|
|
|
Ray_t ray;
|
|
ray.Init(hullMins, hullMaxs);
|
|
auto res = TraceShapeEx(vecStart, vecEnd, filter, ray);
|
|
|
|
if (opts && opts->DrawBeam)
|
|
{
|
|
Color col = res.has_value() ? colors::Red().ToValveColor() : colors::Green().ToValveColor();
|
|
DrawBeam(vecStart, res ? Vector(res->EndPosX, res->EndPosY, res->EndPosZ) : vecEnd, col);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
}
|