From ec54dcedd0213e441006ff52e2f7c522a3dbf0a5 Mon Sep 17 00:00:00 2001 From: Felix Jen Date: Tue, 21 Apr 2026 23:23:00 -0500 Subject: [PATCH] Add unique filament_id for inherited user presets When a user creates a new filament preset by inheriting from an existing one (e.g., "Brand ABS @BBL H2D" inheriting from "Generic ABS @BBL H2D"), the resulting preset previously had no filament_id of its own. This caused two problems: 1. The AMS sync pipeline could not distinguish the user preset from its parent, so syncing filaments from the printer always resolved to the generic base preset instead of the user's custom one. 2. External tools that rely on filament_id for preset identification (e.g., Bambuddy, see maziggy/bambuddy#1053) could not assign or recognize user-created inherited presets in AMS slots. The root cause was twofold: - No filament_id was generated during save_current_preset() for inherited filament presets. Only base (non-inheriting) presets received one via the CreatePresetsDialog flow. - The AMS matching logic in sync_ams_list(), get_ams_cobox_infos(), and get_filament_presets() filtered candidates with `get_preset_base(f) == &f`, which by definition excludes any preset with a non-empty inherits() field. This commit: - Generates a unique filament_id (MD5 hash of preset name, prefixed with "P", truncated to 8 chars) when creating a new filament preset in PresetCollection::save_current_preset(). This matches the existing ID generation scheme used for base filaments in CreatePresetsDialog::get_filament_id(). - Persists filament_id into the JSON when saving inherited presets via Preset::save() and get_differed_values_to_update(). - Broadens the AMS filament matching predicates to also consider user presets that carry their own filament_id, rather than requiring them to be base presets. Files changed: src/libslic3r/Preset.cpp - ID generation, save, lookup src/libslic3r/PresetBundle.cpp - AMS sync matching predicates --- src/libslic3r/Preset.cpp | 27 ++++++++++++++++++++++----- src/libslic3r/PresetBundle.cpp | 4 ++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 826d8a1a19e..1824ddf628a 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include "libslic3r.h" #include "Utils.hpp" @@ -615,6 +617,11 @@ void Preset::save(DynamicPrintConfig* parent_config) opt_dst->set(opt_src); } } + + if (!filament_id.empty()) { + temp_config.set_key_value(BBL_JSON_KEY_FILAMENT_ID, new ConfigOptionString(filament_id)); + } + temp_config.save_to_json(this->file, this->name, from_str, this->version.to_string()); } else if (!filament_id.empty() && inherits().empty()) { DynamicPrintConfig temp_config = config; @@ -1500,9 +1507,9 @@ int PresetCollection::get_differed_values_to_update(Preset& preset, std::map> PresetCollection::get_filamen std::map> filament_presets; for (auto &preset : m_presets) { if (preset.is_user()) { - if (preset.inherits() == "") { filament_presets[preset.filament_id].push_back(&preset); } + if (preset.inherits() == "" || !preset.filament_id.empty()) { filament_presets[preset.filament_id].push_back(&preset); } continue; } if (get_preset_base(preset) == &preset) { filament_presets[preset.filament_id].push_back(&preset); } @@ -2511,8 +2518,18 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det preset.is_project_embedded = false; if (m_type == Preset::TYPE_PRINT) preset.config.option("print_settings_id", true)->value = new_name; - else if (m_type == Preset::TYPE_FILAMENT) + else if (m_type == Preset::TYPE_FILAMENT) { preset.config.option("filament_settings_id", true)->values[0] = new_name; + + boost::uuids::detail::md5 hash; + boost::uuids::detail::md5::digest_type digest; + hash.process_bytes(new_name.data(), new_name.size()); + hash.get_digest(digest); + const auto char_digest = reinterpret_cast(&digest); + std::string result; + boost::algorithm::hex(char_digest, char_digest + sizeof(boost::uuids::detail::md5::digest_type), std::back_inserter(result)); + preset.filament_id = "P" + result.substr(0, 7); + } else if (m_type == Preset::TYPE_PRINTER) preset.config.option("printer_settings_id", true)->value = new_name; //BBS: add lock logic for sync preset in background diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index d5244b6bc0f..2e24d466768 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -2307,7 +2307,7 @@ void PresetBundle::get_ams_cobox_infos(AMSComboInfo& combox_info) continue; } auto iter = std::find_if(filaments.begin(), filaments.end(), - [this, &filament_id](auto &f) { return f.is_compatible && filaments.get_preset_base(f) == &f && f.filament_id == filament_id; }); + [this, &filament_id](auto &f) { return f.is_compatible && (filaments.get_preset_base(f) == &f || (f.is_user() && !f.filament_id.empty())) && f.filament_id == filament_id; }); if (iter == filaments.end()) { BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id; auto filament_type = ams.opt_string("filament_type", 0u); @@ -2409,7 +2409,7 @@ unsigned int PresetBundle::sync_ams_list(std::vector