리뷰어 지적 후속:
- docs/mc_video_player_mod_integration.md 복구 (f0a2e4f 에서 추출).
pull 시점에 main 에 없어서 같이 사라졌던 파일.
- temp/ 부분 적용 패키지 v1.0.26 기준으로 복구. 좌표 보존을 위해
init/*.mcfunction 은 일부러 제외, framework 파일만 포함:
- commands/start.mcfunction, load.mcfunction (모드 게이트 + objective)
- repeat/buttons/{btn,btn_prep,handler}.mcfunction
- repeat/timer.mcfunction + repeat/timers/{init2,init6,init10}.mcfunction
- temp/README.md 에 적용 방법 + 라벨 추가 안내 명시.
- README.md 사실 정정:
- 음원 채널 "기본 weather" → 실제 config.mcfunction 은 player
(UI 비프만 weather). source 가 무엇이 무엇인지 명시.
- 스토리지 섹션의 marker 항목 제거 (현재 config 에 marker 정의 없음,
legacy kill 한 줄만 잔존). mq:input 큐 추가, mq:tmp 페이로드 갱신.
- init/config.mcfunction 설명 / 좌표 의존성 섹션에서 marker 제거.
데이터팩 코드 변경 없음 — v1.0.25 = v1.0.26 동작 동일.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
mc_datapack
마인크래프트 자작 데이터팩 모음 저장소.
현재 포함된 데이터팩:
music_quiz/— 음악퀴즈 데이터팩
music_quiz — 음악퀴즈 데이터팩
플레이어가 노래를 듣고 정답을 맞히는 멀티플레이 음악 퀴즈. 관리자가 버튼/대화창으로 라운드를 진행하고, 참가자는 트리거 명령으로 정답·스킵·힌트·다시듣기 투표에 참여한다.
호환 버전
- Minecraft 26.1.2 (
pack.mcmeta의min_format/max_format모두[101, 1]). - 1.21.6에서 도입된
dialog시스템, 1.21+의 단수형function/태그 폴더, 매크로 함수(function ... with storage) 기능을 사용한다. - 텍스트 컴포넌트는 JSON 표기로 작성돼 있으며, 1.21.5 이후의 SNBT 파서와도 호환된다 (JSON은 SNBT의 부분집합).
외부 모드 의존성 (서버/클라)
서버 측 검증이 들어가 있어 다음 두 모드가 반드시 깔려 있어야 /start 가
진행된다. 미설치 시 commands/start 의 게이트가 사유와 함께 차단한다.
mc_chat_answer_modv1.3.7+ — 서버 전용. 채팅으로 정답 입력을 받는다. presence 는#server mq_chat_mod점수로 매 tick 표시되며,SERVER_STARTED/END_DATA_PACK_RELOAD/PlayerJoin/ServerTick네 지점에서 갱신된다. https://git.tkrmagid.kr/tkrmagid/mc_chat_answer_mod/releases/tag/v1.3.7mc_video_player_mod— 클라이언트 + 서버 모두 필요. 서버 컴포넌트가#server mq_video_mod를 1 로 갱신하고, 클라 join handshake 가 도착하면<player> mq_video_mod를 1 로 set./start는 서버 부재 시 단일 차단, 특정 플레이어 부재 시 본인에게 안내 + 게임 시작 차단.
100% 바닐라 — 의존 플러그인 없음 (모드 외)
음원 재생과 정답 이미지 표시는 모두 바닐라 명령으로 처리한다. 음원과
페인팅 텍스처는 minecraft_launcher
가 만들어주는 리소스팩(musicquiz 네임스페이스)에서 가져온다.
- 음원:
/playsound musicquiz:track_NN <source> @s ~ ~ ~ <volume> <pitch>(예:musicquiz:track_01).init/config.mcfunction의audio.source가 채널을 결정하며, 곡 재생은 기본player채널 (음성/플레이어 볼륨 슬라이더로 음량 제어).stopsound도 같은 채널로 묶여 있다. 카운트다운 비프와 종료 클릭 같은 UI 사운드는 별도로weather채널을 사용한다. - 정답 이미지:
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_prep →
btn 매크로 체인을 호출한다.
start/stop/skip/hint/replay/test
버튼 본체는 보이는 stone_button 블록 + 클릭을 받는 interaction 엔티티
3 타일 (블록 면 바깥, 플레이어 쪽으로 살짝 튀어나오게) + 버튼 바로 아래
벽면에 부착되는 text_display 라벨 1 개로 구성된다. interaction 폭이
width × width 정사각형으로 강제되기 때문에 stone_button hitbox 의 가로
0.375 를 0.125 폭 × 3 타일로 덮고, 깊이는 두께(0.125) 만큼 밖으로 밀어
vanilla stone_button 클릭이 동시에 발화되지 않도록 한다. 라벨은 bold
적용 text component 로 직접 렌더링된다.
각 button_defs 항목의 필드:
- 필수:
n(이름·태그),x,y,z,f(facing),c(실행 명령) - 옵션:
label,label_color(기본black),label_font(기본minecraft:default),label_scale(기본1.0).btn_prep에서 defaults +merge from패턴으로 기본값이 자동 채워진다.
클릭 처리는 항상 interaction 경로로 흐르므로 on target as @s 로 누른
플레이어가 식별되고, 다수결(trigger $(n)) 투표가 성립한다.
interaction / text_display 는 데이터팩이 직접 소환·관리한다 —
buttons 점수가 -1 (초기화) 일 때마다 같은 태그의 기존 entity 를
정리하고 정확한 개수만 (재)소환한다. /reload 가 commands/stop 을
호출해 buttons 점수를 -1 로 재설정하므로 리로드 시 자동 보장된다.
/kill @e 로 지워졌어도 다음 /reload 한 번으로 복구. 월드 회로
(커맨드블럭) 의존은 없다.
파일 구조
music_quiz/
├── pack.mcmeta # min_format/max_format [101, 1]
├── pack.png
└── 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 # 주제·스폰·오디오·페인팅 설정
│ │ ├── 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 매크로
│ ├── images/ # 정답 페인팅 표시·제거
│ │ ├── show.mcfunction # cover painting 소환
│ │ ├── clear.mcfunction # cover painting 일괄 제거
│ │ └── macro/show.mcfunction # $summon painting 매크로
│ ├── repeat/ # tick에서 호출되는 매 틱 처리
│ │ ├── players·check_answer·timer.mcfunction
│ │ ├── timers/{init2,init6,init10}.mcfunction # init 단계별 timer 디스패치 분할
│ │ ├── buttons/{handler,btn_prep,btn}.mcfunction
│ │ └── triggers/{handler,trigger}.mcfunction
│ ├── answer/ # 채팅 정답 입력 정규화/판정 (chat_answer 모드 경로)
│ └── players/{login,mod_active_notice}.mcfunction
├── dialog/page{1,2,3}.json
├── painting_variant/{cover_01..50,gif}.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}— 정답 페인팅 좌표answer={title, author, alias, track, cover}— 현재 곡 정답songs— 곡 목록 (mq:init/songs가 채움)button_defs/trigger_defs— 버튼·트리거 정의
mq:tmp— setanswer·play_sound·페인팅·버튼 호출용 임시 페이로드 (idx, pad, num, playsound, painting, btn, btn_default)mq:input— 채팅 정답 입력 큐 (chat_answer 모드 경로)func:temp—func:헬퍼 함수용 임시 NBT
참고: 과거
marker스토리지와minecraft:marker정답 입력 엔티티는 폐기됨.commands/stop의kill @e[type=marker,tag=mq]한 줄만 이전 월드에 남아 있을 수 있는 legacy entity 청소 목적으로 유지된다.
설정 (한 곳에서 수정)
세계마다 다른 값은 모두 data/mq/function/init/ 폴더에서 편집한다.
/reload 후 반영된다.
init/config.mcfunction— 주제, 스폰 위치, 오디오 설정(audio), 정답 페인팅 좌표(image).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 참조를 일관되게 지원하지 않으므로 직접
편집해야 한다.
설치
- 서버 월드 폴더
datapacks/에music_quiz/디렉터리째 복사. - 서버 mods 폴더에
mc_chat_answer_modv1.3.7+ 와mc_video_player_modjar 설치.mc_video_player_mod는 클라이언트 측에도 설치 필요. - minecraft_launcher 에서 생성한
musicquiz리소스팩을 클라이언트에 적용 (런처가 자동 처리). - 서버
/reload— 리로드 성공 메시지가 채팅에 표시되면 정상. mq:init/buttons에 정의된 좌표 부근에 6개 버튼이 자동 배치된다.start버튼을 눌러 게임 시작 — 모드 미설치 시 사유와 함께 차단된다.
좌표 의존성 (주의)
다음 좌표는 데이터팩 안에 박혀 있어 다른 월드에서 쓰려면 직접 바꿔야 한다. 현재 박혀 있는 좌표는 본인 월드 기준이므로 그대로 옮겨가면 동작 안 한다.
- 정답 페인팅 / 플레이어 스폰 —
init/config.mcfunction(image,spawn) - 버튼 좌표·facing —
init/buttons.mcfunction(button_defs의x,y,z,f)
변경 이력
2026-05-19 — v1.0.25: 버튼 hitbox/라벨 미세조정 + 곡목록·좌표 갱신
repeat/buttons/btn.mcfunction: interaction hitbox 미세조정 (width0.13 가운데 타일로 micro-gap 보정,height0.26, 깊이 오프셋 0.07/0.93, text_display Y~-0.5로 라벨 위치 조정).- 셀렉터 정렬
[type=...,tag=mq,tag=$(n)]→[distance=0..,tag=mq, tag=$(n),type=...]. init/songs.mcfunction: 아이유 17 곡 셋으로 교체 (alias 빈 배열).init/buttons.mcfunction: 버튼 좌표 본인 월드 기준으로 갱신,label필드 추가 ("게임시작" / "정지" / "넘기기" / "힌트" / "다시듣기" / "소리 테스트").repeat/timer.mcfunction분할 →repeat/timers/{init2,init6,init10}.commands/start.mcfunction에mq_video_mod게이트 추가 (서버 부재 단일 차단 + 플레이어별 부재 안내).load.mcfunction에mq_video_modobjective +#server0 materialize 추가.
2026-05-18 ~ 19 — v1.0.19 ~ v1.0.24: 버튼 인프라 안정화
- v1.0.19/20/21:
btn_prepdefaults+merge 패턴,positioned $(x).0로 +0.5 보정 회피, interaction 3 타일 분할,text_display도입. - v1.0.23: 채팅정답 모드 false negative 의 진짜 fix — 데이터팩 게이트는
유지하고 모드 (
mc_chat_answer_modv1.3.7) 의 presence pulse 를 4 지점으로 확장. - v1.0.24:
text_displayY 보정 (~-1→~-0.25) + 라벨 bold + v1.0.21 의 interaction 깊이 부호 반전 수정.
2026-05-13 — 26.1.2 호환 + 1차 정리 (b1babad)
이전 푸시본(6841b7a 이전퀴즈 데이터팩)을 26.1.2 기준으로 정비.
pack_format69 → 75 (MC 26.1.2 / 1.21.11). 이후min_format/max_format가[101, 1]로 갱신됨 (현재).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
가 생성하는 musicquiz 리소스팩과 한 쌍으로 동작한다.
삭제
mq:check/server+mq:repeat/check_server— 플러그인 설치 확인 로직mq:quiz/macro/command_block—data modify block … Command+auto토글 패턴 (YPplayall호출용)mq:quiz/play— 명령 블록 강제 재발화 함수mq:images/image{,_set,_delete}— TSplaceloc/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