Rebuild the G-code line offsets after post-processing scripts run in place

This commit is contained in:
ExPikaPaka
2026-07-29 08:20:11 +02:00
parent 5ede9711f5
commit 9553326e7d
3 changed files with 49 additions and 1 deletions

View File

@@ -2562,6 +2562,43 @@ void GCodeProcessorResult::reset() {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" %1%: this=%2% reset finished")%__LINE__%this;
}
bool GCodeProcessorResult::rebuild_lines_ends()
{
// lock_guard rather than the lock()/unlock() pair reset() uses: this reads a file and grows a
// vector, so a throw between the two would leave the mutex held forever.
std::lock_guard<std::mutex> lock(result_mutex);
// A partially rebuilt map would have the G-code window slicing lines at wrong offsets all over
// again, so every failure below leaves lines_ends empty, which just hides the window.
lines_ends.clear();
FilePtr in{ boost::nowide::fopen(filename.c_str(), "rb") };
if (in.f == nullptr) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": cannot open " << filename << " to rebuild the G-code line offsets.";
return false;
}
// Record the offset one past each '\n', matching what ExportLines emits during the export pass.
std::vector<char> buffer(65536, 0);
size_t file_pos = 0;
for (;;) {
const size_t cnt_read = ::fread(buffer.data(), 1, buffer.size(), in.f);
if (::ferror(in.f)) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": error while reading " << filename
<< " to rebuild the G-code line offsets.";
lines_ends.clear();
return false;
}
for (size_t i = 0; i < cnt_read; ++i) {
if (buffer[i] == '\n')
lines_ends.emplace_back(file_pos + i + 1);
}
file_pos += cnt_read;
if (cnt_read < buffer.size())
break;
}
return true;
}
const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> GCodeProcessor::Producers = {
//BBS: OrcaSlicer is also "bambu". Otherwise the time estimation didn't work.
//FIXME: Workaround and should be handled when do removing-bambu

View File

@@ -317,6 +317,11 @@ class Print;
BedType bed_type = BedType::btCount;
void reset();
// Re-scan this->filename and rebuild lines_ends from it. Needed whenever the exported G-code is
// modified in place after export (post-processing scripts), which shifts the byte offsets the
// G-code viewer uses to slice lines out of the memory-mapped file. Returns false and leaves
// lines_ends empty if the file cannot be read.
bool rebuild_lines_ends();
//BBS: add mutex for protection of gcode result
mutable std::mutex result_mutex;

View File

@@ -261,7 +261,13 @@ void BackgroundSlicingProcess::process_fff()
// GCodeProcessorResult, so m_gcode_result->nozzle_group_result (consumed by the H2C print-dispatch
// nozzle mapping) survives post-processing. No preservation guard is needed on this path.
if (m_fff_print->is_BBL_printer()) {
run_post_process_scripts(m_temp_output_path, false, "File", m_temp_output_path, m_fff_print->full_print_config());
if (run_post_process_scripts(m_temp_output_path, false, "File", m_temp_output_path, m_fff_print->full_print_config()))
// The scripts/plugins rewrote the very file the G-code viewer memory-maps, so every byte
// offset in m_gcode_result->lines_ends (built while exporting the pre-processed G-code) is
// now stale and GCodeWindow would slice the file mid-line. Re-scan it. Note this only
// realigns the line framing: if a script inserts or removes lines, the moves' gcode_id
// still refers to the pre-processed numbering and the highlighted line stays shifted.
m_gcode_result->rebuild_lines_ends();
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": export gcode finished");