5 Commits

Author SHA1 Message Date
Claude (owner)
f98dd9952b 영상 캐시 기능 추가: 시작 시 미리받기 + 동적 재생 + FIFO 축출 + 주소 / 자동제거
- config 에 preload(미리받기 갯수)/keep(유지 갯수) 추가
- 시작 시 1..preload 캐시 미리받기, 재생 중에도 preload 개 앞까지 롤링 prefetch
- 재생 시 캐시 있으면 video_N, 없으면 전체 URL 로 동적 선택(데이터팩 self-tracking)
- keep 초과 시 가장 먼저 받은 캐시부터 삭제(FIFO)
- namespace 끝 / 자동 제거(normalize)
- command_block 한 tick 1회 발동 제약 회피: cache add/remove 직접 실행, clear 는 schedule

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
2026-06-04 22:28:29 +09:00
Claude (owner)
5e9e810e56 Merge remote-tracking branch 'origin/main' into codex/owner/mc_datapack 2026-06-04 22:11:49 +09:00
tkrmagid-desktop
5e80385ab0 수정 2026-06-04 22:06:49 +09:00
Claude (owner)
5eaa11e897 Merge remote-tracking branch 'origin/main' into codex/owner/mc_datapack 2026-05-23 18:01:15 +09:00
tkrmagid-desktop
f211b16224 수정 2026-05-23 17:40:05 +09:00
84 changed files with 507 additions and 143 deletions

View File

@@ -15,7 +15,7 @@
{
"type": "minecraft:plain_message",
"contents": {
"text": "\n1. 정답입력시에 채팅으로 입력해주시면 됩니다.\n[ 띄어쓰기, 영어 대소문자, 특수문자 ]\n상관없이 입력하셔도 인식 됩니다.\n\n2. 모든 소리는 날씨 소리로 조절할수 있습니다.\n\n3. 게임시작후 버튼들은 과반수(절반이상)가 눌러야 작동합니다.\n\n4. 힌트는 특수문자 제외 정답의 절반이 가려져서 나옵니다.\n힌트는 여러번 받을수 있고,\n받을때마다 가려지는 부분이 달라집니다."
"text": "\n1. 정답입력시에 채팅으로 입력해주시면 됩니다.\n[ 띄어쓰기, 영어 대소문자 ]\n상관없이 입력하셔도 인식 됩니다.\n\n2. 모든 소리는 주크박스/소리 블록 채널로 조절할수 있습니다.\n\n3. 게임시작후 버튼들은 과반수(절반이상)가 눌러야 작동합니다.\n\n4. 힌트는 특수문자 제외 정답의 절반이 가려져서 나옵니다.\n힌트는 여러번 받을수 있고,\n받을때마다 가려지는 부분이 달라집니다."
},
"width": 300
}

View File

