diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index 1eab8dfdfd..e1bd38ce3b 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include "PrintConfig.hpp" @@ -2227,8 +2226,7 @@ std::pair PresetBundle::load_system_pre // Then load remaining vendors from per-vendor caches. auto try_vendor_cache = [&](const std::string& vendor_name) -> bool { const std::string json_path = (dir / (vendor_name + ".json")).string(); - const Semver ver = get_version_from_json(json_path); - const std::string ver_str = ver.valid() ? ver.to_string() : ""; + const std::string ver_str = get_vendor_cache_key(json_path); vendor_json_versions[vendor_name] = ver_str; VendorCache vc; @@ -2277,6 +2275,7 @@ std::pair PresetBundle::load_system_pre const auto json_load_t0 = std::chrono::steady_clock::now(); PresetsConfigSubstitutions substitutions; std::string errors_cummulative; + std::set errored_vendors; // vendors whose JSON parse failed — skip their cache save // first = true means no vendor has been loaded yet (from cache or JSON). // false = at least one vendor was applied from the per-vendor cache above. bool first = validation_mode || cache_miss_vendors.size() == vendor_json_versions.size(); @@ -2320,6 +2319,7 @@ std::pair PresetBundle::load_system_pre throw err; errors_cummulative += err.what(); errors_cummulative += "\n"; + errored_vendors.insert(orca_lib_vendor); } } @@ -2356,6 +2356,7 @@ std::pair PresetBundle::load_system_pre throw std::runtime_error(parallel_errors[i]); errors_cummulative += parallel_errors[i]; errors_cummulative += "\n"; + errored_vendors.insert(other_vendors[i]); continue; } if (!parallel_bundles[i]) @@ -2390,10 +2391,14 @@ std::pair PresetBundle::load_system_pre BOOST_LOG_TRIVIAL(info) << "PresetBundle: system presets loaded from JSON in " << json_ms << " ms"; } - // Save per-vendor binary caches for vendors that had to be parsed from JSON. - if (!validation_mode && !cache_miss_vendors.empty() && errors_cummulative.empty()) { + // Save per-vendor binary caches for vendors that parsed successfully. + // Vendors whose JSON produced a parse error are skipped individually so one + // bad vendor does not block caching of all others. + if (!validation_mode && !cache_miss_vendors.empty()) { const auto save_t0 = std::chrono::steady_clock::now(); for (const auto& vendor_name : cache_miss_vendors) { + if (errored_vendors.count(vendor_name)) + continue; const bool is_orca_lib = (vendor_name == ORCA_FILAMENT_LIBRARY); const std::string ver_str = vendor_json_versions.count(vendor_name) ? vendor_json_versions.at(vendor_name) : ""; @@ -5697,6 +5702,19 @@ struct CacheFileHeader { #pragma pack(pop) static_assert(sizeof(CacheFileHeader) == 20, "CacheFileHeader must be 20 bytes"); +// Returns the string used as vendor_json_version in the cache validity check. +// For versioned vendors this is the Semver string from the JSON. +// For version-less vendors we use the file mtime so any edit invalidates the cache. +static std::string get_vendor_cache_key(const std::string& json_path) +{ + const Semver ver = get_version_from_json(json_path); + if (ver.valid()) + return ver.to_string(); + boost::system::error_code ec; + const std::time_t mtime = boost::filesystem::last_write_time(json_path, ec); + return ec ? std::string{} : ("mtime:" + std::to_string(mtime)); +} + template static void save_blob(const std::string& path, const T& obj) { @@ -5790,7 +5808,7 @@ void PresetBundle::VendorCache::capture(const PresetBundle& bundle, bool capture_filament_maps) { cache_version = CACHE_VERSION; - config_options_count = print_config_def.options.size(); + config_options_count = static_cast(print_config_def.options.size()); vendor_json_version = vendor_json_ver; print_presets.clear(); @@ -5801,66 +5819,17 @@ void PresetBundle::VendorCache::capture(const PresetBundle& bundle, config_maps.clear(); filament_id_maps.clear(); - // Vendor profile + // Vendor profile — copy directly; VendorProfile now carries its own serialize() auto vp_it = bundle.vendors.find(vendor_id); - if (vp_it != bundle.vendors.end()) { - const VendorProfile& vp = vp_it->second; - profile.id = vp.id; - profile.name = vp.name; - profile.config_version = vp.config_version.valid() ? vp.config_version.to_string() : ""; - profile.config_update_url = vp.config_update_url; - profile.changelog_url = vp.changelog_url; - profile.models.clear(); - for (const auto& model : vp.models) { - CachedPrinterModel cm; - cm.id = model.id; - cm.name = model.name; - cm.model_id = model.model_id; - cm.family = model.family; - cm.technology = static_cast(model.technology); - for (const auto& v : model.variants) - cm.variants.push_back(v.name); - cm.default_materials = model.default_materials; - cm.not_support_bed_types = model.not_support_bed_types; - cm.bed_model = model.bed_model; - cm.bed_texture = model.bed_texture; - cm.image_bed_type = model.image_bed_type; - cm.bottom_texture_end_name = model.bottom_texture_end_name; - cm.use_double_extruder_default_texture = model.use_double_extruder_default_texture; - cm.bottom_texture_rect = model.bottom_texture_rect; - cm.middle_texture_rect = model.middle_texture_rect; - cm.hotend_model = model.hotend_model; - profile.models.push_back(std::move(cm)); - } - profile.default_filaments.clear(); - for (const auto& f : vp.default_filaments) - profile.default_filaments.push_back(f); - profile.default_sla_materials.clear(); - for (const auto& m : vp.default_sla_materials) - profile.default_sla_materials.push_back(m); - } + if (vp_it != bundle.vendors.end()) + profile = vp_it->second; - // Presets — only those belonging to this vendor - auto capture_col = [&](const PresetCollection& coll, std::vector& out) { + // Presets — only those belonging to this vendor; Preset now carries its own serialize() + auto capture_col = [&](const PresetCollection& coll, std::vector& out) { for (const Preset& p : coll()) { if (!p.is_system) continue; if (p.vendor == nullptr || p.vendor->id != vendor_id) continue; - CachedPreset cp; - cp.type = static_cast(p.type); - cp.name = p.name; - cp.alias = p.alias; - cp.file = p.file; - cp.version = p.version.valid() ? p.version.to_string() : ""; - cp.vendor_id = vendor_id; - cp.filament_id = p.filament_id; - cp.setting_id = p.setting_id; - cp.description = p.description; - cp.renamed_from = p.renamed_from; - cp.is_system = p.is_system; - cp.is_visible = p.is_visible; - cp.m_from_orca_filament_lib = p.m_from_orca_filament_lib; - cp.config = p.config; - out.push_back(std::move(cp)); + out.push_back(p); // vendor pointer not serialized; apply() reconstructs it } }; capture_col(bundle.prints, print_presets); @@ -5878,55 +5847,23 @@ void PresetBundle::VendorCache::capture(const PresetBundle& bundle, void PresetBundle::VendorCache::apply(PresetBundle& bundle) const { // Restore vendor profile (additive — does not reset the bundle) + bundle.vendors.emplace(profile.id, profile); + + // Restore presets; vendor pointer is reconstructed from profile.id since all + // presets in this cache belong to the same vendor. + const VendorProfile* vp = nullptr; { - VendorProfile vp(profile.id); - vp.name = profile.name; - vp.config_update_url = profile.config_update_url; - vp.changelog_url = profile.changelog_url; - if (!profile.config_version.empty()) { - auto v = Semver::parse(profile.config_version); - if (v) vp.config_version = *v; - } - for (const auto& cm : profile.models) { - VendorProfile::PrinterModel model; - model.id = cm.id; - model.name = cm.name; - model.model_id = cm.model_id; - model.family = cm.family; - model.technology = static_cast(cm.technology); - for (const auto& v : cm.variants) - model.variants.emplace_back(v); - model.default_materials = cm.default_materials; - model.not_support_bed_types = cm.not_support_bed_types; - model.bed_model = cm.bed_model; - model.bed_texture = cm.bed_texture; - model.image_bed_type = cm.image_bed_type; - model.bottom_texture_end_name = cm.bottom_texture_end_name; - model.use_double_extruder_default_texture = cm.use_double_extruder_default_texture; - model.bottom_texture_rect = cm.bottom_texture_rect; - model.middle_texture_rect = cm.middle_texture_rect; - model.hotend_model = cm.hotend_model; - vp.models.push_back(std::move(model)); - } - for (const auto& f : profile.default_filaments) - vp.default_filaments.insert(f); - for (const auto& m : profile.default_sla_materials) - vp.default_sla_materials.insert(m); - bundle.vendors.emplace(profile.id, std::move(vp)); + auto it = bundle.vendors.find(profile.id); + if (it != bundle.vendors.end()) + vp = &it->second; } - // Restore presets - auto apply_col = [&](const std::vector& cached, - PresetCollection& coll, - bool is_filaments) { - for (const auto& cp : cached) { - Semver version; - if (!cp.version.empty()) { - auto v = Semver::parse(cp.version); - if (v) version = *v; - } + auto apply_col = [&](const std::vector& cached, + PresetCollection& coll, + bool is_filaments) { + for (const Preset& cp : cached) { DynamicPrintConfig config = cp.config; - Preset& p = coll.load_preset(cp.file, cp.name, std::move(config), /*select=*/false, version); + Preset& p = coll.load_preset(cp.file, cp.name, std::move(config), /*select=*/false, cp.version); p.is_system = true; p.is_visible = cp.is_visible; p.alias = cp.alias; @@ -5935,11 +5872,7 @@ void PresetBundle::VendorCache::apply(PresetBundle& bundle) const p.setting_id = cp.setting_id; p.description = cp.description; p.m_from_orca_filament_lib = cp.m_from_orca_filament_lib; - if (!cp.vendor_id.empty()) { - auto it = bundle.vendors.find(cp.vendor_id); - if (it != bundle.vendors.end()) - p.vendor = &it->second; - } + p.vendor = vp; if (is_filaments) coll.set_printer_hold_alias(p.alias, p); } diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp index f77c9ed1d5..c464de38db 100644 --- a/src/libslic3r/PresetBundle.hpp +++ b/src/libslic3r/PresetBundle.hpp @@ -13,12 +13,6 @@ #include #include -#include -#include -#include -#include -#include -#include #define DEFAULT_USER_FOLDER_NAME "default" #define BUNDLE_STRUCTURE_JSON_NAME "bundle_structure.json" @@ -162,77 +156,23 @@ public: // One file per vendor: // Bundled (CI-generated): resources/profiles/.cache // User (runtime): data_dir/system/.cache - - struct CachedPrinterModel { - std::string id, name, model_id, family; - int technology = 0; - std::vector variants; // nozzle diameter strings - std::vector default_materials; - std::vector not_support_bed_types; - std::string bed_model, bed_texture, image_bed_type; - std::string bottom_texture_end_name, use_double_extruder_default_texture; - std::string bottom_texture_rect, middle_texture_rect, hotend_model; - - template - void serialize(Archive& ar) - { - ar(id, name, model_id, family, technology, variants, default_materials, - not_support_bed_types, bed_model, bed_texture, image_bed_type, - bottom_texture_end_name, use_double_extruder_default_texture, - bottom_texture_rect, middle_texture_rect, hotend_model); - } - }; - - struct CachedVendorProfile { - std::string id, name, config_version, config_update_url, changelog_url; - std::vector models; - std::vector default_filaments; - std::vector default_sla_materials; - - template - void serialize(Archive& ar) - { - ar(id, name, config_version, config_update_url, changelog_url, - models, default_filaments, default_sla_materials); - } - }; - - struct CachedPreset { - int type = 0; - std::string name, alias, file, version; - std::string vendor_id; - std::string filament_id, setting_id, description; - std::string base_id, user_id, sync_info; - long long updated_time = 0; - std::vector renamed_from; - bool is_system = true; - bool is_visible = true; - bool m_from_orca_filament_lib = false; - DynamicPrintConfig config; - - template - void serialize(Archive& ar) - { - ar(type, name, alias, file, version, vendor_id, filament_id, setting_id, - description, base_id, user_id, sync_info, updated_time, renamed_from, - is_system, is_visible, m_from_orca_filament_lib, config); - } - }; + // VendorProfile, VendorProfile::PrinterModel, and Preset carry their own + // cereal serialize() methods so no mirror structs are needed. struct VendorCache { static constexpr uint32_t CACHE_MAGIC = 0x4F52435A; // "ORCZ" - static constexpr uint32_t CACHE_VERSION = 3; + static constexpr uint32_t CACHE_VERSION = 4; // bumped: Preset/VendorProfile serialize directly uint32_t cache_version = CACHE_VERSION; - size_t config_options_count = 0; - std::string vendor_json_version; // Semver string, or "" for version-less vendors + uint32_t config_options_count = 0; // fixed-width: size_t varies between 32/64-bit builds + std::string vendor_json_version; // Semver string, or mtime: for version-less vendors - CachedVendorProfile profile; - std::vector print_presets; - std::vector filament_presets; - std::vector printer_presets; - std::vector sla_print_presets; - std::vector sla_material_presets; + VendorProfile profile; + std::vector print_presets; + std::vector filament_presets; + std::vector printer_presets; + std::vector sla_print_presets; + std::vector sla_material_presets; // Only populated for the ORCA_FILAMENT_LIBRARY vendor. std::map config_maps; @@ -251,7 +191,7 @@ public: bool is_valid(const std::string& current_vendor_json_version) const { return cache_version == CACHE_VERSION - && config_options_count == print_config_def.options.size() + && config_options_count == static_cast(print_config_def.options.size()) && vendor_json_version == current_vendor_json_version; }