diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp b/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp index bef0391109..0e8b1ea12b 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp +++ b/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp @@ -995,16 +995,22 @@ void DevFilaSystemParser::ParseAgentFilament(const json& data, MachineObject* ob } // --- external / direct spools -> obj->vt_slot --- - // extruder 0 -> main virtual slot, extruder >0 -> deputy. + // Keep one virtual slot per extruder. The legacy two-extruder mapping uses + // 255 for extruder 0 and 254 for extruder 1; continue that sequence for + // additional extruders (253, 252, ...). if (obj && data.contains("external") && data["external"].is_array()) { + std::map external_slots; obj->vt_slot.clear(); for (const auto& e : data["external"]) { if (!e.is_object()) continue; const int ext = e.value("extruder", MAIN_EXTRUDER_ID); - const int vt_id = (ext == MAIN_EXTRUDER_ID) ? VIRTUAL_TRAY_MAIN_ID : VIRTUAL_TRAY_DEPUTY_ID; + if (ext < MAIN_EXTRUDER_ID || ext > VIRTUAL_TRAY_MAIN_ID) + continue; + + const int vt_id = VIRTUAL_TRAY_MAIN_ID - ext; DevAmsTray tray(std::to_string(vt_id)); tray.is_exists = e.value("loaded", false); tray.m_fila_type = e.value("material", std::string()); @@ -1013,8 +1019,11 @@ void DevFilaSystemParser::ParseAgentFilament(const json& data, MachineObject* ob tray.nozzle_temp_min = std::to_string(e.value("nozzle_temp_min", 0)); tray.nozzle_temp_max = std::to_string(e.value("nozzle_temp_max", 0)); tray.remain = e.value("remain_percent", -1); - obj->vt_slot.push_back(tray); + external_slots.insert_or_assign(ext, std::move(tray)); } + + for (auto& entry : external_slots) + obj->vt_slot.push_back(std::move(entry.second)); } } diff --git a/tests/slic3rutils/test_dev_mapping.cpp b/tests/slic3rutils/test_dev_mapping.cpp index 4e32bcc20d..ce4727d68f 100644 --- a/tests/slic3rutils/test_dev_mapping.cpp +++ b/tests/slic3rutils/test_dev_mapping.cpp @@ -63,6 +63,32 @@ TEST_CASE("AMS tray placeholder state follows the latest status", "[DevFilaSyste CHECK_FALSE(tray->is_slot_placeholder); } +TEST_CASE("Agent external filament slots preserve every extruder", "[DevFilaSystem]") +{ + MachineObject obj(nullptr, nullptr, "test", "test_dev", "127.0.0.1"); + + const json filament = json::parse(R"({ + "external": [ + { "extruder": 3, "loaded": true, "material": "PETG", "preset_id": "P3" }, + { "extruder": 0, "loaded": true, "material": "PLA", "preset_id": "P0" }, + { "extruder": 2, "loaded": false, "material": "ABS", "preset_id": "P2" }, + { "extruder": 1, "loaded": true, "material": "ASA", "preset_id": "P1" } + ] + })"); + + DevFilaSystemParser::ParseAgentFilament(filament, &obj, obj.GetFilaSystem().get()); + + REQUIRE(obj.vt_slot.size() == 4); + CHECK(obj.vt_slot[0].id == "255"); + CHECK(obj.vt_slot[1].id == "254"); + CHECK(obj.vt_slot[2].id == "253"); + CHECK(obj.vt_slot[3].id == "252"); + CHECK(obj.vt_slot[0].setting_id == "P0"); + CHECK(obj.vt_slot[1].setting_id == "P1"); + CHECK(obj.vt_slot[2].setting_id == "P2"); + CHECK(obj.vt_slot[3].setting_id == "P3"); +} + TEST_CASE("Switch-bound AMS trays map to the left extruder", "[DevMapping]") { MachineObject obj(nullptr, nullptr, "test", "test_dev", "127.0.0.1");