Refactor CRayTrace

This commit is contained in:
SlynxCZ 2026-04-14 22:01:27 +02:00
parent 12585b4161
commit 51afd30a0a
5 changed files with 459 additions and 481 deletions

View file

@ -64,13 +64,15 @@ namespace RayTraceAPI
MASK_NPC_MOVE = Solid | Window | NPCClip | PassBullets MASK_NPC_MOVE = Solid | Window | NPCClip | PassBullets
} }
[StructLayout(LayoutKind.Explicit, Size = 32)] [StructLayout(LayoutKind.Sequential, Pack = 8)]
public unsafe struct TraceOptions public struct TraceOptions
{ {
[FieldOffset(0)] public ulong InteractsAs; public ulong InteractsAs;
[FieldOffset(8)] public ulong InteractsWith; public ulong InteractsWith;
[FieldOffset(16)] public ulong InteractsExclude; public ulong InteractsExclude;
[FieldOffset(24)] public int DrawBeam; public int DrawBeam;
private int _pad;
public TraceOptions() public TraceOptions()
{ {
@ -80,7 +82,8 @@ namespace RayTraceAPI
DrawBeam = 0; DrawBeam = 0;
} }
public TraceOptions(InteractionLayers interactsAs, InteractionLayers interactsWith, InteractionLayers interactsExclude = 0, bool drawBeam = false) public TraceOptions(InteractionLayers interactsAs, InteractionLayers interactsWith,
InteractionLayers interactsExclude = 0, bool drawBeam = false)
{ {
InteractsAs = (ulong)interactsAs; InteractsAs = (ulong)interactsAs;
InteractsWith = (ulong)interactsWith; InteractsWith = (ulong)interactsWith;
@ -89,49 +92,59 @@ namespace RayTraceAPI
} }
} }
[StructLayout(LayoutKind.Explicit, Size = 136)] [StructLayout(LayoutKind.Sequential)]
public unsafe struct TraceResult public unsafe struct TraceResult
{ {
[FieldOffset(0)] public float StartPosX; public Vector3 StartPos;
[FieldOffset(4)] public float StartPosY; public Vector3 EndPos;
[FieldOffset(8)] public float StartPosZ; public Vector3 HitPoint;
public Vector3 Normal;
[FieldOffset(12)] public float EndPosX; public float Fraction;
[FieldOffset(16)] public float EndPosY; public float HitOffset;
[FieldOffset(20)] public float EndPosZ;
[FieldOffset(24)] public float HitPointX; public int TriangleIndex;
[FieldOffset(28)] public float HitPointY; public short HitboxBoneIndex;
[FieldOffset(32)] public float HitPointZ; private short _pad;
[FieldOffset(36)] public float NormalX; public int Contents;
[FieldOffset(40)] public float NormalY; public int RayType;
[FieldOffset(44)] public float NormalZ;
[FieldOffset(48)] public float Fraction; public bool StartInSolid;
[FieldOffset(52)] public float HitOffset; public bool ExactHitPoint;
[FieldOffset(56)] public int TriangleIndex; public nint HitEntity;
[FieldOffset(60)] public int HitboxBoneIndex; public nint Hitbox;
public nint Surface;
public nint Body;
public nint Shape;
[FieldOffset(64)] public int Contents; public nint BodyTransform;
[FieldOffset(68)] public int RayType; public nint ShapeAttributes;
[FieldOffset(72)] public int AllSolid; public readonly bool DidHit() => Fraction < 1.0f;
[FieldOffset(76)] public int ExactHitPoint; public readonly bool IsAllSolid() => StartInSolid;
public readonly bool HasExactHit() => ExactHitPoint;
// pointer section public readonly int GetTriangleIndex() => TriangleIndex;
[FieldOffset(80)] public nint HitEntityPtr; public readonly int GetHitboxBoneIndex() => HitboxBoneIndex;
[FieldOffset(88)] public nint HitboxPtr; public readonly int GetContents() => Contents;
[FieldOffset(96)] public nint SurfacePropsPtr; public readonly int GetRayType() => RayType;
[FieldOffset(104)] public nint BodyHandle;
[FieldOffset(112)] public nint ShapeHandle;
// thread safe heap pointer section public readonly Vector3 GetStartPos() => StartPos;
[FieldOffset(120)] public nint BodyTransformPtr; public readonly Vector3 GetEndPos() => EndPos;
[FieldOffset(128)] public nint ShapeAttributesPtr; public readonly Vector3 GetHitPoint() => HitPoint;
public readonly Vector3 GetNormal() => Normal;
public unsafe ref T GetRef<T>(nint ptr) where T : unmanaged public readonly float GetFraction() => Fraction;
public readonly float GetHitOffset() => HitOffset;
public readonly T* GetPtr<T>(nint ptr) where T : unmanaged
{
return (T*)ptr;
}
public readonly ref T GetRef<T>(nint ptr) where T : unmanaged
{ {
if (ptr == 0) if (ptr == 0)
throw new NullReferenceException(); throw new NullReferenceException();
@ -139,36 +152,58 @@ namespace RayTraceAPI
return ref *(T*)ptr; return ref *(T*)ptr;
} }
public T? GetObject<T>(nint ptr) where T : class public readonly bool TryGetRef<T>(nint ptr, out T* value) where T : unmanaged
{ {
if (ptr == 0) if (ptr == 0)
return null; {
value = null;
return (T)Activator.CreateInstance(typeof(T), ptr)!; return false;
} }
public Vector3 StartPos => new(StartPosX, StartPosY, StartPosZ); value = (T*)ptr;
public Vector3 EndPos => new(EndPosX, EndPosY, EndPosZ); return true;
public Vector3 HitPoint => new(HitPointX, HitPointY, HitPointZ); }
public Vector3 Normal => new(NormalX, NormalY, NormalZ);
public bool DidHit => Fraction < 1.0f; public readonly CEntityInstance HitEntityPtr() => new(HitEntity);
public bool IsAllSolid => AllSolid != 0;
public bool HasExactHit => ExactHitPoint != 0;
public CEntityInstance? HitEntity => GetObject<CEntityInstance>(HitEntityPtr); public readonly CTransform BodyTransformPtr() => new(BodyTransform);
}
[StructLayout(LayoutKind.Sequential)]
public struct QAngle
{
public float X;
public float Y;
public float Z;
} }
#endregion #endregion
public interface CRayTraceInterface public interface CRayTraceInterface
{ {
public unsafe bool TraceShape(Vector origin, QAngle angles, CBaseEntity? ignoreEntity, TraceOptions options, TraceResult TraceShape(
out TraceResult result); in Vector3 start,
in QAngle angles,
CEntityInstance ignoreEntity,
in TraceOptions options);
public unsafe bool TraceEndShape(Vector origin, Vector endOrigin, CBaseEntity? ignoreEntity, TraceResult TraceEndShape(
TraceOptions options, out TraceResult result); in Vector3 start,
in Vector3 end,
CEntityInstance ignoreEntity,
in TraceOptions options);
public unsafe bool TraceHullShape(Vector vecStart, Vector vecEnd, Vector hullMins, Vector hullMaxs, TraceResult TraceHullShape(
CBaseEntity? ignoreEntity, TraceOptions options, out TraceResult result); in Vector3 start,
in Vector3 end,
in Vector3 mins,
in Vector3 maxs,
CEntityInstance ignoreEntity,
in TraceOptions options);
TraceResult TraceShapeEx(
in Vector3 start,
in Vector3 end,
nint traceFilter,
nint ray);
} }
} }

