本文最初于2022年4月17日发布于在 MCBBS,但由于 MCBBS 因不可抗力关站,特此补档

本篇教程并不是完整的附加包开发教程,仅包括了与完成“矿石作物”这个目标相关的内容,学习更多内容请访问官方文档

本文中提到的一些内容在你阅读的时候可能已经过时,请以官方文档为准

本文若有错误,欢迎在评论区指出,不胜感激

你将学到...

  • 自定义物品
  • 自定义方块
  • 自定义合成配方
  • 自定义战利品表
  • 本地化
  • 一点点 Molang

一切开始前...

  • 准备需要使用到的纹理(图标、种子的纹理、作物方块不同生长阶段的纹理等)
  • 准备一个文本编辑器
  • 安装 Blockbench,你可以在这里下载
  • 别忘了最重要的 —— Minecraft 基岩版

准备就绪

开始的开始

你可以按照下面的目录树创建这些在后续需要用到的文件夹

BP是行为包(Behavior Pack)的缩写,\BP 目录则是我们的行为包部分

RP是资源包(Resource Pack)的缩写,\RP 目录则是我们的资源包部分

HelloWorld
  ├─BP
  │  ├─blocks
  │  ├─items
  │  ├─loot_tables │├─loot_tables
  │  └─recipes
  └─RP
     ├─models
     │  └─entity
     ├─texts
     └─textures
        ├─blocks
        └─items

清单文件 manifest.json

首先我们需要在 \BP 与 \RP 目录下分别创建一个名叫 manifest.json 的文件

HelloWorld
  ├─BP
  │  ├─...
  │  └─manifest.json
  └─RP
     ├─...
     └─manifest.json

manifest.json 的基本构成

名称描述
format_version告诉 Minecraft 需要用什么版本来解析这个 Json
header清单的头部信息
modules此附加包所拥有的模块
dependencies此附加包的依赖项

header

header 所需要包含的头部信息:

名称数据类型描述
name字符串此附加包的名称
version向量 [a, b, c]此附加包的版本号
min_engine_version向量 [a, b, c]此附加包所兼容的 Minecraft 的最低版本
uuid字符串此附加包的标识

我们直接把包名设置为 Ore Crops 好了,后面加上 BP、RP 加以区分(事实上不这么做也可以)

描述中我们可以写上作者信息之类的东西

版本号设置成 0.0.1 [注意:若要将附加包上传至基岩版市场,a 值需要大于  0]

uuid 将作为区分附加包的标识,我们需要设置一个独一无二的,你可以在这个网站在线生成 uuid

modules

modules 所需要包含的内容:

名称数据类型描述
type字符串模块的类型
description字符串模块的描述
version向量 [a, b, c]模块的版本
uuid字符串模块的标识

