마붕이들은 이런 기억이 있을 거임.

만약 다른 엔티티들로 하여금 다른 행동을 하도록 시킬 때, 그런데 그 엔티티들이 어딘가 공통점이 있을 때...

아래의 예시는 엔티티들이 매우 간간간간고등어하게 위협하는 코드임. (아이 물어워라)


execute as @e[type=zombie] run mob:zombie_threat :

say @a 마플 키는 169.9다 크어어어어

execute as @e[type=skeleton] run mob:skeleton_threat :

say @a say @a 마플 키는 169.9다 덜그럭 덜그럭



지금은 두 가지 종류가 전부지만, 프로젝트가 커지면 다른 태그를 가진 엔티티들을 execute if나 execute as로 분리해서 써내려가야하는 매우 간고등어 같은 일이 벌어지게 될 것임.


그냥 execute as @e[tag = <supertype>] run 해서 한 루프 안에 모든 것을 끝낼 수 없을까?


$function $(function)


$function isa:call with storage minecraft:vtable list[$(entityID)][$(vtableID)]


방법이 있음! 위 매크로 두 개만 있으면 된다.

먼저 아래와 같이 초기화를 해 준다.


scoreboard objectives add register dummy

scoreboard objectives add vtableID dummy

scoreboard players set #lastID vtableID 0

data modify storage minecraft:vtable list set value []


그리고 다음과 같이 좀비와, 스켈레톤을 제작해 준다.


summon minecraft:zombie ~ ~ ~ {Tags:["new"]}

execute as @n[tag=new] run scoreboard players set @s entityID 1


execute unless data storage minecraft:vtable list[1] run \

data modify storage minecraft:vtable list append value [{function:"test:zombie_say"}, {function:"test:zombie_death"}]


execute if data storage minecraft:vtable list[1] run \

data modify storage minecraft:vtable list[1] set value [{function:"test:zombie_say"}, {function:"test:zombie_death"}]


execute as @n[tag=new] run tag @s remove new




summon minecraft:skeleton ~ ~ ~ {Tags:["new"]}

execute as @n[tag=new] run scoreboard players set @s entityID 0


execute unless data storage minecraft:vtable list[0] run \

data modify storage minecraft:vtable list append value [{function:"test:skeleton_say"}, {function:"test:skeleton_death"}]


execute if data storage minecraft:vtable list[0] run \

data modify storage minecraft:vtable list[0] set value [{function:"test:skeleton_say"}, {function:"test:skeleton_death"}]


execute as @n[tag=new] run tag @s remove new




여기서 눈치 빠른 사람들은 저 위의 function:"test:skeleton_say"가 함수 이름인 것을 확인했을 거임. 저 값이 매크로를 통해 전달되고 전달되어서 마침내 함수 호출로 이어지게 될 거임.


execute unless score #op0 register matches -2147483648..2147483647 \

run return run say #op0 register 를 설정해 주세요.


execute unless score #op1 register matches -2147483648..2147483647 \

run return run say #op1 register 를 설정해 주세요.


data modify storage minecraft:temp val set value {entityVTableID : -1, vtableID : -1}

execute store result storage minecraft:temp val.entityID int 1 run scoreboard players get #op0 register

execute store result storage minecraft:temp val.vtableID int 1 run scoreboard players get #op1 register


function isa:call_vtable/call_with_table with storage minecraft:temp val


#$function isa:call with storage minecraft:vtable list[$(entityID)][$(vtableID)]


#data remove storage minecraft:temp val

scoreboard players reset #op0 register


값 두 개 (entityID, vtableID)를 받아서 정말 함수를 호출하는 코드까지 짜고 나서


function test:say :

execute unless score @s entityID matches -2147483648..2147483647 run return 1

scoreboard players operation #op0 register = @s entityID

scoreboard players set #op1 register 0

execute as @s run function isa:call_vtable


위와 같은 코드를



24b0d121e09c28a8699fe8b115ef046544a9f5


다음과 같이 실행하면



24b0d121e09c28a8699fe8b115ef046f594e9f9b


이렇게 출력이 된다.

마붕이들도 코드를 적게 수정하면서 많은 기능을 추가하는 생산적인 하루 되길 바란다.

예제 코드는 첨부파일로 올려 놓았으니 씹고 뜯고 맛보고 즐기면 되겠음.


첨부파일
test.zip
파일 다운로드


추가적으로 해당 코드는 엔티티 타입이 2 개만 있다고 가정하고 만든 예싱 데이터팩임... 아마 이걸 프로젝트에 바로 적용하려면 수정을 좀 많이 가해야 할 거임. 관련해서는 나중에 또 글을 올리겠음.


그리고 원리적으로는 엔티티의 ID를 통해서 vtable의 위치를 찾는 것이 아니라, 엔티티의 타입ID를 통해서 vtable의 위치를 찾는 것이 원칙임. (그리고 그걸 프로그래밍 언어에서는 class라고 함. ㅇㅇ 그 클래스 맞음) 해당 변수명이 저 꼴이 된 것은 전적으로 글쓴이의 탓이니 그리 알면 되겠음 (이런 간간간ㄴ간고등어같은)