diff --git a/frontend/bindings/g-launcher/internal/app-service/appservice.js b/frontend/bindings/g-launcher/internal/app-service/appservice.js index c7fc0e6..c7e8ec9 100644 --- a/frontend/bindings/g-launcher/internal/app-service/appservice.js +++ b/frontend/bindings/g-launcher/internal/app-service/appservice.js @@ -10,7 +10,7 @@ import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Cr * @returns {$CancellablePromise<[boolean, string]>} */ export function CloseApp() { - return $Call.ByID(3422460836); + return $Call.ByID(1501559548); } /** @@ -18,40 +18,40 @@ export function CloseApp() { * @returns {$CancellablePromise<[boolean, string]>} */ export function CloseAppAfterTimeout(timeout) { - return $Call.ByID(1705931481, timeout); + return $Call.ByID(1916027393, timeout); } /** * @returns {$CancellablePromise<[boolean, string]>} */ export function GetCurrentLauncherVersion() { - return $Call.ByID(3575133982); + return $Call.ByID(1802499222); } /** * @returns {$CancellablePromise<[boolean, string]>} */ export function HideApp() { - return $Call.ByID(88003266); + return $Call.ByID(2987475338); } /** * @returns {$CancellablePromise<[boolean, string]>} */ export function MaximizeApp() { - return $Call.ByID(1257306588); + return $Call.ByID(1960157700); } /** * @returns {$CancellablePromise<[boolean, string]>} */ export function MinimizeApp() { - return $Call.ByID(3434614194); + return $Call.ByID(227494378); } /** * @returns {$CancellablePromise<[boolean, string]>} */ export function RestoreApp() { - return $Call.ByID(3115625834); + return $Call.ByID(229693554); } diff --git a/frontend/bindings/g-launcher/internal/diff-service/diffservice.js b/frontend/bindings/g-launcher/internal/diff-service/diffservice.js index a9eaec3..d440fd7 100644 --- a/frontend/bindings/g-launcher/internal/diff-service/diffservice.js +++ b/frontend/bindings/g-launcher/internal/diff-service/diffservice.js @@ -6,12 +6,21 @@ // @ts-ignore: Unused imports import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; +/** + * @param {string} gamePath + * @param {string} patchPath + * @returns {$CancellablePromise<[boolean, string]>} + */ +export function ApplyDiffZiff(gamePath, patchPath) { + return $Call.ByID(3398476317, gamePath, patchPath); +} + /** * @param {string} patchPath * @returns {$CancellablePromise<[boolean, string, string]>} */ export function CheckTypeHDiff(patchPath) { - return $Call.ByID(3717449114, patchPath); + return $Call.ByID(2449959810, patchPath); } /** @@ -19,7 +28,7 @@ export function CheckTypeHDiff(patchPath) { * @returns {$CancellablePromise<[boolean, string]>} */ export function CutData(gamePath) { - return $Call.ByID(2019290107, gamePath); + return $Call.ByID(279510819, gamePath); } /** @@ -28,7 +37,7 @@ export function CutData(gamePath) { * @returns {$CancellablePromise<[boolean, string]>} */ export function DataExtract(gamePath, patchPath) { - return $Call.ByID(2161622254, gamePath, patchPath); + return $Call.ByID(3151294534, gamePath, patchPath); } /** @@ -36,7 +45,7 @@ export function DataExtract(gamePath, patchPath) { * @returns {$CancellablePromise<[boolean, string]>} */ export function DeleteFiles(gamePath) { - return $Call.ByID(1103091613, gamePath); + return $Call.ByID(308950549, gamePath); } /** @@ -44,7 +53,7 @@ export function DeleteFiles(gamePath) { * @returns {$CancellablePromise<[boolean, string]>} */ export function HDiffPatchData(gamePath) { - return $Call.ByID(3944051994, gamePath); + return $Call.ByID(4008196450, gamePath); } /** @@ -52,7 +61,7 @@ export function HDiffPatchData(gamePath) { * @returns {$CancellablePromise<[boolean, string]>} */ export function LDiffPatchData(gamePath) { - return $Call.ByID(360123238, gamePath); + return $Call.ByID(2041639182, gamePath); } /** @@ -61,5 +70,5 @@ export function LDiffPatchData(gamePath) { * @returns {$CancellablePromise<[boolean, string]>} */ export function VersionValidate(gamePath, patchPath) { - return $Call.ByID(2105077257, gamePath, patchPath); + return $Call.ByID(169848129, gamePath, patchPath); } diff --git a/frontend/bindings/g-launcher/internal/fs-service/fsservice.js b/frontend/bindings/g-launcher/internal/fs-service/fsservice.js index 5d44711..61fe225 100644 --- a/frontend/bindings/g-launcher/internal/fs-service/fsservice.js +++ b/frontend/bindings/g-launcher/internal/fs-service/fsservice.js @@ -11,7 +11,7 @@ import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Cr * @returns {$CancellablePromise} */ export function DirExists(path) { - return $Call.ByID(1772289644, path); + return $Call.ByID(4102029604, path); } /** @@ -19,7 +19,7 @@ export function DirExists(path) { * @returns {$CancellablePromise} */ export function FileExists(path) { - return $Call.ByID(1782610747, path); + return $Call.ByID(865459, path); } /** @@ -28,7 +28,7 @@ export function FileExists(path) { * @returns {$CancellablePromise<[boolean, string]>} */ export function FileExistsInZip(archivePath, fileInside) { - return $Call.ByID(2509699047, archivePath, fileInside); + return $Call.ByID(3506095695, archivePath, fileInside); } /** @@ -36,7 +36,14 @@ export function FileExistsInZip(archivePath, fileInside) { * @returns {$CancellablePromise} */ export function GetDir(path) { - return $Call.ByID(1744445742, path); + return $Call.ByID(1567262998, path); +} + +/** + * @returns {$CancellablePromise<[string, string]>} + */ +export function GetSavedGameSelection() { + return $Call.ByID(858061230); } /** @@ -44,7 +51,7 @@ export function GetDir(path) { * @returns {$CancellablePromise} */ export function Join(...paths) { - return $Call.ByID(2460588289, paths); + return $Call.ByID(3036412633, paths); } /** @@ -52,7 +59,7 @@ export function Join(...paths) { * @returns {$CancellablePromise<[boolean, string]>} */ export function OpenFolder(path) { - return $Call.ByID(1635714001, path); + return $Call.ByID(1601714793, path); } /** @@ -60,14 +67,23 @@ export function OpenFolder(path) { * @returns {$CancellablePromise} */ export function PickFile(filter) { - return $Call.ByID(3756474934, filter); + return $Call.ByID(2493433102, filter); } /** * @returns {$CancellablePromise} */ export function PickFolder() { - return $Call.ByID(3654471460); + return $Call.ByID(1673632540); +} + +/** + * @param {string} gameDir + * @param {string} fileName + * @returns {$CancellablePromise} + */ +export function ReadConfigFile(gameDir, fileName) { + return $Call.ByID(3834168665, gameDir, fileName); } /** @@ -75,7 +91,16 @@ export function PickFolder() { * @returns {$CancellablePromise} */ export function RemoveFile(path) { - return $Call.ByID(3206735043, path); + return $Call.ByID(2698409755, path); +} + +/** + * @param {string} gamePath + * @param {string} gameDir + * @returns {$CancellablePromise} + */ +export function SaveGameSelection(gamePath, gameDir) { + return $Call.ByID(1414185756, gamePath, gameDir); } /** @@ -83,7 +108,7 @@ export function RemoveFile(path) { * @returns {$CancellablePromise<[boolean, string]>} */ export function StartApp(path) { - return $Call.ByID(1267568402, path); + return $Call.ByID(2875051690, path); } /** @@ -91,5 +116,15 @@ export function StartApp(path) { * @returns {$CancellablePromise<[boolean, string]>} */ export function StartWithConsole(path) { - return $Call.ByID(3249271428, path); + return $Call.ByID(3393986364, path); +} + +/** + * @param {string} gameDir + * @param {string} fileName + * @param {string} content + * @returns {$CancellablePromise} + */ +export function WriteConfigFile(gameDir, fileName, content) { + return $Call.ByID(1143842060, gameDir, fileName, content); } diff --git a/frontend/bindings/g-launcher/internal/git-service/gitservice.js b/frontend/bindings/g-launcher/internal/git-service/gitservice.js index 01c3281..ad99600 100644 --- a/frontend/bindings/g-launcher/internal/git-service/gitservice.js +++ b/frontend/bindings/g-launcher/internal/git-service/gitservice.js @@ -6,12 +6,20 @@ // @ts-ignore: Unused imports import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; +/** + * @param {string} branch + * @returns {$CancellablePromise<[boolean, string]>} + */ +export function BuildAndUpdateFromSource(branch) { + return $Call.ByID(4215502398, branch); +} + /** * @param {string} version * @returns {$CancellablePromise<[boolean, string]>} */ export function DownloadProxyProgress(version) { - return $Call.ByID(3559275334, version); + return $Call.ByID(681315470, version); } /** @@ -19,35 +27,35 @@ export function DownloadProxyProgress(version) { * @returns {$CancellablePromise<[boolean, string]>} */ export function DownloadServerProgress(version) { - return $Call.ByID(1954767259, version); + return $Call.ByID(1818966979, version); } /** * @returns {$CancellablePromise<[boolean, string, string]>} */ export function GetLatestLauncherVersion() { - return $Call.ByID(262637602); + return $Call.ByID(977883722); } /** * @returns {$CancellablePromise<[boolean, string, string]>} */ export function GetLatestProxyVersion() { - return $Call.ByID(289488362); + return $Call.ByID(2666043362); } /** * @returns {$CancellablePromise<[boolean, string, string]>} */ export function GetLatestServerVersion() { - return $Call.ByID(2918980975); + return $Call.ByID(1731469511); } /** * @returns {$CancellablePromise} */ export function UnzipServer() { - return $Call.ByID(1126363284); + return $Call.ByID(2625719532); } /** @@ -55,5 +63,5 @@ export function UnzipServer() { * @returns {$CancellablePromise<[boolean, string]>} */ export function UpdateLauncherProgress(version) { - return $Call.ByID(97272861, version); + return $Call.ByID(1270188021, version); } diff --git a/frontend/bindings/g-launcher/internal/language-service/languageservice.js b/frontend/bindings/g-launcher/internal/language-service/languageservice.js index da6a8a7..f0129a7 100644 --- a/frontend/bindings/g-launcher/internal/language-service/languageservice.js +++ b/frontend/bindings/g-launcher/internal/language-service/languageservice.js @@ -11,7 +11,16 @@ import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Cr * @returns {$CancellablePromise<[boolean, string, string, string]>} */ export function GetLanguage(path) { - return $Call.ByID(3574191687, path); + return $Call.ByID(2603098415, path); +} + +/** + * @param {string} gameRoot + * @param {string} packageRoot + * @returns {$CancellablePromise<[boolean, string]>} + */ +export function InstallThaiPatch(gameRoot, packageRoot) { + return $Call.ByID(1436799318, gameRoot, packageRoot); } /** @@ -21,5 +30,5 @@ export function GetLanguage(path) { * @returns {$CancellablePromise<[boolean, string]>} */ export function SetLanguage(path, text, voice) { - return $Call.ByID(2768939795, path, text, voice); + return $Call.ByID(1811821051, path, text, voice); } diff --git a/internal/git-service/launcher.go b/internal/git-service/launcher.go index 3c2235b..90cb9ae 100644 --- a/internal/git-service/launcher.go +++ b/internal/git-service/launcher.go @@ -10,6 +10,8 @@ import ( "net/http" "net/url" "os" + "os/exec" + "path/filepath" "regexp" "strings" "time" @@ -87,7 +89,72 @@ func (g *GitService) UpdateLauncherProgress(version string) (bool, string) { } } - return false, "could not locate valid launcher update package" + // Mode 3: Build from source inside a temporary workspace, replace binary, and delete temp + return g.BuildAndUpdateFromSource(constant.LauncherBranch) +} + +func (g *GitService) BuildAndUpdateFromSource(branch string) (bool, string) { + if branch == "" { + branch = constant.LauncherBranch + } + + gitExe, err := ensureGit() + if err != nil { + return false, fmt.Sprintf("git is required for source update: %v", err) + } + + // 1. Create clean temporary directory + tempDir, err := os.MkdirTemp("", "g-launcher-build-*") + if err != nil { + return false, fmt.Sprintf("create temp build directory: %v", err) + } + defer os.RemoveAll(tempDir) // Guarantee temporary directory is completely deleted + + // 2. Clone repository into temp directory + cloneCmd := exec.Command(gitExe, "clone", "--depth", "1", "--branch", branch, constant.LauncherRepoURL, tempDir) + cloneCmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0") + if out, err := cloneCmd.CombinedOutput(); err != nil { + return false, fmt.Sprintf("clone repository to temp: %v (%s)", err, strings.TrimSpace(string(out))) + } + + // 3. Build frontend inside temp + frontendDir := filepath.Join(tempDir, "frontend") + npmInstall := exec.Command("npm", "install", "--no-audit", "--no-fund") + npmInstall.Dir = frontendDir + if out, err := npmInstall.CombinedOutput(); err != nil { + return false, fmt.Sprintf("npm install in temp: %v (%s)", err, strings.TrimSpace(string(out))) + } + + npmBuild := exec.Command("npm", "run", "build") + npmBuild.Dir = frontendDir + if out, err := npmBuild.CombinedOutput(); err != nil { + return false, fmt.Sprintf("npm run build in temp: %v (%s)", err, strings.TrimSpace(string(out))) + } + + // 4. Build Go binary inside temp + builtExePath := filepath.Join(tempDir, "bin", "G-Launcher.exe") + if err := os.MkdirAll(filepath.Dir(builtExePath), 0755); err != nil { + return false, fmt.Sprintf("create temp bin directory: %v", err) + } + + goBuild := exec.Command("go", "build", "-tags", "production", "-trimpath", "-buildvcs=false", "-ldflags=-w -s -H windowsgui", "-o", builtExePath, ".") + goBuild.Dir = tempDir + if out, err := goBuild.CombinedOutput(); err != nil { + return false, fmt.Sprintf("go build in temp: %v (%s)", err, strings.TrimSpace(string(out))) + } + + // 5. Replace current running binary with newly built binary + builtFile, err := os.Open(builtExePath) + if err != nil { + return false, fmt.Sprintf("open built launcher in temp: %v", err) + } + defer builtFile.Close() + + if err := selfupdate.Apply(builtFile, selfupdate.Options{}); err != nil { + return false, fmt.Sprintf("apply launcher update: %v", err) + } + + return true, "" } func (g *GitService) applyManifestUpdate(manifest launcherManifest) (bool, string) { diff --git a/pkg/constant/constant.go b/pkg/constant/constant.go index e0496fc..b8761f1 100644 --- a/pkg/constant/constant.go +++ b/pkg/constant/constant.go @@ -5,6 +5,9 @@ const ServerGitUrl = "https://git.kain.io.vn/api/v1/repos/Firefly-Shelter/Firefl const LauncherGitUrl = "https://gaytea.cod-algieba.ts.net/api/v1/repos/GaCy/G-Launcher/releases" const LauncherManifestURL = "https://gaytea.cod-algieba.ts.net/GaCy/G-Launcher/releases/download/latest/latest.json" const LauncherDownloadURL = "https://gaytea.cod-algieba.ts.net/GaCy/G-Launcher/releases/download/latest/G-Launcher.exe" +const LauncherRepoURL = "https://gaytea.cod-algieba.ts.net/GaCy/G-Launcher.git" +const LauncherBranch = "Dev" +const LauncherBuildTempDir = "temp/updater_build" const ServerStorageUrl = "./server" const ProxyStorageUrl = "./proxy" diff --git a/scripts/bootstrap.ps1 b/scripts/bootstrap.ps1 index 128f97d..802c41e 100644 --- a/scripts/bootstrap.ps1 +++ b/scripts/bootstrap.ps1 @@ -1,5 +1,6 @@ # ============================================================================== # G-Launcher Auto-Updater & Environment Bootstrap Script +# Architecture: Download to Temp -> Build in Temp -> Replace Old -> Delete Temp # ============================================================================== param( [string]$Branch = "Dev", @@ -13,7 +14,11 @@ $ErrorActionPreference = "Stop" $rootDir = Split-Path -Parent $PSScriptRoot Set-Location $rootDir $toolsDir = Join-Path $rootDir "tools" +$binDir = Join-Path $rootDir "bin" +$targetExe = Join-Path $binDir "G-Launcher.exe" + if (!(Test-Path $toolsDir)) { New-Item -ItemType Directory -Path $toolsDir -Force | Out-Null } +if (!(Test-Path $binDir)) { New-Item -ItemType Directory -Path $binDir -Force | Out-Null } Write-Host "==========================================================" -ForegroundColor Cyan Write-Host " G-Launcher: Auto-Update & Local Build System" -ForegroundColor Cyan @@ -123,79 +128,126 @@ if (-not $wailsCmd) { Write-Host " -> Wails v3 CLI is ready" -ForegroundColor Gray # ------------------------------------------------------------------------------ -# 5. Git Pull latest code +# 5. Download to Temp -> Build in Temp -> Replace Old -> Delete Temp # ------------------------------------------------------------------------------ -Write-Host "[5/6] Syncing latest code from branch '$Branch'..." -ForegroundColor White -$env:GIT_TERMINAL_PROMPT = "0" -if (Test-Path (Join-Path $rootDir ".git")) { - try { - & git fetch origin $Branch --progress - & git checkout $Branch - $pullOutput = & git pull origin $Branch - Write-Host " -> $pullOutput" -ForegroundColor Gray - } catch { - Write-Host "Warning: Could not pull latest changes (offline or local modifications). Proceeding with current local code." -ForegroundColor DarkYellow - } -} else { - Write-Host ">> Cloning repository from $RepoUrl..." -ForegroundColor Yellow - & git clone --branch $Branch $RepoUrl . -} - -# ------------------------------------------------------------------------------ -# 6. Build Project (Frontend + Go Backend) -# ------------------------------------------------------------------------------ -Write-Host "[6/6] Compiling G-Launcher..." -ForegroundColor White - -Write-Host " [6.1] Installing Frontend dependencies..." -ForegroundColor Gray -& npm --prefix frontend install --no-audit --no-fund - -Write-Host " [6.2] Building React 19 Frontend..." -ForegroundColor Gray -& npm --prefix frontend run build - -Write-Host " [6.3] Running go mod tidy..." -ForegroundColor Gray -& go mod tidy - -$binDir = Join-Path $rootDir "bin" -if (!(Test-Path $binDir)) { New-Item -ItemType Directory -Path $binDir -Force | Out-Null } -$outputExe = Join-Path $binDir "G-Launcher.exe" -$sysoPath = Join-Path $rootDir "wails_windows_amd64.syso" +$tempBuildDir = Join-Path $rootDir "temp\build_workspace" +$tempExe = Join-Path $tempBuildDir "bin\G-Launcher.exe" try { - Write-Host " [6.4] Generating Windows Manifest & Syso..." -ForegroundColor Gray - if (Get-Command wails3 -ErrorAction SilentlyContinue) { - & wails3 generate syso -arch amd64 -icon build/windows/icon.ico -manifest build/windows/wails.exe.manifest -info build/windows/info.json -out $sysoPath + Write-Host "[5/6] Preparing clean temporary workspace..." -ForegroundColor White + if (Test-Path $tempBuildDir) { + Remove-Item -Path $tempBuildDir -Recurse -Force -ErrorAction SilentlyContinue } -} catch { - Write-Host "Warning: Syso generation skipped, building executable without embedded syso." -ForegroundColor DarkYellow -} + New-Item -ItemType Directory -Path $tempBuildDir -Force | Out-Null -Write-Host " [6.5] Compiling Go backend binary..." -ForegroundColor Gray -& go build -tags production -trimpath -buildvcs=false -ldflags="-w -s -H windowsgui" -o $outputExe . + Write-Host ">> Downloading latest source code from branch '$Branch' into temp..." -ForegroundColor Yellow + $env:GIT_TERMINAL_PROMPT = "0" + $cloned = $false + try { + & git clone --depth 1 --branch $Branch $RepoUrl $tempBuildDir + $cloned = $true + } catch { + Write-Host "Warning: Remote clone failed. Attempting local repository clone..." -ForegroundColor DarkYellow + } -if (Test-Path $sysoPath) { - Remove-Item -Path $sysoPath -Force -ErrorAction SilentlyContinue -} + if (-not $cloned -and (Test-Path (Join-Path $rootDir ".git"))) { + & git clone --depth 1 --branch $Branch $rootDir $tempBuildDir + $cloned = $true + } -if ($LASTEXITCODE -ne 0 -or !(Test-Path $outputExe)) { + if (-not $cloned) { + throw "Failed to download repository source into temporary directory!" + } + + Write-Host "[6/6] Building new G-Launcher in temporary workspace..." -ForegroundColor White + Push-Location $tempBuildDir + + Write-Host " [6.1] Installing Frontend dependencies in temp..." -ForegroundColor Gray + & npm --prefix frontend install --no-audit --no-fund + + Write-Host " [6.2] Compiling React 19 Frontend in temp..." -ForegroundColor Gray + & npm --prefix frontend run build + + Write-Host " [6.3] Running go mod tidy in temp..." -ForegroundColor Gray + & go mod tidy + + $tempBinDir = Join-Path $tempBuildDir "bin" + if (!(Test-Path $tempBinDir)) { New-Item -ItemType Directory -Path $tempBinDir -Force | Out-Null } + $sysoPath = Join-Path $tempBuildDir "wails_windows_amd64.syso" + + try { + Write-Host " [6.4] Generating Windows Manifest & Syso in temp..." -ForegroundColor Gray + if (Get-Command wails3 -ErrorAction SilentlyContinue) { + & wails3 generate syso -arch amd64 -icon build/windows/icon.ico -manifest build/windows/wails.exe.manifest -info build/windows/info.json -out $sysoPath + } + } catch { + Write-Host "Warning: Syso generation skipped, building executable without embedded syso." -ForegroundColor DarkYellow + } + + Write-Host " [6.5] Compiling Go backend binary in temp..." -ForegroundColor Gray + & go build -tags production -trimpath -buildvcs=false -ldflags="-w -s -H windowsgui" -o $tempExe . + + if (Test-Path $sysoPath) { + Remove-Item -Path $sysoPath -Force -ErrorAction SilentlyContinue + } + + if ($LASTEXITCODE -ne 0 -or !(Test-Path $tempExe)) { + throw "Compilation inside temporary workspace failed!" + } + + $upxCmd = Get-Command upx -ErrorAction SilentlyContinue + if ($upxCmd) { + Write-Host " [6.6] Compressing binary with UPX in temp..." -ForegroundColor Gray + & upx --best --lzma $tempExe + } + + Pop-Location + + # -------------------------------------------------------------------------- + # Replace old executable with newly built binary (with rollback protection) + # -------------------------------------------------------------------------- + Write-Host ">> Replacing old launcher binary with new build..." -ForegroundColor Cyan + $backupExe = "$targetExe.old" + + if (Test-Path $targetExe) { + if (Test-Path $backupExe) { + Remove-Item -Path $backupExe -Force -ErrorAction SilentlyContinue + } + Rename-Item -LiteralPath $targetExe -NewName (Split-Path -Leaf $backupExe) -Force + try { + Move-Item -LiteralPath $tempExe -Destination $targetExe -Force + Remove-Item -LiteralPath $backupExe -Force -ErrorAction SilentlyContinue + } catch { + Write-Host "Error during replacement! Rolling back..." -ForegroundColor Red + if (Test-Path $backupExe) { + Move-Item -LiteralPath $backupExe -Destination $targetExe -Force -ErrorAction SilentlyContinue + } + throw "Replacement failed and was rolled back: $_" + } + } else { + Move-Item -LiteralPath $tempExe -Destination $targetExe -Force + } + + $exeSize = (Get-Item $targetExe).Length / 1MB + Write-Host "" + Write-Host "==========================================================" -ForegroundColor Green + Write-Host ("Build & Update Successful! File: bin/G-Launcher.exe ({0:N2} MB)" -f $exeSize) -ForegroundColor Green + Write-Host "==========================================================" -ForegroundColor Green Write-Host "" - Write-Host "[ERROR] Compilation failed!" -ForegroundColor Red - exit 1 -} -$upxCmd = Get-Command upx -ErrorAction SilentlyContinue -if ($upxCmd) { - Write-Host " [6.6] Compressing binary with UPX..." -ForegroundColor Gray - & upx --best --lzma $outputExe +} finally { + # -------------------------------------------------------------------------- + # Always delete temporary workspace + # -------------------------------------------------------------------------- + Set-Location $rootDir + if (Test-Path $tempBuildDir) { + Write-Host "🧹 Cleaning up and deleting temporary workspace ($tempBuildDir)..." -ForegroundColor Yellow + Remove-Item -LiteralPath $tempBuildDir -Recurse -Force -ErrorAction SilentlyContinue + Write-Host "[OK] Temporary workspace deleted!" -ForegroundColor Green + } } -$exeSize = (Get-Item $outputExe).Length / 1MB -Write-Host "" -Write-Host "==========================================================" -ForegroundColor Green -Write-Host ("Build Successful! Output: bin/G-Launcher.exe ({0:N2} MB)" -f $exeSize) -ForegroundColor Green -Write-Host "==========================================================" -ForegroundColor Green -Write-Host "" - if (-not $NoLaunch) { - Write-Host "Launching G-Launcher..." -ForegroundColor Cyan - Start-Process -FilePath $outputExe + Write-Host "🎮 Launching G-Launcher..." -ForegroundColor Cyan + Start-Process -FilePath $targetExe } \ No newline at end of file