本篇教程的视频:

本篇教程源代码

GitHub地址:TutorialMod-Sign-1.21

介绍

告示牌在游戏中是一个可以写一些东西的方块实体

但要想添加像原版一样的告示牌,这并不简单,因为原版的告示牌在注册方块实体时是硬编码的(待会我们可以看一下源代码),得用Mixin来实现

不过好在,别人已经做好了这个工作,我们只需要调用他们的API就可以了

当然,你完全可以另起炉灶自己造一个告示牌,不过这样的话,就得从头到尾自己写一个方块实体及其屏幕了

这里我们将使用TerraForm API来实现告示牌的添加,之后我们也将使用它来添加箱子船

TerraForm API的GitHub地址:TerraForm API

查看源代码

在开始写之前,我们按照惯例来看看原版告示牌的注册方法

方块注册

1
2
3
4
5
6
7
public static final Block OAK_SIGN = register(
"oak_sign",
new SignBlock(
WoodType.OAK,
AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).solid().instrument(NoteBlockInstrument.BASS).noCollision().strength(1.0F).burnable()
)
);

这是方块注册,没有什么特别的地方,实例化的是SignBlock,这个类是告示牌的方块类

物品注册

1
public static final Item OAK_SIGN = register("oak_sign", new SignItem(new Item.Settings().maxCount(16), Blocks.OAK_SIGN, Blocks.OAK_WALL_SIGN));

这是物品注册,实例化的是SignItem,这个类是告示牌的物品类

后面填了两个方块,一个是告示牌,一个是墙上的告示牌,两个不同的方块状态对应同一个物品

同理,悬挂型HANGING)的告示牌也是如此

方块实体注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static final BlockEntityType<SignBlockEntity> SIGN = create(
"sign",
BlockEntityType.Builder.create(
SignBlockEntity::new,
Blocks.OAK_SIGN,
Blocks.SPRUCE_SIGN,
Blocks.BIRCH_SIGN,
Blocks.ACACIA_SIGN,
Blocks.CHERRY_SIGN,
Blocks.JUNGLE_SIGN,
Blocks.DARK_OAK_SIGN,
Blocks.OAK_WALL_SIGN,
Blocks.SPRUCE_WALL_SIGN,
Blocks.BIRCH_WALL_SIGN,
Blocks.ACACIA_WALL_SIGN,
Blocks.CHERRY_WALL_SIGN,
Blocks.JUNGLE_WALL_SIGN,
Blocks.DARK_OAK_WALL_SIGN,
Blocks.CRIMSON_SIGN,
Blocks.CRIMSON_WALL_SIGN,
Blocks.WARPED_SIGN,
Blocks.WARPED_WALL_SIGN,
Blocks.MANGROVE_SIGN,
Blocks.MANGROVE_WALL_SIGN,
Blocks.BAMBOO_SIGN,
Blocks.BAMBOO_WALL_SIGN
)
);

显然易见,因为BlockEntityType.Builder.create方法从第二个参数起,接受的是可变参数Block... blocks),也就是有多少个就写多少个

不过这样的硬编码也就导致如果我们想加自己的告示牌,就得写Mixin

如果说你不想写Mixin,那么就得用TerraForm API

准备工作

TerraForm API其实是一系列API的集合,我们打开它的仓库,可以看到有很多的API

我们这里只需要它的wood-api就可以了

而后我们往下翻,就能翻到它的使用教程,我们按照教程来做就可以了

添加maven仓库

1
2
3
4
5
6
repositories {
maven {
name = 'TerraformersMC'
url = 'https://maven.terraformersmc.com/'
}
}

把这段代码放到build.gradlerepositories

添加依赖

1
2
3
4
dependencies {
modImplementation "com.terraformersmc.terraform-api:terraform-wood-api-v1:11.0.0-alpha.1"
include "com.terraformersmc.terraform-api:terraform-wood-api-v1:11.0.0-alpha.1"
}

把这段代码放到build.gradledependencies

版本得自己去它的Maven仓库看,这里是11.0.0-alpha.1,不过,其实我们可以查看它的gradle.properties里面的版本,是一样的

由于当时制作视频教程的时候这里还是测试版,所以版本号是11.0.0-alpha.1,写这篇文章的时候已经是正式版了,版本号也可以直接使用11.0.0

include是让这个API打包的时候包括在我们的模组中,这样玩家游戏的时候也就不用再额外下载这个API

随后重载gradle项目,当然,重载完以后记得把genSource再跑一遍,因为每次重载都会将下载好的文件删除

添加告示牌

随后我们就可以开始添加告示牌了,当然,如果说你不知道怎么写,可以看看TerraForm API里面的示例代码

terraform-wood-api-v1里面找testmod即可,这里就不再赘述了

注册告示牌方块

这里我们先写三个材质文件的路径,指向我们的告示牌悬挂告示牌GUI的材质

1
2
3
public static final Identifier ICE_ETHER_SIGN_TEXTURE = Identifier.of(TutorialMod.MOD_ID, "entity/signs/ice_ether");
public static final Identifier ICE_ETHER_HANGING_SIGN_TEXTURE = Identifier.of(TutorialMod.MOD_ID, "entity/signs/hanging/ice_ether");
public static final Identifier ICE_ETHER_HANGING_SIGN_GUI = Identifier.of(TutorialMod.MOD_ID, "textures/gui/hanging_signs/ice_ether");

