mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-12 02:11:39 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bf2aa3e50 | ||
|
|
7369674d8f | ||
|
|
70da7e89bb | ||
|
|
a671bf605d | ||
|
|
bae8f64b8b | ||
|
|
2df07b7ed8 | ||
|
|
295094a594 | ||
|
|
210bc927bc | ||
|
|
00cfb5b259 | ||
|
|
2bd105b0ce | ||
|
|
b81d761605 | ||
|
|
6922edfc20 | ||
|
|
7ec147603f | ||
|
|
8ee9e5915a | ||
|
|
cd5b786704 | ||
|
|
d715bb760c | ||
|
|
63918b44a8 | ||
|
|
64d09c9bca |
+674
-230
File diff suppressed because it is too large
Load Diff
+1006
-340
File diff suppressed because it is too large
Load Diff
+1003
-337
File diff suppressed because it is too large
Load Diff
+1002
-336
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1001
-335
File diff suppressed because it is too large
Load Diff
+1003
-337
File diff suppressed because it is too large
Load Diff
+1005
-339
File diff suppressed because it is too large
Load Diff
+1007
-341
File diff suppressed because it is too large
Load Diff
+1001
-332
File diff suppressed because it is too large
Load Diff
+1013
-347
File diff suppressed because it is too large
Load Diff
+1009
-343
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1012
-346
File diff suppressed because it is too large
Load Diff
+1000
-334
File diff suppressed because it is too large
Load Diff
+1006
-340
File diff suppressed because it is too large
Load Diff
+1006
-340
File diff suppressed because it is too large
Load Diff
+1009
-343
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,795 @@
|
||||
{
|
||||
"presets": {
|
||||
"Bambu ABS @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu ABS @BBL X1C": [
|
||||
"Bambu Lab P1S 0.4 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu ASA @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PA6-CF @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PA6-CF @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PA6-CF @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PA6-CF @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PA6-CF @BBL X1C": [
|
||||
"Bambu Lab P1P 0.6 nozzle",
|
||||
"Bambu Lab P1P 0.8 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab P1S 0.8 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.8 nozzle"
|
||||
],
|
||||
"Bambu PA6-CF @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PAHT-CF @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PAHT-CF @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PAHT-CF @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PAHT-CF @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle",
|
||||
"Bambu Lab P1P 0.8 nozzle"
|
||||
],
|
||||
"Bambu PAHT-CF @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PAHT-CF @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab P1S 0.8 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.8 nozzle"
|
||||
],
|
||||
"Bambu PAHT-CF @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PC @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PETG @0.2 nozzle": [
|
||||
"Qidi Q1 Pro 0.2 nozzle"
|
||||
],
|
||||
"Bambu PETG Basic @BBL H2D 0.6 nozzle": [
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Basic @BBL H2DP 0.6 nozzle": [
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Basic @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Basic @BBL P2S 0.6 nozzle": [
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Basic @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG HF @BBL P2S 0.6 nozzle": [
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG HF @BBL X1C": [
|
||||
"Bambu Lab P1P 0.4 nozzle",
|
||||
"Bambu Lab P1S 0.4 nozzle"
|
||||
],
|
||||
"Bambu PETG HF @BBL X1C 0.8 nozzle": [
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PETG HF @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Translucent @BBL H2D 0.6 nozzle": [
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Translucent @BBL H2DP 0.6 nozzle": [
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Translucent @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Translucent @BBL P2S 0.6 nozzle": [
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG Translucent @BBL X1C 0.8 nozzle": [
|
||||
"Bambu Lab P1P 0.6 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PETG-CF @BBL H2D 0.6 nozzle": [
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG-CF @BBL H2DP 0.6 nozzle": [
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG-CF @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PETG-CF @BBL P2S 0.6 nozzle": [
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Basic @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Basic @BBL X1C": [
|
||||
"Bambu Lab P1S 0.4 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Basic @BBL X2D 0.6 nozzle": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Dynamic @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Dynamic @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Galaxy @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Galaxy @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Glow @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Glow @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Lite @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Lite @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Lite @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Lite @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Lite @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Marble @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle",
|
||||
"Bambu Lab P1P 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Marble @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Matte @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Matte @BBL X1C": [
|
||||
"Bambu Lab P1S 0.4 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Matte @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Metal @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Metal @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Silk+ @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Silk+ @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Silk+ @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Silk+ @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Silk+ @BBL X1C": [
|
||||
"Bambu Lab P1S 0.4 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Silk+ @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Sparkle @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Sparkle @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Tough+ @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Tough+ @BBL X1C": [
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Tough+ @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Translucent @BBL H2D 0.8 nozzle": [
|
||||
"Bambu Lab H2D 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Translucent @BBL H2DP 0.8 nozzle": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Translucent @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA Wood @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA Wood @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu PLA-CF @BBL H2D 0.6 nozzle": [
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA-CF @BBL H2DP 0.6 nozzle": [
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA-CF @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA-CF @BBL P2S 0.6 nozzle": [
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PLA-CF @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PPA-CF @BBL X1C": [
|
||||
"Bambu Lab P1P 0.6 nozzle",
|
||||
"Bambu Lab P1P 0.8 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab P1S 0.8 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.8 nozzle"
|
||||
],
|
||||
"Bambu PVA @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu PVA @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu PVA @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PVA @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu PVA @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA/PETG @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA/PETG @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA/PETG @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA/PETG @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support For PLA/PETG @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support for ABS @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support for ABS @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support for ABS @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support for ABS @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu Support for ABS @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU 90A @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU 90A @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU 95A HF @BBL H2D": [
|
||||
"Bambu Lab H2D 0.4 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU 95A HF @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.4 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU 95A HF @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU 95A HF @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU 95A HF @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU for AMS @BBL H2D": [
|
||||
"Bambu Lab H2D 0.6 nozzle",
|
||||
"Bambu Lab H2D 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU for AMS @BBL H2DP": [
|
||||
"Bambu Lab H2D Pro 0.6 nozzle",
|
||||
"Bambu Lab H2D Pro 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU for AMS @BBL H2S": [
|
||||
"Bambu Lab H2S 0.6 nozzle",
|
||||
"Bambu Lab H2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU for AMS @BBL P1P": [
|
||||
"Bambu Lab P1P 0.6 nozzle"
|
||||
],
|
||||
"Bambu TPU for AMS @BBL P2S": [
|
||||
"Bambu Lab P2S 0.6 nozzle",
|
||||
"Bambu Lab P2S 0.8 nozzle"
|
||||
],
|
||||
"Bambu TPU for AMS @BBL X1C": [
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 Carbon 0.6 nozzle"
|
||||
],
|
||||
"Bambu TPU for AMS @BBL X2D": [
|
||||
"Bambu Lab X2D 0.8 nozzle"
|
||||
],
|
||||
"Blocks ABS @Blocks_RD50_V2": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks ASA @Blocks_RD50_V2": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks ASA-CF @Blocks_RD50_V2": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks PA @Blocks_RD50_V2": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks PA-CF @Blocks_RD50_V2": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks PC @Blocks_RD50_V2": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks PETG @Blocks_Pro_S100": [
|
||||
"BLOCKS RD50 V2 0.4 nozzle",
|
||||
"BLOCKS RD50 V2 0.6 nozzle",
|
||||
"BLOCKS RD50 V2 0.8 nozzle",
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks PLA @Blocks_Pro_S100": [
|
||||
"BLOCKS RD50 V2 0.4 nozzle",
|
||||
"BLOCKS RD50 V2 0.6 nozzle",
|
||||
"BLOCKS RD50 V2 0.8 nozzle",
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks PLA-CF @Blocks_RD50_V2": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks PVA @Blocks_RD50_V2": [
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Blocks TPU @Blocks_Pro_S100": [
|
||||
"BLOCKS RD50 V2 0.4 nozzle",
|
||||
"BLOCKS RD50 V2 0.6 nozzle",
|
||||
"BLOCKS RD50 V2 0.8 nozzle",
|
||||
"BLOCKS RF50 0.4 nozzle",
|
||||
"BLOCKS RF50 0.6 nozzle",
|
||||
"BLOCKS RF50 0.8 nozzle"
|
||||
],
|
||||
"Cubicon ABS @Cubicon xCeler-I 0.4 nozzle": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon ABS-A100 @Cubicon xCeler-I 0.4 nozzle": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon ABSk @Cubicon xCeler-I 0.4 nozzle": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon PA-CF @Cubicon xCeler-I 0.4 nozzle": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon PC @Cubicon xCeler-I 0.4 nozzle": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon PETG @Cubicon xCeler-I 0.4 nozzle": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon PLA @Cubicon xCeler-I 0.4 nozzle": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon PLA+ @Cubicon xCeler-I 0.4 nozzle": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Cubicon PLAi21 @Cubicon xCeler-I 0.4 nozzle": [
|
||||
"Cubicon xCeler-Plus 0.4 nozzle"
|
||||
],
|
||||
"Flashforge HS PLA": [
|
||||
"Flashforge AD5X 0.4 nozzle",
|
||||
"Flashforge AD5X 0.6 nozzle",
|
||||
"Flashforge AD5X 0.8 nozzle"
|
||||
],
|
||||
"Flashforge PETG-CF": [
|
||||
"Flashforge AD5X 0.4 nozzle",
|
||||
"Flashforge AD5X 0.6 nozzle",
|
||||
"Flashforge AD5X 0.8 nozzle"
|
||||
],
|
||||
"Flashforge PLA-CF": [
|
||||
"Flashforge AD5X 0.4 nozzle",
|
||||
"Flashforge AD5X 0.6 nozzle",
|
||||
"Flashforge AD5X 0.8 nozzle"
|
||||
],
|
||||
"Flashforge TPU 95A": [
|
||||
"Flashforge AD5X 0.4 nozzle",
|
||||
"Flashforge AD5X 0.6 nozzle",
|
||||
"Flashforge AD5X 0.8 nozzle"
|
||||
],
|
||||
"FusRock PAHT-CF": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle"
|
||||
],
|
||||
"FusRock PET-CF": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle"
|
||||
],
|
||||
"Generic ABS @Anycubic": [
|
||||
"Anycubic Kobra 3 0.4 nozzle"
|
||||
],
|
||||
"Generic ABS @Creality": [
|
||||
"Creality CR-10 SE 0.2 nozzle",
|
||||
"Creality CR-10 SE 0.4 nozzle",
|
||||
"Creality CR-10 SE 0.6 nozzle",
|
||||
"Creality CR-10 SE 0.8 nozzle",
|
||||
"Creality CR-6 SE 0.2 nozzle",
|
||||
"Creality CR-6 SE 0.4 nozzle",
|
||||
"Creality CR-6 SE 0.6 nozzle",
|
||||
"Creality CR-6 SE 0.8 nozzle",
|
||||
"Creality CR-M4 0.4 nozzle",
|
||||
"Creality Ender-3 V2 0.4 nozzle"
|
||||
],
|
||||
"Generic ABS @Creality Ender-3V3-all": [
|
||||
"Creality Ender-3 V3 Plus 0.4 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.6 nozzle"
|
||||
],
|
||||
"Generic ABS @Creality Hi-all": [
|
||||
"Creality Hi 0.4 nozzle"
|
||||
],
|
||||
"Generic ABS @Creality K1-all": [
|
||||
"Creality K1 SE 0.4 nozzle",
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Generic ABS @Creality K2-all": [
|
||||
"Creality K2 0.4 nozzle",
|
||||
"Creality K2 Plus 0.4 nozzle",
|
||||
"Creality K2 Plus 0.6 nozzle",
|
||||
"Creality K2 Plus 0.8 nozzle",
|
||||
"Creality K2 Pro 0.4 nozzle"
|
||||
],
|
||||
"Generic ABS @Flashforge G3U": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle"
|
||||
],
|
||||
"Generic ASA @Creality Ender-3V3-all": [
|
||||
"Creality Ender-3 V3 Plus 0.4 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.6 nozzle"
|
||||
],
|
||||
"Generic ASA @Creality K1-all": [
|
||||
"Creality K1 SE 0.4 nozzle",
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Generic ASA @Creality K2-all": [
|
||||
"Creality K2 0.4 nozzle",
|
||||
"Creality K2 Plus 0.4 nozzle",
|
||||
"Creality K2 Pro 0.4 nozzle"
|
||||
],
|
||||
"Generic ASA @Flashforge G3U": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle"
|
||||
],
|
||||
"Generic HIPS @Flashforge": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle"
|
||||
],
|
||||
"Generic PA @Prusa": [
|
||||
"Prusa MINIIS 0.25 nozzle",
|
||||
"Prusa MINIIS 0.4 nozzle",
|
||||
"Prusa MINIIS 0.6 nozzle",
|
||||
"Prusa MINIIS 0.8 nozzle"
|
||||
],
|
||||
"Generic PA-CF @Creality Ender-3V3-all": [
|
||||
"Creality Ender-3 V3 Plus 0.4 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.6 nozzle"
|
||||
],
|
||||
"Generic PA-CF @Creality K1-all": [
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Generic PA-CF @Creality K2-all": [
|
||||
"Creality K2 Plus 0.4 nozzle",
|
||||
"Creality K2 Plus 0.6 nozzle",
|
||||
"Creality K2 Plus 0.8 nozzle"
|
||||
],
|
||||
"Generic PA-CF @Prusa": [
|
||||
"Prusa MINIIS 0.25 nozzle",
|
||||
"Prusa MINIIS 0.4 nozzle",
|
||||
"Prusa MINIIS 0.6 nozzle",
|
||||
"Prusa MINIIS 0.8 nozzle"
|
||||
],
|
||||
"Generic PC @Creality K1-all": [
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Generic PETG @Creality": [
|
||||
"Creality CR-6 SE 0.2 nozzle",
|
||||
"Creality CR-6 SE 0.4 nozzle",
|
||||
"Creality CR-6 SE 0.6 nozzle",
|
||||
"Creality CR-6 SE 0.8 nozzle",
|
||||
"Creality CR-M4 0.4 nozzle"
|
||||
],
|
||||
"Generic PETG @Creality Ender-3V3-all": [
|
||||
"Creality Ender-3 V3 0.4 nozzle",
|
||||
"Creality Ender-3 V3 0.6 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.4 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.6 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.2 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.4 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.6 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.8 nozzle"
|
||||
],
|
||||
"Generic PETG @Creality Hi-all": [
|
||||
"Creality Hi 0.4 nozzle"
|
||||
],
|
||||
"Generic PETG @Creality K1-all": [
|
||||
"Creality K1 SE 0.4 nozzle",
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Generic PETG @Creality K2-all": [
|
||||
"Creality K2 0.4 nozzle",
|
||||
"Creality K2 Plus 0.4 nozzle",
|
||||
"Creality K2 Plus 0.6 nozzle",
|
||||
"Creality K2 Plus 0.8 nozzle",
|
||||
"Creality K2 Pro 0.4 nozzle"
|
||||
],
|
||||
"Generic PETG @Flashforge G3U": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle",
|
||||
"Flashforge Guider 3 Ultra 0.8 Nozzle"
|
||||
],
|
||||
"Generic PETG @Sovol Zero Hardened Steel nozzle": [
|
||||
"Sovol Zero 0.4 nozzle"
|
||||
],
|
||||
"Generic PETG HF @BBL X1C": [
|
||||
"Bambu Lab P1S 0.4 nozzle",
|
||||
"Bambu Lab P1S 0.6 nozzle",
|
||||
"Bambu Lab X1 0.4 nozzle",
|
||||
"Bambu Lab X1 0.6 nozzle",
|
||||
"Bambu Lab X1 0.8 nozzle"
|
||||
],
|
||||
"Generic PETG-CF @Flashforge G3U": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle",
|
||||
"Flashforge Guider 3 Ultra 0.8 Nozzle"
|
||||
],
|
||||
"Generic PLA @Creality": [
|
||||
"Creality CR-10 SE 0.2 nozzle",
|
||||
"Creality CR-10 SE 0.4 nozzle",
|
||||
"Creality CR-10 SE 0.6 nozzle",
|
||||
"Creality CR-10 SE 0.8 nozzle",
|
||||
"Creality CR-6 SE 0.2 nozzle",
|
||||
"Creality CR-6 SE 0.4 nozzle",
|
||||
"Creality CR-6 SE 0.6 nozzle",
|
||||
"Creality CR-6 SE 0.8 nozzle",
|
||||
"Creality CR-M4 0.4 nozzle"
|
||||
],
|
||||
"Generic PLA @Creality Ender-3V3-all": [
|
||||
"Creality Ender-3 V3 0.4 nozzle",
|
||||
"Creality Ender-3 V3 0.6 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.4 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.6 nozzle"
|
||||
],
|
||||
"Generic PLA @Creality K1-all": [
|
||||
"Creality K1 SE 0.4 nozzle",
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Generic PLA @Creality K2-all": [
|
||||
"Creality K2 0.4 nozzle",
|
||||
"Creality K2 Plus 0.4 nozzle",
|
||||
"Creality K2 Plus 0.6 nozzle",
|
||||
"Creality K2 Plus 0.8 nozzle",
|
||||
"Creality K2 Pro 0.4 nozzle"
|
||||
],
|
||||
"Generic PLA @Flashforge G3U": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle",
|
||||
"Flashforge Guider 3 Ultra 0.8 Nozzle"
|
||||
],
|
||||
"Generic PLA @Hi-all": [
|
||||
"Creality Hi 0.4 nozzle",
|
||||
"Creality Hi 0.6 nozzle"
|
||||
],
|
||||
"Generic PLA @Sovol Zero Hardened Steel nozzle": [
|
||||
"Sovol Zero 0.4 nozzle"
|
||||
],
|
||||
"Generic PLA Silk @Sovol Zero Hardened Steel nozzle": [
|
||||
"Sovol Zero 0.4 nozzle"
|
||||
],
|
||||
"Generic PLA-CF @Creality K1-all": [
|
||||
"Creality K1 SE 0.4 nozzle",
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Generic PLA-CF @Creality K2-all": [
|
||||
"Creality K2 0.4 nozzle",
|
||||
"Creality K2 Plus 0.4 nozzle",
|
||||
"Creality K2 Pro 0.4 nozzle"
|
||||
],
|
||||
"Generic PLA-CF @Flashforge G3U": [
|
||||
"Flashforge Guider 3 Ultra 0.6 Nozzle",
|
||||
"Flashforge Guider 3 Ultra 0.8 Nozzle"
|
||||
],
|
||||
"Generic PLA-CF @Prusa": [
|
||||
"Prusa MINIIS 0.25 nozzle",
|
||||
"Prusa MINIIS 0.4 nozzle",
|
||||
"Prusa MINIIS 0.6 nozzle",
|
||||
"Prusa MINIIS 0.8 nozzle"
|
||||
],
|
||||
"Generic TPU @Anycubic": [
|
||||
"Anycubic Kobra 3 0.4 nozzle"
|
||||
],
|
||||
"Generic TPU @Creality": [
|
||||
"Creality CR-10 SE 0.2 nozzle",
|
||||
"Creality CR-10 SE 0.4 nozzle",
|
||||
"Creality CR-10 SE 0.6 nozzle",
|
||||
"Creality CR-10 SE 0.8 nozzle"
|
||||
],
|
||||
"Generic TPU @Creality Ender-3V3-all": [
|
||||
"Creality Ender-3 V3 0.4 nozzle",
|
||||
"Creality Ender-3 V3 0.6 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.4 nozzle",
|
||||
"Creality Ender-3 V3 Plus 0.6 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.2 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.4 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.6 nozzle",
|
||||
"Creality Ender-3 V3 SE 0.8 nozzle"
|
||||
],
|
||||
"Generic TPU @Creality K1-all": [
|
||||
"Creality K1 SE 0.4 nozzle",
|
||||
"Creality K1C 0.4 nozzle"
|
||||
],
|
||||
"Generic TPU @Creality K2-all": [
|
||||
"Creality K2 0.4 nozzle",
|
||||
"Creality K2 Plus 0.4 nozzle",
|
||||
"Creality K2 Pro 0.4 nozzle"
|
||||
],
|
||||
"HATCHBOX PETG @0.2 nozzle": [
|
||||
"Qidi Q1 Pro 0.2 nozzle"
|
||||
],
|
||||
"QIDI PETG Basic @0.2 nozzle": [
|
||||
"Qidi Q1 Pro 0.2 nozzle"
|
||||
],
|
||||
"QIDI PETG Rapido @0.2 nozzle": [
|
||||
"Qidi Q1 Pro 0.2 nozzle"
|
||||
],
|
||||
"QIDI PETG Translucent @0.2 nozzle": [
|
||||
"Qidi Q1 Pro 0.2 nozzle"
|
||||
],
|
||||
"re3D PC @0.4 nozzle": [
|
||||
"re3D Gigabot 4 0.8 nozzle",
|
||||
"re3D Gigabot 4 XLT 0.8 nozzle",
|
||||
"re3D Terabot 4 0.8 nozzle"
|
||||
],
|
||||
"re3D PETG @0.4 nozzle": [
|
||||
"re3D Gigabot 4 0.8 nozzle",
|
||||
"re3D Gigabot 4 XLT 0.8 nozzle",
|
||||
"re3D Terabot 4 0.8 nozzle"
|
||||
],
|
||||
"re3D PLA @0.4 nozzle": [
|
||||
"re3D Gigabot 4 0.8 nozzle",
|
||||
"re3D Gigabot 4 XLT 0.8 nozzle",
|
||||
"re3D Terabot 4 0.8 nozzle"
|
||||
],
|
||||
"re3D rPETG @0.8 nozzle": [
|
||||
"re3D GigabotX 2 1.75 nozzle",
|
||||
"re3D GigabotX 2 XLT 1.75 nozzle",
|
||||
"re3D TerabotX 2 1.75 nozzle"
|
||||
],
|
||||
"re3D rPP @0.8 nozzle": [
|
||||
"re3D GigabotX 2 1.75 nozzle",
|
||||
"re3D GigabotX 2 XLT 1.75 nozzle",
|
||||
"re3D TerabotX 2 1.75 nozzle"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Anker",
|
||||
"version": "02.04.00.05",
|
||||
"version": "02.04.00.06",
|
||||
"force_update": "0",
|
||||
"description": "Anker configurations",
|
||||
"machine_model_list": [
|
||||
@@ -304,6 +304,26 @@
|
||||
"name": "Generic PLA Silk @Anker 0.25 nozzle",
|
||||
"sub_path": "filament/Generic PLA Silk @Anker 0.25 nozzle.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Basic @Anker base",
|
||||
"sub_path": "filament/AnkerMake PLA+ Basic @Anker base.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Glitter @Anker base",
|
||||
"sub_path": "filament/AnkerMake PLA+ Glitter @Anker base.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Matte @Anker base",
|
||||
"sub_path": "filament/AnkerMake PLA+ Matte @Anker base.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Metallic @Anker base",
|
||||
"sub_path": "filament/AnkerMake PLA+ Metallic @Anker base.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Silk @Anker base",
|
||||
"sub_path": "filament/AnkerMake PLA+ Silk @Anker base.json"
|
||||
},
|
||||
{
|
||||
"name": "Generic PLA+ @Anker",
|
||||
"sub_path": "filament/Generic PLA+ @Anker.json"
|
||||
@@ -327,6 +347,26 @@
|
||||
{
|
||||
"name": "Generic TPU @Anker",
|
||||
"sub_path": "filament/Generic TPU @Anker.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Basic @Anker",
|
||||
"sub_path": "filament/AnkerMake PLA+ Basic @Anker.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Glitter @Anker",
|
||||
"sub_path": "filament/AnkerMake PLA+ Glitter @Anker.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Matte @Anker",
|
||||
"sub_path": "filament/AnkerMake PLA+ Matte @Anker.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Metallic @Anker",
|
||||
"sub_path": "filament/AnkerMake PLA+ Metallic @Anker.json"
|
||||
},
|
||||
{
|
||||
"name": "AnkerMake PLA+ Silk @Anker",
|
||||
"sub_path": "filament/AnkerMake PLA+ Silk @Anker.json"
|
||||
}
|
||||
],
|
||||
"machine_list": [
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Basic @Anker base",
|
||||
"inherits": "Generic PLA+ @Anker base",
|
||||
"from": "system",
|
||||
"filament_id": "OFUuZlQL",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"AnkerMake"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"200"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"230"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"1"
|
||||
],
|
||||
"close_fan_the_first_x_layers": [
|
||||
"3"
|
||||
],
|
||||
"fan_cooling_layer_time": [
|
||||
"60"
|
||||
],
|
||||
"slow_down_layer_time": [
|
||||
"8"
|
||||
],
|
||||
"slow_down_min_speed": [
|
||||
"30"
|
||||
],
|
||||
"default_filament_colour": [
|
||||
"#FFFFFF"
|
||||
],
|
||||
"filament_max_volumetric_speed": [
|
||||
"22"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Basic @Anker",
|
||||
"inherits": "AnkerMake PLA+ Basic @Anker base",
|
||||
"from": "system",
|
||||
"setting_id": "EfM5rmn4w6pMBajC",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Anker M5 0.4 nozzle",
|
||||
"Anker M5 0.6 nozzle",
|
||||
"Anker M5 All-Metal 0.4 nozzle",
|
||||
"Anker M5 All-Metal 0.6 nozzle",
|
||||
"Anker M5C 0.4 nozzle",
|
||||
"Anker M5C 0.6 nozzle"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Glitter @Anker base",
|
||||
"inherits": "Generic PLA+ @Anker base",
|
||||
"from": "system",
|
||||
"filament_id": "OFxCURdg",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"AnkerMake"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"200"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"230"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"1"
|
||||
],
|
||||
"close_fan_the_first_x_layers": [
|
||||
"3"
|
||||
],
|
||||
"fan_cooling_layer_time": [
|
||||
"60"
|
||||
],
|
||||
"slow_down_layer_time": [
|
||||
"6"
|
||||
],
|
||||
"slow_down_min_speed": [
|
||||
"30"
|
||||
],
|
||||
"default_filament_colour": [
|
||||
"#00AD66"
|
||||
],
|
||||
"filament_max_volumetric_speed": [
|
||||
"22"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Glitter @Anker",
|
||||
"inherits": "AnkerMake PLA+ Glitter @Anker base",
|
||||
"from": "system",
|
||||
"setting_id": "blGHp0htgHEj7khE",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Anker M5 0.4 nozzle",
|
||||
"Anker M5 0.6 nozzle",
|
||||
"Anker M5 All-Metal 0.4 nozzle",
|
||||
"Anker M5 All-Metal 0.6 nozzle",
|
||||
"Anker M5C 0.4 nozzle",
|
||||
"Anker M5C 0.6 nozzle"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Matte @Anker base",
|
||||
"inherits": "Generic PLA+ @Anker base",
|
||||
"from": "system",
|
||||
"filament_id": "OFKDOyNK",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"AnkerMake"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"210"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"230"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"1"
|
||||
],
|
||||
"close_fan_the_first_x_layers": [
|
||||
"3"
|
||||
],
|
||||
"fan_cooling_layer_time": [
|
||||
"60"
|
||||
],
|
||||
"slow_down_layer_time": [
|
||||
"6"
|
||||
],
|
||||
"slow_down_min_speed": [
|
||||
"30"
|
||||
],
|
||||
"default_filament_colour": [
|
||||
"#FFFFFF"
|
||||
],
|
||||
"filament_max_volumetric_speed": [
|
||||
"22"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Matte @Anker",
|
||||
"inherits": "AnkerMake PLA+ Matte @Anker base",
|
||||
"from": "system",
|
||||
"setting_id": "tPgwC1eEXyWPOn9S",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Anker M5 0.4 nozzle",
|
||||
"Anker M5 All-Metal 0.4 nozzle",
|
||||
"Anker M5C 0.4 nozzle"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Metallic @Anker base",
|
||||
"inherits": "Generic PLA+ @Anker base",
|
||||
"from": "system",
|
||||
"filament_id": "OFBfbmtb",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"AnkerMake"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"200"
|
||||
],
|
||||
"textured_plate_temp": [
|
||||
"60"
|
||||
],
|
||||
"textured_plate_temp_initial_layer": [
|
||||
"60"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"1"
|
||||
],
|
||||
"close_fan_the_first_x_layers": [
|
||||
"3"
|
||||
],
|
||||
"fan_cooling_layer_time": [
|
||||
"60"
|
||||
],
|
||||
"slow_down_layer_time": [
|
||||
"6"
|
||||
],
|
||||
"slow_down_min_speed": [
|
||||
"30"
|
||||
],
|
||||
"overhang_fan_speed": [
|
||||
"50"
|
||||
],
|
||||
"reduce_fan_stop_start_freq": [
|
||||
"0"
|
||||
],
|
||||
"filament_retraction_length": [
|
||||
"1"
|
||||
],
|
||||
"filament_retraction_speed": [
|
||||
"50"
|
||||
],
|
||||
"filament_deretraction_speed": [
|
||||
"50"
|
||||
],
|
||||
"default_filament_colour": [
|
||||
"#ACAC8A"
|
||||
],
|
||||
"filament_max_volumetric_speed": [
|
||||
"20"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Metallic @Anker",
|
||||
"inherits": "AnkerMake PLA+ Metallic @Anker base",
|
||||
"from": "system",
|
||||
"setting_id": "jlbAMNNaEacdUASZ",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Anker M5 0.4 nozzle",
|
||||
"Anker M5 All-Metal 0.4 nozzle",
|
||||
"Anker M5C 0.4 nozzle"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Silk @Anker base",
|
||||
"inherits": "Generic PLA+ @Anker base",
|
||||
"from": "system",
|
||||
"filament_id": "OFkxTGQc",
|
||||
"instantiation": "false",
|
||||
"filament_vendor": [
|
||||
"AnkerMake"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"210"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"230"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp": [
|
||||
"65"
|
||||
],
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"textured_plate_temp_initial_layer": [
|
||||
"65"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"1"
|
||||
],
|
||||
"close_fan_the_first_x_layers": [
|
||||
"3"
|
||||
],
|
||||
"fan_cooling_layer_time": [
|
||||
"60"
|
||||
],
|
||||
"slow_down_layer_time": [
|
||||
"2"
|
||||
],
|
||||
"slow_down_min_speed": [
|
||||
"20"
|
||||
],
|
||||
"filament_retraction_length": [
|
||||
"0.5"
|
||||
],
|
||||
"filament_retraction_speed": [
|
||||
"20"
|
||||
],
|
||||
"filament_wipe": [
|
||||
"0"
|
||||
],
|
||||
"default_filament_colour": [
|
||||
"#99ADA3"
|
||||
],
|
||||
"filament_deretraction_speed": [
|
||||
"20"
|
||||
],
|
||||
"filament_max_volumetric_speed": [
|
||||
"13"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"type": "filament",
|
||||
"name": "AnkerMake PLA+ Silk @Anker",
|
||||
"inherits": "AnkerMake PLA+ Silk @Anker base",
|
||||
"from": "system",
|
||||
"setting_id": "eVM9Ckwjl5vEvEKN",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"Anker M5 0.4 nozzle",
|
||||
"Anker M5 All-Metal 0.4 nozzle",
|
||||
"Anker M5 All-Metal 0.6 nozzle",
|
||||
"Anker M5C 0.4 nozzle",
|
||||
"Anker M5C 0.6 nozzle"
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Anycubic",
|
||||
"version": "02.04.00.08",
|
||||
"version": "02.04.00.09",
|
||||
"force_update": "0",
|
||||
"description": "Anycubic configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
"default_filament_profile": [
|
||||
"Generic PLA @Anycubic"
|
||||
],
|
||||
"machine_start_gcode": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG0 Z0.2 F1800 ; move nozzle to print position\nG92 E0 ; specify current extruder position as zero\nG1 Y10 X180 E50 F1200 ; extrude a line in front of the printer\nG92 E0 ; specify current extruder position as zero\nG0 Z20 F6000 ; move head up\nG1 E-7 F2400 ; retract\nG04 S2 ; wait 2s\nG0 X0 F6000 ; wipe from oozed filament\nG1 E-1 F2400 ; undo some of the retraction to avoid oozing\nG1 F6000 ; set travel speed to move to start printing point\nM117",
|
||||
"machine_start_gcode": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG0 Z0.2 F1800 ; move nozzle to print position\nG92 E0 ; specify current extruder position as zero\nM109 S[nozzle_temperature_initial_layer] ; wait for nozzle temp to stabilize\nG1 Y10 X180 E50 F1200 ; extrude a line in front of the printer\nG92 E0 ; specify current extruder position as zero\nG0 Z20 F6000 ; move head up\nG1 E-7 F2400 ; retract\nG04 S2 ; wait 2s\nG0 X0 F6000 ; wipe from oozed filament\nG1 E-1 F2400 ; undo some of the retraction to avoid oozing\nG1 F6000 ; set travel speed to move to start printing point\nM117",
|
||||
"machine_end_gcode": "G4 ; wait\nG92 E0\nG1{if max_layer_z < printable_height} Z{z_offset+min(max_layer_z+30, printable_height)}{endif} ; move print head up\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200 F3000 ; home X axis\nM84 ; disable motors",
|
||||
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]",
|
||||
"layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Bambulab",
|
||||
"url": "http://www.bambulab.com/Parameters/vendor/BBL.json",
|
||||
"version": "02.08.00.13",
|
||||
"version": "02.08.00.14",
|
||||
"force_update": "0",
|
||||
"description": "the initial version of BBL configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"0.4"
|
||||
],
|
||||
"printer_variant": "0.4",
|
||||
"use_3mf": "1",
|
||||
"bed_exclude_area": [
|
||||
"0x0",
|
||||
"28x0",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"0.4"
|
||||
],
|
||||
"printer_variant": "0.4",
|
||||
"use_3mf": "1",
|
||||
"best_object_pos": "0.3x0.5",
|
||||
"bed_exclude_area": [],
|
||||
"bed_temperature_formula": "by_highest_temp",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Prusa",
|
||||
"version": "02.04.00.16",
|
||||
"version": "02.04.00.17",
|
||||
"force_update": "0",
|
||||
"description": "Prusa configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
"35"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.04{elsif nozzle_diameter[filament_extruder_id]==0.25}0.1{elsif nozzle_diameter[filament_extruder_id]==0.3}0.06{elsif nozzle_diameter[filament_extruder_id]==0.35}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.03{elsif nozzle_diameter[filament_extruder_id]==0.6}0.02{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.04{elsif nozzle_diameter[filament_extruder_id]==0.25}0.1{elsif nozzle_diameter[filament_extruder_id]==0.3}0.06{elsif nozzle_diameter[filament_extruder_id]==0.35}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.03{elsif nozzle_diameter[filament_extruder_id]==0.6}0.02{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"110"
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
"35"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.04{elsif nozzle_diameter[filament_extruder_id]==0.25}0.1{elsif nozzle_diameter[filament_extruder_id]==0.3}0.06{elsif nozzle_diameter[filament_extruder_id]==0.35}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.03{elsif nozzle_diameter[filament_extruder_id]==0.6}0.02{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.04{elsif nozzle_diameter[filament_extruder_id]==0.25}0.1{elsif nozzle_diameter[filament_extruder_id]==0.3}0.06{elsif nozzle_diameter[filament_extruder_id]==0.35}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.03{elsif nozzle_diameter[filament_extruder_id]==0.6}0.02{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"110"
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
"0.8"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.053{elsif nozzle_diameter[filament_extruder_id]==0.5}0.042{elsif nozzle_diameter[filament_extruder_id]==0.6}0.032{elsif nozzle_diameter[filament_extruder_id]==0.8}0.018{elsif nozzle_diameter[filament_extruder_id]==0.25}0.18{elsif nozzle_diameter[filament_extruder_id]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.053{elsif nozzle_diameter[filament_extruder_id]==0.5}0.042{elsif nozzle_diameter[filament_extruder_id]==0.6}0.032{elsif nozzle_diameter[filament_extruder_id]==0.8}0.018{elsif nozzle_diameter[filament_extruder_id]==0.25}0.18{elsif nozzle_diameter[filament_extruder_id]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_wipe": [
|
||||
"1"
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
"15"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One|CORE One L).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_z_hop": [
|
||||
"0.6"
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
"7"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[0]==0.4}0.03{elsif nozzle_diameter[0]==0.5}0.022{elsif nozzle_diameter[0]==0.6}0.018{elsif nozzle_diameter[0]==0.8}0.012{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.075{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[0]==0.4}0.05{elsif nozzle_diameter[0]==0.25}0.14{elsif nozzle_diameter[0]==0.3}0.07{elsif nozzle_diameter[0]==0.35}0.06{elsif nozzle_diameter[0]==0.6}0.03{elsif nozzle_diameter[0]==0.5}0.035{elsif nozzle_diameter[0]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[0]==0.4}0.03{elsif nozzle_diameter[0]==0.5}0.022{elsif nozzle_diameter[0]==0.6}0.018{elsif nozzle_diameter[0]==0.8}0.012{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.075{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_z_hop": [
|
||||
"0.6",
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
"0"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.04{elsif nozzle_diameter[filament_extruder_id]==0.25}0.1{elsif nozzle_diameter[filament_extruder_id]==0.3}0.06{elsif nozzle_diameter[filament_extruder_id]==0.35}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.03{elsif nozzle_diameter[filament_extruder_id]==0.6}0.02{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.04{elsif nozzle_diameter[filament_extruder_id]==0.25}0.1{elsif nozzle_diameter[filament_extruder_id]==0.3}0.06{elsif nozzle_diameter[filament_extruder_id]==0.35}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.03{elsif nozzle_diameter[filament_extruder_id]==0.6}0.02{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S40 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"ASA"
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"0"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"PA11-CF"
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
"0"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"PC"
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"0"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S45 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"PC-CF"
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
"0"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.053{elsif nozzle_diameter[filament_extruder_id]==0.5}0.042{elsif nozzle_diameter[filament_extruder_id]==0.6}0.032{elsif nozzle_diameter[filament_extruder_id]==0.8}0.018{elsif nozzle_diameter[filament_extruder_id]==0.25}0.18{elsif nozzle_diameter[filament_extruder_id]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.07{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{elsif nozzle_diameter[filament_extruder_id]==0.35}0.08{elsif nozzle_diameter[filament_extruder_id]==0.6}0.04{elsif nozzle_diameter[filament_extruder_id]==0.5}0.05{elsif nozzle_diameter[filament_extruder_id]==0.8}0.02{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.053{elsif nozzle_diameter[filament_extruder_id]==0.5}0.042{elsif nozzle_diameter[filament_extruder_id]==0.6}0.032{elsif nozzle_diameter[filament_extruder_id]==0.8}0.018{elsif nozzle_diameter[filament_extruder_id]==0.25}0.18{elsif nozzle_diameter[filament_extruder_id]==0.3}0.1{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"PETG"
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
"0"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One|CORE One L).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"PLA"
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"1"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"PVB"
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
"0"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|CORE One).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
"M900 K{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{elsif nozzle_diameter[filament_extruder_id]==0.35}0.06{elsif nozzle_diameter[filament_extruder_id]==0.6}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.8}0.015{else}0{endif} ; Filament gcode\n\n{if printer_notes=~/.*(MK4IS|XLIS|MK4S|MK3.9S|COREONE).*/}\nM572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n{endif}\n\nM142 S36 ; set heatbreak target temp"
|
||||
],
|
||||
"filament_type": [
|
||||
"PLA"
|
||||
|
||||
@@ -11,6 +11,7 @@ commands:
|
||||
normalize rewrite profile files into their canonical shape
|
||||
trim delete profile files no <vendor>.json list references
|
||||
update-index regenerate the *_list sections of <vendor>.json
|
||||
legacy-compat write the printers user presets keep from an older release
|
||||
|
||||
options shared by several commands:
|
||||
--vendor VENDOR act on one vendor bundle only; repeatable, empty means all
|
||||
@@ -24,6 +25,9 @@ After adding, renaming or deleting profile files, run:
|
||||
normalize -> update-index -> generate-id -> check
|
||||
normalize supplies missing types; update-index registers presets before id
|
||||
generation.
|
||||
After renaming filament presets or narrowing their compatible_printers, also
|
||||
rerun legacy-compat --base <2.4.2 profiles> so user presets made against 2.4.2
|
||||
keep their printers.
|
||||
Use trim only for deliberate cleanup, previewed with --dry-run: it judges against
|
||||
the current index and can delete newly added, unindexed presets.
|
||||
|
||||
@@ -3072,6 +3076,131 @@ def fix_variant_arrays(profiles_dir=PROFILES_DIR, vendors=None, dry_run=False, s
|
||||
return len(changed), errors
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# legacy-compat
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
LEGACY_COMPAT_PATH = os.path.normpath(
|
||||
os.path.join(SCRIPTS_DIR, "..", "resources", "info", "legacy_compatible_printers.json"))
|
||||
|
||||
|
||||
def _renamed_from(data):
|
||||
"""A preset's renamed_from names. Profiles write one ';'-separated string, as the
|
||||
loader's unescape_strings_cstyle reads it; none of them quote or escape a name."""
|
||||
value = data.get("renamed_from") or []
|
||||
return [n for v in _as_list(value) for n in v.split(";") if n]
|
||||
|
||||
|
||||
def _flatten_presets(profiles_dir):
|
||||
"""Every bundle's composed filament and printer presets, for legacy-compat.
|
||||
|
||||
Returns (filaments, printers): filaments maps (vendor, name) to a dict with the
|
||||
resolved compatible_printers, filament_id, extruder variants, renamed_from and
|
||||
whether it is instantiated; printers maps each instantiated printer name to a
|
||||
dict with its renamed_from and extruder variants. instantiation is read from the
|
||||
preset's own file, as the loader requires every file to state it.
|
||||
"""
|
||||
def instantiated(data):
|
||||
return str(data.get("instantiation", "")).lower() == "true"
|
||||
|
||||
ofl = load_vendor_configs(profiles_dir, OFL)["filament"]
|
||||
filaments, printers = {}, {}
|
||||
for vendor in list_vendor_names(profiles_dir):
|
||||
configs = load_vendor_configs(profiles_dir, vendor)
|
||||
cache = {}
|
||||
for name, (_rel, data) in configs["filament"].items():
|
||||
config = compose_config(name, configs["filament"], ofl, cache, vendor == OFL)
|
||||
filaments[(vendor, name)] = {
|
||||
"compatible_printers": set(_as_list(config.get("compatible_printers", ([],))[0])),
|
||||
"filament_id": config.get("filament_id", (None,))[0],
|
||||
"variants": set(_as_list(config.get("filament_extruder_variant", ([],))[0])),
|
||||
"instantiation": instantiated(data),
|
||||
"renamed_from": _renamed_from(data),
|
||||
}
|
||||
cache = {}
|
||||
for name, (_rel, data) in configs["machine"].items():
|
||||
if instantiated(data):
|
||||
config = compose_config(name, configs["machine"], {}, cache)
|
||||
printers[name] = {
|
||||
"renamed_from": _renamed_from(data),
|
||||
"variants": set(_as_list(config.get("printer_extruder_variant", ([],))[0])),
|
||||
}
|
||||
return filaments, printers
|
||||
|
||||
|
||||
def legacy_compatible_printers(base_dir, profiles_dir=PROFILES_DIR):
|
||||
"""Printers each current system filament preset covered in the base release
|
||||
but no longer lists, kept only where a current preset with the same
|
||||
filament_id still covers that printer.
|
||||
|
||||
User presets store only their diff, so they inherit their parent's
|
||||
compatible_printers; when a profile change narrows that list, a user preset
|
||||
made against the base release disappears from printers it was used on. The
|
||||
loader adds these printers back to such user presets. Requiring a same-id
|
||||
successor leaves out printers a filament was deliberately taken off, and
|
||||
requiring a shared extruder variant keeps a printer from picking up another
|
||||
variant's values.
|
||||
|
||||
Keyed by the current preset name: the loader resolves a renamed parent
|
||||
before the map is consulted. Printer names are translated through the
|
||||
printers' renamed_from. Returns {preset name: sorted printer names}.
|
||||
"""
|
||||
old_filaments, _ = _flatten_presets(base_dir)
|
||||
new_filaments, new_printers = _flatten_presets(profiles_dir)
|
||||
renamed_printer = {old: new for new, rec in new_printers.items() for old in rec["renamed_from"]}
|
||||
|
||||
old_by_name = {}
|
||||
for (vendor, name), rec in old_filaments.items():
|
||||
old_by_name.setdefault(name, []).append((vendor, rec))
|
||||
|
||||
covering = {} # filament_id -> printers some current instantiated preset covers
|
||||
for rec in new_filaments.values():
|
||||
if rec["instantiation"] and rec["filament_id"]:
|
||||
covering.setdefault(rec["filament_id"], set()).update(rec["compatible_printers"])
|
||||
|
||||
def shares_variant(filament, printer):
|
||||
variants = new_printers[printer]["variants"]
|
||||
return not filament["variants"] or not variants or bool(filament["variants"] & variants)
|
||||
|
||||
result = {}
|
||||
for (vendor, name), rec in sorted(new_filaments.items()):
|
||||
# An empty list means every printer, so nothing can have been lost.
|
||||
if not rec["instantiation"] or not rec["compatible_printers"]:
|
||||
continue
|
||||
old_printers = set()
|
||||
for old_name in [name] + rec["renamed_from"]:
|
||||
candidates = old_by_name.get(old_name, [])
|
||||
same_vendor = [r for v, r in candidates if v == vendor]
|
||||
for old in same_vendor or [r for _, r in candidates]:
|
||||
old_printers |= old["compatible_printers"]
|
||||
old_printers = {renamed_printer.get(p, p) for p in old_printers}
|
||||
lost = old_printers - rec["compatible_printers"]
|
||||
lost &= covering.get(rec["filament_id"], set()) & set(new_printers)
|
||||
lost = {p for p in lost if shares_variant(rec, p)}
|
||||
if lost:
|
||||
result[name] = sorted(lost)
|
||||
return result
|
||||
|
||||
|
||||
def run_legacy_compat(base_dir, profiles_dir, output, check):
|
||||
presets = legacy_compatible_printers(base_dir, profiles_dir)
|
||||
if check:
|
||||
try:
|
||||
with open(output, encoding="utf-8") as f:
|
||||
current = json.load(f).get("presets")
|
||||
except (OSError, ValueError, AttributeError):
|
||||
current = None
|
||||
if current != presets:
|
||||
print_error(f"{output} is out of date; rerun legacy-compat --base {base_dir}")
|
||||
return 1
|
||||
print_success(f"{output} is up to date")
|
||||
return 0
|
||||
with open(output, "w", encoding="utf-8", newline="\n") as f:
|
||||
f.write(json.dumps({"presets": presets}, indent=4, sort_keys=True, ensure_ascii=False) + "\n")
|
||||
print_info(f"wrote {len(presets)} presets / {sum(map(len, presets.values()))} printers to {output}")
|
||||
return 0
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# CLI
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -3093,11 +3222,17 @@ examples:
|
||||
preview resizing the variant arrays check rejects in that bundle
|
||||
orca_profile_tool.py check --strict --vendor BBL
|
||||
also hold every preset's inherited variant arrays to its own width
|
||||
orca_profile_tool.py legacy-compat --base /tmp/v2.4.2/resources/profiles
|
||||
rewrite resources/info/legacy_compatible_printers.json against 2.4.2's
|
||||
profiles (git archive v2.4.2 resources/profiles | tar -x -C /tmp/v2.4.2)
|
||||
|
||||
after adding, renaming or deleting profile files, run in this order:
|
||||
normalize -> update-index -> generate-id -> check
|
||||
normalize supplies missing types; update-index registers presets before id
|
||||
generation.
|
||||
After renaming filament presets or narrowing their compatible_printers, also
|
||||
rerun legacy-compat --base <2.4.2 profiles> so user presets made against 2.4.2
|
||||
keep their printers.
|
||||
Use trim only for deliberate cleanup, previewed with --dry-run: it judges against
|
||||
the current index and can delete newly added, unindexed presets.
|
||||
"""
|
||||
@@ -3227,6 +3362,22 @@ def build_parser():
|
||||
"Use trim only for deliberate unindexed-file cleanup, previewed with\n"
|
||||
"--dry-run; it can also delete newly authored presets.")
|
||||
|
||||
legacy_cmd = add(
|
||||
"legacy-compat", [profiles_opt],
|
||||
"write the printers user presets keep from an older release",
|
||||
"Compare the tree with an older release's profiles and write, per current\n"
|
||||
"filament preset, the printers it covered then and no longer lists, where a\n"
|
||||
"preset with the same filament_id still covers them. The loader adds these\n"
|
||||
"to user presets that inherit the preset, so a narrowed compatible_printers\n"
|
||||
"does not hide them on printers they were made for.")
|
||||
legacy_cmd.add_argument("--base", required=True, metavar="DIR",
|
||||
help="the older release's resources/profiles directory")
|
||||
legacy_cmd.add_argument("--output", default=LEGACY_COMPAT_PATH, metavar="FILE",
|
||||
help="map to write (default: resources/info/"
|
||||
"legacy_compatible_printers.json)")
|
||||
legacy_cmd.add_argument("--check", action="store_true",
|
||||
help="fail if the map differs from what --base implies; write nothing")
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
@@ -3260,6 +3411,9 @@ def main(argv=None):
|
||||
return run_generate_id(profiles_dir, vendors, args.filament_id, args.setting_id,
|
||||
args.dry_run)
|
||||
|
||||
if args.command == "legacy-compat":
|
||||
return run_legacy_compat(args.base, profiles_dir, args.output, args.check)
|
||||
|
||||
if args.command == "fix-variant":
|
||||
_changed, errors = fix_variant_arrays(profiles_dir, vendors, dry_run=args.dry_run,
|
||||
strict=args.strict)
|
||||
|
||||
@@ -1258,6 +1258,97 @@ class TestVariantNames(TreeCase):
|
||||
self.assertIn('holds the legacy variant "Direct Drive Normal"', out)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# legacy-compat
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestLegacyCompat(unittest.TestCase):
|
||||
"""A base release and the current tree, each with one vendor."""
|
||||
|
||||
def setUp(self):
|
||||
self.base, self.cur = Tree(), Tree()
|
||||
self.addCleanup(self.base.cleanup)
|
||||
self.addCleanup(self.cur.cleanup)
|
||||
|
||||
@staticmethod
|
||||
def printer(tree, name, **extra):
|
||||
tree.write("V", f"machine/{name}.json",
|
||||
{"type": "machine", "name": name, "instantiation": "true", **extra})
|
||||
tree.index("V", "machine", name, f"machine/{name}.json")
|
||||
|
||||
@staticmethod
|
||||
def filament(tree, name, printers, filament_id="OFpetg01", **extra):
|
||||
tree.write("V", f"filament/{name}.json",
|
||||
{"type": "filament", "name": name, "instantiation": "true",
|
||||
"filament_id": filament_id, "compatible_printers": printers, **extra})
|
||||
tree.index("V", "filament", name, f"filament/{name}.json")
|
||||
|
||||
def generate(self):
|
||||
return apt.legacy_compatible_printers(self.base.profiles, self.cur.profiles)
|
||||
|
||||
def test_renamed_and_narrowed_preset_keeps_printers_a_same_id_sibling_covers(self):
|
||||
for tree in (self.base, self.cur):
|
||||
for p in ("A 0.4", "A 0.6", "B 0.4"):
|
||||
self.printer(tree, p)
|
||||
self.filament(self.base, "PETG @A-all", ["A 0.4", "A 0.6", "B 0.4"])
|
||||
self.filament(self.cur, "PETG @V A-all", ["A 0.6"], renamed_from="PETG @A-all;PETG A-all")
|
||||
self.filament(self.cur, "PETG @A 0.4", ["A 0.4"])
|
||||
self.assertEqual(self.generate(), {"PETG @V A-all": ["A 0.4"]})
|
||||
|
||||
def test_printer_without_a_successor_is_left_out(self):
|
||||
for tree in (self.base, self.cur):
|
||||
for p in ("A 0.4", "A 0.6"):
|
||||
self.printer(tree, p)
|
||||
self.filament(self.base, "PETG @A", ["A 0.4", "A 0.6"])
|
||||
self.filament(self.cur, "PETG @A", ["A 0.6"])
|
||||
self.filament(self.cur, "Other @A", ["A 0.4"], filament_id="OFother1")
|
||||
self.assertEqual(self.generate(), {})
|
||||
|
||||
def test_printer_names_follow_printer_renames(self):
|
||||
self.printer(self.base, "Old 0.4")
|
||||
self.printer(self.base, "A 0.6")
|
||||
self.printer(self.cur, "New 0.4", renamed_from="Old 0.4")
|
||||
self.printer(self.cur, "A 0.6")
|
||||
self.filament(self.base, "PETG @A", ["Old 0.4", "A 0.6"])
|
||||
self.filament(self.cur, "PETG @A", ["A 0.6"])
|
||||
self.filament(self.cur, "PETG @New", ["New 0.4"])
|
||||
self.assertEqual(self.generate(), {"PETG @A": ["New 0.4"]})
|
||||
|
||||
def test_printer_without_a_shared_extruder_variant_is_left_out(self):
|
||||
for tree in (self.base, self.cur):
|
||||
self.printer(tree, "Direct 0.4", printer_extruder_variant=["Direct Drive Standard"])
|
||||
self.printer(tree, "Bowden 0.4", printer_extruder_variant=["Bowden Standard"])
|
||||
self.filament(self.base, "PETG @all", ["Direct 0.4", "Bowden 0.4"])
|
||||
self.filament(self.cur, "PETG @all", ["Direct 0.4"],
|
||||
filament_extruder_variant=["Direct Drive Standard"])
|
||||
self.filament(self.cur, "PETG @Bowden", ["Bowden 0.4"])
|
||||
self.assertEqual(self.generate(), {})
|
||||
|
||||
def test_preset_now_listing_no_printer_is_skipped(self):
|
||||
for tree in (self.base, self.cur):
|
||||
self.printer(tree, "A 0.4")
|
||||
self.filament(self.base, "PETG @A", ["A 0.4"])
|
||||
self.filament(self.cur, "PETG @A", [])
|
||||
self.assertEqual(self.generate(), {})
|
||||
|
||||
def test_check_passes_on_a_current_map_and_fails_on_a_stale_one(self):
|
||||
for tree in (self.base, self.cur):
|
||||
for p in ("A 0.4", "A 0.6"):
|
||||
self.printer(tree, p)
|
||||
self.filament(self.base, "PETG @A", ["A 0.4", "A 0.6"])
|
||||
self.filament(self.cur, "PETG @A", ["A 0.6"])
|
||||
self.filament(self.cur, "PETG @A 0.4", ["A 0.4"])
|
||||
output = os.path.join(self.cur.dir, "map.json")
|
||||
argv = ["legacy-compat", "--base", self.base.profiles, "--profiles", self.cur.profiles,
|
||||
"--output", output]
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
self.assertEqual(apt.main(argv), 0)
|
||||
self.assertEqual(apt.main(argv + ["--check"]), 0)
|
||||
with open(output, "w", encoding="utf-8") as f:
|
||||
json.dump({"presets": {}}, f)
|
||||
self.assertEqual(apt.main(argv + ["--check"]), 1)
|
||||
|
||||
|
||||
class TestDispatch(TreeCase):
|
||||
def test_each_command_reaches_its_own_writer(self):
|
||||
self.t.write("V", "filament/A.json", {"type": "filament", "name": "A"})
|
||||
|
||||
@@ -405,6 +405,7 @@ set(lisbslic3r_sources
|
||||
Polyline.hpp
|
||||
PresetBundle.cpp
|
||||
PresetBundle.hpp
|
||||
PrinterBedAssets.hpp
|
||||
PresetCacheFormat.cpp
|
||||
PresetCacheFormat.hpp
|
||||
Preset.cpp
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -932,10 +932,14 @@ bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const Pre
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const std::vector<std::string> &legacy = preset.preset.legacy_compatible_printers;
|
||||
auto is_legacy_printer = [&legacy](const std::string &name) { return std::find(legacy.begin(), legacy.end(), name) != legacy.end(); };
|
||||
return preset.preset.is_default || active_printer.preset.name.empty() || !has_compatible_printers ||
|
||||
std::find(compatible_printers->values.begin(), compatible_printers->values.end(), active_printer.preset.name) !=
|
||||
compatible_printers->values.end() ||
|
||||
(!active_printer.preset.is_system && is_compatible_with_parent_printer(preset, active_printer));
|
||||
(!active_printer.preset.is_system && is_compatible_with_parent_printer(preset, active_printer)) ||
|
||||
is_legacy_printer(active_printer.preset.name) ||
|
||||
(!active_printer.preset.is_system && is_legacy_printer(active_printer.preset.inherits()));
|
||||
}
|
||||
|
||||
bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer)
|
||||
@@ -2728,6 +2732,42 @@ void PresetCollection::update_after_user_presets_loaded()
|
||||
return;
|
||||
}
|
||||
|
||||
const Preset *PresetCollection::system_parent_with_inherited_printers(const Preset &preset) const
|
||||
{
|
||||
if (!preset.is_user() || preset.inherits().empty())
|
||||
return nullptr;
|
||||
const Preset *parent = get_preset_parent(preset);
|
||||
if (parent == nullptr || !parent->is_system)
|
||||
return nullptr;
|
||||
// A user preset that sets its own compatible_printers keeps exactly those.
|
||||
const auto *own = preset.config.option<ConfigOptionStrings>("compatible_printers");
|
||||
const auto *inherited = parent->config.option<ConfigOptionStrings>("compatible_printers");
|
||||
return own != nullptr && inherited != nullptr && own->values == inherited->values ? parent : nullptr;
|
||||
}
|
||||
|
||||
void PresetCollection::set_legacy_compatible_printers(const std::map<std::string, std::vector<std::string>> &printers_by_parent)
|
||||
{
|
||||
lock();
|
||||
for (Preset &preset : m_presets) {
|
||||
preset.legacy_compatible_printers.clear();
|
||||
const Preset *parent = system_parent_with_inherited_printers(preset);
|
||||
if (parent == nullptr)
|
||||
continue;
|
||||
// The map names the parent as it was when the map was written; a later rename keeps that name in renamed_from.
|
||||
auto it = printers_by_parent.find(parent->name);
|
||||
for (auto old_name = parent->renamed_from.begin(); it == printers_by_parent.end() && old_name != parent->renamed_from.end(); ++old_name)
|
||||
it = printers_by_parent.find(*old_name);
|
||||
if (it == printers_by_parent.end())
|
||||
continue;
|
||||
preset.legacy_compatible_printers = it->second;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": user preset " << preset.name << " keeps " << it->second.size()
|
||||
<< " printer(s) its parent " << parent->name << " listed in an older release";
|
||||
}
|
||||
if (m_idx_selected < m_presets.size() && m_edited_preset.name == m_presets[m_idx_selected].name)
|
||||
m_edited_preset.legacy_compatible_printers = m_presets[m_idx_selected].legacy_compatible_printers;
|
||||
unlock();
|
||||
}
|
||||
|
||||
//BBS: validate_preset
|
||||
bool PresetCollection::validate_preset(const std::string &preset_name, std::string &inherit_name)
|
||||
{
|
||||
@@ -3081,6 +3121,7 @@ bool PresetCollection::clone_presets(std::vector<Preset const *> const &presets,
|
||||
preset.vendor = nullptr;
|
||||
preset.renamed_from.clear();
|
||||
preset.m_excluded_from.clear();
|
||||
preset.legacy_compatible_printers.clear();
|
||||
preset.setting_id.clear();
|
||||
preset.inherits().clear();
|
||||
preset.is_default = false;
|
||||
@@ -3218,6 +3259,9 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
|
||||
preset.m_excluded_from.clear();
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": save preset %1% , with detach")%new_name;
|
||||
}
|
||||
// Legacy printers belong only to a preset that still inherits its system parent's printer list.
|
||||
if (system_parent_with_inherited_printers(preset) == nullptr)
|
||||
preset.legacy_compatible_printers.clear();
|
||||
//BBS: add lock logic for sync preset in background
|
||||
|
||||
if (m_type == Preset::TYPE_PRINT)
|
||||
@@ -3270,6 +3314,8 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
|
||||
}
|
||||
else
|
||||
preset.is_project_embedded = false;
|
||||
if (system_parent_with_inherited_printers(preset) == nullptr)
|
||||
preset.legacy_compatible_printers.clear();
|
||||
if (m_type == Preset::TYPE_PRINT)
|
||||
preset.config.option<ConfigOptionString>("print_settings_id", true)->value = new_name;
|
||||
else if (m_type == Preset::TYPE_FILAMENT)
|
||||
|
||||
@@ -311,6 +311,10 @@ public:
|
||||
// certain printer models defined in the vendor profile as well, in this case we want to hide this generic preset for these printer models.
|
||||
std::set<std::string> m_excluded_from;
|
||||
|
||||
// Printers a user filament preset is also compatible with because its system parent listed them in
|
||||
// an older release; see PresetCollection::set_legacy_compatible_printers().
|
||||
std::vector<std::string> legacy_compatible_printers;
|
||||
|
||||
// Orca: flag to indicate if this preset is from Orca Filament Library
|
||||
bool m_from_orca_filament_lib = false;
|
||||
|
||||
@@ -601,6 +605,11 @@ public:
|
||||
void save_user_presets(const std::string& dir_path, const std::string& type, std::map<std::string, std::string>& need_to_delete_list);
|
||||
bool load_user_preset(std::string name, std::map<std::string, std::string> preset_values, PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule rule, const PresetOrigin &load_origin = PresetOrigin(PresetOrigin::Kind::User));
|
||||
void update_after_user_presets_loaded();
|
||||
// User presets store only their diff, so a user preset inherits its system parent's compatible_printers
|
||||
// and disappears from a printer once a profile update narrows that list. Give each user preset that
|
||||
// inherits the list the printers its parent covered in an older release (printers_by_parent, keyed by the
|
||||
// parent's current name), so it keeps showing on the printers it was made for.
|
||||
void set_legacy_compatible_printers(const std::map<std::string, std::vector<std::string>> &printers_by_parent);
|
||||
//BBS: get user presets
|
||||
int get_user_presets(PresetBundle *preset_bundle, std::vector<Preset> &result_presets);
|
||||
void set_sync_info_and_save(std::string name, std::string setting_id, std::string syncinfo, long long update_time, const std::string& user_id);
|
||||
@@ -893,6 +902,10 @@ public:
|
||||
size_t num_default_presets() { return m_num_default_presets; }
|
||||
|
||||
protected:
|
||||
// The system parent of a user preset whose compatible_printers is the parent's, or nullptr: the presets
|
||||
// set_legacy_compatible_printers() gives legacy printers to.
|
||||
const Preset* system_parent_with_inherited_printers(const Preset &preset) const;
|
||||
|
||||
PresetCollection() = default;
|
||||
// Deleted by the std::recursive_mutex member. PresetBundle copies by assignment.
|
||||
PresetCollection(const PresetCollection &other) = delete;
|
||||
|
||||
@@ -18,17 +18,20 @@
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <ios>
|
||||
#include <optional>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <iterator>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
|
||||
#include "PresetBundle.hpp"
|
||||
#include "PrinterBedAssets.hpp"
|
||||
|
||||
#include "Config.hpp"
|
||||
#include "Exception.hpp"
|
||||
@@ -64,6 +67,7 @@
|
||||
#include <boost/algorithm/clamp.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
@@ -93,6 +97,34 @@ using json = nlohmann::json;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Per current system filament preset, the printers it listed in an older release and no longer does
|
||||
// (resources/info/legacy_compatible_printers.json, written by orca_profile_tool.py legacy-compat).
|
||||
// The file ships with the build, so it is read once it opens; until then (e.g. presets loaded before
|
||||
// resources_dir() is set) every call tries again and there are no legacy printers.
|
||||
static std::map<std::string, std::vector<std::string>> legacy_compatible_printers()
|
||||
{
|
||||
static std::mutex mutex;
|
||||
static std::map<std::string, std::vector<std::string>> printers_by_parent;
|
||||
static bool read = false;
|
||||
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
if (!read) {
|
||||
const fs::path path = fs::path(resources_dir()) / "info" / "legacy_compatible_printers.json";
|
||||
boost::nowide::ifstream in(path.string());
|
||||
if (!in) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": " << path.string() << " not found";
|
||||
return {};
|
||||
}
|
||||
read = true;
|
||||
try {
|
||||
printers_by_parent = json::parse(in).at("presets").get<std::map<std::string, std::vector<std::string>>>();
|
||||
} catch (const std::exception &err) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": can not read " << path.string() << ": " << err.what();
|
||||
}
|
||||
}
|
||||
return printers_by_parent;
|
||||
}
|
||||
|
||||
// Project-level options imported from a loaded 3MF into project_config. s_project_options_published
|
||||
// below is the reduced subset that crosses over in "published" 3MF mode; keep both in sync.
|
||||
// s_project_options_published additionally carries wipe_tower_rotation_angle, which normal
|
||||
@@ -886,6 +918,7 @@ PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, Forward
|
||||
// raw vendor-JSON references instead of the silently-repaired ones.
|
||||
if (!validation_mode)
|
||||
this->normalize_compatible_presets();
|
||||
filaments.set_legacy_compatible_printers(legacy_compatible_printers());
|
||||
|
||||
this->update_multi_material_filament_presets();
|
||||
this->update_compatible(PresetSelectCompatibleType::Never);
|
||||
@@ -1514,6 +1547,7 @@ PresetsConfigSubstitutions PresetBundle::load_user_presets(AppConfig &
|
||||
|
||||
// Rewrite renamed compatible references in synced user presets before compatibility is evaluated.
|
||||
this->normalize_compatible_presets();
|
||||
filaments.set_legacy_compatible_printers(legacy_compatible_printers());
|
||||
|
||||
this->update_multi_material_filament_presets();
|
||||
this->update_compatible(PresetSelectCompatibleType::Never);
|
||||
@@ -1678,6 +1712,258 @@ bool PresetBundle::apply_vendor_config(
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// The two bed files a printer bundle can carry. Zip names are bed/<n>/<stem><ext>, never the source basename.
|
||||
struct BedAssetSlot {
|
||||
const char *option;
|
||||
const char *stem;
|
||||
};
|
||||
|
||||
constexpr BedAssetSlot k_bed_asset_slots[] = {
|
||||
{"bed_custom_texture", "texture"},
|
||||
{"bed_custom_model", "model"},
|
||||
};
|
||||
|
||||
std::string zip_slashes(std::string name)
|
||||
{
|
||||
for (char &c : name)
|
||||
if (c == '\\')
|
||||
c = '/';
|
||||
return name;
|
||||
}
|
||||
|
||||
// The bed dialog loads only png/svg textures and stl models. Anything else is not a bed asset.
|
||||
bool bed_extension_allowed(const char *option, const std::string &ext)
|
||||
{
|
||||
if (std::string(option) == "bed_custom_texture")
|
||||
return boost::iequals(ext, ".png") || boost::iequals(ext, ".svg");
|
||||
if (std::string(option) == "bed_custom_model")
|
||||
return boost::iequals(ext, ".stl");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extension including the dot, or empty when this option may not use it.
|
||||
std::string bed_asset_extension(const std::string &path, const char *option)
|
||||
{
|
||||
const auto slash = path.find_last_of("/\\");
|
||||
const auto base = slash == std::string::npos ? 0 : slash + 1;
|
||||
const auto dot = path.find_last_of('.');
|
||||
if (dot == std::string::npos || dot < base || dot + 1 >= path.size())
|
||||
return {};
|
||||
const std::string ext = path.substr(dot);
|
||||
if (!bed_extension_allowed(option, ext))
|
||||
return {};
|
||||
return ext;
|
||||
}
|
||||
|
||||
bool utf8_is_file(const std::string &path)
|
||||
{
|
||||
if (path.empty())
|
||||
return false;
|
||||
boost::system::error_code ec;
|
||||
#ifdef _WIN32
|
||||
// A narrow path is the ANSI code page unless nowide_filesystem() has run.
|
||||
const std::wstring wide = boost::nowide::widen(path);
|
||||
if (wide.empty())
|
||||
return false;
|
||||
return boost::filesystem::is_regular_file(boost::filesystem::path(wide), ec) && !ec;
|
||||
#else
|
||||
return boost::filesystem::is_regular_file(path, ec) && !ec;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string bed_asset_dest_utf8(const fs::path &dest)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return boost::nowide::narrow(dest.wstring());
|
||||
#else
|
||||
return dest.string();
|
||||
#endif
|
||||
}
|
||||
|
||||
// True only for bed/<digits>/<stem><ext> with an extension the bed dialog accepts for this field.
|
||||
bool accepted_bed_zip_name(const std::string &raw, const BedAssetSlot &slot, const fs::path &bundle_dir,
|
||||
std::string &zip_name, std::string &folder)
|
||||
{
|
||||
const std::string name = zip_slashes(raw);
|
||||
if (name.find("..") != std::string::npos)
|
||||
return false;
|
||||
if (name.size() < 8 || name.compare(0, 4, "bed/") != 0)
|
||||
return false;
|
||||
const auto slash = name.find('/', 4);
|
||||
if (slash == std::string::npos || slash == 4 || name.find('/', slash + 1) != std::string::npos)
|
||||
return false;
|
||||
const std::string digits = name.substr(4, slash - 4);
|
||||
for (unsigned char c : digits) {
|
||||
if (!std::isdigit(c))
|
||||
return false;
|
||||
}
|
||||
const std::string filename = name.substr(slash + 1);
|
||||
const std::string ext = bed_asset_extension(filename, slot.option);
|
||||
if (ext.empty() || filename != std::string(slot.stem) + ext)
|
||||
return false;
|
||||
if (!is_path_within_root(name, bundle_dir))
|
||||
return false;
|
||||
zip_name = name;
|
||||
folder = digits;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct PendingBedAsset {
|
||||
std::string option;
|
||||
std::string zip_name;
|
||||
std::string dest;
|
||||
std::string printer_key;
|
||||
fs::path final_path;
|
||||
fs::path staged;
|
||||
};
|
||||
|
||||
// Validated asset names only. A raw manifest value that fails the check is not skipped later,
|
||||
// so a value like printer/Name.json cannot hide that preset.
|
||||
// printer_asset is keyed by printer_config zip entry. A flat (unkeyed) object is not read.
|
||||
std::vector<PendingBedAsset> pending_bed_assets(const json &bundle_json, const fs::path &bundle_dir,
|
||||
std::unordered_set<std::string> &skip_names,
|
||||
const std::unordered_set<std::string> &zip_entries)
|
||||
{
|
||||
std::vector<PendingBedAsset> pending;
|
||||
if (!bundle_json.contains("printer_asset") || !bundle_json["printer_asset"].is_object())
|
||||
return pending;
|
||||
const json &assets = bundle_json["printer_asset"];
|
||||
for (auto it = assets.begin(); it != assets.end(); ++it) {
|
||||
const std::string printer_key = it.key();
|
||||
if (zip_entries.count(printer_key) == 0) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Printer bundle asset entry is ignored, no matching printer in the zip: " << printer_key;
|
||||
continue;
|
||||
}
|
||||
if (!it.value().is_object())
|
||||
continue;
|
||||
const json &per_printer = it.value();
|
||||
for (const BedAssetSlot &slot : k_bed_asset_slots) {
|
||||
if (!per_printer.contains(slot.option) || !per_printer[slot.option].is_string())
|
||||
continue;
|
||||
const std::string raw = per_printer[slot.option].get<std::string>();
|
||||
std::string zip_name;
|
||||
std::string folder;
|
||||
if (!accepted_bed_zip_name(raw, slot, bundle_dir, zip_name, folder)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Printer bundle asset path is rejected: " << raw;
|
||||
continue;
|
||||
}
|
||||
const std::string filename = zip_name.substr(zip_name.rfind('/') + 1);
|
||||
const fs::path final_path = fs::absolute(bundle_dir / "bed" / folder / filename);
|
||||
pending.push_back({slot.option, zip_name, bed_asset_dest_utf8(final_path), printer_key, final_path, {}});
|
||||
skip_names.insert(zip_name);
|
||||
}
|
||||
}
|
||||
return pending;
|
||||
}
|
||||
|
||||
// Stage under temp_folder. The bundle bed/ directory is not touched until a printer preset keeps the path.
|
||||
bool stage_bed_asset(mz_zip_archive &zip, PendingBedAsset &asset, const fs::path &temp_folder)
|
||||
{
|
||||
size_t size = 0;
|
||||
void *buf = mz_zip_reader_extract_file_to_heap(&zip, asset.zip_name.c_str(), &size, MZ_ZIP_FLAG_CASE_SENSITIVE);
|
||||
if (buf == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Printer bundle asset is missing, skipping " << asset.option << ": " << asset.zip_name;
|
||||
return false;
|
||||
}
|
||||
const std::string filename = asset.zip_name.substr(asset.zip_name.rfind('/') + 1);
|
||||
asset.staged = temp_folder / "bed" / asset.final_path.parent_path().filename() / filename;
|
||||
boost::system::error_code ec;
|
||||
fs::create_directories(asset.staged.parent_path(), ec);
|
||||
const std::string staged_utf8 = bed_asset_dest_utf8(asset.staged);
|
||||
bool wrote = false;
|
||||
if (!ec) {
|
||||
boost::nowide::ofstream out(staged_utf8, std::ios::binary | std::ios::trunc);
|
||||
wrote = static_cast<bool>(out);
|
||||
if (wrote && size > 0)
|
||||
wrote = static_cast<bool>(out.write(static_cast<const char *>(buf), static_cast<std::streamsize>(size)));
|
||||
}
|
||||
mz_free(buf);
|
||||
if (!wrote) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Printer bundle asset could not be written, skipping " << asset.option << ": " << staged_utf8;
|
||||
fs::remove(asset.staged, ec);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool install_bed_asset(const PendingBedAsset &asset)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
fs::create_directories(asset.final_path.parent_path(), ec);
|
||||
if (!ec)
|
||||
fs::copy_file(asset.staged, asset.final_path, fs::copy_options::overwrite_existing, ec);
|
||||
if (ec) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Printer bundle asset could not be installed: " << asset.dest;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_pending_bed_asset_entry(const std::string &entry, const std::unordered_set<std::string> &names)
|
||||
{
|
||||
return names.count(entry) != 0 || names.count(zip_slashes(entry)) != 0;
|
||||
}
|
||||
|
||||
bool printer_kept_bed_paths(const PresetCollection &printers, const std::map<std::string, std::string> &paths)
|
||||
{
|
||||
if (paths.empty())
|
||||
return false;
|
||||
for (const Preset &preset : printers.get_presets()) {
|
||||
for (const auto &entry : paths)
|
||||
if (preset.config.opt_string(entry.first) == entry.second)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool append_printer_bed_assets(mz_zip_archive &zip, const DynamicPrintConfig &config, json &bundle_structure,
|
||||
const std::string &printer_config_entry, int printer_index)
|
||||
{
|
||||
if (printer_config_entry.empty() || printer_index < 0)
|
||||
return true;
|
||||
json assets = json::object();
|
||||
for (const BedAssetSlot &slot : k_bed_asset_slots) {
|
||||
if (!config.has(slot.option))
|
||||
continue;
|
||||
const std::string stored = config.opt_string(slot.option);
|
||||
if (stored.empty())
|
||||
continue;
|
||||
if (!utf8_is_file(stored)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Bed asset file is missing, skipping " << slot.option << ": " << stored;
|
||||
continue;
|
||||
}
|
||||
const std::string ext = bed_asset_extension(stored, slot.option);
|
||||
if (ext.empty()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Bed asset extension is not packable, skipping " << slot.option << ": " << stored;
|
||||
continue;
|
||||
}
|
||||
boost::nowide::ifstream in(stored, std::ios::binary);
|
||||
if (!in) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Bed asset file cannot be read, skipping " << slot.option << ": " << stored;
|
||||
continue;
|
||||
}
|
||||
const std::string bytes((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
|
||||
if (in.bad()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Bed asset file cannot be read, skipping " << slot.option << ": " << stored;
|
||||
continue;
|
||||
}
|
||||
const std::string zip_name = std::string("bed/") + std::to_string(printer_index) + "/" + slot.stem + ext;
|
||||
const void *data = bytes.empty() ? static_cast<const void *>("") : static_cast<const void *>(bytes.data());
|
||||
if (mz_zip_writer_add_mem(&zip, zip_name.c_str(), data, bytes.size(), MZ_DEFAULT_COMPRESSION) == MZ_FALSE) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to add bed asset to printer bundle: " << zip_name;
|
||||
return false;
|
||||
}
|
||||
assets[slot.option] = zip_name;
|
||||
}
|
||||
if (!assets.empty())
|
||||
bundle_structure["printer_asset"][printer_config_entry] = std::move(assets);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Import presets from UI control
|
||||
PresetsConfigSubstitutions PresetBundle::import_presets(std::vector<std::string> & files,
|
||||
std::function<int(std::string const &)> override_confirm,
|
||||
@@ -1773,14 +2059,44 @@ PresetsConfigSubstitutions PresetBundle::import_presets(std::vector<std::string>
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " No bundle_structure.json found, importing presets into the user preset directory";
|
||||
}
|
||||
|
||||
json bundle_json = json::object();
|
||||
std::unordered_set<std::string> bed_asset_entries;
|
||||
std::vector<PendingBedAsset> bed_assets;
|
||||
std::map<std::string, std::map<std::string, std::string>> bed_paths_by_printer;
|
||||
bool bed_paths_loaded = false;
|
||||
if (has_bundle_structure && !bundle_base_dir.empty()) {
|
||||
try {
|
||||
boost::nowide::ifstream manifest_in(metadata_path.string());
|
||||
manifest_in >> bundle_json;
|
||||
} catch (const std::exception &err) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " failed to read bundle manifest: " << err.what();
|
||||
bundle_json = json::object();
|
||||
}
|
||||
std::unordered_set<std::string> zip_entries;
|
||||
const int zip_file_count = mz_zip_reader_get_num_files(&zip_archive);
|
||||
for (int zi = 0; zi < zip_file_count; ++zi) {
|
||||
mz_zip_archive_file_stat st;
|
||||
if (mz_zip_reader_file_stat(&zip_archive, zi, &st))
|
||||
zip_entries.insert(zip_slashes(st.m_filename));
|
||||
}
|
||||
bed_assets = pending_bed_assets(bundle_json, bundle_base_dir, bed_asset_entries, zip_entries);
|
||||
for (PendingBedAsset &asset : bed_assets)
|
||||
if (stage_bed_asset(zip_archive, asset, temp_folder))
|
||||
bed_paths_by_printer[asset.printer_key].emplace(asset.option, asset.dest);
|
||||
}
|
||||
|
||||
// Extract Files
|
||||
int num_files = mz_zip_reader_get_num_files(&zip_archive);
|
||||
const std::map<std::string, std::string> no_bed_paths;
|
||||
for (int i = 0; i < num_files; i++) {
|
||||
mz_zip_archive_file_stat file_stat;
|
||||
status = mz_zip_reader_file_stat(&zip_archive, i, &file_stat);
|
||||
if (status) {
|
||||
std::string file_name = file_stat.m_filename;
|
||||
const std::string zip_entry = zip_slashes(file_name);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " From zip file: " << file << ". Read file name: " << file_stat.m_filename;
|
||||
if (is_pending_bed_asset_entry(file_name, bed_asset_entries))
|
||||
continue;
|
||||
size_t index = file_name.find_last_of("/\\");
|
||||
if (std::string::npos != index) {
|
||||
file_name = file_name.substr(index + 1);
|
||||
@@ -1798,13 +2114,26 @@ PresetsConfigSubstitutions PresetBundle::import_presets(std::vector<std::string>
|
||||
if (MZ_FALSE == status) {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Failed to open target file: " << target_file_path;
|
||||
} else {
|
||||
const auto paths_it = bed_paths_by_printer.find(zip_entry);
|
||||
const std::map<std::string, std::string> &this_bed_paths =
|
||||
paths_it != bed_paths_by_printer.end() ? paths_it->second : no_bed_paths;
|
||||
bool is_success = import_json_presets(substitutions, target_file_path, override_confirm, rule, overwrite, result,
|
||||
has_bundle_structure ? bundle_base_dir.string() : std::string());
|
||||
has_bundle_structure ? bundle_base_dir.string() : std::string(),
|
||||
this_bed_paths, &bed_paths_loaded);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " import target file: " << target_file_path << " import result" << is_success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy into bed/ only after this import loads a printer that still holds the staged path.
|
||||
// A preset left from an earlier import must not count: declining this import leaves its files alone.
|
||||
if (bed_paths_loaded) {
|
||||
for (const PendingBedAsset &asset : bed_assets) {
|
||||
if (printer_kept_bed_paths(printers, {{asset.option, asset.dest}}))
|
||||
install_bed_asset(asset);
|
||||
}
|
||||
}
|
||||
|
||||
// Set imported_time to current time if not already set
|
||||
if (metadata.imported_time == 0) {
|
||||
metadata.imported_time = std::time(nullptr);
|
||||
@@ -1846,7 +2175,9 @@ bool PresetBundle::import_json_presets(PresetsConfigSubstitutions & s
|
||||
ForwardCompatibilitySubstitutionRule rule,
|
||||
int & overwrite,
|
||||
std::vector<std::string> & result,
|
||||
const std::string & bundle_dir)
|
||||
const std::string & bundle_dir,
|
||||
const std::map<std::string, std::string> & bed_asset_paths,
|
||||
bool * bed_paths_loaded)
|
||||
{
|
||||
try {
|
||||
DynamicPrintConfig config;
|
||||
@@ -1910,6 +2241,10 @@ bool PresetBundle::import_json_presets(PresetsConfigSubstitutions & s
|
||||
if (inherit_preset)
|
||||
inherits_value = inherit_preset->name; // keep the base_id redo below in sync
|
||||
}
|
||||
if (collection == &printers) {
|
||||
for (const auto &entry : bed_asset_paths)
|
||||
config.option<ConfigOptionString>(entry.first, true)->value = entry.second;
|
||||
}
|
||||
if (inherit_preset) {
|
||||
new_config = inherit_preset->config;
|
||||
new_config.apply(std::move(config));
|
||||
@@ -1927,6 +2262,8 @@ bool PresetBundle::import_json_presets(PresetsConfigSubstitutions & s
|
||||
new_config.apply(std::move(config));
|
||||
extend_default_config_length(new_config, true, default_preset.config);
|
||||
}
|
||||
if (bed_paths_loaded != nullptr && collection == &printers && !bed_asset_paths.empty())
|
||||
*bed_paths_loaded = true;
|
||||
|
||||
Preset &preset = collection->load_preset(collection->path_from_name(name, inherit_preset == nullptr), preset_name, std::move(new_config), false);
|
||||
preset.bundle_id = load_origin.bundle_id;
|
||||
@@ -2217,6 +2554,7 @@ PresetsConfigSubstitutions PresetBundle::update_subscribed_presets(
|
||||
|
||||
// Rewrite renamed compatible references in synced user presets before compatibility is evaluated.
|
||||
this->normalize_compatible_presets();
|
||||
filaments.set_legacy_compatible_printers(legacy_compatible_printers());
|
||||
|
||||
this->update_multi_material_filament_presets();
|
||||
this->update_compatible(PresetSelectCompatibleType::Never);
|
||||
|
||||
@@ -319,7 +319,9 @@ public:
|
||||
ForwardCompatibilitySubstitutionRule rule,
|
||||
int& overwrite,
|
||||
std::vector<std::string>& result,
|
||||
const std::string& bundle_dir = "");
|
||||
const std::string& bundle_dir = "",
|
||||
const std::map<std::string, std::string> &bed_asset_paths = {},
|
||||
bool *bed_paths_loaded = nullptr);
|
||||
|
||||
void save_user_presets(AppConfig& config, std::map<std::string, std::string>& need_to_delete_list);
|
||||
void check_and_fix_user_presets_syncinfo(const std::string& user_id);
|
||||
|
||||
@@ -1148,6 +1148,8 @@ void PrintConfigDef::init_common_params()
|
||||
|
||||
def = this->add("print_host", coString);
|
||||
def->label = L("Hostname, IP or URL");
|
||||
// The URL is an example of the format to type, not a link, so it stays in the text.
|
||||
// xgettext:no-url-check
|
||||
def->tooltip = L("Orca Slicer can upload G-code files to a printer host. This field should contain "
|
||||
"the hostname, IP address or URL of the printer host instance. "
|
||||
"Print host behind HAProxy with basic auth enabled can be accessed by putting the user name and password into the URL "
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "miniz_extension.hpp"
|
||||
|
||||
#include <miniz.h>
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class DynamicPrintConfig;
|
||||
|
||||
// Not on PresetBundle.hpp: miniz.h's zlib-compat macros rename GUI methods (GLTexture::Compressor::compress).
|
||||
// printer_config_entry is the zip name also pushed onto bundle_structure["printer_config"].
|
||||
// printer_index is that entry's 0-based index in the exported printer_config list.
|
||||
bool append_printer_bed_assets(mz_zip_archive &zip, const DynamicPrintConfig &config, nlohmann::json &bundle_structure,
|
||||
const std::string &printer_config_entry, int printer_index);
|
||||
|
||||
} // namespace Slic3r
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
// paper: https://people.eecs.berkeley.edu/~jrs/meshpapers/GarlandHeckbert2.pdf
|
||||
// sum up: https://users.csc.calpoly.edu/~zwood/teaching/csc570/final06/jseeba/
|
||||
// inspiration: https://github.com/sp4cerat/Fast-Quadric-Mesh-Simplification
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <wx/valtext.h>
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/PrinterBedAssets.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
@@ -3674,9 +3675,20 @@ ExportConfigsDialog::~ExportConfigsDialog()
|
||||
}
|
||||
|
||||
void ExportConfigsDialog::on_dpi_changed(const wxRect &suggested_rect) {
|
||||
if (m_include_bed_assets)
|
||||
m_include_bed_assets->Rescale();
|
||||
Layout();
|
||||
}
|
||||
|
||||
void ExportConfigsDialog::update_include_bed_assets_enabled()
|
||||
{
|
||||
const bool on = get_curr_radio_type(m_export_type_btns) == m_exprot_type.preset_bundle;
|
||||
if (m_include_bed_assets)
|
||||
m_include_bed_assets->Enable(on);
|
||||
if (m_include_bed_assets_label)
|
||||
m_include_bed_assets_label->Enable(on);
|
||||
}
|
||||
|
||||
void ExportConfigsDialog::show_export_result(const ExportCase &export_case)
|
||||
{
|
||||
MessageDialog *msg_dlg = nullptr;
|
||||
@@ -3819,6 +3831,17 @@ wxBoxSizer *ExportConfigsDialog::create_export_config_item(wxWindow *parent)
|
||||
static_export_printer_preset_bundle_text->SetFont(Label::Body_12);
|
||||
static_export_printer_preset_bundle_text->SetForegroundColour(wxColour("#6B6B6B"));
|
||||
radioBoxSizer->Add(static_export_printer_preset_bundle_text, 0, wxEXPAND | wxLEFT, FromDIP(22));
|
||||
wxBoxSizer *include_bed_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_include_bed_assets = new ::CheckBox(parent);
|
||||
m_include_bed_assets->SetValue(true);
|
||||
include_bed_sizer->Add(m_include_bed_assets, 0, wxALIGN_CENTER_VERTICAL, 0);
|
||||
m_include_bed_assets_label = new wxStaticText(parent, wxID_ANY, _L("Include custom bed texture and model"));
|
||||
m_include_bed_assets_label->SetFont(Label::Body_12);
|
||||
m_include_bed_assets_label->SetForegroundColour(wxColour("#6B6B6B"));
|
||||
include_bed_sizer->Add(m_include_bed_assets_label, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(5));
|
||||
radioBoxSizer->Add(0, 0, 0, wxTOP, FromDIP(6));
|
||||
radioBoxSizer->Add(include_bed_sizer, 0, wxEXPAND | wxLEFT, FromDIP(22));
|
||||
update_include_bed_assets_enabled();
|
||||
radioBoxSizer->Add(create_radio_item(m_exprot_type.filament_bundle, parent, wxEmptyString, m_export_type_btns), 0, wxEXPAND | wxTOP, FromDIP(10));
|
||||
wxStaticText *static_export_filament_preset_bundle_text = new wxStaticText(parent, wxID_ANY, _L("User's filament preset set.\nCan be shared with others."),
|
||||
wxDefaultPosition, wxDefaultSize);
|
||||
@@ -3988,9 +4011,10 @@ void ExportConfigsDialog::select_curr_radiobox(std::vector<std::pair<RadioBox *,
|
||||
radiobox_list[i].first->SetValue(false);
|
||||
}
|
||||
}
|
||||
update_include_bed_assets_enabled();
|
||||
}
|
||||
|
||||
ExportConfigsDialog::ExportCase ExportConfigsDialog::archive_preset_bundle_to_file(const wxString &path)
|
||||
ExportConfigsDialog::ExportCase ExportConfigsDialog::archive_preset_bundle_to_file(const wxString &path, bool include_bed_assets)
|
||||
{
|
||||
std::string export_path = initial_file_path(path, "");
|
||||
if (export_path.empty() || "initial_failed" == export_path) return ExportCase::EXPORT_CANCEL;
|
||||
@@ -4092,6 +4116,12 @@ ExportConfigsDialog::ExportCase ExportConfigsDialog::archive_preset_bundle_to_fi
|
||||
bundle_structure["filament_config"] = filament_configs;
|
||||
bundle_structure["process_config"] = process_configs;
|
||||
|
||||
if (include_bed_assets &&
|
||||
!append_printer_bed_assets(zip_archive, printer_preset->config, bundle_structure, printer_config_file_name, 0)) {
|
||||
mz_zip_writer_end(&zip_archive);
|
||||
return ExportCase::ADD_FILE_FAIL;
|
||||
}
|
||||
|
||||
std::string bundle_structure_str = bundle_structure.dump();
|
||||
status = mz_zip_writer_add_mem(&zip_archive, BUNDLE_STRUCTURE_JSON_NAME, bundle_structure_str.data(), bundle_structure_str.size(), MZ_DEFAULT_COMPRESSION);
|
||||
if (MZ_FALSE == status) {
|
||||
@@ -4339,7 +4369,7 @@ wxWindow *ExportConfigsDialog::create_dialog_buttons(wxWindow* parent)
|
||||
const wxString curr_radio_type = get_curr_radio_type(m_export_type_btns);
|
||||
|
||||
if (curr_radio_type == m_exprot_type.preset_bundle) {
|
||||
export_case = archive_preset_bundle_to_file(path);
|
||||
export_case = archive_preset_bundle_to_file(path, m_include_bed_assets->GetValue());
|
||||
} else if (curr_radio_type == m_exprot_type.filament_bundle) {
|
||||
export_case = archive_filament_bundle_to_file(path);
|
||||
} else if (curr_radio_type == m_exprot_type.printer_preset) {
|
||||
|
||||
@@ -271,6 +271,7 @@ protected:
|
||||
private:
|
||||
void data_init();
|
||||
void select_curr_radiobox(std::vector<std::pair<RadioBox *, wxString>> &radiobox_list, int btn_idx);
|
||||
void update_include_bed_assets_enabled();
|
||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
void show_export_result(const ExportCase &export_case);
|
||||
bool has_check_box_selected();
|
||||
@@ -284,7 +285,7 @@ private:
|
||||
int initial_zip_archive(mz_zip_archive &zip_archive, const std::string &file_path);
|
||||
ExportCase save_zip_archive_to_file(mz_zip_archive &zip_archive);
|
||||
ExportCase save_presets_to_zip(const std::string &export_file, const std::vector<std::pair<std::string, std::string>> &config_paths);
|
||||
ExportCase archive_preset_bundle_to_file(const wxString &path);
|
||||
ExportCase archive_preset_bundle_to_file(const wxString &path, bool include_bed_assets);
|
||||
ExportCase archive_filament_bundle_to_file(const wxString &path);
|
||||
ExportCase archive_printer_preset_to_file(const wxString &path);
|
||||
ExportCase archive_filament_preset_to_file(const wxString &path);
|
||||
@@ -304,6 +305,8 @@ private:
|
||||
wxGridSizer * m_preset_sizer = nullptr;
|
||||
wxPanel * m_presets_window = nullptr;
|
||||
wxStaticText * m_serial_text = nullptr;
|
||||
::CheckBox * m_include_bed_assets = nullptr;
|
||||
wxStaticText * m_include_bed_assets_label = nullptr;
|
||||
};
|
||||
|
||||
class CreatePresetForPrinterDialog : public DPIDialog
|
||||
|
||||
@@ -379,14 +379,24 @@ void FilamentGroupPopup::OnTimer(wxTimerEvent &event)
|
||||
// leaving event got triggered. So the timer is stopped first, then started
|
||||
// again, causing the popup being dismissed immediately.
|
||||
// To fix this, we check if cursor is still inside the popup window before
|
||||
// dismissing.
|
||||
// dismissing, and keep checking while it is: a leave event is not guaranteed
|
||||
// to follow, and a popup left open keeps grabbing the mouse capture.
|
||||
wxPoint pos = this->ScreenToClient(wxGetMousePosition());
|
||||
if (this->GetClientRect().Contains(pos)) return;
|
||||
if (this->GetClientRect().Contains(pos)) {
|
||||
StartTimer();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Dismiss();
|
||||
}
|
||||
|
||||
FilamentGroupPopup::~FilamentGroupPopup()
|
||||
{
|
||||
m_timer->Stop();
|
||||
delete m_timer;
|
||||
}
|
||||
|
||||
void FilamentGroupPopup::Dismiss() {
|
||||
m_active = false;
|
||||
PopupWindow::Dismiss();
|
||||
@@ -405,7 +415,10 @@ void FilamentGroupPopup::OnEnterWindow(wxMouseEvent &)
|
||||
// Ignore spurious ENTER synthesized by PopupWindow::OnMouseEvent2 on macOS.
|
||||
wxPoint pos = this->ScreenToClient(wxGetMousePosition());
|
||||
if (!this->GetClientRect().Contains(pos)) return;
|
||||
// On macOS the timer keeps running instead, and OnTimer closes the popup once the cursor has left it.
|
||||
#ifndef __APPLE__
|
||||
ResetTimer();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FilamentGroupPopup::UpdateButtonStatus(int hover_idx)
|
||||
|
||||
@@ -27,6 +27,7 @@ class FilamentGroupPopup : public PopupWindow
|
||||
{
|
||||
public:
|
||||
FilamentGroupPopup(wxWindow *parent);
|
||||
~FilamentGroupPopup() override;
|
||||
void tryPopup(Plater* plater,PartPlate* plate, bool slice_all);
|
||||
void tryClose();
|
||||
void Dismiss() override;
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/dialog.h>
|
||||
#include "slic3r/GUI/FilamentMapPanel.hpp"
|
||||
#include "slic3r/GUI/FilamentGroupPopup.hpp"
|
||||
#include "slic3r/GUI/MainFrame.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
@@ -377,6 +379,13 @@ FilamentMapMode FilamentMapDialog::get_mode()
|
||||
|
||||
int FilamentMapDialog::ShowModal()
|
||||
{
|
||||
// The Slice-plate hover popup is a transient popup that keeps grabbing the mouse
|
||||
// capture while shown. Left behind this modal dialog it would starve the dialog of
|
||||
// mouse events, so close it synchronously first, whichever path opened the dialog.
|
||||
if (MainFrame* frame = wxGetApp().mainframe;
|
||||
frame && frame->m_filament_group_popup && frame->m_filament_group_popup->IsShown())
|
||||
frame->m_filament_group_popup->Dismiss();
|
||||
|
||||
update_panel_status(m_page_type);
|
||||
return wxDialog::ShowModal();
|
||||
}
|
||||
|
||||
@@ -2654,9 +2654,10 @@ void GUI_App::init_webview_runtime()
|
||||
BOOST_LOG_TRIVIAL(info) << "WebView2 runtime installed successfully.";
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(error) << "WebView2 runtime installation failed or still not detected.";
|
||||
wxMessageBox(_L("The Microsoft WebView2 Runtime could not be installed.\n"
|
||||
"Some features, including the setup wizard, may appear blank until it is installed.\n"
|
||||
"Please install it manually from https://developer.microsoft.com/microsoft-edge/webview2/ and restart Orca Slicer."),
|
||||
wxMessageBox(format_wxstr(_L("The Microsoft WebView2 Runtime could not be installed.\n"
|
||||
"Some features, including the setup wizard, may appear blank until it is installed.\n"
|
||||
"Please install it manually from %1% and restart Orca Slicer."),
|
||||
"https://developer.microsoft.com/microsoft-edge/webview2/"),
|
||||
_L("WebView2 Runtime"), wxOK | wxICON_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface OtherInstanceMessageHandlerMac : NSObject
|
||||
|
||||
@@ -2309,12 +2309,6 @@ wxBoxSizer* MainFrame::create_side_tools()
|
||||
|
||||
bool slice = true;
|
||||
|
||||
// The Slice-plate hover popup is a transient popup that keeps grabbing
|
||||
// the mouse capture while shown. Left behind the modal grouping dialog it
|
||||
// would starve that dialog of mouse events, so close it synchronously first.
|
||||
if (m_filament_group_popup)
|
||||
m_filament_group_popup->Dismiss();
|
||||
|
||||
auto curr_plate = m_plater->get_partplate_list().get_curr_plate();
|
||||
#ifdef __linux__
|
||||
PresetBundle* preset = wxGetApp().preset_bundle;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "slic3r/GUI/wxExtensions.hpp"
|
||||
#include <map>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -12820,8 +12820,8 @@ void Plater::priv::on_select_bed_type(wxCommandEvent &evt)
|
||||
|
||||
// update plater with new config
|
||||
q->on_config_change(wxGetApp().preset_bundle->full_config());
|
||||
if (auto *plate_tab = dynamic_cast<TabPrintPlate *>(wxGetApp().get_plate_tab()))
|
||||
plate_tab->update_model_config();
|
||||
// Rebuild the plate tab from the current selection; its cached plates may be gone after a reset.
|
||||
wxGetApp().obj_list()->update_and_show_object_settings_item();
|
||||
|
||||
// update app_config
|
||||
AppConfig* app_config = wxGetApp().app_config;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface RemovableDriveManagerMM : NSObject
|
||||
|
||||
@@ -5957,7 +5957,7 @@ if (is_marlin_flavor)
|
||||
{
|
||||
// In the configuration group rather than a group of its own: a full-width widget line
|
||||
// records no mode, so a group holding only this line would show in every mode.
|
||||
auto line = Line{ L("Modes"), L("") };
|
||||
auto line = Line{ L("Modes"), "" };
|
||||
line.full_width = 1;
|
||||
line.widget = [this](wxWindow* parent) -> wxSizer* {
|
||||
int n_cols = 0, n_rows = 0, layout = 0;
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/webview.h>
|
||||
|
||||
#ifdef __WXGTK__
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
WebDialog::WebDialog(wxWindow* parent,
|
||||
@@ -52,6 +56,17 @@ WebDialog::WebDialog(wxWindow* parent,
|
||||
Bind(wxEVT_CLOSE_WINDOW, &WebDialog::on_close_window, this);
|
||||
}
|
||||
|
||||
void WebDialog::use_normal_window_type()
|
||||
{
|
||||
#ifdef __WXGTK__
|
||||
// wxGTK types every wxDialog as a dialog, and Mutter offers no maximize for anything but a
|
||||
// normal window. Mutter also stops hiding a normal window from the taskbar, so keep it hidden
|
||||
// as a dialog with a parent is everywhere else.
|
||||
gtk_window_set_type_hint(GTK_WINDOW(m_widget), GDK_WINDOW_TYPE_HINT_NORMAL);
|
||||
gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget), TRUE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WebDialog::add_user_scripts()
|
||||
{
|
||||
if (wxWebView* wv = browser()) {
|
||||
|
||||
@@ -62,6 +62,10 @@ public:
|
||||
|
||||
bool is_open() const { return m_open; }
|
||||
|
||||
// Lets a modeless window be maximized on X11; call before Show(). Modal ones stay dialogs so the
|
||||
// window manager keeps routing focus from the parent to them.
|
||||
void use_normal_window_type();
|
||||
|
||||
// The payload submitted via window.orca.submit() (modal use), if any.
|
||||
const std::optional<nlohmann::json>& result() const { return m_result; }
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
BEGIN_EVENT_TABLE(SideButton, wxWindow)
|
||||
EVT_LEFT_DOWN(SideButton::mouseDown)
|
||||
EVT_LEFT_UP(SideButton::mouseReleased)
|
||||
EVT_MOUSE_CAPTURE_LOST(SideButton::mouseCaptureLost)
|
||||
EVT_PAINT(SideButton::paintEvent)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
@@ -331,20 +332,30 @@ void SideButton::mouseDown(wxMouseEvent& event)
|
||||
event.Skip();
|
||||
pressedDown = true;
|
||||
SetFocus();
|
||||
CaptureMouse();
|
||||
// Capturing twice pushes this button onto the capture stack twice, and the
|
||||
// release would then hand the capture straight back to it.
|
||||
if (!HasCapture())
|
||||
CaptureMouse();
|
||||
}
|
||||
|
||||
void SideButton::mouseReleased(wxMouseEvent& event)
|
||||
{
|
||||
event.Skip();
|
||||
// A press whose release went elsewhere still holds the capture.
|
||||
if (HasCapture())
|
||||
ReleaseMouse();
|
||||
if (pressedDown) {
|
||||
pressedDown = false;
|
||||
ReleaseMouse();
|
||||
if (wxRect({0, 0}, GetSize()).Contains(event.GetPosition()))
|
||||
sendButtonEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void SideButton::mouseCaptureLost(wxMouseCaptureLostEvent&)
|
||||
{
|
||||
pressedDown = false;
|
||||
}
|
||||
|
||||
void SideButton::sendButtonEvent()
|
||||
{
|
||||
wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
|
||||
|
||||
@@ -94,6 +94,7 @@ private:
|
||||
|
||||
void mouseDown(wxMouseEvent& event);
|
||||
void mouseReleased(wxMouseEvent& event);
|
||||
void mouseCaptureLost(wxMouseCaptureLostEvent& event);
|
||||
|
||||
void sendButtonEvent();
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/colour.h>
|
||||
|
||||
|
||||
@@ -197,6 +197,7 @@ bool CloudPluginService::download_cloud_plugin(PluginDescriptor& entry,
|
||||
Http http = Http::get(download_url);
|
||||
http.timeout_connect(30)
|
||||
.timeout_max(300)
|
||||
.tls_verify(true)
|
||||
.on_complete([&body, &http_status](std::string response_body, unsigned status) {
|
||||
body = std::move(response_body);
|
||||
http_status = status;
|
||||
|
||||
@@ -399,6 +399,7 @@ py::object ui_create_window(const std::string& html, const std::string& title, i
|
||||
if (UiRegistry::instance().is_open(new_id))
|
||||
dlg->Destroy();
|
||||
} else {
|
||||
dlg->use_normal_window_type();
|
||||
dlg->Show();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
|
||||
@@ -22,6 +24,7 @@
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/miniz_extension.hpp"
|
||||
#include "libslic3r/PrinterBedAssets.hpp"
|
||||
|
||||
#include "test_utils.hpp"
|
||||
|
||||
@@ -5853,6 +5856,609 @@ TEST_CASE("Config import confines zip entries, preset names and bundle ids to th
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
const std::string kTextureBytes("\x89PNG\x00tex", 8);
|
||||
const std::string kModelBytes("stl\x00model", 9);
|
||||
const std::string kOtherBytes("\x89PNG\x00other", 10);
|
||||
|
||||
void write_bytes(const std::string &utf8_path, const std::string &bytes)
|
||||
{
|
||||
const auto slash = utf8_path.find_last_of("/\\");
|
||||
if (slash != std::string::npos) {
|
||||
#ifdef _WIN32
|
||||
fs::create_directories(fs::path(boost::nowide::widen(utf8_path.substr(0, slash))));
|
||||
#else
|
||||
fs::create_directories(utf8_path.substr(0, slash));
|
||||
#endif
|
||||
}
|
||||
boost::nowide::ofstream out(utf8_path, std::ios::binary | std::ios::trunc);
|
||||
REQUIRE(out);
|
||||
out.write(bytes.data(), static_cast<std::streamsize>(bytes.size()));
|
||||
REQUIRE(out);
|
||||
}
|
||||
|
||||
fs::path write_printer_json(const DynamicPrintConfig &defaults, const fs::path &file, const std::string &name,
|
||||
const std::string &texture, const std::string &model, const std::string &inherits = {})
|
||||
{
|
||||
DynamicPrintConfig config(defaults);
|
||||
config.option<ConfigOptionString>("printer_settings_id", true)->value = name;
|
||||
config.option<ConfigOptionString>("inherits", true)->value = inherits;
|
||||
if (texture.empty())
|
||||
config.erase("bed_custom_texture");
|
||||
else
|
||||
config.option<ConfigOptionString>("bed_custom_texture", true)->value = texture;
|
||||
if (model.empty())
|
||||
config.erase("bed_custom_model");
|
||||
else
|
||||
config.option<ConfigOptionString>("bed_custom_model", true)->value = model;
|
||||
fs::create_directories(file.parent_path());
|
||||
config.save_to_json(file.string(), name, "User", "1.0.0");
|
||||
return file;
|
||||
}
|
||||
|
||||
nlohmann::json bed_manifest(const std::string &bundle_id)
|
||||
{
|
||||
nlohmann::json structure = nlohmann::json::object();
|
||||
structure["id"] = bundle_id;
|
||||
structure["bundle_type"] = "printer config bundle";
|
||||
structure["printer_config"] = nlohmann::json::array({"printer/BedPrinter.json"});
|
||||
return structure;
|
||||
}
|
||||
|
||||
void set_printer_bed_asset(nlohmann::json &structure, const std::string &option, const std::string &zip_name,
|
||||
const std::string &printer_entry = "printer/BedPrinter.json")
|
||||
{
|
||||
structure["printer_asset"][printer_entry][option] = zip_name;
|
||||
}
|
||||
|
||||
nlohmann::json pack_bed_zip(const fs::path &zip_file, const fs::path &printer_json, const DynamicPrintConfig &defaults,
|
||||
const std::string &texture, const std::string &model, const std::string &bundle_id,
|
||||
bool include_bed_assets = true)
|
||||
{
|
||||
DynamicPrintConfig config(defaults);
|
||||
if (!texture.empty())
|
||||
config.option<ConfigOptionString>("bed_custom_texture", true)->value = texture;
|
||||
if (!model.empty())
|
||||
config.option<ConfigOptionString>("bed_custom_model", true)->value = model;
|
||||
nlohmann::json structure = bed_manifest(bundle_id);
|
||||
mz_zip_archive zip;
|
||||
mz_zip_zero_struct(&zip);
|
||||
const std::string printer_bytes = read_file(printer_json);
|
||||
REQUIRE(open_zip_writer(&zip, zip_file.string()));
|
||||
REQUIRE(mz_zip_writer_add_mem(&zip, "printer/BedPrinter.json", printer_bytes.data(), printer_bytes.size(),
|
||||
MZ_DEFAULT_COMPRESSION));
|
||||
if (include_bed_assets)
|
||||
REQUIRE(append_printer_bed_assets(zip, config, structure, "printer/BedPrinter.json", 0));
|
||||
const std::string manifest = structure.dump();
|
||||
REQUIRE(mz_zip_writer_add_mem(&zip, BUNDLE_STRUCTURE_JSON_NAME, manifest.data(), manifest.size(),
|
||||
MZ_DEFAULT_COMPRESSION));
|
||||
REQUIRE(mz_zip_writer_finalize_archive(&zip));
|
||||
REQUIRE(close_zip_writer(&zip));
|
||||
return structure;
|
||||
}
|
||||
|
||||
std::vector<std::string> zip_entry_names(const fs::path &zip_file)
|
||||
{
|
||||
mz_zip_archive zip;
|
||||
mz_zip_zero_struct(&zip);
|
||||
REQUIRE(open_zip_reader(&zip, zip_file.string()));
|
||||
std::vector<std::string> names;
|
||||
const int n = static_cast<int>(mz_zip_reader_get_num_files(&zip));
|
||||
for (int i = 0; i < n; ++i) {
|
||||
mz_zip_archive_file_stat st;
|
||||
REQUIRE(mz_zip_reader_file_stat(&zip, i, &st));
|
||||
names.emplace_back(st.m_filename);
|
||||
}
|
||||
REQUIRE(close_zip_reader(&zip));
|
||||
return names;
|
||||
}
|
||||
|
||||
const Preset *import_named_printer(PresetBundle &bundle, const fs::path &zip_file, const fs::path &data_root,
|
||||
const std::string &bare_name, int confirm = 1)
|
||||
{
|
||||
ScopedDataDir scoped(data_root);
|
||||
AppConfig config;
|
||||
std::vector<std::string> files{zip_file.string()};
|
||||
bundle.import_presets(files, [confirm](std::string const &) { return confirm; },
|
||||
ForwardCompatibilitySubstitutionRule::Disable, config);
|
||||
for (const Preset &preset : bundle.printers.get_presets())
|
||||
if (get_preset_bare_name(preset.name) == bare_name && !preset.file.empty())
|
||||
return &preset;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Preset *import_bed(PresetBundle &bundle, const fs::path &zip_file, const fs::path &data_root, int confirm = 1)
|
||||
{
|
||||
return import_named_printer(bundle, zip_file, data_root, "BedPrinter", confirm);
|
||||
}
|
||||
|
||||
struct BedRoots {
|
||||
ScopedTemporaryDir temp_dir;
|
||||
fs::path src;
|
||||
fs::path data_root;
|
||||
PresetBundle bundle;
|
||||
BedRoots()
|
||||
: src(temp_dir.path() / "src")
|
||||
, data_root(temp_dir.path() / "datadir")
|
||||
{}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Printer bundle round trip packs bed texture and model and rewrites both keys", "[Preset][Bundle]")
|
||||
{
|
||||
// tex_rel "*" builds a non-ASCII source path under the temp directory.
|
||||
const auto pack_import = [](const std::string &bundle_id, const std::string &tex_rel, const std::string &mod_rel,
|
||||
const std::string &tex_bytes, const std::string &mod_bytes, bool tex_exists,
|
||||
bool mod_exists, int imports) {
|
||||
ScopedTemporaryDir temp_dir;
|
||||
const fs::path src = temp_dir.path() / "src";
|
||||
const fs::path data_root = temp_dir.path() / "datadir";
|
||||
std::string texture = tex_rel.empty() ? std::string() : (src / tex_rel).make_preferred().string();
|
||||
std::string model = mod_rel.empty() ? std::string() : (src / mod_rel).make_preferred().string();
|
||||
if (tex_rel == "*") {
|
||||
const fs::path dir = fs::path(src.wstring()) / fs::path(boost::nowide::widen("\xE5\xBA\x8A"));
|
||||
texture = boost::nowide::narrow((dir / fs::path(boost::nowide::widen("\xE7\xBA\xB9\xE7\x90\x86.png"))).wstring());
|
||||
}
|
||||
if (tex_exists)
|
||||
write_bytes(texture, tex_bytes);
|
||||
if (mod_exists)
|
||||
write_bytes(model, mod_bytes);
|
||||
PresetBundle bundle;
|
||||
const fs::path printer_json = write_printer_json(bundle.printers.default_preset().config, src / "BedPrinter.json",
|
||||
"BedPrinter", texture, model);
|
||||
const fs::path zip_file = src / "bundle.orca_printer";
|
||||
const nlohmann::json structure = pack_bed_zip(zip_file, printer_json, bundle.printers.default_preset().config,
|
||||
texture, model, bundle_id);
|
||||
const Preset *saved = nullptr;
|
||||
for (int i = 0; i < imports; ++i)
|
||||
saved = import_bed(bundle, zip_file, data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
const std::string got[] = {saved->config.opt_string("bed_custom_texture"), saved->config.opt_string("bed_custom_model")};
|
||||
const std::string rel[] = {tex_rel, mod_rel};
|
||||
const std::string bytes[] = {tex_bytes, mod_bytes};
|
||||
const std::string path[] = {texture, model};
|
||||
const bool exists[] = {tex_exists, mod_exists};
|
||||
const char *option[] = {"bed_custom_texture", "bed_custom_model"};
|
||||
const char *stem[] = {"texture", "model"};
|
||||
for (int slot = 0; slot < 2; ++slot) {
|
||||
if (exists[slot]) {
|
||||
const std::string ext = fs::path(rel[slot] == "*" ? "x.png" : rel[slot]).extension().string();
|
||||
const std::string zip_name = std::string("bed/0/") + stem[slot] + ext;
|
||||
REQUIRE(structure["printer_asset"]["printer/BedPrinter.json"][option[slot]] == zip_name);
|
||||
REQUIRE(fs::path(got[slot]).filename().string() == std::string(stem[slot]) + fs::path(zip_name).extension().string());
|
||||
REQUIRE(fs::path(got[slot]).parent_path().filename() == "0");
|
||||
REQUIRE(fs::path(got[slot]).parent_path().parent_path().filename() == "bed");
|
||||
REQUIRE(got[slot].find(bundle_id) != std::string::npos);
|
||||
REQUIRE(read_file(got[slot]) == bytes[slot]);
|
||||
REQUIRE(got[slot] != path[slot]);
|
||||
} else if (!rel[slot].empty() && rel[slot] != "*") {
|
||||
REQUIRE_FALSE(structure.value("printer_asset", nlohmann::json::object())
|
||||
.value("printer/BedPrinter.json", nlohmann::json::object())
|
||||
.contains(option[slot]));
|
||||
REQUIRE(got[slot] == path[slot]);
|
||||
} else if (rel[slot].empty()) {
|
||||
REQUIRE(got[slot].empty());
|
||||
}
|
||||
}
|
||||
if (imports > 1) {
|
||||
int copies = 0;
|
||||
for (fs::recursive_directory_iterator it(data_root), end; it != end; ++it)
|
||||
if (it->path().filename() == "texture.png" || it->path().filename() == "model.stl")
|
||||
++copies;
|
||||
REQUIRE(copies == (tex_exists ? 1 : 0) + (mod_exists ? 1 : 0));
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("both assets are packed from the preset config and rewritten on import") {
|
||||
pack_import("bed-roundtrip", "fixture/baseline_bed_texture.png", "fixture/baseline_bed_model.stl",
|
||||
kTextureBytes, kModelBytes, true, true, 1);
|
||||
}
|
||||
SECTION("texture only") {
|
||||
pack_import("texture-only", "only.png", "", kTextureBytes, "", true, false, 1);
|
||||
}
|
||||
SECTION("model only") {
|
||||
pack_import("model-only", "", "only.stl", "", kModelBytes, false, true, 1);
|
||||
}
|
||||
SECTION("texture and model share a source basename") {
|
||||
pack_import("shared-basename", "a/plate.png", "b/plate.stl", kTextureBytes, kOtherBytes, true, true, 1);
|
||||
}
|
||||
SECTION("importing the same bundle twice keeps one copy of the assets") {
|
||||
// First import installs kTextureBytes / kModelBytes. The second pack uses different bytes so
|
||||
// the Yes-overwrite path (copy_file overwrite_existing) is actually proven.
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "twice.png").make_preferred().string();
|
||||
const std::string model = (bed.src / "twice.stl").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
write_bytes(model, kModelBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config,
|
||||
bed.src / "BedPrinter.json", "BedPrinter", texture, model);
|
||||
const fs::path zip_file = bed.src / "bundle.orca_printer";
|
||||
pack_bed_zip(zip_file, printer_json, bed.bundle.printers.default_preset().config, texture, model, "reimport");
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
const std::string got_tex = saved->config.opt_string("bed_custom_texture");
|
||||
const std::string got_mod = saved->config.opt_string("bed_custom_model");
|
||||
REQUIRE(read_file(got_tex) == kTextureBytes);
|
||||
REQUIRE(read_file(got_mod) == kModelBytes);
|
||||
write_bytes(texture, kOtherBytes);
|
||||
write_bytes(model, std::string("stl\x00other", 9));
|
||||
pack_bed_zip(zip_file, printer_json, bed.bundle.printers.default_preset().config, texture, model, "reimport");
|
||||
saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == got_tex);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_model") == got_mod);
|
||||
REQUIRE(read_file(got_tex) == kOtherBytes);
|
||||
REQUIRE(read_file(got_mod) == std::string("stl\x00other", 9));
|
||||
}
|
||||
SECTION("a non-ASCII source path is packed") {
|
||||
pack_import("non-ascii", "*", "", kTextureBytes, "", true, false, 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("An old printer bundle without printer_asset imports unchanged", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "old.png").make_preferred().string();
|
||||
const std::string model = (bed.src / "old.stl").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
write_bytes(model, kModelBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", texture, model);
|
||||
nlohmann::json structure = bed_manifest("old-bundle");
|
||||
REQUIRE_FALSE(structure.contains("printer_asset"));
|
||||
const fs::path zip_file = bed.src / "old.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()}});
|
||||
// A bed/ folder left by an earlier import into the same bundle folder must survive an asset-less import.
|
||||
const fs::path old_bed = bed.data_root / "user" / "default" / "_local" / "old-bundle" / "bed";
|
||||
write_bytes((old_bed / "texture.png").string(), kTextureBytes);
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == texture);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_model") == model);
|
||||
CHECK(fs::exists(old_bed / "texture.png"));
|
||||
}
|
||||
|
||||
TEST_CASE("Printer bundle asset names that escape the bundle directory are rejected", "[Preset][Bundle]")
|
||||
{
|
||||
const char *bad_names[] = {"../../pwned.png", "bed/../../pwned.png", "..\\..\\pwned.png", "C:/Windows/pwned.png",
|
||||
"machine/texture.png", "/bed/texture.png"};
|
||||
const std::string marker = "PWNED-BED-ASSET-MARKER";
|
||||
for (const char *name : bad_names) {
|
||||
DYNAMIC_SECTION("rejects " << name) {
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "kept.png").make_preferred().string();
|
||||
const std::string model = (bed.src / "kept.stl").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
write_bytes(model, kModelBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config,
|
||||
bed.src / "BedPrinter.json", "BedPrinter", texture, model);
|
||||
nlohmann::json structure = bed_manifest("traverse");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", name);
|
||||
std::vector<std::pair<std::string, std::string>> entries = {
|
||||
{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()}};
|
||||
if (name[0] != '/' && name[0] != '\\')
|
||||
entries.emplace_back(name, marker);
|
||||
const fs::path zip_file = bed.src / "bad.orca_printer";
|
||||
write_zip(zip_file, entries);
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == texture);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_model") == model);
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, fs::path(name).filename().string()));
|
||||
if (fs::exists(bed.data_root))
|
||||
for (fs::recursive_directory_iterator it(bed.data_root), end; it != end; ++it)
|
||||
if (fs::is_regular_file(*it))
|
||||
CHECK(read_file(*it).find(marker) == std::string::npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("A printer bundle asset that is missing is skipped", "[Preset][Bundle]")
|
||||
{
|
||||
SECTION("a manifest entry with no zip bytes leaves the original path") {
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "gone.png").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", texture, {});
|
||||
nlohmann::json structure = bed_manifest("missing-zip");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "bed/0/texture.png");
|
||||
const fs::path zip_file = bed.src / "missing.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()}});
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == texture);
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, "texture.png"));
|
||||
}
|
||||
|
||||
SECTION("a missing file at export is omitted and the export still succeeds") {
|
||||
BedRoots bed;
|
||||
const std::string missing = (bed.src / "missing.png").make_preferred().string();
|
||||
const std::string model = (bed.src / "present.stl").make_preferred().string();
|
||||
write_bytes(model, kModelBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", missing, model);
|
||||
const fs::path zip_file = bed.src / "partial.orca_printer";
|
||||
const nlohmann::json structure = pack_bed_zip(zip_file, printer_json, bed.bundle.printers.default_preset().config,
|
||||
missing, model, "missing-export");
|
||||
REQUIRE_FALSE(structure["printer_asset"]["printer/BedPrinter.json"].contains("bed_custom_texture"));
|
||||
REQUIRE(structure["printer_asset"]["printer/BedPrinter.json"]["bed_custom_model"] == "bed/0/model.stl");
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == missing);
|
||||
REQUIRE(read_file(saved->config.opt_string("bed_custom_model")) == kModelBytes);
|
||||
REQUIRE(fs::path(saved->config.opt_string("bed_custom_model")).filename() == "model.stl");
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, "texture.png"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("An inherited printer bundle rewrites bed paths taken from the parent", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "parent.png").make_preferred().string();
|
||||
const std::string model = (bed.src / "parent.stl").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
write_bytes(model, kModelBytes);
|
||||
DynamicPrintConfig parent(bed.bundle.printers.default_preset().config);
|
||||
parent.option<ConfigOptionString>("printer_settings_id", true)->value = "ParentPrinter";
|
||||
parent.option<ConfigOptionString>("inherits", true)->value.clear();
|
||||
parent.option<ConfigOptionString>("bed_custom_texture", true)->value = texture;
|
||||
parent.option<ConfigOptionString>("bed_custom_model", true)->value = model;
|
||||
bed.bundle.printers.load_preset((bed.src / "ParentPrinter.json").string(), "ParentPrinter", std::move(parent), false);
|
||||
const fs::path child_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", {}, {}, "ParentPrinter");
|
||||
const nlohmann::json written = nlohmann::json::parse(read_file(child_json));
|
||||
REQUIRE_FALSE(written.contains("bed_custom_texture"));
|
||||
REQUIRE_FALSE(written.contains("bed_custom_model"));
|
||||
nlohmann::json structure = bed_manifest("inherit-bed");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "bed/0/texture.png");
|
||||
set_printer_bed_asset(structure, "bed_custom_model", "bed/0/model.stl");
|
||||
const fs::path zip_file = bed.src / "inherit.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(child_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()},
|
||||
{"bed/0/texture.png", kTextureBytes}, {"bed/0/model.stl", kModelBytes}});
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") != texture);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_model") != model);
|
||||
REQUIRE(read_file(saved->config.opt_string("bed_custom_texture")) == kTextureBytes);
|
||||
REQUIRE(read_file(saved->config.opt_string("bed_custom_model")) == kModelBytes);
|
||||
REQUIRE(fs::path(saved->config.opt_string("bed_custom_texture")).filename() == "texture.png");
|
||||
REQUIRE(fs::path(saved->config.opt_string("bed_custom_model")).filename() == "model.stl");
|
||||
}
|
||||
|
||||
TEST_CASE("A printer bundle rejects bed assets whose extension the bed dialog does not allow", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", {}, {});
|
||||
nlohmann::json structure = bed_manifest("bad-ext");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "bed/0/texture.stl");
|
||||
set_printer_bed_asset(structure, "bed_custom_model", "bed/0/model.exe");
|
||||
const fs::path zip_file = bed.src / "bad-ext.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()},
|
||||
{"bed/0/texture.stl", kTextureBytes}, {"bed/0/model.exe", std::string("MZ")}});
|
||||
REQUIRE(import_bed(bed.bundle, zip_file, bed.data_root) != nullptr);
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, "model.exe"));
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, "texture.stl"));
|
||||
}
|
||||
|
||||
TEST_CASE("A manifest asset name that points at a preset does not drop that preset", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", {}, {});
|
||||
nlohmann::json structure = bed_manifest("name-clash");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "printer/BedPrinter.json");
|
||||
const fs::path zip_file = bed.src / "clash.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()}});
|
||||
REQUIRE(import_bed(bed.bundle, zip_file, bed.data_root) != nullptr);
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, "texture.png"));
|
||||
}
|
||||
|
||||
TEST_CASE("A declined printer bundle import leaves existing bed files alone", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const fs::path kept = bed.data_root / "user" / "default" / "_local" / "keep-bed" / "bed" / "texture.png";
|
||||
const std::string original("kept-texture");
|
||||
write_bytes(kept.string(), original);
|
||||
DynamicPrintConfig existing(bed.bundle.printers.default_preset().config);
|
||||
existing.option<ConfigOptionString>("printer_settings_id", true)->value = "BedPrinter";
|
||||
existing.option<ConfigOptionString>("inherits", true)->value.clear();
|
||||
bed.bundle.printers.load_preset((bed.src / "existing.json").string(), "_local/keep-bed/BedPrinter", std::move(existing),
|
||||
false);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", {}, {});
|
||||
nlohmann::json structure = bed_manifest("keep-bed");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "bed/0/texture.png");
|
||||
set_printer_bed_asset(structure, "bed_custom_model", "bed/0/model.stl");
|
||||
const fs::path zip_file = bed.src / "keep.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()},
|
||||
{"bed/0/texture.png", kTextureBytes}, {"bed/0/model.stl", kModelBytes}});
|
||||
import_bed(bed.bundle, zip_file, bed.data_root, 0);
|
||||
// This import wrote nothing: the existing texture is unchanged and model.stl was not added.
|
||||
REQUIRE(fs::exists(kept));
|
||||
REQUIRE(read_file(kept) == original);
|
||||
CHECK_FALSE(fs::exists(kept.parent_path() / "model.stl"));
|
||||
CHECK_FALSE(fs::exists(kept.parent_path() / "0" / "model.stl"));
|
||||
}
|
||||
|
||||
TEST_CASE("A declined re-import does not replace bed bytes an earlier import wrote", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", {}, {});
|
||||
nlohmann::json structure = bed_manifest("reimport-no");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "bed/0/texture.png");
|
||||
const std::string manifest = structure.dump();
|
||||
const std::string printer_bytes = read_file(printer_json);
|
||||
const fs::path first_zip = bed.src / "first.orca_printer";
|
||||
const fs::path second_zip = bed.src / "second.orca_printer";
|
||||
write_zip(first_zip, {{"printer/BedPrinter.json", printer_bytes}, {BUNDLE_STRUCTURE_JSON_NAME, manifest},
|
||||
{"bed/0/texture.png", kTextureBytes}});
|
||||
write_zip(second_zip, {{"printer/BedPrinter.json", printer_bytes}, {BUNDLE_STRUCTURE_JSON_NAME, manifest},
|
||||
{"bed/0/texture.png", kOtherBytes}});
|
||||
const Preset *saved = import_bed(bed.bundle, first_zip, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
const std::string installed = saved->config.opt_string("bed_custom_texture");
|
||||
REQUIRE(read_file(installed) == kTextureBytes);
|
||||
import_bed(bed.bundle, second_zip, bed.data_root, 0);
|
||||
REQUIRE(fs::exists(installed));
|
||||
REQUIRE(read_file(installed) == kTextureBytes);
|
||||
}
|
||||
|
||||
TEST_CASE("Export with bed assets disabled packs no bed files and writes no printer_asset", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "off.png").make_preferred().string();
|
||||
const std::string model = (bed.src / "off.stl").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
write_bytes(model, kModelBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", texture, model);
|
||||
const fs::path zip_file = bed.src / "off.orca_printer";
|
||||
const nlohmann::json structure = pack_bed_zip(zip_file, printer_json, bed.bundle.printers.default_preset().config,
|
||||
texture, model, "bed-off", false);
|
||||
REQUIRE_FALSE(structure.contains("printer_asset"));
|
||||
for (const std::string &name : zip_entry_names(zip_file))
|
||||
REQUIRE(name.compare(0, 4, "bed/") != 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Two printers in one bundle keep separate bed folders", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const std::string tex_a = (bed.src / "a.png").make_preferred().string();
|
||||
const std::string mod_a = (bed.src / "a.stl").make_preferred().string();
|
||||
const std::string tex_b = (bed.src / "b.png").make_preferred().string();
|
||||
const std::string mod_b = (bed.src / "b.stl").make_preferred().string();
|
||||
write_bytes(tex_a, kTextureBytes);
|
||||
write_bytes(mod_a, kModelBytes);
|
||||
write_bytes(tex_b, kOtherBytes);
|
||||
write_bytes(mod_b, std::string("stl\x00other", 9));
|
||||
const fs::path json_a = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "PrinterA.json",
|
||||
"PrinterA", tex_a, mod_a);
|
||||
const fs::path json_b = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "PrinterB.json",
|
||||
"PrinterB", tex_b, mod_b);
|
||||
nlohmann::json structure = nlohmann::json::object();
|
||||
structure["id"] = "two-printers";
|
||||
structure["bundle_type"] = "printer config bundle";
|
||||
structure["printer_config"] = nlohmann::json::array({"printer/PrinterA.json", "printer/PrinterB.json"});
|
||||
DynamicPrintConfig config_a(bed.bundle.printers.default_preset().config);
|
||||
config_a.option<ConfigOptionString>("bed_custom_texture", true)->value = tex_a;
|
||||
config_a.option<ConfigOptionString>("bed_custom_model", true)->value = mod_a;
|
||||
DynamicPrintConfig config_b(bed.bundle.printers.default_preset().config);
|
||||
config_b.option<ConfigOptionString>("bed_custom_texture", true)->value = tex_b;
|
||||
config_b.option<ConfigOptionString>("bed_custom_model", true)->value = mod_b;
|
||||
const fs::path zip_file = bed.src / "two.orca_printer";
|
||||
mz_zip_archive zip;
|
||||
mz_zip_zero_struct(&zip);
|
||||
const std::string bytes_a = read_file(json_a);
|
||||
const std::string bytes_b = read_file(json_b);
|
||||
REQUIRE(open_zip_writer(&zip, zip_file.string()));
|
||||
REQUIRE(mz_zip_writer_add_mem(&zip, "printer/PrinterA.json", bytes_a.data(), bytes_a.size(), MZ_DEFAULT_COMPRESSION));
|
||||
REQUIRE(mz_zip_writer_add_mem(&zip, "printer/PrinterB.json", bytes_b.data(), bytes_b.size(), MZ_DEFAULT_COMPRESSION));
|
||||
REQUIRE(append_printer_bed_assets(zip, config_a, structure, "printer/PrinterA.json", 0));
|
||||
REQUIRE(append_printer_bed_assets(zip, config_b, structure, "printer/PrinterB.json", 1));
|
||||
const std::string manifest = structure.dump();
|
||||
REQUIRE(mz_zip_writer_add_mem(&zip, BUNDLE_STRUCTURE_JSON_NAME, manifest.data(), manifest.size(),
|
||||
MZ_DEFAULT_COMPRESSION));
|
||||
REQUIRE(mz_zip_writer_finalize_archive(&zip));
|
||||
REQUIRE(close_zip_writer(&zip));
|
||||
REQUIRE(structure["printer_asset"]["printer/PrinterA.json"]["bed_custom_texture"] == "bed/0/texture.png");
|
||||
REQUIRE(structure["printer_asset"]["printer/PrinterB.json"]["bed_custom_texture"] == "bed/1/texture.png");
|
||||
ScopedDataDir scoped(bed.data_root);
|
||||
AppConfig app_config;
|
||||
std::vector<std::string> files{zip_file.string()};
|
||||
bed.bundle.import_presets(files, [](std::string const &) { return 1; },
|
||||
ForwardCompatibilitySubstitutionRule::Disable, app_config);
|
||||
const Preset *saved_a = nullptr;
|
||||
const Preset *saved_b = nullptr;
|
||||
for (const Preset &preset : bed.bundle.printers.get_presets()) {
|
||||
if (preset.file.empty())
|
||||
continue;
|
||||
if (get_preset_bare_name(preset.name) == "PrinterA")
|
||||
saved_a = &preset;
|
||||
if (get_preset_bare_name(preset.name) == "PrinterB")
|
||||
saved_b = &preset;
|
||||
}
|
||||
REQUIRE(saved_a != nullptr);
|
||||
REQUIRE(saved_b != nullptr);
|
||||
const std::string got_tex_a = saved_a->config.opt_string("bed_custom_texture");
|
||||
const std::string got_tex_b = saved_b->config.opt_string("bed_custom_texture");
|
||||
REQUIRE(fs::path(got_tex_a).parent_path().filename() == "0");
|
||||
REQUIRE(fs::path(got_tex_b).parent_path().filename() == "1");
|
||||
REQUIRE(got_tex_a != got_tex_b);
|
||||
REQUIRE(read_file(got_tex_a) == kTextureBytes);
|
||||
REQUIRE(read_file(got_tex_b) == kOtherBytes);
|
||||
REQUIRE(read_file(saved_a->config.opt_string("bed_custom_model")) == kModelBytes);
|
||||
REQUIRE(read_file(saved_b->config.opt_string("bed_custom_model")) == std::string("stl\x00other", 9));
|
||||
}
|
||||
|
||||
TEST_CASE("A printer_asset entry keyed to a printer not in the zip is ignored", "[Preset][Bundle]")
|
||||
{
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "kept.png").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", texture, {});
|
||||
nlohmann::json structure = bed_manifest("ghost-key");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "bed/0/texture.png", "printer/Ghost.json");
|
||||
const fs::path zip_file = bed.src / "ghost.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()},
|
||||
{"bed/0/texture.png", kOtherBytes}});
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == texture);
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, "texture.png"));
|
||||
}
|
||||
|
||||
TEST_CASE("Keyed printer_asset rejects malformed bed paths", "[Preset][Bundle]")
|
||||
{
|
||||
const char *bad_names[] = {"bed/texture.png", "bed/x/texture.png", "bed/0/../texture.png", "bed/0/model.png"};
|
||||
const std::string marker = "PWNED-BED-ASSET-MARKER";
|
||||
for (const char *name : bad_names) {
|
||||
DYNAMIC_SECTION("rejects " << name) {
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "kept.png").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config,
|
||||
bed.src / "BedPrinter.json", "BedPrinter", texture, {});
|
||||
nlohmann::json structure = bed_manifest("bad-keyed");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", name);
|
||||
std::vector<std::pair<std::string, std::string>> entries = {
|
||||
{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()},
|
||||
{name, marker}};
|
||||
const fs::path zip_file = bed.src / "bad-keyed.orca_printer";
|
||||
write_zip(zip_file, entries);
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == texture);
|
||||
if (fs::exists(bed.data_root))
|
||||
for (fs::recursive_directory_iterator it(bed.data_root), end; it != end; ++it)
|
||||
if (fs::is_regular_file(*it))
|
||||
CHECK(read_file(*it).find(marker) == std::string::npos);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("field name does not match file kind") {
|
||||
BedRoots bed;
|
||||
const std::string texture = (bed.src / "kept.png").make_preferred().string();
|
||||
write_bytes(texture, kTextureBytes);
|
||||
const fs::path printer_json = write_printer_json(bed.bundle.printers.default_preset().config, bed.src / "BedPrinter.json",
|
||||
"BedPrinter", texture, {});
|
||||
nlohmann::json structure = bed_manifest("kind-mismatch");
|
||||
set_printer_bed_asset(structure, "bed_custom_texture", "bed/0/model.stl");
|
||||
const fs::path zip_file = bed.src / "kind.orca_printer";
|
||||
write_zip(zip_file, {{"printer/BedPrinter.json", read_file(printer_json)}, {BUNDLE_STRUCTURE_JSON_NAME, structure.dump()},
|
||||
{"bed/0/model.stl", kModelBytes}});
|
||||
const Preset *saved = import_bed(bed.bundle, zip_file, bed.data_root);
|
||||
REQUIRE(saved != nullptr);
|
||||
REQUIRE(saved->config.opt_string("bed_custom_texture") == texture);
|
||||
CHECK_FALSE(any_filename_contains(bed.data_root, "model.stl"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("A saved printer preset reloads the tool layout it was saved with", "[Preset][Bundle][IMEX]")
|
||||
{
|
||||
ScopedTemporaryDir temp_dir;
|
||||
@@ -6555,3 +7161,89 @@ TEST_CASE("A user filament whose derived compatible printer cannot be written ba
|
||||
CHECK(read_file(file) == before);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("A user filament keeps the printers its narrowed system parent listed in an older release", "[Preset][Bundle]")
|
||||
{
|
||||
PresetBundle bundle;
|
||||
PresetCollection &filaments = bundle.filaments;
|
||||
const std::string parent = "Generic PETG @Creality K1-all";
|
||||
|
||||
// load_preset inserts in sorted order, so presets are looked up again rather than held by reference.
|
||||
auto set_printers = [&filaments](const std::string &name, std::vector<std::string> printers) {
|
||||
filaments.find_preset(name)->config.option<ConfigOptionStrings>("compatible_printers", true)->values = std::move(printers);
|
||||
};
|
||||
add_inmemory_preset(filaments, parent).is_system = true;
|
||||
add_inmemory_preset(filaments, "My PETG", parent);
|
||||
add_inmemory_preset(filaments, "My PETG own list", parent);
|
||||
set_printers(parent, { "Creality K1C 0.6 nozzle" });
|
||||
set_printers("My PETG", { "Creality K1C 0.6 nozzle" });
|
||||
set_printers("My PETG own list", { "Creality K1C 0.6 nozzle", "Creality K1C 0.8 nozzle" });
|
||||
|
||||
filaments.set_legacy_compatible_printers({ { parent, { "Creality K1C 0.4 nozzle" } } });
|
||||
|
||||
auto compatible = [&filaments](const std::string &filament, const Preset &printer) {
|
||||
return is_compatible_with_printer(PresetWithVendorProfile(*filaments.find_preset(filament), nullptr),
|
||||
PresetWithVendorProfile(printer, nullptr));
|
||||
};
|
||||
Preset k1c_04(Preset::TYPE_PRINTER, "Creality K1C 0.4 nozzle");
|
||||
k1c_04.is_system = true;
|
||||
Preset k1_max(Preset::TYPE_PRINTER, "Creality K1 Max 0.4 nozzle");
|
||||
k1_max.is_system = true;
|
||||
Preset my_k1c(Preset::TYPE_PRINTER, "My K1C");
|
||||
my_k1c.config.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS, true)->value = "Creality K1C 0.4 nozzle";
|
||||
|
||||
CHECK(compatible("My PETG", k1c_04));
|
||||
CHECK(compatible("My PETG", my_k1c));
|
||||
CHECK_FALSE(compatible("My PETG", k1_max));
|
||||
// The system preset itself and a user preset with its own list keep exactly their lists.
|
||||
CHECK_FALSE(compatible(parent, k1c_04));
|
||||
CHECK_FALSE(compatible("My PETG own list", k1c_04));
|
||||
|
||||
// A parent renamed after the map was written is still found under its old name.
|
||||
add_inmemory_preset(filaments, "Generic PETG @Creality K1 renamed").is_system = true;
|
||||
add_inmemory_preset(filaments, "My renamed PETG", "Generic PETG @Creality K1 renamed");
|
||||
set_renamed_from(filaments, "Generic PETG @Creality K1 renamed", { parent });
|
||||
set_printers("Generic PETG @Creality K1 renamed", { "Creality K1C 0.6 nozzle" });
|
||||
set_printers("My renamed PETG", { "Creality K1C 0.6 nozzle" });
|
||||
filaments.set_legacy_compatible_printers({ { parent, { "Creality K1C 0.4 nozzle" } } });
|
||||
CHECK(compatible("My renamed PETG", k1c_04));
|
||||
}
|
||||
|
||||
TEST_CASE("A saved user filament keeps its legacy printers only while it inherits its parent's printer list", "[Preset][Bundle]")
|
||||
{
|
||||
ScopedTemporaryDir temp_dir;
|
||||
PresetBundle bundle;
|
||||
PresetCollection &filaments = bundle.filaments;
|
||||
const std::string parent = "Generic PETG @Creality K1-all";
|
||||
add_inmemory_preset(filaments, parent).is_system = true;
|
||||
filaments.find_preset(parent)->config.option<ConfigOptionStrings>("compatible_printers", true)->values = { "Creality K1C 0.6 nozzle" };
|
||||
// Like a real user preset, the file states only its diff, so the printer list comes from the parent.
|
||||
fs::create_directories(temp_dir.path() / PRESET_FILAMENT_NAME);
|
||||
std::ofstream((temp_dir.path() / PRESET_FILAMENT_NAME / "My PETG.json").string())
|
||||
<< R"({"type":"filament","name":"My PETG","from":"User","version":"1.0.0","inherits":")" << parent << R"("})";
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
filaments.load_presets(temp_dir.path().string(), PRESET_FILAMENT_NAME, substitutions,
|
||||
ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||
filaments.set_legacy_compatible_printers({ { parent, { "Creality K1C 0.4 nozzle" } } });
|
||||
const std::vector<std::string> legacy { "Creality K1C 0.4 nozzle" };
|
||||
REQUIRE(filaments.find_preset("My PETG")->legacy_compatible_printers == legacy);
|
||||
|
||||
auto save_from_my_petg = [&filaments](const std::string &name, bool detach) {
|
||||
filaments.select_preset_by_name("My PETG", true);
|
||||
filaments.save_current_preset(name, detach);
|
||||
return filaments.find_preset(name)->legacy_compatible_printers;
|
||||
};
|
||||
CHECK(save_from_my_petg("My PETG copy", false) == legacy);
|
||||
CHECK(save_from_my_petg("My PETG detached", true).empty());
|
||||
|
||||
// A clone is detached from the parent, as "Create filament" makes for another printer.
|
||||
std::vector<std::string> failures;
|
||||
REQUIRE(filaments.clone_presets({ filaments.find_preset("My PETG") }, failures,
|
||||
[](Preset &preset, Preset::Type &) { preset.name = "My PETG clone"; }));
|
||||
CHECK(filaments.find_preset("My PETG clone")->legacy_compatible_printers.empty());
|
||||
|
||||
filaments.select_preset_by_name("My PETG", true);
|
||||
filaments.get_edited_preset().config.option<ConfigOptionStrings>("compatible_printers")->values = { "Creality K1C 0.8 nozzle" };
|
||||
filaments.save_current_preset("My PETG", false);
|
||||
CHECK(filaments.find_preset("My PETG")->legacy_compatible_printers.empty());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user