View file

@ -3,7 +3,9 @@
// Copyright (c) 2025 slynxcz. All rights reserved. // Copyright (c) 2025 slynxcz. All rights reserved.
// //
using System.Buffers; using System.Buffers;
using System.Numerics;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Loader; using System.Runtime.Loader;
using System.Text; using System.Text;
@ -17,6 +19,8 @@ using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Utils;
using RayTraceAPI; using RayTraceAPI;
using QAngle = RayTraceAPI.QAngle;
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
namespace RayTraceImpl; namespace RayTraceImpl;
@ -54,112 +58,122 @@ public class RayTraceImpl : BasePlugin
public class CRayTrace : CRayTraceInterface public class CRayTrace : CRayTraceInterface
{ {
public unsafe bool TraceShape(Vector origin, QAngle angles, CBaseEntity? ignoreEntity, TraceOptions options, out TraceResult result) public TraceResult TraceShape(in Vector3 start, in QAngle angles, CEntityInstance ignore, in TraceOptions options)
{ {
result = default; unsafe
{
if (!NativeBridge.Loaded)
return default;
if (!NativeBridge.m_bRayTraceLoaded || NativeBridge.m_pRayTraceHandle == nint.Zero) return NativeBridge.TraceShape!(
return false; NativeBridge.Handle,
start,
TraceResult resultBuffer = default; angles,
TraceOptions optionsBuffer = options; ignore.Handle,
(nint)Unsafe.AsPointer(ref Unsafe.AsRef(in options))
bool success = NativeBridge._traceShape!(NativeBridge.m_pRayTraceHandle, );
origin.Handle, }
angles.Handle,
ignoreEntity?.Handle ?? nint.Zero,
(nint)(&optionsBuffer),
(nint)(&resultBuffer));
result = resultBuffer;
return success;
} }
public unsafe bool TraceEndShape(Vector origin, Vector endOrigin, CBaseEntity? ignoreEntity, TraceOptions options, out TraceResult result) public TraceResult TraceEndShape(in Vector3 start, in Vector3 end, CEntityInstance ignore, in TraceOptions options)
{ {
result = default; unsafe
{
if (!NativeBridge.Loaded)
return default;
if (!NativeBridge.m_bRayTraceLoaded || NativeBridge.m_pRayTraceHandle == nint.Zero) return NativeBridge.TraceEndShape!(
return false; NativeBridge.Handle,
start,
TraceResult resultBuffer = default; end,
TraceOptions optionsBuffer = options; ignore.Handle,
(nint)Unsafe.AsPointer(ref Unsafe.AsRef(in options))
bool success = NativeBridge._traceEndShape!(NativeBridge.m_pRayTraceHandle, );
origin.Handle, }
endOrigin.Handle,
ignoreEntity?.Handle ?? nint.Zero,
(nint)(&optionsBuffer),
(nint)(&resultBuffer));
result = resultBuffer;
return success;
} }
public unsafe bool TraceHullShape(Vector vecStart, Vector vecEnd, Vector hullMins, Vector hullMaxs, CBaseEntity? ignoreEntity, TraceOptions options, out TraceResult result) public TraceResult TraceHullShape(in Vector3 start, in Vector3 end, in Vector3 mins, in Vector3 maxs, CEntityInstance ignore, in TraceOptions options)
{ {
result = default; unsafe
{
if (!NativeBridge.Loaded)
return default;
if (!NativeBridge.m_bRayTraceLoaded || NativeBridge.m_pRayTraceHandle == nint.Zero) return NativeBridge.TraceHullShape!(
return false; NativeBridge.Handle,
start,
end,
mins,
maxs,
ignore.Handle,
(nint)Unsafe.AsPointer(ref Unsafe.AsRef(in options))
);
}
}
TraceResult resultBuffer = default; public TraceResult TraceShapeEx(in Vector3 start, in Vector3 end, nint filter, nint ray)
TraceOptions optionsBuffer = options; {
unsafe
{
if (!NativeBridge.Loaded)
return default;
bool success = NativeBridge._traceHullShape!(NativeBridge.m_pRayTraceHandle, return NativeBridge.TraceShapeEx!(
vecStart.Handle, NativeBridge.Handle,
vecEnd.Handle, start,
hullMins.Handle, end,
hullMaxs.Handle, filter,
ignoreEntity?.Handle ?? nint.Zero, ray
(nint)(&optionsBuffer), );
(nint)(&resultBuffer)); }
result = resultBuffer;
return success;
} }
} }
public static class NativeBridge public static class NativeBridge
{ {
public static nint m_pRayTraceHandle = nint.Zero; public static nint Handle;
public static bool m_bRayTraceLoaded = false; public static bool Loaded;
public static Func<nint, nint, nint, nint, nint, nint, bool>? _traceShape; public static Func<nint, Vector3, QAngle, nint, nint, TraceResult>? TraceShape;
public static Func<nint, nint, nint, nint, nint, nint, bool>? _traceEndShape; public static Func<nint, Vector3, Vector3, nint, nint, TraceResult>? TraceEndShape;
public static Func<nint, nint, nint, nint, nint, nint, nint, nint, bool>? _traceHullShape; public static Func<nint, Vector3, Vector3, Vector3, Vector3, nint, nint, TraceResult>? TraceHullShape;
public static Func<nint, Vector3, Vector3, nint, nint, TraceResult>? TraceShapeEx;
public static bool Initialize() public static bool Initialize()
{ {
m_pRayTraceHandle = (nint)Utilities.MetaFactory("CRayTraceInterface001")!; Handle = (nint)Utilities.MetaFactory("CRayTraceInterface001")!;
if (m_pRayTraceHandle == nint.Zero) if (Handle == 0)
{
Prints.ServerLog("[RayTraceImpl] Failed to get Ray-Trace interface handle. Is Ray-Trace MetaMod module loaded?", ConsoleColor.Red);
return false; return false;
}
Bind(); Bind();
m_bRayTraceLoaded = true; Loaded = true;
return true; return true;
} }
private static void Bind() private static void Bind()
{ {
int traceShapeIndex = 2; int shape, end, hull, ex;
int traceEndShapeIndex = 3;
int traceHullShapeIndex = 4;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
traceShapeIndex = 1; shape = 1;
traceEndShapeIndex = 2; end = 2;
traceHullShapeIndex = 3; hull = 3;
ex = 4;
}
else
{
shape = 2;
end = 3;
hull = 4;
ex = 5;
} }
_traceShape = VirtualFunction.Create<nint, nint, nint, nint, nint, nint, bool>(m_pRayTraceHandle, traceShapeIndex); TraceShape = VirtualFunction.Create<nint, Vector3, QAngle, nint, nint, TraceResult>(Handle, shape);
_traceEndShape = VirtualFunction.Create<nint, nint, nint, nint, nint, nint, bool>(m_pRayTraceHandle, traceEndShapeIndex); TraceEndShape = VirtualFunction.Create<nint, Vector3, Vector3, nint, nint, TraceResult>(Handle, end);
_traceHullShape = VirtualFunction.Create<nint, nint, nint, nint, nint, nint, nint, nint, bool>(m_pRayTraceHandle, traceHullShapeIndex); TraceHullShape = VirtualFunction.Create<nint, Vector3, Vector3, Vector3, Vector3, nint, nint, TraceResult>(Handle, hull);
TraceShapeEx = VirtualFunction.Create<nint, Vector3, Vector3, nint, nint, TraceResult>(Handle, ex);
} }
} }

