创建流体
概述
在这里,我们将介绍自定义流体的创建。如果计划创建多个流体,建议创建一个抽象的基本流体类,在其中设置必要的默认值,这些默认值将在其子类中共享。我们还将使其像湖泊一样在世界中生成。
创建抽象流体
原版流体继承了 net.minecraft.fluid.FlowableFluid
,我们也应如此。
public abstract class TutorialFluid extends FlowableFluid {
/**
* @return 给定的流体是否为该流体的实例?
*/
@Override
public boolean matchesType(Fluid fluid) {
return fluid == getStill() || fluid == getFlowing();
}
/**
* @return 流体是否可以像无限刷水的方法一样无限生成?在原版,这取决于游戏规则。
*/
@Override
protected boolean isInfinite() {
return false;
}
/**
* 流体流入一个可替换的方块时的行为。
* 水会掉落方块的战利品表。熔岩会播放“block.lava.extinguish”音效。
*/
@Override
protected void beforeBreakingBlock(WorldAccess world, BlockPos pos, BlockState state) {
final BlockEntity blockEntity = state.getBlock().hasBlockEntity() ? world.getBlockEntity(pos) : null;
Block.dropStacks(state, world, pos, blockEntity);
}
/**
* 熔岩在其 FluidState 高于指定的高度且该流体为水时返回 true。
*
* @return 给定的流体能否流入它的 FluidState?
*/
@Override
protected boolean canBeReplacedWith
(FluidState fluidState,
BlockView blockView, BlockPos blockPos, Fluid fluid, Direction direction
) { return false;
}
/**
* 或许与流入周围附近凹洞的距离检查有关?
* 水返回4。熔岩在主世界返回2,而在下界返回4。
*/
@Override
protected int getFlowSpeed(WorldView worldView) {
return 4;
}
/**
* 返回每次流动一格,其等级减少的数值。水返回1,熔岩在主世界返回2,在下界返回1。
*/
@Override
protected int getLevelDecreasePerBlock(WorldView worldView) {
return 1;
}
/**
* 返回每流一格需要花费的时间(按刻计算)。水返回5。熔岩在主世界返回30,在下界返回10。
*/
@Override
public int getTickRate(WorldView worldView) {
return 5;
}
/**
* 返回爆炸抗性。水和熔岩都返回100.0F。
*/
@Override
protected float getBlastResistance() {
return 100.0F;
}
}
实现
现在让我们制作一个拥有静止和流动两个变种的实际流体。在此教程中,我们将其称为“酸”。缺失的引用稍后补全。
public abstract class AcidFluid extends TutorialFluid {
@Override
public Fluid getStill() {
return YOUR_STILL_FLUID_HERE;
}
@Override
public Fluid getFlowing() {
return YOUR_FLOWING_FLUID_HERE;
}
@Override
public Item getBucketItem() {
return YOUR_BUCKET_ITEM_HERE;
}
@Override
protected BlockState toBlockState(FluidState fluidState) {
return YOUR_FLUID_BLOCK_HERE.
getDefaultState().
with(Properties.
LEVEL_15, getBlockStateLevel
(fluidState
)); }
public static class Flowing extends AcidFluid {
@Override
protected void appendProperties(StateManager.Builder<Fluid, FluidState> builder) {
super.appendProperties(builder);
builder.add(LEVEL);
}
@Override
public int getLevel(FluidState fluidState) {
return fluidState.get(LEVEL);
}
@Override
public boolean isStill(FluidState fluidState) {
return false;
}
}
public static class Still extends AcidFluid {
@Override
public int getLevel(FluidState fluidState) {
return 8;
}
@Override
public boolean isStill(FluidState fluidState) {
return true;
}
}
}
接下来,我们将制作静态和动态酸变体的静态实例,以及一个酸桶。在您的
ModInitializer
中:
public static FlowableFluid STILL_ACID;
public static FlowableFluid FLOWING_ACID;
public static Item ACID_BUCKET;
@Override
public void onInitialize() {
STILL_ACID
= Registry.
register(Registries.
FLUID,
new Identifier
("tutorial",
"acid"),
new AcidFluid.
Still()); FLOWING_ACID
= Registry.
register(Registries.
FLUID,
new Identifier
("tutorial",
"flowing_acid"),
new AcidFluid.
Flowing()); ACID_BUCKET
= Registry.
register(Registries.
ITEM,
new Identifier
("tutorial",
"acid_bucket"),
new BucketItem(STILL_ACID, new Item.Settings().recipeRemainder(Items.BUCKET).maxCount(1)));
// ...
}
// ...
为了使自定义流体表现得像水或熔岩,您必须将其添加到相应的流体标签中:对于水,制作 data/minecraft/tags/fluids/water.json
文件,并在其中写入流体 id:
{
"replace": false,
"values":
[
"tutorial:acid",
"tutorial:flowing_acid"
]
}
制作一个流体方块
接下来,我们需要在世界中创建表示酸的方块。net.minecraft.block.FluidBlock
是我们需要使用的类,但由于其构造器受保护,我们不能直接构造它。一种解决方法是制作子类或者匿名子类。这里我们展示后一种方式。在您的 ModInitializer
中:
public static Block ACID;
@Override
public void onInitialize() {
ACID
= Registry.
register(Registries.
BLOCK,
new Identifier
("tutorial",
"acid"),
new FluidBlock
(STILL_ACID, FabricBlockSettings.
copy(Blocks.
WATER)){});
// ...
}
既然我们有了这些静态对象,我们回到 AcidFluid
并补全被重写的方法:
public abstract class AcidFluid extends TutorialFluid {
@Override
public Fluid getStill() {
return TutorialMod.STILL_ACID;
}
@Override
public Fluid getFlowing() {
return TutorialMod.FLOWING_ACID;
}
@Override
public Item getBucketItem() {
return TutorialMod.ACID_BUCKET;
}
@Override
protected BlockState toBlockState(FluidState fluidState) {
// getBlockStateLevel 将流体状态的 LEVEL_1_8 转换为流体方块使用的 LEVEL_15
return TutorialMod.
ACID.
getDefaultState().
with(Properties.
LEVEL_15, getBlockStateLevel
(fluidState
)); }
public static class Flowing extends AcidFluid {
@Override
protected void appendProperties(StateManager.Builder<Fluid, FluidState> builder) {
super.appendProperties(builder);
builder.add(LEVEL);
}
@Override
public int getLevel(FluidState fluidState) {
return fluidState.get(LEVEL);
}
@Override
public boolean isStill(FluidState fluidState) {
return false;
}
}
public static class Still extends AcidFluid {
@Override
public int getLevel(FluidState fluidState) {
return 8;
}
@Override
public boolean isStill(FluidState fluidState) {
return true;
}
}
}
渲染设置
为了让流体拥有纹理,或者与一个颜色绑定,你需要为其注册一个FluidRenderHandler
。这里,我们重用水的纹理,并仅仅改变用于其上的颜色。为确保纹理渲染为半透明的,你可以使用 Fabric 的 BlockRenderLayerMap
(参见 blockappearance)。
public class TutorialModClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
FluidRenderHandlerRegistry.INSTANCE.register(TutorialMod.STILL_ACID, TutorialMod.FLOWING_ACID, new SimpleFluidRenderHandler(
new Identifier("minecraft:block/water_still"),
new Identifier("minecraft:block/water_flow"),
0x4CC248
));
BlockRenderLayerMap.INSTANCE.putFluids(RenderLayer.getTranslucent(), TutorialMod.STILL_ACID, TutorialMod.FLOWING_ACID);
//if you want to use custom textures they needs to be registered.
//In this example this is unnecessary because the vanilla water textures are already registered.
//To register your custom textures use this method.
//ClientSpriteRegistryCallback.event(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE).register((atlasTexture, registry) -> {
// registry.register(new Identifier("tutorial:block/custom_fluid_still"));
// registry.register(new Identifier("tutorial:block/custom_fluid_flowing"));
//});
// ...
}
}
如果你需要使用你自己的流体纹理,你可以参考原版资源包1)作为一个模板。
在世界中生成
为使得酸湖在世界中生成,你可以在你的ModInitializer
中创建一个net.minecraft.world.gen.feature.LakeFeature
,然后将其添加到你需要让它生成的生物群系中:
// ...
public static LakeFeature ACID_LAKE;
// ...
@Override
public void onInitialize()
{
// ...
ACID_LAKE
= Registry.
register(Registry.
FEATURE,
new Identifier
(MOD_ID,
"acid_lake"),
new LakeFeature
(SingleStateFeatureConfig
::deserialize
));
// 在沼泽中生成,类似于水湖,但是概率为40(数字越高,生成几率越低)
Biomes.SWAMP.addFeature(
GenerationStep.Feature.LOCAL_MODIFICATIONS,
ACID_LAKE.configure(new SingleStateFeatureConfig(ACID.getDefaultState()))
.createDecoratedFeature(Decorator.WATER_LAKE.configure(new ChanceDecoratorConfig(40)))
);
// ...
}
// ...