Skip to main content

Tracing

Namespace: DeadworksManaged.Api

A trace draws an invisible line through the world and tells you the first thing it hits. Use it to find what a player is looking at, whether two players can see each other, or where the ground is.

Trace a line between two points​

var result = Trace.Ray(start, end);

if (result.DidHit)
{
Console.WriteLine($"Hit something at {result.HitPosition}");
}

DidHit is false when the line reached end without touching anything.

Find what a player is looking at​

Start at the player's eyes and trace in the direction they are facing. Pass the player as ignore, or the line hits them first.

[Command("lookat")]
public void CmdLookAt(Caller caller)
{
var pawn = caller.Player?.GetHeroPawn();
if (pawn == null)
throw new CommandException("You need a hero to do that.");

var start = pawn.EyePosition;
var end = start + ForwardFromAngles(pawn.EyeAngles) * 5000f;

var result = Trace.Ray(start, end, ignore: pawn);

if (result.DidHit)
caller.Reply($"You are looking at {result.HitPosition}");
else
caller.Reply("You are looking at nothing.");
}

static Vector3 ForwardFromAngles(Vector3 angles)
{
float pitch = angles.X * MathF.PI / 180f;
float yaw = angles.Y * MathF.PI / 180f;

return new Vector3(
MathF.Cos(pitch) * MathF.Cos(yaw),
MathF.Cos(pitch) * MathF.Sin(yaw),
-MathF.Sin(pitch));
}

ForwardFromAngles turns the angles a player is facing into a direction. Copy it into your plugin.

Find out what was hit​

result.Trace.HitEntity is the entity the line hit.

var result = Trace.Ray(start, end, ignore: pawn);

var target = result.Trace.HitEntity?.As<CCitadelPlayerPawn>();
if (target != null)
{
// The line hit another player's hero
target.Hurt(50f, attacker: pawn);
}

Find how far away something is​

var result = Trace.Ray(start, end, ignore: pawn);

if (result.DidHit)
{
float distance = Vector3.Distance(start, result.HitPosition);
}

Find the ground below a point​

Trace straight down, and only let the line hit solid things.

var start = pawn.Position;
var end = start - Vector3.UnitZ * 10000f;

var result = Trace.Ray(start, end, InteractionLayer.Solid, ignore: pawn);

if (result.DidHit)
{
Vector3 ground = result.HitPosition;
}

Choose what the line can hit​

The third argument says which kinds of thing stop the line. Join more than one with |.

// Walls, floors and other solid things
Trace.Ray(start, end, InteractionLayer.Solid);

// Solid things, and the hitboxes of players and NPCs. This is the default
Trace.Ray(start, end, InteractionLayer.Solid | InteractionLayer.Hitbox);

Check whether one player can see another​

Trace from one player's eyes to the other's, ignoring both of them. If nothing is hit, there is nothing in the way.

var trace = CGameTrace.Create();

Trace.SimpleTrace(
a.EyePosition, b.EyePosition,
RayType_t.Line, RnQueryObjectSet.All,
InteractionLayer.Solid, InteractionLayer.None, InteractionLayer.None,
CollisionGroup.CitadelBullet, ref trace,
filterEntity: a, filterSecondEntity: b);

bool canSee = !trace.DidHit;

Trace.Ray can only ignore one entity, so this uses Trace.SimpleTrace, which can ignore two.