diff --git a/application/editormodenmt.cpp b/application/editormodenmt.cpp index 4310d6c8..a540e010 100644 --- a/application/editormodenmt.cpp +++ b/application/editormodenmt.cpp @@ -1030,13 +1030,18 @@ void editor_mode::nmt_lift_scenery(double const Offset) item.yaw = standing.yaw; moves.emplace_back(standing, item); } - if (move_templates(moves) > 0 && m_history.size() >= 2) - m_history.back().joined = true; - // the models, a group as a whole + // the includes moved by the place in their parameters are made anew there: their models aren't moved on their own, nor are + // the models left behind by earlier changes, deleted a moment later: moved, they'd get into the scene again + std::set remade; + for (auto const &move : moves) + if (scene::Layers.tracked(move.first.instance) && scene::Layers.removable(move.first.instance)) + remade.insert(move.first.instance); + // the models, a group as a whole, ahead of the includes, which retire theirs std::set groups; for (auto *instance : simulation::Instances.sequence()) { - if (instance == nullptr) + if (instance == nullptr || remade.contains(instance->m_instance) || + std::any_of(m_retired.begin(), m_retired.end(), [&](std::pair const &Retired) { return Retired.first == instance; })) continue; if (instance->group() > 1 && false == groups.insert(instance->group()).second) continue; @@ -1044,6 +1049,8 @@ void editor_mode::nmt_lift_scenery(double const Offset) m_history.back().joined = true; m_editor.translate(instance, instance->location() + shift, true); } + if (move_templates(moves) > 0 && m_history.size() >= 2) + m_history.back().joined = true; WriteLog(format("Editor: NMT - the scenery moved %+.2f m: %zu tracks, %zu includes, the models", Offset, lifted, moves.size()), logtype::generic); } diff --git a/application/editormodeselftestterrain.cpp b/application/editormodeselftestterrain.cpp index 2b49a7bc..8f2c66ca 100644 --- a/application/editormodeselftestterrain.cpp +++ b/application/editormodeselftestterrain.cpp @@ -231,6 +231,29 @@ editor_mode::selftest_result editor_mode::selftest_terrain(std::string const &co WriteLog("SELFTEST nmtwait: " + m_nmt_state.status + (m_nmt_state.error.empty() ? std::string{} : " (" + m_nmt_state.error + ")")); return selftest_result::handled; } + if (command == "danglers") + { + // models the cells hold which aren't in the scene any more, or are about to be destroyed + std::set const alive{simulation::Instances.sequence().begin(), simulation::Instances.sequence().end()}; + std::size_t held{0}, gone{0}, retired{0}; + for (auto const *section : simulation::Region->m_sections) + { + if (section == nullptr) + continue; + for (auto const &cell : section->m_cells) + for (auto const *sequence : {&cell.m_instancesopaque, &cell.m_instancetranslucent}) + for (auto const *instance : *sequence) + { + ++held; + if (false == alive.contains(instance)) + ++gone; + else if (std::any_of(m_retired.begin(), m_retired.end(), [&](std::pair const &Retired) { return Retired.first == instance; })) + ++retired; + } + } + WriteLog(format("SELFTEST danglers: %zu held, %zu gone, %zu retired, %zu waiting", held, gone, retired, m_retired.size())); + return selftest_result::handled; + } if (command == "terrainmode") { m_terrain_open = true;