Files
airdef/README.md
T

44 KiB
Raw Blame History

AirDef — дальнобойные дроны и ПВО для Horizon

Мод для Horizon (Minecraft 26.3 на Rust): Шахед-136, Герань-3, Patriot и Гепард с 3D-моделями, наведением ракет, слежением башен, падением сбитых дронов и эффектами взрывов.

Работает на своём форке Horizon (horizon/, ветка airdef): в нём добавлен API отрисовки 3D-моделей, которого нет в основном Horizon.

Перехваты

Запуск

Пошаговый гайд для Windows и macOS (готовая сборка из релиза или сборка из исходников): docs/INSTALL.md. Устройство HD-рендера, его статус и план доработки: docs/HD-RENDERER.md.

Коротко, из исходников:

python3 tools/airdef.py all     # скачать Horizon, наложить патчи форка, собрать игру и мод, установить мод
python3 tools/airdef.py play    # запустить (аргументы игры — после: --world "Имя мира")

Для разработки: ./install.sh перегенерирует модели (tools/gen_models.py, нужен Pillow) и звуки (tools/gen_sounds.py, нужны numpy и ffmpeg), собирает и ставит мод. Сгенерированные файлы лежат в репозитории, так что для обычной сборки нужен только Rust.

CI: .gitea/workflows/build.yml на каждый пуш собирает только мод (airdef.hmod), а пуш в main публикует его релизом build-N. Игру-форк собирают вручную: .gitea/workflows/game.yml (Linux) и .gitea/workflows/desktop.yml (macOS и Windows, на раннерах с метками macos-latest / windows-latest); оба запускаются из Actions с тегом готового релиза build-N. Перед сборкой workflow проверяет, что такой релиз создан build.yml (имя релиза = тег, есть airdef.hmod), иначе падает с ошибкой; затем выкачивает ровно коммит этого тега (а не ветку, с которой запущен), сверяет его с коммитом релиза и дописывает архивы только в этот релиз.

Как играть

/airdef give выдаёт пульты. Все срабатывают на ПКМ.

Предмет Что делает
Целеуказатель ставит или снимает цель на блоке под прицелом (до 512 блоков)
Пуск: Шахед-136 / Герань-3 / Ланцет-3 / Х-101 / Калибр / Х-22 / Циркон / Искандер-М / Кинжал запускает дрон или ракету в точку под прицелом
Развернуть Patriot / Гепард / Панцирь-С1 / С-400 / С-500 ставит комплекс на блок под прицелом, носом по взгляду
Свернуть ПВО убирает ближайший комплекс у точки под прицелом

Командный пункт: клавиша N или /airdef menu. В нём список комплексов: выбери комплекс и включай или выключай классы целей (дроны, реактивные дроны, крылатые, сверхзвуковые, баллистика), есть сброс по умолчанию. Там же кнопки «Командный пункт» (сетка), «Налёт…» и «Огонь, ремонт, эффекты…» (огонь ПВО, ремонт всех, эффекты, разрушения).

Налёт (меню N → «Налёт: состав и запуск…»): на первой странице состав — клик по типу листает число (0, 1, 2, 3, 4, 6, 8, 10, 15, 20, 30, 40); на второй — готовый вариант («Рой Шахедов», «Массированный удар», «Баллистика», «Гиперзвук», «Орешник с прикрытием», «Подавление ПВО»), откуда (один сектор, два, со всех сторон, волнами по типам), дальность старта, цели и ПУСК. Цели:

  • только объекты — всё летит по отмеченным объектам (или по игроку, если их нет);
  • объекты и ПВО — треть ударных средств бьёт по случайным комплексам;
  • умный противник — планировщик знает, где стоят комплексы и что видят их РЛС: ведёт дроны и крылатые ракеты маршрутами в обход зон поражения, низко, за рельефом и через мёртвые зоны; «Герберы» прилетают на 15 с раньше, чтобы оттянуть ракеты; «Ланцеты» идут по Гепардам и Панцирям, Х-22/Циркон и часть баллистики — по дальнобойным комплексам; на каждую РЛС дальнего обнаружения идут 2–3 быстрых ударника (Х-22, Циркон, Искандер, Кинжал, затем Х-101, Герань-3, Ланцет, Шахед; не больше четверти налёта); всё остальное стартует со сдвигом так, чтобы прилететь одновременно.

После налёта приходит отчёт: сколько сбито и прорвалось, ракет ПВО потрачено, комплексов потеряно, урон объектам.

Обнаружение. РЛС видит цель не дальше, чем позволяют:

  • её размер: дальность растёт как корень четвёртой степени из ЭПР — Х-101 и Ланцет видно примерно вдвое ближе, чем Х-22;
  • радиогоризонт: низколетящую цель видно поздно (Шахед на 25 м — с ~250 м, баллистику — издалека);
  • рельеф и лес: за холмом цель не видна (каждый комплекс строит свой горизонт по 48 лучам; рельеф известен в прогруженных чанках);
  • вблизи (24 м) видно всё.

Радар игрока и мониторы показывают только то, что держат РЛС; в сводке видно «Вне видимости РЛС: N». Мёртвые зоны — ближе минимальной дальности ракет (Patriot 10 м, Панцирь 25, С-400 30, С-500 40).

Сохранение. Комплексы, объекты, их повреждения и настройки сохраняются отдельно для каждого мира (и для каждого сервера); уничтоженный комплекс остаётся остовом и после перезахода, пока его не отремонтируют.

Сеть ПВО. Каждая единица делится целями со всеми в радиусе 2,25 км (линия связи): РЛС дальнего обнаружения даёт раннее предупреждение всем, пусковая без своей РЛС (P1-SUN) стреляет по чужим данным. Пушкам (Гепард, пушки Панциря) нужна своя цель: они стреляют только по тому, что видят сами. Уничтоженная РЛС — дыра в сети.

Логистика. Пока нет ни одного склада, магазины пополняются сами, как раньше. Как только поставлен склад, боекомплект считается: комплекс без ракет пишет «ЖДЁТ БК»; в 60 м от склада он перезаряжается прямо с него, а дальние обслуживают ТЗМ: заправляются на складе (2 перезарядки), сами едут к ждущим комплексам, ближайшим первым, и возвращаются. Запас склада — 30 перезарядок, он виден в сводке. Склад и ТЗМ детонируют всем грузом.

Перемещение. Пульт перемещения: навестись на технику (выбрать), затем на точку на земле — она сворачивается (С-400 и другие с вертикальным пуском дольше, Гепард и Панцирь быстро), едет по рельефу и разворачивается; всё это время не стреляет и не светит РЛС. Или /airdef move <номер> — к тому месту, где ты стоишь.

РЭБ. Клавиша U (или /airdef ew on|off) включает все станции. Станция в радиусе 350 м сбивает спутниковую навигацию у Шахедов, Герань, Гербер, Х-101 и Калибров: они теряют маршрут и уводятся с цели (баллистике и Ланцетам с оптикой всё равно). Передатчик работает до 20 с и перегревается; остывает ~35 с, пока не остынет — не включить. Включённая станция себя выдаёт: умный противник запоминает её и шлёт на неё Ланцеты и Х-22, а маршруты спутниковых дронов прокладывает в обход.

Умный противник учится. Он запоминает, откуда его налёты сбивали, а откуда они прорывались, и следующий налёт ведёт с лучшего направления; помнит комплексы, выдавшие себя пуском, и станции РЭБ, и во время налёта перенацеливает ещё не взлетевшие Ланцеты и Шахеды на них; если цель-комплекс уничтожен, дроны идут к следующему известному. Дроны под обстрелом прижимаются к земле.

Ночь. Ночью пушки попадают втрое хуже, если цель не освещена. Освещают прожекторы (луч ведёт ближайшую цель из сети, приоритет — цели пушек) и осветительные ракеты: пушечные комплексы пускают их сами (раз в 25 с на цель в темноте), игрок — осветительным пистолетом или /airdef flare. Ракета висит ~30 с и освещает всё вокруг на ~60–90 м.

Графика: три пресета (меню N → «Огонь, ремонт, эффекты…» → «Эффекты», или /airdef shader off|on|hd): выкл — ванильная картинка; обычные — шейдерные огненные шары, ударная волна и подсветка; HD — свой рендер освещения в форке: мир дополнительно рисуется в G-буфер (цвет без света и нормали), и все источники света мода освещают его попиксельно в HDR — факелы ракет и двигатели, раскалённые боевые блоки, осветительные ракеты, вспышки выстрелов, трассеры, взрывы (вспышка и догорающий шар), горящие остовы, пятна прожекторов, — затем bloom и мягкий тонмаппинг (ванильный диапазон не трогается, сжимается только то, что ярче). Источники передаются движку новым API мода render.set-lights (до 512, плавно интерполируются), режим — render.set-lighting.

Сетка J после сбития ещё 3,5 с держит камеру на сбитой цели, и комплекс в это время не пропадает из сетки.

Повреждения. Взрыв рядом с комплексом повреждает его: он хуже поворачивается, хуже видит и попадает, дымит, ниже 35% горит. Уничтоженный остаётся горящим остовом, его боекомплект детонирует: чем больше ракет оставалось, тем мощнее взрыв и дольше вторичные (у Гепарда рвутся снаряды); соседние комплексы тоже могут пострадать. Объекты (Целеуказатель или /airdef target here) имеют прочность, она видна в сводке. Ремонт — кнопкой в меню или /airdef repair.

Монитор комплекса: клавиша K листает комплексы по очереди, после последнего монитор скрывается. Слева вверху показано:

  • состояние комплекса (поиск, сопровождение, доворот, захват, пуск, огонь, перезарядка, огонь запрещён);
  • его РЛС: цели, по которым он работает, красным, остальные серым, текущая цель жёлтым;
  • камера комплекса: настоящий вид мира из точки комплекса (второй рендер форка), с зумом на цель — тепловизор при сопровождении, в поиске днём цвет, ночью ПНВ; рамка захвата, дальность, высота, скорость и пеленг.

Командный пункт ПВО (сетка): клавиша J (или /airdef grid, или кнопка в меню N) — на весь экран сетка до 8 комплексов: у каждого состояние, РЛС, живая камера, прочность и боекомплект. Если комплексов больше, показываются самые занятые (стреляют, держат захват, сопровождают, горят), раз в 2 секунды; комплекс с монитора K — всегда. Повторное J закрывает.

Повторы. Каждый налёт записывается сам: с первой цели в небе до момента, когда небо 5 с чисто (хранятся 3 последних). Меню N → «Повторы…» или клавиша R:

  • карта налёта — вид сверху: комплексы и их зоны, объекты, треки целей (красные), ложных целей (серые) и перехватчиков (жёлтые), сбития (x), прилёты, шкала времени с событиями; время идёт само, колесо мыши перематывает;
  • повтор момента — клик по событию в списке: «призраки» дронов и ракет снова летят в мире, камера идёт за целью, потом за перехватчиком (или смотрит из пушки, со стороны на прилёт), в момент сбития время замедляется;
  • полный повтор — весь налёт, камера-режиссёр сама выбирает, за чем следить; колесо — перемотка, стрелки — скорость;
  • лучшие моменты — нарезка до 8 самых интересных событий (перехват баллистики и гиперзвука, поражения объектов, потерянные комплексы, разделение «Орешника») с титрами и замедлением; колесо листает моменты.

Повтор идёт на весь экран с леттербоксом; звук слышен так, как его слышала бы камера. Управление (подсказка показывается в начале, после нажатия и на паузе): ← → — перемотка на 5 с (в нарезке — соседний момент), ↑ ↓ — скорость (×0.25–×32), Пробел — пауза (в конце — сначала), колесо — время / моменты, R или Backspace — выход, N — выйти в меню. В конце повтор встаёт на паузу.

Чтобы в повторах и камерах комплексов была видна земля далеко от игрока, мод включает дальний ландшафт (48 чанков, упрощённый); выключается в меню N → «Огонь, ремонт, эффекты…» → «Дальний ландшафт».

Клавиши N, K, J, R и U можно переназначить в «Настройки → Моды».

Команды:

  • /airdef wave <тип> [кол-во] [дальность] — налёт на ближайшую цель. Дальность старта — от 60 до 4000 блоков (в меню: 200–4000); землю для площадок, которой нет в загруженных чанках, игра подгружает сама (API 22, render.load-chunks, пока идёт поиск), а где подгрузить нельзя (сервер) или нет пригодного места, дроны всё равно стартуют: «за картой», с высоты полёта на заказанной дальности, без площадки. Типы: shahed, geran3, lancet, gerbera, kh101, kalibr, kh22, zircon, iskander, kinzhal, oreshnik и mix (комбинированный удар двумя секторами: «Герберы», шахеды, Герани-3, Х-101, «Калибры», Х-22, Циркон, «Искандер», «Кинжал», при 30+ — «Орешник»);
  • /airdef replay [map|full|reel|stop] — повтор последнего налёта;
  • /airdef replay film [best|all|N] — фильм режиссёра: для каждого перехвата/прилёта несколько планов (комплекс, пуск, погоня за ракетой, взгляд с цели, замедленный крупный план поражения, общий план после), склейки, плавные движения камеры, камера не уходит под землю; играется в максимальном качестве (HD, мир в полном разрешении, больше шагов облаков и тумана; настройки возвращаются после);
  • /airdef replay export [имя] [best|all|N] [fps=60] [size=1920x1080] [crf=14] [sec=N] [noaudio] — тот же фильм кадр за кадром с фиксированным шагом (скорость компьютера не важна) в MP4 с звуком: <HORIZON_HOME>/airdef-films/<имя>.mp4 (нужен ffmpeg в PATH или HORIZON_FFMPEG; без него — PNG-последовательность и готовая команда ffmpeg). Прогресс в чате, отмена — /airdef replay stop. Окно игры держите в фокусе (пауза останавливает съёмку); чат попадает в кадр.
  • /airdef import — перенести в текущий мир комплексы и цели из старой версии мода (до 0.2.x они были общими для всех миров);
  • /airdef raid — налёт, настроенный в меню; /airdef target here — отметить объект под ногами; /airdef repair — ремонт;
  • /airdef lastchance <on|off> — «последний шанс»: комплекс стреляет и по классу вне ролей, если цель вот-вот попадёт (по умолчанию вкл; сохраняется);
  • /airdef sites — известные пусковые площадки (ПУ) и ударные ракеты; /airdef strike <номер ПУ> — ответный удар по ПУ (#101, «удары по ПУ»). Как это играется:
    • Разведка без волшебства. Площадку находит только работающая РЛС: либо пуск в её досягаемости (низкая цель: радиогоризонт и холмы решают) даёт точечное наблюдение, либо собственный трек вылетевшей цели «указывает назад» лучом в пару градусов, а время полёта с момента пуска (тревоги) на скорости цели даёт дальность (±8% и секунда времени пуска); у баллистической ракеты дуга точнее. Две РЛС, держащие одну цель, дают два наблюдения. Наблюдения сводятся методом наименьших квадратов, ответ всегда с кругом ошибки (90%), он сужается с каждым пуском. Если места не получилось (круг шире 800 блоков или есть только лучи вдоль одной линии), известен только азимут (на скопе метка «N?» на краю), удар невозможен. С местом: ромб на скопе (круг ошибки пунктиром) или метка на краю; в панели строка «Известных ПУ…». Далёкие площадки (километры) открываются грубо (сотни блоков) и бить их почти бесполезно, пока не накопятся пуски.
    • Удар. Ударных ракет мало (3 в запасе, максимум 4, новая за 5 минут), дальность до 4500 блоков; стартуют оттуда, где вы стоите, летят 4 блока в тик (2 км за 25 с) в точку оценки. На подлёте ракету может сбить ПВО противника: у ПУ её нет (40%), лёгкая (35%, сбивает в 30%) или тяжёлая (25%, 65%), у баллистических батарей тяжёлая чаще; узнаёте только по итогу. Разброс ракеты 14 блоков; решает истинное расстояние до ПУ: до 35 блоков — уничтожена (запас сгорел и рвётся, отложенные запуски отменены, огонь и дымящийся остов, взрыв общим кодом), до 90 — подавлена на 30 с (пуски отложены, не отменены), дальше — промах, воронка рядом, ПУ цела: очередь за попадание в соседний грунт не списывается. Плохо известную ПУ (круг в сотни блоков) бить почти бесполезно.
    • Вне карты. ПУ без земли (нет загруженной карты) тоже находится: азимут и дальность по трекам, но не рисуется. Удар, который попал бы, прекращает её пуски («результат не виден»); промах теряется.
    • Цена выбора. Ракета запаса не вернётся, пока летит, налёт идёт: близкие площадки не остановить, далёкие (крылатые и баллистические за 2–4 км) успеваете, но для этого нужны РЛС с обзором в сторону налёта и риск промаха или ПВО противника. Отчёт налёта называет сорванные пуски: «Налёт сорван ударами по ПУ (№…): не взлетело N из заявленных M».
    • Столкновение с рельефом или строением по пути взрывает ракету в точке контакта, не поражая ПУ; неизвестная геометрия задерживает полёт, а не считается воздухом. Если новая волна сворачивает старую ПУ, уже выпущенная ракета всё равно завершает полёт и даёт обычный исход.
    • Запись: полёт ударной ракеты, её двигатель и исход попадают в журнал повтора (трек, строка и взрыв/огонь на карте), самостоятельный удар удерживает запись до завершения; сами ПУ в повторе не рисуются. Запас ракет входит в сохранение и сценарий (strikes <запас> <тиков до следующей>), прогресс пополнения автосохраняется контрольными точками с точностью до 5 секунд. Все числа механики в одной таблице TUNE в src/sim/strike.rs.
  • /airdef roles — показать, по каким классам целей работает каждый комплекс; /airdef roles <patriot|gepard|pantsir|s400|s500|all> <классы|default> — задать (классы через запятую: drone, jet, cruise, supersonic, ballistic или all), например /airdef roles s400 cruise,ballistic;
  • /airdef doctrine — доктрины комплексов (#47; в меню N: «Доктрины…»): /airdef doctrine <номер|all> reserve <K> — держать K ракет для срочных целей (баллистика или до удара меньше 12 с); salvo eco|normal|heavy — сколько перехватчиков на цель (только базовые / как обычно / на один больше); sector <центр°> <полуширина°> или sector off — сектор ответственности (0° — север); guard <объект№>[,<№>] или guard off — стрелять только по тому, что идёт на охраняемые объекты (отметка: /airdef target here). По умолчанию ограничений нет; последний шанс сильнее доктрины; /airdef why <номер> называет, какая настройка остановила или разрешила пуск; сохраняется с миром и сценариями. Карта охраны и пробелов в ней — вместе с картой (#48).
  • /airdef deploy <patriot|gepard|pantsir|s400|s500> — поставить комплекс в 8 блоках перед собой;
  • /airdef hold on|off — запретить или разрешить ПВО огонь, удобно для съёмки ударов;
  • /airdef damage on|off — разрушать ли ландшафт взрывами (через TNT, нужны читы);
  • /airdef shader on|off — шейдерные эффекты;
  • /airdef clear — убрать дроны и ракеты;
  • /airdef targets clear — снять все цели;
  • /airdef stats — сводка.

Интерфейс:

  • сверху справа — сводка: тревога, цели по типам, ближайшая угроза (дальность, высота, скорость), перехватчики в воздухе, по каждому комплексу боезапас или перезарядка, его текущая цель и число сбитых, итоговый счёт;
  • снизу справа — радар на 500 м со сканирующим лучом. Отметки гаснут после прохода луча. Красное — цели (с хвостом по курсу), жёлтое — ракеты, синее — ПВО с кругами дальности, крест — цели удара.

Комплексы ПВО и цели сохраняются между сессиями.

Техника

Дрон / ракета Поведение
Шахед-136 43 км/ч в игре, 45 м над целью, 18 м над рельефом, крен в поворотах, пикирует, винт крутится
Герань-3 реактивный, 115 км/ч, факел из сопла
Ланцет-3 Х-образные крылья, низко (25 м), манёвренный, его труднее сбить
Гербера ложная цель из пенопласта, без боевой части: отвлекает ракеты ПВО
Х-101 крылатая ракета, 170 км/ч, огибает рельеф на 12 м, мощная боевая часть
Калибр крылатая ракета, 150 км/ч, огибает рельеф на 15 м
Х-22 сверхзвуковая, 290 км/ч, идёт на 140 м и круто пикирует издалека
Циркон гиперзвуковая, 400 км/ч, её трудно сбить
Искандер-М баллистическая: стартует за 1 км, дуга с апогеем ~250 м, на конечном участке доворачивает на цель
Кинжал аэробаллистическая, 540 км/ч, стартует за 1,5 км; реально сбивает только С-500
Орешник баллистическая средней дальности: стартует за 2,6 км, над целью разделяется на 6 блоков, каждый — на 6 светящихся суббоеприпасов («огненный дождь», ~5 с); С-500 успевает сбить лишь несколько

Сила взрыва зависит от боевой части: ложные цели — хлопок, дроны — средний взрыв, Шахед — сильный, Х-101/Х-22/Калибр — тяжёлый (двойной удар, столб земли, тряска до 160 м), Искандер/Кинжал — самый мощный (огненный шар 13 м, тряска до 240 м); у каждого уровня свой звук.

ПВО Вооружение Дальность
Patriot 4 × PAC-3, пусковая разворачивается на цель 10–450
Гепард 2 × 35 мм, башня и стволы со слежением и упреждением, 160 очередей 135 (слежение с 195)
Панцирь-С1 12 × 57Э6 и 2 × 30 мм; модуль поворачивается, пакеты и стволы поднимаются ракеты 25–225, пушки 90
С-400 4 × 48Н6, вертикальный холодный старт, РЛС обзора на прицепе 30–720
С-500 4 × 77Н6, холодный старт, самые быстрые ракеты 40–1050
IRIS-T SLM 8 ракет, вертикальный пуск, быстрые и манёвренные 15–600
NASAMS 6 × AMRAAM, наводимая пусковая на прицепе 10–450
Бук-М2 4 × 9М317 на направляющих, башня с РЛС подсвета 20–675
Тор-М2 8 × 9М338 вертикально из башни, быстрая реакция против дронов 8–240
P1-SUN 8 дронов-перехватчиков против Шахедов и Герань; своей РЛС нет — стреляет по данным сети 5–675

Обслуживающая техника (тоже пультами или /airdef deploy <ключ>): РЛС дальнего обнаружения (radar, видит на 2,5 км с высокой мачты, хуже прячутся за рельефом), склад боеприпасов (depot), ТЗМ (tzm), станция РЭБ (ew), прожектор (light). Новые комплексы: irist, nasams, buk, tor, p1sun.

Согласование огня. Комплексы делят цели между собой: на обычную цель идёт одна ракета, на баллистическую две; чем ближе цель к своей точке попадания, тем больше перехватчиков разрешено на неё сразу (за ~12 с до удара ещё один, за ~5 с — ещё один). Комплекс, у которого кончились ракеты или идёт перезарядка, цель не держит; тот, кто не смог навестись за ~2 с, отпускает её другим. Пушки расходятся по разным целям. Первыми бьют по самым опасным (быстрым и тяжёлым) целям, при этом ложные «Герберы» выглядят для них как настоящие. Шанс поражения падает, если цель быстрее перехватчика.

Последний шанс (/airdef lastchance on|off, по умолчанию вкл). Комплекс стреляет и по классу целей вне своих ролей (С-400, С-500 и Patriot по умолчанию не бьют дроны), если цель долетит до своей точки меньше чем за 10 с и на ней ещё нет ничьего перехватчика. Комплексу с пустыми ролями (огонь запрещён) это не касается. /airdef why пишет «последний шанс».

Дальний пуск по РЛС. С-400, С-500 и Patriot могут стрелять дальше своей дальности (до 1,6×) по цели, которую держит свежим треком РЛС дальнего обнаружения в радиусе связи: не чаще раза в 15 с, при не менее чем половине боезапаса, только по своим ролям и только пока в обычной дальности нет цели; шанс поражения на краю вдвое ниже. /airdef why: «дальний пуск по РЛС».

Роли по умолчанию (в сводке в квадратных скобках: Д — дроны, Г — реактивные, К — крылатые, С — сверхзвуковые, Б — баллистика): Гепард ДГК, Панцирь ДГКС, Patriot ГКСБ, С-400 ГКСБ, С-500 СБ. Сбитый дрон падает с остатком скорости, и его боевая часть может сдетонировать на земле.

Звук

Все звуки синтезированы (tools/gen_sounds.py: шум, тоны, фильтры и эхо на numpy, кодирует ffmpeg), сэмплов нет. У каждого объекта свой звук и своя дальность слышимости (attenuation_distance в sounds.json):

  • двигатели: двухтактный мопед шахеда (220 м), турбина Герани-3, электромотор Ланцета, тяжёлый рёв крылатых ракет (320 м), ракетный рёв Х-22, Циркона и перехватчиков, нарастающий визг падающей баллистики и её ударная волна (700–900 м); Двигатели дронов и ракет — постоянные источники звука (API 20, render.sound-sources, #95): один источник на объект идёт за его настоящей позицией, зажигается с нарастанием, при сбитии «захлёбывается» (тон падает, громкость гаснет за секунду) и замолкает вместе с объектом; в повторе и экспорте источники берутся из записанных траекторий и времени повтора (перемотка и смена плана пересоздают их). Одновременно звучат 24 ближайших и громких, остальные «виртуальные». Взрывы, пуски и выстрелы остались разовыми, с задержкой по скорости звука. Баллистика (визг при падении) тоже разовая. Зацикливается устойчивая часть файла (начало и затухание в конце обрезаны), стык — 50 мс.
  • пуски: хлопок и рвущийся рёв Patriot, свистящий старт Панциря, глухой газовый выброс и затем огромный рёв С-400, у С-500 ещё ниже и дольше (до 1 км);
  • пушки: тяжёлые 35-мм очереди Гепарда и частые 30-мм Панциря;
  • взрывы: хлопок, суббас, рокот и треск обломков с длинным эхом, у разных калибров по-разному (до 900 м).

Эффекты

Мод передаёт движку шейдер пост-обработки (airdef-mod/shaders/effects.wgsl):

  • объёмный огненный шар: шум, «прошитый» лучом камеры, с переходом раскалённое ядро → пламя → чёрный дым, который поднимается и рассеивается;
  • вспышка с ореолом и засветкой всего кадра;
  • ударная волна, искажающая картинку за собой;
  • тепловое марево над огнём;
  • свечение факелов ракет, дульных вспышек, красных трассеров и маркеров цели;
  • освещение от огня: взрывы, факелы и трассеры подсвечивают землю и технику, ночью намного сильнее.

У Гепарда и Панциря каждый снаряд — летящий красный трассер.

Всё размещено в мире и скрывается за тем, что стоит перед ним (по глубине сцены). Выключить: /airdef shader off.

Удар Холодный старт С-400

Устройство

HORIZON_COMMIT      коммит апстрима Horizon, на который накладываются патчи
horizon-patches/    изменения форка (git format-patch); tools/airdef.py fork собирает из них horizon/
horizon/            форк (не в репозитории; ветка airdef). Что в нём меняется:
  crates/horizon-mod-sdk/wit/horizon.wit   render.set-models, spawn-particles, play-sound,
                                           query-ground / ground
  crates/horizon-mods/src/runtime.rs       хост этих функций
  crates/horizon-client/src/game/mod_models.rs   интерполяция и отрисовка моделей, частицы
  crates/horizon-client/src/gfx/mod_post.rs      пост-проход мода: render.set-post / set-params
airdef-mod/         сам мод: Rust → WebAssembly
  src/sim.rs          симуляция: дроны, ракеты, ПВО, эффекты (20 тиков/с)
  src/lib.rs          предметы, команды, сохранение, передача в движок
  src/panel.rs        сводка, src/radar.rs — радар, src/monitor.rs — монитор комплекса
  assets/airdef/sounds  звуки (генерирует tools/gen_sounds.py)
  shaders/effects.wgsl  шейдер взрывов и свечения
  assets/, data/      модели, текстуры, предметы (генерирует tools/gen_models.py)
tools/gen_models.py генератор моделей и текстур
legacy/             первая версия: датапак на командах и контент-мод
run-home/           тестовая игровая папка (для проверок через horizon-ctl)

Как рисуются модели. Мод раз в тик отдаёт список объектов: блок-модель, позиция, кватернион и масштаб. Движок держит для каждого id две последние позы и в каждом кадре рисует объект между ними:

  • позиция интерполируется линейно, поворот — через slerp;
  • освещение учитывает поворот модели;
  • glow даёт полную яркость (пламя, вспышки).

Модели — обычные блочные JSON-модели, по одной на часть: корпус, винт, башня, стволы. Их генерирует tools/gen_models.py. Координаты элементов должны быть в пределах −16..32, иначе Horizon отбросит модель.

Рельеф мод узнаёт через render.query-ground: присылает колонки, а движок отвечает высотой по карте высот на следующем тике.

Известные ограничения

  • Мод клиентский: дроны и ПВО видит только тот, у кого он стоит. Мультиплеер не поддерживается.
  • Окно Horizon на macOS не рисует кадры, пока оно перекрыто другими окнами (это поведение движка).
  • Шейдер работает, только если не включён шейдер-пак Horizon (они взаимоисключающие).