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

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 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/macro/command_block with storage mq:main command_block
execute if score init main matches 5 run function mq:quiz/stop_sound
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
stopsound @a weather
function mq:quiz/stop_sound
$scoreboard players set max_index main $(max_index)
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 max_index main $(max_index)
scoreboard players set score main 0
@@ -43,8 +38,6 @@ scoreboard objectives remove score
scoreboard objectives add score dummy {"text":"점수","bold":true}
scoreboard objectives setdisplay sidebar score
data modify storage mq:main command_block.index set value 1
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}]
@@ -55,9 +48,12 @@ bossbar set mq:process visible false
bossbar set mq:process style notched_10
bossbar set mq:process players @a
data modify storage mq:main command_block.name set value "음악퀴즈"
function mq:quiz/macro/summon with storage mq:main command_block
# 대기 상태 marker 1개만 소환 (answer.title="음악퀴즈" 가 sentinel)
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:images/image_delete with storage mq:main command_block
function mq:quiz/stop_sound
function mq:images/clear

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 접두사([ 이름 ])와 사이드바 표시에 사용
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)
data modify storage mq:main spawn set value {x: 144, y: 61, z: -219, r: 180, f: 0}
# 음원 재생용 명령 블록 위치 + 정답 이미지 표시 영역
# x,y,z — 명령 블록 좌표
# r — 명령 블록 정면 방향 (EAST | WEST | SOUTH | NORTH)
# volume yp playall 명령에 넘기는 음량
# x1,y1,z1 — 이미지 표시 영역 한쪽 모서리
# x2,y2,z2 — 이미지 표시 영역 반대 모서리
data modify storage mq:main command_block set value { \
name: "", \
image: "", \
alias: [], \
index: 1, \
volume: 30, \
x: 144, y: 59, z: -219, \
r: "SOUTH", \
x1: 131, y1: 77, z1: -262, \
x2: 157, y2: 91, z2: -262 \
}
# 음원 재생 — minecraft_launcher 리소스팩의 musicquiz:track_NN 사운드 이벤트
# namespace — 리소스팩 네임스페이스 (기본 "musicquiz")
# source — /playsound 채널. stopsound 와 동일해야 함 (기본 "weather")
# volume — 기본 음량. 곡별 override 는 init/songs.mcfunction 의 volume 필드 사용
# pitch — 1.0 = 원본 속도
data modify storage mq:main audio set value {namespace: "musicquiz", source: "weather", volume: 1.0, pitch: 1.0}
# 정답 페인팅 — minecraft_launcher 리소스팩의 musicquiz:cover_NN painting_variant
# namespace — painting_variant 네임스페이스 (기본 "musicquiz")
# x,y,z — 페인팅 entity 좌표 (벽면 앞쪽 블록 위치)
# facing — 페인팅이 바라보는 방향: south=0 / west=1 / north=2 / east=3
data modify storage mq:main image set value {namespace: "musicquiz", x: 144, y: 84, z: -261, facing: 0b}
# 정답 입력용 marker entity 소환 좌표
data modify storage mq:main marker set value {x: 144, y: 59, z: -219}
# 곡 개수 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 append value {title:"Lose My Mind", author:"Don Toliver", 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:"LOV3", author:"식케이", alias:["3","3"]}
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 mq:tmp {}
@@ -10,24 +10,17 @@ function mq:init/triggers
function mq:tellraw {"text":"서버 리로드 성공!","color":"white","msg":'""'}
scoreboard objectives remove func.temp
scoreboard objectives remove status
scoreboard objectives remove main
scoreboard objectives remove buttons
scoreboard objectives remove answer
scoreboard objectives remove leave_game
scoreboard objectives add func.temp dummy
scoreboard objectives add status dummy
scoreboard objectives add main dummy
scoreboard objectives add buttons dummy
scoreboard objectives add answer dummy
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
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
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 command_block.name set from storage mq:main songs[$(idx)].title
$data modify storage mq:main command_block.alias set from storage mq:main songs[$(idx)].alias
$data modify storage mq:main answer.track set value "track_$(pad)$(num)"
$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)"}
execute store result score length func.temp run data get storage mq:main command_block.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 remove storage mq:main command_block.alias[0]
execute if score length func.temp matches 1.. run function mq:quiz/macro/summon2 with storage mq:main command_block
$execute unless data storage mq:main {command_block:{name:"음악퀴즈"}} run summon minecraft:marker $(x) $(y) $(z) {Tags:["mq","default"],CustomName:"정답입력종료"}
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: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:tmp marker_call.alias[0]
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 {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)"}
execute store result score length func.temp run data get storage mq:main command_block.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 remove storage mq:main command_block.alias[0]
execute if score length func.temp matches 1.. run function mq:quiz/macro/summon2 with storage mq:main command_block
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: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:tmp marker_call.alias[0]
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
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
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 players @a
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
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
# songs[$(idx)] → answer 로 복사하고, 트랙/커버 id 부여
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 skip buttons -1
scoreboard players set hint buttons -1
scoreboard players set replay buttons -1
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
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
# endding timer

View File

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