diff --git a/src/server/datapack.ts b/src/server/datapack.ts index 2dcceab..5b7d134 100644 --- a/src/server/datapack.ts +++ b/src/server/datapack.ts @@ -1,8 +1,17 @@ import type { MusicListEntry, PackList } from '../shared/types.js' -/** SNBT 문자열 리터럴 안에 들어갈 문자열을 escape. */ +/** + * SNBT 문자열 리터럴 안에 들어갈 문자열을 escape. + * 백슬래시·따옴표 외에도 줄바꿈·탭을 이스케이프해서 `data modify` 한 줄 명령이 + * description 같은 멀티라인 입력 때문에 깨지지 않게 한다. + */ function escapeSnbtString(input: string): string { - return input.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + return input + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\r/g, '\\r') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') } /** alias 배열을 SNBT 리스트 리터럴로 변환. 빈 배열도 `[]` 로 출력. */ @@ -12,13 +21,14 @@ function aliasListSnbt(aliases: string[]): string { return `[${parts.join(',')}]` } -/** 한 곡(MusicListEntry) → `{title:"...", author:"...", alias:[...]}` SNBT. */ +/** 한 곡(MusicListEntry) → `{title:"...", author:"...", alias:[...], description:"..."}` SNBT. */ function entrySnbt(entry: MusicListEntry): string { const title = escapeSnbtString(entry.title ?? '') // launcher 의 artist → 데이터팩 SNBT 의 author. 빈 값은 빈 문자열로 그대로 둔다. const author = escapeSnbtString(entry.artist ?? '') const alias = aliasListSnbt(entry.aliases ?? []) - return `{title:"${title}", author:"${author}", alias:${alias}}` + const description = escapeSnbtString(entry.description ?? '') + return `{title:"${title}", author:"${author}", alias:${alias}, description:"${description}"}` } /** @@ -29,11 +39,11 @@ function entrySnbt(entry: MusicListEntry): string { export function buildSongsMcfunction(list: PackList): string { const lines: string[] = [] lines.push('# 곡 한 개 = 한 줄.') - lines.push('# 필수 — title, author, alias') + lines.push('# 필수 — title, author, alias, description') lines.push('# 선택 — volume (이 곡만의 /playsound 음량. 미지정시 init/config.mcfunction') lines.push('# 의 audio.volume 사용)') lines.push('# 곡 순서가 리소스팩의 track_NN / cover_NN 인덱스와 1:1 매칭된다.') - lines.push('# 예) {title:"Quiet Song", author:"...", alias:[...], volume:2.0}') + lines.push('# 예) {title:"Quiet Song", author:"...", alias:[...], description:"...", volume:2.0}') lines.push('data modify storage mq:main songs set value []') for (const entry of list.music) { lines.push(`data modify storage mq:main songs append value ${entrySnbt(entry)}`)