Commit Graph

19 Commits

Author SHA1 Message Date
1665f05c55 resourcepack: declare compatibility range from 1.21.6 to latest known
Pack.mcmeta now spans pack_format MIN_SUPPORTED_FORMAT (=63, 1.21.6) up to
max(LATEST_KNOWN_FORMAT, resolved.format) so a single build loads on every
MC from 1.21.6 through 26.1.2+ (currently extending to 86 = 26.2). Both
schemas are written: supported_formats for clients on pack_format <= 64,
and min_format/max_format for 1.21.9+ clients. pack_format itself stays
at the build target so newer clients see the pack as current rather than
legacy.
2026-05-14 21:43:31 +09:00
40b2ff81f5 resourcepack: strip vanilla shader overrides when pack_format > 64
Reviewer was right that warn-only let broken zips through. On 1.21.9+
(pack_format > 64) the vanilla shader GLSL API changed (ProjMat, FogColor
etc.) so any base pack carrying old assets/minecraft/shaders/* fails to
compile and causes the same "리소스 새로고침 실패" the pack.mcmeta fix
addressed. Strip that directory at build time when the target pack_format
exceeds 64; keep textures/models/sounds intact and log what was removed.
On <= 64 the old shaders still work, so leave the base pack untouched.
2026-05-14 21:34:30 +09:00
9cb7c05b43 resourcepack: warn when base zip overrides vanilla shaders
The actual "리소스 새로고침 실패" was caused by pack.mcmeta JsonParseException
(fixed in 6718315). The shader compile errors seen on the same log come from
the user-supplied base resourcepack overriding vanilla shaders for an older
MC. Auto-stripping would silently destroy the user's intended look, so emit
a clear warning during build instead and let the user decide whether to
update the base pack.
2026-05-14 21:28:41 +09:00
671831535b fix(resourcepack): emit min_format/max_format when pack_format > 64
MC 1.21.9+ (pack_format >= 65) deprecated supported_formats and now
requires min_format/max_format at pack root. On 26.1.x (format 84) the
old supported_formats made pack.mcmeta unparseable, so MC rejected the
music-quiz resourcepack with "리소스 새로고침 실패" on reload.
2026-05-14 21:23:45 +09:00
6cd402121b i18n: 리소스팩 설치기 UI 문구를 locales/installer-rp/ko-kr.json 으로 분리
- main/preload/ytdlp/ffmpeg/music/images/pack/renderer 전반에서 로그·에러·진행
  메시지 문자열을 locales/installer-rp/ko-kr.json 사전 키로 교체
- preload 에 loadLocale 추가, main 에 rp:i18n:dict IPC 핸들러 추가
- 패키징된 .exe 에서도 한국어 사전이 적용되도록 electron-builder.yml 의
  extraResources 에 locales/ 폴더 추가

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 04:00:31 +09:00
69ed4ad744 config: 사이트 도메인·서버 설정을 .env 로 중앙화 + 설치기 자동 종료 복구
- dotenv 도입, src/shared/env.ts 추가
  - loadEnv() 가 프로젝트 루트 .env 를 로드 (override=false: 쉘 env 우선)
  - getSiteBaseUrl() / getManifestUrl() 헬퍼
- 서버/설치기/리소스팩설치기 진입점에서 loadEnv() 호출
- 설치기 두 종의 기본 MANIFEST_URL 을 SITE_BASE_URL 기반으로 변경
  (운영 도메인을 한 곳에서만 바꾸면 됨)
- .env.example 템플릿 + .gitignore 에 .env 추가
- README / docs/admin-site.md 에 환경변수 표·사용법 추가
- installer/renderer.js: 4단계 완료 후 자동 종료 다시 활성화
2026-05-13 02:55:58 +09:00
5a018bcb8d fix(installer-rp): URL-encode base pack path, output to .mc_custom + installer: no auto -Xms
리소스팩 간편설치기:
- 베이스 리소스팩 다운로드 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 <noreply@anthropic.com>
2026-05-13 00:48:46 +09:00
45540f3db7 feat(installer-rp): use registered base resourcepack as overlay base
/manifest/<key>.json 의 resourcepackPath 가 비어있지 않으면
/file/resourcepacks/<path> 의 zip 을 받아 임시 폴더에 풀고, 그 위에
음악·사진·sounds.json·pack.mcmeta 를 얹어 최종 zip 을 만든다.

- types.ts: RpFetchedPack 에 resourcepackPath 필드 추가
- main.ts: 로드 시 normalizePackDefinition 으로 resourcepackPath 캡처,
  설치 시 베이스 zip 다운로드 → tempRoot/base.zip → buildResourcepackZip 에 전달
- pack.ts: baseZipPath 옵션 추가. extract-zip 으로 베이스 압축 해제 후 위에 얹기.
  sounds.json 은 기존 항목과 병합, pack.mcmeta 는 mcVersion 에 맞춰 항상 덮어씀.

베이스가 없으면(빈 문자열) 기존처럼 새 리소스팩을 처음부터 생성.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 00:37:00 +09:00
df3d0a5cda feat(installer-rp): stagger music download starts (2.5s gap)
동시 N개를 모두 t=0 에 띄우면 카드들이 0% 에서 같이 멈춰있다가
한꺼번에 100% 가 되는 "정지된 듯한" 구간이 보였음.

이제 새 다운로드 시작 사이에 최소 2.5초 간격을 두어, 어떤 카드는 70%,
어떤 카드는 30% 식으로 항상 진행 흐름이 이어지게 만든다.

- musicStartChain 으로 acquire 직렬화 → race-free
- nextMusicStartAt 으로 마지막 시작 시점 추적
- 동시성(코어 수 기반) 자체는 그대로 유지, 시작 시점만 분산

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 00:24:33 +09:00
bb43e8b125 feat(installer-rp): auto-tune music concurrency to CPU core count
os.cpus().length 기준 동시 다운로드 수를 자동 결정:
- 2 코어 이하 → 2 동시
- 3~4 코어 → 3 동시
- 5~8 코어 → 4 동시
- 9 코어 이상 → 5 동시 (YouTube throttle 때문에 상한)

환경변수 MUSIC_CONCURRENCY 로 강제 오버라이드 가능(상한 8).
설치 로그에 감지된 코어 수와 선택된 동시성 노출.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 00:21:39 +09:00
861e5678fc perf(installer-rp): parallel music download (3 concurrent) + fragmented chunks
- yt-dlp 인자에 --concurrent-fragments 5 추가 (HLS/DASH 청크 병렬 다운로드)
- yt-dlp 인자에 --newline 추가 (진행률 라인 안정화)
- 음악 다운로드 루프를 단일 순차 → worker pool 3개 동시 처리로 전환
- state.currentChild (단일) → state.activeChildren (Set) 으로 확장,
  취소 시 실행 중인 모든 자식 프로세스 kill
- UI 는 카드 그리드라 병렬 진행 상태가 그대로 표시됨

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 00:19:29 +09:00
9f9cffffeb feat(installer-rp): auto-start install with progress card grid
2단계 페이지 진입 즉시 설치를 시작하고, 음악·사진을 1번부터 카드 그리드로
한눈에 볼 수 있게 만든다. 다운로드는 % 게이지로, 완료/실패는 색상으로 표시.

- main: prep/item/package phase 의 ProgressEvent 를 renderer 로 송신
- music.ts: yt-dlp stdout 의 [download] X% 라인을 파싱해 onProgress 호출
- preload: onProgress 채널 구독 함수 노출
- renderer: 다음 버튼 제거, prep chip + music/image 카드 그리드 + 빌드 상태
- styles: progressCard / prepChip / progressGrid 스타일 추가

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 20:01:15 +09:00
d5079125cb fix(installer-rp): type archiver warning handler explicitly
archive.on('warning', ...) 콜백의 err 파라미터에 implicit any 가 떠서
strict tsc 빌드가 깨졌다. Error & { code?: string } 로 명시.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 19:51:33 +09:00
4b83d95cbf Resolve pack_format from the pack's mcVersion
The previous hardcoded pack_format 34 + supported_formats 34..75
covered 1.21 through 1.21.11 only, so a pack generated for the
current latest (26.1.2 → format 84) was rejected as outdated.

Add src/installer-rp/packFormat.ts with a 1.21 → 26.2 lookup table
from the Minecraft wiki and resolveResourcePackFormat() that returns
{matched, format}. Unknown mcVersion falls back to the table's most
recent entry, with a log line warning the user.

Plumb mcVersion through the load → install flow:
- rp:packs:load now also fetches /manifest/<key>.json alongside
  /file/list/<key>.json and runs it through the existing
  normalizePackDefinition so the editor and the installer agree on
  the mcVersion shape. Pack manifest load failures fall back to an
  empty mcVersion (which then triggers the latest-format fallback).
- RpFetchedPack carries mcVersion; the install handler hands it to
  buildResourcepackZip.
- buildResourcepackZip drops the constant pack_format / supported_
  formats and uses the resolved format both as pack_format and as
  the {min,max} of supported_formats. Each pack is thus pinned to
  exactly the MC version it was authored for.
- The renderer's pack card now shows "마인크래프트 <version>" in
  the small line so the user can confirm before installing.

Verified locally: pack.mcmeta generated for mcVersion "1.21",
"1.21.6", "26.1.2", and the bogus "99.9.9" produce pack_format
34 / 63 / 84 / 86 (last falls back to the table tail) respectively.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 15:44:46 +09:00
8525517a87 Build resource pack zip and drop it into .minecraft
Add archiver dep (v7 — v8 dropped the function-style default export
that the @types still describe) and a new src/installer-rp/pack.ts
that assembles the resource pack tree under tempDir/resourcepack/
and zips it to %appdata%/.minecraft/resourcepacks/<key>_musicquiz.zip.

The tree matches Minecraft 1.21+ painting variant + custom sound
conventions:

  pack.mcmeta                                           pack_format 34,
                                                        supported 34..75
  assets/musicquiz/sounds.json                          stream:true per track
  assets/musicquiz/sounds/track_NN.ogg                  from tempDir/music
  assets/musicquiz/textures/painting/cover_NN.png       from tempDir/painting

Music NN.ogg is renamed to track_NN.ogg at copy time so the sound
event ids stay readable. The painting_variant JSON definitions are
intentionally NOT generated here — those live in the data pack and
are owned by /op/datapack on the website.

Wire step 2-4 of the install IPC to call buildResourcepackZip with
the now-populated music/painting temp dirs. Step 2-5 is now just a
log line since buildResourcepackZip writes directly to the final
path.

Verified by a node smoke test: tempDir of two stub ogg files plus
two 256x256 PNGs produces a valid zip with the expected entries
and UTF-8 Korean strings in pack.mcmeta description.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 15:36:58 +09:00
9e96366956 Download and normalize painting images via sharp
Add sharp dep (libvips bindings) — fastest option for the per-image
center-crop + Lanczos resize step. Pure-JS alternatives (jimp) and
spawning ffmpeg per image were both ~5-10x slower in this hot loop.

Add src/installer-rp/images.ts:
- ytIdFromUrl: extracts the video ID from watch?v=, youtu.be/, and
  /shorts|embed/ URL forms
- downloadImage: for YouTube URLs tries i.ytimg.com/vi/<id>/
  maxresdefault.jpg first, falls back to hqdefault.jpg; plain image
  URLs go through a generic HTTP/HTTPS GET that follows 302s
- normalizeToCover: center-crop to min(w,h), Lanczos resize down to
  1024x1024 when larger, never upscales, writes PNG
- coverFileName: returns cover_NN.png with zero-padded NN

Wire step 2-3 of the install handler to download + normalize each
image into <tempDir>/painting/cover_NN.png. Zip build (step 2-4)
will pick those up next.

Verified with synthetic 1200x800 and 2000x1500 buffers: small
input stays 800x800 (no upscale), large input becomes 1024x1024.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 15:30:11 +09:00
5e3a42ff4f Add ffmpeg prep and music ogg download to rp installer
Add src/installer-rp/ffmpeg.ts that downloads BtbN/FFmpeg-Builds
win64-gpl zip into %appdata%/.mc_custom/, extracts ffmpeg.exe out
of bin/, drops it at %appdata%/.mc_custom/ffmpeg.exe and verifies
with `ffmpeg -version`. Reuses existing extract-zip dep.

Add src/installer-rp/music.ts that spawns yt-dlp with
--extract-audio --audio-format vorbis --ffmpeg-location <ffmpeg.exe>
to produce <tempDir>/NN.ogg per track. Streams yt-dlp stdout to
the log channel and reports stderr on non-zero exit.

Wire both into the install IPC handler: step 2-1 now preps both
binaries, step 2-2 iterates the music list and downloads each
track. Track the currently running child process in state so the
cancel button can kill it instead of waiting for it to finish.

Image / zip / place steps remain stubbed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 15:23:01 +09:00
860c30fdfe Wire yt-dlp.exe prep into resource pack installer
Add src/installer-rp/ytdlp.ts that downloads
https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe
into %appdata%/.mc_custom/yt-dlp.exe (fixed path, Windows-only since
the installer is shipped as .exe). If the file is already there and
--version works it is reused; otherwise it is re-downloaded and
verified. The server's existing OS-aware ensureYtDlp stays intact.

The install IPC handler now calls ensureYtDlpExe() in step 2-1 and
logs the resolved path. Music / image / zip / place steps are still
stubbed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 15:18:01 +09:00
db5a1e0eac Scaffold resource pack installer entry
Add a second Electron entry under src/installer-rp/ + installer-rp/
launched by `npm run installer:rp`. It is structurally separate from
the music quiz installer (own tsconfig, own preload, own renderer),
shares the existing styles via a relative link, and exposes a
three-step UI: pick a 음악퀴즈, run the install, then a 완료 page that
can open the resourcepacks folder or quit.

The install IPC handler currently scaffolds the flow per docs/add.md
(yt-dlp prep → music download → image normalize → zip build → place
at %appdata%/.minecraft/resourcepacks/) but the actual work is still
TODO. Cancel/cleanup of %appdata%/.mc_custom/.temp/ is wired up so
that future iterations can plug each step in without rewiring.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 15:11:41 +09:00