ValveSoftware / halflife

Half-Life 1 engine based games
Other
3.6k stars 598 forks source link

Player gets stuck on diagonal geometry due to float imprecision #3586

Open AltimorTASDK opened 8 months ago

AltimorTASDK commented 8 months ago

Subtracting N(V dot N) isn't enough to ensure velocity/endpos is no longer directed towards the surface after float rounding. This is especially noticeable at high FPS where you have more chances to hit unlucky coordinates while sliding.

The original Quake 2 code passes an overbounce of 1.01 to PM_ClipVelocity to hack around this, but GoldSrc changed overbounce to 1 with no alternative solution.

Source Engine fixes it with the following check at the end of CGameMovement::ClipVelocity:

// iterate once to make sure we aren't still moving through the plane
float adjust = DotProduct( out, normal );
if ( adjust < 0.0f )
{
    // min this against a small number (but no further from zero than -DIST_EPSILON) to account for crossing a plane with a near-parallel normal
    adjust = MIN( adjust, -DIST_EPSILON );
    out -= ( normal * adjust );
}
AltimorTASDK commented 8 months ago

Demonstration:

https://github.com/ValveSoftware/halflife/assets/4999944/bba8d282-bdef-427e-8f26-d3c6c362becf

pierow commented 8 months ago

I'd like to see this fixed as well, but I'm not sure if the proposed solutions fix it. I just tried both in my mod and am still getting the issue. Then again, I think I've had this issue with diagonal walls manifest in a couple of ways, so maybe it does fix it in some cases.

I tried debugging this recently and from my testing narrowed it down to the PM_PlayerTrace call in this line returning different results for both server and client even when on a listen server. I haven't had the chance to dig deeper yet. https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/pm_shared/pm_shared.c#L830

Notably, this issue only happens when above 99fps, and then scales with fps.

AltimorTASDK commented 8 months ago

This happens at <100fps, but it’s less likely you end up in an unlucky spot along the wall.

Traces may differ due to networked coordinate quantization. DIST_EPSILON is 1/32 for Source’s quantization, may be different for goldsrc.

AltimorTASDK commented 7 months ago

Changing the < 0.0f to <= 0.0f to account for rounding towards zero seems to handle all cases.