From 67b9f076554b9a56dbd61922be10fb9b77be3775 Mon Sep 17 00:00:00 2001 From: mrmees <38006194+mrmees@users.noreply.github.com> Date: Thu, 28 May 2026 09:29:16 -0500 Subject: [PATCH] Fix built-in placeholders missing from custom G-code and output filenames (#13892) * fix: restore version placeholder in custom G-code PlaceholderParser sets "version" in its constructor, but Print::apply() calls clear_config() which wipes it. Unlike timestamp/user (restored during G-code export), version was never restored, so [version]/{version} threw "Variable does not exist" in custom G-code while working in output filenames. Re-set version after both clear_config() calls so it resolves everywhere. Co-Authored-By: Claude Opus 4.7 (1M context) * fix: resolve timestamp and user placeholders in File header G-code file_start_gcode is processed via print.placeholder_parser() directly, before the G-code parser integration copy that restores timestamp/user. As a result {timestamp}, {year}..{second} and {user} threw "Variable does not exist" in the File header G-code field while working in Machine start/end G-code. Inject fresh timestamp and user into the file_start_gcode config so they resolve, matching the other custom G-code fields. Co-Authored-By: Claude Opus 4.7 (1M context) * fix: expose initial_extruder and extruded_*_total placeholders in output filenames PrintStatistics exposed initial_tool (not its documented alias initial_extruder) and total_weight/extruded_volume (not the documented extruded_weight_total/extruded_volume_total). Filename formats using the missing names failed with "not a variable name". Add the missing aliases to PrintStatistics::config() and placeholders(). Fixes #12436 Fixes #10708 Co-Authored-By: Claude Opus 4.7 (1M context) --- src/libslic3r/GCode.cpp | 3 +++ src/libslic3r/Print.cpp | 7 +++++-- src/libslic3r/PrintApply.cpp | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 359052bc964..867f3243014 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2549,6 +2549,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato std::string top_gcode_template = print.config().file_start_gcode.value; if (!top_gcode_template.empty()) { DynamicConfig top_config; + // file_start_gcode runs before the parser copy that normally restores these, so set them here. + PlaceholderParser::update_timestamp(top_config); + PlaceholderParser::update_user_name(top_config); top_config.set_key_value("print_time_sec", new ConfigOptionString(GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Print_Time_Sec_Placeholder))); top_config.set_key_value("used_filament_length", new ConfigOptionString(GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Used_Filament_Length_Placeholder))); std::string top_gcode = print.placeholder_parser().process(top_gcode_template, 0, &top_config); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 9d8b1c4cf75..a335e29b829 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -3609,9 +3609,12 @@ DynamicConfig PrintStatistics::config() const config.set_key_value("total_cost", new ConfigOptionFloat(this->total_cost)); config.set_key_value("total_toolchanges", new ConfigOptionInt(this->total_toolchanges)); config.set_key_value("total_weight", new ConfigOptionFloat(this->total_weight)); + config.set_key_value("extruded_weight_total", new ConfigOptionFloat(this->total_weight)); + config.set_key_value("extruded_volume_total", new ConfigOptionFloat(this->total_extruded_volume)); config.set_key_value("total_wipe_tower_cost", new ConfigOptionFloat(this->total_wipe_tower_cost)); config.set_key_value("total_wipe_tower_filament", new ConfigOptionFloat(this->total_wipe_tower_filament)); config.set_key_value("initial_tool", new ConfigOptionInt(static_cast(this->initial_tool))); + config.set_key_value("initial_extruder", new ConfigOptionInt(static_cast(this->initial_tool))); return config; } @@ -3620,8 +3623,8 @@ DynamicConfig PrintStatistics::placeholders() DynamicConfig config; for (const std::string key : { "print_time", "normal_print_time", "silent_print_time", - "used_filament", "extruded_volume", "total_cost", "total_weight", - "initial_tool", "total_toolchanges", "total_wipe_tower_cost", "total_wipe_tower_filament"}) + "used_filament", "extruded_volume", "extruded_volume_total", "total_cost", "total_weight", "extruded_weight_total", + "initial_tool", "initial_extruder", "total_toolchanges", "total_wipe_tower_cost", "total_wipe_tower_filament"}) config.set_key_value(key, new ConfigOptionString(std::string("{") + key + "}")); return config; } diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index c9b500a85c3..8f153c3037e 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -1254,6 +1254,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" %1%: found full_config_diff changed.")%__LINE__; update_apply_status(this->invalidate_step(psGCodeExport)); m_placeholder_parser.clear_config(); + // clear_config() wiped the constructor-set "version"; restore it for custom G-code. + m_placeholder_parser.set("version", std::string(SoftFever_VERSION)); // Set the profile aliases for the PrintBase::output_filename() m_placeholder_parser.set("print_preset", new_full_config.option("print_settings_id")->clone()); m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone()); @@ -1630,6 +1632,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" %1%: full_config_diff previous empty, need to apply now.")%__LINE__; m_placeholder_parser.clear_config(); + // clear_config() wiped the constructor-set "version"; restore it for custom G-code. + m_placeholder_parser.set("version", std::string(SoftFever_VERSION)); // Set the profile aliases for the PrintBase::output_filename() m_placeholder_parser.set("print_preset", new_full_config.option("print_settings_id")->clone()); m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone());