🖌️ 画笔#
此示例演示了如何使用 Bookshelf 库在 Minecraft 中创建画笔。画笔会将方块的材质更改为匹配玩家手中的物品,同时保留朝向、浸水和其他方块状态等重要属性。例如,如果玩家手持橡木木板,白桦木楼梯将转变为橡木楼梯。
🎯 我们要构建什么#
我们的画笔系统将:
检测玩家何时使用画笔与方块交互
从玩家手中的物品确定方块类型
识别目标方块
将目标方块的材质替换为手持物品的材质
📦 要求#
在开始之前,请确保你有:
Minecraft Java版
数据包开发的基础知识,包括函数、标签和记分项
Bookshelf
bs.block和bs.view模块,安装方法参见快速开始@require bookshelf.module.block@require bookshelf.module.view
🛠️ 逐步实现#
1. Prepare the Datapack#
首先,我们需要一个函数在数据包加载时初始化我们的系统。创建一个名为 paintbrush:load 的函数并将其注册到 minecraft:load 函数标签中。
➔ 创建 load 函数
@function paintbrush:load
scoreboard objectives add data dummy
此记分项将存储画笔的数据,主要是命令返回的值。
➔ 在 load 标签中注册它
@function_tag minecraft:load
{
"values": [
"paintbrush:load"
]
}
这确保了在数据包启用或重新加载时 paintbrush:load 会自动运行。
2. Detect Player Interaction#
首先,我们需要创建一个玩家可以用来绘制方块的物品。为此,我们将使用刷子物品。然后,当玩家使用刷子与方块交互时,我们将使用进度来触发我们的系统。
➔ 创建 use 进度
@advancement paintbrush:use
{
"criteria": {
"requirement": {
"trigger": "minecraft:using_item",
"conditions": {
"player": [],
"item": {
"items": [
"minecraft:brush"
],
"predicates": {
"minecraft:custom_data": "{\"paintbrush\":true}"
}
}
}
}
},
"rewards": {
"function": "paintbrush:use"
}
}
当使用刷子时,奖励函数使我们能够触发特定的函数。我们将在此处使用 paintbrush:use 函数。
请注意,此进度仅在刷子具有自定义数据
{paintbrush: true}时才会触发函数,确保原版刷子继续正常运作。
➔ 创建 use 函数
@function paintbrush:use
say Paintbrush used!
➔ 创建 give 函数
@function paintbrush:give
give @s minecraft:brush[ \
minecraft:custom_data={ paintbrush: true }, \
minecraft:item_name=["",{text:"MAGIC BRUSH",color:"light_purple",bold:true,italic:true},{text:" - Right click to use",color:"gray"}], \
minecraft:lore=[{text:"A brushstroke of creation.",color:"dark_gray",italic:false},"",{text:"Imbue the aimed block with the properties",color:"gray",italic:false},{text:"of the block held in your offhand.",color:"gray",italic:false}], \
]
接下来,通过运行 function paintbrush:give 给自己一个画笔来测试。现在……右键点击,你会在聊天栏中看到“Paintbrush used!”。但是,如果你再次尝试,什么也不会发生。这是因为玩家现在已经获得了 painterbrush:use 进度,这会阻止它再次触发。由于进度每个玩家只能触发一次,我们需要在每次使用画笔时重置它。
➔ 更新 use 函数
@function paintbrush:use
advancement revoke @s only paintbrush:use
say Paintbrush used!
再次尝试(记得在测试前手动重置一次进度),你会看到每次使用画笔时消息都会显示。
3. Replace the Targeted Block#
我们已成功设置了检测玩家使用画笔右键点击的功能。然而,现在的问题是我们的函数在玩家位置执行。我们实际想要做的是转换玩家瞄准的方块。虽然 Minecraft 没有提供获取此信息的直接方法,但 Bookshelf 库提供了!
我们可以使用 bs.view 模块,特别是 at_aimed_block 函数,它允许我们直接在玩家瞄准的方块位置执行命令。
➔ 更新 use 函数
@function paintbrush:use
advancement revoke @s only paintbrush:use
function #bs.view:at_aimed_block { run: "function paintbrush:replace_block", with: {} }
➔ 创建 replace_block 函数
@function paintbrush:replace_block
setblock ~ ~ ~ minecraft:bookshelf
现在,每次玩家使用画笔时,paintbrush:use 函数都会在瞄准的方块位置执行 paintbrush:replace_block,将其替换为书架方块。
你可能已经注意到一个空的
with宏变量。我们不能直接将可选的宏变量传递给函数,但使用with允许我们为它们设置默认值。在这种情况下,我们不需要传递任何可选变量,所以将其留空。
4. Paint the Targeted Block#
现在,让我们开始绘制!我们将使用 bs.block 模块将副手中物品的方块应用到目标方块。此过程包括三个步骤:
将目标方块加载到存储(
bs:out block)中作为“虚拟方块”使用各种操作转换虚拟方块(本例中为
mix_type)从虚拟方块生成最终结果,可以是方块、物品、粒子、方块展示实体等(这里我们将它转换后再替换方块)。
设置转换#
mix_type 函数使用映射注册表来确定如何转换方块。Bookshelf 提供了两个内置注册表:
bs.colors:该注册表通过颜色属性实现方块转换功能。例如,当手持染色方块时,会尝试将颜色转换应用于目标方块。bs.shapes:此注册表用于形状转换方块。例如,如果手持方块是橡木木板,目标方块是白桦木楼梯,此注册表会将橡木木板映射到相应的方块形状,即橡木楼梯。这非常适合在具有相似结构形状的方块之间进行转换。
可以通过这些注册表更精确地控制方块转换。在此示例中,我们将使用 bs.shapes。要实现转换,我们需要指定 mapping_registry 并将玩家副手方块的 type 存储到某个命令存储中。
➔ 更新 replace_block 函数
@function paintbrush:replace_block
# Prepare the input of the mix_type function
data remove storage painterbrush:input type
data modify storage painterbrush:input mapping_registry set value "bs.shapes"
execute store success score #success data run data modify storage painterbrush:input type set from entity @s equipment.offhand.id
execute if score #success data matches 0 run return fail
在这里,我们使用分数来检查命令是否成功。如果失败,我们立即返回以防止意外行为。
加载目标方块#
#bs.view:at_aimed_block 函数确保执行已经在目标方块位置,因此我们可以直接使用 get_block 加载它。
➔ 更新 replace_block 函数
@function paintbrush:replace_block
# Prepare the input of the mix_type function
data remove storage painterbrush:input type
data modify storage painterbrush:input mapping_registry set value "bs.shapes"
execute store success score #success data run data modify storage painterbrush:input type set from entity @s equipment.offhand.id
execute if score #success data matches 0 run return fail
# Load the aimed block
function #bs.block:get_block
应用转换#
现在方块已加载且转换输入已就绪,我们可以应用 mix_type。
➔ 更新 replace_block 函数
@function paintbrush:replace_block
# Prepare the input of the mix_type function
data remove storage painterbrush:input type
data modify storage painterbrush:input mapping_registry set value "bs.shapes"
execute store success score #success data run data modify storage painterbrush:input type set from entity @s equipment.offhand.id
execute if score #success data matches 0 run return fail
# Load the aimed block
function #bs.block:get_block
# Apply the transformation
execute store success score #success data run function #bs.block:mix_type with storage painterbrush:input
execute if score #success data matches 0 run return fail
mix_type函数直接用转换后的值覆盖bs:out存储中的虚拟方块。如果返回0,则表示未找到转换,因此我们返回失败。
放置转换后的方块#
最后,我们使用 set_block 将转换后的方块应用到世界中。
➔ 更新 replace_block 函数
@function paintbrush:replace_block
# Prepare the input of the mix_type function
data remove storage painterbrush:input type
data modify storage painterbrush:input mapping_registry set value "bs.shapes"
execute store success score #success data run data modify storage painterbrush:input type set from entity @s equipment.offhand.id
execute if score #success data matches 0 run return fail
# Load the aimed block
function #bs.block:get_block
# Apply the transformation
execute store success score #success data run function #bs.block:mix_type with storage painterbrush:input
execute if score #success data matches 0 run return fail
# Produce the new block
data modify storage bs:in block.set_block set from storage bs:out block
function #bs.block:set_block
这就完成了转换过程。如果你现在尝试绘制方块,你会看到方块被转换了,完美!
5. Going Further#
如果你在告示牌上尝试此操作,你会发现方块并没有转换为匹配手持方块的材质。这是因为 using_item 进度条件不会在某些方块(如告示牌)上触发。要解决此问题,我们可以使用记分板记分项来补充我们的方法,以跟踪玩家何时使用画笔。我们需要在分数增加时触发 use 函数。为此,我们将添加一个循环运行的新 tick 函数,并在 paintbrush:use 函数中重置分数。
➔ 更新 load 函数
@function paintbrush:load
scoreboard objectives add data dummy
scoreboard objectives add use_brush minecraft.used:minecraft.brush
schedule function paintbrush:tick 1t
➔ 创建 tick 函数
@function paintbrush:tick
execute as @a[scores={use_brush=1..}] run function paintbrush:use
schedule function paintbrush:tick 1t
➔ 更新 use 函数
@function paintbrush:use
scoreboard players reset @s use_brush
advancement revoke @s only paintbrush:use
function #bs.view:at_aimed_block { run: "function paintbrush:replace_block", with: {} }
就是这样!你现在可以使用绘画工具绘制方块了,如你所见,这真的很简单!
✔️ 结语#
恭喜!你已成功使用 Bookshelf 创建了一个功能性画笔!此项目演示了如何:
使用 Bookshelf 的 view 模块来获取瞄准的方块
使用 Bookshelf 的 block 模块来操作方块
画笔不仅是一个有用的工具,也是展示 Bookshelf 如何简化复杂数据包开发的绝佳示例。请随意尝试代码并添加你自己的功能,使其变得更强大!
💬 这对你有帮助吗?
欢迎在下方留下你的问题和反馈!