Skip to content

自定义农作物方块 ​

自定义农作物方块支持多阶段生长,可以实现类似小麦、胡萝卜的种植机制。中国版提供两种实现方式:纯 JSON 配置(netease:transform)和脚本控制(netease:random_tick + netease:block_entity)。你可以根据需求灵活选择。

前置条件

本功能不需要开启实验性玩法。请先阅读 自定义基础方块 了解方块注册流程和 JSON 组件基础。方式二(脚本控制)还需要了解 Python 脚本开发 的基本用法。

概述 ​

自定义农作物的核心思路是:将每个生长阶段定义为独立的方块,通过条件触发方块之间的转换来模拟生长。一套完整的农作物通常包括:

  • 种子物品 — 玩家手持种子右键耕地时种下
  • 多个阶段方块 — 从幼苗到成熟,每个阶段是一个独立的自定义方块
  • 收获掉落物 — 成熟阶段方块被破坏时掉落果实和种子

两种实现方式对比:

特性方式一:纯 JSON方式二:脚本控制
base_blockcustom_crop_block不需要
生长驱动netease:transform 组件BlockRandomTickServerEvent 事件
转换条件光照、随机刻次数、周围方块脚本中自由判断任意条件
灵活度适合简单线性生长适合复杂逻辑(天气、季节、施肥等)
脚本依赖不需要 Python 脚本需要 Python 脚本

方式一:纯 JSON 配置(netease:transform) ​

base_block 设置 ​

每个生长阶段方块的 description 中,base_block 需要设为 custom_crop_block。这使引擎将方块识别为农作物类型,并启用 netease:transform 驱动的方块转换功能。

netease:transform 组件 ​

键类型默认值说明
conditionsdict—必填,方块转换条件,所有子条件同时满足时触发转换
resultstring—必填,转换后的目标方块标识符

conditions 子条件:

条件键类型说明
brightnessdict光照条件。min/max 定义光照等级范围(0~15),方块位置光照在此范围内时满足
random_tick_countdict随机刻次数。value 表示在第 N+1 次随机刻时触发转化,值必须 > 0
surroudingdict周围方块条件。value 为方块标识符,radius 为检测半径,检测范围内存在该方块时满足

拼写注意

surrouding 是引擎内部的固定拼写(少了一个 n),请勿写成 surrounding,否则条件不会生效。

种子物品定义 ​

种子使用 minecraft:seed 组件,定义在行为包的 netease_items_beh/ 目录中:

json
{
    "format_version": "1.10",
    "minecraft:item": {
        "description": {
            "identifier": "mymod:tomato_seeds",
            "category": "Nature",
            "register_to_create_menu": true
        },
        "components": {
            "minecraft:seed": {
                "crop_result": "mymod:tomato_stage0",
                "plant_at": "minecraft:farmland"
            }
        }
    }
}
键类型说明
crop_resultstring种子种下后生成的方块(第一阶段)
plant_atstring种子只能种植在该方块上

种植后,所有生长阶段的下方方块也必须为 plant_at 指定的方块,否则农作物会被自动破坏(类似原版小麦在耕地被踩坏后掉落)。

完整 JSON 示例(方式一) ​

以下示例创建一套三阶段番茄农作物:种子 → 阶段0(幼苗)→ 阶段1(生长中)→ 阶段2(成熟)。

种子物品 ​

文件路径:行为包/netease_items_beh/tomato_seeds.json

json
{
    "format_version": "1.10",
    "minecraft:item": {
        "description": {
            "identifier": "mymod:tomato_seeds",
            "category": "Nature",
            "register_to_create_menu": true
        },
        "components": {
            "minecraft:seed": {
                "crop_result": "mymod:tomato_stage0",
                "plant_at": "minecraft:farmland"
            }
        }
    }
}

阶段 0 — 幼苗 ​

文件路径:行为包/netease_blocks/tomato_stage0.json

json
{
    "format_version": "1.10.0",
    "minecraft:block": {
        "description": {
            "identifier": "mymod:tomato_stage0",
            "base_block": "custom_crop_block",
            "register_to_create_menu": false
        },
        "components": {
            "minecraft:block_light_absorption": { "value": 0 },
            "netease:render_layer": { "value": "alpha" },
            "netease:aabb": {
                "collision": {
                    "min": [0.0, 0.0, 0.0],
                    "max": [1.0, 0.3, 1.0]
                },
                "clip": {
                    "min": [0.0, 0.0, 0.0],
                    "max": [1.0, 0.3, 1.0]
                }
            },
            "netease:transform": {
                "conditions": {
                    "brightness": { "min": 9, "max": 15 },
                    "random_tick_count": { "value": 1 },
                    "surrouding": { "value": "minecraft:farmland", "radius": 1 }
                },
                "result": "mymod:tomato_stage1"
            }
        }
    }
}

阶段 1 — 生长中 ​

文件路径:行为包/netease_blocks/tomato_stage1.json

json
{
    "format_version": "1.10.0",
    "minecraft:block": {
        "description": {
            "identifier": "mymod:tomato_stage1",
            "base_block": "custom_crop_block",
            "register_to_create_menu": false
        },
        "components": {
            "minecraft:block_light_absorption": { "value": 0 },
            "netease:render_layer": { "value": "alpha" },
            "netease:aabb": {
                "collision": {
                    "min": [0.0, 0.0, 0.0],
                    "max": [1.0, 0.6, 1.0]
                },
                "clip": {
                    "min": [0.0, 0.0, 0.0],
                    "max": [1.0, 0.6, 1.0]
                }
            },
            "netease:transform": {
                "conditions": {
                    "brightness": { "min": 9, "max": 15 },
                    "random_tick_count": { "value": 2 },
                    "surrouding": { "value": "minecraft:farmland", "radius": 1 }
                },
                "result": "mymod:tomato_stage2"
            }
        }
    }
}

