Skip to content

feat(genclient): генерация зеркальных констант web/game.js из Go (итер. 41) - #40

Merged
Azazlokus merged 1 commit into
mainfrom
feat/client-codegen
Aug 17, 2026
Merged

Azazlokus merged 1 commit into
mainfrom
feat/client-codegen

Conversation

@Azazlokus

Copy link
Copy Markdown
Owner

Что

Итерация 41 — codegen клиентских констант. web/game.js больше не зеркалит константы
провода/геометрии вручную: единственный источник истины — Go, а cmd/genclient
генерирует блок в клиенте между // GENERATED-BEGIN / // GENERATED-END.

  • internal/protocol/clientgen.go — ClientWire(): коды сообщений, Btn*,
    weaponSelectShift/Mask, ActDash, маски полей дельты, matchFlag*, CoordScale.
  • internal/game/clientgen.go — ClientSim(): движение/рывок, InputRate, геометрия
    (walls/pickupSpots/domPoints/flagBases/hill), enum'ы matchPhase/pickup/weapon.
  • cmd/genclient — рендер + spliceBlock между маркерами (путь через runtime.Caller),
    //go:generate go run ., golden-тест на дрейф.
  • web/game.js — сгенерированный блок; клиент ссылается на него (weaponKeyMap/
    WEAPON_NAMES→PROTO.Weapon*, маска→PROTO.WeaponSelectMask, PREDICT.dt→1/INPUT_RATE).
  • Makefile — make gen. Docs: README RU/EN, docs/protocol.md.

Зачем

Ручное зеркалирование дрейфило (сломанный разбор MsgMatchState в итер. 23). Golden-тест
cmd/genclient в make check теперь ловит любое расхождение Go↔клиент.

Как

  • Формат провода НЕ менялся — codec.go/protocol.go не тронуты, это рефактор зеркала.
  • Поверхности read-only читают РЕАЛЬНЫЕ значения в пакете (в т.ч. на iota/неэкспортированные);
    срезы копируются (как Obstacles(), итер. 28) — на симуляцию/Checksum/горутины не влияют.
  • Значения совпали со старым ручным зеркалом байт-в-байт (единственное — INV_SQRT2
    0.70710678→0.70710677, точный float32 серверного invSqrt2; клиент, вне Checksum).
  • Генератор идемпотентен; make gen/go generate перезаписывают только межмаркерный блок.
  • Вне маркеров — ручной рендер/UX (цвета/глифы/баннеры) и INTERP.tickRate (рантайм-конфиг).

Стражи (/audit)

Все три чисты:

  • concurrency — новых горутин/каналов нет, аксессоры read-only, срезы копируются,
    модель «одна комната = одна горутина» не задета; -race+vet зелёные.
  • determinism — значения симуляционных констант не менялись (сверены у источника),
    Step/состояние/Checksum не тронуты, новый код вне горячего пути, серверный invSqrt2
    неизменен.
  • protocol — вердикт «СИНХРОНИЗИРОВАНО», байт-в-байт включая раскладку MsgMatchState
    (критичное ребро итер. 23 чисто); protocol не тянет игровое/сетевое; zero-alloc/fuzz зелёные.
    Находки-не-дефекты закрыты в итерации тем же конвейером (коды оружия, weaponSelectMask).
    Отложено (finding 1): codegen байтовых РАСКЛАДОК сообщений — другой механизм; смещения
    в декодере остаются ручными (задокументировано в docs/protocol.md).

Тестирование

  • make check — зелёный (включая golden-тест cmd/genclient).
  • node --check web/game.js — OK; генератор идемпотентен (повторный прогон — «already up to date»).
  • Негативный drift-тест: искусственное расхождение → тест падает; после make gen → проходит.
  • BENCHMARKS.md не трогался — горячего пути нет.

…р. 41)

Клиент больше не зеркалит константы провода/геометрии вручную — это дрейфило
(напр. сломанный разбор MsgMatchState в итер. 23). Теперь источник истины — Go,
а cmd/genclient переносит значения в web/game.js. Формат провода НЕ менялся
(codec.go/protocol.go не тронуты) — чистый рефактор зеркала.

Механизм:
- protocol.ClientWire() + game.ClientSim() — read-only поверхности, читают реальные
  значения констант в своём пакете (в т.ч. на iota и неэкспортированные); срезы
  копируются (как Obstacles(), итер. 28).
- cmd/genclient рендерит JS-блок и вписывает в web/game.js между
  // GENERATED-BEGIN / // GENERATED-END (путь через runtime.Caller, идемпотентно).
- golden-тест cmd/genclient ловит дрейф Go→клиент в make check; регенерация —
  make gen (//go:generate go run .).

Покрыто: PROTO (коды 0x01..0x1a, enum'ы matchPhase/pickup/weapon, биты Btn/Field,
WeaponSelectShift/Mask, ActDash), MATCH_*_MODE, COORD_SCALE, INPUT_RATE, INV_SQRT2,
SIM (движение/рывок + hill/dom/ctf-геометрия), WALLS, PICKUP_SPOTS. Значения совпали
со старым ручным зеркалом байт-в-байт (INV_SQRT2 → точный float32 0.70710677, клиент,
вне Checksum). Клиент ссылается на сгенерированное: weaponKeyMap/WEAPON_NAMES →
PROTO.Weapon*, маска → PROTO.WeaponSelectMask, PREDICT.dt → 1/INPUT_RATE. Вне маркеров
остаётся ручной рендер/UX и INTERP.tickRate (рантайм-конфиг, не const).

Стражи (concurrency/determinism/protocol) — чисто: новых горутин/каналов нет,
значения симуляции не менялись, Step/Checksum не тронуты, protocol не тянет игровое,
zero-alloc/fuzz зелёные, вердикт protocol-guardian «СИНХРОНИЗИРОВАНО» (байт-в-байт
включая раскладку MsgMatchState). Отложено (finding 1): codegen байтовых РАСКЛАДОК
сообщений — другой механизм, смещения в декодере остаются ручными (задокументировано
в docs/protocol.md).

Тестирование: make check зелёный (вкл. golden-тест), node --check web/game.js,
негативный drift-тест (падает при расхождении, проходит после make gen), идемпотентность.
@Azazlokus
Azazlokus merged commit 9ecb820 into main Aug 17, 2026
10 checks passed
@Azazlokus
Azazlokus deleted the feat/client-codegen branch August 17, 2026 16:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant