[bug] Дроны и баллистика взрываются у старой точки/высоты цели после разрушения платформы или горы #34

Closed
opened 2026-10-29 12:47:09 +00:00 by chexit · 1 comment
Owner

Наблюдение владельца, подтверждённое кодом и native-тестами на опубликованном 90379f6.

Сценарии в игре:

  1. Отметить цель на платформе в воздухе. После разрушения платформы следующие дроны/ракеты всё равно взрываются в воздухе у прежней точки.
  2. Отправить одну волну дронов и Орешник на вершину горы. Дроны сносят вершину/гору до прихода баллистики; поздние боеприпасы подрываются на высоте уже отсутствующей вершины.

Причина — не только возможный устаревший Ground cache:

  • Целеуказатель сохраняет DVec3 точки и отдельное виртуальное здоровье. Геометрическая существующая опора/блок к цели не привязана. Каждому Drone дополнительно копируется собственный target, включая Y.
  • У обычных дронов/крылатых at_target = d.pos.distance(d.target) < speed.max(1.5) само по себе вызывает explode(). Проверка наличия блока/поверхности в этой точке не требуется.
  • У баллистики аналогичный proximity test с speed.max(2.0) плюс ещё более широкий триггер (d.vel.y < 0.0 && d.pos.y < d.target.y - 1.0). Последний — фактически горизонтальная плоскость прежней высоты цели, без требования приблизиться к цели по X/Z или коснуться земли.
  • Дочерние блоки/суббоеприпасы Орешника наследуют target.y; высота разделения блока также вычисляется относительно старого target.y. Это влияет и на каскад разделения, и на место конечного подрыва.
  • Проверка земли в коде ЕСТЬ: below=ground.at(...), in_ground/аналогичный ballistic test. Поэтому неверно говорить, что все боеприпасы взрываются ТОЛЬКО по координатам: они могут попасть в землю раньше. Но попадание в сохранённую точку/плоскость — независимое достаточное условие подрыва даже в воздухе.

Результаты трёх исполняемых проверок исходного Sim::step_drones (glam=0.30.10, cargo test --release, без Horizon/GPU):

  • Shahed, Dive: target=(0,120,0), начало=(0,121,0), ground заранее отвечает Y=64 → удалён, hits=1, blast.y=120.19.
  • OreshnikSub, Ballistic: target=(0,120,0), начало=(0,124,0), ground Y=64 → удалён, hits=1, blast.y=120.8.
  • Iskander: target=(0,120,0), начало=(100,121,0), скорость вниз 4 блока/тик, ground Y=64 → blast примерно (99.838,116.953,0). Это почти 100 блоков в стороне от заданной точки и ~53 блока над актуальной землёй; сработала плоскость target.y−1.

Во всех проверках использовался СВЕЖИЙ ответ высоты Y=64, а не прежняя высота платформы. sim.damage=false выключал отправку реальных TNT-команд; сама логика попадания и explode выполнялась. Тесты характеризуют текущий дефект, реальную игровую сцену с разрушением блоков здесь не запускали.

