diff --git a/managed/RayTrace/RayTraceApi/RayTraceApi.cs b/managed/RayTrace/RayTraceApi/RayTraceApi.cs index 66b8b29..cc41a6f 100644 --- a/managed/RayTrace/RayTraceApi/RayTraceApi.cs +++ b/managed/RayTrace/RayTraceApi/RayTraceApi.cs @@ -11,164 +11,199 @@ namespace RayTraceAPI { #region Native Structs (matching C++ layout exactly) [Flags] - public enum InteractionLayers: ulong - { - None = 0, - Solid = 0x1, - Hitboxes = 0x2, - Trigger = 0x4, - Sky = 0x8, - PlayerClip = 0x10, - NPCClip = 0x20, - BlockLOS = 0x40, - BlockLight = 0x80, - Ladder = 0x100, - Pickup = 0x200, - BlockSound = 0x400, - NoDraw = 0x800, - Window = 0x1000, - PassBullets = 0x2000, - WorldGeometry = 0x4000, - Water = 0x8000, - Slime = 0x10000, - TouchAll = 0x20000, - Player = 0x40000, - NPC = 0x80000, - Debris = 0x100000, - Physics_Prop = 0x200000, - NavIgnore = 0x400000, - NavLocalIgnore = 0x800000, - PostProcessingVolume = 0x1000000, - UnusedLayer3 = 0x2000000, - CarriedObject = 0x4000000, - PushAway = 0x8000000, - ServerEntityOnClient = 0x10000000, - CarriedWeapon = 0x20000000, - StaticLevel = 0x40000000, - csgo_team1 = 0x80000000, - csgo_team2 = 0x100000000, - csgo_grenadeclip = 0x200000000, - csgo_droneclip = 0x400000000, - csgo_moveable = 0x800000000, - csgo_opaque = 0x1000000000, - csgo_monster = 0x2000000000, - csgo_thrown_grenade = 0x8000000000, + public enum InteractionLayers : ulong + { + None = 0, + Solid = 0x1, + Hitboxes = 0x2, + Trigger = 0x4, + Sky = 0x8, + PlayerClip = 0x10, + NPCClip = 0x20, + BlockLOS = 0x40, + BlockLight = 0x80, + Ladder = 0x100, + Pickup = 0x200, + BlockSound = 0x400, + NoDraw = 0x800, + Window = 0x1000, + PassBullets = 0x2000, + WorldGeometry = 0x4000, + Water = 0x8000, + Slime = 0x10000, + TouchAll = 0x20000, + Player = 0x40000, + NPC = 0x80000, + Debris = 0x100000, + Physics_Prop = 0x200000, + NavIgnore = 0x400000, + NavLocalIgnore = 0x800000, + PostProcessingVolume = 0x1000000, + UnusedLayer3 = 0x2000000, + CarriedObject = 0x4000000, + PushAway = 0x8000000, + ServerEntityOnClient = 0x10000000, + CarriedWeapon = 0x20000000, + StaticLevel = 0x40000000, + csgo_team1 = 0x80000000, + csgo_team2 = 0x100000000, + csgo_grenadeclip = 0x200000000, + csgo_droneclip = 0x400000000, + csgo_moveable = 0x800000000, + csgo_opaque = 0x1000000000, + csgo_monster = 0x2000000000, + csgo_thrown_grenade = 0x8000000000, - MASK_SHOT_PHYSICS = Solid | PlayerClip | Window | PassBullets | Player | NPC | Physics_Prop, - MASK_SHOT_HITBOX = Hitboxes | Player | NPC, - MASK_SHOT_FULL = MASK_SHOT_PHYSICS | Hitboxes, - MASK_WORLD_ONLY = Solid | Window | PassBullets, - MASK_GRENADE = Solid | Window | Physics_Prop | PassBullets, - MASK_BRUSH_ONLY = Solid | Window, - MASK_PLAYER_MOVE = Solid | Window | PlayerClip | PassBullets, - MASK_NPC_MOVE = Solid | Window | NPCClip | PassBullets - } + MASK_SHOT_PHYSICS = Solid | PlayerClip | Window | PassBullets | Player | NPC | Physics_Prop, + MASK_SHOT_HITBOX = Hitboxes | Player | NPC, + MASK_SHOT_FULL = MASK_SHOT_PHYSICS | Hitboxes, + MASK_WORLD_ONLY = Solid | Window | PassBullets, + MASK_GRENADE = Solid | Window | Physics_Prop | PassBullets, + MASK_BRUSH_ONLY = Solid | Window, + MASK_PLAYER_MOVE = Solid | Window | PlayerClip | PassBullets, + MASK_NPC_MOVE = Solid | Window | NPCClip | PassBullets + } - [StructLayout(LayoutKind.Explicit, Size = 32)] - public unsafe struct TraceOptions - { - [FieldOffset(0)] public ulong InteractsAs; - [FieldOffset(8)] public ulong InteractsWith; - [FieldOffset(16)] public ulong InteractsExclude; - [FieldOffset(24)] public int DrawBeam; + [StructLayout(LayoutKind.Sequential, Pack = 8)] + public struct TraceOptions + { + public ulong InteractsAs; + public ulong InteractsWith; + public ulong InteractsExclude; + public int DrawBeam; - public TraceOptions() - { - InteractsAs = 0; - InteractsWith = (ulong)InteractionLayers.MASK_SHOT_PHYSICS; - InteractsExclude = 0; - DrawBeam = 0; - } + private int _pad; - public TraceOptions(InteractionLayers interactsAs, InteractionLayers interactsWith, InteractionLayers interactsExclude = 0, bool drawBeam = false) - { - InteractsAs = (ulong)interactsAs; - InteractsWith = (ulong)interactsWith; - InteractsExclude = (ulong)interactsExclude; - DrawBeam = drawBeam ? 1 : 0; - } - } + public TraceOptions() + { + InteractsAs = 0; + InteractsWith = (ulong)InteractionLayers.MASK_SHOT_PHYSICS; + InteractsExclude = 0; + DrawBeam = 0; + } - [StructLayout(LayoutKind.Explicit, Size = 136)] - public unsafe struct TraceResult - { - [FieldOffset(0)] public float StartPosX; - [FieldOffset(4)] public float StartPosY; - [FieldOffset(8)] public float StartPosZ; + public TraceOptions(InteractionLayers interactsAs, InteractionLayers interactsWith, + InteractionLayers interactsExclude = 0, bool drawBeam = false) + { + InteractsAs = (ulong)interactsAs; + InteractsWith = (ulong)interactsWith; + InteractsExclude = (ulong)interactsExclude; + DrawBeam = drawBeam ? 1 : 0; + } + } - [FieldOffset(12)] public float EndPosX; - [FieldOffset(16)] public float EndPosY; - [FieldOffset(20)] public float EndPosZ; + [StructLayout(LayoutKind.Sequential)] + public unsafe struct TraceResult + { + public Vector3 StartPos; + public Vector3 EndPos; + public Vector3 HitPoint; + public Vector3 Normal; - [FieldOffset(24)] public float HitPointX; - [FieldOffset(28)] public float HitPointY; - [FieldOffset(32)] public float HitPointZ; + public float Fraction; + public float HitOffset; - [FieldOffset(36)] public float NormalX; - [FieldOffset(40)] public float NormalY; - [FieldOffset(44)] public float NormalZ; + public int TriangleIndex; + public short HitboxBoneIndex; + private short _pad; - [FieldOffset(48)] public float Fraction; - [FieldOffset(52)] public float HitOffset; + public int Contents; + public int RayType; - [FieldOffset(56)] public int TriangleIndex; - [FieldOffset(60)] public int HitboxBoneIndex; + public bool StartInSolid; + public bool ExactHitPoint; - [FieldOffset(64)] public int Contents; - [FieldOffset(68)] public int RayType; + public nint HitEntity; + public nint Hitbox; + public nint Surface; + public nint Body; + public nint Shape; - [FieldOffset(72)] public int AllSolid; - [FieldOffset(76)] public int ExactHitPoint; + public nint BodyTransform; + public nint ShapeAttributes; - // 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 bool DidHit() => Fraction < 1.0f; + public readonly bool IsAllSolid() => StartInSolid; + public readonly bool HasExactHit() => ExactHitPoint; - // thread safe heap pointer section - [FieldOffset(120)] public nint BodyTransformPtr; - [FieldOffset(128)] public nint ShapeAttributesPtr; + public readonly int GetTriangleIndex() => TriangleIndex; + public readonly int GetHitboxBoneIndex() => HitboxBoneIndex; + public readonly int GetContents() => Contents; + public readonly int GetRayType() => RayType; - public unsafe ref T GetRef(nint ptr) where T : unmanaged - { - if (ptr == 0) - throw new NullReferenceException(); + public readonly Vector3 GetStartPos() => StartPos; + public readonly Vector3 GetEndPos() => EndPos; + public readonly Vector3 GetHitPoint() => HitPoint; + public readonly Vector3 GetNormal() => Normal; - return ref *(T*)ptr; - } + public readonly float GetFraction() => Fraction; + public readonly float GetHitOffset() => HitOffset; - public T? GetObject(nint ptr) where T : class - { - if (ptr == 0) - return null; + public readonly T* GetPtr(nint ptr) where T : unmanaged + { + return (T*)ptr; + } - return (T)Activator.CreateInstance(typeof(T), ptr)!; - } + public readonly ref T GetRef(nint ptr) where T : unmanaged + { + if (ptr == 0) + throw new NullReferenceException(); - 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); + return ref *(T*)ptr; + } - public bool DidHit => Fraction < 1.0f; - public bool IsAllSolid => AllSolid != 0; - public bool HasExactHit => ExactHitPoint != 0; + public readonly bool TryGetRef(nint ptr, out T* value) where T : unmanaged + { + if (ptr == 0) + { + value = null; + return false; + } - public CEntityInstance? HitEntity => GetObject(HitEntityPtr); - } + value = (T*)ptr; + return true; + } + + public readonly CEntityInstance HitEntityPtr() => new(HitEntity); + + 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); } -} +} \ No newline at end of file diff --git a/managed/RayTrace/RayTraceImpl/RayTraceImpl.cs b/managed/RayTrace/RayTraceImpl/RayTraceImpl.cs index 59f003a..2e10bfa 100644 --- a/managed/RayTrace/RayTraceImpl/RayTraceImpl.cs +++ b/managed/RayTrace/RayTraceImpl/RayTraceImpl.cs @@ -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? _traceShape; - public static Func? _traceEndShape; - public static Func? _traceHullShape; + public static Func? TraceShape; + public static Func? TraceEndShape; + public static Func? TraceHullShape; + public static Func? 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(m_pRayTraceHandle, traceShapeIndex); - _traceEndShape = VirtualFunction.Create(m_pRayTraceHandle, traceEndShapeIndex); - _traceHullShape = VirtualFunction.Create(m_pRayTraceHandle, traceHullShapeIndex); + TraceShape = VirtualFunction.Create(Handle, shape); + TraceEndShape = VirtualFunction.Create(Handle, end); + TraceHullShape = VirtualFunction.Create(Handle, hull); + TraceShapeEx = VirtualFunction.Create(Handle, ex); } } diff --git a/public/craytraceinterface.h b/public/craytraceinterface.h index f00cdfc..d30d1be 100644 --- a/public/craytraceinterface.h +++ b/public/craytraceinterface.h @@ -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(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(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; }; diff --git a/src/raytrace.cpp b/src/raytrace.cpp index 879639b..b3f2e28 100644 --- a/src/raytrace.cpp +++ b/src/raytrace.cpp @@ -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(); - - if (!pVTable) + m_pCNavPhysicsInterfaceVTable = DynLibUtils::CModule(shared::g_pServer).GetVirtualTableByName("CNavPhysicsInterface").RCast(); + 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(); - + m_pCNavPhysicsInterface_TraceShape = m_pCNavPhysicsInterfaceVTable[shared::g_pGameConfig->GetOffset("CNavPhysicsInterface_TraceShape")]; return true; } @@ -54,167 +43,129 @@ namespace RayTracePlugin::RayTrace beam->DispatchSpawn(); } - std::optional 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(pIgnoreEntity)) : CTraceFilterEx(); + + filter.m_nInteractsAs = 0; + filter.m_nInteractsWith = static_cast(MASK_SHOT_PHYSICS); + filter.m_nInteractsExclude = 0; + + if (pTraceOptions) + { + if (pTraceOptions->InteractsAs != 0) + filter.m_nInteractsAs = pTraceOptions->InteractsAs; + + if (pTraceOptions->InteractsWith != static_cast(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 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(ignoreEntity)) : CTraceFilterEx(); - - filter.m_nInteractsAs = 0; - filter.m_nInteractsWith = static_cast(MASK_SHOT_PHYSICS); - filter.m_nInteractsExclude = 0; - - if (opts) - { - if (opts->InteractsAs != 0) - filter.m_nInteractsAs = opts->InteractsAs; - - if (opts->InteractsWith != static_cast(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 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(ignoreEntity)) : CTraceFilterEx(); + CTraceFilterEx filter = pIgnoreEntity ? CTraceFilterEx(static_cast(pIgnoreEntity)) : CTraceFilterEx(); filter.m_nInteractsAs = 0; filter.m_nInteractsWith = static_cast(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(MASK_SHOT_PHYSICS)) - filter.m_nInteractsWith = opts->InteractsWith; + if (pTraceOptions->InteractsWith != static_cast(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 TraceHullShape(const Vector &vecStart, const Vector &vecEnd, const Vector &hullMins, - const Vector &hullMaxs, CEntityInstance *ignoreEntity, const TraceOptions *opts) { - CTraceFilterEx filter = ignoreEntity ? CTraceFilterEx(static_cast(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(pIgnoreEntity)) : CTraceFilterEx(); filter.m_nInteractsAs = 0; filter.m_nInteractsWith = static_cast(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(MASK_SHOT_PHYSICS)) - filter.m_nInteractsWith = opts->InteractsWith; + if (pTraceOptions->InteractsWith != static_cast(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); + } } diff --git a/src/raytrace.h b/src/raytrace.h index e71538d..09604ce 100644 --- a/src/raytrace.h +++ b/src/raytrace.h @@ -27,98 +27,18 @@ namespace RayTracePlugin::RayTrace } }; - bool Initialize(); - - std::optional TraceShape( - const Vector& origin, - const QAngle& viewangles, - CEntityInstance* ignoreEntity = nullptr, - const TraceOptions* opts = nullptr); - - std::optional TraceEndShape( - const Vector& origin, - const Vector& endOrigin, - CEntityInstance* ignoreEntity = nullptr, - const TraceOptions* opts = nullptr); - - std::optional TraceHullShape( - const Vector& vecStart, - const Vector& vecEnd, - const Vector& hullMins, - const Vector& hullMaxs, - CEntityInstance* ignoreEntity = nullptr, - const TraceOptions* opts = nullptr); - - std::optional 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;