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>
This commit is contained in:
2026-05-12 15:44:46 +09:00
parent 8525517a87
commit 4b83d95cbf
5 changed files with 86 additions and 18 deletions

View File

@@ -1,16 +1,10 @@
import { promises as fs, createWriteStream } from 'node:fs'
import path from 'node:path'
import archiver from 'archiver'
import { resolveResourcePackFormat } from './packFormat.js'
const NAMESPACE = 'musicquiz'
/**
* 1.21 (pack_format 34) 를 기준으로 하되 supported_formats 로 1.21 ~ 1.21.11
* 까지 받아들이도록 선언. 더 신 버전이 나오면 max_inclusive 만 올리면 됨.
*/
const RESOURCE_PACK_FORMAT = 34
const SUPPORTED_FORMATS = { min_inclusive: 34, max_inclusive: 75 }
export interface BuildResourcepackOptions {
/** ogg 음악 파일들이 들어 있는 폴더 (01.ogg, 02.ogg, …). */
musicDir: string
@@ -18,10 +12,14 @@ export interface BuildResourcepackOptions {
paintingDir: string
/** pack.mcmeta 의 description 에 들어갈 표시 이름. */
packName: string
/** /manifest/<key>.json 의 mcVersion. pack_format 결정용. */
mcVersion: string
/** 작업 폴더(임시). 이 안에 트리를 펼친 뒤 zip 생성. */
workDir: string
/** 최종 zip 출력 경로. */
outZipPath: string
/** 진단용 로그 콜백 (선택). */
log?: (line: string) => void
}
/**
@@ -42,11 +40,19 @@ export async function buildResourcepackZip(opts: BuildResourcepackOptions): Prom
await fs.mkdir(paintingOutDir, { recursive: true })
// 1) pack.mcmeta
// mcVersion 으로 resource pack format 을 결정. 알 수 없는 버전이면 가장 최근
// 알려진 포맷으로 폴백 (resolveResourcePackFormat 가 알아서 처리).
const resolved = resolveResourcePackFormat(opts.mcVersion)
if (resolved.matched) {
opts.log?.(`pack_format = ${resolved.format} (mcVersion ${resolved.matched})`)
} else {
opts.log?.(`pack_format = ${resolved.format} (mcVersion "${opts.mcVersion}" 매칭 실패, 최신 폴백)`)
}
const mcmeta = {
pack: {
description: `음악퀴즈 리소스팩 - ${opts.packName}`,
pack_format: RESOURCE_PACK_FORMAT,
supported_formats: SUPPORTED_FORMATS
pack_format: resolved.format,
supported_formats: { min_inclusive: resolved.format, max_inclusive: resolved.format }
}
}
await fs.writeFile(path.join(root, 'pack.mcmeta'), JSON.stringify(mcmeta, null, 2) + '\n')