View file

@ -144,36 +144,106 @@ struct TraceOptions
struct TraceResult struct TraceResult
{ {
float StartPosX; TraceResult()
float StartPosY; {
float StartPosZ; m_flFraction = 1.0f;
float EndPosX; m_bStartInSolid = false;
float EndPosY; m_bExactHitPoint = false;
float EndPosZ; m_pEnt = nullptr;
float HitPointX; m_pHitbox = nullptr;
float HitPointY; m_pSurfaceProperties = nullptr;
float HitPointZ; }
float NormalX;
float NormalY;
float NormalZ;
float Fraction;
float HitOffset;
int TriangleIndex; explicit TraceResult(const CGameTrace* pTrace, bool bResult)
int HitboxBoneIndex; {
int Contents; m_bTraceShapeResult = bResult;
int RayType; m_pSurfaceProperties = pTrace->m_pSurfaceProperties;
int AllSolid; m_pEnt = pTrace->m_pEnt;
int ExactHitPoint; m_pHitbox = pTrace->m_pHitbox;
m_hBody = pTrace->m_hBody;
m_hShape = pTrace->m_hShape;
m_nContents = pTrace->m_nContents;
m_BodyTransform = pTrace->m_BodyTransform;
m_ShapeAttributes = pTrace->m_ShapeAttributes;
m_vStartPos = pTrace->m_vStartPos;
m_vEndPos = pTrace->m_vEndPos;
m_vHitNormal = pTrace->m_vHitNormal;
m_vHitPoint = pTrace->m_vHitPoint;
m_flHitOffset = pTrace->m_flHitOffset;
m_flFraction = pTrace->m_flFraction;
m_nTriangle = pTrace->m_nTriangle;
m_nHitboxBoneIndex = pTrace->m_nHitboxBoneIndex;
m_eRayType = pTrace->m_eRayType;
m_bStartInSolid = pTrace->m_bStartInSolid;
m_bExactHitPoint = pTrace->m_bExactHitPoint;
}
CEntityInstance *HitEntity; TraceResult(const TraceResult&) = delete;
CHitBox *Hitbox; TraceResult& operator=(const TraceResult&) = delete;
CPhysSurfaceProperties *SurfaceProps;
IPhysicsBody *BodyHandle;
IPhysicsShape *ShapeHandle;
CTransform *BodyTransform; TraceResult(TraceResult&&) = default;
RnCollisionAttr_t *ShapeAttributes; TraceResult& operator=(TraceResult&&) = default;
const Vector& StartPos() const { return m_vStartPos; }
const Vector& EndPos() const { return m_vEndPos; }
const Vector& HitPoint() const { return m_vHitPoint; }
const Vector& Normal() const { return m_vHitNormal; }
float Fraction() const { return m_flFraction; }
float HitOffset() const { return m_flHitOffset; }
bool DidHit() const { return m_flFraction < 1.0f; }
bool IsAllSolid() const { return m_bStartInSolid; }
bool HasExactHit() const { return m_bExactHitPoint; }
CEntityInstance* HitEntity() const { return m_pEnt; }
int TriangleIndex() const { return m_nTriangle; }
int HitboxBoneIndex() const { return m_nHitboxBoneIndex; }
CHitBox* Hitbox() const { return const_cast<CHitBox*>(m_pHitbox); }
int Contents() const { return m_nContents; }
RayType_t RayType() const { return m_eRayType; }
IPhysicsBody* Body() const { return m_hBody; }
IPhysicsShape* Shape() const { return m_hShape; }
const CTransform& BodyTransform() const { return m_BodyTransform; }
const RnCollisionAttr_t& ShapeAttributes() const { return m_ShapeAttributes; }
CPhysSurfaceProperties* Surface() const { return const_cast<CPhysSurfaceProperties*>(m_pSurfaceProperties); }
private:
bool m_bTraceShapeResult; // return value from RayTrace::TraceShapeEx
const CPhysSurfaceProperties *m_pSurfaceProperties;
CEntityInstance *m_pEnt;
const CHitBox *m_pHitbox;
HPhysicsBody m_hBody;
HPhysicsShape m_hShape;
uint64 m_nContents; // contents on other side of surface hit
CTransform m_BodyTransform;
RnCollisionAttr_t m_ShapeAttributes;
Vector m_vStartPos; // start position
Vector m_vEndPos; // final position
Vector m_vHitNormal; // surface normal at impact
Vector m_vHitPoint; // exact hit point if m_bExactHitPoint is true, otherwise equal to m_vEndPos
float m_flHitOffset; // surface normal hit offset
float m_flFraction; // time completed, 1.0 = didn't hit anything
int32 m_nTriangle; // the index of the triangle that was hit
int16 m_nHitboxBoneIndex; // the index of the hitbox bone that was hit
RayType_t m_eRayType;
bool m_bStartInSolid; // if true, the initial point was in a solid area
bool m_bExactHitPoint; // if true, then m_vHitPoint is the exact hit point of the query and the shape
}; };
class CRayTraceInterface class CRayTraceInterface
@ -181,37 +251,25 @@ class CRayTraceInterface
public: public:
virtual ~CRayTraceInterface() = default; virtual ~CRayTraceInterface() = default;
virtual bool TraceShape( virtual TraceResult TraceShape(const Vector& vecStart,
const Vector* origin, const QAngle& angAngles,
const QAngle* viewangles, CEntityInstance* pIgnoreEntity,
CEntityInstance* ignoreEntity, TraceOptions* pTraceOptions) = 0;
const TraceOptions* opts,
TraceResult* outResult
) = 0;
virtual bool TraceEndShape( virtual TraceResult TraceEndShape(const Vector& vecStart,
const Vector* origin, const Vector& vecEnd,
const Vector* endOrigin, CEntityInstance* pIgnoreEntity,
CEntityInstance* ignoreEntity, TraceOptions* pTraceOptions) = 0;
const TraceOptions* opts,
TraceResult* outResult
) = 0;
virtual bool TraceHullShape( virtual TraceResult TraceHullShape(const Vector& vecStart,
const Vector* vecStart, const Vector& vecEnd,
const Vector* vecEnd, const Vector& vecMins,
const Vector* hullMins, const Vector& vecMaxs,
const Vector* hullMaxs, CEntityInstance* pIgnoreEntity,
CEntityInstance* ignoreEntity, TraceOptions* pTraceOptions) = 0;
const TraceOptions* opts,
TraceResult* outResult
) = 0;
virtual bool TraceShapeEx( virtual TraceResult TraceShapeEx(const Vector& vecStart,
const Vector* vecStart, const Vector& vecEnd,
const Vector* vecEnd, CTraceFilter* pTraceFilter,
CTraceFilter* filterInc, Ray_t* pRay) = 0;
Ray_t* rayInc,
TraceResult* outResult
) = 0;
}; };

