Files
ark-stronghold-protocol/types
ZiyueW1116 8a64edc9e9 feedback7 R22-RENDER: an enemy standing out its attack recovery is drawn standing — the snapshot carries stand / standCut and the interpolator holds the position until the recovery ends (PR #381 by @ZiyueW1116, supersedes #307 / #314); golden: unchanged
Since 0.2.0 the sim stands an unblocked enemy for the rest of its attack clip (ai.js attackStand → atkStandUntil),
but render/interp.js lerped x/y over the whole snapshot gap, so the view slid through a recovery the sim held
(repro: a real 隐形弩手, snapshots 4.9 / 5.0, stand until 4.934 — sampled at 4.917 it slid at vx −0.2).

The snapshot now carries, only when non-empty, `stand: [[id, until]]` (atkStandUntil of enemies alive, deployed,
visible, neither feared nor stunned) and `standCut: [[id, at]]` (the latest time each listed enemy's recovery was cut
or ignored: a displacement, fear, a stun, hiding, leaving — Battle._cutAttackStand, display metadata the battle never
reads). sample() holds the older position until `until` and interpolates the rest (HP / SP keep the whole interval),
stays linear when the newer snapshot records a cut inside the interval, and extrapolates nothing for a newest snapshot
that shows a stand, a death, a stun or a block. Teleports and redeploys still snap first; old snapshots without the
fields interpolate as before.

Substantially @ZiyueW1116's code (PR #381), authored as theirs. Changed on review: the docs (SIM §9, design/network.md)
and code comments in English like the rest of them; the snapshot builds its listed-id set only when an enemy has a cut
to report.

Golden: unchanged — the digest canon hashes neither field and the sim's timing does not move (all 283 scenarios match).

Tests: test/render/attack-recovery-interp.test.js (new, 25: metadata validation, hold-then-slide, cuts, legacy
snapshots, extrapolation guards, real 隐形弩手 / Weedy push-kill / stun / freeze / sleep / levitate / block / fear
battles) 25/25; render/interp 16/16; sim battle, perf, robustness, downelem 69/69.
2026-10-08 18:54:54 +08:00
..

Typecheck

npm run typecheck runs tsc --noEmit --checkJs -p jsconfig.json.

The first slice is the closed set that already typechecks:

  • shared/ except shared/protocol.js and shared/bandBonds.js (their JSDoc does not match the code yet; see below)
  • server/sim/rng.js, server/sim/dir.js, server/sim/constants.js (the last imports GEO from shared)
  • types/ — JSDoc for Unit, DamageInfo, the snapshot tuples, and the protocol message envelope

strict is off. tsc does not read jsconfig.json on its own; the script passes -p.

Widen it

Add one file or one folder to jsconfig.json include, then run npm run typecheck. Fix JSDoc that disagrees with the code in that folder. Leave strict off until the folder reports nothing. Do not add @ts-nocheck.

Suggested order once the sim split settles: server/sim/grid.js, server/sim/body.js, server/sim/buffs.js, then server/sim/damage.js against the typedefs in types/core.js. The sim does not import types/. The typedefs are a reference, not a runtime dependency.

types/core.js follows docs/DESIGN.md §5.2, §5.4, §8 and docs/SIM.md §4, §9. Where those two disagree on DamageInfo.type, the typedef uses the union makeDamageInfo actually builds ('elemental' as well as 'element').

Not in the first slice

shared/protocol.js — the catalogue JSDoc is ahead of a few object literals ($optional sits on a Record of checkers; unitStatsEntry does not list side or silenced, and the code reads side). Fix the comments, then remove it from exclude.

shared/bandBonds.js — the data-shape JSDoc rejects an empty fallback object and a tuple callback. Same treatment.