我们需要分别为 \BP\manifest.json 和 \RP\manifest.json 添加行为包模块(data)与资源包模块(resources

dependencies

dependencies所需要包含的内容:

名称数据类型描述
uuid字符串所依赖的附加包的 uuid
version向量 [a, b, c]所依赖的附加包的版本

为了将行为包与资源包关联起来,我们需要将他们添加到对方的 dependencies 中

现在,我们的清单文件应该是这样的:

\BP\manifest.json

{
    "format_version":2,
    "header":{
        "name":"Ore Crops (BP)",
        "description":"Ore Crops behavior pack",
        "uuid":"c5960d44-cfa8-457d-83e4-ccc56fbc22e4",
        "version":[0,0,1],
        "min_engine_version":[1,18,10]
    },
    "modules":[
        {
            "type":"data",
            "description":"Ore Crops behavior pack",
            "uuid":"713b3a86-1a48-c1b2-26f8-4416db5b876b",
            "version":[0,0,1]
        }
    ],
    "dependencies":[
        {
            "uuid":"330199b2-ea33-da59-8cb9-c412055d23e9",
            "version":[0,0,1]
        }
    ]
}

\BP\manifest.json

{
    "format_version":2,
    "header":{
        "name":"Ore Crops (RP)",
        "description":"Ore Crops resource pack",
        "uuid":"330199b2-ea33-da59-8cb9-c412055d23e9",
        "version":[0,0,1],
        "min_engine_version":[1,18,10]
    },
    "modules":[
        {
            "type":"resources",
            "description":"Ore Crops resource pack",
            "uuid":"0e262f01-38dc-b893-0902-cb0140885a43",
            "version":[0,0,1]
        }
    ],
    "dependencies":[
        {
            "uuid":"c5960d44-cfa8-457d-83e4-ccc56fbc22e4",
            "version":[0,0,1]
        }
    ]
}

图标文件 pack_icon.png

别忘了设置一个图标!

在 \BP 和 \RP 目录下放置 pack_icon.png 即可

完成了这些,我们可以正式开始开发工作了 ——

第一个物品

添加物品

首先你需要在 \BP\items 目录下创建一个 .json 文件,文件名随意,这里使用 coal_seed.json 作为“煤炭种子”的物品 json 文件。

物品 json 文件的基本格式如下

{
    "format_version":"1.18.0",  // 游戏版本号
    "minecraft:item":{
        "description":{
            // 物品的基本信息
        },
        "components":{
            // 物品的组件
        },
        "events":{
            // 物品的事件
        }
    }
}

description 的基本结构如下:

名称数据类型描述
identifier字符串物品的命名空间与物品名构成的标识
category字符串物品在创造模式物品栏的分类
is_experimental布尔值物品是否为实验性物品

首先是 identifier,命名空间一般为 addon 的名称,这里“煤炭种子”可以设置为 orecrops:coal_seed

category 的可选值有:equipment(装备), items(物品), natural(自然), block(建筑), commands(不可通过命令获取)。这里我们选择 natural

is_experimental 将决定物品是否需开启实验性玩法才可获得,默认值为 false

现在,你的 \BP\items\coal_seed.json 应该是这样子的:

{
    "format_version":"1.18.0",
    "minecraft:item":{
        "description":{
            "identifier":"orecrops:coal_seed",
            "category":"natural"
        }
    }
}

至此,你已经成功添加了你的第一个物品!

但是它还缺少纹理、名字等等一些必要属性,下面我们为它定义一个纹理

定义纹理与物品名称

定义纹理

转到 \RP\textures\items 目录,在这里放置你的物品纹理

回到 \RP\textures 目录,在这里新建一个名为 item_texture.json 的文件,在里面输入下面的内容来定义物品纹理

{
    "resource_pack_name":"Ore Crops resource pack",
    "texture_name":"atlas.items",
    "texture_data":{
        "coal_seed":{
            "textures":"textures/items/fang/coal_seed"
        }
    }
}
名称描述
resource_pack_name资源包的名称,可填vanilla或其他名称[存疑]
texture_name请填为 atlas.item [存疑]
texture_data纹理资源 "纹理名称":{"textures":"纹理路径"}

物品名称

我们在 \RP\texts 目录下新建一个 zh_CN.lang, 在里面输入:

item.orecrops:coal_seed.name=煤炭种子

我们在 zh_CN.lang 中输入的这一行定义了在简体中文语言下 item.orecrops:coal_seed.name 键所对应的文本,以这种方式设置物品名称将方便我们后续进行本地化,与本地化相关的内容我们会在最后学习

到这里你可能会很疑惑,为什么我的物品还是没有纹理?

我们成功添加了一个物品并定义了他的纹理,下面我们将使用组件赋予它名字、纹理与一些作为物品该有的基本属性

物品组件

我们将使用到下表中的组件,更多组件请查阅文档

组件名称描述
minecraft:creative_category注册物品到创造模式物品栏的指定分类、分组
minecraft:display_name设置物品显示的名称(可使用本地化键名)
minecraft:icon设置物品显示的纹理
minecraft:max_stack_size设置物品的最大堆叠数量

minecraft:creative_category

"minecraft:creative_category": {
    "parent": "分组"
}

下面是一些分组

字符串组名
itemGroup.name.anvil铁砧
itemGroup.name.arrow
itemGroup.name.axe
itemGroup.name.banner旗帜
itemGroup.name.banner_pattern旗帜图案
itemGroup.name.bed
itemGroup.name.boat
itemGroup.name.boots靴子
itemGroup.name.buttons按钮
itemGroup.name.candles蜡烛
itemGroup.name.chest箱子
itemGroup.name.chestBoat运输船
itemGroup.name.chestplate胸甲
itemGroup.name.concrete混凝土
itemGroup.name.concretePowder混凝土粉末
itemGroup.name.cookedFood熟食
itemGroup.name.copper
itemGroup.name.copperHorn‌Copper Horn
itemGroup.name.coral珊瑚块
itemGroup.name.coral_decorations珊瑚装饰
itemGroup.name.crop农作物
itemGroup.name.door
itemGroup.name.dye染料
itemGroup.name.element元素
itemGroup.name.enchantedBook附魔书
itemGroup.name.fence栅栏
itemGroup.name.fenceGate栅栏门
itemGroup.name.firework烟花火箭
itemGroup.name.fireworkStars烟火之星
itemGroup.name.flower
itemGroup.name.glass玻璃
itemGroup.name.glassPane玻璃板
itemGroup.name.glazedTerracotta带釉陶瓦
itemGroup.name.goatHorn山羊角
itemGroup.name.grass地被植物
itemGroup.name.helmet头盔
itemGroup.name.hoe
itemGroup.name.horseArmor马凯
itemGroup.name.leaves树叶
itemGroup.name.leggings护腿
itemGroup.name.lingeringPotion滞留药水
itemGroup.name.log原木
itemGroup.name.minecart矿车
itemGroup.name.miscFood其他食物
itemGroup.name.mobEgg刷怪蛋
itemGroup.name.monsterStoneEgg被虫蚀的石头
itemGroup.name.mushroom蘑菇
itemGroup.name.netherWartBlock下界疣块
itemGroup.name.ore矿石
itemGroup.name.pickaxe
itemGroup.name.planks木板
itemGroup.name.potion药水
itemGroup.name.pressurePlate压力板
itemGroup.name.rail铁轨
itemGroup.name.rawFood生食
itemGroup.name.record唱片
itemGroup.name.sandstone砂岩
itemGroup.name.sapling树苗
itemGroup.name.seed种子
itemGroup.name.shovel
itemGroup.name.shulkerBox潜影盒
itemGroup.name.sign告示牌
itemGroup.name.skull头颅
itemGroup.name.slab台阶
itemGroup.name.splashPotion喷溅药水
itemGroup.name.stainedClay陶瓦
itemGroup.name.sculkSculk
itemGroup.name.stairs楼梯
itemGroup.name.stone石头
itemGroup.name.stoneBrick石砖
itemGroup.name.sword
itemGroup.name.trapdoor活板门
itemGroup.name.walls
itemGroup.name.wood木头
itemGroup.name.wool羊毛
itemGroup.name.woolCarpet地毯

我们使用这个组件将“煤炭种子”归入“种子”分组

minecraft:display_name

"minecraft:display_name": {
    "name":"名称或本地化键名"
}

在上一节我们定义了“煤炭种子”的本地化键名(item.orecrops:coal_seed.name),直接填进去即可

minecraft:icon

"minecraft:icon": {
    "texture":"纹理名称"
}

在上一节我们定义了“煤炭种子”的纹理名称(coal_seed),直接填进去即可

minecraft:max_stack_size

"minecraft:max_stack_size": 堆叠上限

堆叠上限是一个大于等于 1 小于等于 64 的整数型值

我们设置为 64

现在,我们的 coal_seed.json 应该是这样的:

{
    "format_version":"1.18.0",
    "minecraft:item":{
        "description":{
            "identifier":"orecrops:coal_seed",
            "category":"nature"
        },
        "components":{
            "minecraft:display_name":{
                "value":"item.orecrops:coal_seed.name"
            },
            "minecraft:creative_category":{
                "parent":"itemGroup.name.seed"
            },
            "minecraft:max_stack_size":64,
            "minecraft:icon":{
                "texture":"coal_seed"
            }
        }
    }
}

现在,你的第一个物品已经有了名字、纹理,下面我们来完成你的第一个方块

第一个方块

添加方块

\BP\blocks 目录创建一个名为 coal_crops.json 的文件作为“煤炭作物”的作物方块

方块 json 文件的基本格式如下

{
    "format_version": "1.18.0",  // 游戏版本
    "minecraft:block": {
        "description": {
            // 描述
        },
        "components": {
            // 组件
        },
        "events": {
            // 事件
        },
        "permutations": [
            //置换
        ]
    }
}

方块的描述部分与物品稍有不同:

名称数据类型描述
identifier字符串方块的命名空间与物品名构成的标识
properties对象方块的属性
is_experimental布尔值方块是否为实验性方块

identifier 我们设置为 orecrops:coal_crop

properties 在下一章将具体学习

is_experimental 与物品相同,默认值为 false

现在,你的 \BP\blocks\coal_crop.json 应该是这样的:

{
    "format_version":"1.18.0",
    "minecraft:block":{
        "description":{
            "identifier":"orecrops:coal_crop"
        }
    }
}

定义纹理

将作物的不同生长状态的纹理放进 \RP\textures\blocks 中,本教程中我为作物设置了 8 个不同生长阶段

回到 \RP\textures 目录,新建 terrain_texture.json,在里面输入:

{
    "resource_pack_name":"Ore Crops resource pack",
    "texture_name":"atlas.terrain",
    "num_mip_levels":4,
    "padding":8,
    "texture_data":{
        "coal_crop_0":{
            "textures":"textures/blocks/fang/crop_stage_0"
        },
        "coal_crop_1":{
            "textures":"textures/blocks/fang/crop_stage_1"
        },
        "coal_crop_2":{
            "textures":"textures/blocks/fang/crop_stage_2"
        },
        "coal_crop_3":{
            "textures":"textures/blocks/fang/crop_stage_3"
        },
        "coal_crop_4":{
            "textures":"textures/blocks/fang/crop_stage_4"
        },
        "coal_crop_5":{
            "textures":"textures/blocks/fang/coal_stage_5"
        },
        "coal_crop_6":{
            "textures":"textures/blocks/fang/coal_stage_6"
        },
        "coal_crop_7":{
            "textures":"textures/blocks/fang/coal_stage_7"
        }
    }
}

我们还需要在资源包中为方块指定纹理,回到 \RP 目录

创建 blocks.json,为我们的作物方块指定纹理和音效

{
    "format_version":"1.18.0",
    "orecrops:coal_crop":{
        "textures":"coal_crop_0",
        "sound":"grass"
    }
}

textures 的值也可以是一个对象,用来设置方块不同面的纹理,例如这样:

"textures":{
    "down" : "log_end",
    "side" : "log_side",
    "up" : "log_end"
}

现在它是一个有纹理的方块了,但是看起来一点都不像一个作物该有的样子,我们需要为它制作一个模型

打开 Blockbench,为它制作一个模型(更多 Blockbench 的用法,请查阅此教程

XuCypng

选择新建 Bedrock Model

X6xlpng

设置好后点击 Confirm

XX15png

制作出想要的模型(新建两个 cube,将 Size 的第三个值设置成 0 就成薄片状了)

XtzLpng

将导出的模型放在 \RP\models\entity 中,之后我们就可以通过组件为方块设置模型和必要属性了

方块组件

我们将使用到下表中的组件,更多组件请查阅文档

名称描述
minecraft:collision_box设置方块的碰撞箱
minecraft:geometry设置方块的模型
minecraft:placement_filter设置方块被放置时的条件

minecraft:collision_box

// 对象写法
"minecraft:collision_box":{
    "origin": 锚点,
    "size": 尺寸
}

// 布尔值写法
"minecraft:collision_box": 布尔值

以上是 minecraft:collision_box 组件的不同写法,当布尔值写法的数据值设置为 false 时则禁用碰撞箱,也就是说下面两种写法是等价的

// 对象写法
"minecraft:collision_box":{
    "origin": [0, 0, 0],
    "size": [0, 0, 0]
}

// 布尔值写法
"minecraft:collision_box": false

在原版中的作物方块实体是可以自由穿过的,这里我们可以直接将 minecraft:collision_box 的数据值设置为 false 禁用碰撞箱

minecraft:geometry

"minecraft:geometry": "几何模型"

还记得你在上一节设置的 Model Identifier 吗?将它填进去就好

minecraft:placement_filter

"minecraft:placement_filter": {
  "conditions": [   // 条件可以设置多个
    {
      "block_filter": 方块数组,
      "allowed_faces": 面数组
    }
  ]
}

我们的作物方块只可以放置在耕地方块的上面block_filter 设置为 ["farmland"]allowed_faces 设置为 ["up"]

另:allowed_faces 可选的值有 up(顶面)、down(底面)、north(北面)、south(南面)、east(东面)、west(西面)、side(侧面)、all(所有面)

现在我们的 coal_crops.json 应该是这样的:

{
    "format_version":"1.18.0",
    "minecraft:block":{
        "description":{
            "identifier":"orecrops:coal_crop"
        },
        "components":{
            "minecraft:collision_box":false,
            "minecraft:geometry":"geometry.crop",
            "minecraft:placement_filter":{
                "conditions":[
                    {
                        "block_filter":["farmland"],
                        "allowed_faces":["up"]
                    }
                ]
            }
        }
    }
}

种子、作物

种子

我们将使用 minecraft:block_placer 组件让“煤炭种子”拥有放置方块的能力,在放置方块的同时将使用一个物品

"minecraft:block_placer":{
    "block": "方块的标识",
    "use_on": 可以在何种方块上使用(数组)
}

写好后应该长这样:

"minecraft:block_placer":{
    "block": "orecrops:coal_crop",
    "use_on": ["farmland"]
}

大功告成!物品这一部分我们已经彻底完成了 ——

{
    "format_version":"1.18.0",
    "minecraft:item":{
        "description":{
            "identifier":"orecrops:coal_seed",
            "category":"nature"
        },
        "components":{
            "minecraft:display_name":{
                "value":"item.orecrops:coal_seed.name"
            },
            "minecraft:creative_category":{
                "parent":"itemGroup.name.seed"
            },
            "minecraft:max_stack_size":64,
            "minecraft:icon":{
                "texture":"coal_seed"
            },
            "minecraft:block_placer":{
                "block":"orecrops:coal_crop",
                "use_on":["farmland"]
            }
        }
    }
}

作物

不同生长状态

为了实现不同生长状态,我们首先需要在方块的描述中为方块定义一个属性(properties),它们类似“变量”,一个方块可以拥有多个属性,属性的值可以是数字、布尔值或字符串

我们先为作物方块定义一个 orecrops:growth 属性,来储存它的不同生长阶段

"properties":{
    "orecrops:growth":[0, 1, 2, 3, 4, 5, 6, 7]
}

为了让作物方块在不同生长阶段拥有不同的纹理,我们需要使用置换(permutations)

在置换部分我们要接触到 Molang 了!

下面是 permutations 的格式,你可以设置不同条件对应不同欲被替换的组件

{
    "condition":"条件",
    "components": 欲被替换的组件
}

条件部分我们可以使用 Molang,在这里我们通常使用 Molang 的逻辑运算符对值进行判断

运算符描述示例
!逻辑非运算符。使一个表达式的结果从 true 变为 false ,从 false 变为 true。!query.can_fly
&&逻辑与运算符。只有当两个表达式都为true 时,整个表达式的结果才为true。query.can_walk == 1 && query.can_climb == 1
\ 逻辑或运算符。只要其中任意一个表达式为 true 整个表达式都为 true。`query.can_walk == 1
<小于运算符。比较左右两边表达式数值的大小,若左边小于右边即为 true,反之则为 false。query.total_particle_count < 5
<=小于等于运算符。用于比较左右两边表达式数值的大小,若左边小于或等于右边即为 true,反之则为 false。query.trade_tier <= 2
>=大于等于运算符。用于比较左右两边表达式数值的大小,若左边大于或等于右边即为 true,反之则为 false。query.health  >= 5
>大于运算符。用于比较左右两边表达式数值的大小,若左边大于右边即为 true,反之则为 false。query.day > 7
==等于运算符。若左边与右边表达式的结果相等时即为 true,反之则为 false。query.block_face == query.cardinal_player_facing
!=不等于运算符。若左边与右边表达式的结果不相等时即为 true,反之则为 false。query.body_x_rotation != query.body_y_rotation

我们需要判断此前设置的 orecrops:growth 的值是否为特定值,所以选用等于运算符 ==

若要获取 orecrops:growth 还需要用到查询函数 query.block_property(),这个函数需要传入一个参数,参数则是要查询的属性名称

我们的煤炭作物生长第一阶段的“条件”是:query.block_property('orecrops:growth') == 0

我们共需要设置 8 个这样的置换,来做到 8 个生长状态:

"permutations": [
    {
        "condition":"query.block_property('orecrops:growth') == 0",
        "components":{
            "minecraft:material_instances":{
                "*":{
                    "texture":"crop_0",
                    "render_method":"alpha_test"
                }
            }
        }
    },
    {
        "condition":"query.block_property('orecrops:growth') == 1",
        "components":{
            "minecraft:material_instances":{
                "*":{
                    "texture":"coal_crop_1",
                    "render_method":"alpha_test"
                }
            }
        }
    },
    {
        "condition":"query.block_property('orecrops:growth') == 2",
        "components":{
            "minecraft:material_instances":{
                "*":{
                    "texture":"coal_crop_2",
                    "render_method":"alpha_test"
                }
            }
        }
    },
    {
        "condition":"query.block_property('orecrops:growth') == 3",
        "components":{
            "minecraft:material_instances":{
                "*":{
                    "texture":"coal_crop_3",
                    "render_method":"alpha_test"
                }
            }
        }
    },
    {
        "condition":"query.block_property('orecrops:growth') == 4",
        "components":{
            "minecraft:material_instances":{
                "*":{
                    "texture":"coal_crop_4",
                    "render_method":"alpha_test"
                }
            }
        }
    },
    {
        "condition":"query.block_property('orecrops:growth') == 5",
        "components":{
            "minecraft:material_instances":{
                "*":{
                    "texture":"coal_crop_5",
                    "render_method":"alpha_test"
                }
            }
        }
    },
    {
        "condition":"query.block_property('orecrops:growth') == 6",
        "components":{
            "minecraft:material_instances":{
                "*":{
                    "texture":"coal_crop_6",
                    "render_method":"alpha_test"
                }
            }
        }
    },
    {
        "condition":"query.block_property('orecrops:growth') == 7",
        "components":{
            "minecraft:material_instances":{
                "*":{
                    "texture":"coal_crop_7",
                    "render_method":"alpha_test"
                }
            }
        }
    }
]

生长

我们在上一节已经完整了作物的不同生长阶段,下面我们使用触发器组件与自定义事件完成作物的自然生长与骨粉催熟

我们先来设置事件,先来一个生长事件:

"grow_event":{  // 自定义事件名
    "randomize":[    // 随机执行一个事件组
        {
            "weight":1   // 权重,如果随机到这里什么都不会发生
        },
        {
            "weight":1,  // 权重
            "set_block_property":{   // 设置方块的属性的值
                "orecrops:growth":"(query.block_property('orecrops:growth')<7) ? query.block_property('orecrops:growth') + 1 : 7"  // 在下方详细解释
            }
        }
    ]
}

set_block_property 中我们使用了 Molang 让 orecrops:growth 增加

这里我们用到了 Molang 的三元条件运算符 ?::当问号左边的表达式为真,则将问号与冒号中间表达式的值作为整个表达式的取值,反之则将冒号后面表达式的值作为整个表达式的取值。

翻译成人话就是:若 orecrops:growth 小于 7 让 orecrops:growth + 1,否则设置 orecrops:growth 为 7

下面我们来完成骨粉催熟事件

"usebonemeal_event": {  // 自定义事件名
    "sequence":[  // 执行下面的所有事件
        {
            "decrement_stack":{  // 减少一个手持的物品
                "ignore_game_mode":false  // 是否忽略游戏模式
            }
        },
        {
            "run_command":{  // 执行命令
                "command":[  // 命令(数组)
                    "particle minecraft:crop_growth_emitter ~ ~ ~"  // 在方块处生成 crop_growth_emitter 粒子
                ]
            }
        },
        {
            "trigger":{  
                "event":"grow_event"  // 执行自定义事件“grow_event”
            }
        }
    ]
}

完成事件后我们还需要使用触发器组件来触发这些事件

"minecraft:on_interact": {  // 右键触发器组件
    "condition":"query.get_equipped_item_name('main_hand') == 'bone_meal'",  // 触发条件是拿着骨粉右键
    "event":"usebonemeal_event"  // 触发拿着骨粉右键将触发 usebonemeal_event 事件
},
"minecraft:random_ticking": {  // 随机刻组件
    "on_tick":{  // 触发器
        "event":"grow_event"  // 触发 grow_event 事件
    }
}

现在我们的 coal_crop.json 是这个样子的:

{
    "format_version":"1.18.0",
    "minecraft:block":{
        "description":{
            "identifier":"orecrops:coal_crop",
            "properties":{
                "orecrops:growth":[0, 1, 2, 3, 4, 5, 6, 7]
            }
        },
        "components":{
            "minecraft:geometry":"geometry.crop",
            "minecraft:collision_box":false,
            "minecraft:placement_filter":{
                "conditions":[
                    {
                        "block_filter":["farmland"],
                        "allowed_faces":["up"]
                    }
                ]
            },
            "minecraft:on_interact":{
                "condition":"query.get_equipped_item_name('main_hand') == 'bone_meal'",
                "event":"usebonemeal_event"
            },
            "minecraft:random_ticking":{
                "on_tick":{
                    "event":"grow_event"
                }
            }
        },
        "events":{
            "grow_event":{
                "randomize":[
                    {
                        "weight":1
                    },
                    {
                        "weight":1,
                        "set_block_property":{
                            "orecrops:growth":"(query.block_property('orecrops:growth')<7) ? query.block_property('orecrops:growth') + 1 : 7"
                        }
                    }
                ]
            },
            "usebonemeal_event":{
                "sequence":[
                    {
                        "decrement_stack":{
                            "ignore_game_mode":false
                        }
                    },
                    {
                        "run_command":{
                            "command":[
                                "particle minecraft:crop_growth_emitter ~ ~ ~"
                            ]
                        }
                    },
                    {
                        "trigger":{
                            "event":"grow_event"
                        }
                    }
                ]
            }
        },
        "permutations":[
            {
                "condition":"query.block_property('orecrops:growth') == 0",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_0",
                            "render_method":"alpha_test"
                        }
                    }
                }
            },
            {
                "condition":"query.block_property('orecrops:growth') == 1",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_1",
                            "render_method":"alpha_test"
                        }
                    }
                }
            },
            {
                "condition":"query.block_property('orecrops:growth') == 2",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_2",
                            "render_method":"alpha_test"
                        }
                    }
                }
            },
            {
                "condition":"query.block_property('orecrops:growth') == 3",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_3",
                            "render_method":"alpha_test"
                        }
                    }
                }
            },
            {
                "condition":"query.block_property('orecrops:growth') == 4",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_4",
                            "render_method":"alpha_test"
                        }
                    }
                }
            },
            {
                "condition":"query.block_property('orecrops:growth') == 5",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_5",
                            "render_method":"alpha_test"
                        }
                    }
                }
            },
            {
                "condition":"query.block_property('orecrops:growth') == 6",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_6",
                            "render_method":"alpha_test"
                        }
                    }
                }
            },
            {
                "condition":"query.block_property('orecrops:growth') == 7",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_7",
                            "render_method":"alpha_test"
                        }
                    }
                }
            }
        ]
    }
}

现在,一个可生长的作物已经初步成型了,等等——破坏掉它没有掉落物?!

收获

战利品表

我们需要使用战利品表自定义作物的掉落物

在 \BP\loot_tables 目录新建 coal_seed.json 文件作为物品还未成熟时的掉落物的战利品表

{
    "pools":[  // 随机池列表
        {
            "rolls":1,  // 此随机池中的抽取次数
            "entries":[  
                {
                    "weight":1,  // 权重
                    "type":"item",  // 战利品的类型
                    "name":"orecrops:coal_seed", // 战利品的标识
                    "functions":[  // 函数列表
                        {
                            "function":"set_count",  // 函数名(设置战利品的数量)
                            "count":1  // 数量为 1
                        }
                    ]
                }
            ]
        }
    ]
}

在 \BP\loot_tables 目录新建 coal_crop.json 文件作为物品已经成熟时的掉落物的战利品表

{
    "pools":[
        {
            "rolls":1,
            "entries":[
                {
                    "weight":1,
                    "type":"item",
                    "name":"orecrops:coal_seed",
                    "functions":[
                        {
                            "function":"set_count",
                            "count":{
                                "min":0,  // 随机 0~2 个战利品
                                "max":2
                            }
                        }
                    ]
                }
            ]
        },
        {
            "rolls":1,
            "entries":[
                {
                    "weight":1,
                    "type":"item",
                    "name":"minecraft:coal",
                    "functions":[
                        {
                            "function":"set_count",
                            "count":{
                                "min":1,  // 随机 1~3 个战利品
                                "max":3
                            }
                        }
                    ]
                }
            ]
        }
    ]
}

回到方块的 json 文件,使用 minecraft:loot 组件设置战利品表

我们为未成熟的作物方块设置 coal_seed.json 战利品

为成熟的作物方块设置 coal_crop.json 战利品

收获事件

为了在作物成熟的时候右键即可收获,且一株作物可以多次结矿物,我们可以新增一个自定义事件 harvest_event

"harvest_event":{
    "spawn_loot":{  // 生成战利品表
        "table":"loot_tables/coal_crop.json"
    },
    "set_block_property":{  // 设置 orecrops:growth 为 5
        "orecrops:growth":"5"
    }
}

我们还需要在 orecrops:growth 为 7 时的置换中置换 minecraft:on_interact 事件和 minecraft:loot 事件

{
    "condition":"query.block_property('orecrops:growth') == 7",
    "components":{
        "minecraft:material_instances":{
            "*":{
                "texture":"coal_crop_7",
                "render_method":"alpha_test"
            }
        },
        "minecraft:loot":"loot_tables/coal_crop.json",
        "minecraft:on_interact":{
            "event":"harvest_event"
        }
    }
}

最终,我们的 coal_crop.json 是这样的:

{
    "format_version":"1.18.0",
    "minecraft:block":{
        "description":{
            "identifier":"orecrops:coal_crop",
            "properties":{
                "orecrops:growth":[0, 1, 2, 3, 4, 5, 6, 7]
            }
        },
        "components":{
            "minecraft:loot":"loot_tables/coal_seed.json",
            "minecraft:geometry":"geometry.crop",
            "minecraft:collision_box":false,
            "minecraft:placement_filter":{
                "conditions":[
                    {
                        "block_filter":["farmland"],
                        "allowed_faces":["up"]
                    }
                ]
            },
            "minecraft:on_interact":{
                "condition":"query.get_equipped_item_name('main_hand') == 'bone_meal'",
                "event":"usebonemeal_event"
            },
            "minecraft:random_ticking":{
                "on_tick":{
                    "event":"grow_event"
                }
            }
        },
        "events":{
            "grow_event":{
                "randomize":[
                    {
                        "weight":1
                    },
                    {
                        "weight":1,
                        "set_block_property":{
                            "orecrops:growth":"(query.block_property('orecrops:growth')<7) ? query.block_property('orecrops:growth') + 1 : 7"
                        }
                    }
                ]
            },
            "harvest_event":{
                "spawn_loot":{
                    "table":"loot_tables/coal_crop.json"
                },
                "set_block_property":{
                    "orecrops:growth":"5"
                }
            },
            "usebonemeal_event":{
                "sequence":[
                    {
                        "decrement_stack":{
                            "ignore_game_mode":false
                        }
                    },
                    {
                        "run_command":{
                            "command":[
                                "particle minecraft:crop_growth_emitter ~ ~ ~"
                            ]
                        }
                    },
                    {
                        "trigger":{
                            "event":"grow_event"
                        }
                    }
                ]
            }
        },
        "permutations":[
            {
                "condition":"query.block_property('orecrops:growth') == 0",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_0",
                            "render_method":"alpha_test"
                        }
                    },
                    "minecraft:loot":"loot_tables/coal_seed.json"
                }
            },
            {
                "condition":"query.block_property('orecrops:growth') == 1",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_1",
                            "render_method":"alpha_test"
                        }
                    },
                    "minecraft:loot":"loot_tables/coal_seed.json"
                }
            },
            {
                "condition":"query.block_property('orecrops:growth') == 2",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_2",
                            "render_method":"alpha_test"
                        }
                    },
                    "minecraft:loot":"loot_tables/coal_seed.json"
                }
            },
            {
                "condition":"query.block_property('orecrops:growth') == 3",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_3",
                            "render_method":"alpha_test"
                        }
                    },
                    "minecraft:loot":"loot_tables/coal_seed.json"
                }
            },
            {
                "condition":"query.block_property('orecrops:growth') == 4",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_4",
                            "render_method":"alpha_test"
                        }
                    },
                    "minecraft:loot":"loot_tables/coal_seed.json"
                }
            },
            {
                "condition":"query.block_property('orecrops:growth') == 5",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_5",
                            "render_method":"alpha_test"
                        }
                    },
                    "minecraft:loot":"loot_tables/coal_seed.json"
                }
            },
            {
                "condition":"query.block_property('orecrops:growth') == 6",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_6",
                            "render_method":"alpha_test"
                        }
                    },
                    "minecraft:loot":"loot_tables/coal_seed.json"
                }
            },
            {
                "condition":"query.block_property('orecrops:growth') == 7",
                "components":{
                    "minecraft:material_instances":{
                        "*":{
                            "texture":"coal_crop_7",
                            "render_method":"alpha_test"
                        }
                    },
                    "minecraft:loot":"loot_tables/coal_crop.json",
                    "minecraft:on_interact":{
                        "event":"harvest_event"
                    }
                }
            }
        ]
    }
}

至此,种子与作物方块已经全部完成了,下面一章我们将学习使用自定义合成配方

合成种子

有序合成配方的基本结构

{
    "format_version":"1.12",
    "minecraft:recipe_shaped":{
        "description":{
            // 描述
        },
        "tags":[
            // 类别
        ],
        "pattern":[
            // 样式
        ],
        "key":{
            // 材料
        },
        "result":{
            // 成品
        }
    }
}

pattern:有序合成的物品摆放样式

key:使用字符代表物品,用在 pattern 中

// 写法1
"字符":"物品的标识"

//写法2
"字符":{
    "item": "物品的标识",
    "data": "物品的特殊值(支持 Molang)"
}

在 \BP\recipes 目录新建一个 coal_seed.json

看看下面 coal_seed.json 的例子就懂了 ——

{
    "format_version":"1.18.0",
    "minecraft:recipe_shaped": {
        "description":{
            "identifier": "orecrops:coal_seed"
        },
        "tags": ["crafting_table"],
        "pattern": [
            "OOO",
            "OSO",
            "OOO"
        ],
        "key": {
            "O": {
                "item": "minecraft:coal"
            },
            "S": {
                "item": "minecraft:wheat_seeds"
            }
        },
        "result":{
            "item": "orecrops:coal_seed"
        }
    }
}

向世界推广你的 Addon

为了适配不同语言的游戏,我们在很早就做好了本地化的准备。现在,如果你想增加一门语言的支持,只需要在 \RP\texts 目录新建一个 语言代号.lang,例如 en_US.lang

在这些语言文件中增加两行:

pack.description=资源包的描述
pack.name=矿石作物

修改你的包名和描述为 pack.name 和 pack.description

再新建一个文件 languages.json,输入:

[
    "zh_CN",
    "en_US"
]

这样就可以做到预读取语言文件,在不同语言下附加包的名称与描述都会变为与对应语言文件中对应的文本

参考与引用

本文在撰写过程中参考或引用了来自以下网站的文本

致谢

感谢以下组织、个人、网站和软件在教程编写过程中对本人提供的帮助