The client lifts its fog over a strike's disc from its launch until its blast ends #141
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "task/3775-the-client-lifts-its-fog-over-the-disc-t"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Tracker: #3775
Step 3 of plan #3560. Every client lifts its fog over the disc a launched nuke reveals, from the launch until its blast ends, and the player-facing text records the whole change.
What it delivers
fogFriends(src/client/render/view.ts): the player's units and owned cities throughcollectFriends, then the reveal's sight sources, which every player gets, spectators included. The reveal's sources go after the units' and cities', so a disc that comes or goes only changes the friend count: the live field rebuilds once, as on a unit's death, and no unit's or city's stamp shifts.GameView.showRevealstakes them for the next frame. main.ts and the Nuke yard (src/mock/nuke.ts) pass the replica'sreveals()(step 2). The Map Yard (src/mock/map-yard.ts) passes its own strikes' through the sharedaddReveals, so?fog&doom=nukedraws the reveal. Its at-rest strike landed CRATER_AGE (30 s) earlier, past its window, so the at-rest yard draws as before.Tests
src/client/render/reveal.test.ts runs two clients, the launcher's and another player's. Neither has a unit or city with sight over the disc. Each is a Replica given the same frames (the strike in flight, then landed, then gone), each frame reaching it 3 ticks after the server's tick it carries. Each has its own Fog, fed
fogFriendsat every local tick with dt = 1/30. Read through the fog sheet'sliveandexploredtextures:due + BLAST_TICKS − 1;due + BLAST_TICKS, before the frame that unlists the strike arrives;Mutation check (a scratch dir outside the checkout,
vi.mockof src/shared/nuke.ts replacingrevealingandaddReveals, which calls it): the control passes.tick <= due + BLAST_TICKSfails with the disc seen through tick 770 (due + BLAST_TICKS), andtick < due + BLAST_TICKS − 1fails with it ending at 768, against the expected 769. With frames applied on their own tick, the<=mutant passed, because the frame that unlists the strike lands on the very tick the window ends. That is why the test delivers its frames late, as a real client receives them.Draw checks
Map Yard bench (src/bench/map.ts, Playwright WebKit, iPhone 15 landscape, on m5): 8 arms in one
map.ts 7 …call per session, 5 sessions × 7 runs, 840 pages, no page errors. Base6b8535dand head were built fromgit archivetrees. The head's yard dist was built at1249534and is byte-identical to the final head 9ffb2a4's (diff -r), because the later commit touches only the test.Frame times fall into two clusters on every arm (at 1× the base's quartiles are 1.10 / 1.43 / 1.70 ms), so the pooled medians land in either. The paired median takes each arm against its partner loaded in the same rotation (session, run, view). In ms a frame, with the phone estimate (7.5×) in brackets:
?fog&doom=nuke− base?fog&doom=nuke(the reveal's own cost)?doom=battle−&spare?doom=nuke−&spare?fog&doom=nuke(88 / 86 / 72 calls).fullgate from 10:01) on the same runner, and another session's headless Chromium. The one-minute load reached 15–21. Sessions took 10–13 minutes.Node fog cost. The yard's units never move, so the bench does not time the fog's per-move work.
Fog.updatewas timed in Node (tsx, ESM scratch dir, the checkout's fog.ts, which this step leaves unchanged) at 192² with 40 friends of six unit types moving at jittered speeds (±15%), dt = 1/60. The friends were built asfogFriendsbuilds them, throughcollectFriendsand then the disc.view.tsitself does not load under tsx because of its asset imports. The disc was present from frame 300 to 1199, and a unit died at frame 1500. Medians over 9 sessions, under the same load:Renders. The Map Yard at
?fog&doom=nuke, 1×, 0.5× and 0.25×, in the four finishes, reduced motion. Per finish and view: head, base, then head again, from probe copies of both trees (outside the checkout). The probe copies publish the disc's outline on screen (REVEAL_RADIUS + FOG_FEATHER round the impact, projected) and count the disc's tiles outside player 1's own sight. Pixel counts where R+G+B differs by more than 12, inside / outside the outline:impact=100,88: 335 of its 561 tiles lie outside player 1's sight. Lighter pixels inside the outline: 145k at 0.5× (control 0.5–0.6k), 36.5k at 0.25× (control 0.1k) and 71–72k at 1× (control 1.4–1.9k). Outside the outline the lighter and darker counts stay within the control's range at 0.5× (7.7–8.7k against 8.1–8.5k) and 0.25× (1.8–2.3k against 2.0–2.2k). At 1× they run up to 1.8k above that finish's control (lighter 13.1–13.8k against 12.0–13.2k), and the overlay puts every one of those pixels in speckle on the old crater's smoke at the top of the screen.impact=100,88, the head draws 292 more triangles than the base in DieCast, Toybox and Voxel, and the same as its second load. That is something the lifted fog shows inside the disc; I did not trace which part.Play
The step changes only the view, main.ts, the mocks, the help and the changelog. The esbuild bundles of src/ai/sim.ts and src/bench/net.ts built from the base and head trees are byte-identical (sim.js a3c510e5…, net.js 4ffd0007…), so the play code does not take in this change. The 14 AI matches and
npm run benchwere not rerun.Gates
faston1249534(this run's gate 1, tracker gate run 283): passed,npm test980/980.fullon9ffb2a4, the final head (this run's gate 2, tracker gate run 290): passed.npm test980/980 in 68.6 s at a one-minute load of about 18, while run 516 worked beside it.test:phone180/180.