阶段 2 — 成熟 ​

文件路径:行为包/netease_blocks/tomato_stage2.json

json
{
    "format_version": "1.10.0",
    "minecraft:block": {
        "description": {
            "identifier": "mymod:tomato_stage2",
            "base_block": "custom_crop_block",
            "register_to_create_menu": false
        },
        "components": {
            "minecraft:block_light_absorption": { "value": 0 },
            "netease:render_layer": { "value": "alpha" },
            "netease:aabb": {
                "collision": {
                    "min": [0.0, 0.0, 0.0],
                    "max": [1.0, 1.0, 1.0]
                },
                "clip": {
                    "min": [0.0, 0.0, 0.0],
                    "max": [1.0, 1.0, 1.0]
                }
            },
            "minecraft:loot": {
                "value": "loot_tables/blocks/tomato_harvest.json"
            }
        }
    }
}

掉落表 ​

文件路径:行为包/loot_tables/blocks/tomato_harvest.json

json
{
    "pools": [
        {
            "rolls": 1,
            "entries": [
                {
                    "type": "item",
                    "name": "mymod:tomato_seeds",
                    "weight": 1,
                    "functions": [
                        { "function": "set_count", "count": { "min": 1, "max": 2 } }
                    ]
                }
            ]
        }
    ]
}

方式二:脚本控制(netease:random_tick + netease:block_entity) ​

方式二不需要设置 base_block 为 custom_crop_block,生长逻辑完全由 Python 脚本控制。这种方式灵活度更高,可以自定义任意生长条件(天气、时间、施肥、附近水源等)。

方块 JSON 定义 ​

每个阶段方块需要配置 netease:random_tick 和 netease:block_entity 组件:

文件路径:行为包/netease_blocks/script_crop_stage0.json

json
{
    "format_version": "1.10.0",
    "minecraft:block": {
        "description": {
            "identifier": "mymod:script_crop_stage0",
            "register_to_create_menu": false
        },
        "components": {
            "minecraft:block_light_absorption": { "value": 0 },
            "netease:render_layer": { "value": "alpha" },
            "netease:random_tick": {
                "enable": true,
                "tick_to_script": true
            },
            "netease:block_entity": {
                "tick": false,
                "movable": true
            },
            "netease:neighborchanged_sendto_script": { "value": true },
            "netease:redstone_property": { "value": "break_on_push" }
        }
    }
}

Python 脚本示例 ​

python
import server.extraServerApi as serverApi
ServerSystem = serverApi.GetServerSystemCls()

class CropServer(ServerSystem):
    def __init__(self, namespace, systemName):
        super(CropServer, self).__init__(namespace, systemName)
        engineNs = serverApi.GetEngineNamespace()
        engineSys = serverApi.GetEngineSystemName()
        self.ListenForEvent(engineNs, engineSys,
            'BlockRandomTickServerEvent', self, self.OnRandomTick)

    def OnRandomTick(self, args):
        blockName = args["blockName"]
        pos = (args["posX"], args["posY"], args["posZ"])
        dimensionId = args["dimensionId"]

        if blockName != "mymod:script_crop_stage0":
            return

        # 获取方块实体数据,记录生长进度
        comp = serverApi.GetEngineCompFactory().CreateBlockEntityData(self.levelId)
        blockEntityData = comp.GetBlockEntityData(dimensionId, pos)
        if not blockEntityData:
            return

        growth = blockEntityData.get("growth", 0)
        growth += 1
        blockEntityData["growth"] = growth

        # 判断光照条件
        blockInfoComp = serverApi.GetEngineCompFactory().CreateBlockInfo(self.levelId)
        # 自定义条件:生长计数达到 3 时切换到下一阶段
        if growth >= 3:
            blockDict = {
                'name': 'mymod:script_crop_stage1',
                'aux': 0
            }
            blockInfoComp.SetBlockNew(pos, blockDict, dimensionId=dimensionId)

方式二的优势

脚本控制方式可以实现更复杂的生长逻辑,例如:根据时间段决定是否生长、根据附近水源加速生长、实现施肥功能等。代价是需要编写和维护 Python 脚本。

农作物外观 ​

农作物方块可以使用自定义方块模型配置外观。建议所有阶段共用同一个模型工程,仅更换贴图纹理。也可以使用交叉贴图方块的方式配置十字交叉贴图外观,类似原版小麦。

常见问题 ​

农作物不生长 ​

排查步骤(方式一):

  1. 确认 base_block 设为 custom_crop_block
  2. 确认 netease:transform 的 conditions 中各子条件拼写正确(特别是 surrouding)
  3. 确认方块位置的光照等级在 brightness 范围内
  4. 确认方块下方存在 surrouding 指定的方块
  5. 随机刻触发是概率性的,可能需要等待较长时间

排查步骤(方式二):

  1. 确认 netease:random_tick 的 enable 和 tick_to_script 均为 true
  2. 确认 Python 脚本正确监听了 BlockRandomTickServerEvent
  3. 确认脚本中的方块名匹配正确

种子无法种植 ​

原因: minecraft:seed 组件的 plant_at 字段指定了种植基底方块。确认玩家右键的方块与 plant_at 一致(通常为 minecraft:farmland)。

农作物在生长过程中自动掉落 ​

原因: 农作物下方的基底方块被破坏或改变。使用方式一时,所有阶段下方必须始终存在 plant_at 指定的方块。

下一步 ​