mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-20 01:12:09 +00:00
profiles: deterministic setting_id from vendor/type/name (#14432)
* profiles: enforce globally-unique, per-vendor-namespaced setting_id Many non-Bambu vendors copied Bambu's generic setting_ids (GFSA04 alone appeared in 1557 files), so setting_id was not globally unique. This namespaces every vendor's ids and reserves Bambu/OrcaFilamentLibrary space. - Reserve "G*" (Bambu) and "O*" (OrcaFilamentLibrary) id spaces. - Assign each other vendor a 2-char prefix (first+last letter, collision resolved) and renumber every instantiated preset to <PREFIX><NNNN>. - Strip setting_id from base profiles (instantiation:false) per Bambu's convention; assign one to instantiated presets that lacked it. - Remove the pre-existing misspelled "settings_id" key (91 files). - filament_id is left untouched (it is a per-material id). - Add one-time migration script scripts/assign_vendor_setting_ids.py with a persisted registry resources/profiles/vendor_prefixes.json. Re-runs freeze existing ids; only new vendors/profiles get new ids. - Bump version in each changed vendor index file. - Extend scripts/orca_extra_profile_check.py with a CI guard: global uniqueness, in-namespace, no base setting_id, no gaps, no settings_id typo. 7425 profile files changed across 61 vendors; 0 cross-vendor collisions; validator clean; migration idempotent. BBL and OrcaFilamentLibrary id spaces untouched. * profiles: add setting_id authoring guide for new vendors / profiles * profiles: drop in-repo README; setting_id guide now lives in the wiki * profiles: derive setting_id deterministically from vendor/type/name * bump profile version
This commit is contained in:
@@ -39,6 +39,8 @@
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/locale.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
@@ -520,6 +522,39 @@ std::string Preset::get_type_string(Preset::Type type)
|
||||
}
|
||||
}
|
||||
|
||||
std::string generate_preset_setting_id(const std::string& vendor, const std::string& type, const std::string& name)
|
||||
{
|
||||
if (vendor.empty() || name.empty())
|
||||
return "";
|
||||
|
||||
// Dedicated namespace for preset setting_ids, distinct from the cloud per-user
|
||||
// namespace (OrcaCloudServiceAgent). Keep in sync with scripts/assign_vendor_setting_ids.py;
|
||||
// never change this constant.
|
||||
static const boost::uuids::uuid vendor_namespace =
|
||||
boost::uuids::string_generator()("c1f4d9e2-7a3b-5c8d-9e0f-1a2b3c4d5e6f");
|
||||
|
||||
boost::uuids::name_generator_sha1 gen(vendor_namespace);
|
||||
boost::uuids::uuid id = gen(vendor + "/" + type + "/" + name);
|
||||
|
||||
// Render the low 16 base62 digits of the 128-bit id, most-significant first.
|
||||
// Implemented as long-division over the 16 raw (big-endian) bytes so it stays
|
||||
// portable (no __int128, which MSVC lacks) and matches the Python reference.
|
||||
static const char ALPHABET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
unsigned char bytes[16];
|
||||
std::copy(id.begin(), id.end(), bytes);
|
||||
char out[16];
|
||||
for (int pos = 15; pos >= 0; --pos) {
|
||||
unsigned int rem = 0;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
unsigned int cur = (rem << 8) | bytes[i];
|
||||
bytes[i] = static_cast<unsigned char>(cur / 62);
|
||||
rem = cur % 62;
|
||||
}
|
||||
out[pos] = ALPHABET[rem];
|
||||
}
|
||||
return std::string(out, 16);
|
||||
}
|
||||
|
||||
std::string Preset::get_iot_type_string(Preset::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
@@ -2196,11 +2231,12 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
|
||||
const auto inherits_iter = preset_values.find(BBL_JSON_KEY_INHERITS);
|
||||
const bool preset_inherits_from_parent = inherits_iter != preset_values.end() && !inherits_iter->second.empty();
|
||||
if (preset_inherits_from_parent) {
|
||||
// This indicates that there is inherits exists but there is no base_id
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__
|
||||
<< boost::format("can not find base_id, not loading for user preset %1%") % canonical_name;
|
||||
unlock();
|
||||
return false;
|
||||
// No base_id stored although the preset inherits from a parent. Rather than
|
||||
// dropping the preset, derive base_id on the fly from the resolved parent's
|
||||
// setting_id below (the parent is found by its "inherits" name). Only the
|
||||
// genuinely unresolvable-parent case is skipped, further down.
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__
|
||||
<< boost::format("no base_id for user preset %1%, will derive it from the parent") % canonical_name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2228,6 +2264,11 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
|
||||
const Preset& default_preset = this->default_preset_for(cloud_config);
|
||||
if (inherit_preset) {
|
||||
new_config = inherit_preset->config;
|
||||
// Derive base_id from the resolved parent when it was not supplied. The
|
||||
// parent's setting_id is itself computed deterministically at load time, so
|
||||
// this stays stable. Does not affect the preset's own (cloud) setting_id.
|
||||
if (based_id.empty())
|
||||
based_id = inherit_preset->setting_id;
|
||||
if (cloud_filament_id == "null") {
|
||||
cloud_filament_id = inherit_preset->filament_id;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,16 @@ namespace Slic3r {
|
||||
class AppConfig;
|
||||
class PresetBundle;
|
||||
|
||||
// Deterministic preset setting_id: uuid5(vendor/type/name) -> 16 base62 chars.
|
||||
// Pure function of a system preset's identity, so the value can be assigned by
|
||||
// scripts/assign_vendor_setting_ids.py and recomputed here when a profile ships
|
||||
// without it. MUST stay byte-identical to scripts/assign_vendor_setting_ids.py.
|
||||
// This is NOT the per-user cloud-sync setting_id
|
||||
// (OrcaCloudServiceAgent::generate_uuid_for_setting_id) - do not conflate them.
|
||||
std::string generate_preset_setting_id(const std::string& vendor,
|
||||
const std::string& type,
|
||||
const std::string& name);
|
||||
|
||||
enum ConfigFileType
|
||||
{
|
||||
CONFIG_FILE_TYPE_UNKNOWN,
|
||||
|
||||
@@ -5039,6 +5039,13 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
|
||||
loaded.version = current_vendor_profile->config_version;
|
||||
loaded.description = description;
|
||||
loaded.setting_id = setting_id;
|
||||
// Derive the preset setting_id on the fly when a profile ships without one,
|
||||
// matching scripts/assign_vendor_setting_ids.py. Only instantiated presets
|
||||
// carry an id; non-instantiated base profiles return earlier above. This never
|
||||
// touches the per-user cloud-sync setting_id written into user .info files.
|
||||
if (loaded.setting_id.empty() && instantiation == "true")
|
||||
loaded.setting_id = generate_preset_setting_id(
|
||||
vendor_name, Preset::get_type_string(presets_collection->type()), preset_name);
|
||||
loaded.filament_id = filament_id;
|
||||
loaded.m_from_orca_filament_lib = is_from_lib;
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << " " << __LINE__ << ", " << loaded.name << " load filament_id: " << filament_id;
|
||||
|
||||
Reference in New Issue
Block a user