View file

@ -15,27 +15,16 @@ namespace RayTracePlugin::RayTrace
{ {
CRayTrace g_CRayTrace; CRayTrace g_CRayTrace;
using TraceShapeFn = bool(*)(void* pThis, bool CRayTrace::Initialize()
Ray_t& ray,
Vector& start,
Vector& end,
CTraceFilter* filter,
CGameTrace* trace);
static TraceShapeFn s_TraceShape = nullptr;
bool Initialize()
{ {
DynLibUtils::CModule libserver = DynLibUtils::CModule(shared::g_pServer); m_pCNavPhysicsInterfaceVTable = DynLibUtils::CModule(shared::g_pServer).GetVirtualTableByName("CNavPhysicsInterface").RCast<void**>();
void** pVTable = libserver.GetVirtualTableByName("CNavPhysicsInterface").RCast<void**>(); if (!m_pCNavPhysicsInterfaceVTable)
if (!pVTable)
{ {
FP_ERROR("Failed to find CNavPhysicsInterface VTable!"); FP_WARN("Tried getting virtual function from a null vtable.");
return false; return false;
} }
s_TraceShape = DynLibUtils::CMemory(pVTable[shared::g_pGameConfig->GetOffset("CNavPhysicsInterface_TraceShape")]).RCast<TraceShapeFn>(); m_pCNavPhysicsInterface_TraceShape = m_pCNavPhysicsInterfaceVTable[shared::g_pGameConfig->GetOffset("CNavPhysicsInterface_TraceShape")];
return true; return true;
} }
@ -54,167 +43,129 @@ namespace RayTracePlugin::RayTrace
beam->DispatchSpawn(); beam->DispatchSpawn();
} }
std::optional<TraceResult> TraceShapeEx( TraceResult CRayTrace::TraceShape(const Vector& vecStart, const QAngle& angAngles, CEntityInstance* pIgnoreEntity, TraceOptions* pTraceOptions)
const Vector& start,
const Vector& end,
CTraceFilter& filterInc,
Ray_t rayInc)
{ {
if (!s_TraceShape) { CTraceFilterEx filter = pIgnoreEntity ? CTraceFilterEx(static_cast<CBaseEntity*>(pIgnoreEntity)) : CTraceFilterEx();
FP_ERROR("CNavPhysicsInterface::TraceShape is not bound!");
return std::nullopt; filter.m_nInteractsAs = 0;
filter.m_nInteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS);
filter.m_nInteractsExclude = 0;
if (pTraceOptions)
{
if (pTraceOptions->InteractsAs != 0)
filter.m_nInteractsAs = pTraceOptions->InteractsAs;
if (pTraceOptions->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS))
filter.m_nInteractsWith = pTraceOptions->InteractsWith;
if (pTraceOptions->InteractsExclude != 0)
filter.m_nInteractsExclude = pTraceOptions->InteractsExclude;
} }
thread_local 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 = (int)tr.m_eRayType;
r.AllSolid = tr.m_bStartInSolid;
r.ExactHitPoint = tr.m_bExactHitPoint;
r.HitEntity = (CEntityInstance*)tr.m_pEnt;
r.Hitbox = (CHitBox*)tr.m_pHitbox;
r.SurfaceProps = (CPhysSurfaceProperties*)tr.m_pSurfaceProperties;
r.BodyHandle = (IPhysicsBody*)tr.m_hBody;
r.ShapeHandle = (IPhysicsShape*)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; Vector forward;
AngleVectors(viewangles, &forward); AngleVectors(angAngles, &forward);
Vector endOrigin{ Vector vecEnd{
origin.x + forward.x * 8192.f, vecStart.x + forward.x * 8192.f,
origin.y + forward.y * 8192.f, vecStart.y + forward.y * 8192.f,
origin.z + forward.z * 8192.f vecStart.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; Ray_t ray;
auto res = TraceShapeEx(origin, endOrigin, filter, ray); auto res = TraceShapeEx(vecStart, vecEnd, &filter, &ray);
if (opts && opts->DrawBeam) if (pTraceOptions && pTraceOptions->DrawBeam)
{ {
Color col = res.has_value() ? colors::Red().ToValveColor() : colors::Green().ToValveColor(); Color col = res.DidHit() ? colors::Red().ToValveColor() : colors::Green().ToValveColor();
DrawBeam(origin, res ? Vector(res->EndPosX, res->EndPosY, res->EndPosZ) : endOrigin, col); DrawBeam(vecStart, res.DidHit() ? res.HitPoint() : vecEnd, col);
} }
return res; return res;
} }
std::optional<TraceResult> TraceEndShape( TraceResult CRayTrace::TraceEndShape(const Vector& vecStart, const Vector& vecEnd, CEntityInstance* pIgnoreEntity, TraceOptions* pTraceOptions)
const Vector& origin,
const Vector& endOrigin,
CEntityInstance* ignoreEntity,
const TraceOptions* opts)
{ {
CTraceFilterEx filter = ignoreEntity ? CTraceFilterEx(static_cast<CBaseEntity*>(ignoreEntity)) : CTraceFilterEx(); CTraceFilterEx filter = pIgnoreEntity ? CTraceFilterEx(static_cast<CBaseEntity*>(pIgnoreEntity)) : CTraceFilterEx();
filter.m_nInteractsAs = 0; filter.m_nInteractsAs = 0;
filter.m_nInteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS); filter.m_nInteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS);
filter.m_nInteractsExclude = 0; filter.m_nInteractsExclude = 0;
if (opts) if (pTraceOptions)
{ {
if (opts->InteractsAs != 0) if (pTraceOptions->InteractsAs != 0)
filter.m_nInteractsAs = opts->InteractsAs; filter.m_nInteractsAs = pTraceOptions->InteractsAs;
if (opts->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS)) if (pTraceOptions->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS))
filter.m_nInteractsWith = opts->InteractsWith; filter.m_nInteractsWith = pTraceOptions->InteractsWith;
if (opts->InteractsExclude != 0) if (pTraceOptions->InteractsExclude != 0)
filter.m_nInteractsExclude = opts->InteractsExclude; filter.m_nInteractsExclude = pTraceOptions->InteractsExclude;
} }
Ray_t ray; Ray_t ray;
auto res = TraceShapeEx(origin, endOrigin, filter, ray); auto res = TraceShapeEx(vecStart, vecEnd, &filter, &ray);
if (opts && opts->DrawBeam) if (pTraceOptions && pTraceOptions->DrawBeam)
{ {
Color col = res.has_value() ? colors::Red().ToValveColor() : colors::Green().ToValveColor(); Color col = res.DidHit() ? colors::Red().ToValveColor() : colors::Green().ToValveColor();
DrawBeam(origin, res ? Vector(res->EndPosX, res->EndPosY, res->EndPosZ) : endOrigin, col); DrawBeam(vecStart, res.DidHit() ? res.HitPoint() : vecEnd, col);
} }
return res; return res;
} }
std::optional<TraceResult> TraceHullShape(const Vector &vecStart, const Vector &vecEnd, const Vector &hullMins, TraceResult CRayTrace::TraceHullShape(const Vector& vecStart, const Vector& vecEnd, const Vector& vecMins,
const Vector &hullMaxs, CEntityInstance *ignoreEntity, const TraceOptions *opts) { const Vector& vecMaxs, CEntityInstance* pIgnoreEntity, TraceOptions* pTraceOptions)
CTraceFilterEx filter = ignoreEntity ? CTraceFilterEx(static_cast<CBaseEntity*>(ignoreEntity)) : CTraceFilterEx(); {
CTraceFilterEx filter = pIgnoreEntity ? CTraceFilterEx(static_cast<CBaseEntity*>(pIgnoreEntity)) : CTraceFilterEx();
filter.m_nInteractsAs = 0; filter.m_nInteractsAs = 0;
filter.m_nInteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS); filter.m_nInteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS);
filter.m_nInteractsExclude = 0; filter.m_nInteractsExclude = 0;
if (opts) if (pTraceOptions)
{ {
if (opts->InteractsAs != 0) if (pTraceOptions->InteractsAs != 0)
filter.m_nInteractsAs = opts->InteractsAs; filter.m_nInteractsAs = pTraceOptions->InteractsAs;
if (opts->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS)) if (pTraceOptions->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS))
filter.m_nInteractsWith = opts->InteractsWith; filter.m_nInteractsWith = pTraceOptions->InteractsWith;
if (opts->InteractsExclude != 0) if (pTraceOptions->InteractsExclude != 0)
filter.m_nInteractsExclude = opts->InteractsExclude; filter.m_nInteractsExclude = pTraceOptions->InteractsExclude;
} }
Ray_t ray; Ray_t ray;
ray.Init(hullMins, hullMaxs); ray.Init(vecMins, vecMaxs);
auto res = TraceShapeEx(vecStart, vecEnd, filter, ray);
if (opts && opts->DrawBeam) auto res = TraceShapeEx(vecStart, vecEnd, &filter, &ray);
if (pTraceOptions && pTraceOptions->DrawBeam)
{ {
Color col = res.has_value() ? colors::Red().ToValveColor() : colors::Green().ToValveColor(); Color col = res.DidHit() ? colors::Red().ToValveColor() : colors::Green().ToValveColor();
DrawBeam(vecStart, res ? Vector(res->EndPosX, res->EndPosY, res->EndPosZ) : vecEnd, col); DrawBeam(vecStart, res.DidHit() ? res.HitPoint() : vecEnd, col);
} }
return res; return res;
} }
TraceResult CRayTrace::TraceShapeEx(const Vector& vecStart, const Vector& vecEnd, CTraceFilter* pTraceFilter, Ray_t* pRay)
{
if (!m_pCNavPhysicsInterface_TraceShape)
{
FP_ERROR("CNavPhysicsInterface::TraceShape is not bound!");
return TraceResult();
}
Vector vecStartCopy = vecStart;
Vector vecEndCopy = vecEnd;
CGameTrace trace;
bool bResult = m_pCNavPhysicsInterface_TraceShape.RCast<
bool (*)(void*, Ray_t&, Vector&, Vector&, CTraceFilter*, CGameTrace*)>()(
nullptr, *pRay, vecStartCopy, vecEndCopy, pTraceFilter, &trace);
return TraceResult(&trace, bResult);
}
} }

