うまげーむさん

ゲームの情報を主に投稿します。

【マインクラフト Modding】1.15対応 自作MODの作り方 #13 液体

このシリーズのまとめはこちら:

umagame.hatenablog.jp

どうも。

はじめに

今回は液体を作ります。泥です。

前回:

umagame.hatenablog.jp

液体を作る

液体登録用クラス

まず、アイテムやブロックと同じように、initに液体を登録するクラスを作ります。

f:id:Umagame:20200405110250p:plain

ソースコードの中に、まだ作っていないFluidMudというクラスがあるのでエラーが出ますが気にせずに。

package com.umagame.dirtmod.init;

import com.umagame.dirtmod.fluid.FluidMud;
import com.umagame.dirtmod.main.DirtMod;

import net.minecraft.fluid.Fluid;
import net.minecraft.tags.FluidTags;
import net.minecraft.tags.Tag;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus;
import net.minecraftforge.registries.ObjectHolder;

@ObjectHolder(DirtMod.MOD_ID)
public class DirtModFluids {

    public static final FluidMud.Flowing FLOWING_MUD = null;
    public static final FluidMud.Source MUD = null;

    public static class Tags {
        public static final Tag<Fluid> MUD = new FluidTags.Wrapper(new ResourceLocation(DirtMod.MOD_ID, "mud"));
    }

    @Mod.EventBusSubscriber(modid = DirtMod.MOD_ID, bus = Bus.MOD)
    public static class Register {

        @SubscribeEvent
        public static void registerFluids(final RegistryEvent.Register<Fluid> event) {
            final Fluid[] fluids = {
                    new FluidMud.Flowing().setRegistryName(DirtMod.MOD_ID, "flowing_mud"),
                    new FluidMud.Source().setRegistryName(DirtMod.MOD_ID, "mud")
            };

            event.getRegistry().registerAll(fluids);
        }
    }
}

3つIDを入力するところがあるので忘れないように。

液体のクラス

液体のクラスをfluidパッケージに作ります。

f:id:Umagame:20200405110757p:plain

液体の場合は複雑で、いつものようにクラスを継承してメソッドの戻り値を設定する...だけではできないので、とりあえずコピペしてください。

package com.umagame.dirtmod.fluid;

import com.umagame.dirtmod.init.DirtModBlocks;
import com.umagame.dirtmod.init.DirtModFluids;
import com.umagame.dirtmod.item.ItemMudBucket;
import com.umagame.dirtmod.main.DirtMod;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.FlowingFluidBlock;
import net.minecraft.fluid.FlowingFluid;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.Item;
import net.minecraft.state.StateContainer.Builder;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
import net.minecraftforge.fluids.FluidAttributes;

public abstract class FluidMud extends FlowingFluid{

    @Override
    public Fluid getFlowingFluid() {
        return DirtModFluids.FLOWING_MUD;
    }

    @Override
    public Fluid getStillFluid() {
        return DirtModFluids.MUD;
    }

    @Override
    protected boolean canSourcesMultiply() {
        return true;
    }

    @Override
    protected void beforeReplacingBlock(IWorld worldIn, BlockPos pos, BlockState state) {
        @SuppressWarnings("deprecation")
        TileEntity tileentity = state.getBlock().hasTileEntity() ? worldIn.getTileEntity(pos) : null;
        Block.spawnDrops(state, worldIn.getWorld(), pos, tileentity);
    }

    @Override
    protected int getSlopeFindDistance(IWorldReader worldIn) {
        return 4;
    }

    @Override
    protected int getLevelDecreasePerBlock(IWorldReader worldIn) {
        return 1;
    }

    @Override
    public Item getFilledBucket() {
        return new ItemMudBucket();
    }

    @Override
    protected boolean func_215665_a(IFluidState p_215665_1_, IBlockReader p_215665_2_, BlockPos p_215665_3_,
        Fluid p_215665_4_, Direction p_215665_5_) {
        return p_215665_5_ == Direction.DOWN && !p_215665_4_.isIn(DirtModFluids.Tags.MUD);
    }

    @Override
    public int getTickRate(IWorldReader p_205569_1_) {
        return 5;
    }

    @Override
    protected float getExplosionResistance() {
        return 100.0F;
    }

    @Override
    protected BlockState getBlockState(IFluidState state) {
        return DirtModBlocks.MUD.getDefaultState().with(FlowingFluidBlock.LEVEL, Integer.valueOf(getLevelFromState(state)));
    }

    @Override
    public boolean isEquivalentTo(Fluid fluidIn) {
        return fluidIn == DirtModFluids.MUD || fluidIn == DirtModFluids.FLOWING_MUD;
    }

    @Override
    protected FluidAttributes createAttributes() {
        return FluidAttributes.builder(new ResourceLocation(DirtMod.MOD_ID, "block/mud_still"), new ResourceLocation(DirtMod.MOD_ID, "block/mud_flow"))
                .translationKey("block.dirtmod.mud")
                .build(this);
    }

