Update: add TraceHullShape

This commit is contained in:
SlynxCZ 2026-02-06 21:56:25 +04:00
parent 29e9201c0b
commit a8418ceabc
5 changed files with 140 additions and 25 deletions

View file

@ -49,7 +49,7 @@ public:
virtual bool TraceShape( virtual bool TraceShape(
const Vector* pOrigin, const Vector* pOrigin,
const QAngle* pViewAngles, const QAngle* pViewAngles,
CBaseEntity* pIgnorePlayer, CBaseEntity* pIgnoreEntity,
const TraceOptions* pOpts, const TraceOptions* pOpts,
TraceResult* pOutResult TraceResult* pOutResult
) = 0; ) = 0;
@ -57,7 +57,17 @@ public:
virtual bool TraceEndShape( virtual bool TraceEndShape(
const Vector* pOrigin, const Vector* pOrigin,
const Vector* pEndOrigin, const Vector* pEndOrigin,
CBaseEntity* pIgnorePlayer, CBaseEntity* pIgnoreEntity,
const TraceOptions* pOpts,
TraceResult* pOutResult
) = 0;
virtual bool TraceHullShape(
const Vector* pVecStart,
const Vector* pVecEnd,
const Vector* pHullMins,
const Vector* pHullMaxs,
CBaseEntity* pIgnoreEntity,
const TraceOptions* pOpts, const TraceOptions* pOpts,
TraceResult* pOutResult TraceResult* pOutResult
) = 0; ) = 0;
@ -196,10 +206,10 @@ public void DoTrace(CCSPlayerController player)
Due to C++ ABI differences: Due to C++ ABI differences:
| Platform | TraceShape index | TraceEndShape index | | Platform | TraceShape index | TraceEndShape index | TraceHullShape index |
| ------------------- | ---------------- | ------------------- | | ------------------- | ---------------- | ------------------- |----------------------|
| Linux (Itanium ABI) | 2 | 3 | | Linux (Itanium ABI) | 2 | 3 | 4 |
| Windows (MSVC ABI) | 1 | 2 | | Windows (MSVC ABI) | 1 | 2 | 3 |
`public/Example.cs` applies Itanium offsets by default. `public/Example.cs` applies Itanium offsets by default.

View file