Что исправить:

  1. Разделить точку наведения и условие физического попадания. Для обычной атаки наземной цели близость к старому waypoint или пересечение старой высоты не должны автоматически считаться контактом и вызывать взрыв.
  2. Удалить безусловный terminal-hit по target.y−1; достижение точки наведения не должно удалять боеприпас, если вокруг воздух. Определить продолжение terminal trajectory/баллистики и при необходимости обновление высоты наземной цели по актуальному рельефу. Одной правки маркера недостаточно: старые координаты уже скопированы в активные Drone, queue/план и дочерние элементы.
  3. Проверять реальный контакт за пройденный отрезок до первой преграды (swept/segment collision), особенно для быстрых объектов, чтобы они не пролетали сквозь тонкую платформу. Collision point должен определять место взрыва.
  4. Heightmap верхнего блока колонки недостаточен как универсальная проверка попадания: воздух под нависающей платформой/в полости не является твёрдым блоком только из-за pos.y <= top_height. Согласовать API запросов/батчинг с форком, не добавляя полный обход всех блоков каждым дроном на каждом тике. Устаревшие/неизвестные данные не считать доказанным контактом.
  5. Ground invalidation после разрушений и асинхронные ответы проверить отдельно (#1/#31): explode вызывает forget(...,8), затем реальные TNT-команды исполняет движок; обновление геометрии не обязано совпадать с тиком запроса. Это дополнительная проблема актуальности, но она не объясняет перечисленные тесты со свежей землёй.
  6. Если нужен намеренный airburst по координатам — отдельный явный режим взрывателя, не скрытый default наземного удара. Не ломать штатные proximity fuses перехватчиков ПВО и высоты разделения Орешника как таковые; отвязать наземные высоты этапов от исчезнувшего рельефа согласно выбранной игровой модели.
  7. Не записывать прохождение старой точки как успешный hits/поражение объекта в отчёте и реплее. Time-to-live/self-destruct и реальный impact должны иметь разные причины завершения.

Acceptance/regression:

  • Два пользовательских сценария (разрушенная воздушная платформа; гора, снесённая первой частью смешанной волны).
  • При актуальной земле Y=64 и старой наземной цели Y=120 боеприпасы НЕ взрываются/не исчезают у прежней точки или после пересечения старой плоскости, а следуют выбранной физической terminal-политике до реального контакта.
  • Тонкая платформа, склон/стена на траектории, пролёт под нависающим блоком, большая скорость, неизвестные/запаздывающие ответы земли.
  • Если препятствие сохранилось, оно останавливает боеприпас в первом пересечении.
  • У Орешника корректно разделяются блоки и суббоеприпасы, фактические попадания и отчёт согласованы.

Код:

self.sim.targets.push(at);

let hit = d.pos.distance(d.target) < speed.max(2.0)

let at_target = d.pos.distance(d.target) < speed.max(1.5);

let aim = d.target + DVec3::new(a.sin() * r, 0.0, a.cos() * r);

Наблюдение владельца, подтверждённое кодом и native-тестами на опубликованном 90379f6. Сценарии в игре: 1. Отметить цель на платформе в воздухе. После разрушения платформы следующие дроны/ракеты всё равно взрываются в воздухе у прежней точки. 2. Отправить одну волну дронов и Орешник на вершину горы. Дроны сносят вершину/гору до прихода баллистики; поздние боеприпасы подрываются на высоте уже отсутствующей вершины. Причина — не только возможный устаревший Ground cache: - Целеуказатель сохраняет DVec3 точки и отдельное виртуальное здоровье. Геометрическая существующая опора/блок к цели не привязана. Каждому Drone дополнительно копируется собственный target, включая Y. - У обычных дронов/крылатых `at_target = d.pos.distance(d.target) < speed.max(1.5)` само по себе вызывает explode(). Проверка наличия блока/поверхности в этой точке не требуется. - У баллистики аналогичный proximity test с speed.max(2.0) плюс ещё более широкий триггер `(d.vel.y < 0.0 && d.pos.y < d.target.y - 1.0)`. Последний — фактически горизонтальная плоскость прежней высоты цели, без требования приблизиться к цели по X/Z или коснуться земли. - Дочерние блоки/суббоеприпасы Орешника наследуют target.y; высота разделения блока также вычисляется относительно старого target.y. Это влияет и на каскад разделения, и на место конечного подрыва. - Проверка земли в коде ЕСТЬ: below=ground.at(...), in_ground/аналогичный ballistic test. Поэтому неверно говорить, что все боеприпасы взрываются ТОЛЬКО по координатам: они могут попасть в землю раньше. Но попадание в сохранённую точку/плоскость — независимое достаточное условие подрыва даже в воздухе. Результаты трёх исполняемых проверок исходного Sim::step_drones (glam=0.30.10, cargo test --release, без Horizon/GPU): - Shahed, Dive: target=(0,120,0), начало=(0,121,0), ground заранее отвечает Y=64 → удалён, hits=1, blast.y=120.19. - OreshnikSub, Ballistic: target=(0,120,0), начало=(0,124,0), ground Y=64 → удалён, hits=1, blast.y=120.8. - Iskander: target=(0,120,0), начало=(100,121,0), скорость вниз 4 блока/тик, ground Y=64 → blast примерно (99.838,116.953,0). Это почти 100 блоков в стороне от заданной точки и ~53 блока над актуальной землёй; сработала плоскость target.y−1. Во всех проверках использовался СВЕЖИЙ ответ высоты Y=64, а не прежняя высота платформы. sim.damage=false выключал отправку реальных TNT-команд; сама логика попадания и explode выполнялась. Тесты характеризуют текущий дефект, реальную игровую сцену с разрушением блоков здесь не запускали. Что исправить: 1. Разделить точку наведения и условие физического попадания. Для обычной атаки наземной цели близость к старому waypoint или пересечение старой высоты не должны автоматически считаться контактом и вызывать взрыв. 2. Удалить безусловный terminal-hit по target.y−1; достижение точки наведения не должно удалять боеприпас, если вокруг воздух. Определить продолжение terminal trajectory/баллистики и при необходимости обновление высоты наземной цели по актуальному рельефу. Одной правки маркера недостаточно: старые координаты уже скопированы в активные Drone, queue/план и дочерние элементы. 3. Проверять реальный контакт за пройденный отрезок до первой преграды (swept/segment collision), особенно для быстрых объектов, чтобы они не пролетали сквозь тонкую платформу. Collision point должен определять место взрыва. 4. Heightmap верхнего блока колонки недостаточен как универсальная проверка попадания: воздух под нависающей платформой/в полости не является твёрдым блоком только из-за `pos.y <= top_height`. Согласовать API запросов/батчинг с форком, не добавляя полный обход всех блоков каждым дроном на каждом тике. Устаревшие/неизвестные данные не считать доказанным контактом. 5. Ground invalidation после разрушений и асинхронные ответы проверить отдельно (#1/#31): explode вызывает forget(...,8), затем реальные TNT-команды исполняет движок; обновление геометрии не обязано совпадать с тиком запроса. Это дополнительная проблема актуальности, но она не объясняет перечисленные тесты со свежей землёй. 6. Если нужен намеренный airburst по координатам — отдельный явный режим взрывателя, не скрытый default наземного удара. Не ломать штатные proximity fuses перехватчиков ПВО и высоты разделения Орешника как таковые; отвязать наземные высоты этапов от исчезнувшего рельефа согласно выбранной игровой модели. 7. Не записывать прохождение старой точки как успешный hits/поражение объекта в отчёте и реплее. Time-to-live/self-destruct и реальный impact должны иметь разные причины завершения. Acceptance/regression: - Два пользовательских сценария (разрушенная воздушная платформа; гора, снесённая первой частью смешанной волны). - При актуальной земле Y=64 и старой наземной цели Y=120 боеприпасы НЕ взрываются/не исчезают у прежней точки или после пересечения старой плоскости, а следуют выбранной физической terminal-политике до реального контакта. - Тонкая платформа, склон/стена на траектории, пролёт под нависающим блоком, большая скорость, неизвестные/запаздывающие ответы земли. - Если препятствие сохранилось, оно останавливает боеприпас в первом пересечении. - У Орешника корректно разделяются блоки и суббоеприпасы, фактические попадания и отчёт согласованы. Код: https://gitea.maoniao.team/chexit/airdef/src/commit/90379f6/airdef-mod/src/lib.rs#L178 https://gitea.maoniao.team/chexit/airdef/src/commit/90379f6/airdef-mod/src/sim/mod.rs#L1353 https://gitea.maoniao.team/chexit/airdef/src/commit/90379f6/airdef-mod/src/sim/mod.rs#L1459 https://gitea.maoniao.team/chexit/airdef/src/commit/90379f6/airdef-mod/src/sim/mod.rs#L1377
chexit added the area:simulationpriority:P1type:bug labels 2026-10-29 13:11:38 +00:00
Author
Owner

🤖 Agent: исправлено в https://gitea.maoniao.team/chexit/airdef/commit/e08fc65 (запушено в main).

🤖 Agent: исправлено в https://gitea.maoniao.team/chexit/airdef/commit/e08fc65 (запушено в main).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chexit/airdef#34