Bullet's pre-launch trace system is somewhat FUBAR

Issue #363 resolved
Matt Hands created an issue

The pre-launch trace (PLT) system for bullets is designed to trace any close range hit, where ballistics & time lag to target isn't going to be a factor. If positive, it avoids spawning a bullet & simply handles the resulting damage & hit effects right there.

This is primarily a network optimisation, as it avoids replicating the bullet actor to every client in range, just for that bullet to almost immediately detect the same hit as the PLT. A secondary benefit is the avoidance of processor time on both server & clients in spawning the bullet, moving it & handling the resulting collision. But the net optimisation is the much greater benefit, so PLTis of limited value in single player.

The problem is it doesn't work for a whole range of reasons. Many are connected with the use of HitPointTrace (HPT), which is an RO native function that seems to have some significant flaws, although we can't see what's going on. It's useful for tracing hits on a player pawn. Compared to a normal trace, it detects hits on player pawns that have no collision (highly relevant: vehicle occupants), and it returns the body part location of any hit. So it has a place, but we have to understand its limitations & failings and I've spent time investigating this.

PLT problems:

  1. Solely uses HPT to attempt to trace any actor, but HPT is only useful for tracing hits on a player pawn. It may return another 'intervening' actor if the trace would otherwise reach a player or maybe a player's bullet whip attachment. But if there isn't a player, it ignores other actors and returns none. This means that the PLT nearly always fails. And, as with many other bugs, solving that one reveals several others !

  2. Bullets sometimes pass through vehicles, e.g. through the side or rear of a half-track, especially the M3, hitting players who should have been protected. Seems worse when there are multiple players in the vehicle (overlapping whip attachments?). That is simply the main flaw of HPT: it should return any blocking actor in the way, but doesn't always. Some kind of 2nd trace verification is needed. Contributes to https://bitbucket.org/darklightgames/darkesthour/issues/345/passengers-can-be-shot-through-the-sides of some infantry vehicles.

  3. Ignores vehicle's collision static meshes. This is because it has to use the Instigator (the firing player pawn) to do the trace, as PLT happens in the WeaponFire class, which is not an actor & so can't access Actor functions. And any trace uses the collision properties of the actor it's called from, & a pawn doesn't bUseCollisionStaticMesh, which a projectile does. Result is crude collision boxes block PLT from reaching an exposed vehicle occupant who is enveloped inside the col box. Contributes to: https://bitbucket.org/darklightgames/darkesthour/issues/341/cant-damage-exposed-vehicle-occupants-who are 'enveloped' in a collision box.

  4. Inaccurate hit detection on player pawn. Appears to be caused because HPT "doesn't like short traces" (commented as such in RO code). Results in trace being out by maybe 6 inches laterally on a player, meaning mid air hits on right side of body and partly immune left side. Even though PLT is usually 2624 or 1314 UU (44/22m), a HPT of 10k UU still gives inaccurate results. Have to do a very long HPT of 65k UU, then do distance check on any returned actor. Believe this is the cause of https://bitbucket.org/darklightgames/darkesthour/issues/261/huge-offset-of-player-hit-collision.

  5. On net client, it plays the bullet hit effect for the LAST hit location, not where you've just fired. That's because native code calls ThirdPartyEffects() to spawn the hit effect slightly before the client receives the mHitLocation vector through replication. Have to delay & trigger hit effects from PostNetReceive().

There are probably some more !

Comments (4)

  1. Matt Hands reporter

    Think I have fixed all the issues listed above (not committed yet).

    But makes me wonder whether to just turn off PLT ! Could turn it off for single player - although certainly leave for now, as it makes testing much easier. Probably should skip PLT if firing a tracer, which would be simple.

  2. Matt Hands reporter

    Commit c438a0b fixes problems no. 1 to 4 listed above:

    1. Now uses a 2nd standard trace as well as HPT, so we check for any close actors that we should hit, not just player pawns.

    2. If the standard trace finds any valid, blocking actors closer than any traced player pawn hit, the invalid hit on the player is now ignored and the hit is registered only on the blocking actor.

    3. Instigator's collision settings are now temporarily set to bUseCollisionStaticMesh. This is reset as soon as the traces are done, so it's only for a split second. And that is harmless anyway, because if we set a player pawn to bUseCollisionStaticMesh, all that means is it has more complex collision detection with vehicles, i.e. the player's feet would follow the hull's shape more closely when standing on the vehicle, rather than simply standing on the crude collision box.

    4. HPT now does long 65k UU trace, which gives an accurate HitLocation on player pawns that are close to us. If HPT hits a player, we now check to see if the player was actually within HPT range.

    PLT functionality is moved into new PreLaunchTrace() function, so SpawnProjectile() is shorter & easier to read.

  3. Matt Hands reporter

    Commit 4060987 fixes remaining problem no.5, where net client spawns a hit effect for the LAST hit location, not where you've just fired.

    Here's a video Basnett showed me, which demonstrates the problem: https://www.youtube.com/watch?v=g7UQrYSY3e8

    Fix is to avoid spawning hit effects for a net client in ThirdPartyEffects() and instead let PostNetReceive() trigger spawning of hit effects only when the client receives the updated mHitLocation vector. bNetNotify is now always true for DHWeaponAttachment, so we get PostNetReceive() calls. Functionality is moved into new SpawnHitEffects() function, called from either ThirdPartEffects() or from PostNetReceive(), depending on net mode.

    UpdateHit() function on server now forces quick net update after setting new mHitLocation and SpawnHitCount values, as these are what a net client uses to trigger and play a hit effect. You still get a slight delay before the hit effect, but that's just replication & it can't be speeded up.

    Client has to do a very short trace, using received mHitLocation, to determine what it has hit and get a HitNormal, as these properties are not replicated to the client (only the mHitLocation is). Changed it so this trace uses the weapon's muzzle bone position, instead of the cruder Instigator pawn location, so we get a much more accurate clientside trace. Also rationalised the client's GetHitInfo() and GetVehicleHitInfo() functions, which seemed quite duplicating.

    What a marathon that was ! :)

  4. Log in to comment