From 5a018bcb8d83487157847eb70d26c6fc81f754aa Mon Sep 17 00:00:00 2001 From: claude-bot Date: Wed, 13 May 2026 00:48:46 +0900 Subject: [PATCH] fix(installer-rp): URL-encode base pack path, output to .mc_custom + installer: no auto -Xms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 리소스팩 간편설치기: - 베이스 리소스팩 다운로드 URL 에 encodeURIComponent 적용. "Puzzle Resource Pack (basic).zip" 같이 공백·괄호가 들어간 파일명 정상 처리. - 출력 경로를 %appdata%/.minecraft/resourcepacks/ → %appdata%/.mc_custom/ resourcepacks/ 로 변경 (renderer 안내문, openFolder, 빌드 출력 일괄). - 로드 직후 각 음악퀴즈의 베이스 등록 여부를 로그에 노출 (디버그용). - 베이스 다운로드 시 실제 URL 도 로그에 출력. 음악퀴즈 간편설치기: - mergeRamArgs: -Xms 가 기존에 없으면 추가하지 않도록 수정. clientMinRam 은 "유저 PC 사양 최소 요구치" 의미이지 JVM 초기 힙이 아님. -Xmx 는 계속 추천 RAM 으로 강제 갱신. Co-Authored-By: Claude Opus 4.7 --- installer-rp/renderer.js | 2 +- src/installer-rp/main.ts | 18 ++++++++++++------ src/installer-rp/preload.ts | 2 +- src/installer/main.ts | 18 ++++++++---------- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/installer-rp/renderer.js b/installer-rp/renderer.js index 7e79370..233c869 100644 --- a/installer-rp/renderer.js +++ b/installer-rp/renderer.js @@ -117,7 +117,7 @@ function renderStep2() { section.innerHTML = '

2단계. 리소스팩 설치

' + '

음악·사진을 받아 리소스팩을 만들고 ' + - '%appdata%/.minecraft/resourcepacks/ 에 자동 설치합니다.

' + + '%appdata%/.mc_custom/resourcepacks/ 에 자동 설치합니다.

' + '
' + ' yt-dlp 준비' + ' ffmpeg 준비' + diff --git a/src/installer-rp/main.ts b/src/installer-rp/main.ts index f14ac84..a3f51d7 100644 --- a/src/installer-rp/main.ts +++ b/src/installer-rp/main.ts @@ -205,6 +205,9 @@ ipcMain.handle('rp:packs:load', async (_event, manifestUrlInput?: string): Promi state.packs.clear() for (const item of results) state.packs.set(item.key, item) sendLog(`로드된 음악퀴즈: ${results.length}개`) + for (const item of results) { + sendLog(` - ${item.key}: mc=${item.mcVersion || '?'} 베이스=${item.resourcepackPath || '(없음)'}`) + } return results }) @@ -344,9 +347,12 @@ ipcMain.handle('rp:install:start', async (): Promise<{ resourcepackPath: string throwIfCancelled() let baseZipPath: string | undefined if (pack.resourcepackPath) { - const baseUrl = `${state.baseUrl}/file/resourcepacks/${pack.resourcepackPath.replace(/^\/+/, '')}` + // 파일명에 공백·괄호가 있을 수 있어 encodeURIComponent 로 인코딩. + const cleaned = pack.resourcepackPath.replace(/^\/+/, '') + const baseUrl = `${state.baseUrl}/file/resourcepacks/${encodeURIComponent(cleaned)}` baseZipPath = path.join(tempRoot, 'base.zip') - sendLog(`베이스 리소스팩 다운로드: ${pack.resourcepackPath}`) + sendLog(`베이스 리소스팩 다운로드: ${cleaned}`) + sendLog(` URL: ${baseUrl}`) sendProgress({ phase: 'package', message: '베이스 리소스팩 다운로드 중' }) try { const buf = await fetchBuffer(baseUrl) @@ -356,13 +362,13 @@ ipcMain.handle('rp:install:start', async (): Promise<{ resourcepackPath: string throw new Error(`베이스 리소스팩 다운로드 실패: ${(err as Error).message}`) } } else { - sendLog('베이스 리소스팩 없음 — 새 리소스팩으로 생성') + sendLog('베이스 리소스팩 없음(resourcepackPath 빈 값) — 새 리소스팩으로 생성') } // 2-5. 리소스팩 zip 빌드 (pack.mcmeta + sounds.json + 음악·이미지, 베이스 위에 얹기) throwIfCancelled() const resourcepackName = `${state.selectedKey}_musicquiz.zip` - const resourcepackDir = path.join(getAppDataDir(), '.minecraft', 'resourcepacks') + const resourcepackDir = path.join(getMcCustomDir(), 'resourcepacks') const resourcepackPath = path.join(resourcepackDir, resourcepackName) sendLog(`리소스팩 zip 빌드 중… (${resourcepackName})`) sendProgress({ phase: 'package', message: baseZipPath ? '베이스에 음악·사진 추가 중' : 'zip 빌드 중' }) @@ -377,7 +383,7 @@ ipcMain.handle('rp:install:start', async (): Promise<{ resourcepackPath: string log: sendLog }) - // 2-6. %appdata%/.minecraft/resourcepacks/ 에 배치 (위 빌드가 직접 outZipPath 에 저장) + // 2-6. %appdata%/.mc_custom/resourcepacks/ 에 배치 (위 빌드가 직접 outZipPath 에 저장) sendLog(`설치 완료: ${resourcepackPath}`) sendProgress({ phase: 'package', message: '설치 완료', done: true }) return { resourcepackPath } @@ -403,7 +409,7 @@ function throwIfCancelled(): void { // ── IPC: 3단계 완료 ────────────────────────────────── ipcMain.handle('rp:finish:openFolder', async () => { - const dir = path.join(getAppDataDir(), '.minecraft', 'resourcepacks') + const dir = path.join(getMcCustomDir(), 'resourcepacks') if (!fs.existsSync(dir)) { await fsp.mkdir(dir, { recursive: true }) } diff --git a/src/installer-rp/preload.ts b/src/installer-rp/preload.ts index 3d3ec5b..cc022d8 100644 --- a/src/installer-rp/preload.ts +++ b/src/installer-rp/preload.ts @@ -16,7 +16,7 @@ const api = { cancelInstall: (): Promise => ipcRenderer.invoke('rp:install:cancel'), - /** %appdata%/.minecraft/resourcepacks/ 폴더를 OS 파일 탐색기로 연다. */ + /** %appdata%/.mc_custom/resourcepacks/ 폴더를 OS 파일 탐색기로 연다. */ openResourcepackFolder: (): Promise => ipcRenderer.invoke('rp:finish:openFolder'), /** 프로그램 종료. */ diff --git a/src/installer/main.ts b/src/installer/main.ts index 45e9077..a57db53 100644 --- a/src/installer/main.ts +++ b/src/installer/main.ts @@ -580,22 +580,20 @@ function getAppDataDir(): string { } /** - * 기존 javaArgs 에서 -Xmx/-Xms 토큰만 새 값으로 교체하고 나머지 args 는 보존한다. - * 기존에 없으면 새 RAM 인자를 앞에 붙인다. + * 기존 javaArgs 에서 RAM 토큰만 새 값으로 교체하고 나머지 args 는 보존한다. + * - -Xmx: 항상 추천 RAM 으로 설정 (없으면 추가). + * - -Xms: 기존에 있을 때만 교체. 없으면 추가하지 않음. + * (clientMinRam 은 "유저 PC 사양 최소 요구치" 의미이지 JVM 초기 힙이 아님) */ -function mergeRamArgs(existing: string, maxMb: number, minMb: number): string { - const newXmx = `-Xmx${maxMb}M` - const newXms = `-Xms${minMb}M` +function mergeRamArgs(existing: string, recommendedMb: number): string { + const newXmx = `-Xmx${recommendedMb}M` const tokens = (existing || '').split(/\s+/).filter(Boolean) let foundXmx = false - let foundXms = false const merged = tokens.map((t) => { if (t.startsWith('-Xmx')) { foundXmx = true; return newXmx } - if (t.startsWith('-Xms')) { foundXms = true; return newXms } return t }) if (!foundXmx) merged.unshift(newXmx) - if (!foundXms) merged.splice(foundXmx ? 0 : 1, 0, newXms) return merged.join(' ').trim() } @@ -611,9 +609,9 @@ async function updateLauncherProfile(pack: PackDefinition, gameDir: string): Pro const profileKey = pack.name const existingProfile = json.profiles[profileKey] ?? {} const existingJavaArgs = typeof existingProfile.javaArgs === 'string' ? (existingProfile.javaArgs as string) : '' - const javaArgs = mergeRamArgs(existingJavaArgs, pack.serverMaxRam, pack.serverMinRam) + const javaArgs = mergeRamArgs(existingJavaArgs, pack.serverMaxRam) if (existingJavaArgs && existingJavaArgs !== javaArgs) { - sendLog(`기존 JVM 인수 유지, RAM 만 갱신: "${existingJavaArgs}" → "${javaArgs}"`) + sendLog(`기존 JVM 인수 유지, -Xmx 만 갱신: "${existingJavaArgs}" → "${javaArgs}"`) } const lastVersionId = pack.platform.type === 'vanilla' ? pack.mcVersion