@@ -8,3 +8,4 @@ execute if score init main matches 10 run return run function mq:tellraw {"text"
# warn-off execute-group
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

@@ -38,4 +38,8 @@ function mq:quiz/stop_sound
$scoreboard players set max_index main $(max_index)
scoreboard players set init main 1
# 시작 시 1..preload 번 영상 캐시 미리받기. schedule 로 다음 tick(서버 소스)에
# 실행해 videoCache add 권한 보장 + max_index 설정 이후 동작 보장.
schedule function mq:videos/cache/preload 1t
dialog show @a mq:page1

View File

@@ -74,3 +74,5 @@ kill @e[distance=0..,tag=mq,type=minecraft:text_display]
function mq:quiz/stop_sound
function mq:images/clear
function mq:videos/clear
function mq:videos/cache/clear

View File

@@ -1,6 +1,8 @@
stopsound @a block minecraft:block.stone_button.click_on
function mq:tellraw {"text":"띵!!!","color":"white","msg":'""'}
$stopsound @a player $(namespace):bell
# warn-off execute-group
execute as @a at @s run playsound minecraft:block.note_block.bell weather @s ~ ~ ~ 1 0.9
execute as @a at @s run playsound minecraft:block.note_block.bell weather @s ~ ~ ~ 1 0.9
execute as @a at @s run playsound minecraft:block.note_block.bell weather @s ~ ~ ~ 1 0.9
$execute as @a at @s run playsound $(namespace):bell $(source) @s ~ ~ ~ 1 0.9
$execute as @a at @s run playsound $(namespace):bell $(source) @s ~ ~ ~ 1 0.9
$execute as @a at @s run playsound $(namespace):bell $(source) @s ~ ~ ~ 1 0.9

View File

@@ -9,15 +9,16 @@
# label_color : 텍스트 색 (예 "black", "red", "#FFAA00"). 기본 "black".
# label_font : 텍스트 폰트 (예 "minecraft:default"). 기본 "minecraft:default".
# label_scale : 텍스트 크기 (Vector3f 한 축, 3축 동일). 기본 "1.0".
# label_addY : 추가할 높이. 기본 "-0.1".
#
# interaction entity 의 위치/크기와 text_display 의 위치/회전은 facing 만
# 보면 결정됨 — 매번 손으로 ox/oy/oz 를 적지 않는다. 실제 오프셋 테이블은
# repeat/buttons/btn 안에서 한 곳에만 정의되어 있다.
data modify storage mq:main button_defs set value []
data modify storage mq:main button_defs append value {n:"start", x:2773, y:86, z:5968, f:"north", c:"function mq:commands/start with storage mq:main", label:"게임시작"}
data modify storage mq:main button_defs append value {n:"stop", x:2771, y:86, z:5968, f:"north", c:"function mq:commands/stop with storage mq:main", label:"정지"}
data modify storage mq:main button_defs append value {n:"skip", x:2769, y:86, z:5968, f:"north", c:"function mq:commands/skip", label:"넘기기"}
data modify storage mq:main button_defs append value {n:"hint", x:2767, y:86, z:5968, f:"north", c:"function mq:commands/hint", label:"힌트"}
data modify storage mq:main button_defs append value {n:"replay", x:2765, y:86, z:5968, f:"north", c:"function mq:commands/replay", label:"다시듣기"}
data modify storage mq:main button_defs append value {n:"test", x:2769, y:87, z:5957, f:"south", c:"function mq:commands/test", label:"소리 테스트"}
data modify storage mq:main button_defs append value {n:"start", x:2773, y:86, z:5968, f:"north", c:"function mq:commands/start with storage mq:main", label:"게임시작"}
data modify storage mq:main button_defs append value {n:"stop", x:2771, y:86, z:5968, f:"north", c:"function mq:commands/stop with storage mq:main", label:"정지"}
data modify storage mq:main button_defs append value {n:"skip", x:2769, y:86, z:5968, f:"north", c:"function mq:commands/skip", label:"넘기기"}
data modify storage mq:main button_defs append value {n:"hint", x:2767, y:86, z:5968, f:"north", c:"function mq:commands/hint", label:"힌트"}
data modify storage mq:main button_defs append value {n:"replay", x:2765, y:86, z:5968, f:"north", c:"function mq:commands/replay", label:"다시듣기"}
data modify storage mq:main button_defs append value {n:"test", x:2769, y:87, z:5957, f:"south", c:"function mq:commands/test with storage mq:main audio", label:"소리\n테스트", label_addY: "-0.2"}

View File

@@ -6,17 +6,35 @@ data modify storage mq:main spawn set value {x: 2769, y: 85, z: 5963, r: 0, f: 0
# 음원 재생 — minecraft_launcher 리소스팩의 musicquiz:track_NN 사운드 이벤트
# namespace — 리소스팩 네임스페이스 (기본 "musicquiz")
# source — /playsound 채널. stopsound 와 동일해야 함. 노래는 "player" 채널로
# 재생 (음성/플레이어 채널 슬라이더로 음량 제어). 타이머/UI 비프는
# 별도로 weather 채널 사용.
# source — /playsound 채널. stopsound 와 동일해야 함. 노래는 "record" 채널로
# 재생 (주크박스/소리 블록 채널 슬라이더로 음량 제어).
# volume — 기본 음량. 곡별 override 는 init/songs.mcfunction 의 volume 필드 사용
# pitch — 1.0 = 원본 속도
data modify storage mq:main audio set value {namespace: "musicquiz", source: "player", volume: 1.0, pitch: 1.0}
data modify storage mq:main audio set value {namespace: "musicquiz", source: "record", volume: 1.0, pitch: 1.0}
# 정답 페인팅 — 데이터팩의 mq:cover_NN painting_variant (텍스처는 리소스팩 musicquiz:cover_NN)
# namespace — painting_variant 네임스페이스 (기본 "mq")
# x,y,z — 페인팅 entity 좌표 (벽면 앞쪽 블록 위치)
# facing — 페인팅이 바라보는 방향: south=0 / west=1 / north=2 / east=3
data modify storage mq:main image set value {namespace: "mq", x: 2775, y: 85, z: 5982, facing: 2b}
data modify storage mq:main image set value {namespace: "mq", x: 2782, y: 88, z: 5979, facing: 2b}
# 정답 영상 — 모드의 영상 재생 관련
# namespace — 영상 아이디를 제외한 주소 (마지막 / 는 자동으로 제거됨)
# x,y,z — 영상 블럭 좌표 (벽면 앞쪽 블록 위치)
# w,h — 영상 가로세로 크키 (왼쪽아래 기준)
# facing — 영상이 바라보는 방향: south / west / north / east
# sound — 영상 소리 설정 (0~100, 음소거: -1)
# preload — 게임 시작 시 미리 받아둘 영상 캐시 갯수 (1번부터 N번까지).
# 재생 중에도 항상 N개 앞까지 미리 받아둠. 0 이면 미리받기 끔(매번 URL 재생)
# keep — 캐시 유지 갯수(FIFO). 이 값을 넘기면 가장 먼저 받은 캐시부터 삭제.
# 메모리 관리용이므로 preload 보다 크거나 같게 설정 권장
data modify storage mq:main video set value { \
namespace: "https://video.tkrmagid.kr/api/video/1/2", \
cmd_x: 2769, cmd_y: 73, cmd_z: 5965, \
x: 2731, y: 96, z: 6034, facing: "north", w: 25,h: 14, \
sound: -1, \
preload: 5, \
keep: 10 \
}
# 곡 개수 max_index 는 init/songs.mcfunction 의 길이로 자동 계산됨

View File

@@ -2,25 +2,25 @@
# 필수 — title, author, alias, volume
# volume: /playsound 음량. 1.0 = 기본. 곡마다 음량 조절 가능.
# 곡 순서가 리소스팩의 track_NN / cover_NN 인덱스와 1:1 매칭된다.
# 예) {title:"Quiet Song", author:"...", alias:[...], volume:2.0}
# 예) {title:"Quiet Song", author:"...", alias:[...], description:"...", volume:0.5}
data modify storage mq:main songs set value []
data modify storage mq:main songs append value {title:"푸르던", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"금요일에 만나요", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"나의 옛날이야기", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"비밀의 화원", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"겨울잠", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"이런엔딩", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"이름에게", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"드라마", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"가을아침", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"Rain Drop", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"에필로그", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"무릎", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"마음", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"잠 못 드는 밤 비는 내리고", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"정거장", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"자장가", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"사랑이 지나가면", author:"아이유", alias:[]}
data modify storage mq:main songs append value {title:"푸르던", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"금요일에 만나요", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"나의 옛날이야기", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"비밀의 화원", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"겨울잠", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"이런엔딩", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"이름에게", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"드라마", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"가을아침", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"Rain Drop", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"에필로그", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"무릎", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"마음", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"잠 못 드는 밤 비는 내리고", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"정거장", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"자장가", author:"아이유", alias:[], description:"", volume:1.0}
data modify storage mq:main songs append value {title:"사랑이 지나가면", author:"아이유", alias:[], description:"", volume:1.0}
# 곡 개수는 songs 배열 길이에서 자동 계산됨
execute store result storage mq:main max_index int 1 run data get storage mq:main songs

View File

@@ -1,8 +1,9 @@
data modify storage mq:main answer set value {title:"", author:"", alias:[]}
data modify storage mq:main answer set value {title:"", author:"", alias:[], description:""}
data merge storage func:temp {}
data merge storage mq:tmp {}
function mq:init/config
function mq:videos/normalize
function mq:init/songs
function mq:init/buttons
function mq:init/triggers
@@ -45,3 +46,5 @@ bossbar add mq:process [{"text":"진행도: ","color": "yellow","bold": true},{"
function mq:commands/stop with storage mq:main
function mq:players/login with storage mq:main spawn
function mq:videos/cache/clear

View File

@@ -5,6 +5,7 @@ scoreboard players set @s answer 2
function mq:tellraw {"text":"","color":"black","msg":""}
function mq:tellraw {"text":"","color":"black",msg:[{"text":"정답: ","color": "aqua"},{"storage":"mq:main","nbt":"answer.title","color": "yellow","bold": true}]}
function mq:tellraw {"text":"","color":"black",msg:[{"text":"가수: ","color":"aqua"},{"storage":"mq:main","nbt":"answer.author","color": "yellow","bold": true}]}
function mq:tellraw {"text":"","color":"black",msg:[{"text":"설명: ","color":"aqua"},{"storage":"mq:main","nbt":"answer.description","color": "yellow","bold": false}]}
execute if score skip buttons matches -2 run function mq:tellraw {"text":"","color":"black",msg:[{"text":"정답자: ","color": "aqua"},{"text":"스킵","color": "yellow","bold": true}]}
execute unless score skip buttons matches -2 run function mq:tellraw {"text":"","color":"black",msg:[{"text":"정답자: ","color": "aqua"},{"selector":"@s","color": "yellow","bold": true}]}
function mq:tellraw {"text":"","color":"black",msg:[{"text": "( 15초뒤 다음문제로 넘어갑니다. )","color": "gray"}]}
@@ -30,3 +31,4 @@ scoreboard players set replay buttons -3
scoreboard players set timer main 1
function mq:images/show
function mq:videos/show

View File

@@ -3,3 +3,8 @@ 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
# volume 테스트 (replay 이용)
# function mq:quiz/stop_sound
# data modify storage mq:main answer.volume set value 0.5
# function mq:quiz/play_sound

View File

@@ -20,3 +20,4 @@ execute if score index main matches 1..9 run data modify storage mq:tmp pad set
execute unless score index main matches 1..9 run data modify storage mq:tmp pad set value ""
function mq:quiz/setanswer
function mq:videos/cache/add

View File

@@ -1,6 +1,6 @@
# warn-off-file always-pass-condition
# 버튼 1개에 대한 매 tick 처리.
# 매크로 인자(mq:tmp.btn): n, x, y, z, f, c, label, label_color, label_font, label_scale
# 매크로 인자(mq:tmp.btn): n, x, y, z, f, c, label, label_color, label_font, label_scale, label_addY
# buttons 점수 상태:
# ..-2 : 비활성 (버튼 블록 제거, interaction 응답 차단)
# -1 : 초기화 단계 (버튼 블록 + interaction × 3 + text_display 보장 후 0)
@@ -80,25 +80,25 @@ $execute if score $(n) buttons matches -1 run kill @e[distance=0..,tag=mq,tag=$(
$execute if score $(n) buttons matches -1 if data storage mq:tmp btn{f:"south"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:interaction ~0.37 ~0.37 ~0.07 {Tags:["mq","$(n)"],width:0.125f,height:0.26f,response:0b}
$execute if score $(n) buttons matches -1 if data storage mq:tmp btn{f:"south"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:interaction ~0.5 ~0.37 ~0.07 {Tags:["mq","$(n)"],width:0.13f,height:0.26f,response:0b}
$execute if score $(n) buttons matches -1 if data storage mq:tmp btn{f:"south"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:interaction ~0.63 ~0.37 ~0.07 {Tags:["mq","$(n)"],width:0.125f,height:0.26f,response:0b}
$execute if score $(n) buttons matches -1 unless data storage mq:tmp btn{label:""} if data storage mq:tmp btn{f:"south"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:text_display ~0.5 ~-0.5 ~0.01 {Tags:["mq","$(n)"],Rotation:[0f,0f],background:0,text:{text:"$(label)",color:"$(label_color)",font:"$(label_font)",bold:true},transformation:{scale:[$(label_scale)f,$(label_scale)f,$(label_scale)f],translation:[0f,0f,0f],left_rotation:[0f,0f,0f,1f],right_rotation:[0f,0f,0f,1f]}}
$execute if score $(n) buttons matches -1 unless data storage mq:tmp btn{label:""} if data storage mq:tmp btn{f:"south"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:text_display ~0.5 ~-0.5 ~0.01 {Tags:["mq","$(n)"],Rotation:[0f,0f],background:0,text:{text:"$(label)",color:"$(label_color)",font:"$(label_font)",bold:true},transformation:{scale:[$(label_scale)f,$(label_scale)f,$(label_scale)f],translation:[0f,$(label_addY)f,0f],left_rotation:[0f,0f,0f,1f],right_rotation:[0f,0f,0f,1f]}}
# north: 깊이축=z(+0.8125, 플레이어 쪽), 가로축=x, 3 타일 + 라벨
$execute if score $(n) buttons matches -1 if data storage mq:tmp btn{f:"north"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:interaction ~0.37 ~0.37 ~0.93 {Tags:["mq","$(n)"],width:0.125f,height:0.26f,response:0b}
$execute if score $(n) buttons matches -1 if data storage mq:tmp btn{f:"north"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:interaction ~0.5 ~0.37 ~0.93 {Tags:["mq","$(n)"],width:0.13f,height:0.26f,response:0b}
$execute if score $(n) buttons matches -1 if data storage mq:tmp btn{f:"north"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:interaction ~0.63 ~0.37 ~0.93 {Tags:["mq","$(n)"],width:0.125f,height:0.26f,response:0b}
$execute if score $(n) buttons matches -1 unless data storage mq:tmp btn{label:""} if data storage mq:tmp btn{f:"north"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:text_display ~0.5 ~-0.5 ~0.99 {Tags:["mq","$(n)"],Rotation:[180f,0f],background:0,text:{text:"$(label)",color:"$(label_color)",font:"$(label_font)",bold:true},transformation:{scale:[$(label_scale)f,$(label_scale)f,$(label_scale)f],translation:[0f,0f,0f],left_rotation:[0f,0f,0f,1f],right_rotation:[0f,0f,0f,1f]}}
$execute if score $(n) buttons matches -1 unless data storage mq:tmp btn{label:""} if data storage mq:tmp btn{f:"north"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:text_display ~0.5 ~-0.5 ~0.99 {Tags:["mq","$(n)"],Rotation:[180f,0f],background:0,text:{text:"$(label)",color:"$(label_color)",font:"$(label_font)",bold:true},transformation:{scale:[$(label_scale)f,$(label_scale)f,$(label_scale)f],translation:[0f,$(label_addY)f,0f],left_rotation:[0f,0f,0f,1f],right_rotation:[0f,0f,0f,1f]}}
# east: 깊이축=x(+0.1875, 플레이어 쪽), 가로축=z, 3 타일 + 라벨
$execute if score $(n) buttons matches -1 if data storage mq:tmp btn{f:"east"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:interaction ~0.07 ~0.37 ~0.37 {Tags:["mq","$(n)"],width:0.125f,height:0.26f,response:0b}
$execute if score $(n) buttons matches -1 if data storage mq:tmp btn{f:"east"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:interaction ~0.07 ~0.37 ~0.5 {Tags:["mq","$(n)"],width:0.13f,height:0.26f,response:0b}
$execute if score $(n) buttons matches -1 if data storage mq:tmp btn{f:"east"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:interaction ~0.07 ~0.37 ~0.63 {Tags:["mq","$(n)"],width:0.125f,height:0.26f,response:0b}
$execute if score $(n) buttons matches -1 unless data storage mq:tmp btn{label:""} if data storage mq:tmp btn{f:"east"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:text_display ~0.01 ~-0.5 ~0.5 {Tags:["mq","$(n)"],Rotation:[-90f,0f],background:0,text:{text:"$(label)",color:"$(label_color)",font:"$(label_font)",bold:true},transformation:{scale:[$(label_scale)f,$(label_scale)f,$(label_scale)f],translation:[0f,0f,0f],left_rotation:[0f,0f,0f,1f],right_rotation:[0f,0f,0f,1f]}}
$execute if score $(n) buttons matches -1 unless data storage mq:tmp btn{label:""} if data storage mq:tmp btn{f:"east"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:text_display ~0.01 ~-0.5 ~0.5 {Tags:["mq","$(n)"],Rotation:[-90f,0f],background:0,text:{text:"$(label)",color:"$(label_color)",font:"$(label_font)",bold:true},transformation:{scale:[$(label_scale)f,$(label_scale)f,$(label_scale)f],translation:[0f,$(label_addY)f,0f],left_rotation:[0f,0f,0f,1f],right_rotation:[0f,0f,0f,1f]}}
# west: 깊이축=x(+0.8125, 플레이어 쪽), 가로축=z, 3 타일 + 라벨
$execute if score $(n) buttons matches -1 if data storage mq:tmp btn{f:"west"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:interaction ~0.93 ~0.37 ~0.37 {Tags:["mq","$(n)"],width:0.125f,height:0.26f,response:0b}
$execute if score $(n) buttons matches -1 if data storage mq:tmp btn{f:"west"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:interaction ~0.93 ~0.37 ~0.5 {Tags:["mq","$(n)"],width:0.13f,height:0.26f,response:0b}
$execute if score $(n) buttons matches -1 if data storage mq:tmp btn{f:"west"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:interaction ~0.93 ~0.37 ~0.63 {Tags:["mq","$(n)"],width:0.125f,height:0.26f,response:0b}
$execute if score $(n) buttons matches -1 unless data storage mq:tmp btn{label:""} if data storage mq:tmp btn{f:"west"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:text_display ~0.99 ~-0.5 ~0.5 {Tags:["mq","$(n)"],Rotation:[90f,0f],background:0,text:{text:"$(label)",color:"$(label_color)",font:"$(label_font)",bold:true},transformation:{scale:[$(label_scale)f,$(label_scale)f,$(label_scale)f],translation:[0f,0f,0f],left_rotation:[0f,0f,0f,1f],right_rotation:[0f,0f,0f,1f]}}
$execute if score $(n) buttons matches -1 unless data storage mq:tmp btn{label:""} if data storage mq:tmp btn{f:"west"} positioned $(x).0 $(y).0 $(z).0 run summon minecraft:text_display ~0.99 ~-0.5 ~0.5 {Tags:["mq","$(n)"],Rotation:[90f,0f],background:0,text:{text:"$(label)",color:"$(label_color)",font:"$(label_font)",bold:true},transformation:{scale:[$(label_scale)f,$(label_scale)f,$(label_scale)f],translation:[0f,$(label_addY)f,0f],left_rotation:[0f,0f,0f,1f],right_rotation:[0f,0f,0f,1f]}}
$execute if score $(n) buttons matches -1 run scoreboard players set $(n) buttons 0
@@ -109,8 +109,9 @@ $execute if score $(n) buttons matches -1 run scoreboard players set $(n) button
# (나머지는 target 부재로 체인 중단). limit=1 을 두면 MC 가 임의로 1개를
# 골라 잘못된 entity 만 검사하므로 limit 두지 않음.
$execute as @e[distance=0..,tag=mq,tag=$(n),type=minecraft:interaction] on target as @s positioned $(x).0 $(y).0 $(z).0 run playsound minecraft:block.stone_button.click_on block @s ~ ~ ~ 1 1
$execute as @e[distance=0..,tag=mq,tag=$(n),type=minecraft:interaction] on target as @s positioned $(x).0 $(y).0 $(z).0 if score init main matches 0 run $(c)
$execute as @e[distance=0..,tag=mq,tag=$(n),type=minecraft:interaction] on target as @s positioned $(x).0 $(y).0 $(z).0 unless score init main matches 0 run trigger $(n)
$execute as @e[distance=0..,tag=mq,tag=$(n),type=minecraft:interaction] on target if data storage mq:tmp btn{n:"test"} run $(c)
$execute as @e[distance=0..,tag=mq,tag=$(n),type=minecraft:interaction] on target unless data storage mq:tmp btn{n:"test"} as @s positioned $(x).0 $(y).0 $(z).0 if score init main matches 0 run $(c)
$execute as @e[distance=0..,tag=mq,tag=$(n),type=minecraft:interaction] on target unless data storage mq:tmp btn{n:"test"} as @s positioned $(x).0 $(y).0 $(z).0 unless score init main matches 0 run trigger $(n)
# ---- 처리 후 attack/interaction NBT 클리어 (다음 tick 중복 발화 방지) ----
$execute as @e[distance=0..,tag=mq,tag=$(n),type=minecraft:interaction] at @s run data remove entity @s attack

View File

@@ -6,6 +6,7 @@
# label_color : 기본 "black"
# label_font : 기본 "minecraft:default"
# label_scale : 기본 "1.0" (Vector3f 의 한 축, 3축 동일하게 사용됨)
# label_addY : 기본 "-0.1"
#
# 구현: defaults 컴파운드를 먼저 만들고 entry (mq:tmp.btn) 를 그 위에 merge
# 한 뒤 다시 mq:tmp.btn 으로 되돌린다. data modify ... merge from 은 source
@@ -16,6 +17,6 @@
# 방식이었으나 MC 26.1.2 parser 가 해당 라인을 거부했음. merge 방식은 문제
# 난 execute-unless-data 구문 자체를 제거.)
data modify storage mq:tmp btn_default set value {label:"",label_color:"black",label_font:"minecraft:default",label_scale:"1.0"}
data modify storage mq:tmp btn_default set value {label:"",label_color:"black",label_font:"minecraft:default",label_scale:"1.0",label_addY:"-0.1"}
data modify storage mq:tmp btn_default merge from storage mq:tmp btn
data modify storage mq:tmp btn set from storage mq:tmp btn_default

View File

@@ -6,10 +6,10 @@ execute unless score init main matches 2 \
run scoreboard players set timer main 0
# start title timer
execute if score init main matches 2 run function mq:repeat/timers/init2
execute if score init main matches 2 run function mq:repeat/timers/init2 with storage mq:main audio
# next song timer
execute if score init main matches 6 run function mq:repeat/timers/init6
# endding timer
execute if score init main matches 10 run function mq:repeat/timers/init10
execute if score init main matches 10 run function mq:repeat/timers/init10 with storage mq:main audio

View File

@@ -1,3 +1,15 @@
execute if score timer main matches 300 run title @a title {"text":""}
execute if score timer main matches 290 run function mq:images/clear
execute if score timer main matches 300.. run function mq:quiz/select with storage mq:main
# warn-off-file execute-group
execute if score timer main matches 60 run function mq:tellraw {"text":"퀴즈가 종료되었습니다.","color":"white","msg":""}
$execute if score timer main matches 60 as @a at @s run playsound minecraft:ui.button.click $(source) @s ~ ~ ~ 1 1
$execute if score timer main matches 60 as @a at @s run playsound minecraft:ui.button.click $(source) @s ~ ~ ~ 1 1
$execute if score timer main matches 60 as @a at @s run playsound minecraft:ui.button.click $(source) @s ~ ~ ~ 1 1
execute if score timer main matches 180 run function mq:tellraw {"text":"퀴즈를 다시 시작하시려면 종료를 눌러주세요.","color":"white","msg":""}
execute if score timer main matches 120 as @a at @s run scoreboard players set stop buttons -1
$execute if score timer main matches 120 as @a at @s run playsound minecraft:ui.button.click $(source) @s ~ ~ ~ 1 1
$execute if score timer main matches 120 as @a at @s run playsound minecraft:ui.button.click $(source) @s ~ ~ ~ 1 1
$execute if score timer main matches 120 as @a at @s run playsound minecraft:ui.button.click $(source) @s ~ ~ ~ 1 1
execute if score timer main matches 120 run function mq:tellraw {"text":"플레이 해주셔서 감사합니다.","color":"white","msg":""}
$execute if score timer main matches 180 as @a at @s run playsound minecraft:ui.button.click $(source) @s ~ ~ ~ 1 1
$execute if score timer main matches 180 as @a at @s run playsound minecraft:ui.button.click $(source) @s ~ ~ ~ 1 1
$execute if score timer main matches 180 as @a at @s run playsound minecraft:ui.button.click $(source) @s ~ ~ ~ 1 1
execute if score timer main matches 200.. run scoreboard players set init main 11

View File

@@ -1,15 +1,15 @@
# warn-off-file execute-group
execute if score timer main matches 20 run title @a title {"text":"3"}
execute if score timer main matches 20 as @a at @s run playsound minecraft:block.note_block.iron_xylophone weather @s ~ ~ ~ 1 1
execute if score timer main matches 20 as @a at @s run playsound minecraft:block.note_block.iron_xylophone weather @s ~ ~ ~ 1 1
execute if score timer main matches 20 as @a at @s run playsound minecraft:block.note_block.iron_xylophone weather @s ~ ~ ~ 1 1
$execute if score timer main matches 20 as @a at @s run playsound minecraft:block.note_block.iron_xylophone $(source) @s ~ ~ ~ 1 1
$execute if score timer main matches 20 as @a at @s run playsound minecraft:block.note_block.iron_xylophone $(source) @s ~ ~ ~ 1 1
$execute if score timer main matches 20 as @a at @s run playsound minecraft:block.note_block.iron_xylophone $(source) @s ~ ~ ~ 1 1
execute if score timer main matches 40 run title @a title {"text":"2"}
execute if score timer main matches 40 as @a at @s run playsound minecraft:block.note_block.iron_xylophone weather @s ~ ~ ~ 1 1
execute if score timer main matches 40 as @a at @s run playsound minecraft:block.note_block.iron_xylophone weather @s ~ ~ ~ 1 1
execute if score timer main matches 40 as @a at @s run playsound minecraft:block.note_block.iron_xylophone weather @s ~ ~ ~ 1 1
$execute if score timer main matches 40 as @a at @s run playsound minecraft:block.note_block.iron_xylophone $(source) @s ~ ~ ~ 1 1
$execute if score timer main matches 40 as @a at @s run playsound minecraft:block.note_block.iron_xylophone $(source) @s ~ ~ ~ 1 1
$execute if score timer main matches 40 as @a at @s run playsound minecraft:block.note_block.iron_xylophone $(source) @s ~ ~ ~ 1 1
execute if score timer main matches 60 run title @a title {"text":"1"}
execute if score timer main matches 60 as @a at @s run playsound minecraft:block.note_block.iron_xylophone weather @s ~ ~ ~ 1 1
execute if score timer main matches 60 as @a at @s run playsound minecraft:block.note_block.iron_xylophone weather @s ~ ~ ~ 1 1
execute if score timer main matches 60 as @a at @s run playsound minecraft:block.note_block.iron_xylophone weather @s ~ ~ ~ 1 1
$execute if score timer main matches 60 as @a at @s run playsound minecraft:block.note_block.iron_xylophone $(source) @s ~ ~ ~ 1 1
$execute if score timer main matches 60 as @a at @s run playsound minecraft:block.note_block.iron_xylophone $(source) @s ~ ~ ~ 1 1
$execute if score timer main matches 60 as @a at @s run playsound minecraft:block.note_block.iron_xylophone $(source) @s ~ ~ ~ 1 1
execute if score timer main matches 100 run title @a title {"text":""}
execute if score timer main matches 100.. run function mq:quiz/select with storage mq:main

View File

@@ -1,15 +1,5 @@
# warn-off-file execute-group
execute if score timer main matches 60 run function mq:tellraw {"text":"퀴즈가 종료되었습니다.","color":"white","msg":""}
execute if score timer main matches 60 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
execute if score timer main matches 60 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
execute if score timer main matches 60 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
execute if score timer main matches 180 run function mq:tellraw {"text":"퀴즈를 다시 시작하시려면 종료를 눌러주세요.","color":"white","msg":""}
execute if score timer main matches 120 as @a at @s run scoreboard players set stop buttons -1
execute if score timer main matches 120 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
execute if score timer main matches 120 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
execute if score timer main matches 120 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
execute if score timer main matches 120 run function mq:tellraw {"text":"플레이 해주셔서 감사합니다.","color":"white","msg":""}
execute if score timer main matches 180 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
execute if score timer main matches 180 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
execute if score timer main matches 180 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
execute if score timer main matches 200.. run scoreboard players set init main 11
execute if score timer main matches 300 run title @a title {"text":""}
# warn-off execute-group
execute if score timer main matches 290 run function mq:images/clear
execute if score timer main matches 290 run function mq:videos/clear
execute if score timer main matches 300.. run function mq:quiz/select with storage mq:main

View File

@@ -0,0 +1,12 @@
# 재생 진행에 맞춰 항상 preload 개 앞까지 캐시를 채운다.
# 현재 index 에서 (preload-1) 만큼 앞선 영상을 받아두면 시작 시 preload(1..N)
# 와 합쳐져 N개 버퍼가 굴러간다.
execute store result score cache_preload func.temp run data get storage mq:main video.preload
execute if score cache_preload func.temp matches ..0 run return 0
scoreboard players operation cache_target func.temp = index main
scoreboard players operation cache_target func.temp += cache_preload func.temp
scoreboard players remove cache_target func.temp 1
execute if score cache_target func.temp > max_index main run return 0
function mq:videos/cache/add_one

View File

@@ -0,0 +1,4 @@
# cache_target(func.temp) 번 영상을 캐시에 추가. 매크로로 넘겨 등록/추적/축출.
data modify storage mq:tmp video set from storage mq:main video
execute store result storage mq:tmp video.num int 1 run scoreboard players get cache_target func.temp
function mq:videos/cache/macro/add_one with storage mq:tmp video

View File

@@ -0,0 +1,5 @@
# 추적 목록을 비우고, 다음 tick 에 서버 소스로 전체 캐시 wipe.
# (videoCache clear 를 호출자 소스에서 바로 실행하면 player/비OP 소스일 때
# 권한 문제가 날 수 있어 schedule 로 서버 소스 보장.)
data modify storage mq:main video.cached set value []
schedule function mq:videos/cache/clear_run 1t

View File

@@ -0,0 +1 @@
videoCache clear

View File

@@ -0,0 +1,4 @@
# 캐시 갯수가 keep 을 넘으면 가장 먼저 받은 것부터(FIFO) 삭제.
execute store result score cache_len func.temp run data get storage mq:main video.cached
execute store result score cache_keep func.temp run data get storage mq:main video.keep
execute if score cache_len func.temp > cache_keep func.temp run function mq:videos/cache/evict_one

View File

@@ -0,0 +1,5 @@
execute store result storage mq:tmp evict_num int 1 run data get storage mq:main video.cached[0].i
function mq:videos/cache/macro/evict_one with storage mq:tmp
data remove storage mq:main video.cached[0]
# keep 보다 여러 개 초과해 있을 수 있으니 재귀로 다시 검사.
function mq:videos/cache/evict

View File

@@ -0,0 +1,7 @@
# 이미 받은 영상이면(추적 목록에 {i:num} 존재) 건너뜀.
$execute if data storage mq:main video.cached[{i:$(num)}] run return 0
# videoCache add 는 서버 소스(또는 OP)에서 직접 실행. preload/select 모두 서버
# 소스이므로 command_block 우회 없이 바로 호출 가능.
$videoCache add video_$(num) $(namespace)/$(num)
$data modify storage mq:main video.cached append value {i:$(num)}
function mq:videos/cache/evict

View File

@@ -0,0 +1 @@
$videoCache remove video_$(evict_num)

View File

@@ -0,0 +1,5 @@
# 게임 시작 시 1번부터 preload 번까지 캐시를 미리 받는다 (max_index 로 상한).
scoreboard players set cache_i func.temp 1
execute store result score cache_max func.temp run data get storage mq:main video.preload
execute if score cache_max func.temp > max_index main run scoreboard players operation cache_max func.temp = max_index main
function mq:videos/cache/preload_loop

View File

@@ -0,0 +1,5 @@
execute if score cache_i func.temp > cache_max func.temp run return 0
scoreboard players operation cache_target func.temp = cache_i func.temp
function mq:videos/cache/add_one
scoreboard players add cache_i func.temp 1
function mq:videos/cache/preload_loop

View File

@@ -0,0 +1,4 @@
data modify storage mq:tmp video set from storage mq:main video
execute store result storage mq:tmp video.num int 1 run scoreboard players get index main
data modify storage mq:tmp video.cmd set value "delete"
function mq:videos/macro/cmd with storage mq:tmp video

View File

@@ -0,0 +1,14 @@
$execute if data storage mq:tmp {video:{cmd:"delete"}} run setblock $(cmd_x) $(cmd_y) $(cmd_z) minecraft:command_block[conditional=false,facing=up]{ \
Command:"videoDelete $(x) $(y) $(z)", \
auto:0b \
}
$execute if data storage mq:tmp {video:{cmd:"play"}} run setblock $(cmd_x) $(cmd_y) $(cmd_z) minecraft:command_block[conditional=false,facing=up]{ \
Command:"videoPlace $(x) $(y) $(z) $(facing) $(w) $(h) $(sound) $(src)", \
auto:0b \
}
$execute if data storage mq:tmp {video:{cmd:"custom"}} run setblock $(cmd_x) $(cmd_y) $(cmd_z) minecraft:command_block[conditional=false,facing=up]{ \
Command:"$(cmd_value)", \
auto:0b \
}
$data modify block $(cmd_x) $(cmd_y) $(cmd_z) auto set value 1b

View File

@@ -0,0 +1,8 @@
# mq:tmp video.src 를 결정한다.
# - 기본: 전체 URL "<namespace>/<num>"
# - mq:main video.cached 목록에 {i:num} 이 있으면(=videoCache add 로 등록됨)
# 등록 이름 "video_<num>" 사용 → 모드가 서버 config 에서 URL 로 resolve.
# cached 목록은 데이터팩이 videoCache add/remove 와 1:1 로 직접 추적하므로
# 모드에 캐시 존재 여부를 묻지 않고도 정확하다.
$data modify storage mq:tmp video.src set value "$(namespace)/$(num)"
$execute if data storage mq:main video.cached[{i:$(num)}] run data modify storage mq:tmp video.src set value "video_$(num)"

View File

@@ -0,0 +1,7 @@
# namespace 끝에 / 가 붙어 있으면 제거 (config 오타 방어).
# string 소스 마지막 글자만 떼서 비교 후, 맞으면 마지막 글자를 잘라낸다.
data modify storage mq:tmp ns_last set string storage mq:main video.namespace -1
execute if data storage mq:tmp {ns_last:"/"} run data modify storage mq:main video.namespace set string storage mq:main video.namespace 0 -1
# 캐시 추적 목록 초기화 (videoCache add/remove 와 1:1 로 관리되는 {i:N} 리스트)
data modify storage mq:main video.cached set value []

View File

@@ -0,0 +1,10 @@
# 정답 영상 재생. videoPlace 는 같은 앵커 좌표를 덮어쓰므로 별도 clear 불필요
# (clear + place 를 한 tick 에 하면 command_block 이 한 번만 켜져 place 가 씹힘).
data modify storage mq:tmp video set from storage mq:main video
execute store result storage mq:tmp video.num int 1 run scoreboard players get index main
# 캐시가 있으면 video_N(등록된 이름), 없으면 전체 URL 로 src 결정
function mq:videos/macro/resolve_src with storage mq:tmp video
data modify storage mq:tmp video.cmd set value "play"
function mq:videos/macro/cmd with storage mq:tmp video

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_01",
"width": 2,
"height": 2,
"title": "cover_01",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_01"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_02",
"width": 2,
"height": 2,
"title": "cover_02",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_02"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_03",
"width": 2,
"height": 2,
"title": "cover_03",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_03"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_04",
"width": 2,
"height": 2,
"title": "cover_04",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_04"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_05",
"width": 2,
"height": 2,
"title": "cover_05",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_05"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_06",
"width": 2,
"height": 2,
"title": "cover_06",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_06"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_07",
"width": 2,
"height": 2,
"title": "cover_07",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_07"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_08",
"width": 2,
"height": 2,
"title": "cover_08",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_08"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_09",
"width": 2,
"height": 2,
"title": "cover_09",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_09"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_10",
"width": 2,
"height": 2,
"title": "cover_10",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_10"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_11",
"width": 2,
"height": 2,
"title": "cover_11",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_11"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_12",
"width": 2,
"height": 2,
"title": "cover_12",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_12"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_13",
"width": 2,
"height": 2,
"title": "cover_13",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_13"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_14",
"width": 2,
"height": 2,
"title": "cover_14",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_14"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_15",
"width": 2,
"height": 2,
"title": "cover_15",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_15"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_16",
"width": 2,
"height": 2,
"title": "cover_16",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_16"
}

View File

@@ -1,7 +1,7 @@
{
"asset_id": "musicquiz:cover_17",
"width": 2,
"height": 2,
"title": "cover_17",
"author": "musicquiz"
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_17"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_18",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_18"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_19",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_19"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_20",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_20"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_21",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_21"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_22",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_22"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_23",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_23"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_24",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_24"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_25",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_25"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_26",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_26"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_27",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_27"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_28",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_28"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_29",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_29"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_30",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_30"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_31",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_31"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_32",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_32"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_33",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_33"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_34",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_34"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_35",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_35"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_36",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_36"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_37",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_37"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_38",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_38"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_39",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_39"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_40",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_40"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_41",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_41"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_42",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_42"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_43",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_43"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_44",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_44"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_45",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_45"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_46",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_46"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_47",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_47"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_48",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_48"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_49",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_49"
}

View File

@@ -0,0 +1,7 @@
{
"asset_id": "musicquiz:cover_50",
"width": 5,
"height": 5,
"author": "musicquiz",
"title": "cover_50"
}

View File

@@ -1,7 +1,5 @@
{
"asset_id": "musicquiz:gif",
"width": 2,
"height": 2,
"title": "gif",
"author": "musicquiz"
"width": 1,
"height": 1
}