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

@ -11,7 +11,7 @@ namespace RayTraceAPI
{
#region Native Structs (matching C++ layout exactly)
[Flags]
public enum InteractionLayers: ulong
public enum InteractionLayers : ulong
{
None = 0,
Solid = 0x1,
@ -64,13 +64,15 @@ namespace RayTraceAPI
MASK_NPC_MOVE = Solid | Window | NPCClip | PassBullets
}
[StructLayout(LayoutKind.Explicit, Size = 32)]
public unsafe struct TraceOptions
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct TraceOptions
{
[FieldOffset(0)] public ulong InteractsAs;
[FieldOffset(8)] public ulong InteractsWith;
[FieldOffset(16)] public ulong InteractsExclude;
[FieldOffset(24)] public int DrawBeam;
public ulong InteractsAs;
public ulong InteractsWith;
public ulong InteractsExclude;
public int DrawBeam;
private int _pad;
public TraceOptions()
{
@ -80,7 +82,8 @@ namespace RayTraceAPI
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;
InteractsWith = (ulong)interactsWith;
@ -89,49 +92,59 @@ namespace RayTraceAPI
}
}
[StructLayout(LayoutKind.Explicit, Size = 136)]
[StructLayout(LayoutKind.Sequential)]
public unsafe struct TraceResult
{
[FieldOffset(0)] public float StartPosX;
[FieldOffset(4)] public float StartPosY;
[FieldOffset(8)] public float StartPosZ;
public Vector3 StartPos;
public Vector3 EndPos;
public Vector3 HitPoint;
public Vector3 Normal;
[FieldOffset(12)] public float EndPosX;
[FieldOffset(16)] public float EndPosY;
[FieldOffset(20)] public float EndPosZ;
public float Fraction;
public float HitOffset;
[FieldOffset(24)] public float HitPointX;
[FieldOffset(28)] public float HitPointY;
[FieldOffset(32)] public float HitPointZ;
public int TriangleIndex;
public short HitboxBoneIndex;
private short _pad;
[FieldOffset(36)] public float NormalX;
[FieldOffset(40)] public float NormalY;
[FieldOffset(44)] public float NormalZ;
public int Contents;
public int RayType;
[FieldOffset(48)] public float Fraction;
[FieldOffset(52)] public float HitOffset;
public bool StartInSolid;
public bool ExactHitPoint;
[FieldOffset(56)] public int TriangleIndex;
[FieldOffset(60)] public int HitboxBoneIndex;
public nint HitEntity;
public nint Hitbox;
public nint Surface;
public nint Body;
public nint Shape;
[FieldOffset(64)] public int Contents;
[FieldOffset(68)] public int RayType;
public nint BodyTransform;
public nint ShapeAttributes;
[FieldOffset(72)] public int AllSolid;
[FieldOffset(76)] public int ExactHitPoint;
public readonly bool DidHit() => Fraction < 1.0f;
public readonly bool IsAllSolid() => StartInSolid;
public readonly bool HasExactHit() => ExactHitPoint;
// pointer section
[FieldOffset(80)] public nint HitEntityPtr;
[FieldOffset(88)] public nint HitboxPtr;
[FieldOffset(96)] public nint SurfacePropsPtr;
[FieldOffset(104)] public nint BodyHandle;
[FieldOffset(112)] public nint ShapeHandle;
public readonly int GetTriangleIndex() => TriangleIndex;
public readonly int GetHitboxBoneIndex() => HitboxBoneIndex;
public readonly int GetContents() => Contents;
public readonly int GetRayType() => RayType;
// thread safe heap pointer section
[FieldOffset(120)] public nint BodyTransformPtr;
[FieldOffset(128)] public nint ShapeAttributesPtr;
public readonly Vector3 GetStartPos() => StartPos;
public readonly Vector3 GetEndPos() => EndPos;
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)
throw new NullReferenceException();
@ -139,36 +152,58 @@ namespace RayTraceAPI
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)
return null;
return (T)Activator.CreateInstance(typeof(T), ptr)!;
{
value = null;
return false;
}
public Vector3 StartPos => new(StartPosX, StartPosY, StartPosZ);
public Vector3 EndPos => new(EndPosX, EndPosY, EndPosZ);
public Vector3 HitPoint => new(HitPointX, HitPointY, HitPointZ);
public Vector3 Normal => new(NormalX, NormalY, NormalZ);
value = (T*)ptr;
return true;
}
public bool DidHit => Fraction < 1.0f;
public bool IsAllSolid => AllSolid != 0;
public bool HasExactHit => ExactHitPoint != 0;
public readonly CEntityInstance HitEntityPtr() => new(HitEntity);
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
public interface CRayTraceInterface
{
public unsafe bool TraceShape(Vector origin, QAngle angles, CBaseEntity? ignoreEntity, TraceOptions options,
out TraceResult result);
TraceResult TraceShape(
in Vector3 start,
in QAngle angles,
CEntityInstance ignoreEntity,
in TraceOptions options);
public unsafe bool TraceEndShape(Vector origin, Vector endOrigin, CBaseEntity? ignoreEntity,
TraceOptions options, out TraceResult result);
TraceResult TraceEndShape(
in Vector3 start,
in Vector3 end,
CEntityInstance ignoreEntity,
in TraceOptions options);
public unsafe bool TraceHullShape(Vector vecStart, Vector vecEnd, Vector hullMins, Vector hullMaxs,
CBaseEntity? ignoreEntity, TraceOptions options, out TraceResult result);
TraceResult TraceHullShape(
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.
//
using System.Buffers;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using System.Text;
@ -17,6 +19,8 @@ using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils;
using RayTraceAPI;
using QAngle = RayTraceAPI.QAngle;
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
namespace RayTraceImpl;
@ -54,112 +58,122 @@ public class RayTraceImpl : BasePlugin
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 false;
TraceResult resultBuffer = default;
TraceOptions optionsBuffer = options;
bool success = NativeBridge._traceShape!(NativeBridge.m_pRayTraceHandle,
origin.Handle,
angles.Handle,
ignoreEntity?.Handle ?? nint.Zero,
(nint)(&optionsBuffer),
(nint)(&resultBuffer));
result = resultBuffer;
return success;
return NativeBridge.TraceShape!(
NativeBridge.Handle,
start,
angles,
ignore.Handle,
(nint)Unsafe.AsPointer(ref Unsafe.AsRef(in options))
);
}
}
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 false;
TraceResult resultBuffer = default;
TraceOptions optionsBuffer = options;
bool success = NativeBridge._traceEndShape!(NativeBridge.m_pRayTraceHandle,
origin.Handle,
endOrigin.Handle,
ignoreEntity?.Handle ?? nint.Zero,
(nint)(&optionsBuffer),
(nint)(&resultBuffer));
result = resultBuffer;
return success;
return NativeBridge.TraceEndShape!(
NativeBridge.Handle,
start,
end,
ignore.Handle,
(nint)Unsafe.AsPointer(ref Unsafe.AsRef(in options))
);
}
}
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 false;
return NativeBridge.TraceHullShape!(
NativeBridge.Handle,
start,
end,
mins,
maxs,
ignore.Handle,
(nint)Unsafe.AsPointer(ref Unsafe.AsRef(in options))
);
}
}
TraceResult resultBuffer = default;
TraceOptions optionsBuffer = options;
public TraceResult TraceShapeEx(in Vector3 start, in Vector3 end, nint filter, nint ray)
{
unsafe
{
if (!NativeBridge.Loaded)
return default;
bool success = NativeBridge._traceHullShape!(NativeBridge.m_pRayTraceHandle,
vecStart.Handle,
vecEnd.Handle,
hullMins.Handle,
hullMaxs.Handle,
ignoreEntity?.Handle ?? nint.Zero,
(nint)(&optionsBuffer),
(nint)(&resultBuffer));
result = resultBuffer;
return success;
return NativeBridge.TraceShapeEx!(
NativeBridge.Handle,
start,
end,
filter,
ray
);
}
}
}
public static class NativeBridge
{
public static nint m_pRayTraceHandle = nint.Zero;
public static bool m_bRayTraceLoaded = false;
public static nint Handle;
public static bool Loaded;
public static Func<nint, nint, nint, nint, nint, nint, bool>? _traceShape;
public static Func<nint, nint, nint, nint, nint, nint, bool>? _traceEndShape;
public static Func<nint, nint, nint, nint, nint, nint, nint, nint, bool>? _traceHullShape;
public static Func<nint, Vector3, QAngle, nint, nint, TraceResult>? TraceShape;
public static Func<nint, Vector3, Vector3, nint, nint, TraceResult>? TraceEndShape;
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()
{
m_pRayTraceHandle = (nint)Utilities.MetaFactory("CRayTraceInterface001")!;
Handle = (nint)Utilities.MetaFactory("CRayTraceInterface001")!;
if (m_pRayTraceHandle == nint.Zero)
{
Prints.ServerLog("[RayTraceImpl] Failed to get Ray-Trace interface handle. Is Ray-Trace MetaMod module loaded?", ConsoleColor.Red);
if (Handle == 0)
return false;
}
Bind();
m_bRayTraceLoaded = true;
Loaded = true;
return true;
}
private static void Bind()
{
int traceShapeIndex = 2;
int traceEndShapeIndex = 3;
int traceHullShapeIndex = 4;
int shape, end, hull, ex;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
traceShapeIndex = 1;
traceEndShapeIndex = 2;
traceHullShapeIndex = 3;
shape = 1;
end = 2;
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);
_traceEndShape = VirtualFunction.Create<nint, nint, nint, nint, nint, nint, bool>(m_pRayTraceHandle, traceEndShapeIndex);
_traceHullShape = VirtualFunction.Create<nint, nint, nint, nint, nint, nint, nint, nint, bool>(m_pRayTraceHandle, traceHullShapeIndex);
TraceShape = VirtualFunction.Create<nint, Vector3, QAngle, nint, nint, TraceResult>(Handle, shape);
TraceEndShape = VirtualFunction.Create<nint, Vector3, Vector3, nint, nint, TraceResult>(Handle, end);
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
{
float StartPosX;
float StartPosY;
float StartPosZ;
float EndPosX;
float EndPosY;
float EndPosZ;
float HitPointX;
float HitPointY;
float HitPointZ;
float NormalX;
float NormalY;
float NormalZ;
float Fraction;
float HitOffset;
TraceResult()
{
m_flFraction = 1.0f;
m_bStartInSolid = false;
m_bExactHitPoint = false;
m_pEnt = nullptr;
m_pHitbox = nullptr;
m_pSurfaceProperties = nullptr;
}
int TriangleIndex;
int HitboxBoneIndex;
int Contents;
int RayType;
int AllSolid;
int ExactHitPoint;
explicit TraceResult(const CGameTrace* pTrace, bool bResult)
{
m_bTraceShapeResult = bResult;
m_pSurfaceProperties = pTrace->m_pSurfaceProperties;
m_pEnt = pTrace->m_pEnt;
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;
CHitBox *Hitbox;
CPhysSurfaceProperties *SurfaceProps;
IPhysicsBody *BodyHandle;
IPhysicsShape *ShapeHandle;
TraceResult(const TraceResult&) = delete;
TraceResult& operator=(const TraceResult&) = delete;
CTransform *BodyTransform;
RnCollisionAttr_t *ShapeAttributes;
TraceResult(TraceResult&&) = default;
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
@ -181,37 +251,25 @@ class CRayTraceInterface
public:
virtual ~CRayTraceInterface() = default;
virtual bool TraceShape(
const Vector* origin,
const QAngle* viewangles,
CEntityInstance* ignoreEntity,
const TraceOptions* opts,
TraceResult* outResult
) = 0;
virtual TraceResult TraceShape(const Vector& vecStart,
const QAngle& angAngles,
CEntityInstance* pIgnoreEntity,
TraceOptions* pTraceOptions) = 0;
virtual bool TraceEndShape(
const Vector* origin,
const Vector* endOrigin,
CEntityInstance* ignoreEntity,
const TraceOptions* opts,
TraceResult* outResult
) = 0;
virtual TraceResult TraceEndShape(const Vector& vecStart,
const Vector& vecEnd,
CEntityInstance* pIgnoreEntity,
TraceOptions* pTraceOptions) = 0;
virtual bool TraceHullShape(
const Vector* vecStart,
const Vector* vecEnd,
const Vector* hullMins,
const Vector* hullMaxs,
CEntityInstance* ignoreEntity,
const TraceOptions* opts,
TraceResult* outResult
) = 0;
virtual TraceResult TraceHullShape(const Vector& vecStart,
const Vector& vecEnd,
const Vector& vecMins,
const Vector& vecMaxs,
CEntityInstance* pIgnoreEntity,
TraceOptions* pTraceOptions) = 0;
virtual bool TraceShapeEx(
const Vector* vecStart,
const Vector* vecEnd,
CTraceFilter* filterInc,
Ray_t* rayInc,
TraceResult* outResult
) = 0;
virtual TraceResult TraceShapeEx(const Vector& vecStart,
const Vector& vecEnd,
CTraceFilter* pTraceFilter,
Ray_t* pRay) = 0;
};

View file

@ -15,27 +15,16 @@ 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()
bool CRayTrace::Initialize()
{
DynLibUtils::CModule libserver = DynLibUtils::CModule(shared::g_pServer);
void** pVTable = libserver.GetVirtualTableByName("CNavPhysicsInterface").RCast<void**>();
if (!pVTable)
m_pCNavPhysicsInterfaceVTable = DynLibUtils::CModule(shared::g_pServer).GetVirtualTableByName("CNavPhysicsInterface").RCast<void**>();
if (!m_pCNavPhysicsInterfaceVTable)
{
FP_ERROR("Failed to find CNavPhysicsInterface VTable!");
FP_WARN("Tried getting virtual function from a null vtable.");
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;
}
@ -54,167 +43,129 @@ namespace RayTracePlugin::RayTrace
beam->DispatchSpawn();
}
std::optional<TraceResult> TraceShapeEx(
const Vector& start,
const Vector& end,
CTraceFilter& filterInc,
Ray_t rayInc)
TraceResult CRayTrace::TraceShape(const Vector& vecStart, const QAngle& angAngles, CEntityInstance* pIgnoreEntity, TraceOptions* pTraceOptions)
{
if (!s_TraceShape) {
FP_ERROR("CNavPhysicsInterface::TraceShape is not bound!");
return std::nullopt;
CTraceFilterEx filter = pIgnoreEntity ? CTraceFilterEx(static_cast<CBaseEntity*>(pIgnoreEntity)) : CTraceFilterEx();
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;
AngleVectors(viewangles, &forward);
Vector endOrigin{
origin.x + forward.x * 8192.f,
origin.y + forward.y * 8192.f,
origin.z + forward.z * 8192.f
AngleVectors(angAngles, &forward);
Vector vecEnd{
vecStart.x + forward.x * 8192.f,
vecStart.y + forward.y * 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;
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();
DrawBeam(origin, res ? Vector(res->EndPosX, res->EndPosY, res->EndPosZ) : endOrigin, col);
Color col = res.DidHit() ? colors::Red().ToValveColor() : colors::Green().ToValveColor();
DrawBeam(vecStart, res.DidHit() ? res.HitPoint() : vecEnd, col);
}
return res;
}
std::optional<TraceResult> TraceEndShape(
const Vector& origin,
const Vector& endOrigin,
CEntityInstance* ignoreEntity,
const TraceOptions* opts)
TraceResult CRayTrace::TraceEndShape(const Vector& vecStart, const Vector& vecEnd, 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_nInteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS);
filter.m_nInteractsExclude = 0;
if (opts)
if (pTraceOptions)
{
if (opts->InteractsAs != 0)
filter.m_nInteractsAs = opts->InteractsAs;
if (pTraceOptions->InteractsAs != 0)
filter.m_nInteractsAs = pTraceOptions->InteractsAs;
if (opts->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS))
filter.m_nInteractsWith = opts->InteractsWith;
if (pTraceOptions->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS))
filter.m_nInteractsWith = pTraceOptions->InteractsWith;
if (opts->InteractsExclude != 0)
filter.m_nInteractsExclude = opts->InteractsExclude;
if (pTraceOptions->InteractsExclude != 0)
filter.m_nInteractsExclude = pTraceOptions->InteractsExclude;
}
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();
DrawBeam(origin, res ? Vector(res->EndPosX, res->EndPosY, res->EndPosZ) : endOrigin, col);
Color col = res.DidHit() ? colors::Red().ToValveColor() : colors::Green().ToValveColor();
DrawBeam(vecStart, res.DidHit() ? res.HitPoint() : vecEnd, 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();
TraceResult CRayTrace::TraceHullShape(const Vector& vecStart, const Vector& vecEnd, const Vector& vecMins,
const Vector& vecMaxs, CEntityInstance* pIgnoreEntity, TraceOptions* pTraceOptions)
{
CTraceFilterEx filter = pIgnoreEntity ? CTraceFilterEx(static_cast<CBaseEntity*>(pIgnoreEntity)) : CTraceFilterEx();
filter.m_nInteractsAs = 0;
filter.m_nInteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS);
filter.m_nInteractsExclude = 0;
if (opts)
if (pTraceOptions)
{
if (opts->InteractsAs != 0)
filter.m_nInteractsAs = opts->InteractsAs;
if (pTraceOptions->InteractsAs != 0)
filter.m_nInteractsAs = pTraceOptions->InteractsAs;
if (opts->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS))
filter.m_nInteractsWith = opts->InteractsWith;
if (pTraceOptions->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS))
filter.m_nInteractsWith = pTraceOptions->InteractsWith;
if (opts->InteractsExclude != 0)
filter.m_nInteractsExclude = opts->InteractsExclude;
if (pTraceOptions->InteractsExclude != 0)
filter.m_nInteractsExclude = pTraceOptions->InteractsExclude;
}
Ray_t ray;
ray.Init(hullMins, hullMaxs);
auto res = TraceShapeEx(vecStart, vecEnd, filter, ray);
ray.Init(vecMins, vecMaxs);
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();
DrawBeam(vecStart, res ? Vector(res->EndPosX, res->EndPosY, res->EndPosZ) : vecEnd, col);
Color col = res.DidHit() ? colors::Red().ToValveColor() : colors::Green().ToValveColor();
DrawBeam(vecStart, res.DidHit() ? res.HitPoint() : vecEnd, col);
}
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();
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
{
class CRayTrace : public CRayTraceInterface {
public:
bool TraceShape(
const Vector* origin,
const QAngle* viewangles,
CEntityInstance* ignoreEntity,
const TraceOptions* opts,
TraceResult* outResult) override
{
auto result = RayTrace::TraceShape(*origin, *viewangles, ignoreEntity, opts);
if (!result.has_value())
return false;
*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;
}
bool Initialize();
public:
TraceResult TraceShape(const Vector& vecStart, const QAngle& angAngles, CEntityInstance* pIgnoreEntity, TraceOptions* pTraceOptions) override;
TraceResult TraceEndShape(const Vector& vecStart, const Vector& vecEnd, CEntityInstance* pIgnoreEntity, TraceOptions* pTraceOptions) override;
TraceResult TraceHullShape(const Vector& vecStart, const Vector& vecEnd, const Vector& vecMins, const Vector& vecMaxs, CEntityInstance* pIgnoreEntity, TraceOptions* pTraceOptions) override;
TraceResult TraceShapeEx(const Vector& vecStart, const Vector& vecEnd, CTraceFilter* pTraceFilter, Ray_t* pRay) override;
protected:
DynLibUtils::CMemory m_pCNavPhysicsInterface_TraceShape;
protected:
void** m_pCNavPhysicsInterfaceVTable;
};
extern CRayTrace g_CRayTrace;