概述
一个流体,有着对应的桶是一件很正常的事情,这部分教程作者将带领读者一步一步地完成一个水银桶的制作、和注册。
流体桶的制作
还好,Minecraft提供了一个名为ItemBucket的类,我们只需要继承这个类就好了。在包com.github.ustc_zzzz.fmltutor.item下新建文件ItemBucketMercury.java:
src/main/java/com/github/ustc_zzzz/fmltutor/item/ItemBucketMercury.java:
package com.github.ustc_zzzz.fmltutor.item;
import com.github.ustc_zzzz.fmltutor.block.BlockLoader;
import com.github.ustc_zzzz.fmltutor.creativetab.CreativeTabsLoader;
import net.minecraft.init.Items;
import net.minecraft.item.ItemBucket;
public class ItemBucketMercury extends ItemBucket
{
public ItemBucketMercury()
{
super(BlockLoader.fluidMercury);
this.setContainerItem(Items.bucket);
this.setUnlocalizedName("bucketMercury");
this.setCreativeTab(CreativeTabsLoader.tabFMLTutor);
}
}
ItemBucket类的构造方法需要一个方块作为参数,这个方块当然就是对应的流体方块。
setContainerItem方法的作用是设置包含的物品,这样在合成等地方使用后,Minecraft可以识别出这个物品包含一个桶,并把桶留下。
模型和语言文件:
src/main/resources/assets/fmltutor/models/item/bucket_mercury.json:
{
"parent": "builtin/generated",
"textures": {
"layer0": "fmltutor:items/bucket_mercury"
},
"display": {
"thirdperson": {
"rotation": [ -90, 0, 0 ],
"translation": [ 0, 1, -3 ],
"scale": [ 0.55, 0.55, 0.55 ]
},
"firstperson": {
"rotation": [ 0, -135, 25 ],
"translation": [ 0, 4, 2 ],
"scale": [ 1.7, 1.7, 1.7 ]
}
}
}
src/main/resources/assets/fmltutor/lang/en_US.lang(部分):
item.bucketMercury.name=Mercury Bucket
src/main/resources/assets/fmltutor/lang/zh_CN.lang(部分):
item.bucketMercury.name=水银桶
因为教程编写者没有美工带来的不忍直视的材质:
src/main/resources/assets/fmltutor/textures/items/bucket_mercury.png:

一些例行公事:
src/main/java/com/github/ustc_zzzz/fmltutor/item/ItemLoader.java(部分):
public static Item bucketMercury = new ItemBucketMercury();
src/main/java/com/github/ustc_zzzz/fmltutor/item/ItemLoader.java(部分):
public ItemLoader(FMLPreInitializationEvent event)
{
register(goldenEgg, "golden_egg");
register(redstonePickaxe, "redstone_pickaxe");
register(redstoneApple, "redstone_apple");
register(redstoneHelmet, "redstone_helmet");
register(redstoneChestplate, "redstone_chestplate");
register(redstoneLeggings, "redstone_leggings");
register(redstoneBoots, "redstone_boots");
register(bucketMercury, "bucket_mercury");
}
@SideOnly(Side.CLIENT)
public static void registerRenders()
{
registerRender(goldenEgg);
registerRender(redstonePickaxe);
registerRender(redstoneApple);
registerRender(redstoneHelmet);
registerRender(redstoneChestplate);
registerRender(redstoneLeggings);
registerRender(redstoneBoots);
registerRender(bucketMercury);
}
现在游戏中应该出现了一个桶,并且可以倒出流体了。
注册这个流体桶
然而,现在一个负责处理流体桶的Mod,对于这个物品,还是有三点是未知的:
- 这是一个用于盛放流体的桶
- 这个桶盛放的流体是水银这个流体
- 这个桶的容量正好是一个桶,也就是1000mB
Forge提供的FluidContainerRegistry类就是统一这种事情的,FluidContainerRegistry类提供了四个常用的注册流体容器的方法:
public static boolean registerFluidContainer(Fluid fluid, ItemStack filledContainer)public static boolean registerFluidContainer(Fluid fluid, ItemStack filledContainer, ItemStack emptyContainer)public static boolean registerFluidContainer(FluidStack stack, ItemStack filledContainer)public static boolean registerFluidContainer(FluidStack stack, ItemStack filledContainer, ItemStack emptyContainer)
如果提供的第一个参数是Fluid类的实例对象,那么默认注册的流体容器大小为一个桶(也就是1000mB),如果是FluidStack,则按照FluidStack提供的来。
如果提供了emptyContainer参数,则表示这个流体容器有着空容器,否则没有(比如盛装了流体的IndustrailCraft2 Experimental的空流体单元)。
我们现在完成一下这个注册步骤:
src/main/java/com/github/ustc_zzzz/fmltutor/item/ItemBucketMercury.java:
package com.github.ustc_zzzz.fmltutor.item;
import com.github.ustc_zzzz.fmltutor.block.BlockLoader;
import com.github.ustc_zzzz.fmltutor.creativetab.CreativeTabsLoader;
import com.github.ustc_zzzz.fmltutor.fluid.FluidLoader;
import net.minecraft.init.Items;
import net.minecraft.item.ItemBucket;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidContainerRegistry;
public class ItemBucketMercury extends ItemBucket
{
public ItemBucketMercury()
{
super(BlockLoader.fluidMercury);
this.setContainerItem(Items.bucket);
this.setUnlocalizedName("bucketMercury");
this.setCreativeTab(CreativeTabsLoader.tabFMLTutor);
FluidContainerRegistry.registerFluidContainer(FluidLoader.fluidMercury, new ItemStack(this),
FluidContainerRegistry.EMPTY_BUCKET);
}
}
现在看起来似乎没什么问题了。
解决游戏和流体桶交互的问题
其实,细心的读者可能已经发现了,现在游戏有着一个不易发现但是很致命的问题,就是如果在生存模式下使用一个空桶去盛装水银这个流体,会得到一个水桶,这显然不是我们想要的。
这是因为Minecraft中只认水和岩浆两种流体,这导致新添加的流体不会与对应的流体桶交互。我们这里监听一下桶被盛装的事件:
src/main/java/com/github/ustc_zzzz/fmltutor/common/EventLoader.java(部分):
@SubscribeEvent
public void onFillBucket(FillBucketEvent event)
{
BlockPos blockpos = event.target.getBlockPos();
IBlockState blockState = event.world.getBlockState(blockpos);
Fluid fluid = FluidRegistry.lookupFluidForBlock(blockState.getBlock());
if (fluid != null && new Integer(0).equals(blockState.getValue(BlockFluidBase.LEVEL)))
{
FluidStack fluidStack = new FluidStack(fluid, FluidContainerRegistry.BUCKET_VOLUME);
event.world.setBlockToAir(blockpos);
event.result = FluidContainerRegistry.fillFluidContainer(fluidStack, event.current);
event.setResult(Result.ALLOW);
}
}
现在看起来真的没什么问题了。