Skip to content

five-on-it / packages/net-client/src/remote-buffer

packages/net-client/src/remote-buffer ​

Snapshot interpolation for one remote entity: keeps the server's recent measurements of its pose and samples the pose at any (fractional) tick between them. Past the newest measurement of an entity in motion it extrapolates with the last velocity for up to MAX_EXTRAPOLATION_TICKS, then holds; one at rest (@foi/protocol's atRest, the server's own rule) is held where it was measured, which is exact: the server sends its pose the moment it sets off. A renderer sampling every remote every frame passes a sample of its own to write into, so a crowd costs no garbage.

Every sample pushed is a measurement the server made at the tick given (the snapshot reader says which entities a frame measured and when, FrameNews.posed; the intake, intake.ts, pushes those and nothing else), so the buffer keeps every sample with a newer tick: a pose at the same place with another velocity is a measurement like any other (a car coming to a stop), and nothing is ever filled in or dropped by a rule of the buffer's own. Before its first measurement's tick the entity's pose is unknown and there is no sample: a remote new to the client (come into the area of interest, spawned, living again under its id) is drawn from the tick of its first measurement on, moving as measured, never standing at it for the ticks before. The server sends a stop and a start the moment it sees one (whatever the entity's turn), so between a measurement at rest and the next in motion the entity stood until one snapshot before the second at the latest, and between one in motion and the next at rest it had stopped one snapshot before the second: the pose is held at rest over the rest and interpolated over the motion, never spread over a long stand. Two measurements at rest in different places mean the server moved the entity (it sat down on a bench, it was put somewhere): the pose steps to the second at its tick, its feet still, never a slide of a standing figure.

Over the motion a vehicle's position is a cubic Hermite curve through both measurements with both measured velocities (each measurement carries its velocity), not a straight line: the drawn velocity is continuous at every measurement, as the car's own is. A straight line drew a constant speed per segment, the segment's average, so a car accelerating smoothly was drawn with a step of its speed at every measurement (a far car's, a fifth of a second apart, is half a metre a second at 2.5 m/s²): an acceleration in jolts. Where the motion starts or ends at rest the curve starts or ends at the measured standstill, so a car pulls away and draws up as it did. A person or a dog changes its velocity within two or three ticks, at a moment the measurements do not say, and keeps the straight line and the segment's average (smoothMotion). The sample's speed is the speed the pose is drawn moving at, so a figure's feet and its body agree.

Far from the player the server sends an entity's pose every second or fourth snapshot (its tier, carried in every change of it: TIER_EVERY). Drawn the usual six ticks behind the newest snapshot, such an entity would be past its newest measurement for most of the time between its turns, guessed on and corrected at each: a sawtooth of its speed. So a buffer draws its entity further behind by its tier's period less one snapshot (TIER_DELAY_TICKS: nothing, three ticks, nine), and it is interpolated between two measurements at every frame. The delay follows the tier it is told at every change, never by a jump: it slews by RENDER_DRIFT of a tick per tick of render time (an entity coming nearer catches up five per cent faster, one going away falls five per cent behind), and a new entity starts at its tier's.

A pose drawn past the newest measurement is a guess (the last velocity, carried on), and a pose held at rest may be overtaken by a late measurement that says the entity had moved: at the first frame after new measurements come, what was last drawn is compared with what is known now of that tick, and the difference is drawn away over BLEND_TICKS instead of jumped, whether one late sample came or a burst of them at once (a stall of the link), and over longer when it is more than those ticks' worth of motion: at no more than a third again the entity's pace (BLEND_PACE_SHARE), so a car held through a stall catches up without a dash; a difference of metres (a teleport) is taken at once, and none at all (the usual frame: the newest measurement lies beyond the tick drawn) leaves nothing to blend.

Classes ​

Interfaces ​

Variables ​

Functions ​