零:写在前面
准备工具
VSCode以及DHP插件,或者其他代码工具。
minecraft测试环境,本教程使用minecraft1.20.1原版,其他版本可能有语法差别。
print.net,或其他绘图工具(非必须)。
7zip,或者其他支持压缩的软件。Windows自带的也行
需要了解
数据包的文件夹结构。
json文件格式,mcfunction文件格式。
本文在使用下划线部分可以替换为[0-9,a-z,_]字符的组合,可以自行替换。
一:开始
建立想法
我们假设想要创造的结构为一个水井,在最后放置水时会把水替换为信标,并在信标顶上填充玻璃。
创建文件夹结构
启动一次minecraft,并创建新世界(建议选用创造模式,允许作弊,超平坦,超平坦预设:虚空。)
打开世界文件夹中的datapacks文件夹,在此文件夹新建一个文件夹(教程使用了testdatapack作为名称),右击文件夹,使用vscode打开。
在目录里新建文件pack.mcmeta(数据包描述文件,必须),pack.png(数据包图标,非必须),data文件夹(数据包数据文件夹,必须)。
pack.mcmeta
vscode会使用文本编辑器打开此文件。
在文件内粘贴以下内容,并在正确的地方输入合适的内容。
{ "pack": { "pack_format": 15, "description": [ { "text": "6623" } ] }}其中6623可根据需要替换为介绍。
data文件夹和它的的子文件夹们 (仅列举功能所需的文件夹)
在data文件夹新建文件夹作为命名空间(教程使用了francium6623作为命名空间),在francium6623文件夹下新建下列文件夹:
advancements 定义进度,这里作为触发器。
functions 定义进度,这里作为触发器返回。
predicates 谓词,这里作为判断条件。
tags 标签,用于同时兼容多项。
advancements 此文件夹内文件格式为.json。
在advancements文件夹下新建test.json,粘贴以下内容:
{ "criteria": { "test": { "trigger": "minecraft:placed_block", "conditions": { "location": [ { "condition": "minecraft:reference", "name": "francium6623:test" }, { "condition": "minecraft:match_tool", "predicate": { "items": [ "minecraft:water_bucket" ] } } ] } } }, "rewards": { "function": "francium6623:test" }}带注释部分:(在json中不能写入注释,此处使用#作为注释符号用以解释代码的含义。)
{
"criteria": {
"test": { #此项名称在只有一项时无特殊作用。
"trigger": "minecraft:placed_block", #由于我们检查水桶的放置,使用了 placed_block(放置方块)。
"conditions": {
"location": [
{
"condition": "minecraft:reference", #使用谓词文件作为条件检查。
"name": "francium6623:test" #自定义的谓词名称,将会在下文提到。
},
{
"condition": "minecraft:match_tool", #条件检查 match_tool(使用工具)。
"predicate": {
"items": [
"minecraft:water_bucket" #检查目标物品为水桶。
]
}
}
]
}
}
},
"rewards": {
"function": "francium6623:test" #返回函数,将会在下文提到。
}
}
functions 此文件夹内文件格式为.mcfunction。
在functions文件夹下新建test.mcfunction,粘贴以下内容:
advancement revoke @s only francium6623:testfill ~-6 ~-6 ~-6 ~6 ~6 ~6 command_block{auto:1b,Command:"execute align xyz positioned ~0.5 ~ ~0.5 run function francium6623:test2"} replace water[level=0]带注释部分:(mcfunction文件支持在开头使用#使该行变为注释。)
advancement revoke @s only francium6623:test
#剥夺触发函数的进度,使这个进度能重复触发。fill ~-6 ~-6 ~-6 ~6 ~6 ~6 command_block{auto:1b,Command:"execute align xyz positioned ~0.5 ~ ~0.5 run function francium6623:test2"} replace water[level=0]
#fill ~-6 ~-6 ~-6 ~6 ~6 ~6 command_block replace water[level=0]:将玩家附近13x13x13的水源替换为自动执行的命令方块。
#{auto:1b,Command:"命令"}:自动执行内部命令。
#function francium6623:test2:调用函数执行接下来的命令,在下边介绍。
在functions文件夹下新建test2.mcfunction,粘贴以下内容:
execute if predicate francium6623:test run fill ~ ~1 ~ ~ ~1 ~ minecraft:glass replace #francium6623:can_replaceexecute if predicate francium6623:test run setblock ~ ~ ~ minecraft:beaconexecute unless predicate francium6623:test run setblock ~ ~ ~ water
execute if predicate francium6623:test run fill ~ ~1 ~ ~ ~1~ minecraft:glass replace #francium6623:can_replace
#如果满足谓词条件的话把原位置Y+1的位置标签为#francium6623:can_replace内的方块替换为玻璃。
execute if predicate francium6623:test run setblock ~ ~ ~ minecraft:beacon
#如果满足谓词条件的话把原位置替换为信标。
execute unless predicate francium6623:test run setblock ~ ~ ~ water
#如果不满足谓词条件的话把原位置还原为水。
predicates 此文件夹内文件格式为.json。
在predicates文件夹下新建test.json,粘贴以下内容:
[ { "condition": "all_of", "terms": [ { "condition": "minecraft:location_check", "offsetX": -1, "offsetY": 0, "offsetZ": 0, "predicate": { "block": { "blocks": [ "minecraft:cobblestone" ] } } }, { "condition": "minecraft:location_check", "offsetX": 1, "offsetY": 0, "offsetZ": 0, "predicate": { "block": { "blocks": [ "minecraft:cobblestone" ] } } }, { "condition": "minecraft:location_check", "offsetX": 0, "offsetY": 0, "offsetZ": 1, "predicate": { "block": { "blocks": [ "minecraft:cobblestone" ] } } }, { "condition": "minecraft:location_check", "offsetX": 0, "offsetY": 0, "offsetZ": -1, "predicate": { "block": { "blocks": [ "minecraft:cobblestone" ] } } } ] }]带注释部分:(在json中不能写入注释,此处使用#作为注释符号用以解释代码的含义。)
[
{
"condition": "all_of",
"terms": [
{
"condition": "minecraft:location_check", #条件:位置检查,下同
"offsetX": -1,
"offsetY": 0,
"offsetZ": 0,
"predicate": {
"block": {
"blocks": [
"minecraft:cobblestone" #在相对坐标x,y,z的位置为方块:圆石,下同。
]
}
}
},
{
"condition": "minecraft:location_check",
"offsetX": 1,
"offsetY": 0,
"offsetZ": 0,
"predicate": {
"block": {
"blocks": [
"minecraft:cobblestone"
]
}
}
},
{
"condition": "minecraft:location_check",
"offsetX": 0,
"offsetY": 0,
"offsetZ": 1,
"predicate": {
"block": {
"blocks": [
"minecraft:cobblestone"
]
}
}
},
{
"condition": "minecraft:location_check",
"offsetX": 0,
"offsetY": 0,
"offsetZ": -1,
"predicate": {
"block": {
"blocks": [
"minecraft:cobblestone"
]
}
}
}
]
}
]
这样我们就能检测执行位置方块四周是否都为圆石了。
tags 此文件夹内文件格式为.json。
在tags文件夹下新建blocks文件夹,打开后新建can_replace.json,粘贴以下内容:
{ "replace": false, "values": [ "minecraft:cave_air", "minecraft:air" ]}此文件将air和cave_air加入方块标签#francium6623:can_replace。
二:测试
输入/datapack list刷新数据包列表。
在minecraft中输入/datapack enable "file/testdatapack"来启用数据包。
测试发现当周围水上有睡莲时,睡莲会掉落。
当在世界边界或上下界执行操作时,fill指令超出范围。
为什么?怎么办?
对于fill指令超出范围,我们可以缩小fill之后的参数,但是这样会缩小检测范围。
分析我们的实现过程,我们曾将附近的水替换为命令方块用以检测,但是这一步会损坏水面的睡莲。
我们可以把睡莲也替换为命令方块,但是这样可能产生问题,所以选择把睡莲对应位置放置标记实体,在执行前清除为air,执行后还原。
在function文件夹中新建文件marker.mcfunction,将要输入以下内容:由于编辑器卡顿,使用了外部链接marker.mcfunction
kill @e[type=marker,nbt={Tags:["_marker"]}]execute anchored eyes if block ~-6 ~-6 ~-6 minecraft:lily_pad run summon marker ~-6 ~-6 ~-6 {Tags:["_marker"]}execute anchored eyes if block ~-6 ~-6 ~-5 minecraft:lily_pad run summon marker ~-6 ~-6 ~-5 {Tags:["_marker"]}execute anchored eyes if block ~-6 ~-6 ~-4 minecraft:lily_pad run summon marker ~-6 ~-6 ~-4 {Tags:["_marker"]}execute anchored eyes if block ~-6 ~-6 ~-3 minecraft:lily_pad run summon marker ~-6 ~-6 ~-3 {Tags:["_marker"]}............execute anchored eyes if block ~6 ~6 ~3 minecraft:lily_pad run summon marker ~6 ~6 ~3 {Tags:["_marker"]}execute anchored eyes if block ~6 ~6 ~4 minecraft:lily_pad run summon marker ~6 ~6 ~4 {Tags:["_marker"]}execute anchored eyes if block ~6 ~6 ~5 minecraft:lily_pad run summon marker ~6 ~6 ~5 {Tags:["_marker"]}execute anchored eyes if block ~6 ~6 ~6 minecraft:lily_pad run summon marker ~6 ~6 ~6 {Tags:["_marker"]}execute anchored eyes if block ~ ~ ~ minecraft:lily_pad run summon marker ~ ~ ~ {Tags:["_marker"]}
#将当前位置偏移范围-6 -6 -6到6 6 6的位置遍历检测是否为睡莲,如果是则生成具有_marker标签的标记实体。
你也可以使用以下Python代码生成遍历部分:
x=-6y=-6z=-6for x in range(-6,7):for y in range(-6,7):for z in range(-6,7):print ("execute anchored eyes if block ~",x," ~",y," ~",z," minecraft:lily_pad run summon marker ~",x," ~",y," ~",z," {Tags:[\"_marker\"]}",sep="")在此不对Python代码进行解释。
修改test.mcfunction:
advancement revoke @s only francium6623:testfunction francium6623:markerexecute at @e[type=marker,nbt={Tags:["_marker"]}] run setblock ~ ~ ~ airfill ~-6 ~-6 ~-6 ~6 ~6 ~6 command_block{auto:1b,Command:"execute align xyz positioned ~0.5 ~ ~0.5 run function francium6623:test2"} replace water[level=0]schedule function francium6623:test3 2t添加test3.mcfunction:
execute at @e[type=marker,nbt={Tags:["_marker"]}] run setblock ~ ~ ~ lily_padkill @e[type=marker,nbt={Tags:["_marker"]}]function francium6623:marker
#在test中第二行调用marker函数。
execute at @e[type=marker,nbt={Tags:["_marker"]}] run setblock ~ ~ ~ air
#第三行把标记实体位置替换为空气。
schedule function francium6623:test3 2t
#第五行计划函数test3。
execute at @e[type=marker,nbt={Tags:["_marker"]}] run setblock ~ ~ ~ lily_pad
#在test3中第一行还原睡莲,kill @e[type=marker,nbt={Tags:["_marker"]}]
#第二行清除标记。
为什么要使用schedule命令延时2t,我不使用的时候schedule命令延时2t也没有问题?
对于单片睡莲,不使用schedule命令延时2t的确没有问题。
但是当有多片睡莲在一起时,需要延时避免睡莲掉落。
什么原理:不知道能跑就行
三:再次测试
输入/reload重载数据包文件,进行测试,此时睡莲不会再掉落了。
四:打包数据包
打开存档文件夹里的datapacks文件夹,找到testdatapack文件夹。
打开testdatapack文件夹并全选文件,选择7-zip>添加到 "xxxx.zip"。
五:问题
哪些情况不能触发?
使用非水桶放置的水源,你甚至不能使用打破冰获得的水源。
使用命令,修改文件放置的水源。它们不能触发触发器。
使用mod的方块放置器放置的水源。由于它们不能触发触发器,也就不会执行后续操作。
未能实现?
检查:
输入/advancement grant @s only francium6623:test,若提示未知的命令,则为advancements文件夹下的进度文件错误。
输入/function francium6623:xxx,若提示未知的命令,则为functions文件夹下的对应的mcfunction文件错误。
对错误的文件进行修复。