diff --git a/music_quiz/data/mq/function/commands/start.mcfunction b/music_quiz/data/mq/function/commands/start.mcfunction index ae5cdc1..e76382e 100644 --- a/music_quiz/data/mq/function/commands/start.mcfunction +++ b/music_quiz/data/mq/function/commands/start.mcfunction @@ -38,8 +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 설정 이후 동작 보장. +# 시작 시 1..preload 번 영상 캐시 미리받기(큐 적재). schedule 로 다음 tick 에 +# 실행해 max_index 설정 이후 동작 보장. 실제 다운로드는 drain 이 tick 마다 처리. schedule function mq:videos/cache/preload 1t dialog show @a mq:page1 diff --git a/music_quiz/data/mq/function/tick.mcfunction b/music_quiz/data/mq/function/tick.mcfunction index 724d307..c97243f 100644 --- a/music_quiz/data/mq/function/tick.mcfunction +++ b/music_quiz/data/mq/function/tick.mcfunction @@ -2,6 +2,9 @@ function mq:repeat/players function mq:repeat/buttons/handler function mq:repeat/triggers/handler +# 영상 모드 명령 큐를 매 tick 한 개씩 command_block 으로 실행 +function mq:videos/drain + 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 diff --git a/music_quiz/data/mq/function/videos/cache/add.mcfunction b/music_quiz/data/mq/function/videos/cache/add.mcfunction index b3ace99..8edf143 100644 --- a/music_quiz/data/mq/function/videos/cache/add.mcfunction +++ b/music_quiz/data/mq/function/videos/cache/add.mcfunction @@ -1,12 +1,8 @@ -# 재생 진행에 맞춰 항상 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 +# 라운드 진행 시 preload 윈도우의 맨 앞(index+preload-1) 한 개를 캐시에 추가. +# 시작 preload 와 합쳐 항상 preload 개 버퍼가 굴러간다. +execute store result score cache_lo func.temp run data get storage mq:main video.preload +execute if score cache_lo func.temp matches ..0 run return 0 +scoreboard players operation cache_lo func.temp += index main +scoreboard players remove cache_lo func.temp 1 +scoreboard players operation cache_hi func.temp = cache_lo func.temp +function mq:videos/cache/fill diff --git a/music_quiz/data/mq/function/videos/cache/add_one.mcfunction b/music_quiz/data/mq/function/videos/cache/add_one.mcfunction deleted file mode 100644 index 08b7d4d..0000000 --- a/music_quiz/data/mq/function/videos/cache/add_one.mcfunction +++ /dev/null @@ -1,4 +0,0 @@ -# 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 diff --git a/music_quiz/data/mq/function/videos/cache/clear.mcfunction b/music_quiz/data/mq/function/videos/cache/clear.mcfunction index 4edbb2f..ccf5528 100644 --- a/music_quiz/data/mq/function/videos/cache/clear.mcfunction +++ b/music_quiz/data/mq/function/videos/cache/clear.mcfunction @@ -1,5 +1,5 @@ -# 추적 목록을 비우고, 다음 tick 에 서버 소스로 전체 캐시 wipe. -# (videoCache clear 를 호출자 소스에서 바로 실행하면 player/비OP 소스일 때 -# 권한 문제가 날 수 있어 schedule 로 서버 소스 보장.) +# 추적 목록을 비우고 전체 캐시 wipe 를 큐에 적재 (command_block 으로 실행). data modify storage mq:main video.cached set value [] -schedule function mq:videos/cache/clear_run 1t +data modify storage mq:tmp video set from storage mq:main video +data modify storage mq:tmp video.cmd set value "cache_clear" +function mq:videos/macro/cmd with storage mq:tmp video diff --git a/music_quiz/data/mq/function/videos/cache/clear_run.mcfunction b/music_quiz/data/mq/function/videos/cache/clear_run.mcfunction deleted file mode 100644 index 37bb540..0000000 --- a/music_quiz/data/mq/function/videos/cache/clear_run.mcfunction +++ /dev/null @@ -1 +0,0 @@ -videoCache clear diff --git a/music_quiz/data/mq/function/videos/cache/evict.mcfunction b/music_quiz/data/mq/function/videos/cache/evict.mcfunction index d6a245f..37762d4 100644 --- a/music_quiz/data/mq/function/videos/cache/evict.mcfunction +++ b/music_quiz/data/mq/function/videos/cache/evict.mcfunction @@ -1,4 +1,12 @@ -# 캐시 갯수가 keep 을 넘으면 가장 먼저 받은 것부터(FIFO) 삭제. -execute store result score cache_len func.temp run data get storage mq:main video.cached +# 추적 캐시 갯수가 keep 을 넘으면 가장 먼저 받은 것부터(FIFO) 제거 큐에 적재. +# keep<=0 이면 무제한으로 보고 축출하지 않는다. 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 +execute if score cache_keep func.temp matches ..0 run return 0 +execute store result score cache_len func.temp run data get storage mq:main video.cached +execute if score cache_len func.temp <= cache_keep func.temp run return 0 +data modify storage mq:tmp video set from storage mq:main video +data modify storage mq:tmp video.num set from storage mq:main video.cached[0].i +data modify storage mq:tmp video.cmd set value "cache_remove" +function mq:videos/macro/cmd with storage mq:tmp video +data remove storage mq:main video.cached[0] +function mq:videos/cache/evict diff --git a/music_quiz/data/mq/function/videos/cache/evict_one.mcfunction b/music_quiz/data/mq/function/videos/cache/evict_one.mcfunction deleted file mode 100644 index 8ba4d5d..0000000 --- a/music_quiz/data/mq/function/videos/cache/evict_one.mcfunction +++ /dev/null @@ -1,5 +0,0 @@ -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 diff --git a/music_quiz/data/mq/function/videos/cache/fill.mcfunction b/music_quiz/data/mq/function/videos/cache/fill.mcfunction new file mode 100644 index 0000000..83b9803 --- /dev/null +++ b/music_quiz/data/mq/function/videos/cache/fill.mcfunction @@ -0,0 +1,11 @@ +# cache_lo..cache_hi 범위의 영상을 캐시 큐에 등록한다 (max_index 상한). +# 등록 후 keep 초과분은 FIFO 로 축출. 실제 videoCache add/remove 는 큐를 통해 +# command_block 으로 실행되므로 모드 없이도 로드된다. +execute if score cache_lo func.temp > cache_hi func.temp run return run function mq:videos/cache/evict +execute if score cache_lo func.temp > max_index main run return run function mq:videos/cache/evict +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_lo func.temp +data modify storage mq:tmp video.cmd set value "cache_add" +function mq:videos/macro/cmd with storage mq:tmp video +scoreboard players add cache_lo func.temp 1 +function mq:videos/cache/fill diff --git a/music_quiz/data/mq/function/videos/cache/macro/add_one.mcfunction b/music_quiz/data/mq/function/videos/cache/macro/add_one.mcfunction deleted file mode 100644 index 4cc7a55..0000000 --- a/music_quiz/data/mq/function/videos/cache/macro/add_one.mcfunction +++ /dev/null @@ -1,7 +0,0 @@ -# 이미 받은 영상이면(추적 목록에 {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 diff --git a/music_quiz/data/mq/function/videos/cache/macro/evict_one.mcfunction b/music_quiz/data/mq/function/videos/cache/macro/evict_one.mcfunction deleted file mode 100644 index a5fb796..0000000 --- a/music_quiz/data/mq/function/videos/cache/macro/evict_one.mcfunction +++ /dev/null @@ -1 +0,0 @@ -$videoCache remove video_$(evict_num) diff --git a/music_quiz/data/mq/function/videos/cache/preload.mcfunction b/music_quiz/data/mq/function/videos/cache/preload.mcfunction index 5b9b5bc..ebe87f1 100644 --- a/music_quiz/data/mq/function/videos/cache/preload.mcfunction +++ b/music_quiz/data/mq/function/videos/cache/preload.mcfunction @@ -1,5 +1,6 @@ -# 게임 시작 시 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 +# 게임 시작 시 1번부터 preload 번까지 캐시를 미리 등록한다. +execute store result score cache_lo func.temp run data get storage mq:main video.preload +execute if score cache_lo func.temp matches ..0 run return 0 +scoreboard players operation cache_hi func.temp = cache_lo func.temp +scoreboard players set cache_lo func.temp 1 +function mq:videos/cache/fill diff --git a/music_quiz/data/mq/function/videos/cache/preload_loop.mcfunction b/music_quiz/data/mq/function/videos/cache/preload_loop.mcfunction deleted file mode 100644 index 72e2bc7..0000000 --- a/music_quiz/data/mq/function/videos/cache/preload_loop.mcfunction +++ /dev/null @@ -1,5 +0,0 @@ -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 diff --git a/music_quiz/data/mq/function/videos/clear.mcfunction b/music_quiz/data/mq/function/videos/clear.mcfunction index dd2b16d..7d7c5ce 100644 --- a/music_quiz/data/mq/function/videos/clear.mcfunction +++ b/music_quiz/data/mq/function/videos/clear.mcfunction @@ -1,4 +1,3 @@ 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 diff --git a/music_quiz/data/mq/function/videos/drain.mcfunction b/music_quiz/data/mq/function/videos/drain.mcfunction new file mode 100644 index 0000000..659c76a --- /dev/null +++ b/music_quiz/data/mq/function/videos/drain.mcfunction @@ -0,0 +1,17 @@ +# 매 tick: 큐(mq:main video.cmdq)에 대기 중인 모드 명령을 한 개씩 command_block 으로 +# 실행한다. command_block 은 auto:1b 면 매 tick 재실행되므로(=videoCache add 중복 +# 실패 스팸) 명령을 실행한 다음 tick 에 auto:0b 로 꺼서 1회만 실행되게 한다. +# 한 좌표 블록은 한 tick 에 1회만 켜지므로 큐를 1개씩 소진해 preload·축출 다건도 +# 순서대로 처리된다. +data remove storage mq:tmp fire +execute if data storage mq:main video.cmdq[0] run data modify storage mq:tmp fire set from storage mq:main video +execute if data storage mq:main video.cmdq[0] run data modify storage mq:tmp fire.c set from storage mq:main video.cmdq[0].c + +# 큐에 명령이 있으면 적재·실행하고 armed 표시 후 pop. +execute if data storage mq:tmp fire.c run function mq:videos/macro/drain with storage mq:tmp fire +execute if data storage mq:tmp fire.c run data modify storage mq:main video.armed set value 1b +execute if data storage mq:tmp fire.c run data remove storage mq:main video.cmdq[0] + +# 큐가 비었고 직전에 켠 블록이 있으면 한 번만 꺼서 재실행을 막는다. +execute unless data storage mq:tmp fire.c if data storage mq:main {video:{armed:1b}} run function mq:videos/macro/drain_off with storage mq:main video +execute unless data storage mq:tmp fire.c run data modify storage mq:main video.armed set value 0b diff --git a/music_quiz/data/mq/function/videos/macro/cmd.mcfunction b/music_quiz/data/mq/function/videos/macro/cmd.mcfunction index 3110718..c6dcbec 100644 --- a/music_quiz/data/mq/function/videos/macro/cmd.mcfunction +++ b/music_quiz/data/mq/function/videos/macro/cmd.mcfunction @@ -1,14 +1,16 @@ -$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 +# 모드 명령을 "큐(mq:main video.cmdq)"에 문자열로 적재한다. 실제 실행은 매 tick +# videos/drain 이 command_block 으로 하나씩 처리한다. 데이터팩 로드 시 모드 명령을 +# 직접 파싱하지 않으므로 영상 모드가 없어도 게임이 동작한다. +# delete : videoDelete +# play : videoPlace (캐시 추적중이면 video_N, 아니면 전체 URL) +# cache_add : videoCache add (이미 추적중이면 skip, 아니면 추적목록 append) +# cache_remove : videoCache remove +# cache_clear : videoCache clear +$execute if data storage mq:tmp {video:{cmd:"delete"}} run data modify storage mq:main video.cmdq append value {c:"videoDelete $(x) $(y) $(z)"} +$execute if data storage mq:tmp {video:{cmd:"play"}} if data storage mq:main video.cached[{i:$(num)}] run data modify storage mq:main video.cmdq append value {c:"videoPlace $(x) $(y) $(z) $(facing) $(w) $(h) $(sound) video_$(num)"} +$execute if data storage mq:tmp {video:{cmd:"play"}} unless data storage mq:main video.cached[{i:$(num)}] run data modify storage mq:main video.cmdq append value {c:"videoPlace $(x) $(y) $(z) $(facing) $(w) $(h) $(sound) $(namespace)/$(num)"} +$execute if data storage mq:tmp {video:{cmd:"cache_add"}} if data storage mq:main video.cached[{i:$(num)}] run return 0 +$execute if data storage mq:tmp {video:{cmd:"cache_add"}} run data modify storage mq:main video.cmdq append value {c:"videoCache add video_$(num) $(namespace)/$(num)"} +$execute if data storage mq:tmp {video:{cmd:"cache_add"}} run data modify storage mq:main video.cached append value {i:$(num)} +$execute if data storage mq:tmp {video:{cmd:"cache_remove"}} run data modify storage mq:main video.cmdq append value {c:"videoCache remove video_$(num)"} +$execute if data storage mq:tmp {video:{cmd:"cache_clear"}} run data modify storage mq:main video.cmdq append value {c:"videoCache clear"} diff --git a/music_quiz/data/mq/function/videos/macro/drain.mcfunction b/music_quiz/data/mq/function/videos/macro/drain.mcfunction new file mode 100644 index 0000000..4112f39 --- /dev/null +++ b/music_quiz/data/mq/function/videos/macro/drain.mcfunction @@ -0,0 +1,3 @@ +# 큐에서 꺼낸 명령 1개를 공용 command_block 에 적재 후 auto 0→1 로 실행시킨다. +$setblock $(cmd_x) $(cmd_y) $(cmd_z) minecraft:command_block[conditional=false,facing=up]{Command:"$(c)",auto:0b} +$data modify block $(cmd_x) $(cmd_y) $(cmd_z) auto set value 1b diff --git a/music_quiz/data/mq/function/videos/macro/drain_off.mcfunction b/music_quiz/data/mq/function/videos/macro/drain_off.mcfunction new file mode 100644 index 0000000..6796ccd --- /dev/null +++ b/music_quiz/data/mq/function/videos/macro/drain_off.mcfunction @@ -0,0 +1,2 @@ +# 직전 tick 에 켠 명령 블록을 끈다 (armed 일 때만 호출되므로 블록이 존재함). +$data modify block $(cmd_x) $(cmd_y) $(cmd_z) auto set value 0b diff --git a/music_quiz/data/mq/function/videos/macro/resolve_src.mcfunction b/music_quiz/data/mq/function/videos/macro/resolve_src.mcfunction deleted file mode 100644 index bad9340..0000000 --- a/music_quiz/data/mq/function/videos/macro/resolve_src.mcfunction +++ /dev/null @@ -1,8 +0,0 @@ -# mq:tmp video.src 를 결정한다. -# - 기본: 전체 URL "/" -# - mq:main video.cached 목록에 {i:num} 이 있으면(=videoCache add 로 등록됨) -# 등록 이름 "video_" 사용 → 모드가 서버 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)" diff --git a/music_quiz/data/mq/function/videos/normalize.mcfunction b/music_quiz/data/mq/function/videos/normalize.mcfunction index b9a47b1..38eb706 100644 --- a/music_quiz/data/mq/function/videos/normalize.mcfunction +++ b/music_quiz/data/mq/function/videos/normalize.mcfunction @@ -3,5 +3,7 @@ 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} 리스트) +# 캐시 추적 목록({i:N}), 모드 명령 큐, command_block armed 플래그 초기화. data modify storage mq:main video.cached set value [] +data modify storage mq:main video.cmdq set value [] +data modify storage mq:main video.armed set value 0b diff --git a/music_quiz/data/mq/function/videos/show.mcfunction b/music_quiz/data/mq/function/videos/show.mcfunction index d52af10..4b4907b 100644 --- a/music_quiz/data/mq/function/videos/show.mcfunction +++ b/music_quiz/data/mq/function/videos/show.mcfunction @@ -1,10 +1,6 @@ -# 정답 영상 재생. videoPlace 는 같은 앵커 좌표를 덮어쓰므로 별도 clear 불필요 -# (clear + place 를 한 tick 에 하면 command_block 이 한 번만 켜져 place 가 씹힘). +# 정답 영상 재생을 큐에 적재. videoPlace 는 같은 앵커 좌표를 덮어쓰므로 별도 +# clear 불필요. 캐시 추적중이면 video_N, 아니면 전체 URL 로 macro/cmd 가 결정. 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