# mc_datapack 마인크래프트 자작 데이터팩 모음 저장소. 현재 포함된 데이터팩: - `music_quiz/` — 음악퀴즈 데이터팩 --- ## music_quiz — 음악퀴즈 데이터팩 플레이어가 노래를 듣고 정답을 맞히는 멀티플레이 음악 퀴즈. 관리자가 버튼/대화창으로 라운드를 진행하고, 참가자는 트리거 명령으로 정답·스킵·힌트·다시듣기 투표에 참여한다. ### 호환 버전 - **Minecraft 26.1.2** (pack_format `75`) 기준. - 1.21.6에서 도입된 `dialog` 시스템, 1.21+의 단수형 `function/` 태그 폴더, 매크로 함수(`function ... with storage`) 기능을 사용한다. - 텍스트 컴포넌트는 JSON 표기로 작성돼 있으며, 1.21.5 이후의 SNBT 파서와도 호환된다 (JSON은 SNBT의 부분집합). ### 100% 바닐라 — 의존 플러그인 없음 음원 재생과 정답 이미지 표시는 모두 바닐라 명령으로 처리한다. 음원과 페인팅 텍스처는 [minecraft_launcher](https://git.tkrmagid.kr/tkrmagid/minecraft_launcher) 가 만들어주는 리소스팩(`musicquiz` 네임스페이스)에서 가져온다. - 음원: `/playsound musicquiz:track_NN @s ~ ~ ~ ` (예: `musicquiz:track_01`). 채널은 기본 `weather` — `stopsound` 와 함께 묶여 있다. - 정답 이미지: `painting_variant musicquiz:cover_NN` 을 `/summon painting` 으로 벽에 띄우고, 다음 곡 직전 `kill @e[type=painting,tag=mq_cover]` 로 제거. 리소스팩 트랙 번호와 `mq:init/songs` 리스트의 순서가 1:1로 일치해야 한다. 1번째 곡 → `track_01` / `cover_01`, … (2자리 zero-pad). ### 게임 흐름과 상태 (`init` 스코어보드) 게임 전체 상태는 `main` 스코어보드의 가상 플레이어 `init` 값으로 관리한다. | `init` | 단계 | |--------|------| | `0` | 정지/대기 (기본 상태) | | `1` | 게임 시작 — page1 대화창에서 `ready` 트리거 대기 | | `2` | 카운트다운 (3·2·1) | | `5` | 곡 재생 + 정답 입력 단계 | | `6` | 정답 공개·점수 부여 | | `10` | 엔딩 시퀀스 | `main` 스코어보드의 `timer`는 활성 상태에서만 증가하는 카운터로, `mq:repeat/timer`가 이를 보고 상태 전이를 처리한다. 매 틱 디스패치는 `init` 값에 따라 게이팅된다. ### 트리거 명령 다음 명령은 `trigger` 타입 스코어보드로 등록돼 있어 어드벤처 모드의 일반 플레이어도 사용할 수 있다. - `trigger ready` — 시작 안내 대화창에서 시작 확정 - `trigger cancel` — 시작 취소 - `trigger stop` — 다수결 종료 - `trigger skip` — 다수결 스킵 (현재 곡 패스) - `trigger hint` — 다수결 힌트 요청 (자음 절반 가리기 — `func:hint`) - `trigger replay` — 다수결 다시 듣기 스킵/힌트/리플레이는 `mq:repeat/triggers/trigger` 매크로 안에서 `max_player = ceil(전체/2)` 다수결 계산을 거친 뒤 실행된다. 트리거 정의 자체는 `mq:init/triggers`에서 storage 리스트로 관리된다. ### 입력 버튼 관리자가 사용하는 6개의 물리 스톤 버튼. 좌표·표면 방향·실행 명령은 `mq:init/buttons`에서 storage 리스트(`mq:main button_defs`)로 관리되며, `mq:repeat/buttons/handler`가 매 틱 storage 인덱스로 `btn` 매크로를 호출한다. - `start` / `stop` / `skip` / `hint` / `replay` / `test` 버튼 본체는 보이는 `stone_button` 블록 + 그 좌표에 덮인 `interaction` 엔티티로 구성된다. 클릭 처리는 항상 `interaction` 경로로 흐르므로 `on target as @s` 로 누른 플레이어가 식별되고, 다수결(`trigger $(n)`) 투표가 성립한다. `interaction` 은 데이터팩이 직접 소환·관리한다 — `buttons` 점수가 `-1` (초기화) 일 때마다 같은 태그의 기존 entity 를 정리하고 정확히 1개를 (재)소환한다. `/reload` 가 `commands/stop` 을 호출해 `buttons` 점수를 `-1` 로 재설정하므로, 리로드 시 자동 보장된다. `/kill @e` 로 지워졌어도 다음 `/reload` 한 번으로 복구. 월드 회로(커맨드블럭) 의존은 없다. ### 파일 구조 ``` music_quiz/ ├── pack.mcmeta # pack_format 75 └── data/ ├── minecraft/tags/function/ │ ├── load.json # → mq:load │ └── tick.json # → mq:tick ├── func/function/ # 공용 헬퍼 (length/half/shuffle/text_list/join…) │ ─ mq:commands/hint에서 사용 └── mq/ ├── function/ │ ├── load.mcfunction # 스코어보드·storage 초기화, init/* 호출 │ ├── tick.mcfunction # 매 틱 서브함수 디스패치 (init 게이팅) │ ├── tellraw.mcfunction # 매크로 prefix 메시지 헬퍼 │ ├── init/ # 사용자 설정·정적 데이터 (수정 포인트) │ │ ├── config.mcfunction # 주제·스폰·오디오·페인팅·marker 설정 │ │ ├── songs.mcfunction # 곡 목록 + max_index 자동계산 │ │ ├── buttons.mcfunction # 버튼 좌표·실행 명령 │ │ └── triggers.mcfunction # 다수결 트리거 정의 │ ├── commands/ # start·stop·skip·hint·replay·test │ ├── quiz/ # 게임 진행 로직 │ │ ├── start·select·setanswer·correct·end.mcfunction │ │ ├── play_sound·stop_sound.mcfunction # /playsound · /stopsound 래퍼 │ │ └── macro/ # 매크로 진입점 │ │ ├── setanswer.mcfunction # songs[$(idx)] → answer + track/cover id │ │ ├── play_sound.mcfunction # $playsound 매크로 │ │ ├── stop_sound.mcfunction # $stopsound 매크로 │ │ └── summon{,2}.mcfunction # 정답 marker 엔티티 + alias 체인 │ ├── images/ # 정답 페인팅 표시·제거 │ │ ├── show.mcfunction # cover painting 소환 │ │ ├── clear.mcfunction # cover painting 일괄 제거 │ │ └── macro/show.mcfunction # $summon painting 매크로 │ ├── repeat/ # tick에서 호출되는 매 틱 처리 │ │ ├── players·check_answer·timer.mcfunction │ │ ├── buttons/{handler,btn}.mcfunction │ │ └── triggers/{handler,trigger}.mcfunction │ └── players/login.mcfunction ├── dialog/page{1,2,3}.json └── advancement/player/login.json ``` ### 사용 스코어보드 / 스토리지 스코어보드: - `main` — 게임 핵심 상태 (`init`, `index`, `max_index`, `timer`, `score`, `song_idx`) - `buttons` — 물리 버튼 상태 머신 - `answer` — 플레이어별 정답 입력값 (`1`=정답, `2`=오답) - `func.temp` — 산술용 임시 상수 (`two=2` 등) - `leave_game` — `custom:leave_game` 통계 (재접속 감지) - `score` — 사이드바 표시용 점수 - `ready` / `cancel` / `stop` / `skip` / `hint` / `replay` — 플레이어 트리거 스토리지: - `mq:main` — 게임 전역 데이터 - `title`, `max_index`, `spawn` — 설정 - `audio` = `{namespace, source, volume, pitch}` — `/playsound` 파라미터 - `image` = `{namespace, x, y, z, facing}` — 정답 페인팅 좌표 - `marker` = `{x, y, z}` — 정답 입력 marker 엔티티 위치 - `answer` = `{title, author, alias, track, cover}` — 현재 곡 정답 - `songs` — 곡 목록 (`mq:init/songs` 가 채움) - `button_defs` / `trigger_defs` — 버튼·트리거 정의 - `mq:tmp` — setanswer·play_sound·페인팅 호출용 임시 페이로드 (idx, pad, num, playsound, painting, marker_call) - `func:temp` — `func:` 헬퍼 함수용 임시 NBT ### 설정 (한 곳에서 수정) 세계마다 다른 값은 모두 `data/mq/function/init/` 폴더에서 편집한다. `/reload` 후 반영된다. - **`init/config.mcfunction`** — 주제, 스폰 위치, 오디오 설정(`audio`), 정답 페인팅 좌표(`image`), marker 엔티티 좌표. `title` 은 `[ … ]` 채팅 접두사로도 사용된다. - **`init/songs.mcfunction`** — 곡 목록 (한 줄에 한 곡씩 append). `alias` 배열의 문자열은 정답 판정 시 동의어로 인정된다. **곡의 순서가 리소스팩 트랙 번호와 1:1 매칭** 되므로 순서 변경 시 리소스팩도 함께 재생성해야 한다. `max_index` 는 리스트 길이로 자동 계산된다. - **`init/buttons.mcfunction`** — 6개 물리 버튼의 좌표·표면 방향·실행 명령. - **`init/triggers.mcfunction`** — 다수결 트리거(`stop`/`skip`/`hint`/`replay`) 표시 이름·실행 명령. `load.mcfunction` 은 위 4개를 호출해 `mq:main` 스토리지를 적재한다. 스코어보드·보스바 같은 런타임 인프라는 `load.mcfunction` 본문에 남아 있다. 다이얼로그 페이지(`data/mq/dialog/page{1,2,3}.json`) 의 타이틀과 설명문구는 JSON 텍스트 컴포넌트가 storage 참조를 일관되게 지원하지 않으므로 직접 편집해야 한다. ### 설치 1. 서버 월드 폴더 `datapacks/`에 `music_quiz/` 디렉터리째 복사. 2. minecraft_launcher 에서 생성한 `musicquiz` 리소스팩을 클라이언트에 적용 (런처가 자동 처리). 3. 서버 `/reload` — 리로드 성공 메시지가 채팅에 표시되면 정상. 4. 좌표 `144, 62, -225` 부근에 6개 버튼이 자동 배치된다. 5. `start` 버튼을 눌러 게임 시작. ### 좌표 의존성 (주의) 다음 좌표가 데이터팩 안에 박혀 있어, 다른 월드에서 그대로 사용하려면 `init/config.mcfunction` 의 값을 바꿔야 한다: - 정답 입력 marker: `144 59 -219` — `marker.{x,y,z}` - 정답 페인팅: `144 84 -261` (facing south) — `image.{x,y,z,facing}` - 플레이어 스폰: `144 61 -219` (yaw 180) — `spawn` - 버튼 좌표: `140..148, 62, -225` / `144, 62, -213` — `mq:init/buttons` --- ## 변경 이력 ### 2026-05-13 — 26.1.2 호환 + 1차 정리 (`b1babad`) 이전 푸시본(`6841b7a 이전퀴즈 데이터팩`)을 26.1.2 기준으로 정비. - `pack_format` 69 → 75 (MC 26.1.2 / 1.21.11) - `mq:load`, `mq:players/login`, `mq:commands/start`, `mq:commands/stop`, `mq:quiz/start`, `mq:quiz/end`, `mq:repeat/buttons/btn` 등에 남아 있던 `# say ...` / `# stopsound` 사문화 디버그 주석 제거 ### 2026-05-13 — 무대 의존 제거 + 최적화 (`2b61af2`) 특정 맵 좌표에만 동작하던 장식 로직을 들어내고, 매 틱 부하와 정적 데이터 관리를 정비했다. - `repeat/map/` (무대 트리/조명 애니메이션) 삭제 - `images/image_custom.mcfunction` (호출자 없는 사문화 코드) 삭제 - `tick.mcfunction` 디스패치를 `init` 상태로 게이팅 (idle 틱 함수 호출 8→4) - 곡 데이터를 `mq:init/songs` 의 `mq:main.songs` 리스트로 한 번 적재. 매크로 룩업 한 줄로 50× → O(1) 복사 - 버튼/트리거 정의를 `mq:init/buttons` / `mq:init/triggers` 의 storage 리스트로 분리. handler 는 인덱스로 매크로 호출만 한다. - 다수결 산술 dedup (트리거당 5 라인 절감 × 4 트리거) ### 2026-05-13 — 설정 통합 (`b236118`) 세계별 수정 포인트를 한 파일로 모았다. - `init/config.mcfunction` 신설 — 주제·곡 개수·스폰·명령 블록 좌표를 한곳에 - `mq:tellraw` 가 `mq:main.title` 을 읽도록 변경 ([ 주제 ] 접두사 동기화) ### 2026-05-13 — 바닐라 마이그레이션 (이번 커밋) YP / TS Bukkit 플러그인 의존을 제거하고, 음원과 정답 이미지를 바닐라 명령으로 재구현했다. [minecraft_launcher](https://git.tkrmagid.kr/tkrmagid/minecraft_launcher) 가 생성하는 `musicquiz` 리소스팩과 한 쌍으로 동작한다. #### 삭제 - `mq:check/server` + `mq:repeat/check_server` — 플러그인 설치 확인 로직 - `mq:quiz/macro/command_block` — `data modify block … Command` + `auto` 토글 패턴 (YP `playall` 호출용) - `mq:quiz/play` — 명령 블록 강제 재발화 함수 - `mq:images/image{,_set,_delete}` — TS `placeloc` / `removeall` 호출 - `status` 스코어보드 (`yp`, `ts`, `skript`, `timer`) — 플러그인 hello 패킷 대기에만 쓰이던 객체 #### 신설 - **음원** — `mq:quiz/play_sound` → `mq:quiz/macro/play_sound`: `$execute as @a at @s run playsound $(namespace):$(track) $(source) @s ~ ~ ~ $(volume) $(pitch)` - **음원 정지** — `mq:quiz/stop_sound` → `mq:quiz/macro/stop_sound`: `$stopsound @a $(source)` (모든 stopsound 호출 합쳐서 매크로화) - **정답 페인팅** — `mq:images/show` → `mq:images/macro/show`: `$summon minecraft:painting $(x) $(y) $(z) {variant:"$(namespace):$(cover)",facing:$(facing)b,Tags:["mq","mq_cover"]}` - **정답 페인팅 제거** — `mq:images/clear`: `kill @e[type=painting,tag=mq_cover]` #### 스토리지 재구성 - `command_block` 컴파운드(좌표·볼륨·이미지 영역·alias 사본을 한데 묶었던 것) 폐기 - `audio` = `{namespace, source, volume, pitch}` 신설 — `/playsound` 인자 - `image` = `{namespace, x, y, z, facing}` 신설 — `/summon painting` 좌표 - `marker` = `{x, y, z}` 신설 — 정답 입력 marker 위치 - `answer.track` / `answer.cover` 필드 추가 — 라운드별 리소스팩 ID (`track_NN` / `cover_NN`) - `max_index` 는 `mq:init/songs` 끝에서 `songs` 배열 길이로 자동 계산 (수동 동기화 필요 없음) #### 트랙 번호 padding mcfunction 은 문자열 zero-pad 가 없으므로, `quiz/select` 에서 `index ∈ 1..9` 일 때만 `mq:tmp.pad="0"` 로 분기시키고, 매크로 안에서 `"track_$(pad)$(num)"` 로 조립한다. #### 기타 - `tick.mcfunction` 에서 `mq:repeat/check_server` 제거 (매 틱 함수 호출 4→3 으로 추가 감소) - `commands/start` / `commands/stop` / `commands/replay` 의 하드코딩된 `stopsound @a weather` 를 모두 `function mq:quiz/stop_sound` 로 교체 — 채널 변경 시 `audio.source` 한 곳만 수정하면 됨 - `setanswer` 호출 경로 단축: 기존 `select → macro/command_block → play(auto-toggle) → setanswer → macro/setanswer + macro/summon` → 현재 `select → setanswer → macro/setanswer → macro/summon → play_sound` --- ## 원격 저장소 - `https://git.tkrmagid.kr/tkrmagid/mc_datapack.git`