@ -136,6 +136,7 @@ static_assert(
struct TraceOptions struct TraceOptions
{ {
uint64_t InteractsAs = 0;
uint64_t InteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS); uint64_t InteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS);
uint64_t InteractsExclude = 0; uint64_t InteractsExclude = 0;
int DrawBeam = 0; int DrawBeam = 0;
@ -158,7 +159,7 @@ public:
virtual bool TraceShape( virtual bool TraceShape(
const Vector* origin, const Vector* origin,
const QAngle* viewangles, const QAngle* viewangles,
CBaseEntity* ignorePlayer, CBaseEntity* ignoreEntity,
const TraceOptions* opts, const TraceOptions* opts,
TraceResult* outResult TraceResult* outResult
) = 0; ) = 0;
@ -166,7 +167,17 @@ public:
virtual bool TraceEndShape( virtual bool TraceEndShape(
const Vector* origin, const Vector* origin,
const Vector* endOrigin, const Vector* endOrigin,
CBaseEntity* ignorePlayer, CBaseEntity* ignoreEntity,
const TraceOptions* opts,
TraceResult* outResult
) = 0;
virtual bool TraceHullShape(
const Vector* vecStart,
const Vector* vecEnd,
const Vector* hullMins,
const Vector* hullMaxs,
CBaseEntity* ignoreEntity,
const TraceOptions* opts, const TraceOptions* opts,
TraceResult* outResult TraceResult* outResult
) = 0; ) = 0;

View file

@ -62,22 +62,25 @@ namespace RayTrace
MASK_NPC_MOVE = Solid | Window | NPCClip | PassBullets MASK_NPC_MOVE = Solid | Window | NPCClip | PassBullets
} }
[StructLayout(LayoutKind.Explicit, Size = 24)] [StructLayout(LayoutKind.Explicit, Size = 32)]
public struct TraceOptions public struct TraceOptions
{ {
[FieldOffset(0)] public ulong InteractsWith; [FieldOffset(0)] public ulong InteractsAs;
[FieldOffset(8)] public ulong InteractsExclude; [FieldOffset(8)] public ulong InteractsWith;
[FieldOffset(16)] public int DrawBeam; [FieldOffset(16)] public ulong InteractsExclude;
[FieldOffset(24)] public int DrawBeam;
public TraceOptions() public TraceOptions()
{ {
InteractsAs = 0;
InteractsWith = (ulong)InteractionLayers.MASK_SHOT_PHYSICS; InteractsWith = (ulong)InteractionLayers.MASK_SHOT_PHYSICS;
InteractsExclude = 0; InteractsExclude = 0;
DrawBeam = 0; DrawBeam = 0;
} }
public TraceOptions(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; InteractsWith = (ulong)interactsWith;
InteractsExclude = (ulong)interactsExclude; InteractsExclude = (ulong)interactsExclude;
DrawBeam = drawBeam ? 1 : 0; DrawBeam = drawBeam ? 1 : 0;
@ -111,6 +114,7 @@ namespace RayTrace
private static Func<nint, nint, nint, nint, nint, nint, bool>? _traceShape; private static Func<nint, nint, nint, nint, nint, nint, bool>? _traceShape;
private static Func<nint, nint, nint, nint, nint, nint, bool>? _traceEndShape; private static Func<nint, nint, nint, nint, nint, nint, bool>? _traceEndShape;
private static Func<nint, nint, nint, nint, nint, nint, nint, nint, bool>? _traceHullShape;
public static void Init() public static void Init()
{ {
@ -127,6 +131,7 @@ namespace RayTrace
{ {
_traceShape = VirtualFunction.Create<nint, nint, nint, nint, nint, nint, bool>(g_pRayTraceHandle, 2); _traceShape = VirtualFunction.Create<nint, nint, nint, nint, nint, nint, bool>(g_pRayTraceHandle, 2);
_traceEndShape = VirtualFunction.Create<nint, nint, nint, nint, nint, nint, bool>(g_pRayTraceHandle, 3); _traceEndShape = VirtualFunction.Create<nint, nint, nint, nint, nint, nint, bool>(g_pRayTraceHandle, 3);
_traceHullShape = VirtualFunction.Create<nint, nint, nint, nint, nint, nint, nint, nint, bool>(g_pRayTraceHandle, 4);
} }
public static unsafe bool TraceShape(Vector origin, QAngle angles, CBaseEntity? ignoreEntity, TraceOptions options, out TraceResult result) public static unsafe bool TraceShape(Vector origin, QAngle angles, CBaseEntity? ignoreEntity, TraceOptions options, out TraceResult result)
@ -170,5 +175,28 @@ namespace RayTrace
result = resultBuffer; result = resultBuffer;
return success; return success;
} }
public static unsafe bool TraceHullShape(Vector vecStart, Vector vecEnd, Vector hullMins, Vector hullMaxs, CBaseEntity? ignoreEntity, TraceOptions options, out TraceResult result)
{
result = default;
if (!g_bRayTraceLoaded || g_pRayTraceHandle == nint.Zero)
return false;
TraceResult resultBuffer = default;
TraceOptions optionsBuffer = options;
bool success = _traceHullShape!(g_pRayTraceHandle,
vecStart.Handle,
vecEnd.Handle,
hullMins.Handle,
hullMaxs.Handle,
ignoreEntity?.Handle ?? nint.Zero,
(nint)(&optionsBuffer),
(nint)(&resultBuffer));
result = resultBuffer;
return success;
}
} }
} }

View file

