installer: 마인크래프트 런처 실행 전략 재정렬 — Win32/MSIX 직접 실행 우선
minecraft:// URL 스킴이 핸들러가 깨졌거나 비어 있을 때 MS Store 로 폴백되어
실제 런처가 안 떠는 케이스 대응. 실행 순서를 아래로 변경:
1) Win32 설치판 직접 spawn (Program Files / Xbox / portable)
2) App Execution Alias(Minecraft.exe / MinecraftLauncher.exe, reparse point
이므로 cmd /c start 경유)
3) explorer.exe shell:AppsFolder\\Microsoft.4297127D64EC6_8wekyb3d8bbwe!Minecraft
로 MSIX(Microsoft Store) 런처 직접 호출
4) 마지막 수단: minecraft:// URL 스킴
This commit is contained in:
@@ -1379,39 +1379,78 @@ ipcMain.handle('finish:startServer', async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('finish:startLauncher', async () => {
|
ipcMain.handle('finish:startLauncher', async () => {
|
||||||
// 1순위: minecraft:// URL 스킴. UWP(Microsoft Store) / Win32 / Xbox 앱 어떤 형태로 설치돼
|
// 마인크래프트 런처는 두 가지 형태로 배포된다:
|
||||||
// 있어도 OS의 등록된 프로토콜 핸들러가 처리하므로 가장 견고하다.
|
// 1) Win32 설치판: C:\Program Files (x86)\Minecraft Launcher\MinecraftLauncher.exe 등
|
||||||
|
// 2) MSIX(Microsoft Store) 앱: PackageFamilyName=Microsoft.4297127D64EC6_8wekyb3d8bbwe, AppId=Minecraft
|
||||||
|
// - 일반 .exe 가 아니라 shell:AppsFolder\<PFN>!<AppId> 또는 App Execution Alias 로만 띄울 수 있음.
|
||||||
|
// minecraft:// URL 스킴은 런처가 핸들러로 등록되어 있어야만 동작하고, 등록이 깨지거나 비어 있으면
|
||||||
|
// MS Store 로 폴백되므로 가장 마지막 시도로 미룬다.
|
||||||
|
if (process.platform !== 'win32') {
|
||||||
try {
|
try {
|
||||||
sendLog('마인크래프트 런처 실행 요청(URL 스킴 minecraft://)...')
|
|
||||||
await shell.openExternal('minecraft://')
|
await shell.openExternal('minecraft://')
|
||||||
sendLog('마인크래프트 런처 실행 요청 완료.')
|
sendLog('마인크래프트 런처 실행 요청 완료(URL 스킴, 비-Windows).')
|
||||||
return
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
sendLog(`URL 스킴 실행 실패: ${(err as Error).message}. 직접 경로 탐색으로 폴백합니다.`)
|
sendLog(`런처 실행 실패: ${(err as Error).message}`)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2순위: 알려진 설치 경로 탐색. 구버전 .exe 설치판 / Xbox 앱 설치 위치까지 커버.
|
|
||||||
const programFilesX86 = process.env['ProgramFiles(x86)'] ?? 'C:\\Program Files (x86)'
|
const programFilesX86 = process.env['ProgramFiles(x86)'] ?? 'C:\\Program Files (x86)'
|
||||||
const programFiles = process.env['ProgramFiles'] ?? 'C:\\Program Files'
|
const programFiles = process.env['ProgramFiles'] ?? 'C:\\Program Files'
|
||||||
const localAppData = process.env['LOCALAPPDATA'] ?? path.join(os.homedir(), 'AppData', 'Local')
|
const localAppData = process.env['LOCALAPPDATA'] ?? path.join(os.homedir(), 'AppData', 'Local')
|
||||||
const candidates = [
|
|
||||||
path.join(programFilesX86, 'Minecraft Launcher', 'MinecraftLauncher.exe'),
|
type LauncherCandidate = { label: string; path: string; viaShell: boolean }
|
||||||
path.join(programFiles, 'Minecraft Launcher', 'MinecraftLauncher.exe'),
|
const candidates: LauncherCandidate[] = [
|
||||||
path.join(programFilesX86, 'Minecraft', 'MinecraftLauncher.exe'),
|
// Win32 설치판 — 실행 파일 직접 spawn.
|
||||||
path.join(programFiles, 'Minecraft', 'MinecraftLauncher.exe'),
|
{ label: 'Win32 설치(Program Files (x86))', path: path.join(programFilesX86, 'Minecraft Launcher', 'MinecraftLauncher.exe'), viaShell: false },
|
||||||
'C:\\XboxGames\\Minecraft Launcher\\Content\\Minecraft.exe',
|
{ label: 'Win32 설치(Program Files)', path: path.join(programFiles, 'Minecraft Launcher', 'MinecraftLauncher.exe'), viaShell: false },
|
||||||
path.join(localAppData, 'Programs', 'minecraft-launcher', 'MinecraftLauncher.exe')
|
{ label: 'Win32 설치(legacy Minecraft 폴더)', path: path.join(programFilesX86, 'Minecraft', 'MinecraftLauncher.exe'), viaShell: false },
|
||||||
|
{ label: 'Win32 설치(legacy Minecraft 폴더)', path: path.join(programFiles, 'Minecraft', 'MinecraftLauncher.exe'), viaShell: false },
|
||||||
|
{ label: 'Xbox / Game Pass', path: 'C:\\XboxGames\\Minecraft Launcher\\Content\\Minecraft.exe', viaShell: false },
|
||||||
|
{ label: 'npm/portable', path: path.join(localAppData, 'Programs', 'minecraft-launcher', 'MinecraftLauncher.exe'), viaShell: false },
|
||||||
|
// App Execution Alias(MS Store 설치 시 자동 생성, reparse point 라 cmd /c start 로 띄워야 안정적).
|
||||||
|
{ label: 'App Execution Alias(Minecraft.exe)', path: path.join(localAppData, 'Microsoft', 'WindowsApps', 'Minecraft.exe'), viaShell: true },
|
||||||
|
{ label: 'App Execution Alias(MinecraftLauncher.exe)', path: path.join(localAppData, 'Microsoft', 'WindowsApps', 'MinecraftLauncher.exe'), viaShell: true }
|
||||||
]
|
]
|
||||||
const target = candidates.find((candidate) => {
|
|
||||||
try { return fs.existsSync(candidate) } catch { return false }
|
for (const cand of candidates) {
|
||||||
})
|
let exists = false
|
||||||
if (target) {
|
try { exists = fs.existsSync(cand.path) } catch { exists = false }
|
||||||
spawn(target, [], { detached: true, stdio: 'ignore' }).unref()
|
if (!exists) continue
|
||||||
sendLog(`마인크래프트 런처 실행: ${target}`)
|
try {
|
||||||
|
if (cand.viaShell) {
|
||||||
|
sendLog(`마인크래프트 런처 실행(${cand.label}, 셸 경유): ${cand.path}`)
|
||||||
|
spawn('cmd.exe', ['/c', 'start', '', cand.path], { detached: true, stdio: 'ignore' }).unref()
|
||||||
|
} else {
|
||||||
|
sendLog(`마인크래프트 런처 실행(${cand.label}): ${cand.path}`)
|
||||||
|
spawn(cand.path, [], { detached: true, stdio: 'ignore' }).unref()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
|
} catch (err) {
|
||||||
|
sendLog(`${cand.path} 실행 실패: ${(err as Error).message}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendLog('Minecraft Launcher를 찾을 수 없습니다. Microsoft Store에서 "Minecraft Launcher"를 설치하거나 minecraft.net에서 받은 뒤 직접 실행해 주세요.')
|
// MSIX 앱 직접 실행: shell:AppsFolder\<PackageFamilyName>!<AppId>.
|
||||||
|
// 마인크래프트 런처(Java) PFN: Microsoft.4297127D64EC6_8wekyb3d8bbwe, AppId: Minecraft.
|
||||||
|
try {
|
||||||
|
const aumid = 'shell:AppsFolder\\Microsoft.4297127D64EC6_8wekyb3d8bbwe!Minecraft'
|
||||||
|
sendLog(`AppsFolder 로 MS Store 런처 실행 시도: ${aumid}`)
|
||||||
|
spawn('explorer.exe', [aumid], { detached: true, stdio: 'ignore' }).unref()
|
||||||
|
return
|
||||||
|
} catch (err) {
|
||||||
|
sendLog(`AppsFolder 실행 실패: ${(err as Error).message}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 마지막 수단: minecraft:// URL 스킴. 런처가 없으면 MS Store 가 열린다.
|
||||||
|
try {
|
||||||
|
sendLog('마지막 시도: minecraft:// URL 스킴 (런처가 없으면 MS Store 가 열릴 수 있음).')
|
||||||
|
await shell.openExternal('minecraft://')
|
||||||
|
} catch (err) {
|
||||||
|
sendLog(`URL 스킴 실행 실패: ${(err as Error).message}.`)
|
||||||
|
}
|
||||||
|
|
||||||
|
sendLog('Minecraft Launcher 실행 시도가 모두 실패했습니다. minecraft.net 또는 Microsoft Store 에서 "Minecraft Launcher" 를 설치한 뒤 다시 시도해 주세요.')
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('app:quit', () => {
|
ipcMain.handle('app:quit', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user