op: 데이터팩 출력을 zip 대신 songs.mcfunction 코드 텍스트로 변경
운영자가 mc_datapack 의 init/songs.mcfunction 파일에 직접 복사해 붙여넣
는 워크플로로 단순화. 전체 데이터팩을 패키징할 필요가 없다.
- /op/datapack/:packName/generate 가 buildSongsMcfunction(list) 결과를
text/plain 으로 반환 (zip 스트리밍 제거).
- file/datapacks/music_quiz_template/ 정적 사본 제거.
- datapack.ejs 에 코드블록·복사 버튼 복원, 안내 문구 추가
("data/mq/function/init/songs.mcfunction 에 그대로 덮어쓰세요").
- datapack 로케일 라벨을 "코드 출력 / 복사 / 출력 완료" 로 정리.
This commit is contained in:
@@ -1,7 +0,0 @@
|
|||||||
scoreboard objectives add func.temp dummy
|
|
||||||
|
|
||||||
$execute store result score n1 func.temp run data get storage func:temp $(n1)
|
|
||||||
$execute store result score n2 func.temp run data get storage func:temp $(n2)
|
|
||||||
|
|
||||||
execute if score n1 func.temp = n2 func.temp run return 1
|
|
||||||
return 0
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
scoreboard players set two func.temp 2
|
|
||||||
|
|
||||||
$data modify storage func:temp half.result set from storage func:temp $(list)
|
|
||||||
|
|
||||||
execute store result score length func.temp run data get storage func:temp half.result
|
|
||||||
|
|
||||||
scoreboard players operation half func.temp = length func.temp
|
|
||||||
scoreboard players operation half func.temp /= two func.temp
|
|
||||||
|
|
||||||
scoreboard players operation odd func.temp = length func.temp
|
|
||||||
scoreboard players operation odd func.temp %= two func.temp
|
|
||||||
|
|
||||||
scoreboard players operation half func.temp += odd func.temp
|
|
||||||
|
|
||||||
function func:half/f1
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
execute if score half func.temp < length func.temp run function func:half/f2
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
data remove storage func:temp half.result[-1]
|
|
||||||
|
|
||||||
scoreboard players remove length func.temp 1
|
|
||||||
|
|
||||||
function func:half/f1
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
$function func:length {text:"$(text)"}
|
|
||||||
# return length
|
|
||||||
function func:num_list with storage func:temp
|
|
||||||
# return num_list
|
|
||||||
function func:shuffle {list:"num_list"}
|
|
||||||
# return shuffle.result
|
|
||||||
function func:half {list:"shuffle.result"}
|
|
||||||
# return half.result
|
|
||||||
|
|
||||||
$function func:length {text:"$(text)"}
|
|
||||||
# return length
|
|
||||||
function func:text_list with storage func:temp
|
|
||||||
# return text_list
|
|
||||||
|
|
||||||
function func:join {list:"text_list"}
|
|
||||||
# return join.text
|
|
||||||
|
|
||||||
# tellraw @a {"storage":"func:temp","nbt":"join.text"}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
$execute if data storage func:temp {$(l1):{$(l2):[$(index)]}} run return 1
|
|
||||||
return 0
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
$execute if data storage func:temp {space:{text:"$(space)"}} run return 1
|
|
||||||
return 0
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
data modify storage func:temp join.text set value ""
|
|
||||||
$data modify storage func:temp join.list set from storage func:temp $(list)
|
|
||||||
|
|
||||||
function func:join/f1
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
execute store result score length func.temp run data get storage func:temp join.list
|
|
||||||
|
|
||||||
execute if score length func.temp matches 0 run return 1
|
|
||||||
|
|
||||||
data modify storage func:temp join.now set from storage func:temp join.text
|
|
||||||
data modify storage func:temp join.next set from storage func:temp join.list[0]
|
|
||||||
|
|
||||||
function func:join/f2 with storage func:temp join
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
$data modify storage func:temp join.text set value "$(now)$(next)"
|
|
||||||
|
|
||||||
data remove storage func:temp join.list[0]
|
|
||||||
|
|
||||||
function func:join/f1
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
$data modify storage func:temp text set value "$(text)"
|
|
||||||
|
|
||||||
execute store result storage func:temp length int 1 run data get storage func:temp text
|
|
||||||
|
|
||||||
return run data get storage func:temp length
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
data modify storage func:temp space.space set value " "
|
|
||||||
data modify storage func:temp zero set value 0
|
|
||||||
$data modify storage func:temp length set value $(length)
|
|
||||||
|
|
||||||
execute store result score result func.temp run function func:comp_num {n1:"zero",n2:"length"}
|
|
||||||
execute if score result func.temp matches 1 run tellraw @s {"text":"length는 1이상 이어야 합니다.","color":"red"}
|
|
||||||
execute if score result func.temp matches 1 run return 0
|
|
||||||
|
|
||||||
data modify storage func:temp num_list set value []
|
|
||||||
data modify storage func:temp index set value 0
|
|
||||||
data modify storage func:temp index_next set value 1
|
|
||||||
|
|
||||||
function func:num_list/f1 with storage func:temp
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
$data modify storage func:temp space.text set string storage func:temp text $(index) $(index_next)
|
|
||||||
execute store result score result func.temp run function func:is_space with storage func:temp space
|
|
||||||
|
|
||||||
$execute if score result func.temp matches 0 run data modify storage func:temp num_list append value $(index)
|
|
||||||
|
|
||||||
function func:plus {name:"index",plus:1}
|
|
||||||
function func:plus {name:"index_next",plus:1}
|
|
||||||
|
|
||||||
execute store result score result func.temp run function func:comp_num {n1:"index",n2:"length"}
|
|
||||||
execute if score result func.temp matches 1 run return 1
|
|
||||||
|
|
||||||
function func:num_list/f1 with storage func:temp
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
scoreboard objectives add func.temp dummy
|
|
||||||
|
|
||||||
$execute store result score temp func.temp run data get storage func:temp $(name)
|
|
||||||
|
|
||||||
$scoreboard players add temp func.temp $(plus)
|
|
||||||
|
|
||||||
$execute store result storage func:temp $(name) int 1 run scoreboard players get temp func.temp
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
scoreboard objectives add func.temp dummy
|
|
||||||
|
|
||||||
data modify storage func:temp shuffle.result set value []
|
|
||||||
|
|
||||||
$data modify storage func:temp shuffle.list set from storage func:temp $(list)
|
|
||||||
|
|
||||||
execute store result score length func.temp run data get storage func:temp shuffle.list
|
|
||||||
|
|
||||||
function func:shuffle/f1
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
execute store result score length func.temp run data get storage func:temp shuffle.list
|
|
||||||
|
|
||||||
execute if score length func.temp matches 0 run return 1
|
|
||||||
|
|
||||||
execute store result score random func.temp run random value 0..2147483646
|
|
||||||
scoreboard players operation random func.temp %= length func.temp
|
|
||||||
|
|
||||||
execute run function func:shuffle/f2 with storage func:temp {index:0}
|
|
||||||
|
|
||||||
execute store result storage func:temp shuffle.index int 1 run scoreboard players get random func.temp
|
|
||||||
function func:shuffle/f2 with storage func:temp shuffle
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
$data modify storage func:temp shuffle.result append from storage func:temp shuffle.list[$(index)]
|
|
||||||
$data remove storage func:temp shuffle.list[$(index)]
|
|
||||||
|
|
||||||
function func:shuffle/f1
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
data modify storage func:temp space.space set value " "
|
|
||||||
data modify storage func:temp zero set value 0
|
|
||||||
$data modify storage func:temp length set value $(length)
|
|
||||||
|
|
||||||
execute store result score result func.temp run function func:comp_num {n1:"zero",n2:"length"}
|
|
||||||
execute if score result func.temp matches 1 run tellraw @s {"text":"length는 1이상 이어야 합니다.","color":"red"}
|
|
||||||
execute if score result func.temp matches 1 run return 0
|
|
||||||
|
|
||||||
data modify storage func:temp text_list set value []
|
|
||||||
data modify storage func:temp index set value 0
|
|
||||||
data modify storage func:temp index_next set value 1
|
|
||||||
|
|
||||||
function func:text_list/f1 with storage func:temp
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
$data modify storage func:temp space.text set string storage func:temp text $(index) $(index_next)
|
|
||||||
execute store result score result func.temp run function func:is_space with storage func:temp space
|
|
||||||
|
|
||||||
$execute store result score result2 func.temp run function func:is_index {l1:"half",l2:"result",index:$(index)}
|
|
||||||
|
|
||||||
execute if score result2 func.temp matches 0 if score result func.temp matches 0 run data modify storage func:temp text_list append value "■"
|
|
||||||
execute if score result2 func.temp matches 0 if score result func.temp matches 1 run data modify storage func:temp text_list append from storage func:temp space.text
|
|
||||||
execute if score result2 func.temp matches 1 run data modify storage func:temp text_list append from storage func:temp space.text
|
|
||||||
|
|
||||||
function func:plus {name:"index",plus:1}
|
|
||||||
function func:plus {name:"index_next",plus:1}
|
|
||||||
|
|
||||||
execute store result score result func.temp run function func:comp_num {n1:"index",n2:"length"}
|
|
||||||
execute if score result func.temp matches 1 run return 1
|
|
||||||
|
|
||||||
function func:text_list/f1 with storage func:temp
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"values": [
|
|
||||||
"mq:load"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"values": [
|
|
||||||
"mq:tick"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"criteria": {
|
|
||||||
"placed_something": {
|
|
||||||
"trigger": "minecraft:impossible",
|
|
||||||
"conditions": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rewards": {
|
|
||||||
"function": "mq:players/login"
|
|
||||||
},
|
|
||||||
"parent": "minecraft:story/root",
|
|
||||||
"display": {
|
|
||||||
"icon": {
|
|
||||||
"id": "minecraft:stone"
|
|
||||||
},
|
|
||||||
"title": "로그인 감지",
|
|
||||||
"description": "서버 접속을 감지",
|
|
||||||
"hidden": false,
|
|
||||||
"announce_to_chat": true,
|
|
||||||
"show_toast": true,
|
|
||||||
"frame": "task"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "minecraft:confirmation",
|
|
||||||
"title": {
|
|
||||||
"text": "음악퀴즈",
|
|
||||||
"bold": true
|
|
||||||
},
|
|
||||||
"body": [
|
|
||||||
{
|
|
||||||
"type": "minecraft:plain_message",
|
|
||||||
"contents": {
|
|
||||||
"text": "음악퀴즈 설명",
|
|
||||||
"bold": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "minecraft:plain_message",
|
|
||||||
"contents": {
|
|
||||||
"text": "\n1. 정답입력시에 채팅으로 입력해주시면 됩니다.\n[ 띄어쓰기, 영어 대소문자, 특수문자 ]\n상관없이 입력하셔도 인식 됩니다.\n\n2. 모든 소리는 날씨 소리로 조절할수 있습니다.\n\n3. 게임시작후 버튼들은 과반수(절반이상)가 눌러야 작동합니다.\n\n4. 힌트는 특수문자 제외 정답의 절반이 가려져서 나옵니다.\n힌트는 여러번 받을수 있고,\n받을때마다 가려지는 부분이 달라집니다."
|
|
||||||
},
|
|
||||||
"width": 300
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"inputs": [],
|
|
||||||
"can_close_with_escape": true,
|
|
||||||
"pause": false,
|
|
||||||
"after_action": "close",
|
|
||||||
"yes": {
|
|
||||||
"label": {
|
|
||||||
"text": "취소",
|
|
||||||
"type": "text"
|
|
||||||
},
|
|
||||||
"action": {
|
|
||||||
"type": "minecraft:run_command",
|
|
||||||
"command": "trigger cancel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"no": {
|
|
||||||
"label": {
|
|
||||||
"text": "다음 페이지 ->"
|
|
||||||
},
|
|
||||||
"action": {
|
|
||||||
"type": "minecraft:show_dialog",
|
|
||||||
"dialog": "mq:page2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "minecraft:confirmation",
|
|
||||||
"title": {
|
|
||||||
"text": "음악퀴즈",
|
|
||||||
"bold": true
|
|
||||||
},
|
|
||||||
"body": [
|
|
||||||
{
|
|
||||||
"type": "minecraft:plain_message",
|
|
||||||
"contents": {
|
|
||||||
"text": "음악퀴즈 설명",
|
|
||||||
"bold": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "minecraft:plain_message",
|
|
||||||
"contents": {
|
|
||||||
"text": "\n5. 다시듣기는 노래가 끝까지 다 재생되었거나,\n다시 처음부분부터 들어보고싶을때\n누르면 좋습니다.\n\n6. 뒤에있는 \"소리 테스트\" 버튼으로\n미리 소리크기를 들어보고 조절할수있습니다."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"inputs": [],
|
|
||||||
"can_close_with_escape": true,
|
|
||||||
"pause": false,
|
|
||||||
"after_action": "close",
|
|
||||||
"yes": {
|
|
||||||
"label": {
|
|
||||||
"text": "<- 이전 페이지",
|
|
||||||
"type": "text"
|
|
||||||
},
|
|
||||||
"action": {
|
|
||||||
"type": "minecraft:show_dialog",
|
|
||||||
"dialog": "mq:page1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"no": {
|
|
||||||
"label": {
|
|
||||||
"text": "다음 페이지 ->"
|
|
||||||
},
|
|
||||||
"action": {
|
|
||||||
"type": "minecraft:show_dialog",
|
|
||||||
"dialog": "mq:page3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "minecraft:confirmation",
|
|
||||||
"title": {
|
|
||||||
"text": "음악퀴즈",
|
|
||||||
"bold": true
|
|
||||||
},
|
|
||||||
"body": [
|
|
||||||
{
|
|
||||||
"type": "minecraft:plain_message",
|
|
||||||
"contents": {
|
|
||||||
"text": "음악퀴즈 설명",
|
|
||||||
"bold": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "minecraft:plain_message",
|
|
||||||
"contents": {
|
|
||||||
"text": "\n재미있게 즐겨주세요."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"inputs": [],
|
|
||||||
"can_close_with_escape": true,
|
|
||||||
"pause": false,
|
|
||||||
"after_action": "close",
|
|
||||||
"yes": {
|
|
||||||
"label": {
|
|
||||||
"text": "<- 이전 페이지",
|
|
||||||
"type": "text"
|
|
||||||
},
|
|
||||||
"action": {
|
|
||||||
"type": "minecraft:show_dialog",
|
|
||||||
"dialog": "mq:page2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"no": {
|
|
||||||
"label": {
|
|
||||||
"text": "준비완료",
|
|
||||||
"bold": true
|
|
||||||
},
|
|
||||||
"action": {
|
|
||||||
"type": "minecraft:run_command",
|
|
||||||
"command": "trigger ready"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
scoreboard players reset @a hint
|
|
||||||
|
|
||||||
execute if score init main matches 0 run return run function mq:tellraw {"text":"아직 퀴즈가 시작되지 않았습니다.","color":"red",msg:'""'}
|
|
||||||
execute if score init main matches 1..4 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 5 run data modify storage mq:main hint.text set from storage mq:main answer.title
|
|
||||||
execute if score init main matches 5 run data modify storage mq:main hint.hint set value ""
|
|
||||||
execute if score init main matches 5 run function func:hint with storage mq:main hint
|
|
||||||
execute if score init main matches 5 run data modify storage mq:main hint.hint set from storage func:temp join.text
|
|
||||||
execute if score init main matches 5 run function mq:tellraw {"text":"","color":"black",msg:'""'}
|
|
||||||
execute if score init main matches 5 run function mq:tellraw {"text":"","color":"black",msg:[{"text":"힌트: ","color":"aqua","bold":true},{"storage":"mq:main","nbt":"hint.hint","color": "yellow","bold": true}]}
|
|
||||||
execute if score init main matches 5 run function mq:tellraw {"text":"","color":"black",msg:'""'}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
scoreboard players reset @a replay
|
|
||||||
|
|
||||||
execute if score init main matches 0 run return run function mq:tellraw {"text":"아직 퀴즈가 시작되지 않았습니다.","color":"red",msg:'""'}
|
|
||||||
execute if score init main matches 1..4 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 5 run function mq:quiz/stop_sound
|
|
||||||
execute if score init main matches 5 run function mq:quiz/play_sound
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
scoreboard players reset @a skip
|
|
||||||
|
|
||||||
execute if score init main matches 0 run return run function mq:tellraw {"text":"아직 퀴즈가 시작되지 않았습니다.","color":"red",msg:'""'}
|
|
||||||
execute if score init main matches 1..4 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 5 run scoreboard players set skip buttons -2
|
|
||||||
execute if score init main matches 5 run function mq:quiz/correct
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
execute if score init main matches 10 run return run function mq:tellraw {"text":"퀴즈가 완전히 종료된후 시작해주세요.","color":"red","msg":""}
|
|
||||||
|
|
||||||
setblock ~ ~ ~ minecraft:air
|
|
||||||
|
|
||||||
function mq:quiz/stop_sound
|
|
||||||
|
|
||||||
$scoreboard players set max_index main $(max_index)
|
|
||||||
scoreboard players set init main 1
|
|
||||||
|
|
||||||
dialog show @a mq:page1
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
scoreboard players set index main 0
|
|
||||||
$scoreboard players set max_index main $(max_index)
|
|
||||||
scoreboard players set score main 0
|
|
||||||
scoreboard players set init main 0
|
|
||||||
scoreboard players set timer main 0
|
|
||||||
|
|
||||||
scoreboard players set start buttons -1
|
|
||||||
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 test buttons -1
|
|
||||||
|
|
||||||
scoreboard players reset @a answer
|
|
||||||
|
|
||||||
# 트리거 시작
|
|
||||||
scoreboard objectives remove ready
|
|
||||||
scoreboard objectives add ready trigger
|
|
||||||
|
|
||||||
scoreboard objectives remove cancel
|
|
||||||
scoreboard objectives add cancel trigger
|
|
||||||
|
|
||||||
scoreboard objectives remove stop
|
|
||||||
scoreboard objectives add stop trigger
|
|
||||||
|
|
||||||
scoreboard objectives remove skip
|
|
||||||
scoreboard objectives add skip trigger
|
|
||||||
|
|
||||||
scoreboard objectives remove hint
|
|
||||||
scoreboard objectives add hint trigger
|
|
||||||
|
|
||||||
scoreboard objectives remove replay
|
|
||||||
scoreboard objectives add replay trigger
|
|
||||||
# 트리거 끝
|
|
||||||
|
|
||||||
scoreboard objectives setdisplay sidebar
|
|
||||||
scoreboard objectives remove score
|
|
||||||
scoreboard objectives add score dummy {"text":"점수","bold":true}
|
|
||||||
scoreboard objectives setdisplay sidebar score
|
|
||||||
|
|
||||||
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 max $(max_index)
|
|
||||||
bossbar set mq:process value 0
|
|
||||||
bossbar set mq:process color pink
|
|
||||||
bossbar set mq:process visible false
|
|
||||||
bossbar set mq:process style notched_10
|
|
||||||
bossbar set mq:process players @a
|
|
||||||
|
|
||||||
# 대기 상태 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
|
|
||||||
|
|
||||||
function mq:quiz/stop_sound
|
|
||||||
function mq:images/clear
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
stopsound @a block minecraft:block.stone_button.click_on
|
|
||||||
function mq:tellraw {"text":"띵!!!","color":"white","msg":'""'}
|
|
||||||
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
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
kill @e[type=minecraft:painting,tag=mq_cover]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
$summon minecraft:painting $(x) $(y) $(z) {variant:"$(namespace):$(cover)",facing:$(facing)b,Tags:["mq","mq_cover"]}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
data modify storage mq:main button_defs set value []
|
|
||||||
data modify storage mq:main button_defs append value {n:"start", x:140, y:62, z:-225, f:"south", c:"function mq:commands/start with storage mq:main"}
|
|
||||||
data modify storage mq:main button_defs append value {n:"stop", x:142, y:62, z:-225, f:"south", c:"function mq:commands/stop with storage mq:main"}
|
|
||||||
data modify storage mq:main button_defs append value {n:"skip", x:144, y:62, z:-225, f:"south", c:"function mq:commands/skip"}
|
|
||||||
data modify storage mq:main button_defs append value {n:"hint", x:146, y:62, z:-225, f:"south", c:"function mq:commands/hint"}
|
|
||||||
data modify storage mq:main button_defs append value {n:"replay", x:148, y:62, z:-225, f:"south", c:"function mq:commands/replay"}
|
|
||||||
data modify storage mq:main button_defs append value {n:"test", x:144, y:62, z:-213, f:"north", c:"function mq:commands/test"}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# 음악퀴즈 주제 — tellraw 접두사([ 이름 ])와 사이드바 표시에 사용
|
|
||||||
data modify storage mq:main title set value "음악퀴즈"
|
|
||||||
|
|
||||||
# 플레이어 접속 시 텔레포트 위치 (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}
|
|
||||||
|
|
||||||
# 음원 재생 — 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 의 길이로 자동 계산됨
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
data modify storage mq:main trigger_defs set value []
|
|
||||||
data modify storage mq:main trigger_defs append value {n:"stop", n2:"중지", c:"function mq:commands/stop with storage mq:main"}
|
|
||||||
data modify storage mq:main trigger_defs append value {n:"skip", n2:"스킵", c:"function mq:commands/skip"}
|
|
||||||
data modify storage mq:main trigger_defs append value {n:"hint", n2:"힌트", c:"function mq:commands/hint"}
|
|
||||||
data modify storage mq:main trigger_defs append value {n:"replay", n2:"다시재생", c:"function mq:commands/replay"}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
data modify storage mq:main answer set value {title:"", author:"", alias:[]}
|
|
||||||
data merge storage func:temp {}
|
|
||||||
data merge storage mq:tmp {}
|
|
||||||
|
|
||||||
function mq:init/config
|
|
||||||
function mq:init/songs
|
|
||||||
function mq:init/buttons
|
|
||||||
function mq:init/triggers
|
|
||||||
|
|
||||||
function mq:tellraw {"text":"서버 리로드 성공!","color":"white","msg":'""'}
|
|
||||||
|
|
||||||
scoreboard objectives remove func.temp
|
|
||||||
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 main dummy
|
|
||||||
scoreboard objectives add buttons dummy
|
|
||||||
scoreboard objectives add answer dummy
|
|
||||||
scoreboard objectives add leave_game custom:leave_game
|
|
||||||
|
|
||||||
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}]
|
|
||||||
|
|
||||||
function mq:commands/stop with storage mq:main
|
|
||||||
function mq:players/login with storage mq:main spawn
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
tag @s add player
|
|
||||||
scoreboard players reset @s leave_game
|
|
||||||
|
|
||||||
title @s times 10t 80t 10t
|
|
||||||
title @s subtitle ""
|
|
||||||
title @s title ""
|
|
||||||
|
|
||||||
$setworldspawn $(x) $(y) $(z) $(r) $(f)
|
|
||||||
$tp @s $(x) $(y) $(z) $(r) $(f)
|
|
||||||
gamemode adventure @s
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
scoreboard players set init main 6
|
|
||||||
|
|
||||||
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}]}
|
|
||||||
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"}]}
|
|
||||||
function mq:tellraw {"text":"","color":"black","msg":""}
|
|
||||||
|
|
||||||
title @a subtitle [{"text":"정답: ","color": "aqua"},{"storage":"mq:main","nbt":"answer.title","color": "yellow","bold": true}]
|
|
||||||
title @a title {"text":""}
|
|
||||||
|
|
||||||
scoreboard players set @a ready 0
|
|
||||||
scoreboard players set @a stop 0
|
|
||||||
scoreboard players set @a skip 0
|
|
||||||
scoreboard players set @a hint 0
|
|
||||||
scoreboard players set @a replay 0
|
|
||||||
|
|
||||||
execute if score skip buttons matches -2 run scoreboard players add 스킵 score 1
|
|
||||||
execute unless score skip buttons matches -2 run scoreboard players add @s score 1
|
|
||||||
|
|
||||||
scoreboard players set stop buttons -3
|
|
||||||
scoreboard players set skip buttons -3
|
|
||||||
scoreboard players set hint buttons -3
|
|
||||||
scoreboard players set replay buttons -3
|
|
||||||
|
|
||||||
scoreboard players set timer main 1
|
|
||||||
|
|
||||||
function mq:images/show
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
scoreboard players set init main 10
|
|
||||||
|
|
||||||
scoreboard players set timer main 1
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
$execute as @a at @s run playsound $(namespace):$(track) $(source) @s ~ ~ ~ $(volume) $(pitch)
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
$data modify storage mq:main answer set from storage mq:main songs[$(idx)]
|
|
||||||
$data modify storage mq:main answer.track set value "track_$(pad)$(num)"
|
|
||||||
$data modify storage mq:main answer.cover set value "cover_$(pad)$(num)"
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
$stopsound @a $(source)
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
$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: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:"정답입력종료"}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
$summon minecraft:marker $(x) $(y) $(z) {Tags:["mq","default"],CustomName:"$(name)"}
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,20 +0,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
|
|
||||||
|
|
||||||
scoreboard players add index main 1
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
# 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
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# 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/play_sound
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
scoreboard players set init main 2
|
|
||||||
|
|
||||||
scoreboard players set index main 0
|
|
||||||
bossbar set mq:process visible true
|
|
||||||
|
|
||||||
scoreboard players set timer main 1
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
function mq:quiz/macro/stop_sound with storage mq:main audio
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
$execute if score $(n) buttons matches ..-2 run setblock $(x) $(y) $(z) minecraft:air
|
|
||||||
$execute if score $(n) buttons matches ..-2 run data modify entity @e[type=minecraft:interaction,tag=mq,tag=$(n),limit=1] response set value 0b
|
|
||||||
$execute if score $(n) buttons matches ..-2 run return 0
|
|
||||||
$execute unless score $(n) buttons matches -1.. run scoreboard players set $(n) buttons -1
|
|
||||||
$execute if score $(n) buttons matches -1 run setblock $(x) $(y) $(z) minecraft:stone_button[face=wall,facing=$(f),powered=false]
|
|
||||||
$execute if score $(n) buttons matches -1 positioned $(x) $(y) $(z) run setblock ~ ~-3 ~ minecraft:redstone_block
|
|
||||||
$execute if score $(n) buttons matches -1 positioned $(x) $(y) $(z) run setblock ~ ~-3 ~ minecraft:red_wool
|
|
||||||
$execute if score $(n) buttons matches -1 run scoreboard players set $(n) buttons 0
|
|
||||||
|
|
||||||
$execute if block $(x) $(y) $(z) minecraft:stone_button[face=wall,facing=$(f),powered=true] \
|
|
||||||
if score $(n) buttons matches 0 \
|
|
||||||
run scoreboard players set $(n) buttons 1
|
|
||||||
|
|
||||||
$execute if score $(n) buttons matches 1 unless entity @e[type=minecraft:interaction,tag=mq,tag=$(n),limit=1] positioned $(x) $(y) $(z) run $(c)
|
|
||||||
|
|
||||||
$execute if score $(n) buttons matches 1 \
|
|
||||||
run scoreboard players set $(n) buttons 2
|
|
||||||
|
|
||||||
$execute if block $(x) $(y) $(z) minecraft:stone_button[face=wall,facing=$(f),powered=false] \
|
|
||||||
if score $(n) buttons matches 1.. \
|
|
||||||
run scoreboard players set $(n) buttons 0
|
|
||||||
|
|
||||||
$execute as @e[type=minecraft:interaction,tag=mq,tag=$(n),limit=1] on target as @s positioned $(x) $(y) $(z) run playsound minecraft:block.stone_button.click_on block @s ~ ~ ~ 1 1
|
|
||||||
$execute as @e[type=minecraft:interaction,tag=mq,tag=$(n),limit=1] on target as @s positioned $(x) $(y) $(z) if score init main matches 0 run $(c)
|
|
||||||
$execute as @e[type=minecraft:interaction,tag=mq,tag=$(n),limit=1] on target as @s positioned $(x) $(y) $(z) unless score init main matches 0 run trigger $(n)
|
|
||||||
|
|
||||||
$execute as @e[type=minecraft:interaction,tag=mq,tag=$(n)] at @s run data remove entity @s attack
|
|
||||||
$execute as @e[type=minecraft:interaction,tag=mq,tag=$(n)] at @s run data remove entity @s interaction
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
function mq:repeat/buttons/btn with storage mq:main button_defs[0]
|
|
||||||
function mq:repeat/buttons/btn with storage mq:main button_defs[1]
|
|
||||||
function mq:repeat/buttons/btn with storage mq:main button_defs[2]
|
|
||||||
function mq:repeat/buttons/btn with storage mq:main button_defs[3]
|
|
||||||
function mq:repeat/buttons/btn with storage mq:main button_defs[4]
|
|
||||||
function mq:repeat/buttons/btn with storage mq:main button_defs[5]
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
execute as @a[scores={answer=1}] run function mq:quiz/correct with storage mq:main answer
|
|
||||||
execute as @a[scores={answer=2}] run scoreboard players reset @a answer
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
execute as @a[tag=!player] run function mq:players/login with storage mq:main spawn
|
|
||||||
execute as @a if score @s leave_game matches 1.. run function mq:players/login with storage mq:main spawn
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
execute if score timer main matches 1.. run scoreboard players add timer main 1
|
|
||||||
|
|
||||||
execute unless score init main matches 2 \
|
|
||||||
unless score init main matches 6 \
|
|
||||||
unless score init main matches 10 \
|
|
||||||
run scoreboard players set timer main 0
|
|
||||||
|
|
||||||
# start title timer
|
|
||||||
execute if score init main matches 2 if score timer main matches 20 run title @a title {"text":"3"}
|
|
||||||
execute if score init main matches 2 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 init main matches 2 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 init main matches 2 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 init main matches 2 if score timer main matches 40 run title @a title {"text":"2"}
|
|
||||||
execute if score init main matches 2 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 init main matches 2 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 init main matches 2 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 init main matches 2 if score timer main matches 60 run title @a title {"text":"1"}
|
|
||||||
execute if score init main matches 2 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 init main matches 2 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 init main matches 2 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 init main matches 2 if score timer main matches 100 run title @a title {"text":""}
|
|
||||||
execute if score init main matches 2 if score timer main matches 100.. run function mq:quiz/select with storage mq:main
|
|
||||||
|
|
||||||
# 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/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
|
|
||||||
execute if score init main matches 10 if score timer main matches 60 run function mq:tellraw {"text":"퀴즈가 종료되었습니다.","color":"white","msg":""}
|
|
||||||
execute if score init main matches 10 if score timer main matches 60 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
|
|
||||||
execute if score init main matches 10 if score timer main matches 60 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
|
|
||||||
execute if score init main matches 10 if score timer main matches 60 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
|
|
||||||
|
|
||||||
execute if score init main matches 10 if score timer main matches 180 run function mq:tellraw {"text":"퀴즈를 다시 시작하시려면 종료를 눌러주세요.","color":"white","msg":""}
|
|
||||||
execute if score init main matches 10 if score timer main matches 120 as @a at @s run scoreboard players set stop buttons -1
|
|
||||||
execute if score init main matches 10 if score timer main matches 120 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
|
|
||||||
execute if score init main matches 10 if score timer main matches 120 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
|
|
||||||
execute if score init main matches 10 if score timer main matches 120 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
|
|
||||||
|
|
||||||
execute if score init main matches 10 if score timer main matches 120 run function mq:tellraw {"text":"플레이 해주셔서 감사합니다.","color":"white","msg":""}
|
|
||||||
execute if score init main matches 10 if score timer main matches 180 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
|
|
||||||
execute if score init main matches 10 if score timer main matches 180 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
|
|
||||||
execute if score init main matches 10 if score timer main matches 180 as @a at @s run playsound minecraft:ui.button.click weather @s ~ ~ ~ 1 1
|
|
||||||
|
|
||||||
execute if score init main matches 10 if score timer main matches 200.. run scoreboard players set init main 11
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
execute if score init main matches 0..1 run scoreboard players enable @a ready
|
|
||||||
execute if score init main matches 0..1 as @a if score @s ready matches 1 run function mq:tellraw {"text":"","color":"black",msg:[{"selector":"@s","color": "yellow","bold": true},{"text":" : ","color":"gray"},{"text":"준비완료","color":"white"}]}
|
|
||||||
execute if score init main matches 0..1 as @a if score @s ready matches 1 run scoreboard players set @s ready 2
|
|
||||||
execute if score init main matches 0..1 as @a if score @s ready matches 3 run function mq:tellraw {"text":"","color":"black",msg:[{"selector":"@s","color": "yellow","bold": true},{"text":" : ","color":"gray"},{"text":"이미 준비완료 상태입니다.","color": "red"}]}
|
|
||||||
execute if score init main matches 0..1 as @a if score @s ready matches 3 run scoreboard players set @s ready 2
|
|
||||||
|
|
||||||
|
|
||||||
execute if score init main matches 0..1 run scoreboard players enable @a cancel
|
|
||||||
execute if score init main matches 0..1 as @a if score @s cancel matches 1 run function mq:tellraw {"text":"","color":"black",msg:[{"selector":"@s","color": "yellow","bold": true},{"text":" : ","color":"gray"},{"text":"취소를 선택하셨습니다.","color": "red"}]}
|
|
||||||
execute if score init main matches 0..1 as @a if score @s cancel matches 1 run function mq:commands/stop with storage mq:main
|
|
||||||
|
|
||||||
|
|
||||||
execute if score init main matches 0..1 store result score max_player ready if entity @a
|
|
||||||
execute if score init main matches 0..1 store result score ready_player ready if entity @a[scores={ready=2..}]
|
|
||||||
execute if score init main matches 0..1 \
|
|
||||||
unless score max_player ready matches 0 \
|
|
||||||
if score max_player ready = ready_player ready \
|
|
||||||
run function mq:quiz/start with storage mq:main
|
|
||||||
|
|
||||||
|
|
||||||
function mq:repeat/triggers/trigger with storage mq:main trigger_defs[0]
|
|
||||||
function mq:repeat/triggers/trigger with storage mq:main trigger_defs[1]
|
|
||||||
function mq:repeat/triggers/trigger with storage mq:main trigger_defs[2]
|
|
||||||
function mq:repeat/triggers/trigger with storage mq:main trigger_defs[3]
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
$scoreboard players enable @a $(n)
|
|
||||||
|
|
||||||
$execute unless score init main matches 5 as @a if score @s $(n) matches 1.. run scoreboard players reset @s $(n)
|
|
||||||
execute unless score init main matches 5 run return 0
|
|
||||||
|
|
||||||
$execute store result score real_max_player $(n) if entity @a
|
|
||||||
|
|
||||||
$execute store result score rest_player $(n) if entity @a
|
|
||||||
$execute unless score rest_player $(n) matches 0 run scoreboard players operation rest_player $(n) %= two func.temp
|
|
||||||
$execute store result score max_player $(n) if entity @a
|
|
||||||
$execute unless score real_max_player $(n) matches 0 run scoreboard players operation max_player $(n) /= two func.temp
|
|
||||||
$execute unless score real_max_player $(n) matches 0 run scoreboard players operation max_player $(n) += rest_player $(n)
|
|
||||||
$execute store result score $(n)_player $(n) if entity @a[scores={$(n)=2..}]
|
|
||||||
$execute store result score $(n)_player_add $(n) if entity @a[scores={$(n)=2..}]
|
|
||||||
$execute run scoreboard players add $(n)_player_add $(n) 1
|
|
||||||
|
|
||||||
$execute as @a if score @s $(n) matches 1 run function mq:tellraw {"text":"","color":"black",msg:[{"selector":"@s","color": "yellow","bold": true}," : ",{"text":"$(n2) 투표 완료","color": "white"}, \
|
|
||||||
{"text":" (","color":"gray"},{"score":{"name":"$(n)_player_add","objective": "$(n)"},"color":"gray"},{"text":"/","color":"gray"},{"score":{"name":"max_player","objective": "$(n)"},"color":"gray"},{"text":")","color":"gray"}]}
|
|
||||||
$execute as @a if score @s $(n) matches 1 run scoreboard players set @s $(n) 2
|
|
||||||
$execute as @a if score @s $(n) matches 3 run function mq:tellraw {"text":"","color":"black",msg:[{"selector":"@s","color": "yellow","bold": true}," : ",{"text":"이미 $(n2)투표를 하셨습니다.","color": "red"}]}
|
|
||||||
$execute as @a if score @s $(n) matches 3 run scoreboard players set @s $(n) 2
|
|
||||||
|
|
||||||
$execute store result score $(n)_player $(n) if entity @a[scores={$(n)=2..}]
|
|
||||||
|
|
||||||
$execute unless score real_max_player $(n) matches 0 \
|
|
||||||
if score max_player $(n) = $(n)_player $(n) \
|
|
||||||
run $(c)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
$tellraw @a ["",{"text":"[ ","bold":true,"color":"gray"},{"storage":"mq:main","nbt":"title","bold":true,"color":"dark_green"},{"text":" ]","bold":true,"color":"gray"},{"text":" "},{"text":"$(text)","color":"$(color)"},$(msg)]
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
function mq:repeat/players
|
|
||||||
function mq:repeat/buttons/handler
|
|
||||||
function mq:repeat/triggers/handler
|
|
||||||
|
|
||||||
execute if score init main matches 2.. run function mq:repeat/timer
|
|
||||||
execute if score init main matches 5..6 run function mq:repeat/check_answer
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"pack": {
|
|
||||||
"pack_format": 75,
|
|
||||||
"description": "음악퀴즈용 데이터팩입니다."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -136,9 +136,12 @@
|
|||||||
"pickedNone": "선택된 음악퀴즈 없음",
|
"pickedNone": "선택된 음악퀴즈 없음",
|
||||||
"pickedLabel": "선택: {{name}}",
|
"pickedLabel": "선택: {{name}}",
|
||||||
"totalCount": "총 {{count}}개의 음악을 찾았습니다.",
|
"totalCount": "총 {{count}}개의 음악을 찾았습니다.",
|
||||||
"export": "데이터팩 zip 다운로드",
|
"hint": "music_quiz 데이터팩의 data/mq/function/init/songs.mcfunction 파일에 아래 코드를 그대로 덮어쓰세요.",
|
||||||
"exporting": "다운로드 준비 중…",
|
"export": "코드 출력",
|
||||||
"exported": "다운로드를 시작했습니다.",
|
"copy": "복사",
|
||||||
|
"copied": "복사됨",
|
||||||
|
"exporting": "출력 중…",
|
||||||
|
"exported": "출력 완료",
|
||||||
"failed": "실패: {{message}}",
|
"failed": "실패: {{message}}",
|
||||||
"modalPickTitle": "음악퀴즈 선택"
|
"modalPickTitle": "음악퀴즈 선택"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,14 +1,5 @@
|
|||||||
import path from 'node:path'
|
|
||||||
import { Readable } from 'node:stream'
|
|
||||||
import archiver from 'archiver'
|
|
||||||
import type { Response } from 'express'
|
|
||||||
import { fileDatapacksDirPath } from '../shared/paths.js'
|
|
||||||
import type { MusicListEntry, PackList } from '../shared/types.js'
|
import type { MusicListEntry, PackList } from '../shared/types.js'
|
||||||
|
|
||||||
/** music_quiz/ 정적 템플릿 디렉터리. (songs.mcfunction 만 동적으로 생성) */
|
|
||||||
const TEMPLATE_DIR = path.join(fileDatapacksDirPath, 'music_quiz_template')
|
|
||||||
const SONGS_PATH_IN_ZIP = 'music_quiz/data/mq/function/init/songs.mcfunction'
|
|
||||||
|
|
||||||
/** SNBT 문자열 리터럴 안에 들어갈 문자열을 escape. */
|
/** SNBT 문자열 리터럴 안에 들어갈 문자열을 escape. */
|
||||||
function escapeSnbtString(input: string): string {
|
function escapeSnbtString(input: string): string {
|
||||||
return input.replace(/\\/g, '\\\\').replace(/"/g, '\\"')
|
return input.replace(/\\/g, '\\\\').replace(/"/g, '\\"')
|
||||||
@@ -30,7 +21,11 @@ function entrySnbt(entry: MusicListEntry): string {
|
|||||||
return `{title:"${title}", author:"${author}", alias:${alias}}`
|
return `{title:"${title}", author:"${author}", alias:${alias}}`
|
||||||
}
|
}
|
||||||
|
|
||||||
/** list.music 으로부터 `data/mq/function/init/songs.mcfunction` 본문을 생성. */
|
/**
|
||||||
|
* list.music 으로부터 `data/mq/function/init/songs.mcfunction` 본문을 생성.
|
||||||
|
* 운영자는 mc_datapack 의 music_quiz 데이터팩에서 이 파일만 이 내용으로
|
||||||
|
* 덮어쓰면 된다 — 나머지 파일은 launcher 가 관여하지 않는다.
|
||||||
|
*/
|
||||||
export function buildSongsMcfunction(list: PackList): string {
|
export function buildSongsMcfunction(list: PackList): string {
|
||||||
const lines: string[] = []
|
const lines: string[] = []
|
||||||
lines.push('# 곡 한 개 = 한 줄.')
|
lines.push('# 곡 한 개 = 한 줄.')
|
||||||
@@ -48,32 +43,3 @@ export function buildSongsMcfunction(list: PackList): string {
|
|||||||
lines.push('execute store result storage mq:main max_index int 1 run data get storage mq:main songs')
|
lines.push('execute store result storage mq:main max_index int 1 run data get storage mq:main songs')
|
||||||
return lines.join('\n') + '\n'
|
return lines.join('\n') + '\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
/** music_quiz 데이터팩 zip 을 Response 로 스트리밍. */
|
|
||||||
export function streamMusicQuizZip(res: Response, packKey: string, list: PackList): void {
|
|
||||||
const fileName = `music_quiz_${packKey}.zip`
|
|
||||||
res.setHeader('Content-Type', 'application/zip')
|
|
||||||
res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`)
|
|
||||||
|
|
||||||
const archive = archiver('zip', { zlib: { level: 9 } })
|
|
||||||
archive.on('warning', (err) => {
|
|
||||||
if (err.code !== 'ENOENT') res.destroy(err)
|
|
||||||
})
|
|
||||||
archive.on('error', (err) => {
|
|
||||||
res.destroy(err)
|
|
||||||
})
|
|
||||||
archive.pipe(res)
|
|
||||||
|
|
||||||
// 정적 템플릿 전체를 music_quiz/ 아래로 묶되 songs.mcfunction 만 제외.
|
|
||||||
archive.glob('**/*', {
|
|
||||||
cwd: TEMPLATE_DIR,
|
|
||||||
dot: false,
|
|
||||||
ignore: ['data/mq/function/init/songs.mcfunction']
|
|
||||||
}, { prefix: 'music_quiz/' })
|
|
||||||
|
|
||||||
// 동적으로 만든 songs.mcfunction 을 추가.
|
|
||||||
const songsText = buildSongsMcfunction(list)
|
|
||||||
archive.append(Readable.from([songsText]), { name: SONGS_PATH_IN_ZIP })
|
|
||||||
|
|
||||||
void archive.finalize()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { fetchPlaylistEntries, fetchVideoMeta, YtDlpUnavailableError } from '../
|
|||||||
import { requireAuth } from '../middleware/auth.js'
|
import { requireAuth } from '../middleware/auth.js'
|
||||||
import type { PackDefinition, PackList } from '../../shared/types.js'
|
import type { PackDefinition, PackList } from '../../shared/types.js'
|
||||||
import { t } from '../i18n.js'
|
import { t } from '../i18n.js'
|
||||||
import { streamMusicQuizZip } from '../datapack.js'
|
import { buildSongsMcfunction } from '../datapack.js'
|
||||||
|
|
||||||
export const opRouter = Router()
|
export const opRouter = Router()
|
||||||
|
|
||||||
@@ -235,8 +235,8 @@ opRouter.get('/op/datapack', requireAuth, async (req, res, next) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 데이터팩 출력: mc_datapack 의 music_quiz/ 템플릿을 zip 으로 묶고,
|
// 데이터팩 출력: list.music 으로부터 init/songs.mcfunction 본문만 만들어
|
||||||
// data/mq/function/init/songs.mcfunction 만 list.music 으로 새로 만들어 덮어쓴다.
|
// text/plain 으로 반환한다. 운영자가 mc_datapack 의 해당 파일에 붙여넣는다.
|
||||||
opRouter.get('/op/datapack/:packName/generate', requireAuth, async (req, res, next) => {
|
opRouter.get('/op/datapack/:packName/generate', requireAuth, async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const packKey = sanitizePackKey(pickFirstValue(req.params.packName))
|
const packKey = sanitizePackKey(pickFirstValue(req.params.packName))
|
||||||
@@ -246,7 +246,7 @@ opRouter.get('/op/datapack/:packName/generate', requireAuth, async (req, res, ne
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const list = await loadPackList(packKey)
|
const list = await loadPackList(packKey)
|
||||||
streamMusicQuizZip(res, packKey, list)
|
res.type('text/plain; charset=utf-8').send(buildSongsMcfunction(list))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error)
|
next(error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<p class="muted"><%= t('datapack.hint') %></p>
|
||||||
|
|
||||||
<section class="dpControls">
|
<section class="dpControls">
|
||||||
<button type="button" class="primaryButton" id="pickPackBtn"><%= t('datapack.pickPack') %></button>
|
<button type="button" class="primaryButton" id="pickPackBtn"><%= t('datapack.pickPack') %></button>
|
||||||
<span class="muted" id="pickedLabel"><%= t('datapack.pickedNone') %></span>
|
<span class="muted" id="pickedLabel"><%= t('datapack.pickedNone') %></span>
|
||||||
@@ -26,8 +28,11 @@
|
|||||||
|
|
||||||
<section class="dpActions" hidden id="dpActions">
|
<section class="dpActions" hidden id="dpActions">
|
||||||
<button type="button" class="secondaryButton" id="exportBtn"><%= t('datapack.export') %></button>
|
<button type="button" class="secondaryButton" id="exportBtn"><%= t('datapack.export') %></button>
|
||||||
|
<button type="button" class="secondaryButton" id="copyBtn"><%= t('datapack.copy') %></button>
|
||||||
<span class="statusText" id="dp-status"></span>
|
<span class="statusText" id="dp-status"></span>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<pre class="codeBlock" id="codeOut" hidden></pre>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- 음악퀴즈 선택 팝업 -->
|
<!-- 음악퀴즈 선택 팝업 -->
|
||||||
@@ -85,16 +90,36 @@
|
|||||||
document.getElementById('dpActions').hidden = false
|
document.getElementById('dpActions').hidden = false
|
||||||
document.getElementById('dp-status').textContent = ''
|
document.getElementById('dp-status').textContent = ''
|
||||||
document.getElementById('dp-status').classList.remove('error')
|
document.getElementById('dp-status').classList.remove('error')
|
||||||
|
document.getElementById('codeOut').hidden = true
|
||||||
|
document.getElementById('codeOut').textContent = ''
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
document.getElementById('exportBtn').addEventListener('click', function () {
|
document.getElementById('exportBtn').addEventListener('click', function () {
|
||||||
if (!pickedKey) return
|
if (!pickedKey) return
|
||||||
var s = document.getElementById('dp-status')
|
var s = document.getElementById('dp-status')
|
||||||
s.textContent = I18N.exporting; s.classList.remove('error')
|
s.textContent = I18N.exporting; s.classList.remove('error')
|
||||||
// zip 다운로드를 트리거하기 위해 location 으로 이동시킨다.
|
fetch('/op/datapack/' + encodeURIComponent(pickedKey) + '/generate')
|
||||||
window.location.href = '/op/datapack/' + encodeURIComponent(pickedKey) + '/generate'
|
.then(function (r) { return r.text().then(function (t) { return { ok: r.ok, text: t } }) })
|
||||||
// 다운로드는 비동기 / 별도 응답이므로 약간의 지연 후 "완료" 표시.
|
.then(function (res) {
|
||||||
setTimeout(function () { s.textContent = I18N.exported }, 500)
|
if (!res.ok) {
|
||||||
|
s.textContent = I18N.failed.replace('{{message}}', res.text); s.classList.add('error')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var out = document.getElementById('codeOut')
|
||||||
|
out.textContent = res.text
|
||||||
|
out.hidden = false
|
||||||
|
s.textContent = I18N.exported
|
||||||
|
})
|
||||||
|
.catch(function (err) { s.textContent = I18N.failed.replace('{{message}}', err.message); s.classList.add('error') })
|
||||||
|
})
|
||||||
|
document.getElementById('copyBtn').addEventListener('click', function () {
|
||||||
|
var out = document.getElementById('codeOut')
|
||||||
|
if (out.hidden) return
|
||||||
|
navigator.clipboard.writeText(out.textContent).then(function () {
|
||||||
|
var s = document.getElementById('dp-status')
|
||||||
|
s.textContent = I18N.copied
|
||||||
|
s.classList.remove('error')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})()
|
})()
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user