Buggy Traces: A Gmod Issue or a Source One?

Previous thread where we discussed this briefly

Decided to make a thread for this because we haven’t really found a solution to this problem yet. This issue with traces has most likely gone unnoticed for quite some time due to it being a non-issue in a majority of the cases in which you would use traces, but would be a head scratcher for people who aren’t aware that it can happen in any mod utilizing them. This bug is pretty common in ACF if anyone is familiar with it, but doesn’t actually seem to be any fault of the mod.

tl;dr: traces are missing props which are moving towards the source of the trace if the trace is being directed at the specific prop’s position (tracing from one point to another). Traces with an end point past the prop have a 100% success rate however.


Top left number shows number of traces fired from the e2 chip next to the screens towards the ball, and bottom left shows how many miss, while the top right shows how many hit anything at all, and bottom right shows if it’s just stopping in empty space (in front of ball). We originally thought it was an issue with the getPos() function working with traces, but we’re not entirely sure if they are related. This isn’t just and e2 issue.

The issue seems to be almost a delay in traces being performed and they are doing some kind of prediction of where the object will be in the frame which the trace takes place, but doing a poor job of it. Almost as if overcompensating because they always hit an object moving away from the trace.

Here’s a quick video of it happening in ACF with a 100mm thick plate and an mg that only does ~10mm of pen. Nothing should be getting through the plate.


Realized I accidentally added in comment about changing velocity in the clip before I did it. Dunno how I missed that, but not really worth fixing now.

Would be nice to find the actual cause of this and perhaps even find a fix. Saves us some headaches on some things we’re working on now for ACF plus anything people work on in the future. Is this also able to be replicated in other source games?

Link again to the other thread if you still want to read what we already discussed.

For convenience, this theory is the most sensible (emphasis mine):

Perhaps setting the physics position would help as Think comes before any physics simulation happen.

I’ve suggested that, didn’t work according to SteebJerbs (I haven’t tried it myself)

For the record, I really don’t think this glitch has any meaningful/serious implications. When would you ever end a trace at an entity’s GetPos and actually care whether you’ve hit it or not?

ACF does this all the time as shown in the video. Each tick a round moves forward whatever velocity it’s traveling sending a trace to where it thinks it will be in the next tick. If that trace just so happens to end within the prop as we discussed, ACF counts that as a miss and ignores the prop entirely then continues to move forward until it hits something vital inside the vehicle causing it to explode.

HE in acf uses a form of getPos to check if props are visible to the explosion. Wherever the round detonates, it sends traces to props within the radius to check if ACF can see them in order to damage them. Once again any prop moving towards that explosion are likely to be ignored.

If this is a simple bug within gmod, we could possibly fix it and avoid having to do tons of retry tracing and back tracing to check if we missed something we shouldn’t, but if it’s a source bug, I’m not as confident about fixing it and unfortunately would have to resort to spamming more traces on any impact to check for this.

The simple solution would be to extend the trace further in the same direction, regardless of anything:

[lua]tr.endpos = (ent:GetPhysicsObject():GetPos() - tr.start):GetNormalized() * explosion_radius + tr.start[/lua]

I also recommend getting the physics object’s center of mass, because some entities have weird origins.

Edit: fixed snippet (+ tr.start)

This doesn’t solve all of the problems.
In ACF the projectiles cast out a segment every tick along their flight path, we can’t know to extend beyond a certain point because we don’t know if there’s anything to hit.
Now, we could probably do something like:

local Step = Velocity * DeltaTime
local NextPos = Pos + Step

local TraceRes = util.TraceLine({ start = Pos, endpos = Pos + Step*2 })

if TraceRes.Hit and TraceRes.Fraction <= 0.5 then -- Our trace is twice as long as it should be, so only accept things that hit before halfway
    -- do impact stuff

But that adds additional code to it and slows down a performance intensive portion of the script, and since the bug happens with the trace origin and endpos swapped we’d probably have to pull the start position back a bit as well:

local Step = Velocity * DeltaTime
local NextPos = Pos + Step

local TraceRes = util.TraceLine({ start = Pos - Step, endpos = Pos + Step*2 })

if TraceRes.Hit and TraceRes.Fraction <= 0.66 and TraceRes.Fraction >= 0.33 then -- Accept things only after a 1/3 and before 2/3 of the traces length
    -- do impact stuff

But now we’re getting fairly hacky, and effectively adding a required extra performance hit to every trace call. Nobody should have to do this.
In fact, the example presented wouldn’t even work. What if something hits it close to the origin, or near the end? Trace again, but reduce the segment length? That defeats the entire purpose.

We should also note that this is consistent across all use in Gmod, so it’s more than likely affecting other addons. Just as an example, bobbleheadbob’s bullet drop for SWEPs probably suffers the same issue.

I can at least attest to this being the case to some degree with the traceLine function. Some background, on a server I develop for, trace lines are used for bullet traces, ignoring the standard source bullet behaviour. There’s some partial agreement that weapons that are multishot and hence firing multiple traces have this kind of behaviour and can miss at point blank range.

I’m fairly certain this problem exists and it would be great if it were resolved.

What I want to also try with this is TraceHull and see if the same behaviour happens.