@ -82,7 +82,7 @@ namespace RayTracePlugin::RayTrace
std::optional<TraceResult> TraceShape( std::optional<TraceResult> TraceShape(
const Vector& origin, const Vector& origin,
const QAngle& viewangles, const QAngle& viewangles,
CBaseEntity* ignorePlayer, CBaseEntity* ignoreEntity,
const TraceOptions* opts) const TraceOptions* opts)
{ {
Vector forward; Vector forward;
@ -93,14 +93,18 @@ namespace RayTracePlugin::RayTrace
origin.z + forward.z * 8192.f origin.z + forward.z * 8192.f
}; };
CTraceFilterEx filter = ignorePlayer ? CTraceFilterEx(ignorePlayer) : CTraceFilterEx(); CTraceFilterEx filter = ignoreEntity ? CTraceFilterEx(ignoreEntity) : CTraceFilterEx();
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 (opts)
{ {
if (opts->InteractsWith != 0) if (opts->InteractsAs != 0)
filter.m_nInteractsAs = opts->InteractsAs;
if (opts->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS))
filter.m_nInteractsWith = opts->InteractsWith; filter.m_nInteractsWith = opts->InteractsWith;
if (opts->InteractsExclude != 0) if (opts->InteractsExclude != 0)
@ -122,17 +126,21 @@ namespace RayTracePlugin::RayTrace
std::optional<TraceResult> TraceEndShape( std::optional<TraceResult> TraceEndShape(
const Vector& origin, const Vector& origin,
const Vector& endOrigin, const Vector& endOrigin,
CBaseEntity* ignorePlayer, CBaseEntity* ignoreEntity,
const TraceOptions* opts) const TraceOptions* opts)
{ {
CTraceFilterEx filter = ignorePlayer ? CTraceFilterEx(ignorePlayer) : CTraceFilterEx(); CTraceFilterEx filter = ignoreEntity ? CTraceFilterEx(ignoreEntity) : CTraceFilterEx();
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 (opts)
{ {
if (opts->InteractsWith != 0) if (opts->InteractsAs != 0)
filter.m_nInteractsAs = opts->InteractsAs;
if (opts->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS))
filter.m_nInteractsWith = opts->InteractsWith; filter.m_nInteractsWith = opts->InteractsWith;
if (opts->InteractsExclude != 0) if (opts->InteractsExclude != 0)
@ -150,4 +158,37 @@ namespace RayTracePlugin::RayTrace
return res; return res;
} }
std::optional<TraceResult> TraceHullShape(const Vector &vecStart, const Vector &vecEnd, const Vector &hullMins,
const Vector &hullMaxs, CBaseEntity *ignoreEntity, const TraceOptions *opts) {
CTraceFilterEx filter = ignoreEntity ? CTraceFilterEx(ignoreEntity) : CTraceFilterEx();
filter.m_nInteractsAs = 0;
filter.m_nInteractsWith = static_cast<uint64_t>(MASK_SHOT_PHYSICS);
filter.m_nInteractsExclude = 0;
if (opts)
{
if (opts->InteractsAs != 0)
filter.m_nInteractsAs = opts->InteractsAs;
if (opts->InteractsWith != static_cast<uint64_t>(MASK_SHOT_PHYSICS))
filter.m_nInteractsWith = opts->InteractsWith;
if (opts->InteractsExclude != 0)
filter.m_nInteractsExclude = opts->InteractsExclude;
}
Ray_t ray;
ray.Init(hullMins, hullMaxs);
auto res = TraceShapeEx(vecStart, vecEnd, filter, ray);
if (opts && opts->DrawBeam)
{
Color col = res.has_value() ? colors::Red().ToValveColor() : colors::Green().ToValveColor();
DrawBeam(vecStart, res ? res->EndPos : vecEnd, col);
}
return res;
}
} }

View file

@ -32,13 +32,21 @@ namespace RayTracePlugin::RayTrace
std::optional<TraceResult> TraceShape( std::optional<TraceResult> TraceShape(
const Vector& origin, const Vector& origin,
const QAngle& viewangles, const QAngle& viewangles,
CBaseEntity* ignorePlayer = nullptr, CBaseEntity* ignoreEntity = nullptr,
const TraceOptions* opts = nullptr); const TraceOptions* opts = nullptr);
std::optional<TraceResult> TraceEndShape( std::optional<TraceResult> TraceEndShape(
const Vector& origin, const Vector& origin,
const Vector& endOrigin, const Vector& endOrigin,
CBaseEntity* ignorePlayer = nullptr, CBaseEntity* ignoreEntity = nullptr,
const TraceOptions* opts = nullptr);
std::optional<TraceResult> TraceHullShape(
const Vector& vecStart,
const Vector& vecEnd,
const Vector& hullMins,
const Vector& hullMaxs,
CBaseEntity* ignoreEntity = nullptr,
const TraceOptions* opts = nullptr); const TraceOptions* opts = nullptr);
std::optional<TraceResult> TraceShapeEx( std::optional<TraceResult> TraceShapeEx(
@ -53,11 +61,11 @@ namespace RayTracePlugin::RayTrace
bool TraceShape( bool TraceShape(
const Vector* origin, const Vector* origin,
const QAngle* viewangles, const QAngle* viewangles,
CBaseEntity* ignorePlayer, CBaseEntity* ignoreEntity,
const TraceOptions* opts, const TraceOptions* opts,
TraceResult* outResult) override TraceResult* outResult) override
{ {
auto result = RayTrace::TraceShape(*origin, *viewangles, ignorePlayer, opts); auto result = RayTrace::TraceShape(*origin, *viewangles, ignoreEntity, opts);
if (!result.has_value()) if (!result.has_value())
return false; return false;
@ -68,11 +76,28 @@ namespace RayTracePlugin::RayTrace
bool TraceEndShape( bool TraceEndShape(
const Vector* origin, const Vector* origin,
const Vector* endOrigin, const Vector* endOrigin,
CBaseEntity* ignorePlayer, CBaseEntity* ignoreEntity,
const TraceOptions* opts, const TraceOptions* opts,
TraceResult* outResult) override TraceResult* outResult) override
{ {
auto result = RayTrace::TraceEndShape(*origin, *endOrigin, ignorePlayer, opts); 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,
CBaseEntity* ignoreEntity,
const TraceOptions* opts,
TraceResult* outResult) override
{
auto result = RayTrace::TraceHullShape(*vecStart, *vecEnd, *hullMins, *hullMaxs, ignoreEntity, opts);
if (!result.has_value()) if (!result.has_value())
return false; return false;