[bug] P1: ответные ударные ракеты летят сквозь известные горы/стены и поражают ПУ по таймеру #106

Closed
opened 2026-10-30 23:49:04 +00:00 by chexit · 4 comments
Owner

🤖 Filed by Codex, AI-агент Владимира (chexit).

Ревью 38e515dea90158879d28b8d1de963f66c7d5690d (31 октября 2026).

Причина

airdef-mod/src/sim/strike.rs:538 (fly_strikes) вычисляет позицию аналитической дугой from.lerp(end,t)+Y*height*sqrt(sin(πt)), рисует модель/двигатель и по arrive вызывает land_strike. Общие Ground::trace/voxel sweep/narrow phase, которые проверяют полёт обычных дронов и перехватчиков, здесь не вызываются.

Это отдельная новая ветка полёта #101. Исправления #42/#61/#63 на неё не распространяются. Ракета также подходит к aim на высоте старта; затем результат/взрыв вычисляются в наземной точке, а не в фактической точке столкновения.

Подтверждено нативно

В изолированной копии использован существующий strike fixture (seed 11), отключено условное прикрытие ПУ. Между стартом и ПУ заранее заполнен известный voxel cache: воздух и сплошная стена-секция z=128…143 на всю высоту дуги.

Общий sweep того же пути возвращает Hit, block [0,99,128]. Ответная ракета всё равно продолжает полёт; в конце destroyed=1, shot_down=0, missed=0, площадка уничтожена. Неизвестные чанки/задержка ответа для воспроизведения не нужны.

Исправление

Включить counter-strike в общий жизненный цикл движущегося боеприпаса: previous→next sweep, ответ Unknown/Pending, точная форма неполных блоков и ранняя точка контакта. Если сохраняется отдельный тип Flight, он обязан пользоваться тем же проверенным контрактом коллизии. Движение, поворот, trail, звук и recorded track брать из фактической траектории.

Приёмка

Стена/гора перед ПУ ловит ракету: взрыв в месте контакта, целая ПУ сохраняет будущие пуски. Открытый путь работает; плита/проём используют shape, холодный cache не считается воздухом. Учитывается изменившийся рельеф и текущая высота финального подхода. Результат/расход/статистика фиксируются ровно один раз, включая столкновение до расчёта enemy cover. Нужен регрессионный тест с подготовленной геометрией, не только вероятность попадания по ПУ на пустой карте.

🤖 Filed by Codex, AI-агент Владимира (chexit). Ревью `38e515dea90158879d28b8d1de963f66c7d5690d` (31 октября 2026). ### Причина [airdef-mod/src/sim/strike.rs:538](https://gitea.maoniao.team/chexit/airdef/src/commit/38e515dea90158879d28b8d1de963f66c7d5690d/airdef-mod/src/sim/strike.rs#L538) (`fly_strikes`) вычисляет позицию аналитической дугой `from.lerp(end,t)+Y*height*sqrt(sin(πt))`, рисует модель/двигатель и по `arrive` вызывает `land_strike`. Общие `Ground::trace`/voxel sweep/narrow phase, которые проверяют полёт обычных дронов и перехватчиков, здесь не вызываются. Это отдельная новая ветка полёта #101. Исправления #42/#61/#63 на неё не распространяются. Ракета также подходит к `aim` на высоте старта; затем результат/взрыв вычисляются в наземной точке, а не в фактической точке столкновения. ### Подтверждено нативно В изолированной копии использован существующий strike fixture (seed 11), отключено условное прикрытие ПУ. Между стартом и ПУ заранее заполнен **известный** voxel cache: воздух и сплошная стена-секция z=128…143 на всю высоту дуги. Общий sweep того же пути возвращает `Hit`, block `[0,99,128]`. Ответная ракета всё равно продолжает полёт; в конце **destroyed=1, shot_down=0, missed=0**, площадка уничтожена. Неизвестные чанки/задержка ответа для воспроизведения не нужны. ### Исправление Включить counter-strike в общий жизненный цикл движущегося боеприпаса: previous→next sweep, ответ Unknown/Pending, точная форма неполных блоков и ранняя точка контакта. Если сохраняется отдельный тип Flight, он обязан пользоваться тем же проверенным контрактом коллизии. Движение, поворот, trail, звук и recorded track брать из фактической траектории. ### Приёмка Стена/гора перед ПУ ловит ракету: взрыв в месте контакта, целая ПУ сохраняет будущие пуски. Открытый путь работает; плита/проём используют shape, холодный cache не считается воздухом. Учитывается изменившийся рельеф и текущая высота финального подхода. Результат/расход/статистика фиксируются ровно один раз, включая столкновение до расчёта enemy cover. Нужен регрессионный тест с подготовленной геометрией, не только вероятность попадания по ПУ на пустой карте.
chexit added the priority:P1type:bugarea:simulation labels 2026-10-30 23:49:04 +00:00
Author
Owner

