op: 데이터팩 출력을 zip 대신 songs.mcfunction 코드 텍스트로 변경
운영자가 mc_datapack 의 init/songs.mcfunction 파일에 직접 복사해 붙여넣
는 워크플로로 단순화. 전체 데이터팩을 패키징할 필요가 없다.
- /op/datapack/:packName/generate 가 buildSongsMcfunction(list) 결과를
text/plain 으로 반환 (zip 스트리밍 제거).
- file/datapacks/music_quiz_template/ 정적 사본 제거.
- datapack.ejs 에 코드블록·복사 버튼 복원, 안내 문구 추가
("data/mq/function/init/songs.mcfunction 에 그대로 덮어쓰세요").
- datapack 로케일 라벨을 "코드 출력 / 복사 / 출력 완료" 로 정리.
This commit is contained in:
@@ -1,14 +1,5 @@
|
||||
import path from 'node:path'
|
||||
import { Readable } from 'node:stream'
|
||||
import archiver from 'archiver'
|
||||
import type { Response } from 'express'
|
||||
import { fileDatapacksDirPath } from '../shared/paths.js'
|
||||
import type { MusicListEntry, PackList } from '../shared/types.js'
|
||||
|
||||
/** music_quiz/ 정적 템플릿 디렉터리. (songs.mcfunction 만 동적으로 생성) */
|
||||
const TEMPLATE_DIR = path.join(fileDatapacksDirPath, 'music_quiz_template')
|
||||
const SONGS_PATH_IN_ZIP = 'music_quiz/data/mq/function/init/songs.mcfunction'
|
||||
|
||||
/** SNBT 문자열 리터럴 안에 들어갈 문자열을 escape. */
|
||||
function escapeSnbtString(input: string): string {
|
||||
return input.replace(/\\/g, '\\\\').replace(/"/g, '\\"')
|
||||
@@ -30,7 +21,11 @@ function entrySnbt(entry: MusicListEntry): string {
|
||||
return `{title:"${title}", author:"${author}", alias:${alias}}`
|
||||
}
|
||||
|
||||
/** list.music 으로부터 `data/mq/function/init/songs.mcfunction` 본문을 생성. */
|
||||
/**
|
||||
* list.music 으로부터 `data/mq/function/init/songs.mcfunction` 본문을 생성.
|
||||
* 운영자는 mc_datapack 의 music_quiz 데이터팩에서 이 파일만 이 내용으로
|
||||
* 덮어쓰면 된다 — 나머지 파일은 launcher 가 관여하지 않는다.
|
||||
*/
|
||||
export function buildSongsMcfunction(list: PackList): string {
|
||||
const lines: string[] = []
|
||||
lines.push('# 곡 한 개 = 한 줄.')
|
||||
@@ -48,32 +43,3 @@ export function buildSongsMcfunction(list: PackList): string {
|
||||
lines.push('execute store result storage mq:main max_index int 1 run data get storage mq:main songs')
|
||||
return lines.join('\n') + '\n'
|
||||
}
|
||||
|
||||
/** music_quiz 데이터팩 zip 을 Response 로 스트리밍. */
|
||||
export function streamMusicQuizZip(res: Response, packKey: string, list: PackList): void {
|
||||
const fileName = `music_quiz_${packKey}.zip`
|
||||
res.setHeader('Content-Type', 'application/zip')
|
||||
res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`)
|
||||
|
||||
const archive = archiver('zip', { zlib: { level: 9 } })
|
||||
archive.on('warning', (err) => {
|
||||
if (err.code !== 'ENOENT') res.destroy(err)
|
||||
})
|
||||
archive.on('error', (err) => {
|
||||
res.destroy(err)
|
||||
})
|
||||
archive.pipe(res)
|
||||
|
||||
// 정적 템플릿 전체를 music_quiz/ 아래로 묶되 songs.mcfunction 만 제외.
|
||||
archive.glob('**/*', {
|
||||
cwd: TEMPLATE_DIR,
|
||||
dot: false,
|
||||
ignore: ['data/mq/function/init/songs.mcfunction']
|
||||
}, { prefix: 'music_quiz/' })
|
||||
|
||||
// 동적으로 만든 songs.mcfunction 을 추가.
|
||||
const songsText = buildSongsMcfunction(list)
|
||||
archive.append(Readable.from([songsText]), { name: SONGS_PATH_IN_ZIP })
|
||||
|
||||
void archive.finalize()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user