Tracing
Namespace:
DeadworksManaged.Api
Cast rays and shapes through the world using the VPhys2 physics system. Useful for hit detection, line of sight, and collision checks.
Trace (Static Class)
All methods are no-ops if the physics query system is not yet ready.
Simple Ray Cast
Fire a line ray from start to end:
var result = Trace.Ray(
start: pawn.EyePosition,
end: pawn.EyePosition + forwardDirection * 1000f,
mask: MaskTrace.Solid,
ignore: pawn // skip the casting entity
);
if (result.DidHit)
{
Console.WriteLine($"Hit at {result.HitPosition}, fraction: {result.Fraction}");
}
TraceShape (Advanced)
Full control with custom ray shape and filter:
var ray = new Ray_t();
// Initialize ray shape...
var filter = new CTraceFilter();
// Configure filter...
CGameTrace trace;
Trace.TraceShape(start, end, ray, filter, out trace);
if (trace.DidHit)
{
var hitEntity = trace.HitEntity;
Console.WriteLine($"Hit: {hitEntity?.Classname} at {trace.HitPoint}");
}
SimpleTrace
Convenience method that builds the filter and ray from parameters:
CGameTrace trace;
Trace.SimpleTrace(
start, end,
RayType_t.Line,
RnQueryObjectSet.All,
interactMask, solidMask, triggerMask,
CollisionGroup.Default,
out trace,
ignoreEntity1: pawn,
ignoreEntity2: null
);
SimpleTraceAngles
Like SimpleTrace but uses pitch/yaw angles instead of an end point:
CGameTrace trace;
Trace.SimpleTraceAngles(
origin, angles,
RayType_t.Line,
RnQueryObjectSet.All,
interactMask, solidMask, triggerMask,
CollisionGroup.Default,
out trace,
ignoreEntity1: pawn,
ignoreEntity2: null,
maxDistance: 5000f
);
Trace Methods Summary
| Method | Description |
|---|---|
Ray(Vector3 start, Vector3 end, MaskTrace mask, CBaseEntity? ignore) | Simple line ray, returns TraceResult |
TraceShape(Vector3, Vector3, Ray_t, CTraceFilter, out CGameTrace) | Full shape trace with custom ray and filter |
SimpleTrace(...) | Convenience with individual parameters |
SimpleTraceAngles(...) | Like SimpleTrace but with angles and max distance |
TraceResult
Simplified result from Trace.Ray():
| Property | Type | Description |
|---|---|---|
DidHit | bool | Whether the ray hit something |
HitPosition | Vector3 | World position of the hit |
Fraction | float | 0.0 (at start) to 1.0 (at end) — how far the ray traveled |
Trace | CGameTrace | Full trace data |
CGameTrace
Full result of a VPhys2 shape trace:
| Member | Type | Description |
|---|---|---|
DidHit | bool | Whether the trace hit something |
HitPoint | Vector3 | World position of the hit |
HitNormal | Vector3 | Surface normal at hit point |
HitEntity | CBaseEntity? | Entity that was hit |
Ray Shapes
RayType_t
Shape type for trace queries:
| Value | Description |
|---|---|
| Line | Line ray (default) |
| Sphere | Sphere shape |
| Hull | AABB hull |
| Capsule | Capsule shape |
Shape Data Structs
| Struct | Description |
|---|---|
LineTrace | Line ray with optional radius (swept sphere) |
SphereTrace | Sphere at a fixed center point |
HullTrace | AABB hull swept along a ray |
CapsuleTrace | Capsule between two center points with radius |
MeshTrace | Convex mesh with bounds and vertices |
Collision Filtering
CollisionGroup
Determines which objects interact in physics simulation.
InteractionLayer
Individual content/interaction layers for building trace bitmasks.
MaskTrace
Bitmask combining InteractionLayer values:
| Value | Description |
|---|---|
Solid | Solid world geometry |
| (others) | Various content layer combinations |
RnQueryObjectSet
Controls which object sets are included:
| Value | Description |
|---|---|
All | All object sets (static, dynamic, locatable) |
CTraceFilter
Full trace filter with entity-aware filtering:
var filter = new CTraceFilter(true) {
IterateEntities = true,
QueryShapeAttributes = new RnQueryShapeAttr_t {
ObjectSetMask = RnQueryObjectSet.All,
InteractsWith = MaskTrace.Solid,
InteractsExclude = MaskTrace.Empty,
InteractsAs = MaskTrace.Empty,
CollisionGroup = CollisionGroup.CitadelBullet,
HitSolid = true,
}
};
// Ignore specific entities by index (requires unsafe)
unsafe {
filter.QueryShapeAttributes.EntityIdsToIgnore[0] = (uint)pawn.EntityIndex;
}
RnQueryShapeAttr_t
Query attributes for shape traces:
| Property | Type | Description |
|---|---|---|
ObjectSetMask | RnQueryObjectSet | Which object sets to query |
InteractsWith | MaskTrace | What the ray interacts with |
InteractsExclude | MaskTrace | What to exclude from interaction |
InteractsAs | MaskTrace | What the ray acts as |
CollisionGroup | CollisionGroup | Collision group for filtering |
HitSolid | bool | Whether to hit solid objects |
HitTrigger | bool | Whether to hit trigger volumes |
EntityIdsToIgnore | fixed uint[2] | Up to 2 entity indices to skip (requires unsafe) |
Trace.Ray with MaskTrace.Solid will hit trigger volumes like CPostProcessingVolume, returning DidHit=True with Fraction=0.000 if the ray starts inside one. For line-of-sight checks, use TraceShape with a CTraceFilter configured with CollisionGroup.CitadelBullet and HitSolid = true (without HitTrigger).
Example: Line-of-Sight Check
Bullet-style LOS check that ignores trigger volumes and specific entities:
var trace = CGameTrace.Create();
var ray = new Ray_t { Type = RayType_t.Line };
var filter = new CTraceFilter(true) {
IterateEntities = true,
QueryShapeAttributes = new RnQueryShapeAttr_t {
ObjectSetMask = RnQueryObjectSet.All,
InteractsWith = MaskTrace.Solid,
InteractsExclude = MaskTrace.Empty,
InteractsAs = MaskTrace.Empty,
CollisionGroup = CollisionGroup.CitadelBullet,
HitSolid = true,
}
};
unsafe {
filter.QueryShapeAttributes.EntityIdsToIgnore[0] = (uint)sourcePawn.EntityIndex;
filter.QueryShapeAttributes.EntityIdsToIgnore[1] = (uint)targetPawn.EntityIndex;
}
Trace.TraceShape(sourcePawn.EyePosition, targetPawn.EyePosition, ray, filter, ref trace);
bool hasLos = !trace.DidHit;
// trace.HitEntity?.Classname tells you what blocked (e.g. "CWorld" for walls)
EntityIdsToIgnore is a fixed-size buffer — accessing it requires unsafe code and <AllowUnsafeBlocks>true</AllowUnsafeBlocks> in your .csproj.
Example: Player Eye Trace
From the Deathmatch plugin:
[ChatCommand("trace")]
public HookResult OnTrace(ChatCommandContext ctx)
{
var pawn = ctx.Controller?.GetHeroPawn();
if (pawn == null) return HookResult.Handled;
var result = Trace.Ray(
pawn.EyePosition,
pawn.EyePosition + ForwardFromAngles(pawn.EyeAngles) * 5000f,
MaskTrace.Solid,
pawn
);
if (result.DidHit)
{
ctx.Controller.PrintToConsole($"Hit at {result.HitPosition}");
ctx.Controller.PrintToConsole($"Distance: {result.Fraction * 5000f} units");
}
return HookResult.Handled;
}
See Also
- Entities — Entity references in trace results
- Players —
EyePosition,EyeAngles,ViewAngles - Deathmatch Example — Trace system in practice