我的世界Java版1.21.4的Fabric模组开发教程(十一)创建方块

这是适用于Minecraft Java版1.21.4的Fabric模组开发系列教程专栏第十一章------创建方块。想要阅读其他内容,请查看或订阅上面的专栏。

方块(Block) 是构成Minecraft世界的主要组成部分,是组成游戏地图的最基本单元,也是模组开发的核心元素之一。

与创建物品类似,方块同样也需要在游戏注册表中注册,也同样需要创建对应的模型文件、模型描述文件和方块纹理。方块的复杂程度要高于物品,因此方块需要创建更多的配置文件来完成方块各种功能的设置。如果是首次阅读到本文且没有Fabric模组开发基础,请先访问我的世界Java版1.21.4的Fabric模组开发教程(二)创建物品

在本章,我们将创建一个自定义方块------浓缩泥土(condensed_dirt)。文章将先以最简单方块的形式详细讲解创建方块的步骤,然后在最简单方块的基础上,拓展更多关于方块其他功能的配置方式。

通常,如果是首次创建方块,以最简单的方块为例,整个过程应当按照以下步骤推进:

  • 创建方块注册类;
  • 封装register()方法;
  • 注册方块并将其添加到指定物品组中;
  • 在语言文件中为方块添加翻译键值对;
  • 创建方块的模型文件、模型描述文件和方块纹理;
  • 创建方块状态定义文件;

此外还可以为方块:

  • 配置掉落物;
  • 配置挖掘工具。

创建方块注册类

对于简单的方块,我们可以直接将其在游戏注册表中注册。不过,在此之前可以提前封装Minecraft API中提供的Registry.register()方法,使注册过程更加简单。

一般,方块注册类中有三种内容:

  • register():封装了Registry.register()方法并用于注册方块的核心方法,将在下一小节详细讲解;
  • initialize():用于初始化方块注册类,需要在入口点类中调用;
  • 类型为Block的方块注册静态常量:用于注册自定义方块。

1.在com/example/test/utils目录中创建ModBlocks.java,作为方块注册类;

java 复制代码
public class ModBlocks {}

2.声明静态方法register(),用于注册方块;

java 复制代码
public static Block register(){}

下一小节将详细讲解方法体中的内容;

3.声明静态方法initialize(),用于初始化方块注册类;

java 复制代码
public static void initialize(){
    Test.LOGGER.info("注册方块!");
}

其中可以输出日志信息;

4.在入口点类的onInitialize()方法中调用ModBlocks.initialize(),完成方块注册类的初始化;

java 复制代码
@Override
public void onInitialize() {
	...
	ModBlocks.initialize();
	...
}

封装register()方法

根据Fabric官方文档所述,应当使用下面的写法封装Registry.register()方法,来简化注册方块的代码;

java 复制代码
private static Block register(String name, Function<AbstractBlock.Settings, Block> blockFactory, AbstractBlock.Settings settings, boolean shouldRegisterItem) {
    // Create a registry key for the block
    RegistryKey<Block> blockKey = RegistryKey.of(RegistryKeys.BLOCK, Identifier.of(FabricDocsReference.MOD_ID, name));
    // Create the block instance
    Block block = blockFactory.apply(settings.registryKey(blockKey));

    // Sometimes, you may not want to register an item for the block.
    // Eg: if it's a technical block like `minecraft:moving_piston` or `minecraft:end_gateway`
    if (shouldRegisterItem) {
        // Items need to be registered with a different type of registry key, but the ID can be the same.
        RegistryKey<Item> itemKey = RegistryKey.of(RegistryKeys.ITEM, Identifier.of(FabricDocsReference.MOD_ID, name));

        BlockItem blockItem = new BlockItem(block, new Item.Settings().registryKey(itemKey));
        Registry.register(Registries.ITEM, itemKey, blockItem);
    }

    return Registry.register(Registries.BLOCK, blockKey, block);
}

方法中需要传递四个参数:

  • String name:指定方块名,即标识符中的路径;
  • Function<AbstractBlock.Settings, Block> blockFactory:抽象方块设置内部类对象和方块对象的函数表达式,仅用于创建Block对象;
  • AbstractBlock.Settings settings:抽象方块设置内部类对象,可以用于配置方的属性;
  • boolean shouldRegisterItem:指定是否需要为方块注册方块物品,使其可以在创造模式物品栏中显示;

