Skip to content

update: add Ray/Hull Trace API (INavPhysicsInterface)#1331

Open
SlynxCZ wants to merge 2 commits into
roflmuffin:mainfrom
SlynxCZ:SlynxCZ/nav_physics_impl
Open

update: add Ray/Hull Trace API (INavPhysicsInterface)#1331
SlynxCZ wants to merge 2 commits into
roflmuffin:mainfrom
SlynxCZ:SlynxCZ/nav_physics_impl

Conversation

@SlynxCZ
Copy link
Copy Markdown
Contributor

@SlynxCZ SlynxCZ commented Jun 2, 2026

Adds a complete ray and hull trace system to CounterStrikeSharp, exposing CS2's CNavPhysicsInterface vtable to C# plugins.

What changed

C++ (src/)

  • src/core/cs2_sdk/interfaces/navphysicsinterface.h/.cpp — adapts the existing INavPhysicsInterface static wrapper to use CSSharp's own modules::server->FindVirtualTable() instead of Source2Toolkit's DynLibUtils
  • src/scripting/natives/natives_raytrace.cpp/.yaml — 6 new natives:
    • TRACE_SHAPE / TRACE_END_SHAPE / TRACE_HULL_SHAPE — write into a caller-provided CSSTraceResult buffer (no heap allocation on C++ side)
    • POINT_CONTENTS — contents bitmask at world position
    • CHECK_AREA_OVERLAPPING_ENTITY — nav area vs entity AABB overlap
    • GET_ENTITY_WORLD_SPACE_AABB — world-space AABB of an entity
  • CTraceFilter is constructed with the entity's owner handle and hierarchy ID (read via schema with static caching), matching CTraceFilterEx behaviour from Source2Toolkit

C# (managed/)

  • Modules/Utils/Trace.cs
    • TraceOptionsInteractsAs, InteractsWith, InteractsExclude
    • TraceResult[StructLayout(Sequential, Pack=1)] unmanaged struct, stack-allocated by each Trace.* method and returned by value; zero heap allocation, zero native calls for field access
    • Trace static class — TraceShape, TraceEndShape, TraceHullShape, PointContents, CheckAreaOverlappingEntity, GetEntityWorldSpaceAABB
  • Modules/Utils/ContentsMask.csContents and Mask static classes with all CONTENTS_* and MASK_* constants from bspflags.h / const.h as const ulong

Usage

// Line trace from player eye position
var result = Trace.TraceShape(player.AbsOrigin!, player.EyeAngles, player);
if (result.DidHit())
    Server.PrintToConsole($"Hit {result.HitEntity().DesignerName} at {result.HitPoint}");

// Hull trace with custom mask
var result = Trace.TraceHullShape(start, end, mins, maxs,
    options: new TraceOptions { InteractsWith = Mask.PlayerSolid });

// AABB
Trace.GetEntityWorldSpaceAABB(entity, out var mins, out var maxs);

// Contents check
bool isSolid = (Trace.PointContents(pos) & Contents.Solid) != 0;

Notes

  • gamedata.json has no new entries required — vtable is found by RTTI name ("CNavPhysicsInterface")
  • CSSTraceResult layout is #pragma pack(1) and must stay in sync with TraceResult's [StructLayout(Sequential, Pack=1)]
  • CTransform / RnCollisionAttr_t are intentionally not exposed on the C# side; opaque pointers (nint) are available via Body(), Shape(), Surface(), Hitbox() for interop

@SlynxCZ SlynxCZ requested a review from roflmuffin as a code owner June 2, 2026 13:35
@roflmuffin
Copy link
Copy Markdown
Owner

roflmuffin commented Jun 2, 2026

I think this looks passable to me. It is a bit annoying with the opaque pointers to the structs we don't have definitions for, but it is better than nothing since CS#1.0 native struct support is terrible. I'll probably write some integration/game tests for this to try it out which may take me some time.

public CEntityInstance HitEntity() => new(m_pEnt);

/// <summary>Native <c>CHitBox*</c> — opaque pointer.</summary>
public nint Hitbox() => m_pHitbox;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth considering naming these something else, like HitboxPtr, just in case we do ever add the proper struct types for these later down the line and then we would have to make a breaking change to the existing property. Don't know what your thoughts are on that?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about naming them the way they those members are named as we could use NativeObject and construct them in same way as CEntityInstance wrapper is. So naming would be ideal, otherwise it can be changed right away.

@SlynxCZ
Copy link
Copy Markdown
Contributor Author

SlynxCZ commented Jun 2, 2026

I think this looks passable to me. It is a bit annoying with the opaque pointers to the structs we don't have definitions for, but it is better than nothing since CS#1.0 native struct support is terrible. I'll probably write some integration/game tests for this to try it out which may take me some time.

Thanks, yeah I didn't imlement them as we can use NativeObject or raw unsafe / marshal passing, also I had idea of having raytrace logic in core so we can just bump SDK and its fixed right away,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants