fable/val Public Public: anyone can read this; nobody can change it.
forked from benjivers/val
workbenchthis machine
Files f9684ed1bb99e56b05e36b22256d41a87611661b
| 1 | /** |
| 2 | * Where this person is looking. |
| 3 | * |
| 4 | * The view angle is the browser's to move: the mouse arrives at frame rate, |
| 5 | * and a snapshot is a description of a moment already gone. The client used |
| 6 | * to take `snap.me.angle` on every snapshot, which dragged the camera back |
| 7 | * to a stale angle thirty times a second — worst exactly when you turned |
| 8 | * fastest, because that is when the stale angle is furthest away. |
| 9 | * |
| 10 | * So the local angle is the camera's, and the server's angle is taken only |
| 11 | * when it is telling us something we did not say: there is no view yet, the |
| 12 | * body under us changed, we respawned, or the angle that came back is one we |
| 13 | * never sent. That last one is what the sent log is for — the server echoes |
| 14 | * our own angle back, rounded, so an angle matching nothing we sent in the |
| 15 | * last second came from the match (a round start recentring everybody at the |
| 16 | * site) rather than from us, and is worth taking. |
| 17 | * |
| 18 | * Nothing here is sent anywhere: the angle still leaves through the input |
| 19 | * timer exactly as it always did. |
| 20 | */ |
| 21 | |
| 22 | /** How long a sent angle is remembered, in seconds. */ |
| 23 | export const SENT_MEMORY = 1.2; |
| 24 | /** How close an echo must be to count as ours. The server rounds to 0.1. */ |
| 25 | export const SENT_TOLERANCE = 0.08; |
| 26 | |
| 27 | /** `corrected` counts the times the server's angle replaced ours: every one is a jump of the view. */ |
| 28 | export const makeYaw = (angle = 0) => ({ angle, id: "", alive: false, ready: false, sent: [], corrected: 0 }); |
| 29 | |
| 30 | /** The short way round from one angle to another, in (-π, π]. */ |
| 31 | export const shortWay = (from, to) => ((to - from + Math.PI * 3) % (Math.PI * 2)) - Math.PI; |
| 32 | |
| 33 | /** A mouse delta, or an arrow key's share of a second. Ours, always taken. */ |
| 34 | export function turn(yaw, delta) { |
| 35 | yaw.angle += delta; |
| 36 | return yaw.angle; |
| 37 | } |
| 38 | |
| 39 | /** Point it somewhere outright: the top-down view's pointer aim. */ |
| 40 | export function aim(yaw, angle) { |
| 41 | yaw.angle = angle; |
| 42 | return yaw.angle; |
| 43 | } |
| 44 | |
| 45 | /** Remember an angle we told the server about, at a time in seconds. */ |
| 46 | export function told(yaw, angle, at) { |
| 47 | yaw.sent.push({ at, angle }); |
| 48 | while (yaw.sent.length && yaw.sent[0].at < at - SENT_MEMORY) yaw.sent.shift(); |
| 49 | return yaw; |
| 50 | } |
| 51 | |
| 52 | /** Is this angle one we sent recently? An echo, not a correction. */ |
| 53 | const ours = (yaw, angle, at) => |
| 54 | yaw.sent.some((s) => s.at >= at - SENT_MEMORY && Math.abs(shortWay(s.angle, angle)) <= SENT_TOLERANCE); |
| 55 | |
| 56 | /** |
| 57 | * A snapshot landed. Returns the angle to look along, having decided whether |
| 58 | * the server's word replaces ours. |
| 59 | * |
| 60 | * `me` is the snapshot's own body: `{ id, angle, alive }`. `at` is now, in |
| 61 | * seconds. An empty sent log is not evidence of anything — a client that has |
| 62 | * not spoken yet keeps what it has. |
| 63 | */ |
| 64 | export function settle(yaw, me, at) { |
| 65 | const seatChanged = !yaw.ready || me.id !== yaw.id; |
| 66 | const respawned = me.alive && !yaw.alive; |
| 67 | const corrected = yaw.sent.length > 0 && !ours(yaw, me.angle, at); |
| 68 | if (seatChanged || respawned || corrected) { |
| 69 | if (yaw.ready) yaw.corrected += 1; |
| 70 | yaw.angle = me.angle; |
| 71 | yaw.sent.length = 0; |
| 72 | } |
| 73 | yaw.id = me.id; |
| 74 | yaw.alive = me.alive; |
| 75 | yaw.ready = true; |
| 76 | return yaw.angle; |
| 77 | } |