方法首先使用RegistryKey.of()方法获取方块注册键对象,其中按顺序传递了注册键为方块RegistryKeys.BLOCK和由模组Id和方块路径组成的Identifier标识符对象。然后通过RegistryKey<Block>注册键创建方块Block对象。至此,方块对象创建完毕;

接着,根据shouldRegisterItem变量的值,来确定是否需要注册方块对应的方块物品。如果需要注册,则再次使用RegistryKey.of()方法获取物品的注册键对象,其中按顺序传递了注册键为物品RegistryKeys.Item和由模组Id和方块路径组成的Identifier标识符对象。然后调用BlockItem类的构造方法来创建方块物品BlockItem对象,方法中按顺序传递了方块对象和物品注册键对象。最后调用Registry.register()方法将方块物品在游戏注册表中注册,方法中按顺序传递了注册键常量Registries.ITEM、方块物品注册键对象和方块物品对象;

如果不需要注册方块物品,则直接调用Registry.register()方法将方块在游戏注册表中注册,方法中按顺序传递了注册键常量Registries.BLOCK、方块注册键对象和方块对象。

关于IdentifierRegistry类的详细用法说明请参考我的世界Java版1.21.4的Fabric模组开发教程(二)创建物品;关于RegistryKey.of()方法的详细用法说明请参考我的世界Java版1.21.4的Fabric模组开发教程(五)创建高级物品:盔甲


方块类Block

Block类是Minecraft中所有方块的基类,定义了方块的核心行为和属性 。通常,创建带有复杂自定义行为和属性的方块时,可以创建继承了Block类的自定义方块类。在游戏中,同一类型的方块共享同一个Block实例,例如,一个世界中的所有石头方块只共享一个石头方块实例,而不是为每一个石头方块都创建实例。创建方块对象后对应的方块物品对象不会自动创建,创建方块物品对象还需调用Registy.register()方法。

Block类中提供了许多方法,可以在涉及到方块的任何场景调用:

  • asItem():方法返回与方块对应的物品对象;

在后续章节中用到的方法将在此处补充。

抽象方块类AbstractBlock及其设置内部类AbstractBlock.Settings

AbstractBlock作为一个抽象类,定义了所有方块的基础属性和通用行为AbstractBlockBlock类的父类,但AbstractBlock不能直接继承自定义方块类。

方块的自定义属性由内部类AbstractBlock.Settings的实例控制,其构造方法已经被私有化,想要创建AbstractBlock.Settings的实例,只能调用其静态方法create(),直接返回一个内部类AbstractBlock.Settings的实例;

java 复制代码
public static AbstractBlock.Settings create() {
	return new AbstractBlock.Settings();
}

AbstractBlock.Settings类中提供了许多方法来配置方块的属性,所有方法均支持链式编程,包括:

  • requiresTool():配置方块只能由工具采集;
  • sounds():配置方块与玩家交互的声音,通常传递一个BlockSoundGroup类中的静态常量;
  • hardness():指定方块硬度。参考值:橡木木板2.0f;

在后续章节中用到的方法将在此处补充。

方块物品类BlockItem

BlockItem类继承了Item类,用于将方块和物品关联起来,使得方块能够以物品的形式存在于玩家的背包、快捷栏或合成表中,并允许玩家在世界中通过方块物品来使用方块。

一般,调用其构造方法来创建BlockItem类的对象;

java 复制代码
public BlockItem(Block block, Item.Settings settings) {
	super(settings);
	this.block = block;
}

其中需要传递两个参数:


直接将register()方法体复制到方块注册类ModBlocks.javaregister()方法中,然后将访问修饰符改为private

注册方块并将其添加到指定物品组中

现在,我们将方块"浓缩泥土"在游戏注册表中注册,然后将其方块物品添加到物品组中。方块注册逻辑可以写在方块注册类ModBlocks.java中,但将方块物品添加到物品组的逻辑依然需要写在入口点类中。

1.在ModBlocks.java中声明静态常量CONDENSED_DIRT,类型为Block,并调用register()方法对其初始化;

java 复制代码
public static final Block CONDENSED_DIRT = register(
        "condensed_dirt",
        Block::new,
        AbstractBlock.Settings.create().sounds(BlockSoundGroup.GRASS),
        true
);

按顺序依次设置了物品名为"condensed_dirt"、抽象方块设置内部类对象和方块对象的函数式Block::new、交互声音为BlockSoundGroup.GRASS并要求注册方块对应的方块物品。

2.在入口点类的onInitialize()方法中,将方块添加到指定物品组中;

java 复制代码
ItemGroupEvents.modifyEntriesEvent(CUSTOM_ITEM_GROUP_KEY)
		.register((itemGroup) -> {
			...
			itemGroup.add(ModBlocks.CONDENSED_DIRT.asItem());
			...
		});

需要调用asItem()方法将方块转换为物品。

在语言文件中为方块添加翻译键值对

打开语言文件zh-cn.json,为方块添加中文翻译;

json 复制代码
{
	...
	"item.test.condensed_dirt": "浓缩泥土",
	...
}

"condensed_dirt"为注册方块时使用的路径名。

创建方块的模型文件、模型描述文件和方块纹理

同物品一样,方块也需要创建模型文件、模型描述文件和对应的方块纹理。但是这些配置文件和物品的配置文件存放的位置不同。如果是首次创建自定义方块,可能需要创建新的目录。

1.在assets/test/models目录中创建block目录,用于存放方块的模型文件。在目录中创建condensed_dirt.json

java 复制代码
{
	"parent": "minecraft:block/cube_all",
	"textures": {
		"all": "test:block/condensed_dirt"
	}
}

此时我们使用的模型为block/cube_alltextures配置项中,需要添加all配置项,值为test:block/condensed_dirt,即"模组Id+:block/+标识符",代表方块的所有面应用的纹理图位置;

2.在assets/test/items中创建condensed_dirt.json,代表方块的模型描述文件;

json 复制代码
{
	"model": {
		"type": "minecraft:model",
		"model": "test:block/condensed_dirt"
	}
}

此处与物品模型描述文件的写法大致相同;

3.在assets/test/textures目录中创建block目录,将方块纹理图移动到目录中;

图片大小为16*16,文件名为"condensed_dirt.png",即方块路径名。不能使用其他格式的图片, 只能使用.png文件。

创建方块状态定义文件

方块状态定义用于指示游戏基于当前方块的状态要渲染哪个模型。目前,还不需要编程式的方块状态定义,只需要创建方块状态定义JSON文件即可。

"浓缩泥土"方块并没有复杂的状态,方块状态定义文件中只需要添加一条配置项;

assets/test目录中创建blockstates目录,用于存放方块的状态定义文件。在其中创建condensed_dirt.json,文件名应当与方块路径名相同;

json 复制代码
{
	"variants": {
		"": {
			"model": "test:block/condensed_dirt"
		}
	}
}

其中的配置项包含:

  • "variants":设置变种与对应的模型,内部需要列出此方块的所有变种;
    • "":变种名。不含有方块属性的方块状态使用""作为变种名;
      • "model":指定模型文件的标识符;

其中有更多的配置项,将在后续章节详细讲解关于方块状态的知识。

启动游戏测试

现在,我们打开游戏测试一下"浓缩泥土"方块的各种功能。

1.启动游戏,打开创造模式物品栏,找到"浓缩泥土";

可以看到方块物品已经成功注册,方块纹理和中文名称显示正常。将其添加到背包,然后主手持"浓缩泥土",右键点击使用方块;

可以看到方块显示正常。

至此,一个最简单的方块已经创建完毕。如果想给方块添加更多自定义功能和属性,还请继续阅读下文。

添加方块的掉落物/战利品列表

现在,无论是在创造模式,还是生存模式,使用任何工具或徒手破坏方块都不会出现掉落物。我们可以为其添加掉落物 ,由于某些方块破坏后掉落的东西不止一种,方块的掉落物也称之为战利品列表

在开始前,确保你的项目已经启用数据生成(即使不使用数据生成类)。关于启用项目的数据生成说明,请参考我的世界Java版1.21.4的Fabric模组开发教程(二)创建物品中的"为物品添加合成配方"小节。

data/test目录中创建loot_table目录,用于存放方块战利品列表JSON配置文件,在其中创建blocks文件夹,代表方块的掉落物/战利品列表JSON配置文件,然后继续在其中创建condensed_dirt.json,文件名与方块注册时使用的路径相同。

对于"浓缩泥土"方块,破坏方块时只需掉落其本身即可,其配置文件的写法应当如下:

json 复制代码
{
	"type": "minecraft:block",
	"pools": [
		{
			"rolls": 1,
			"entries": [
				{
					"type": "minecraft:item",
					"name": "test:condensed_dirt"
				}
				
			],
			"conditions": [
				{
					"condition": "minecraft:survives_explosion"
				}
			]
		}
	]
}

