63aefc7621
Co-Authored-By: Codex <noreply@openai.com>
153 lines
15 KiB
Markdown
153 lines
15 KiB
Markdown
# Закреплённый движок AirDef
|
||
|
||
Движок: https://gitea.maoniao.team/chexit/horizon-airdef, ветка `airdef`.
|
||
AirDef хранит точный SHA как gitlink `horizon/`; новый push движка не меняет старые сборки мода.
|
||
История upstream и всех 44 прежних патчей сохранена в форке. Старые patch-файлы и HORIZON_COMMIT
|
||
доступны в истории AirDef и больше не являются вторым источником движка. Baseline описан в AIRDEF-FORK.md.
|
||
|
||
## Windows: обновление и запуск
|
||
|
||
```powershell
|
||
git fetch origin
|
||
git switch kimi-work
|
||
git pull --ff-only
|
||
python tools/airdef.py all
|
||
python tools/airdef.py play
|
||
```
|
||
|
||
Первое клонирование: `git clone --recurse-submodules https://gitea.maoniao.team/chexit/airdef.git`.
|
||
Обычный clone тоже поддерживается: `python tools/airdef.py fork` или команда submodule выше.
|
||
`all` инициализирует зависимость сам, включая переход со старой папки `horizon/`.
|
||
Для чистого checkout можно отдельно выполнить `git submodule update --init --recursive`. Нужны Git, Python и Rust согласно INSTALL.md.
|
||
Сборка клиента и мод устанавливаются в обычное место; ресурсы Minecraft готовятся отдельно по INSTALL.md.
|
||
|
||
При первом переходе со старого отдельного clone `horizon/` скрипт сохраняет его Git-историю и ветки,
|
||
переводит в сабмодуль и получает закреплённый SHA. Если там есть изменения при другом SHA,
|
||
обновление останавливается с объяснением: сначала закоммитьте/сохраните свои изменения.
|
||
Скрипт не выполняет reset --hard или clean. Чистый checkout может остаться detached HEAD — это нормально для зависимости.
|
||
|
||
## Изменение движка
|
||
|
||
1. В `horizon/` создать рабочую ветку от закреплённого SHA. Проверить изменение и push в репозиторий движка.
|
||
2. В AirDef выполнить `git add horizon`, проверить мод/игру, коммитить обновление gitlink отдельно.
|
||
3. Push AirDef выполняется после движка. Не коммитить Git URL с токенами.
|
||
4. Для возврата выбрать прежний commit AirDef и выполнить `git submodule update --init --recursive`.
|
||
|
||
Упаковщик собирается repo-local в `.horizon-cache/packer/<engine-identity>/`, глобальный
|
||
`cargo-horizon-mod` не используется. Изменения tracked-исходников движка входят в identity.
|
||
Рядом с airdef.hmod записывается build-identity.json: SHA AirDef, pin/identity движка,
|
||
SHA256 WIT и артефакта. API-диагностика остаётся в `python tools/airdef.py check`.
|
||
Нативные тесты не заменяют отдельную игровую проверку графики, звука и экспорта.
|
||
|
||
## Проверка настоящего WASM
|
||
|
||
`python tools/airdef.py test-wasm` собирает `.hmod` и запускает `tests/*.toml` в настоящем
|
||
runtime закреплённого движка. Используется временное storage; игровые миры не нужны.
|
||
Сценарий проверяет загрузку/регистрацию команды, два комплекса, налёт, tick/frame,
|
||
выход из мира и перезагрузку мода. Действуют лимиты runtime: 64 MiB linear memory,
|
||
300 млн fuel на tick, 10 млн на frame, 1 млрд на event, 2 млрд на init.
|
||
Это проверка ABI и fallback при отсутствии render replies; она не измеряет GPU,
|
||
не подтверждает акустику/MP4 и не заменяет максимальный боевой полигон.
|
||
|
||
В CI проверка assets входит в лёгкий build. Wasmtime tier вынесен в ручной workflow
|
||
`wasm-contract`, чтобы не компилировать тяжёлый runtime на каждом push слабого общего runner.
|
||
|
||
## Готовность объёмного дыма (API 26)
|
||
|
||
`render.smoke-status` разделяет доступность API, включённый режим, принятую отправку этого мода
|
||
и готовность smoke/fog пути последнего подготовленного основного кадра. Возвращаются поколение мира
|
||
и причина (`awaiting-frame`, `disabled`, `path-unavailable`, `ready`). AirDef убирает обычный дым
|
||
только когда выполнены все четыре условия; после смены мира старые сегменты и часы очищаются.
|
||
Это подтверждение выбранного пути рендера, а не завершения GPU или видимости каждого сегмента.
|
||
Сам `smoke-status` не подтверждает акустику и capture; их отдельные статусы добавлены в API 27 ниже.
|
||
|
||
## Акустика и владение захватом (API 27)
|
||
|
||
Текущий pin: `f95f03c08ec2916a0e5bd3b2d4a2a790e7937b47` (API 27). Новые
|
||
`render.acoustics-status` и `render.capture-owner-status` возвращают поколение,
|
||
`available`, `enabled`, `request-accepted`, `prepared` и причину. В игре всё это показывает
|
||
`/airdef capabilities`. Отсутствие запроса, выключение, ожидание backend и ошибка различаются.
|
||
|
||
Для акустики `prepared` означает выполненный шаг обработки с геометрией при доступном live/offline
|
||
микшере. Шаг может поставить worker job или принять результаты; это **не** подтверждение результата
|
||
для каждого источника, завершения worker, слышимого звука или точного отражения. В режиме no-audio
|
||
без offline-микшера готовность не наступает. AirDef подтверждает текущее глобальное предпочтение,
|
||
не меняя его, и сохраняет собственные дальние варианты звука до подтверждённой подготовки.
|
||
|
||
Для capture запрос принадлежит конкретному запуску мода и поколению мира. `prepared` соответствует
|
||
его стадиям Recording/Encoding/Done; состояние файла и ошибка по-прежнему читаются из `capture-status`.
|
||
AirDef не принимает чужие Recording/Done за свой экспорт. Ожидание первоначальной подготовки
|
||
ограничено 600 тиками. Остановка проверяет владельца; смена мира отменяет модовый захват и
|
||
сбрасывает готовность. Уже переданный writer файл на Encoding может всё же завершиться:
|
||
это запрос отмены, не гарантия удаления файла.
|
||
|
||
## Отдельный тяжёлый WASM tier
|
||
|
||
```sh
|
||
python3 tools/airdef.py test-budgets
|
||
python3 tools/test_budget_report.py
|
||
python3 tools/test_airdef_build.py
|
||
```
|
||
|
||
Сценарий `airdef-mod/tests/budgets/wasm_flat_budget.toml` запускается в изолированном временном `tests/`,
|
||
поскольку CLI читает только непосредственные `tests/*.toml`. Обычный `test-wasm` остаётся лёгким.
|
||
Ручной workflow `.gitea/workflows/wasm-budget.yml` не добавляет нагрузку на каждый push.
|
||
|
||
Исходный профиль запрашивал 64 комплекса и две волны по 80 целей на 4000 блоках,
|
||
602 вызова tick и 300 frame, 69 шагов. Позднее обнаружено: второй заказ во время подготовки
|
||
первого отклонялся, а fixture не проверял ответ. Поэтому тот прогон **не доказывает перекрытие
|
||
160 целей**; сохранённый JSON помечен `coverage_correction`. Новый сценарий проверяет принятие
|
||
обоих заказов и отличает requested counts от неизвестного пика в воздухе.
|
||
Это не полный лимит расстановки (2000) и не нагрузочный
|
||
тест GPU, mixer voices или всех физических world replies: sandbox не выполняет настоящий рендер/звук.
|
||
|
||
Текущий default заменён на flat render-world: ground/sections/rays отвечают для плоскости y=64,
|
||
GPU не имитируется. Проверяются два принятых налёта по 40 «Орешников» и 64 ПВО; в середине
|
||
включаются HD и grid. На тике 2102 assertion подтверждает **184 цели в воздухе**, а не пик за всё время.
|
||
Прогон `2932364` прошёл: 271 шаг, 2102 tick и 2052 вызова frame стенда. У AirDef нет собственного
|
||
frame hook; эти вызовы не являются нагрузкой на GPU или измерением 10M frame fuel мода.
|
||
Точный отчёт: [flat-world budget](measurements/flat-wasm-raid-budget.json).
|
||
|
||
Fixture копируется из тех же байтов, чей SHA записан до сборки. Проверенные 2 принятия и точка
|
||
184/2102 заносятся только после success и совпадения `BUDGET_ASSERTED_SHA256` с точной версией файла.
|
||
После изменения fixture нужно повторно проверить её и обновить SHA/метаданные; простой список
|
||
запрошенных целей не заменяет assertions. Пик остаётся null, если он не измерен.
|
||
Отчёт `.horizon-cache/wasm-budget-report.json` содержит SHA/dirty/diff AirDef, pin/identity движка,
|
||
API/WIT/артефакт, проверку build identity, сценарий, Wasmtime и исходные memory/fuel limits.
|
||
`AIRDEF_BUDGET_REPORT` меняет путь отчёта. Stale identity запрещает запуск, ошибки сборки/тестов
|
||
записываются как failed и дают ненулевой exit code.
|
||
|
||
Лимиты берутся из исходников: memory 64 MiB; fuel init/tick/frame/event — 2B/300M/10M/1B.
|
||
Начиная с продолжения 4 ноября `test-budgets` включает `--fuel-profile` и сохраняет
|
||
`measured_fuel.callbacks`: число вызовов, максимум guest fuel, бюджет и ошибки отдельно по callback.
|
||
Отсутствие запрошенных счётчиков делает проверку неуспешной, даже если сценарий завершился.
|
||
Это не время host/GPU и не peak memory; невызывавшиеся callbacks, включая init до включения профиля,
|
||
не получают выдуманного нуля. Первый прогон: tick 2102 вызова, max 106132646/300000000;
|
||
command 69 вызовов, max 1013370/1000000000; ошибок нет.
|
||
Исторический отчёт без измерения fuel:
|
||
[API27 budget report с поправкой покрытия](measurements/api27-wasm-budget.json).
|
||
|
||
Проверены реальный WASM guest с переходами состояний/владельца/мира, сборка клиента и два коротких
|
||
offscreen-профиля Metal. При `HORIZON_ACOUSTICS=1` + `HORIZON_NO_AUDIO=1` в игре получено
|
||
enabled/request=true, prepared=false, awaiting-backend; HD smoke переходит в ready после подготовки
|
||
основного кадра. Это не замер производительности и не прослушивание.
|
||
|
||
Остаток #102: аналогичные статусы света/камер/источников звука, полные query/voice/peak budgets,
|
||
GPU/готовый MP4 и платформенная приёмка. Эти результаты текущими тестами не объявляются выполненными.
|
||
|
||
## Измеренный fuel и массовые взрывы
|
||
|
||
В runtime добавлен выключенный по умолчанию профиль вызовов. У тестового CLI флаг
|
||
`test --fuel-profile` выводит mod/callback, число вызовов, максимальный израсходованный guest fuel,
|
||
бюджет и число ошибок; результат печатается и при неуспехе сценария. Init до включения профиля
|
||
и предыдущие поколения после reload в эти значения не входят. Это гостевые инструкции,
|
||
не время CPU, не heap peak и не работа GPU/host. Обычный `test-budgets` без этого флага по-прежнему
|
||
не выдаёт свои исходные caps за измеренный расход.
|
||
|
||
С профилем воспроизведён остановившийся tick на двух максимальных составах меню и HD:
|
||
полный обход height-cache при каждом взрыве доводил его до 300M. `1f28f83` заменяет обход
|
||
удалением только затронутого квадрата. В контрольном диагностическом WASM-прогоне после исправления
|
||
3602 тика прошли, max tick fuel = 135273690/300M, failures=0. Лимиты не менялись.
|
||
Диагностический гость содержит только временный способ запуска точного меню-состава;
|
||
это не исходный пользовательский Windows-сеанс. [Данные и воспроизведение](RAID-STABILITY.md).
|