View file

@ -27,98 +27,18 @@ namespace RayTracePlugin::RayTrace
} }
}; };
bool Initialize(); class CRayTrace : public CRayTraceInterface {
std::optional<TraceResult> TraceShape(
const Vector& origin,
const QAngle& viewangles,
CEntityInstance* ignoreEntity = nullptr,
const TraceOptions* opts = nullptr);
std::optional<TraceResult> TraceEndShape(
const Vector& origin,
const Vector& endOrigin,
CEntityInstance* ignoreEntity = nullptr,
const TraceOptions* opts = nullptr);
std::optional<TraceResult> TraceHullShape(
const Vector& vecStart,
const Vector& vecEnd,
const Vector& hullMins,
const Vector& hullMaxs,
CEntityInstance* ignoreEntity = nullptr,
const TraceOptions* opts = nullptr);
std::optional<TraceResult> TraceShapeEx(
const Vector& vecStart,
const Vector& vecEnd,
CTraceFilter& filterInc,
Ray_t rayInc);
class CRayTrace : public CRayTraceInterface
{
public: public:
bool TraceShape( bool Initialize();
const Vector* origin, public:
const QAngle* viewangles, TraceResult TraceShape(const Vector& vecStart, const QAngle& angAngles, CEntityInstance* pIgnoreEntity, TraceOptions* pTraceOptions) override;
CEntityInstance* ignoreEntity, TraceResult TraceEndShape(const Vector& vecStart, const Vector& vecEnd, CEntityInstance* pIgnoreEntity, TraceOptions* pTraceOptions) override;
const TraceOptions* opts, TraceResult TraceHullShape(const Vector& vecStart, const Vector& vecEnd, const Vector& vecMins, const Vector& vecMaxs, CEntityInstance* pIgnoreEntity, TraceOptions* pTraceOptions) override;
TraceResult* outResult) override TraceResult TraceShapeEx(const Vector& vecStart, const Vector& vecEnd, CTraceFilter* pTraceFilter, Ray_t* pRay) override;
{ protected:
auto result = RayTrace::TraceShape(*origin, *viewangles, ignoreEntity, opts); DynLibUtils::CMemory m_pCNavPhysicsInterface_TraceShape;
if (!result.has_value()) protected:
return false; void** m_pCNavPhysicsInterfaceVTable;
*outResult = result.value();
return true;
}
bool TraceEndShape(
const Vector* origin,
const Vector* endOrigin,
CEntityInstance* ignoreEntity,
const TraceOptions* opts,
TraceResult* outResult) override
{
auto result = RayTrace::TraceEndShape(*origin, *endOrigin, ignoreEntity, opts);
if (!result.has_value())
return false;
*outResult = result.value();
return true;
}
bool TraceHullShape(
const Vector* vecStart,
const Vector* vecEnd,
const Vector* hullMins,
const Vector* hullMaxs,
CEntityInstance* ignoreEntity,
const TraceOptions* opts,
TraceResult* outResult) override
{
auto result = RayTrace::TraceHullShape(*vecStart, *vecEnd, *hullMins, *hullMaxs, ignoreEntity, opts);
if (!result.has_value())
return false;
*outResult = result.value();
return true;
}
bool TraceShapeEx(
const Vector* vecStart,
const Vector* vecEnd,
CTraceFilter* filterInc,
Ray_t* rayInc,
TraceResult* outResult) override
{
auto result = RayTrace::TraceShapeEx(*vecStart, *vecEnd, *filterInc, *rayInc);
if (!result.has_value())
return false;
*outResult = result.value();
return true;
}
}; };
extern CRayTrace g_CRayTrace; extern CRayTrace g_CRayTrace;