    public static class Flowing extends FluidMud {

        @Override
        protected void fillStateContainer(Builder<Fluid, IFluidState> builder) {
            super.fillStateContainer(builder);
            builder.add(LEVEL_1_8);
        }

        @Override
        public boolean isSource(IFluidState state) {
            return false;
        }

        @Override
        public int getLevel(IFluidState state) {
            return state.get(FluidMud.LEVEL_1_8);
        }

    }

    public static class Source extends FluidMud {

        @Override
        public boolean isSource(IFluidState state) {
            return true;
        }

        @Override
        public int getLevel(IFluidState p_207192_1_) {
            return 8;
        }

    }
}

少し解説すると、

  • getFlowingFluidとgetStillFluidで液体を指定
  • canSourcesMultiplyで無限水源になるかどうかを指定
  • getFilledBucketで液体の入ったバケツのアイテムを指定(後ほど作ります)
  • createAttributesで、IDの指定が必要なので忘れずに
  • FlowingとSourceクラスで、それぞれのisSourceとgetLevelの値を分けています
  • 他のメソッドは、液体自体の設定です(今回は水と同じ挙動をするようにしています。)

これでさっきの登録用クラスのエラーがなくなったかと思います。

液体ブロックの追加

液体のブロックとしてのクラスも必要になるので、blockに新しくクラスを作ります。

f:id:Umagame:20200405111855p:plain

FlowingFluidBlockを継承して、superの中に登録用クラスの液体と、Propertiesを設定します。

IDの設定も必要なので忘れずに。

package com.umagame.dirtmod.block;

import com.umagame.dirtmod.init.DirtModFluids;
import com.umagame.dirtmod.main.DirtMod;

import net.minecraft.block.FlowingFluidBlock;
import net.minecraft.block.material.Material;

public class BlockMud extends FlowingFluidBlock{

    public BlockMud() {
        super(() -> DirtModFluids.MUD, Properties.create(Material.WATER).doesNotBlockMovement().hardnessAndResistance(100.0F).noDrops());
        this.setRegistryName(DirtMod.MOD_ID, "mud");
    }
}

ちなみに、私の場合superの行で謎のエラーが出ました。

その時はonEntityCollisionというメソッドをオーバーライドしたらなぜか直ったのですが、普通にEclipseを再起動しても大丈夫かと思います。

あと、ブロック登録用クラスで登録しておいてください。

ブロック登録についてはこちら:

umagame.hatenablog.jp

液体バケツの追加

itemに、液体の入ったバケツのクラスを作ります。

f:id:Umagame:20200405113443p:plain

BucketItemを継承して作ります。

package com.umagame.dirtmod.item;

import com.umagame.dirtmod.init.DirtModFluids;
import com.umagame.dirtmod.main.DirtMod;

import net.minecraft.item.BucketItem;

public class ItemMudBucket extends BucketItem{

    public ItemMudBucket() {
        super(() -> DirtModFluids.MUD,new Properties().group(DirtMod.DIRTMOD_TAB));
        this.setRegistryName("mud_bucket");
    }
}

登録も忘れずに。

アイテム登録についてはこちら:

umagame.hatenablog.jp

とりあえずこれで起動してみます。

テクスチャのない液体が追加されていることが分かります。

f:id:Umagame:20200405110054p:plain

ですが、この液体を触れても当たり判定がなく、泳ぐことができません。

これは修正が必要です。

修正・テクスチャ

少し調べたところ、タグというものをいじればいいっぽいです。

src/main/resources/data/minecraft/tags/fluidsに、water.jsonというファイルを作り、

f:id:Umagame:20200405123632p:plain

このように記述します。

{
  "replace": false,
  "values": [
    "minecraft:water",
    "minecraft:flowing_water",
    "dirtmod:mud",
    "dirtmod:flowing_mud"
  ]
}

こうすることにより、追加した液体で泳ぐことができるようになります。

この場合追加した液体にwaterというタグをつけていることになるので、おそらく液体登録用クラスの中に作ったタグの意味はなくなります。(めんどくさいのでこのままでやります)

テクスチャの設定は、バニラの水を参考にして作ります。

textures/blockにpngとmcmetaファイルを追加して、(mcmetaの中身はバニラの水のものと同じです)

f:id:Umagame:20200405124149p:plain

models/blockにmud.jsonを作ってこのように入力し、

{
    "textures": {
        "particle": "block/mud_still"
    }
}

blockstatesにmud.jsonを作ってこのように入力します。

{
    "variants": {
        "": { "model": "block/mud" }
    }
}

これで起動すると、テクスチャが反映され、泳げるようになります。

f:id:Umagame:20200405124500p:plain

バケツのテクスチャは過去記事を参考にして設定してください。

さいごに

今回はここまでです。

不具合等あればご報告お願いします。

次回は未定です。