物品栏 1.21 Fabric
本篇教程的视频:
本篇教程源代码:
GitHub地址:TutorialMod-ItemGroup-1.21
Fabric API方法
介绍
Fabric API提供了能将我们的物品加入原版物品栏的方法,本质上使用的是Mixin。
不过,一旦你的模组里面使用了Fabric API,那么你的模组就需要这个API运行,打包之后放到真正的游戏中就要安装Fabric API。
使用方法
Fabric API提供了一个FabricItemGroupEntries
类,
我们先将物品加入到这个entries中,再由ItemGroupEvents
添加至原版物品栏
添加物品
1 | private static void addItemToIG(FabricItemGroupEntries fabricItemGroupEntries){ |
这里我们先创建一个方法,将我们的物品加入到entries中。
添加至原版物品栏
然后我们将之前创建的物品加入到entries中,这里我们使用的是ICE_ETHER
。
1 | ItemGroupEvents.modifyEntriesEvent(ItemGroups.INGREDIENTS).register(ModItems::addItemToIG); |
在之前写的初始化方法registerModItems
中添加这一行代码,这样我们的物品就会被加入到原版的材料物品栏中。
modifyEntriesEvent
方法的参数是一个ItemGroup
,这里我们使用的是ItemGroups.INGREDIENTS
,这个是原版的材料物品栏。
具体其他的物品栏可以查看ItemGroups
类。(注意,你需要genSource才能够正确调用ItemGroups
中的字段)
后面的register
方法直接引用我们之前创建的方法即可。
举一反三
那如果说我现在还有一个物品,想加入到原版的杂项(MISC)物品栏中,应该怎么做呢?
1 | private static void addItemToIG2(FabricItemGroupEntries fabricItemGroupEntries){ |
这里我们再创建一个方法,与之前的方法类似,将我们的物品加入到entries中。
添加多个物品直接用add
方法即可。
1 | ItemGroupEvents.modifyEntriesEvent(ItemGroups.MISC).register(ModItems::addItemToIG2); |
那么同样的,使用不同的物品栏,只需要将ItemGroups.INGREDIENTS
替换成ItemGroups.MISC
即可。
然后再引用addItemToIG2
方法即可。`
原版方法
介绍
使用Fabric API并不能创建自定义的物品栏,只能将物品加入到原版的物品栏中。
所以说如果想要创建自定义的物品栏,还是需要使用原版的方法。
查看源代码
我们先来看看原版是如何添加物品到物品栏的。上面也提到过了,原版物品栏的注册在ItemGroups
类中。
1 | public static final RegistryKey<ItemGroup> INGREDIENTS = ItemGroups.register("ingredients"); |
首先我们看到它的注册,这里使用的是ItemGroups.register
方法,这个方法是一个静态方法,返回一个RegistryKey<ItemGroup>
。
1 | private static RegistryKey<ItemGroup> register(String id) { |
看着这个方法的返回语句,是否和之前物品的注册有些类似呢?是的没错,同样的,Identifier
要我们自行更改
那么除此之外,还有什么要注意的呢?我们可以看到registerAndGetDefault
方法中一堆的entries.add(...)
那么这些东西便是将物品加入到物品栏的方法了
1 | Registry.register(registry, INGREDIENTS, |
这里我们以INGREDIENTS
为例,我们可以看到它使用的是Registry.register
方法,这个方法是用来注册物品栏的
但是首先我们得知道这个registry
应该写什么,其实它就是Registries.ITEM_GROUP
,这个是原版的物品栏注册器
1 | public static final Registry<ItemGroup> ITEM_GROUP = Registries.create(RegistryKeys.ITEM_GROUP, ItemGroups::registerAndGetDefault); |
我们在Registries
类中可以看到,ITEM_GROUP
是一个Registry<ItemGroup>
类型的常量,创建的时候使用的是registerAndGetDefault
方法
而我们自己写的时候直接使用Registries.ITEM_GROUP
即可
那么接下来,我们看到INGREDIENTS
的第二个参数是INGREDIENTS
,这个是一个RegistryKey<ItemGroup>
类型的常量,这个是物品栏的ID
然后我们看到ItemGroup.create
方法,这个方法是用来创建物品栏的,里面有一些参数,比如ItemGroup.Row.BOTTOM
,这个是指物品栏所在的位置,这里的BOTTOM
表示它在GUI的下面那行中,3
是指在第4个;
那么其他的还有ItemGroup.Row.TOP
,这个是指在GUI的上面那行中
我们接着看displayName
方法,这个是用来设置物品栏的名字的,这里使用的是Text.translatable
方法,这个方法是用来设置物品栏名字的,这里使用的是itemGroup.ingredients
,这个是一个翻译键,我们可以在语言文件中找到这个翻译键,然后设置物品栏的名字
然后我们看icon
方法,这个是用来设置物品栏的图标的,这里使用的是Items.IRON_INGOT
,这个是物品栏的图标,这里使用的是铁锭
entries
方法是用来设置物品栏的物品的,这里使用的是一个lambda表达式,这个lambda表达式有两个参数,
一个是displayContext
,一个是entries
,这个displayContext
是用来设置物品栏的显示的,这里没有用到,entries
是用来设置物品栏的物品的,这里的东西省略了,我们就不展开了
创建ModItemGroups类
1 | public class ModItemGroups { |
注册方法
1 | private static RegistryKey<ItemGroup> register(String id) { |
那么Identifier
同样的还是要改
注册物品栏Key
1 | public static final RegistryKey<ItemGroup> TUTORIAL_GROUP = register("tutorial_group"); |
这里的都是仿照原版在编写
初始化注册方法
1 | public static void registerModItemGroups() { |
不要忘记到主类调用这个初始化方法
1 | ModItemGroups.registerModItemGroups(); |
注册物品栏
这个语句直接写在初始化注册方法中就好了,这样在模组初始化时就可以注册完成
1 | Registry.register(Registries.ITEM_GROUP, TUTORIAL_GROUP, |
这个就是和原版一模一样的语句,不同的地方在于第一个参数我们直接用了Registries.ITEM_GROUP
而ItemGroup.create
方法里面的参数,不要和原版重叠(虽然我没试过会发生什么),然后具体的位置其实可以在确定有多少个物品栏之后再写。
实际情况是,如果前面空着,比如说我里面的参数写8
,但7
的位置没有东西,那么你新增的物品栏的位置还是7
。TOP
和BOTTOM
同理,前者补完补后者
简化?YES
是不是觉得还是很复杂?能不能简化呢?当然可以(不过有个弊端,后面dataGen跑语言文件生成的时候就不能直接调写的KEY了,不过直接复制displayName
也一样)
这里我们就要利用返回值为ItemGroup
这个特性,还记得源代码里面registerAndGetDefault
方法的返回值吗?没错,它就是ItemGroup
所以在这里,我们依旧可以选择让它修饰为和Item
一样的static final
,利用初始化完成注册
1 | public static final ItemGroup TUTORIAL_GROUP = Registry.register(Registries.ITEM_GROUP, Identifier.of(TutorialMod.MOD_ID, "tutorial_group"), |
中间的Identifier
直接写你的MOD_ID
和id
即可
然后我这里的ItemGroup.create
直接使用null
和-1
,这个就直接让它填在最后一个位置上,如果你使用FabricItemGroup
进行创建,它就是这样写的
这样就可以简化很多,另外你也可以添加原版中有的物品,比如Blocks.BRICKS
和Items.DIAMOND
,这样就可以直接添加原版的物品了
不过,初始化方法还是要写的,也记得在主类中调用这个初始化方法
整体代码
1 | public class ModItemGroups { |
语言文件
1 | { |
这个就是我们的物品栏的名字,这里的itemGroup.tutorial_group
就是我们在displayName
方法中设置的翻译键
测试
现在我们启动游戏,由于原版的物品栏已经填满了第一页,不过它会自动生成一个翻页符,我们点击翻页符,就可以看到我们的物品栏了