Compare commits

...

9 Commits

Author SHA1 Message Date
Argo
7e63fce706 Fix 3MF import crash for silent-mode machine limits with legacy vector sizes (#12289)
Normalize printer_options_with_variant_2 (stride=2) machine limit vectors during preset merge to handle legacy 3MF/projects that store only a single (normal,silent) pair despite multiple printer variants, preventing set_with_restore() size-mismatch crashes.

Crash error message during 3MF import as project:

<img width="833" height="274" alt="image" src="https://github.com/user-attachments/assets/f92148a9-98c6-47b7-a0ab-d5ac8b1f2be4" />

3MF attached that causes the bug. 
[cube.3mf.zip](https://github.com/user-attachments/files/25318309/cube.3mf.zip)
2026-02-15 20:50:17 +08:00
Matthias Blaicher
380f4b4a18 Fix EGL/GLX mismatch causing blank 3D preview on Linux (#12308)
- Add configurable GLEW_USE_EGL option (default OFF) to match wxWidgets
- Explicitly set wxUSE_GLCANVAS_EGL=OFF for vendored wxWidgets build
- Add compile-time check to detect EGL/GLX backend mismatch between
  GLEW and wxWidgets, preventing silent rendering failures

The bug occurred when GLEW was compiled with EGL support (using
eglGetProcAddress) but wxWidgets created GLX contexts. This mismatch
caused OpenGL function pointers to fail loading, resulting in blank
3D model preview.

Co-authored-by: SoftFever <softfeverever@gmail.com>
2026-02-15 16:27:07 +08:00
SoftFever
240cf9ab5d bump version to 2.3.2-beta2 2026-02-15 14:31:57 +08:00
Branden Cash
05cb8b4d89 feat(MoonrakerPrinterAgent): support Happy Hare as alternative to AFC for filament sync (#12307)
# Description


# Screenshots/Recordings/Graphs


https://github.com/user-attachments/assets/5558b4be-24eb-4f2d-83fd-8482560a0014

<img width="445" height="285" alt="Screenshot 2026-02-14 at 7 31 57 PM" src="https://github.com/user-attachments/assets/e71fee66-05da-4f9c-8123-0f52e93f0ebb" />


## Tests

Removed configured filaments and pressed the sync button. Observed the filaments configured in my system were populated.
2026-02-15 14:31:29 +08:00
SoftFever
897a3e915f bump profile version to "02.03.02.40" (#12309) 2026-02-15 14:26:33 +08:00
Ian Bassi
586e96479a Linux: Repaired VFA tower (#12290)
* Update CalibUtils.cpp

* VFA.drc case to vfa.drc
2026-02-15 14:26:33 +08:00
Ian Bassi
0879b2079b Spanish minor update (#12268) 2026-02-15 14:26:33 +08:00
Ian Bassi
c4801250ea Spanish Update (#12254)
* Spanish Update
2026-02-15 14:26:33 +08:00
SoftFever
f0386d981f Revert "Switch to self hosted mac runner (#12024)"
This reverts commit f1212be6bb.
2026-02-14 18:11:06 +08:00
77 changed files with 3863 additions and 2548 deletions

View File

@@ -66,7 +66,7 @@ jobs:
matrix:
include:
- os: windows-latest
- os: orca-macos-arm64
- os: macos-14
arch: arm64
# Don't run scheduled builds on forks:
if: ${{ !cancelled() && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }}

View File

@@ -33,7 +33,7 @@ jobs:
- name: set outputs
id: set_outputs
env:
dep-folder-name: ${{ inputs.os != 'orca-macos-arm64' && '/OrcaSlicer_dep' || '' }}
dep-folder-name: ${{ inputs.os != 'macos-14' && '/OrcaSlicer_dep' || '' }}
output-cmd: ${{ inputs.os == 'windows-latest' && '$env:GITHUB_OUTPUT' || '"$GITHUB_OUTPUT"'}}
run: |
echo cache-key=${{ inputs.os }}-cache-orcaslicer_deps-build-${{ hashFiles('deps/**') }} >> ${{ env.output-cmd }}

View File

@@ -74,18 +74,18 @@ jobs:
cd ${{ github.workspace }}/deps/build
- name: Build on Mac ${{ inputs.arch }}
if: inputs.os == 'orca-macos-arm64'
if: inputs.os == 'macos-14'
working-directory: ${{ github.workspace }}
run: |
# brew install automake texinfo libtool
# brew list
# brew uninstall --ignore-dependencies zstd
./build_release_macos.sh -dx -a universal -t 10.15
brew install automake texinfo libtool
brew list
brew uninstall --ignore-dependencies zstd
./build_release_macos.sh -dx -a universal -t 10.15 -1
for arch in arm64 x86_64; do
(cd "${{ github.workspace }}/deps/build/${arch}" && \
find . -mindepth 1 -maxdepth 1 ! -name 'OrcaSlicer_dep' -exec rm -rf {} +)
done
# brew install zstd
brew install zstd
- name: Apt-Install Dependencies
@@ -104,7 +104,7 @@ jobs:
# Upload Artifacts
# - name: Upload Mac ${{ inputs.arch }} artifacts
# if: inputs.os == 'orca-macos-arm64'
# if: inputs.os == 'macos-14'
# uses: actions/upload-artifact@v6
# with:
# name: OrcaSlicer_dep_mac_${{ env.date }}

View File

@@ -86,29 +86,29 @@ jobs:
# Mac
- name: Install tools mac
if: inputs.os == 'orca-macos-arm64'
if: inputs.os == 'macos-14'
run: |
# brew install libtool
# brew list
brew install libtool
brew list
mkdir -p ${{ github.workspace }}/deps/build
# - name: Free disk space
# if: inputs.os == 'orca-macos-arm64'
# run: |
# df -hI /dev/disk3s1s1
# sudo find /Applications -maxdepth 1 -type d -name "Xcode_*.app" ! -name "Xcode_15.4.app" -exec rm -rf {} +
# sudo rm -rf ~/Library/Developer/CoreSimulator/Caches/*
# df -hI /dev/disk3s1s1
- name: Free disk space
if: inputs.os == 'macos-14'
run: |
df -hI /dev/disk3s1s1
sudo find /Applications -maxdepth 1 -type d -name "Xcode_*.app" ! -name "Xcode_15.4.app" -exec rm -rf {} +
sudo rm -rf ~/Library/Developer/CoreSimulator/Caches/*
df -hI /dev/disk3s1s1
- name: Build slicer mac
if: inputs.os == 'orca-macos-arm64'
if: inputs.os == 'macos-14'
working-directory: ${{ github.workspace }}
run: |
./build_release_macos.sh -s -n -x -a universal -t 10.15
./build_release_macos.sh -s -n -x -a universal -t 10.15 -1
# Thanks to RaySajuuk, it's working now
- name: Sign app and notary
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && inputs.os == 'orca-macos-arm64'
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && inputs.os == 'macos-14'
working-directory: ${{ github.workspace }}
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
@@ -162,7 +162,7 @@ jobs:
fi
- name: Create DMG without notary
if: github.ref != 'refs/heads/main' && inputs.os == 'orca-macos-arm64'
if: github.ref != 'refs/heads/main' && inputs.os == 'macos-14'
working-directory: ${{ github.workspace }}
run: |
mkdir -p ${{ github.workspace }}/build/universal/OrcaSlicer_dmg
@@ -181,14 +181,14 @@ jobs:
fi
- name: Upload artifacts mac
if: inputs.os == 'orca-macos-arm64'
if: inputs.os == 'macos-14'
uses: actions/upload-artifact@v6
with:
name: OrcaSlicer_Mac_universal_${{ env.ver }}
path: ${{ github.workspace }}/OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
- name: Upload OrcaSlicer_profile_validator DMG mac
if: inputs.os == 'orca-macos-arm64'
if: inputs.os == 'macos-14'
uses: actions/upload-artifact@v6
with:
name: OrcaSlicer_profile_validator_Mac_universal_DMG_${{ env.ver }}
@@ -196,7 +196,7 @@ jobs:
if-no-files-found: ignore
- name: Deploy Mac release
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && inputs.os == 'orca-macos-arm64'
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && inputs.os == 'macos-14'
uses: WebFreak001/deploy-nightly@v3.2.0
with:
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
@@ -207,7 +207,7 @@ jobs:
max_releases: 1 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted
- name: Deploy Mac OrcaSlicer_profile_validator DMG release
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && inputs.os == 'orca-macos-arm64'
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && inputs.os == 'macos-14'
uses: WebFreak001/deploy-nightly@v3.2.0
with:
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}

View File

@@ -5,6 +5,8 @@ find_package(OpenGL QUIET REQUIRED)
orcaslicer_add_cmake_project(
GLEW
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/glew
CMAKE_ARGS
-DGLEW_USE_EGL=OFF
)
if (MSVC)

View File

@@ -3,9 +3,17 @@ project(GLEW)
find_package(OpenGL REQUIRED)
if(OpenGL_EGL_FOUND)
message(STATUS "building GLEW for EGL (hope that wxWidgets agrees, otherwise you won't have any output!)")
# Allow parent project to control EGL usage.
# Default to OFF since OrcaSlicer forces GDK_BACKEND=x11 (using GLX contexts).
# GLEW must use glXGetProcAddressARB (GLX) to match wxWidgets GL canvas.
# Using EGL function loading with GLX contexts causes rendering failures.
option(GLEW_USE_EGL "Use EGL instead of GLX for OpenGL function loading" OFF)
if(GLEW_USE_EGL)
message(STATUS "Building GLEW with EGL support")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGLEW_EGL")
else()
message(STATUS "Building GLEW with GLX support")
endif()
add_library(GLEW src/glew.c)

View File

@@ -51,6 +51,7 @@ orcaslicer_add_cmake_project(
-DwxUSE_UNICODE=ON
-DwxUSE_PRIVATE_FONTS=ON
-DwxUSE_OPENGL=ON
-DwxUSE_GLCANVAS_EGL=OFF
-DwxUSE_WEBREQUEST=ON
-DwxUSE_WEBVIEW=ON
${_wx_edge}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "Afinia",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Afinia configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Anker",
"version": "02.03.01.20",
"version": "02.03.02.40",
"force_update": "0",
"description": "Anker configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Anycubic",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Anycubic configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Artillery",
"version": "02.03.02.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Artillery configurations",
"machine_model_list": [

View File

@@ -1,7 +1,7 @@
{
"name": "Bambulab",
"url": "http://www.bambulab.com/Parameters/vendor/BBL.json",
"version": "02.00.00.56",
"version": "02.01.00.00",
"force_update": "0",
"description": "the initial version of BBL configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "BIQU",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "BIQU configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Blocks",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Blocks configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "CONSTRUCT3D",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Construct3D configurations",
"machine_model_list": [

View File

@@ -1,7 +1,7 @@
{
"name": "Chuanying",
"url": "",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Chuanying configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Co Print",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "CoPrint configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "CoLiDo",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "CoLiDo configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Comgrow",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Comgrow configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Creality",
"version": "02.03.01.20",
"version": "02.03.02.40",
"force_update": "0",
"description": "Creality configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Cubicon",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Cubicon configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Custom Printer",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "My configurations",
"machine_model_list": [

View File

@@ -1,7 +1,7 @@
{
"name": "DeltaMaker",
"url": "",
"version": "02.03.01.11",
"version": "02.03.02.40",
"force_update": "0",
"description": "DeltaMaker configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Dremel",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Dremel configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Elegoo",
"version": "02.03.01.20",
"version": "02.03.02.40",
"force_update": "0",
"description": "Elegoo configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Eryone",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Eryone configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "FLSun",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "FLSun configurations",
"machine_model_list": [

View File

@@ -1,7 +1,7 @@
{
"name": "Flashforge",
"url": "",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Flashforge configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "FlyingBear",
"version": "02.03.01.00",
"version": "02.03.02.40",
"force_update": "1",
"description": "FlyingBear configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Folgertech",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Folgertech configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Geeetech",
"version": "02.03.01.11",
"version": "02.03.02.40",
"force_update": "0",
"description": "Geeetech configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Ginger Additive",
"version": "02.03.01.11",
"version": "02.03.02.40",
"force_update": "1",
"description": "Ginger configuration",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "InfiMech",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "1",
"description": "InfiMech configurations",
"machine_model_list": [

View File

@@ -1,7 +1,7 @@
{
"name": "Kingroon",
"url": "https://kingroon.com/",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "1",
"description": "Kingroon configuration files",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "LONGER",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "LONGER configurations",
"machine_model_list": [

View File

@@ -1,7 +1,7 @@
{
"name": "Lulzbot",
"url": "https://ohai.lulzbot.com/group/taz-6/",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Lulzbot configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "M3D",
"version": "1.0.0",
"version": "02.03.02.40",
"force_update": "0",
"description": "Configuration for M3D printers",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "MagicMaker",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "MagicMaker configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Mellow",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Mellow Printer Profiles",
"machine_model_list": [

View File

@@ -1,7 +1,7 @@
{
"name": "OpenEYE",
"url": "http://www.openeye.tech",
"version": "01.00.00.03",
"version": "02.03.02.40",
"force_update": "0",
"description": "OpenEYE Printers Configurations",
"machine_model_list": [

View File

@@ -1,7 +1,7 @@
{
"name": "Orca Arena Printer",
"url": "",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Orca Arena configuration files",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "OrcaFilamentLibrary",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Orca Filament Library",
"filament_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Peopoly",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Peopoly configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Phrozen",
"version": "02.03.01.11",
"version": "02.03.02.40",
"force_update": "0",
"description": "Phrozen configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Positron 3D",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Positron 3D Printer Profile",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Prusa",
"version": "02.03.01.11",
"version": "02.03.02.40",
"force_update": "0",
"description": "Prusa configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Qidi",
"version": "02.03.01.20",
"version": "02.03.02.40",
"force_update": "0",
"description": "Qidi configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "RH3D",
"version": "00.06.10.25",
"version": "02.03.02.40",
"force_update": "0",
"description": "RH3D - printer profiles",
"machine_model_list": [

View File

@@ -1,7 +1,7 @@
{
"name": "Raise3D",
"url": "",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Raise3D configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "RatRig",
"version": "02.03.01.11",
"version": "02.03.02.40",
"force_update": "0",
"description": "RatRig configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "RolohaunDesign",
"version": "02.03.02.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "RolohaunDesign Printer Profiles",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "SecKit",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "SecKit configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Snapmaker",
"version": "02.03.01.20",
"version": "02.03.02.40",
"force_update": "0",
"description": "Snapmaker configurations",
"machine_model_list": [

View File

@@ -1,7 +1,7 @@
{
"name": "Sovol",
"url": "",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Sovol configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Tiertime",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Tiertime configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Tronxy",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Tronxy configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "TwoTrees",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "1",
"description": "TwoTrees configurations",
"machine_model_list": [

View File

@@ -1,7 +1,7 @@
{
"name": "UltiMaker",
"url": "",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "UltiMaker configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Vivedino",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Vivedino configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Volumic",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "1",
"description": "VOLUMIC configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Voron",
"version": "02.03.01.11",
"version": "02.03.02.40",
"force_update": "0",
"description": "Voron configurations",
"machine_model_list": [

View File

@@ -1,7 +1,7 @@
{
"name": "Voxelab",
"url": "",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Voxelab configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Vzbot",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Vzbot configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "WEMAKE3D",
"version": "02.03.01.20",
"version": "02.03.02.40",
"force_update": "0",
"description": "WEMAKE3D configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Wanhao France",
"version": "02.03.01.11",
"version": "02.03.02.40",
"force_update": "0",
"description": "Wanhao France D12 configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "Wanhao",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Wanhao configurations",
"machine_model_list": [

View File

@@ -1,7 +1,7 @@
{
"name": "WonderMaker",
"url": "",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "WonderMaker configurations",
"machine_model_list": [

View File

@@ -1,7 +1,7 @@
{
"name": "Z-Bolt",
"url": "",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "0",
"description": "Z-Bolt configurations",
"machine_model_list": [

View File

@@ -1,6 +1,6 @@
{
"name": "innovatiQ",
"version": "02.03.01.10",
"version": "02.03.02.40",
"force_update": "1",
"description": "innovatiQ configuration",
"machine_model_list": [

View File

@@ -9288,6 +9288,61 @@ void DynamicPrintConfig::update_values_to_printer_extruders_for_multiple_filamen
}
}
namespace {
// Options in printer_options_with_variant_2 are stored as (normal,silent) pairs per printer variant.
// Some legacy presets/projects carry a variant list but still store only one pair; normalize to avoid crashes.
static void normalize_stride2_floats(ConfigOptionFloats &opt, size_t expected_size)
{
auto &v = opt.values;
if (expected_size == 0) {
v.clear();
return;
}
if (v.empty()) {
// Fallback: keep behavior predictable instead of crashing. This should be rare.
v.resize(expected_size, 0.0);
return;
}
const double first = v[0];
const double second = (v.size() >= 2) ? v[1] : first;
// Ensure we have at least one (normal,silent) pair to replicate.
if (v.size() < 2) {
v.resize(2, first);
v[1] = second;
}
// Keep pair alignment if some legacy preset produced odd length.
if (v.size() % 2 != 0)
v.push_back(second);
if (v.size() > expected_size) {
v.resize(expected_size);
return;
}
const size_t have_variants = v.size() / 2;
const size_t want_variants = expected_size / 2;
v.resize(expected_size);
for (size_t vi = have_variants; vi < want_variants; ++vi) {
v[vi * 2] = first;
if (vi * 2 + 1 < v.size())
v[vi * 2 + 1] = second;
}
}
static void log_normalize_legacy_vector_size(const char *fn, const std::string &key, int stride, size_t src_size, size_t dest_size, size_t expected_size,
size_t restore_n, int cur_variant_count, int target_variant_count, size_t cur_ids, size_t target_ids,
const ConfigOption *opt_src, const ConfigOption *opt_target)
{
BOOST_LOG_TRIVIAL(debug) << fn << ": normalizing legacy vector size for key '" << key << "'"
<< " stride=" << stride << " src_size=" << src_size << " dest_size=" << dest_size << " expected=" << expected_size
<< " restore_index.size=" << restore_n << " cur_variants=" << cur_variant_count << " target_variants=" << target_variant_count
<< " cur_ids=" << cur_ids << " target_ids=" << target_ids << " cur_value=" << opt_src->serialize()
<< " target_value=" << opt_target->serialize();
}
} // namespace
void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfig& new_config, const t_config_option_keys& keys, const std::set<std::string>& different_keys,
std::string extruder_id_name, std::string extruder_variant_name, std::set<std::string>& key_set1, std::set<std::string>& key_set2)
{
@@ -9310,7 +9365,10 @@ void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfi
variant_index.resize(target_variant_count, -1);
if (cur_variant_count == 0) {
variant_index[0] = 0;
// Defensive: target_variant_count may be 0 if the preset doesn't carry extruder_variant_name.
// In that case keep variant_index empty and let the downstream size checks produce a useful error.
if (!variant_index.empty())
variant_index[0] = 0;
}
else if ((cur_extruder_ids.size() > 0) && cur_variant_count != cur_extruder_ids.size()){
//should not happen
@@ -9352,12 +9410,53 @@ void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfi
//nothing to do, keep the original one
}
else {
ConfigOptionVectorBase* opt_vec_src = static_cast<ConfigOptionVectorBase*>(opt_src);
const ConfigOptionVectorBase* opt_vec_dest = static_cast<const ConfigOptionVectorBase*>(opt_target);
int stride = 1;
if (key_set2.find(opt) != key_set2.end())
stride = 2;
opt_vec_src->set_with_restore(opt_vec_dest, variant_index, stride);
const size_t restore_n = variant_index.size();
const size_t expected_size = restore_n * size_t(stride);
if (stride == 2) {
// Options in key_set2 are machine limits stored as (normal,silent) pairs per printer variant.
if (opt_src->type() != coFloats || opt_target->type() != coFloats)
throw ConfigurationError((boost::format("%1%: key '%2%' is expected to be ConfigOptionFloats for stride=2.") % __FUNCTION__ % opt).str());
auto *src_f = static_cast<ConfigOptionFloats*>(opt_src);
ConfigOptionFloats rhs_tmp(*static_cast<const ConfigOptionFloats*>(opt_target));
const size_t src_size = src_f->values.size();
const size_t dest_size = rhs_tmp.values.size();
if (src_size != expected_size || dest_size != expected_size)
log_normalize_legacy_vector_size(__FUNCTION__, opt, stride, src_size, dest_size, expected_size, restore_n, cur_variant_count,
target_variant_count, cur_extruder_ids.size(), target_extruder_ids.size(), opt_src, opt_target);
// Normalize src in-place so backup_values indexing is safe, normalize rhs via a temporary copy.
normalize_stride2_floats(*src_f, expected_size);
normalize_stride2_floats(rhs_tmp, expected_size);
src_f->set_with_restore(&rhs_tmp, variant_index, stride);
} else {
ConfigOptionVectorBase* opt_vec_src = static_cast<ConfigOptionVectorBase*>(opt_src);
const size_t src_size = opt_vec_src->size();
const size_t dest_size = static_cast<const ConfigOptionVectorBase*>(opt_target)->size();
if (src_size != expected_size || dest_size != expected_size)
log_normalize_legacy_vector_size(__FUNCTION__, opt, stride, src_size, dest_size, expected_size, restore_n, cur_variant_count,
target_variant_count, cur_extruder_ids.size(), target_extruder_ids.size(), opt_src, opt_target);
if (opt_vec_src->size() != expected_size)
opt_vec_src->resize(expected_size, opt_target);
// Normalize rhs via a cloned temporary (rhs itself is const).
ConfigOptionUniquePtr rhs_owner(opt_target->clone());
ConfigOptionVectorBase *rhs_vec = dynamic_cast<ConfigOptionVectorBase*>(rhs_owner.get());
if (rhs_vec == nullptr)
throw ConfigurationError((boost::format("%1%: key '%2%' is expected to be a vector option.") % __FUNCTION__ % opt).str());
if (rhs_vec->size() != expected_size)
rhs_vec->resize(expected_size, opt_target);
opt_vec_src->set_with_restore(rhs_vec, variant_index, stride);
}
}
}
}

View File

@@ -25,6 +25,18 @@
#include "../Utils/MacDarkMode.hpp"
#endif // __APPLE__
// Verify GLEW and wxWidgets use the same OpenGL backend (EGL vs GLX).
// A mismatch causes rendering failures: GLEW's function loading must match
// the context type created by wxWidgets.
#if defined(__linux__)
#if defined(GLEW_EGL) && (!defined(wxUSE_GLCANVAS_EGL) || !wxUSE_GLCANVAS_EGL)
#error "OpenGL backend mismatch: GLEW has EGL support enabled but wxWidgets does not. Ensure GLEW_USE_EGL and wxUSE_GLCANVAS_EGL are both ON or both OFF."
#endif
#if !defined(GLEW_EGL) && defined(wxUSE_GLCANVAS_EGL) && wxUSE_GLCANVAS_EGL
#error "OpenGL backend mismatch: wxWidgets has EGL support enabled but GLEW does not. Ensure GLEW_USE_EGL and wxUSE_GLCANVAS_EGL are both ON or both OFF."
#endif
#endif
namespace Slic3r {
namespace GUI {

View File

@@ -1,7 +1,7 @@
#include "CalibUtils.hpp"
#include "../GUI/I18N.hpp"
#include "../GUI/GUI_App.hpp"
#include "../GUI/DeviceCore/DevStorage.h"
#include "../GUI/DeviceCore/DevStorage.h"
#include "../GUI/DeviceManager.hpp"
#include "../GUI/Jobs/ProgressIndicator.hpp"
#include "../GUI/PartPlate.hpp"

View File

@@ -461,42 +461,6 @@ void MoonrakerPrinterAgent::build_ams_payload(int ams_count, int max_lane_index,
return;
}
// Color normalization helper (handles #RRGGBB, 0xRRGGBB -> RRGGBBAA)
auto normalize_color = [](const std::string& color) -> std::string {
std::string value = color;
boost::trim(value);
// Remove 0x or 0X prefix if present
if (value.size() >= 2 && (value.rfind("0x", 0) == 0 || value.rfind("0X", 0) == 0)) {
value = value.substr(2);
}
// Remove # prefix if present
if (!value.empty() && value[0] == '#') {
value = value.substr(1);
}
// Extract only hex digits
std::string normalized;
for (char c : value) {
if (std::isxdigit(static_cast<unsigned char>(c))) {
normalized.push_back(static_cast<char>(std::toupper(static_cast<unsigned char>(c))));
}
}
// If 6 hex digits, add FF alpha
if (normalized.size() == 6) {
normalized += "FF";
}
// Validate length - return default if invalid
if (normalized.size() != 8) {
return "00000000";
}
return normalized;
};
// Build BBL-format JSON for DevFilaSystemParser::ParseV1_0
nlohmann::json ams_json = nlohmann::json::object();
nlohmann::json ams_array = nlohmann::json::array();
@@ -535,7 +499,7 @@ void MoonrakerPrinterAgent::build_ams_payload(int ams_count, int max_lane_index,
tray_json["tray_info_idx"] = tray->tray_info_idx;
tray_json["tray_type"] = tray->tray_type;
tray_json["tray_color"] = normalize_color(tray->tray_color);
tray_json["tray_color"] = normalize_color_value(tray->tray_color);
// Add temperature data if provided
if (tray->bed_temp > 0) {
@@ -604,119 +568,30 @@ void MoonrakerPrinterAgent::build_ams_payload(int ams_count, int max_lane_index,
bool MoonrakerPrinterAgent::fetch_filament_info(std::string dev_id)
{
// Fetch AFC lane data from Moonraker database (inline)
std::string url = join_url(device_info.base_url, "/server/database/item?namespace=lane_data");
std::string response_body;
bool success = false;
std::string http_error;
auto http = Http::get(url);
if (!device_info.api_key.empty()) {
http.header("X-Api-Key", device_info.api_key);
}
http.timeout_connect(5)
.timeout_max(10)
.on_complete([&](std::string body, unsigned status) {
if (status == 200) {
response_body = body;
success = true;
} else {
http_error = "HTTP error: " + std::to_string(status);
}
})
.on_error([&](std::string body, std::string err, unsigned status) {
http_error = err;
if (status > 0) {
http_error += " (HTTP " + std::to_string(status) + ")";
}
})
.perform_sync();
if (!success) {
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_filament_info: Failed to fetch lane data: " << http_error;
return false;
}
auto json = nlohmann::json::parse(response_body, nullptr, false, true);
if (json.is_discarded()) {
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_filament_info: Invalid JSON response";
return false;
}
// Expected structure: { "result": { "namespace": "lane_data", "value": { "lane1": {...}, ... } } }
if (!json.contains("result") || !json["result"].contains("value") || !json["result"]["value"].is_object()) {
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_filament_info: Unexpected JSON structure or no lane_data found";
return false;
}
// Parse response into AmsTrayData
const auto& value = json["result"]["value"];
std::vector<AmsTrayData> trays;
int max_lane_index = 0;
// Null-safe JSON accessors: nlohmann::json::value() throws type_error
// when the key exists but the value is null (type mismatch).
auto safe_string = [](const nlohmann::json& obj, const char* key) -> std::string {
auto it = obj.find(key);
if (it != obj.end() && it->is_string())
return it->get<std::string>();
return "";
};
auto safe_int = [](const nlohmann::json& obj, const char* key) -> int {
auto it = obj.find(key);
if (it != obj.end() && it->is_number())
return it->get<int>();
return 0;
};
for (const auto& [lane_key, lane_obj] : value.items()) {
if (!lane_obj.is_object()) {
continue;
}
// Extract lane index from the "lane" field (tool number, 0-based)
std::string lane_str = safe_string(lane_obj, "lane");
int lane_index = -1;
if (!lane_str.empty()) {
try {
lane_index = std::stoi(lane_str);
} catch (...) {
lane_index = -1;
}
}
if (lane_index < 0) {
continue;
}
AmsTrayData tray;
tray.slot_index = lane_index;
tray.tray_color = safe_string(lane_obj, "color");
tray.tray_type = safe_string(lane_obj, "material");
tray.bed_temp = safe_int(lane_obj, "bed_temp");
tray.nozzle_temp = safe_int(lane_obj, "nozzle_temp");
tray.has_filament = !tray.tray_type.empty();
auto* bundle = GUI::wxGetApp().preset_bundle;
tray.tray_info_idx = bundle
? bundle->filaments.filament_id_by_type(tray.tray_type)
: map_filament_type_to_generic_id(tray.tray_type);
max_lane_index = std::max(max_lane_index, lane_index);
trays.push_back(tray);
// Try Happy Hare first (more widely adopted, supports more filament changers)
if (fetch_hh_filament_info(trays, max_lane_index)) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: Detected Happy Hare MMU with "
<< (max_lane_index + 1) << " gates";
int ams_count = (max_lane_index + 4) / 4;
build_ams_payload(ams_count, max_lane_index, trays);
return true;
}
if (trays.empty()) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: No AFC lanes found";
return false;
// Fallback to AFC
if (fetch_afc_filament_info(trays, max_lane_index)) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: Detected AFC with "
<< (max_lane_index + 1) << " lanes";
int ams_count = (max_lane_index + 4) / 4;
build_ams_payload(ams_count, max_lane_index, trays);
return true;
}
// Calculate AMS count from max lane index (4 trays per AMS unit)
int ams_count = (max_lane_index + 4) / 4;
// Build and parse the AMS payload
build_ams_payload(ams_count, max_lane_index, trays);
return true;
// No MMU detected - this is normal for printers without MMU, not an error
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: No MMU system detected (neither HH nor AFC)";
return false;
}
std::string MoonrakerPrinterAgent::trim_and_upper(const std::string& input)
@@ -780,6 +655,298 @@ std::string MoonrakerPrinterAgent::map_filament_type_to_generic_id(const std::st
return UNKNOWN_FILAMENT_ID;
}
// JSON helper methods - null-safe accessors
std::string MoonrakerPrinterAgent::safe_json_string(const nlohmann::json& obj, const char* key)
{
auto it = obj.find(key);
if (it != obj.end() && it->is_string())
return it->get<std::string>();
return "";
}
int MoonrakerPrinterAgent::safe_json_int(const nlohmann::json& obj, const char* key)
{
auto it = obj.find(key);
if (it != obj.end() && it->is_number())
return it->get<int>();
return 0;
}
std::string MoonrakerPrinterAgent::safe_array_string(const nlohmann::json& arr, int idx)
{
if (arr.is_array() && idx >= 0 && idx < static_cast<int>(arr.size()) && arr[idx].is_string())
return arr[idx].get<std::string>();
return "";
}
int MoonrakerPrinterAgent::safe_array_int(const nlohmann::json& arr, int idx)
{
if (arr.is_array() && idx >= 0 && idx < static_cast<int>(arr.size()) && arr[idx].is_number())
return arr[idx].get<int>();
return 0;
}
std::string MoonrakerPrinterAgent::normalize_color_value(const std::string& color)
{
std::string value = color;
boost::trim(value);
// Remove 0x or 0X prefix if present
if (value.size() >= 2 && (value.rfind("0x", 0) == 0 || value.rfind("0X", 0) == 0)) {
value = value.substr(2);
}
// Remove # prefix if present
if (!value.empty() && value[0] == '#') {
value = value.substr(1);
}
// Extract only hex digits
std::string normalized;
for (char c : value) {
if (std::isxdigit(static_cast<unsigned char>(c))) {
normalized.push_back(static_cast<char>(std::toupper(static_cast<unsigned char>(c))));
}
}
// If 6 hex digits, add FF alpha
if (normalized.size() == 6) {
normalized += "FF";
}
// Validate length - return default if invalid
if (normalized.size() != 8) {
return "00000000";
}
return normalized;
}
// Fetch filament info from Armored Turtle AFC
bool MoonrakerPrinterAgent::fetch_afc_filament_info(std::vector<AmsTrayData>& trays, int& max_lane_index)
{
// Fetch AFC lane data from Moonraker database
std::string url = join_url(device_info.base_url, "/server/database/item?namespace=lane_data");
std::string response_body;
bool success = false;
std::string http_error;
auto http = Http::get(url);
if (!device_info.api_key.empty()) {
http.header("X-Api-Key", device_info.api_key);
}
http.timeout_connect(5)
.timeout_max(10)
.on_complete([&](std::string body, unsigned status) {
if (status == 200) {
response_body = body;
success = true;
} else {
http_error = "HTTP error: " + std::to_string(status);
}
})
.on_error([&](std::string body, std::string err, unsigned status) {
http_error = err;
if (status > 0) {
http_error += " (HTTP " + std::to_string(status) + ")";
}
})
.perform_sync();
if (!success) {
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_afc_filament_info: Failed to fetch lane data: " << http_error;
return false;
}
auto json = nlohmann::json::parse(response_body, nullptr, false, true);
if (json.is_discarded()) {
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_afc_filament_info: Invalid JSON response";
return false;
}
// Expected structure: { "result": { "namespace": "lane_data", "value": { "lane1": {...}, ... } } }
if (!json.contains("result") || !json["result"].contains("value") || !json["result"]["value"].is_object()) {
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_afc_filament_info: Unexpected JSON structure or no lane_data found";
return false;
}
// Parse response into AmsTrayData
const auto& value = json["result"]["value"];
trays.clear();
max_lane_index = 0;
for (const auto& [lane_key, lane_obj] : value.items()) {
if (!lane_obj.is_object()) {
continue;
}
// Extract lane index from the "lane" field (tool number, 0-based)
std::string lane_str = safe_json_string(lane_obj, "lane");
int lane_index = -1;
if (!lane_str.empty()) {
try {
lane_index = std::stoi(lane_str);
} catch (...) {
lane_index = -1;
}
}
if (lane_index < 0) {
continue;
}
AmsTrayData tray;
tray.slot_index = lane_index;
tray.tray_color = safe_json_string(lane_obj, "color");
tray.tray_type = safe_json_string(lane_obj, "material");
tray.bed_temp = safe_json_int(lane_obj, "bed_temp");
tray.nozzle_temp = safe_json_int(lane_obj, "nozzle_temp");
tray.has_filament = !tray.tray_type.empty();
auto* bundle = GUI::wxGetApp().preset_bundle;
tray.tray_info_idx = bundle
? bundle->filaments.filament_id_by_type(tray.tray_type)
: map_filament_type_to_generic_id(tray.tray_type);
max_lane_index = std::max(max_lane_index, lane_index);
trays.push_back(tray);
}
if (trays.empty()) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_afc_filament_info: No AFC lanes found";
return false;
}
return true;
}
// Fetch filament info from Happy Hare MMU
bool MoonrakerPrinterAgent::fetch_hh_filament_info(std::vector<AmsTrayData>& trays, int& max_lane_index)
{
// Query Happy Hare MMU status
std::string url = join_url(device_info.base_url, "/printer/objects/query?mmu");
std::string response_body;
bool success = false;
std::string http_error;
auto http = Http::get(url);
if (!device_info.api_key.empty()) {
http.header("X-Api-Key", device_info.api_key);
}
http.timeout_connect(5)
.timeout_max(10)
.on_complete([&](std::string body, unsigned status) {
if (status == 200) {
response_body = body;
success = true;
} else {
http_error = "HTTP error: " + std::to_string(status);
}
})
.on_error([&](std::string body, std::string err, unsigned status) {
http_error = err;
if (status > 0) {
http_error += " (HTTP " + std::to_string(status) + ")";
}
})
.perform_sync();
if (!success) {
BOOST_LOG_TRIVIAL(debug) << "MoonrakerPrinterAgent::fetch_hh_filament_info: Failed to fetch HH data: " << http_error;
return false;
}
auto json = nlohmann::json::parse(response_body, nullptr, false, true);
if (json.is_discarded()) {
BOOST_LOG_TRIVIAL(debug) << "MoonrakerPrinterAgent::fetch_hh_filament_info: Invalid JSON response";
return false;
}
// Expected structure: { "result": { "status": { "mmu": { ... } } } }
if (!json.contains("result") || !json["result"].contains("status") ||
!json["result"]["status"].contains("mmu") || !json["result"]["status"]["mmu"].is_object()) {
BOOST_LOG_TRIVIAL(debug) << "MoonrakerPrinterAgent::fetch_hh_filament_info: No mmu object in response";
return false;
}
const auto& mmu = json["result"]["status"]["mmu"];
// Check if HH is installed (empty mmu object means HH not installed)
if (mmu.empty()) {
BOOST_LOG_TRIVIAL(debug) << "MoonrakerPrinterAgent::fetch_hh_filament_info: Empty mmu object (HH not installed)";
return false;
}
// Get num_gates
if (!mmu.contains("num_gates") || !mmu["num_gates"].is_number()) {
BOOST_LOG_TRIVIAL(debug) << "MoonrakerPrinterAgent::fetch_hh_filament_info: No num_gates field";
return false;
}
int num_gates = mmu["num_gates"].get<int>();
if (num_gates <= 0) {
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_hh_filament_info: Invalid num_gates: " << num_gates;
return false;
}
// Get arrays
const auto& gate_status = mmu.contains("gate_status") ? mmu["gate_status"] : nlohmann::json::array();
const auto& gate_material = mmu.contains("gate_material") ? mmu["gate_material"] : nlohmann::json::array();
const auto& gate_color = mmu.contains("gate_color") ? mmu["gate_color"] : nlohmann::json::array();
const auto& gate_temperature = mmu.contains("gate_temperature") ? mmu["gate_temperature"] : nlohmann::json::array();
if (!gate_status.is_array() || !gate_material.is_array() ||
!gate_color.is_array() || !gate_temperature.is_array()) {
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_hh_filament_info: HH arrays not found or invalid type";
return false;
}
// Parse gate data
trays.clear();
max_lane_index = 0;
for (int gate_idx = 0; gate_idx < num_gates; ++gate_idx) {
// Check gate_status: -1 = unknown, 0 = empty, 1 or 2 = available
int status = safe_array_int(gate_status, gate_idx);
if (status <= 0) {
continue; // Skip unknown or empty gates
}
// Extract gate data
std::string material = safe_array_string(gate_material, gate_idx);
std::string color = safe_array_string(gate_color, gate_idx);
int nozzle_temp = safe_array_int(gate_temperature, gate_idx);
// Skip if no material type (empty gate)
if (material.empty()) {
continue;
}
AmsTrayData tray;
tray.slot_index = gate_idx;
tray.tray_type = material;
tray.tray_color = color;
tray.nozzle_temp = nozzle_temp;
tray.bed_temp = 0; // HH doesn't provide bed temp in gate arrays
tray.has_filament = true;
auto* bundle = GUI::wxGetApp().preset_bundle;
tray.tray_info_idx = bundle
? bundle->filaments.filament_id_by_type(tray.tray_type)
: map_filament_type_to_generic_id(tray.tray_type);
max_lane_index = std::max(max_lane_index, gate_idx);
trays.push_back(tray);
}
if (trays.empty()) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_hh_filament_info: No valid HH gates found";
return false;
}
return true;
}
int MoonrakerPrinterAgent::handle_request(const std::string& dev_id, const std::string& json_str)
{
auto json = nlohmann::json::parse(json_str, nullptr, false);

View File

@@ -160,6 +160,17 @@ private:
const std::string& api_key,
uint64_t generation);
// System-specific filament fetch methods
bool fetch_hh_filament_info(std::vector<AmsTrayData>& trays, int& max_lane_index);
bool fetch_afc_filament_info(std::vector<AmsTrayData>& trays, int& max_lane_index);
// JSON helper methods
static std::string safe_json_string(const nlohmann::json& obj, const char* key);
static int safe_json_int(const nlohmann::json& obj, const char* key);
static std::string safe_array_string(const nlohmann::json& arr, int idx);
static int safe_array_int(const nlohmann::json& arr, int idx);
static std::string normalize_color_value(const std::string& color);
std::string ssdp_announced_host;
std::string ssdp_announced_id;
std::shared_ptr<ICloudServiceAgent> m_cloud_agent;

View File

@@ -7,7 +7,7 @@ set(SLIC3R_APP_KEY "OrcaSlicer")
if(NOT DEFINED BBL_INTERNAL_TESTING)
set(BBL_INTERNAL_TESTING "0")
endif()
set(SoftFever_VERSION "2.3.2-beta")
set(SoftFever_VERSION "2.3.2-beta2")
string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)"
SoftFever_VERSION_MATCH ${SoftFever_VERSION})
set(ORCA_VERSION_MAJOR ${CMAKE_MATCH_1})