mirror of
https://github.com/ClusterM/open-bamboo-networking.git
synced 2026-10-19 01:29:46 -05:00
432 lines
16 KiB
PowerShell
432 lines
16 KiB
PowerShell
# Open Bamboo Networking -- interactive installer for Windows.
|
|
# Ships inside the distribution archive next to lib\vXX.XX.XX\ directories.
|
|
# Detects the slicer, matches the ABI version, copies binaries, patches
|
|
# the slicer conf, and registers the DirectShow filter.
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
# Path to the slicer executable (e.g. the bambu-studio.exe of a manually
|
|
# unzipped/portable build). Its FileVersion is used for ABI detection —
|
|
# preferred over the registry, which is stale/absent for such installs.
|
|
[string]$StudioExe = "",
|
|
|
|
# Force the ABI version literally instead of auto-detecting, e.g.
|
|
# -Version 02.08.03 . Use -StudioExe instead when you can point at the exe.
|
|
[string]$Version = ""
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
function Write-Info { param([string]$msg) Write-Host " [info] $msg" -ForegroundColor Green }
|
|
function Write-Warn { param([string]$msg) Write-Host " [warn] $msg" -ForegroundColor Yellow }
|
|
function Write-Err { param([string]$msg) Write-Host " [error] $msg" -ForegroundColor Red }
|
|
|
|
function Wait-And-Exit {
|
|
param([int]$code = 1)
|
|
if ($Host.Name -eq "ConsoleHost") {
|
|
Write-Host ""
|
|
Write-Host "Press any key to exit..."
|
|
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
|
}
|
|
exit $code
|
|
}
|
|
|
|
function IsValidVersion {
|
|
param([string]$v)
|
|
return $v -match '^\d+(\.\d+){2,3}$'
|
|
}
|
|
|
|
# Windows PowerShell 5.1 ConvertFrom-Json cannot build a PSCustomObject
|
|
# property with an empty name. OrcaSlicer.conf contains valid JSON keys
|
|
# like "access_code": {"": "..."}. Swap those keys for a sentinel around
|
|
# the parse/serialize round-trip, then put "" back.
|
|
$script:ObnEmptyJsonKey = "__OBN_EMPTY_JSON_KEY__"
|
|
|
|
function Protect-EmptyJsonKeys {
|
|
param([string]$Json)
|
|
$name = '"' + $script:ObnEmptyJsonKey + '"'
|
|
return [regex]::Replace($Json, '""(\s*:)', ($name + '$1'))
|
|
}
|
|
|
|
function Restore-EmptyJsonKeys {
|
|
param([string]$Json)
|
|
$name = '"' + $script:ObnEmptyJsonKey + '"'
|
|
return $Json.Replace($name, '""')
|
|
}
|
|
|
|
# -- Client selection ------------------------------------------------------
|
|
|
|
Write-Host ""
|
|
Write-Host "Open Bamboo Networking - Installer" -ForegroundColor White
|
|
$VersionFile = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) "VERSION"
|
|
if (Test-Path $VersionFile) {
|
|
$VersionContent = (Get-Content -Path $VersionFile -Raw).Trim()
|
|
Write-Host " Build: $VersionContent"
|
|
}
|
|
Write-Host ""
|
|
Write-Host "Select your slicer:"
|
|
Write-Host " 1) Bambu Studio"
|
|
Write-Host " 2) Orca Slicer"
|
|
Write-Host ""
|
|
$choice = Read-Host "Choice [1]"
|
|
if ($choice -eq "2") {
|
|
$Client = "orca_slicer"
|
|
$ClientLabel = "Orca Slicer"
|
|
$ConfName = "OrcaSlicer.conf"
|
|
$VersionKey = "network_plugin_version"
|
|
$ClientDir = Join-Path $env:APPDATA "OrcaSlicer"
|
|
$DisplayName = "OrcaSlicer"
|
|
} else {
|
|
$Client = "bambu_studio"
|
|
$ClientLabel = "Bambu Studio"
|
|
$ConfName = "BambuStudio.conf"
|
|
$VersionKey = "version"
|
|
$DisplayName = "Bambu Studio"
|
|
|
|
$stableDir = Join-Path $env:APPDATA "BambuStudio"
|
|
$betaDir = Join-Path $env:APPDATA "BambuStudioBeta"
|
|
$hasStable = Test-Path $stableDir
|
|
$hasBeta = Test-Path $betaDir
|
|
|
|
if ($hasStable -and $hasBeta) {
|
|
Write-Host ""
|
|
Write-Host "Both Bambu Studio and Bambu Studio Beta configs found."
|
|
Write-Host " 1) Bambu Studio (stable)"
|
|
Write-Host " 2) Bambu Studio Beta"
|
|
Write-Host ""
|
|
$edition = Read-Host "Choice [1]"
|
|
if ($edition -eq "2") {
|
|
$ClientLabel = "Bambu Studio Beta"
|
|
$ClientDir = $betaDir
|
|
} else {
|
|
$ClientDir = $stableDir
|
|
}
|
|
} elseif ($hasBeta) {
|
|
$ClientLabel = "Bambu Studio Beta"
|
|
$ClientDir = $betaDir
|
|
} else {
|
|
$ClientDir = $stableDir
|
|
}
|
|
}
|
|
Write-Host ""
|
|
|
|
$Prefix = $ClientDir
|
|
|
|
if (-not (Test-Path $Prefix)) {
|
|
Write-Err "$ClientLabel config directory not found: $Prefix"
|
|
Write-Err "Launch $ClientLabel at least once to create its config, then re-run this installer."
|
|
Wait-And-Exit
|
|
}
|
|
|
|
$ConfPath = Join-Path $Prefix $ConfName
|
|
if (-not (Test-Path $ConfPath)) {
|
|
Write-Err "$ConfName not found at $ConfPath"
|
|
Write-Err "Launch $ClientLabel at least once to create its config, then re-run this installer."
|
|
Wait-And-Exit
|
|
}
|
|
|
|
# -- ABI version detection -------------------------------------------------
|
|
|
|
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$LibDir = Join-Path $ScriptDir "lib"
|
|
|
|
if (-not (Test-Path $LibDir)) {
|
|
Write-Err "lib\ directory not found next to this script"
|
|
Wait-And-Exit
|
|
}
|
|
|
|
if ($Client -eq "orca_slicer") {
|
|
# Orca Slicer: always use 02.03.00 ABI (the version Orca ships by default).
|
|
# The installer patches OrcaSlicer.conf to match, so the user does not need
|
|
# to pick a specific network_plugin_version in Preferences.
|
|
$AbiPrefix = "02.03.00"
|
|
$detectedSource = "fixed"
|
|
} else {
|
|
# Bambu Studio: detect from exe version in the registry.
|
|
function Detect-VersionFromConf {
|
|
param([string]$ConfPath, [string]$Key)
|
|
if (-not (Test-Path $ConfPath)) { return "" }
|
|
$line = Select-String -Path $ConfPath `
|
|
-Pattern "`"$Key`"\s*:\s*`"([0-9][0-9.]*)`"" `
|
|
-ErrorAction SilentlyContinue |
|
|
Select-Object -First 1
|
|
if ($line -and $line.Matches.Count -gt 0 -and $line.Matches[0].Groups.Count -ge 2) {
|
|
return $line.Matches[0].Groups[1].Value
|
|
}
|
|
return ""
|
|
}
|
|
|
|
function Detect-VersionFromExe {
|
|
param([string]$Name)
|
|
$regPaths = @(
|
|
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
|
|
'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*',
|
|
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
|
|
)
|
|
$entries = Get-ItemProperty -Path $regPaths -ErrorAction SilentlyContinue |
|
|
Where-Object { $_.PSObject.Properties['DisplayName'] -and $_.DisplayName -eq $Name }
|
|
foreach ($e in $entries) {
|
|
$exe = $null
|
|
if ($e.DisplayIcon) {
|
|
$candidate = ($e.DisplayIcon -split ',')[0].Trim('"')
|
|
if (Test-Path $candidate) { $exe = $candidate }
|
|
}
|
|
if (-not $exe -and $e.InstallLocation) {
|
|
$base = ([System.IO.Path]::GetFileNameWithoutExtension($Name).ToLower() -replace ' ','-')
|
|
$candidate = Join-Path $e.InstallLocation ($base + '.exe')
|
|
if (Test-Path $candidate) { $exe = $candidate }
|
|
}
|
|
if ($exe) {
|
|
$fv = (Get-Item $exe).VersionInfo.FileVersion
|
|
if (IsValidVersion $fv) {
|
|
return $fv
|
|
}
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
$confVer = Detect-VersionFromConf -ConfPath $ConfPath -Key $VersionKey
|
|
$exeVer = Detect-VersionFromExe -Name $DisplayName
|
|
|
|
# -StudioExe / -Version override detection (manual/unzipped Studio not in
|
|
# the registry, or a stale registry entry from an older installed build).
|
|
if ($StudioExe) {
|
|
if (-not (Test-Path $StudioExe)) {
|
|
Write-Err "-StudioExe not found: $StudioExe"; Wait-And-Exit
|
|
}
|
|
$fv = (Get-Item $StudioExe).VersionInfo.FileVersion
|
|
if (-not (IsValidVersion $fv)) {
|
|
Write-Err "Cannot read a version from -StudioExe (FileVersion='$fv'): $StudioExe"
|
|
Wait-And-Exit
|
|
}
|
|
Write-Info "Using version $fv from $StudioExe"
|
|
$exeVer = $fv; $confVer = ""
|
|
} elseif ($Version) {
|
|
if (-not (IsValidVersion $Version)) {
|
|
Write-Err "Cannot parse -Version: $Version (expected 3 or 4 dotted numeric components)."
|
|
Wait-And-Exit
|
|
}
|
|
$exeVer = $Version; $confVer = ""
|
|
}
|
|
|
|
$detected = ""
|
|
if (-not [string]::IsNullOrEmpty($exeVer)) {
|
|
$detected = $exeVer
|
|
$detectedSource = "$ClientLabel v$detected"
|
|
} elseif (-not [string]::IsNullOrEmpty($confVer)) {
|
|
$detected = $confVer
|
|
$detectedSource = "$ClientLabel v$detected"
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($detected)) {
|
|
Write-Err "Cannot determine ABI version."
|
|
Write-Err "Launch $ClientLabel at least once, then re-run this installer."
|
|
Wait-And-Exit
|
|
}
|
|
|
|
if ($detected -match '^(\d+\.\d+\.\d+)') {
|
|
$AbiPrefix = $Matches[1]
|
|
} else {
|
|
Write-Err "Cannot parse version: $detected"
|
|
Wait-And-Exit
|
|
}
|
|
}
|
|
|
|
$PluginVer = "$AbiPrefix.99"
|
|
|
|
# -- Match available ABI directory -----------------------------------------
|
|
|
|
$MatchedDir = $null
|
|
$candidate = Join-Path $LibDir "v$AbiPrefix"
|
|
if (Test-Path $candidate) {
|
|
$MatchedDir = $candidate
|
|
}
|
|
|
|
if (-not $MatchedDir) {
|
|
$available = (Get-ChildItem -Path $LibDir -Directory -Filter "v*" |
|
|
Sort-Object Name |
|
|
ForEach-Object { $_.Name -replace '^v', '' }) -join ', '
|
|
if (-not $available) { $available = "none" }
|
|
Write-Err "No compatible ABI version for $detectedSource (need $AbiPrefix)."
|
|
Write-Err "Available in this package: $available"
|
|
Write-Err "You may need a newer distribution package from GitHub."
|
|
Wait-And-Exit
|
|
}
|
|
|
|
$MatchedVer = (Split-Path -Leaf $MatchedDir) -replace '^v', ''
|
|
$PluginVer = "$MatchedVer.99"
|
|
|
|
# -- Confirmation ---------------------------------------------------------
|
|
|
|
$DestDir = Join-Path $Prefix "plugins"
|
|
|
|
Write-Host "Installation summary:" -ForegroundColor White
|
|
Write-Host " Slicer: $ClientLabel"
|
|
Write-Host " Config dir: $Prefix"
|
|
Write-Host " ABI version: $MatchedVer ($detectedSource)"
|
|
Write-Host " Install to: $DestDir"
|
|
Write-Host ""
|
|
Write-Warn "Close $ClientLabel before proceeding. If it is running, it will overwrite the patched config on exit."
|
|
Write-Host ""
|
|
$confirm = Read-Host "Proceed? [Y/n]"
|
|
if ($confirm -match '^[Nn]') {
|
|
Write-Host "Aborted."
|
|
Wait-And-Exit -code 0
|
|
}
|
|
Write-Host ""
|
|
|
|
# -- Install binaries -----------------------------------------------------
|
|
|
|
New-Item -ItemType Directory -Force -Path $DestDir | Out-Null
|
|
|
|
if ($Client -eq "bambu_studio") {
|
|
$PluginDestName = "bambu_networking.dll"
|
|
} else {
|
|
$PluginDestName = "bambu_networking_$PluginVer.dll"
|
|
}
|
|
|
|
$srcPlugin = Join-Path $MatchedDir "bambu_networking.dll"
|
|
if (-not (Test-Path $srcPlugin)) {
|
|
Write-Err "Plugin binary not found in $MatchedDir"
|
|
Wait-And-Exit
|
|
}
|
|
Copy-Item -Path $srcPlugin -Destination (Join-Path $DestDir $PluginDestName) -Force
|
|
Write-Info "Installed $PluginDestName"
|
|
|
|
$srcSource = Join-Path $MatchedDir "BambuSource.dll"
|
|
if (Test-Path $srcSource) {
|
|
Copy-Item -Path $srcSource -Destination (Join-Path $DestDir "BambuSource.dll") -Force
|
|
Write-Info "Installed BambuSource.dll"
|
|
}
|
|
|
|
$srcLive = Join-Path $MatchedDir "live555.dll"
|
|
$dstLive = Join-Path $DestDir "live555.dll"
|
|
if (Test-Path $srcLive) {
|
|
$installLive = $true
|
|
if (Test-Path $dstLive) {
|
|
$existingSize = (Get-Item $dstLive).Length
|
|
if ($existingSize -gt 65536) {
|
|
$installLive = $false
|
|
Write-Info "Keeping existing live555.dll ($existingSize bytes, looks like vendor build)"
|
|
}
|
|
}
|
|
if ($installLive) {
|
|
Copy-Item -Path $srcLive -Destination $dstLive -Force
|
|
Write-Info "Installed live555.dll"
|
|
}
|
|
}
|
|
|
|
# OTA manifest (Bambu Studio only)
|
|
if ($Client -eq "bambu_studio") {
|
|
$srcJson = Join-Path $MatchedDir "network_plugins.json"
|
|
if (Test-Path $srcJson) {
|
|
$otaDir = Join-Path $Prefix "ota\plugins"
|
|
New-Item -ItemType Directory -Force -Path $otaDir | Out-Null
|
|
Copy-Item -Path $srcJson -Destination (Join-Path $otaDir "network_plugins.json") -Force
|
|
Write-Info "Installed ota\plugins\network_plugins.json"
|
|
}
|
|
}
|
|
|
|
# -- Patch slicer conf ----------------------------------------------------
|
|
|
|
if (Test-Path $ConfPath) {
|
|
try {
|
|
$raw = Get-Content -Path $ConfPath -Raw
|
|
$jsonBody = $raw -replace '[\r\n]+# MD5 checksum[^\r\n]*[\r\n]*$', ''
|
|
$conf = Protect-EmptyJsonKeys $jsonBody | ConvertFrom-Json
|
|
$changed = $false
|
|
|
|
if ($null -ne $conf.app) {
|
|
if ($Client -eq "bambu_studio") {
|
|
$studioPatches = @{
|
|
installed_networking = "1"
|
|
update_network_plugin = "false"
|
|
ignore_module_cert = "1"
|
|
}
|
|
} else {
|
|
$studioPatches = @{
|
|
installed_networking = "true"
|
|
network_plugin_version = $PluginVer
|
|
network_plugin_remind_later = "true"
|
|
ignore_module_cert = "1"
|
|
}
|
|
}
|
|
foreach ($k in $studioPatches.Keys) {
|
|
$current = $conf.app | Select-Object -ExpandProperty $k -ErrorAction SilentlyContinue
|
|
if ($current -ne $studioPatches[$k]) {
|
|
if ($null -eq ($conf.app | Get-Member -Name $k -MemberType NoteProperty)) {
|
|
$conf.app | Add-Member -NotePropertyName $k -NotePropertyValue $studioPatches[$k]
|
|
} else {
|
|
$conf.app.$k = $studioPatches[$k]
|
|
}
|
|
$changed = $true
|
|
}
|
|
}
|
|
if ($Client -eq "orca_slicer") {
|
|
$skipped = $conf.app | Select-Object -ExpandProperty network_plugin_skipped_versions -ErrorAction SilentlyContinue
|
|
if ($skipped -and $skipped.Contains($PluginVer)) {
|
|
$parts = ($skipped -split ';') | Where-Object { $_ -and $_ -ne $PluginVer }
|
|
$newSkipped = $parts -join ';'
|
|
$conf.app.network_plugin_skipped_versions = $newSkipped
|
|
$changed = $true
|
|
}
|
|
}
|
|
|
|
if ($changed) {
|
|
Copy-Item -Path $ConfPath -Destination "$ConfPath.obn-bak" -Force
|
|
$newJson = Restore-EmptyJsonKeys ($conf | ConvertTo-Json -Depth 20)
|
|
$newJson + "`n# MD5 checksum 00000000000000000000000000000000`n" |
|
|
Set-Content -Path $ConfPath -NoNewline
|
|
Write-Info "Patched $ConfName (backup: $ConfName.obn-bak)"
|
|
} else {
|
|
Write-Info "Slicer conf already patched, no changes needed"
|
|
}
|
|
} else {
|
|
Write-Warn "$ConfName has no 'app' object, skipping patch"
|
|
}
|
|
} catch {
|
|
Write-Warn "Could not parse $ConfName, skipping patch: $_"
|
|
}
|
|
} else {
|
|
Write-Err "$ConfName not found at $ConfPath"
|
|
Write-Err "Launch $ClientLabel at least once to create it, then re-run this installer."
|
|
Wait-And-Exit
|
|
}
|
|
|
|
# -- Register DirectShow filter -------------------------------------------
|
|
|
|
$bsDll = Join-Path $DestDir "BambuSource.dll"
|
|
if (Test-Path $bsDll) {
|
|
Write-Host ""
|
|
$regConfirm = Read-Host "Register BambuSource DirectShow filter for live camera? [Y/n]"
|
|
if ($regConfirm -notmatch '^[Nn]') {
|
|
$rc = (Start-Process regsvr32.exe -ArgumentList "/s `"$bsDll`"" -Wait -PassThru).ExitCode
|
|
if ($rc -eq 0) {
|
|
Write-Info "Registered BambuSource DirectShow filter (HKCU)"
|
|
} else {
|
|
Write-Warn "regsvr32 failed (rc=$rc); register manually: regsvr32 /s `"$bsDll`""
|
|
}
|
|
}
|
|
}
|
|
|
|
# -- Summary --------------------------------------------------------------
|
|
|
|
$ObnConf = Join-Path $Prefix "obn.conf"
|
|
|
|
Write-Host ""
|
|
Write-Host "Installation complete!" -ForegroundColor Green
|
|
Write-Host ""
|
|
Write-Host " Plugin: $(Join-Path $DestDir $PluginDestName)"
|
|
Write-Host " Config: $ObnConf"
|
|
Write-Host " Slicer: $ClientLabel ($Prefix)"
|
|
Write-Host ""
|
|
Write-Host "Next steps:"
|
|
Write-Host " 1. Launch $ClientLabel - it should load the open-bamboo-networking plugin"
|
|
Write-Host " 2. Edit $ObnConf to customize plugin behavior (created on first launch)"
|
|
Write-Host ""
|
|
Write-Host "GitHub: https://github.com/ClusterM/open-bamboo-networking" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
|
|
Wait-And-Exit -code 0
|