待会记得将对应的材质文件放到对应的路径下即可

而后我们来注册告示牌方块

1
2
3
4
5
6
7
8
9
10
11
public static final Block ICE_ETHER_SIGN = Registry.register(Registries.BLOCK, Identifier.of(TutorialMod.MOD_ID, "ice_ether_sign"),
new TerraformSignBlock(ICE_ETHER_SIGN_TEXTURE, AbstractBlock.Settings.copy(Blocks.OAK_SIGN)));

public static final Block ICE_ETHER_WALL_SIGN = Registry.register(Registries.BLOCK, Identifier.of(TutorialMod.MOD_ID, "ice_ether_wall_sign"),
new TerraformWallSignBlock(ICE_ETHER_SIGN_TEXTURE, AbstractBlock.Settings.copy(Blocks.OAK_WALL_SIGN)));

public static final Block ICE_ETHER_HANGING_SIGN = Registry.register(Registries.BLOCK, Identifier.of(TutorialMod.MOD_ID, "ice_ether_hanging_sign"),
new TerraformHangingSignBlock(ICE_ETHER_HANGING_SIGN_TEXTURE, ICE_ETHER_HANGING_SIGN_GUI, AbstractBlock.Settings.copy(Blocks.OAK_HANGING_SIGN)));

public static final Block ICE_ETHER_WALL_HANGING_SIGN = Registry.register(Registries.BLOCK, Identifier.of(TutorialMod.MOD_ID, "ice_ether_wall_hanging_sign"),
new TerraformWallHangingSignBlock(ICE_ETHER_HANGING_SIGN_TEXTURE, ICE_ETHER_HANGING_SIGN_GUI, AbstractBlock.Settings.copy(Blocks.OAK_WALL_HANGING_SIGN)));

这里我们注册了告示牌悬挂告示牌墙上告示牌墙上悬挂告示牌四个方块

注意我们并不是用之前的注册方法写的,而是直接使用Registry.register来注册

因为刚才我们也看到了,一个物品是对应两个方块的,所以物品我们待会再写

另外还需注意,这里实例化的方块是TerraformSignBlockWallSignBlockHangingSignBlockWallHangingSignBlock,不是原版的那些类

里面接受的参数是材质方块设置,这里我们直接copy了原版的方块设置

注册告示牌物品

1
2
3
4
5
6
public static final Item ICE_ETHER_SIGN = registerItems("ice_ether_sign",
new SignItem(new Item.Settings().maxCount(16), ModBlocks.ICE_ETHER_SIGN, ModBlocks.ICE_ETHER_WALL_SIGN));

public static final Item ICE_ETHER_HANGING_SIGN = registerItems("ice_ether_hanging_sign",
new HangingSignItem(ModBlocks.ICE_ETHER_HANGING_SIGN, ModBlocks.ICE_ETHER_WALL_HANGING_SIGN, new Item.Settings().maxCount(16)));

这里我们注册了告示牌悬挂告示牌的物品,填写两个对应的方块

不过,他们两个的参数顺序是不一样的,得注意一下,一个是Settings在前,一个在后

加入物品栏

1
2
entries.add(ModItems.ICE_ETHER_SIGN);
entries.add(ModItems.ICE_ETHER_HANGING_SIGN);

物品栏也是一样的,加入这两个物品

数据文件

方块组

接下来我们还得写方块组,这个是之前写过的,用于数据生成的

之前我们翻源代码的时候也看到了,那些木头衍生的方块有一个sign方法在里面,这个方法便是用于设置告示牌的

我们在ModBlockFamilies加入以下代码

1
2
3
4
5
public static final BlockFamily ICE_ETHER_WOOD = register(ModBlocks.ICE_ETHER_PLANKS)
.sign(ModBlocks.ICE_ETHER_SIGN, ModBlocks.ICE_ETHER_WALL_SIGN)
.group("wooden")
.unlockCriterionName("has_planks")
.build();

不过这里只有普通告示牌的,不包括悬挂告示牌,但悬挂告示牌的不用单独写,不会生成文件,但可以跑(我猜它直接写在API里面了,你也可以去看看它的源代码)

语言文件

1
2
translationBuilder.add(ModItems.ICE_ETHER_SIGN, "Ice Ether Sign");
translationBuilder.add(ModItems.ICE_ETHER_HANGING_SIGN, "Ice Ether Hanging Sign");

只需要写物品的语言文件即可

模型文件

模型文件就写悬挂告示牌的物品模型即可

1
itemModelGenerator.register(ModItems.ICE_ETHER_HANGING_SIGN, Models.GENERATED);

这里我们用的是GENERATED

另外,原有的ICE_ETHER_PLANKS已经加入了方块组,所以得去掉,不然就重复生成会报错

不过,悬挂告示牌的模型文件不会生成,也没有对应的模型或者方块状态文件,破坏的粒子有一定的问题(不知道正式版有没有修好)

而后,跑完数据生成就可以启动游戏了