Attempting to post my understanding of this at a more general level:
On the server, at level.time L a given clients pos.trTime will be the serverTime C of their most recent command. After each client think, and before each snapshot, the clients pos.trBase is the ps->origin generated by Pmove.
This is a contradiction: Is the trBase (and ps->origin and everything else that gets set from it) supposed to be the clients position at time L, or time C ? When interacting with other entities on the server, it is treated at as L, but when sent to the clients, it is treated as C.
In normal operation, the client tries to interpolate entities from snap to nextSnap. The timestamps on these are the L values from when G_RunFrame was run just prior to that snapshot. Each player entity in the snapshot has a trajectory_t pos, with a time C.
When the client goes to position the player for a given frame, it evaluates the trajectories using the snapshot time L. Thus even when interpolating between what were two valid positions on the server, it gets different results. It is treating what the server used as a position at time L as a position at time C and then extrapolating it forward to L. It then interpolates between those two extrapolated positions!
The trDuration is 50, but the difference between L and C is by observation, always more. Since the client will only extrapolate up to 50, that explains your player position being 50ms ahead of where it was on the server at time L. It also explains why a player extrapolates into solid objects, because even when interpolating between to valid snapshots, whose trBase positions are not in solid, evaluated positions will be extrapolated 50ms. Finally, it almost certainly introduces some jerkiness into player movement.
It is not clear why, even on a LAN, is there such a big delta between C and L in ClientEndFrame.
It seems to me that the client should treat the entity positions in the snapshots as being at time L. That is the time the server saw them at that position, and did the authoritative physics on them. Then when the client is properly interpolating, the players will always be truly between two valid positions. Extrapolating the base positions given in snap and nextSnap seems senseless, and wrong. The whole point of having two snapshots is that you are between too valid positions, rather than extrapolating all the time. If we wanted to extrapolate all the time (as we currently are) then we could just use the most recent snap!
When the client is forced to extrapolate (due to missing snaps etc), it should extrapolate forward from the most recent snap.The base position should still be at time L and the extrapolation should be based on how many client frames we are ahead of that.
Thoughts ? Corrections ?

:bump:
