music_quiz: YP/TS 플러그인 의존 제거, 바닐라 playsound + painting_variant 로 마이그레이션

minecraft_launcher 가 만드는 musicquiz 리소스팩 (track_NN / cover_NN)
과 한 쌍으로 동작한다.

- 음원 재생: yp playall (명령 블록 + auto 토글) → /playsound musicquiz:track_NN
- 정답 이미지: ts placeloc → /summon painting (musicquiz:cover_NN) +
  /kill @e[type=painting,tag=mq_cover]
- stopsound 하드코딩(weather) 4곳을 mq:quiz/stop_sound 매크로 호출로 통일
- check/server, repeat/check_server, status 스코어보드(yp/ts/skript) 등
  플러그인 hello 패킷 대기 로직 일괄 삭제
- 스토리지 재구성: command_block 컴파운드 폐기, audio/image/marker 분리
  (init/config.mcfunction 한 곳에서 수정)
- 곡 단위 volume override 지원 — songs[i].volume 으로 곡별 음량 지정 가능
  (미지정 시 audio.volume fallback)
- 트랙 번호 zero-pad 는 mq:tmp.pad 분기 + 매크로 문자열 조립으로 처리
- max_index 는 songs 배열 길이에서 자동 계산
- 호출 경로 단축: select → setanswer → macro/setanswer → macro/summon →
  play_sound
This commit is contained in:
Claude (owner)
2026-05-13 16:25:05 +09:00
parent b2361187b9
commit cea3d29c7d
29 changed files with 187 additions and 181 deletions

181
README.md
View File

@@ -22,16 +22,19 @@
- 텍스트 컴포넌트는 JSON 표기로 작성돼 있으며, 1.21.5 이후의 SNBT 파서와도 - 텍스트 컴포넌트는 JSON 표기로 작성돼 있으며, 1.21.5 이후의 SNBT 파서와도
호환된다 (JSON은 SNBT의 부분집합). 호환된다 (JSON은 SNBT의 부분집합).
### 의존 Bukkit 플러그인 ### 100% 바닐라 — 의존 플러그인 없음
데이터팩 자체만으로는 동작하지 않고, 다음 Bukkit 플러그인이 서버에 설치돼 음원 재생과 정답 이미지 표시는 모두 바닐라 명령으로 처리한다. 음원과
있어야 한다: 페인팅 텍스처는 [minecraft_launcher](https://git.tkrmagid.kr/tkrmagid/minecraft_launcher)
가 만들어주는 리소스팩(`musicquiz` 네임스페이스)에서 가져온다.
- **YP** (`yp playall song<n>`) — 음원 재생용. 명령 블록을 통해 호출된다. - 음원: `/playsound musicquiz:track_NN <source> @s ~ ~ ~ <volume> <pitch>`
- **TS** (`ts placeloc <image>.jpg ...`)정답 이미지 표시용. (예: `musicquiz:track_01`). 채널은 기본 `weather``stopsound` 와 함께 묶여 있다.
- 정답 이미지: `painting_variant musicquiz:cover_NN``/summon painting` 으로
벽에 띄우고, 다음 곡 직전 `kill @e[type=painting,tag=mq_cover]` 로 제거.
서버 측 상태는 `status` 스코어보드의 `yp`, `ts`, `skript` 값으로 추적하며, 리소스팩 트랙 번호와 `mq:init/songs` 리스트의 순서가 1:1로 일치해야 한다.
플러그인 미설치 시 `mq:check/server`가 안내 타이틀을 띄운다. 1번째 곡 → `track_01` / `cover_01`, … (2자리 zero-pad).
### 게임 흐름과 상태 (`init` 스코어보드) ### 게임 흐름과 상태 (`init` 스코어보드)
@@ -42,7 +45,6 @@
| `0` | 정지/대기 (기본 상태) | | `0` | 정지/대기 (기본 상태) |
| `1` | 게임 시작 — page1 대화창에서 `ready` 트리거 대기 | | `1` | 게임 시작 — page1 대화창에서 `ready` 트리거 대기 |
| `2` | 카운트다운 (3·2·1) | | `2` | 카운트다운 (3·2·1) |
| `4` | 곡 셋업 (한 틱 사이) |
| `5` | 곡 재생 + 정답 입력 단계 | | `5` | 곡 재생 + 정답 입력 단계 |
| `6` | 정답 공개·점수 부여 | | `6` | 정답 공개·점수 부여 |
| `10` | 엔딩 시퀀스 | | `10` | 엔딩 시퀀스 |
@@ -95,21 +97,28 @@ music_quiz/
│ ├── tick.mcfunction # 매 틱 서브함수 디스패치 (init 게이팅) │ ├── tick.mcfunction # 매 틱 서브함수 디스패치 (init 게이팅)
│ ├── tellraw.mcfunction # 매크로 prefix 메시지 헬퍼 │ ├── tellraw.mcfunction # 매크로 prefix 메시지 헬퍼
│ ├── init/ # 사용자 설정·정적 데이터 (수정 포인트) │ ├── init/ # 사용자 설정·정적 데이터 (수정 포인트)
│ │ ├── config.mcfunction # 주제·곡 개수·스폰·명령 블록 좌표 │ │ ├── config.mcfunction # 주제·스폰·오디오·페인팅·marker 설정
│ │ ├── songs.mcfunction # 곡 목록 │ │ ├── songs.mcfunction # 곡 목록 + max_index 자동계산
│ │ ├── buttons.mcfunction # 버튼 좌표·실행 명령 │ │ ├── buttons.mcfunction # 버튼 좌표·실행 명령
│ │ └── triggers.mcfunction # 다수결 트리거 정의 │ │ └── triggers.mcfunction # 다수결 트리거 정의
│ ├── check/server.mcfunction # YP / TS 설치 확인
│ ├── commands/ # start·stop·skip·hint·replay·test │ ├── commands/ # start·stop·skip·hint·replay·test
│ ├── quiz/ # 게임 진행 로직 │ ├── quiz/ # 게임 진행 로직
│ │ ├── start·select·play·correct·end·setanswer.mcfunction │ │ ├── start·select·setanswer·correct·end.mcfunction
│ │ ── macro/ # 매크로 진입점 (summon·setanswer·command_block) │ │ ── 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에서 호출되는 매 틱 처리 │ ├── repeat/ # tick에서 호출되는 매 틱 처리
│ │ ├── players·check_answer·timer·check_server.mcfunction │ │ ├── players·check_answer·timer.mcfunction
│ │ ├── buttons/{handler,btn}.mcfunction │ │ ├── buttons/{handler,btn}.mcfunction
│ │ └── triggers/{handler,trigger}.mcfunction │ │ └── triggers/{handler,trigger}.mcfunction
── players/login.mcfunction ── players/login.mcfunction
│ └── images/{image,image_set,image_delete}.mcfunction
├── dialog/page{1,2,3}.json ├── dialog/page{1,2,3}.json
└── advancement/player/login.json └── advancement/player/login.json
``` ```
@@ -119,7 +128,6 @@ music_quiz/
스코어보드: 스코어보드:
- `main` — 게임 핵심 상태 (`init`, `index`, `max_index`, `timer`, `score`, `song_idx`) - `main` — 게임 핵심 상태 (`init`, `index`, `max_index`, `timer`, `score`, `song_idx`)
- `status` — 외부 의존(YP·TS·Skript) 및 글로벌 타이머
- `buttons` — 물리 버튼 상태 머신 - `buttons` — 물리 버튼 상태 머신
- `answer` — 플레이어별 정답 입력값 (`1`=정답, `2`=오답) - `answer` — 플레이어별 정답 입력값 (`1`=정답, `2`=오답)
- `func.temp` — 산술용 임시 상수 (`two=2` 등) - `func.temp` — 산술용 임시 상수 (`two=2` 등)
@@ -131,12 +139,13 @@ music_quiz/
- `mq:main` — 게임 전역 데이터 - `mq:main` — 게임 전역 데이터
- `title`, `max_index`, `spawn` — 설정 - `title`, `max_index`, `spawn` — 설정
- `answer` = `{title, author, alias}` — 현재 곡 정답 - `audio` = `{namespace, source, volume, pitch}``/playsound` 파라미터
- `command_block` — 명령 블록 좌표/볼륨, 이미지 표시 영역, 작업용 alias 사본 - `image` = `{namespace, x, y, z, facing}` — 정답 페인팅 좌표
- `marker` = `{x, y, z}` — 정답 입력 marker 엔티티 위치
- `answer` = `{title, author, alias, track, cover}` — 현재 곡 정답
- `songs` — 곡 목록 (`mq:init/songs` 가 채움) - `songs` — 곡 목록 (`mq:init/songs` 가 채움)
- `button_defs` — 버튼 정의 (`mq:init/buttons` 가 채움) - `button_defs` / `trigger_defs` — 버튼·트리거 정의
- `trigger_defs` — 트리거 정의 (`mq:init/triggers` 가 채움) - `mq:tmp` — setanswer·play_sound·페인팅 호출용 임시 페이로드 (idx, pad, num, playsound, painting, marker_call)
- `mq:tmp` — setanswer 룩업용 임시 인덱스
- `func:temp``func:` 헬퍼 함수용 임시 NBT - `func:temp``func:` 헬퍼 함수용 임시 NBT
### 설정 (한 곳에서 수정) ### 설정 (한 곳에서 수정)
@@ -144,11 +153,13 @@ music_quiz/
세계마다 다른 값은 모두 `data/mq/function/init/` 폴더에서 편집한다. 세계마다 다른 값은 모두 `data/mq/function/init/` 폴더에서 편집한다.
`/reload` 후 반영된다. `/reload` 후 반영된다.
- **`init/config.mcfunction`** — 주제, 곡 개수, 스폰 위치, 음원 명령 블록 - **`init/config.mcfunction`** — 주제, 스폰 위치, 오디오 설정(`audio`),
좌표, 정답 이미지 표시 영역. `title``[ … ]` 채팅 접두사로도 사용된다. 정답 페인팅 좌표(`image`), marker 엔티티 좌표. `title``[ … ]`
- **`init/songs.mcfunction`** — 곡 목록 (한 줄에 한 곡씩 append). 채팅 접두사로도 사용된다.
`alias` 배열의 문자열은 정답 판정 시 동의어로 인정된다. 곡 수를 바꾸면 - **`init/songs.mcfunction`** — 곡 목록 (한 줄에 한 곡씩 append). `alias`
`init/config.mcfunction``max_index` 도 함께 맞춰야 한다. 배열의 문자열은 정답 판정 시 동의어로 인정된다. **곡의 순서가 리소스팩
트랙 번호와 1:1 매칭** 되므로 순서 변경 시 리소스팩도 함께 재생성해야
한다. `max_index` 는 리스트 길이로 자동 계산된다.
- **`init/buttons.mcfunction`** — 6개 물리 버튼의 좌표·표면 방향·실행 명령. - **`init/buttons.mcfunction`** — 6개 물리 버튼의 좌표·표면 방향·실행 명령.
- **`init/triggers.mcfunction`** — 다수결 트리거(`stop`/`skip`/`hint`/`replay`) - **`init/triggers.mcfunction`** — 다수결 트리거(`stop`/`skip`/`hint`/`replay`)
표시 이름·실행 명령. 표시 이름·실행 명령.
@@ -163,7 +174,8 @@ JSON 텍스트 컴포넌트가 storage 참조를 일관되게 지원하지 않
### 설치 ### 설치
1. 서버 월드 폴더 `datapacks/``music_quiz/` 디렉터리째 복사. 1. 서버 월드 폴더 `datapacks/``music_quiz/` 디렉터리째 복사.
2. YP, TS 플러그인 설치 확인. 2. minecraft_launcher 에서 생성한 `musicquiz` 리소스팩을 클라이언트에 적용
(런처가 자동 처리).
3. 서버 `/reload` — 리로드 성공 메시지가 채팅에 표시되면 정상. 3. 서버 `/reload` — 리로드 성공 메시지가 채팅에 표시되면 정상.
4. 좌표 `144, 62, -225` 부근에 6개 버튼이 자동 배치된다. 4. 좌표 `144, 62, -225` 부근에 6개 버튼이 자동 배치된다.
5. `start` 버튼을 눌러 게임 시작. 5. `start` 버튼을 눌러 게임 시작.
@@ -171,12 +183,12 @@ JSON 텍스트 컴포넌트가 storage 참조를 일관되게 지원하지 않
### 좌표 의존성 (주의) ### 좌표 의존성 (주의)
다음 좌표가 데이터팩 안에 박혀 있어, 다른 월드에서 그대로 사용하려면 다음 좌표가 데이터팩 안에 박혀 있어, 다른 월드에서 그대로 사용하려면
값을 바꿔야 한다: `init/config.mcfunction`값을 바꿔야 한다:
- 명령 블록: `144 59 -219``mq:load``command_block` 초기값 - 정답 입력 marker: `144 59 -219``marker.{x,y,z}`
- 플레이어 스폰: `144 61 -219` (`yaw 180`) — `mq:load``spawn` 초기값 - 정답 페인팅: `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` - 버튼 좌표: `140..148, 62, -225` / `144, 62, -213``mq:init/buttons`
- 이미지 표시 영역: `131 77 -262` ~ `157 91 -262``mq:load``command_block.x1..z2`
--- ---
@@ -191,70 +203,81 @@ JSON 텍스트 컴포넌트가 storage 참조를 일관되게 지원하지 않
`mq:quiz/start`, `mq:quiz/end`, `mq:repeat/buttons/btn` 등에 남아 있던 `mq:quiz/start`, `mq:quiz/end`, `mq:repeat/buttons/btn` 등에 남아 있던
`# say ...` / `# stopsound` 사문화 디버그 주석 제거 `# say ...` / `# stopsound` 사문화 디버그 주석 제거
### 2026-05-13 — 무대 의존 제거 + 최적화 (이번 커밋) ### 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 트리거)
- `repeat/map/` 디렉터리 통째 — 무대 트리/조명 애니메이션 (`tree`, `lamp1`) ### 2026-05-13 — 설정 통합 (`b236118`)
- `images/image_custom.mcfunction` — 파이브가이즈 간판 (호출자 없음)
- `data/mq/수정.txt` — 작가용 TODO 메모
- `load.mcfunction``map` 스코어보드 초기화, `tree map -1`, `lamp1 map -1`,
`fill 94 78 -279 194 78 -279 minecraft:red_wool`
- `tick.mcfunction``function mq:repeat/map/tree`, `function mq:repeat/map/lamp1`
#### 매 틱 부하 감소 세계별 수정 포인트를 한 파일로 모았다.
- `tick.mcfunction` 디스패치를 `init` 상태로 게이팅: - `init/config.mcfunction` 신설 — 주제·곡 개수·스폰·명령 블록 좌표를 한곳에
- `repeat/timer` `init >= 2` 일 때만 - `mq:tellraw` `mq:main.title` 을 읽도록 변경 ([ 주제 ] 접두사 동기화)
- `repeat/check_answer``init in {5, 6}` 일 때만
- `check_server` / `players` / `buttons/handler` / `triggers/handler`
항상 호출 (게임 비활성 상태에서도 시작 버튼·로그인 처리 필요)
- idle 틱(`init=0`)에서 함수 호출 8개 → 4개. 정답 스캔과 카운트다운 reset
로직이 빠진다.
#### 곡 관리 단순화 ### 2026-05-13 — 바닐라 마이그레이션 (이번 커밋)
기존: `quiz/setanswer.mcfunction` 안에 50곡의 `function mq:quiz/macro/setanswer { index:N, title:..., author:..., alias:... }` YP / TS Bukkit 플러그인 의존을 제거하고, 음원과 정답 이미지를 바닐라
나열돼 있어, 매번 50개 매크로 호출 × 5라인 (`if score index matches N` 명령으로 재구현했다. [minecraft_launcher](https://git.tkrmagid.kr/tkrmagid/minecraft_launcher)
드 포함) = 약 250 명령이 평가됐다. 생성하는 `musicquiz` 리소스팩과 한 쌍으로 동작한다.
변경: #### 삭제
- 곡 데이터를 `mq:init/songs` 에서 `mq:main.songs` 리스트로 한 번 적재 - `mq:check/server` + `mq:repeat/check_server` — 플러그인 설치 확인 로직
- `quiz/setanswer.mcfunction` `index - 1` 을 계산해 `mq:tmp.idx` 에 저장 - `mq:quiz/macro/command_block` `data modify block … Command` + `auto`
- `quiz/macro/setanswer.mcfunction` 은 매크로 한 줄로 룩업: 토글 패턴 (YP `playall` 호출용)
`data modify storage mq:main answer set from storage mq:main songs[$(idx)]` - `mq:quiz/play` — 명령 블록 강제 재발화 함수
- 호출당 3 라인의 storage 복사로 끝남 (50× → O(1)) - `mq:images/image{,_set,_delete}` — TS `placeloc` / `removeall` 호출
- `status` 스코어보드 (`yp`, `ts`, `skript`, `timer`) — 플러그인 hello 패킷
대기에만 쓰이던 객체
#### 버튼/트리거 정의 분리 #### 신설
- 버튼 6개의 좌표·실행 명령을 `mq:init/buttons` 에서 `mq:main.button_defs` - **음원** — `mq:quiz/play_sound` `mq:quiz/macro/play_sound`:
리스트로 적재. `repeat/buttons/handler` 는 인덱스로 매크로 호출만 한다. `$execute as @a at @s run playsound $(namespace):$(track) $(source) @s ~ ~ ~ $(volume) $(pitch)`
- 트리거 4개(stop/skip/hint/replay)도 동일하게 `mq:init/triggers` - **음원 정지** — `mq:quiz/stop_sound``mq:quiz/macro/stop_sound`:
`mq:main.trigger_defs` 로 분리. `$stopsound @a $(source)` (모든 stopsound 호출 합쳐서 매크로화)
- 버튼/트리거를 추가·제거할 때 `repeat/*/handler` 가 아닌 `init/*` - **정답 페인팅** — `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]`
#### 다수결 산술 dedup #### 스토리지 재구성
`repeat/triggers/trigger.mcfunction` 에서 투표 갱신 전후로 `real_max_player`, - `command_block` 컴파운드(좌표·볼륨·이미지 영역·alias 사본을 한데 묶었던
`rest_player`, `max_player` 를 두 번 계산했다. 이 값들은 (참가자 수에만 것) 폐기
의존하므로) 한 틱 안에서 바뀌지 않는다. 갱신되는 것은 `$(n)_player` - `audio` = `{namespace, source, volume, pitch}` 신설 — `/playsound` 인자
(투표 수)뿐이라 — 후처리 블록은 `$(n)_player` 재계산 한 줄로 축약. - `image` = `{namespace, x, y, z, facing}` 신설 — `/summon painting` 좌표
트리거당 5 라인 절감 × 4 트리거. - `marker` = `{x, y, z}` 신설 — 정답 입력 marker 위치
- `answer.track` / `answer.cover` 필드 추가 — 라운드별 리소스팩 ID
(`track_NN` / `cover_NN`)
- `max_index``mq:init/songs` 끝에서 `songs` 배열 길이로 자동 계산
(수동 동기화 필요 없음)
#### 다듬지 않은 부분 (의도된 동작) #### 트랙 번호 padding
- `mq:commands/test``mq:repeat/timer` 의 3중 `playsound` — 음량 강조용 mcfunction 은 문자열 zero-pad 가 없으므로, `quiz/select` 에서
스택 호출. `index ∈ 1..9` 일 때만 `mq:tmp.pad="0"` 로 분기시키고, 매크로 안에서
- `mq:quiz/play``auto 1b``0b` 토글 두 줄 — 명령 블록 강제 재발화 `"track_$(pad)$(num)"` 로 조립한다.
패턴.
- `mq:repeat/buttons/btn` 내부 상태머신 — 상태 -2/-1/0/1/2 전이 의미가 #### 기타
엮여 있어 라인 단축 시 디바운스가 깨질 위험이 있어 유지.
- `func:` 헬퍼는 `mq:commands/hint` 가 사용 중이므로 유지. - `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`
--- ---

View File

@@ -1,3 +0,0 @@
title @a times 0t 20t 0t
title @a subtitle {"text":"이 맵은 버킷 서버에서 열어야 합니다."}
title @a title {"text":"오류 발생!","color":"red"}

View File

@@ -5,5 +5,5 @@ execute if score init main matches 1..4 run return run function mq:tellraw {"tex
execute if score init main matches 6.. run return run function mq:tellraw {"text":"아직 다음노래가 재생되지 않았습니다.","color":"red",msg:'""'} execute if score init main matches 6.. run return run function mq:tellraw {"text":"아직 다음노래가 재생되지 않았습니다.","color":"red",msg:'""'}
execute if score init main matches 10 run return run function mq:tellraw {"text":"퀴즈가 종료되었습니다.","color":"red",msg:'""'} execute if score init main matches 10 run return run function mq:tellraw {"text":"퀴즈가 종료되었습니다.","color":"red",msg:'""'}
execute if score init main matches 5 run stopsound @a weather execute if score init main matches 5 run function mq:quiz/stop_sound
execute if score init main matches 5 run function mq:quiz/macro/command_block with storage mq:main command_block execute if score init main matches 5 run function mq:quiz/play_sound

View File

@@ -2,7 +2,7 @@ execute if score init main matches 10 run return run function mq:tellraw {"text"
setblock ~ ~ ~ minecraft:air setblock ~ ~ ~ minecraft:air
stopsound @a weather function mq:quiz/stop_sound
$scoreboard players set max_index main $(max_index) $scoreboard players set max_index main $(max_index)
scoreboard players set init main 1 scoreboard players set init main 1

View File

@@ -1,8 +1,3 @@
scoreboard players set timer status 0
scoreboard players set skript status 0
scoreboard players set yp status 0
scoreboard players set ts status 0
scoreboard players set index main 0 scoreboard players set index main 0
$scoreboard players set max_index main $(max_index) $scoreboard players set max_index main $(max_index)
scoreboard players set score main 0 scoreboard players set score main 0
@@ -43,8 +38,6 @@ scoreboard objectives remove score
scoreboard objectives add score dummy {"text":"점수","bold":true} scoreboard objectives add score dummy {"text":"점수","bold":true}
scoreboard objectives setdisplay sidebar score scoreboard objectives setdisplay sidebar score
data modify storage mq:main command_block.index set value 1
dialog clear @a dialog clear @a
bossbar set mq:process name [{"text":"진행도: ","color": "yellow","bold": true},{"score":{"name":"index","objective": "main"},"color": "yellow","bold": true},{"text":"/","color": "yellow","bold": true},{"score":{"name":"max_index","objective": "main"},"color": "yellow","bold": true}] bossbar set mq:process name [{"text":"진행도: ","color": "yellow","bold": true},{"score":{"name":"index","objective": "main"},"color": "yellow","bold": true},{"text":"/","color": "yellow","bold": true},{"score":{"name":"max_index","objective": "main"},"color": "yellow","bold": true}]
@@ -55,9 +48,12 @@ bossbar set mq:process visible false
bossbar set mq:process style notched_10 bossbar set mq:process style notched_10
bossbar set mq:process players @a bossbar set mq:process players @a
data modify storage mq:main command_block.name set value "음악퀴즈" # 대기 상태 marker 1개만 소환 (answer.title="음악퀴즈" 가 sentinel)
function mq:quiz/macro/summon with storage mq:main command_block data modify storage mq:main answer set value {title:"음악퀴즈", alias:[]}
data modify storage mq:tmp marker_call set from storage mq:main marker
data modify storage mq:tmp marker_call.name set value "음악퀴즈"
data modify storage mq:tmp marker_call.alias set value []
function mq:quiz/macro/summon with storage mq:tmp marker_call
stopsound @a weather function mq:quiz/stop_sound
function mq:images/clear
function mq:images/image_delete with storage mq:main command_block

View File

@@ -0,0 +1 @@
kill @e[type=minecraft:painting,tag=mq_cover]

View File

@@ -1,3 +0,0 @@
$data modify storage mq:main command_block.image set value "ts placeloc song$(index).jpg world SOUTH $(x1) $(y1) $(z1) $(x2) $(y2) $(z2) 1 솔리드스킵"
function mq:images/image_set with storage mq:main command_block

View File

@@ -1,4 +0,0 @@
$data modify block $(x) $(y) $(z) Command set value "ts removeall"
$data modify block $(x) $(y) $(z) auto set value 1b
$data modify block $(x) $(y) $(z) auto set value 0b

View File

@@ -1,4 +0,0 @@
$data modify block $(x) $(y) $(z) Command set value "$(image)"
$data modify block $(x) $(y) $(z) auto set value 1b
$data modify block $(x) $(y) $(z) auto set value 0b

View File

@@ -0,0 +1 @@
$summon minecraft:painting $(x) $(y) $(z) {variant:"$(namespace):$(cover)",facing:$(facing)b,Tags:["mq","mq_cover"]}

View File

@@ -0,0 +1,3 @@
data modify storage mq:tmp painting set from storage mq:main image
data modify storage mq:tmp painting.cover set from storage mq:main answer.cover
function mq:images/macro/show with storage mq:tmp painting

View File

@@ -1,26 +1,23 @@
# 음악퀴즈 주제 — tellraw 접두사([ 이름 ])와 사이드바 표시에 사용 # 음악퀴즈 주제 — tellraw 접두사([ 이름 ])와 사이드바 표시에 사용
data modify storage mq:main title set value "음악퀴즈" data modify storage mq:main title set value "음악퀴즈"
# 곡 개수 — init/songs.mcfunction 의 곡 수와 일치시킬 것
data modify storage mq:main max_index set value 50
# 플레이어 접속 시 텔레포트 위치 (x y z, r=yaw, f=pitch) # 플레이어 접속 시 텔레포트 위치 (x y z, r=yaw, f=pitch)
data modify storage mq:main spawn set value {x: 144, y: 61, z: -219, r: 180, f: 0} data modify storage mq:main spawn set value {x: 144, y: 61, z: -219, r: 180, f: 0}
# 음원 재생용 명령 블록 위치 + 정답 이미지 표시 영역 # 음원 재생 — minecraft_launcher 리소스팩의 musicquiz:track_NN 사운드 이벤트
# x,y,z — 명령 블록 좌표 # namespace — 리소스팩 네임스페이스 (기본 "musicquiz")
# r — 명령 블록 정면 방향 (EAST | WEST | SOUTH | NORTH) # source — /playsound 채널. stopsound 와 동일해야 함 (기본 "weather")
# volume yp playall 명령에 넘기는 음량 # volume — 기본 음량. 곡별 override 는 init/songs.mcfunction 의 volume 필드 사용
# x1,y1,z1 — 이미지 표시 영역 한쪽 모서리 # pitch — 1.0 = 원본 속도
# x2,y2,z2 — 이미지 표시 영역 반대 모서리 data modify storage mq:main audio set value {namespace: "musicquiz", source: "weather", volume: 1.0, pitch: 1.0}
data modify storage mq:main command_block set value { \
name: "", \ # 정답 페인팅 — minecraft_launcher 리소스팩의 musicquiz:cover_NN painting_variant
image: "", \ # namespace — painting_variant 네임스페이스 (기본 "musicquiz")
alias: [], \ # x,y,z — 페인팅 entity 좌표 (벽면 앞쪽 블록 위치)
index: 1, \ # facing — 페인팅이 바라보는 방향: south=0 / west=1 / north=2 / east=3
volume: 30, \ data modify storage mq:main image set value {namespace: "musicquiz", x: 144, y: 84, z: -261, facing: 0b}
x: 144, y: 59, z: -219, \
r: "SOUTH", \ # 정답 입력용 marker entity 소환 좌표
x1: 131, y1: 77, z1: -262, \ data modify storage mq:main marker set value {x: 144, y: 59, z: -219}
x2: 157, y2: 91, z2: -262 \
} # 곡 개수 max_index 는 init/songs.mcfunction 의 길이로 자동 계산됨

View File

@@ -1,3 +1,9 @@
# 곡 한 개 = 한 줄.
# 필수 — title, author, alias
# 선택 — volume (이 곡만의 /playsound 음량. 미지정시 init/config.mcfunction
# 의 audio.volume 사용)
# 곡 순서가 리소스팩의 track_NN / cover_NN 인덱스와 1:1 매칭된다.
# 예) {title:"Quiet Song", author:"...", alias:[...], volume:2.0}
data modify storage mq:main songs set value [] data modify storage mq:main songs set value []
data modify storage mq:main songs append value {title:"Lose My Mind", author:"Don Toliver", alias:[" "," "," "]} data modify storage mq:main songs append value {title:"Lose My Mind", author:"Don Toliver", alias:[" "," "," "]}
data modify storage mq:main songs append value {title:"The Chase", author:"Hearts2Hearts", alias:[" "," "," "]} data modify storage mq:main songs append value {title:"The Chase", author:"Hearts2Hearts", alias:[" "," "," "]}
@@ -49,3 +55,6 @@ data modify storage mq:main songs append value {title:"XOXZ", author:"IVE", alia
data modify storage mq:main songs append value {title:"여름이었다", author:"H1-KEY", alias:[]} data modify storage mq:main songs append value {title:"여름이었다", author:"H1-KEY", alias:[]}
data modify storage mq:main songs append value {title:"LOV3", author:"식케이", alias:["3","3"]} data modify storage mq:main songs append value {title:"LOV3", author:"식케이", alias:["3","3"]}
data modify storage mq:main songs append value {title:"Drive", author:"Ed Sheeran", alias:["",""]} data modify storage mq:main songs append value {title:"Drive", author:"Ed Sheeran", alias:["",""]}
# 곡 개수는 songs 배열 길이에서 자동 계산됨
execute store result storage mq:main max_index int 1 run data get storage mq:main songs

View File

@@ -1,4 +1,4 @@
data modify storage mq:main answer set value {author: "", title: "", alias: []} data modify storage mq:main answer set value {title:"", author:"", alias:[]}
data merge storage func:temp {} data merge storage func:temp {}
data merge storage mq:tmp {} data merge storage mq:tmp {}
@@ -10,24 +10,17 @@ function mq:init/triggers
function mq:tellraw {"text":"서버 리로드 성공!","color":"white","msg":'""'} function mq:tellraw {"text":"서버 리로드 성공!","color":"white","msg":'""'}
scoreboard objectives remove func.temp scoreboard objectives remove func.temp
scoreboard objectives remove status
scoreboard objectives remove main scoreboard objectives remove main
scoreboard objectives remove buttons scoreboard objectives remove buttons
scoreboard objectives remove answer scoreboard objectives remove answer
scoreboard objectives remove leave_game scoreboard objectives remove leave_game
scoreboard objectives add func.temp dummy scoreboard objectives add func.temp dummy
scoreboard objectives add status dummy
scoreboard objectives add main dummy scoreboard objectives add main dummy
scoreboard objectives add buttons dummy scoreboard objectives add buttons dummy
scoreboard objectives add answer dummy scoreboard objectives add answer dummy
scoreboard objectives add leave_game custom:leave_game scoreboard objectives add leave_game custom:leave_game
scoreboard players set timer status 0
scoreboard players set skript status 0
scoreboard players set yp status 0
scoreboard players set ts status 0
scoreboard players set two func.temp 2 scoreboard players set two func.temp 2
bossbar add mq:process [{"text":"진행도: ","color": "yellow","bold": true},{"text":"0","color": "yellow","bold": true},{"text":"/","color": "yellow","bold": true},{"text":"0","color": "yellow","bold": true}] bossbar add mq:process [{"text":"진행도: ","color": "yellow","bold": true},{"text":"0","color": "yellow","bold": true},{"text":"/","color": "yellow","bold": true},{"text":"0","color": "yellow","bold": true}]

View File

@@ -29,4 +29,4 @@ scoreboard players set replay buttons -3
scoreboard players set timer main 1 scoreboard players set timer main 1
function mq:images/image with storage mq:main command_block function mq:images/show

View File

@@ -1,3 +0,0 @@
$data modify block $(x) $(y) $(z) Command set value "yp playall song$(index) $(volume)"
function mq:quiz/play with storage mq:main command_block

View File

@@ -0,0 +1 @@
$execute as @a at @s run playsound $(namespace):$(track) $(source) @s ~ ~ ~ $(volume) $(pitch)

View File

@@ -1,3 +1,3 @@
$data modify storage mq:main answer set from storage mq:main songs[$(idx)] $data modify storage mq:main answer set from storage mq:main songs[$(idx)]
$data modify storage mq:main command_block.name set from storage mq:main songs[$(idx)].title $data modify storage mq:main answer.track set value "track_$(pad)$(num)"
$data modify storage mq:main command_block.alias set from storage mq:main songs[$(idx)].alias $data modify storage mq:main answer.cover set value "cover_$(pad)$(num)"

View File

@@ -0,0 +1 @@
$stopsound @a $(source)

View File

@@ -1,8 +1,9 @@
$execute unless data storage mq:main {command_block:{name:"음악퀴즈"}} run summon minecraft:marker $(x) $(y) $(z) {Tags:["mq","default"],CustomName:"정답입력시작"} $execute unless data storage mq:main {answer:{title:"음악퀴즈"}} run summon minecraft:marker $(x) $(y) $(z) {Tags:["mq","default"],CustomName:"정답입력시작"}
$summon minecraft:marker $(x) $(y) $(z) {Tags:["mq","default"],CustomName:"$(name)"} $summon minecraft:marker $(x) $(y) $(z) {Tags:["mq","default"],CustomName:"$(name)"}
execute store result score length func.temp run data get storage mq:main command_block.alias execute store result score length func.temp run data get storage mq:tmp marker_call.alias
execute if score length func.temp matches 1.. run data modify storage mq:main command_block.name set from storage mq:main command_block.alias[0] execute if score length func.temp matches 1.. run data modify storage mq:tmp marker_call.name set from storage mq:tmp marker_call.alias[0]
execute if score length func.temp matches 1.. run data remove storage mq:main command_block.alias[0] execute if score length func.temp matches 1.. run data remove storage mq:tmp marker_call.alias[0]
execute if score length func.temp matches 1.. run function mq:quiz/macro/summon2 with storage mq:main command_block execute if score length func.temp matches 1.. run function mq:quiz/macro/summon2 with storage mq:tmp marker_call
$execute unless data storage mq:main {command_block:{name:"음악퀴즈"}} run summon minecraft:marker $(x) $(y) $(z) {Tags:["mq","default"],CustomName:"정답입력종료"}
$execute unless data storage mq:main {answer:{title:"음악퀴즈"}} run summon minecraft:marker $(x) $(y) $(z) {Tags:["mq","default"],CustomName:"정답입력종료"}

View File

@@ -1,6 +1,6 @@
$summon minecraft:marker $(x) $(y) $(z) {Tags:["mq","default"],CustomName:"$(name)"} $summon minecraft:marker $(x) $(y) $(z) {Tags:["mq","default"],CustomName:"$(name)"}
execute store result score length func.temp run data get storage mq:main command_block.alias execute store result score length func.temp run data get storage mq:tmp marker_call.alias
execute if score length func.temp matches 1.. run data modify storage mq:main command_block.name set from storage mq:main command_block.alias[0] execute if score length func.temp matches 1.. run data modify storage mq:tmp marker_call.name set from storage mq:tmp marker_call.alias[0]
execute if score length func.temp matches 1.. run data remove storage mq:main command_block.alias[0] execute if score length func.temp matches 1.. run data remove storage mq:tmp marker_call.alias[0]
execute if score length func.temp matches 1.. run function mq:quiz/macro/summon2 with storage mq:main command_block execute if score length func.temp matches 1.. run function mq:quiz/macro/summon2 with storage mq:tmp marker_call

View File

@@ -1,6 +0,0 @@
scoreboard players set init main 4
$data modify block $(x) $(y) $(z) auto set value 1b
$data modify block $(x) $(y) $(z) auto set value 0b
function mq:quiz/setanswer

View File

@@ -0,0 +1,5 @@
data modify storage mq:tmp playsound set from storage mq:main audio
data modify storage mq:tmp playsound.track set from storage mq:main answer.track
# 곡 단위 volume override — songs[i].volume 가 없으면 audio.volume 그대로 유지 (no-op)
data modify storage mq:tmp playsound.volume set from storage mq:main answer.volume
function mq:quiz/macro/play_sound with storage mq:tmp playsound

View File

@@ -1,14 +1,20 @@
scoreboard players add init main 3
scoreboard players set timer main 0 scoreboard players set timer main 0
execute if score index main >= max_index main run return run function mq:quiz/end with storage mq:main execute if score index main >= max_index main run return run function mq:quiz/end with storage mq:main
scoreboard players add index main 1 scoreboard players add index main 1
execute store result storage mq:main command_block.index int 1 run scoreboard players get index main
# 보스바
bossbar set mq:process name [{"text":"진행도: ","color": "yellow","bold": true},{"score":{"name":"index","objective": "main"},"color": "yellow","bold": true},{"text":"/","color": "yellow","bold": true},{"score":{"name":"max_index","objective": "main"},"color": "yellow","bold": true}] bossbar set mq:process name [{"text":"진행도: ","color": "yellow","bold": true},{"score":{"name":"index","objective": "main"},"color": "yellow","bold": true},{"text":"/","color": "yellow","bold": true},{"score":{"name":"max_index","objective": "main"},"color": "yellow","bold": true}]
bossbar set mq:process players @a bossbar set mq:process players @a
execute store result bossbar mq:process value run scoreboard players get index main execute store result bossbar mq:process value run scoreboard players get index main
function mq:quiz/macro/command_block with storage mq:main command_block # tmp.{idx (0-based, songs[] 인덱스), num (1-based, track_NN), pad ("0"|"")} 구성
execute store result storage mq:tmp num int 1 run scoreboard players get index main
scoreboard players operation song_idx func.temp = index main
scoreboard players remove song_idx func.temp 1
execute store result storage mq:tmp idx int 1 run scoreboard players get song_idx func.temp
execute if score index main matches 1..9 run data modify storage mq:tmp pad set value "0"
execute unless score index main matches 1..9 run data modify storage mq:tmp pad set value ""
function mq:quiz/setanswer

View File

@@ -1,13 +1,17 @@
scoreboard players operation song_idx func.temp = index main # songs[$(idx)] → answer 로 복사하고, 트랙/커버 id 부여
scoreboard players remove song_idx func.temp 1
execute store result storage mq:tmp idx int 1 run scoreboard players get song_idx func.temp
function mq:quiz/macro/setanswer with storage mq:tmp function mq:quiz/macro/setanswer with storage mq:tmp
# 정답 marker entity 소환 (좌표 + name/alias 합쳐서 macro 호출)
data modify storage mq:tmp marker_call set from storage mq:main marker
data modify storage mq:tmp marker_call.name set from storage mq:main answer.title
data modify storage mq:tmp marker_call.alias set from storage mq:main answer.alias
function mq:quiz/macro/summon with storage mq:tmp marker_call
scoreboard players set stop buttons -1 scoreboard players set stop buttons -1
scoreboard players set skip buttons -1 scoreboard players set skip buttons -1
scoreboard players set hint buttons -1 scoreboard players set hint buttons -1
scoreboard players set replay buttons -1 scoreboard players set replay buttons -1
scoreboard players set init main 5 scoreboard players set init main 5
function mq:quiz/macro/summon with storage mq:main command_block
function mq:quiz/play_sound

View File

@@ -0,0 +1 @@
function mq:quiz/macro/stop_sound with storage mq:main audio

View File

@@ -1,12 +0,0 @@
execute if score timer status matches 20.. \
if score skript status matches 0 \
if score yp status matches 0 \
if score ts status matches 0 \
run return run function mq:check/server
execute if score timer status matches 0.. run scoreboard players add timer status 1
execute if score timer status matches 1..10 run scoreboard players set skript status 0
execute if score timer status matches 1..10 run scoreboard players set yp status 0
execute if score timer status matches 1..10 run scoreboard players set ts status 0
execute if score timer status matches 21.. run scoreboard players set timer status -1

View File

@@ -26,7 +26,7 @@ execute if score init main matches 2 if score timer main matches 100.. run funct
# next song timer # next song timer
execute if score init main matches 6 if score timer main matches 300 run title @a title {"text":""} execute if score init main matches 6 if score timer main matches 300 run title @a title {"text":""}
execute if score init main matches 6 if score timer main matches 290 run function mq:images/image_delete with storage mq:main command_block execute if score init main matches 6 if score timer main matches 290 run function mq:images/clear
execute if score init main matches 6 if score timer main matches 300.. run function mq:quiz/select with storage mq:main execute if score init main matches 6 if score timer main matches 300.. run function mq:quiz/select with storage mq:main
# endding timer # endding timer

View File

@@ -1,4 +1,3 @@
function mq:repeat/check_server
function mq:repeat/players function mq:repeat/players
function mq:repeat/buttons/handler function mq:repeat/buttons/handler
function mq:repeat/triggers/handler function mq:repeat/triggers/handler