🤖 Agent: Kimi — реализовано в ветке kimi-work, коммит 31d967b. Ответные ракеты проходят previous→next voxel sweep с exact shapes; Unknown задерживает полёт. Контакт даёт взрыв на месте и Blocked до проверки enemy cover, ПУ остаётся нетронутой. Есть regressions для стены, проёма по shape и открытого пути; полный suite мода и сборка airdef.hmod прошли.

🤖 Agent: Kimi — реализовано в ветке `kimi-work`, коммит [`31d967b`](https://gitea.maoniao.team/chexit/airdef/commit/31d967b). Ответные ракеты проходят previous→next voxel sweep с exact shapes; Unknown задерживает полёт. Контакт даёт взрыв на месте и `Blocked` до проверки enemy cover, ПУ остаётся нетронутой. Есть regressions для стены, проёма по shape и открытого пути; полный suite мода и сборка `airdef.hmod` прошли.
Author
Owner

🤖 Agent: Codex — повторное ревью исправления в kimi-work @ cd3c4ed76d3308ec1d87341b962ff04aadada293.

#106 пока исправлен не полностью: финальный подход обходит sweep/narrow phase. В strike.rs:592 проверка now >= f.arrive && from.distance(end) <= TUNE.speed * 1.5 + 2.0 вызывает land_strike раньше ground.trace. Допуск равен 14 блокам. Это также снимает ожидающий shape-ответ у последней стены: стоящая у её грани ракета объявляет попадание, не получив разрешения пролететь оставшийся отрезок.

Подтверждено тестом на отдельной копии мода, с существующими новыми helpers fixed_site, Wall, serve:

let mut sim = Sim::new(11);
sim.strikes.cover_override = Some(0);
let id = fixed_site(&mut sim, DVec3::new(0.0,64.0,300.0), 2);
let (mut ground, mut out) = (Ground::default(), Out::default());
sim.order_strike(id, DVec3::new(0.0,64.0,0.0), &mut out).unwrap();
let f = sim.strikes.flights[0];
let wall = Wall { at: f.land.y.floor() as i32 - 1, hole: None };
for _ in 0..400 {
    serve(&mut ground, &wall, sim.tick);
    sim.step(&mut ground, None, &mut out);
    if sim.strikes.flights.is_empty() { break; }
}
assert_eq!(sim.strikes.destroyed, 0); // падает: 1

Выбранная без подмены RNG точка land (1.155,266.097), стена z=265, arrive=38. Взрыв в (1.150,65.295,264.999986) — прямо перед стеной. При этом площадка z=300 получает alive=false, stock=0, оба будущих запуска отменены; сообщение «площадка уничтожена». Ожидался Blocked с сохранением площадки по контракту этого issue.

Нужно проверять весь терминальный отрезок, включая Pending/Wait/Unknown, до решения об исходе. Близость к endpoint сама по себе не подтверждает свободный путь. Добавить этот тест рядом с уже работающими стеной посередине/проёмом/открытым путём. P1 этого issue остаётся актуальным; отдельный дубль не создаю.

🤖 Agent: Codex — повторное ревью исправления в `kimi-work` @ `cd3c4ed76d3308ec1d87341b962ff04aadada293`. **#106 пока исправлен не полностью: финальный подход обходит sweep/narrow phase.** В [strike.rs:592](https://gitea.maoniao.team/chexit/airdef/src/commit/cd3c4ed76d3308ec1d87341b962ff04aadada293/airdef-mod/src/sim/strike.rs#L592) проверка `now >= f.arrive && from.distance(end) <= TUNE.speed * 1.5 + 2.0` вызывает `land_strike` раньше `ground.trace`. Допуск равен 14 блокам. Это также снимает ожидающий shape-ответ у последней стены: стоящая у её грани ракета объявляет попадание, не получив разрешения пролететь оставшийся отрезок. Подтверждено тестом на отдельной копии мода, с существующими новыми helpers `fixed_site`, `Wall`, `serve`: ```rust let mut sim = Sim::new(11); sim.strikes.cover_override = Some(0); let id = fixed_site(&mut sim, DVec3::new(0.0,64.0,300.0), 2); let (mut ground, mut out) = (Ground::default(), Out::default()); sim.order_strike(id, DVec3::new(0.0,64.0,0.0), &mut out).unwrap(); let f = sim.strikes.flights[0]; let wall = Wall { at: f.land.y.floor() as i32 - 1, hole: None }; for _ in 0..400 { serve(&mut ground, &wall, sim.tick); sim.step(&mut ground, None, &mut out); if sim.strikes.flights.is_empty() { break; } } assert_eq!(sim.strikes.destroyed, 0); // падает: 1 ``` Выбранная без подмены RNG точка land `(1.155,266.097)`, стена `z=265`, arrive=38. Взрыв в `(1.150,65.295,264.999986)` — прямо **перед** стеной. При этом площадка z=300 получает `alive=false`, stock=0, оба будущих запуска отменены; сообщение «площадка уничтожена». Ожидался `Blocked` с сохранением площадки по контракту этого issue. Нужно проверять весь терминальный отрезок, включая Pending/Wait/Unknown, до решения об исходе. Близость к endpoint сама по себе не подтверждает свободный путь. Добавить этот тест рядом с уже работающими стеной посередине/проёмом/открытым путём. P1 этого issue остаётся актуальным; отдельный дубль не создаю.
Author
Owner

🤖 Agent: Codex — отдельная регрессия нового движения при ожидании world-query вынесена в #117: после 20 тиков ожидания открытого мира ракета за следующий тик перемещается на 164.7 блока при TUNE.speed=8. Терминальный пропуск коллизии описан выше в этом issue; это разные причины и регрессионные проверки.

🤖 Agent: Codex — отдельная регрессия нового движения при ожидании world-query вынесена в #117: после 20 тиков ожидания открытого мира ракета за следующий тик перемещается на 164.7 блока при TUNE.speed=8. Терминальный пропуск коллизии описан выше в этом issue; это разные причины и регрессионные проверки.
Author
Owner

🤖 Agent: Codex — исправлен оставшийся терминальный обход коллизии, опубликовано в kimi-work, 5860c50.

Убран land_strike по одной близости к endpoint до trace. Последний отрезок проходит тот же sweep/exact-shape путь; Wait и удерживающий Unknown не засчитываются как попадание. Контакт в самой конечной точке допускает нормальное приземление, промежуточная стена даёт Blocked.

Добавлена регрессия из повторного ревью: стена за один блок перед выбранной land, seed=11. ПУ остаётся живой, оба отложенных запуска сохранены, фиксируется ровно один Blocked у стены. Существующие проверки открытого пути/проёма тоже проходят.

Проверка всего набора после объединения: 173 unit + 4 scenario tests passed, 7 ignored; WASM release build и git diff --check прошли. GUI/прослушивание звука в этом проходе не выполнялись. Статус issue не меняю.

🤖 Agent: Codex — исправлен оставшийся терминальный обход коллизии, опубликовано в `kimi-work`, [5860c50](https://gitea.maoniao.team/chexit/airdef/commit/5860c50). Убран land_strike по одной близости к endpoint до trace. Последний отрезок проходит тот же sweep/exact-shape путь; Wait и удерживающий Unknown не засчитываются как попадание. Контакт в самой конечной точке допускает нормальное приземление, промежуточная стена даёт Blocked. Добавлена регрессия из повторного ревью: стена за один блок перед выбранной land, seed=11. ПУ остаётся живой, оба отложенных запуска сохранены, фиксируется ровно один Blocked у стены. Существующие проверки открытого пути/проёма тоже проходят. Проверка всего набора после объединения: 173 unit + 4 scenario tests passed, 7 ignored; WASM release build и git diff --check прошли. GUI/прослушивание звука в этом проходе не выполнялись. Статус issue не меняю.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chexit/airdef#106