其中的配置项包含:

  • "type":战利品上下文的参数集类型。指定了调用该战利品时要应用的上下文环境,用于验证其他配置项的合法性,当某些配置错误或缺失时,游戏日志中会打印警告信息;
  • "pools":战利品表的随机池的列表。主要定义了若干待选的抽取项;
    • "rolls":指定该随机池的抽取次数;
    • "entries":指定随机池中的抽取项。抽取项分为单一抽取项和复合抽取项,单一抽取项定义了单个物品生成行为,是随机池中最终要抽取的带权重的项目。如果不使用物品修饰器,物品数量默认为1。此处我们使用的是单一抽取项,下面给出类型为item的战利品池抽取项的数据格式:
      • "type""minecraft:item"
      • "name":物品的标识符;
    • "conditions":战利品表谓词列表。仅当满足列表中的所有条件时,该随机池才会被使用;
      • "condition":战利品表谓词,又称战利品表物品条件,用于在战利品表中制定战利品的产生条件。此处使用了"minecraft:survives_explosion",代表物品可以通过爆炸掉落;

启动游戏,在创造模式下将"浓缩泥土"放入背包,然后切换为生存模式,放置方块,然后破坏方块,可以看到掉落物。

配置推荐的挖掘工具

如果想限制挖掘方块的工具,可以继续添加配置文件。例如,这里我们令"浓缩泥土"只能由锹类工具挖掘时才会掉落。

data目录中创建minecraft文件夹,然后在其中依次创建tag/block/mineable目录,最后创建shovel.json

配置文件中的结构如下:

json 复制代码
{
	"values": ["test:condensed_dirt"]
}

"values"配置项中直接提供方块的标识符。将"浓缩泥土"的标识符添加到文件中,代表只能使用锹挖掘方块才能获得掉落物,否则挖掘速度将很慢且没有掉落物;

shovel.json文件中存放推荐使用锹类工具破坏的方块的集合。此外,还有其他配置文件:

  • hoe.json:推荐使用锄类工具破坏;
  • axe.json:推荐使用斧类工具破坏;
  • pickaxe.json:推荐使用镐类工具破坏;

这些文件和Minecraft原生配置文件的文件名和文件位置相同,数据将会追加到原生配置文件中,而不是完全替换原生配置文件。

配置指定的工具等级

如果想限制挖掘方块所用工具的材质级别,可以继续添加配置文件。例如,这里我们令"浓缩泥土"只能由"铁锹"及以上的材料(钻石锹、下界合金锹)挖掘时才会掉落。

data/minecraft/tags/block目录中创建needs_diamond_tool.json,文件结构与文的shovel.json相同;

json 复制代码
{
	"values": ["test:condensed_dirt"]
}

为了演示效果,我们调用hardness()方法为方块设置硬度,使其破坏需要一定时间。找到ModBlocks.java,修改register()方法中的参数;

java 复制代码
public static final Block CONDENSED_DIRT = register(
        "condensed_dirt",
        Block::new,
        AbstractBlock.Settings.create()
                .sounds(BlockSoundGroup.GRASS)
                .requiresTool()
                .hardness(2.5f),
        true
);

将硬度改为2.5。启动游戏,使用铁锹破坏方块;

可以看到掉落物。使用钻石锹或下界合金锹破坏方块也可以获得掉落物。

本章小结

本章详细阐述了创建一个自定义方块的步骤。本文篇幅较长,但难度一般,阅读本文要求开发者有创建物品的知识基础,才能理解文中的部分写法。感谢各位的阅读,有兴趣可以订阅此专栏!

相关推荐
MyikJ1 小时前
Java求职面试:从Spring到微服务的技术挑战
java·数据库·spring boot·spring cloud·微服务·orm·面试技巧
MyikJ1 小时前
Java 面试实录:从Spring到微服务的技术探讨
java·spring boot·微服务·kafka·spring security·grafana·prometheus
ShiinaMashirol1 小时前
代码随想录打卡|Day50 图论(拓扑排序精讲 、dijkstra(朴素版)精讲 )
java·图论
cui_hao_nan2 小时前
Nacos实战——动态 IP 黑名单过滤
java
惜.己2 小时前
MySql(十一)
java·javascript·数据库
10000hours2 小时前
【存储基础】NUMA架构
java·开发语言·架构
伍六星3 小时前
动态拼接内容
java·jsp
TeamDev3 小时前
从 SWT Browser 迁移到 JxBrowser
java·前端·eclipse
迢迢星万里灬3 小时前
Java求职者面试指南:DevOps技术栈深度解析
java·ci/cd·docker·kubernetes·jenkins·devops
oioihoii4 小时前
C++23 已移除特性解析
java·jvm·c++23