From f409ffad12dab3066b1f6d52deca47a8901d99a4 Mon Sep 17 00:00:00 2001 From: Docker Build Date: Sun, 10 May 2026 21:54:04 -0500 Subject: [PATCH] fix(launcher): Gitea http URL; Wine Z: path + Wow.exe case check - baked-gitea-channel: http:// for brassnet mirror. - win-game-dir: map Unix /home/... to Z:\ under win32 (Wine folder picker). - resolveGameDir + saveGameDir + patch paths use it; Wow.exe resolved case-insensitively. - Version 1.0.6; README checklist for Wine. Co-authored-by: Cursor --- tools/fractured-launcher-electron/README.md | 3 +- .../lib/baked-gitea-channel.js | 4 +-- .../lib/config-store.js | 6 ++-- .../fractured-launcher-electron/lib/patch.js | 29 ++++++++++++++++--- .../lib/win-game-dir.js | 21 ++++++++++++++ tools/fractured-launcher-electron/main.js | 4 ++- .../fractured-launcher-electron/package.json | 3 +- 7 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 tools/fractured-launcher-electron/lib/win-game-dir.js diff --git a/tools/fractured-launcher-electron/README.md b/tools/fractured-launcher-electron/README.md index efdb43f..7149170 100644 --- a/tools/fractured-launcher-electron/README.md +++ b/tools/fractured-launcher-electron/README.md @@ -125,7 +125,8 @@ CI workflow **Sync release to Gitea** (`.github/workflows/gitea-release-sync.yml 6. **Secrets** — **`GITEA_BASE_URL`**, **`GITEA_TOKEN`**, **`GITEA_OWNER`**, **`GITEA_REPO`** must be set under **Settings → Secrets and variables → Actions**. A failed “Upload to Gitea” step usually prints which is missing. 7. **Actions tab** — Open the latest **Sync release to Gitea** run; a red **build-electron** (old tag without `package-lock.json`, etc.) or **Upload to Gitea** step shows the real error. 8. **HTTP 422 `repo is empty`** — The Gitea repo has **no commits** yet. Push any initial commit (e.g. **Add README** in the Gitea web UI, or `git push` to **`main`**). Optionally set **`GITEA_TARGET_REF`** to match your real default branch if it is not **`main`**. From this repo you can run **`scripts/bootstrap-gitea-repo.sh`** (see script header for `GITEA_*` env or pass the HTTPS/SSH clone URL as the first argument). -9. **`sync Wow.exe: fetch failed`** (Linux/AppImage especially) — Usually **TLS** (self-signed Gitea cert) or **cannot reach** the host. Use a **trusted certificate** on Gitea, or put your CA in the system trust store, or set **`NODE_EXTRA_CA_CERTS=/path/to/ca.pem`** when launching the AppImage if you must use self-signed HTTPS. If the mirror is LAN-only HTTP, set **`base_url`** in **`lib/baked-gitea-channel.js`** to **`http://…`** (only if acceptable). Ensure **`Wow-patched.exe`** exists on the **same Gitea release** you configured (**`release_tag`**: `latest` vs pinned tag). Newer builds show the failing URL and TLS hints in the error text. +9. **`sync Wow.exe: fetch failed`** — Often **HTTPS/TLS** to Gitea; use **`http://…`** in **`lib/baked-gitea-channel.js`** if you only serve plain HTTP, or fix certs / **`NODE_EXTRA_CA_CERTS`**. Ensure **`Wow-patched.exe`** exists on the release (**`release_tag`**: `latest` vs pinned). Errors include the failing URL when possible. +10. **Wine + Windows portable** — If the folder picker returns **`/home/...`**, the launcher maps it to **`Z:\home\...`** (Wine’s Unix root). **`Wow.exe`** is matched case-insensitively for Linux-backed folders. Re-save the WoW folder after upgrading if validation still fails. ### Private Gitea token for players diff --git a/tools/fractured-launcher-electron/lib/baked-gitea-channel.js b/tools/fractured-launcher-electron/lib/baked-gitea-channel.js index fc1fa7e..4f338bc 100644 --- a/tools/fractured-launcher-electron/lib/baked-gitea-channel.js +++ b/tools/fractured-launcher-electron/lib/baked-gitea-channel.js @@ -6,8 +6,8 @@ * Token stays in env: GITEA_TOKEN or launcher.json → gitea.token_env. */ module.exports = { - // Scheme optional — gitea-release normalizes to https:// if missing. - base_url: 'https://brassnet.ddns.net:33983', + // http:// kept as-is; bare host gets https in gitea-release.js + base_url: 'http://brassnet.ddns.net:33983', owner: 'Dawnsorrow', repo: 'Fractured-Distro', release_tag: 'latest', diff --git a/tools/fractured-launcher-electron/lib/config-store.js b/tools/fractured-launcher-electron/lib/config-store.js index 4610a6d..edd8d49 100644 --- a/tools/fractured-launcher-electron/lib/config-store.js +++ b/tools/fractured-launcher-electron/lib/config-store.js @@ -2,6 +2,7 @@ const path = require('path'); const fs = require('fs').promises; +const { normalizeWinGameDir } = require('./win-game-dir'); /** Sources no longer shipped; drop from merged files so old launcher.json does not keep fetching them. */ const DEPRECATED_FILE_SOURCES = new Set(['patch-Z.MPQ']); @@ -105,8 +106,9 @@ async function saveGameDir(configPath, gameDir) { function resolveGameDir(cfg, configPath) { const gd = cfg.game_dir; if (!gd) return ''; - if (path.isAbsolute(gd)) return path.normalize(gd); - return path.normalize(path.join(path.dirname(configPath), gd)); + const abs = path.isAbsolute(gd) ? path.normalize(gd) : path.normalize(path.join(path.dirname(configPath), gd)); + if (process.platform === 'win32') return normalizeWinGameDir(abs); + return abs; } module.exports = { getConfigPath, loadConfig, saveGameDir, resolveGameDir, mergeConfig, applyBakedGitea }; diff --git a/tools/fractured-launcher-electron/lib/patch.js b/tools/fractured-launcher-electron/lib/patch.js index c5bd336..be284a0 100644 --- a/tools/fractured-launcher-electron/lib/patch.js +++ b/tools/fractured-launcher-electron/lib/patch.js @@ -2,7 +2,9 @@ const path = require('path'); const fs = require('fs').promises; +const fsSync = require('fs'); const { downloadGitHubRepoFile, downloadReleaseAsset } = require('./github'); +const { normalizeWinGameDir } = require('./win-game-dir'); function pad2(n) { return String(n).padStart(2, '0'); @@ -13,19 +15,38 @@ function backupSuffix() { } function wowExePath(cfg) { + const gd = normalizeWinGameDir(cfg.game_dir || ''); const exe = (cfg.launch && cfg.launch.exe) || 'Wow.exe'; const parts = exe.replace(/\\/g, '/').split('/').filter(Boolean); - return path.join(cfg.game_dir, ...parts); + const primary = path.join(gd, ...parts); + if (process.platform === 'win32' && gd && fsSync.existsSync(primary)) return primary; + if (process.platform === 'win32' && gd) { + try { + const base = path.basename(primary); + const dir = path.dirname(primary); + const names = fsSync.readdirSync(dir); + const hit = names.find((n) => n.toLowerCase() === base.toLowerCase()); + if (hit) { + const alt = path.join(dir, hit); + if (fsSync.statSync(alt).isFile()) return alt; + } + } catch (_) { + /* ignore */ + } + } + return primary; } function wowInstallValid(cfg) { if (!cfg.game_dir) return false; - return require('fs').existsSync(wowExePath(cfg)); + const p = wowExePath(cfg); + return fsSync.existsSync(p) && fsSync.statSync(p).isFile(); } async function installFile(cfg, entry) { const parts = String(entry.dest).replace(/\\/g, '/').split('/').filter(Boolean); - const destAbs = path.join(cfg.game_dir, ...parts); + const root = normalizeWinGameDir(cfg.game_dir || ''); + const destAbs = path.join(root, ...parts); if (entry.backup) { try { const st = await fs.stat(destAbs); @@ -66,7 +87,7 @@ async function applyRealmlist(cfg) { const r = String(rel).trim().replace(/\\/g, '/'); if (!r) continue; const segs = r.split('/').filter(Boolean); - const abs = path.join(cfg.game_dir, ...segs); + const abs = path.join(normalizeWinGameDir(cfg.game_dir || ''), ...segs); await fs.mkdir(path.dirname(abs), { recursive: true }); await fs.writeFile(abs, content, 'utf8'); } diff --git a/tools/fractured-launcher-electron/lib/win-game-dir.js b/tools/fractured-launcher-electron/lib/win-game-dir.js new file mode 100644 index 0000000..f72ef86 --- /dev/null +++ b/tools/fractured-launcher-electron/lib/win-game-dir.js @@ -0,0 +1,21 @@ +'use strict'; + +const path = require('path'); + +/** + * Under Wine, the folder picker often returns a Unix absolute path (/home/...). + * Windows Node does not resolve that to the WoW install; map to Wine's Z: drive + * (Z: == / on typical Wine prefixes). + */ +function normalizeWinGameDir(gameDir) { + if (process.platform !== 'win32') return String(gameDir || '').trim(); + let s = String(gameDir || '').trim(); + if (!s) return s; + s = s.replace(/\//g, path.win32.sep); + if (s.startsWith('\\\\')) return path.normalize(s); + if (/^[A-Za-z]:/.test(s)) return path.normalize(s); + if (s.startsWith(path.win32.sep)) return path.win32.normalize(`Z:${s}`); + return path.normalize(s); +} + +module.exports = { normalizeWinGameDir }; diff --git a/tools/fractured-launcher-electron/main.js b/tools/fractured-launcher-electron/main.js index 3473bf6..50860a3 100644 --- a/tools/fractured-launcher-electron/main.js +++ b/tools/fractured-launcher-electron/main.js @@ -4,6 +4,7 @@ const { app, BrowserWindow, ipcMain, dialog, Menu } = require('electron'); const path = require('path'); const { spawn } = require('child_process'); const { loadConfig, saveGameDir, resolveGameDir } = require('./lib/config-store'); +const { normalizeWinGameDir } = require('./lib/win-game-dir'); const { applyPatches, wowExePath, wowInstallValid, doAuth } = require('./lib/patch'); const { readPatchState } = require('./lib/patch-manifest'); const { setupAutoUpdater } = require('./lib/auto-update'); @@ -95,7 +96,8 @@ ipcMain.handle('launcher:saveGameDir', async (_e, dir) => { const trimmed = String(dir || '').trim(); if (!trimmed) throw new Error('folder path is empty'); const { configPath } = await loadConfig(app); - const norm = path.normalize(trimmed); + const norm = + process.platform === 'win32' ? normalizeWinGameDir(path.normalize(trimmed)) : path.normalize(trimmed); const probe = { ...(await readMergedConfig()).config, game_dir: norm }; if (!wowInstallValid(probe)) { throw new Error(`That folder does not contain ${(probe.launch && probe.launch.exe) || 'Wow.exe'}`); diff --git a/tools/fractured-launcher-electron/package.json b/tools/fractured-launcher-electron/package.json index 63ba9d5..01630c6 100644 --- a/tools/fractured-launcher-electron/package.json +++ b/tools/fractured-launcher-electron/package.json @@ -1,6 +1,6 @@ { "name": "fractured-launcher-electron", - "version": "1.0.5", + "version": "1.0.6", "description": "Fractured WoW launcher (Electron) — no console window, native folder picker, auto-update", "main": "main.js", "repository": { @@ -36,6 +36,7 @@ "renderer.js", "styles.css", "default-launcher.json", + "lib/win-game-dir.js", "lib/baked-gitea-channel.js", "lib/gitea-release.js", "lib/patch-manifest.js",