Files
mc_datapack/README.md
Claude (owner) d8d5e75e7d v1.0.26: 삭제됐던 docs/temp 복구 + README 사실 정정
리뷰어 지적 후속:
- 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>
2026-05-19 02:53:26 +09:00

363 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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_mod` v1.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.7
- **`mc_video_player_mod`** — 클라이언트 + 서버 모두 필요. 서버 컴포넌트가
`#server mq_video_mod` 를 1 로 갱신하고, 클라 join handshake 가 도착하면
`<player> mq_video_mod` 를 1 로 set. `/start` 는 서버 부재 시 단일 차단,
특정 플레이어 부재 시 본인에게 안내 + 게임 시작 차단.
### 100% 바닐라 — 의존 플러그인 없음 (모드 외)
음원 재생과 정답 이미지 표시는 모두 바닐라 명령으로 처리한다. 음원과
페인팅 텍스처는 [minecraft_launcher](https://git.tkrmagid.kr/tkrmagid/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 참조를 일관되게 지원하지 않으므로 직접
편집해야 한다.
### 설치
1. 서버 월드 폴더 `datapacks/``music_quiz/` 디렉터리째 복사.
2. 서버 mods 폴더에 `mc_chat_answer_mod` v1.3.7+ 와 `mc_video_player_mod`
jar 설치. `mc_video_player_mod` 는 클라이언트 측에도 설치 필요.
3. minecraft_launcher 에서 생성한 `musicquiz` 리소스팩을 클라이언트에 적용
(런처가 자동 처리).
4. 서버 `/reload` — 리로드 성공 메시지가 채팅에 표시되면 정상.
5. `mq:init/buttons` 에 정의된 좌표 부근에 6개 버튼이 자동 배치된다.
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 미세조정 (`width`
0.13 가운데 타일로 micro-gap 보정, `height` 0.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_mod`
objective + `#server` 0 materialize 추가.
### 2026-05-18 ~ 19 — v1.0.19 ~ v1.0.24: 버튼 인프라 안정화
- v1.0.19/20/21: `btn_prep` defaults+merge 패턴, `positioned $(x).0`
로 +0.5 보정 회피, interaction 3 타일 분할, `text_display` 도입.
- v1.0.23: 채팅정답 모드 false negative 의 진짜 fix — 데이터팩 게이트는
유지하고 모드 (`mc_chat_answer_mod` v1.3.7) 의 presence pulse 를
4 지점으로 확장.
- v1.0.24: `text_display` Y 보정 (`~-1` → `~-0.25`) + 라벨 bold + v1.0.21
의 interaction 깊이 부호 반전 수정.
### 2026-05-13 — 26.1.2 호환 + 1차 정리 (`b1babad`)
이전 푸시본(`6841b7a 이전퀴즈 데이터팩`)을 26.1.2 기준으로 정비.
- `pack_format` 69 → 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](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`