[Java] [Java]Let’s create a Minecraft mod 1.14.4 [8. Add or create ore]

4 minute read

(This article is one of a series of commentary articles)

First article: Introduction Previous article: 7. Add progress Next article: 9. Adding and Generating Trees

Add ore

It’s finally time to move on to the full-scale part. If you make a mod’s unique material, you must prepare a way to obtain it. If it was a primary resource, it would have to be created in the world. This time we will learn to add ore.

First, let’s add an ore block as already explained in 2. Add block. Since it is exactly the same process, I will omit the explanation, but I added BlockList.ExampleOre.

BlockList.java


//...
public class BlockList {
    public static Block ExampleOre = new Block(
            Block.Properties.create(Material.ROCK)
                    .hardnessAndResistance(3.0F, 3.0F)
                    .lightValue(15))
            .setRegistryName(new ResourceLocation(ExampleMod.MOD_ID, "example_ore"));

    @SubscribeEvent
    public static void registerBlocks(RegistryEvent.Register<Block> event) {
        event.getRegistry().registerAll(
                ExampleOre
        );
    }

    @SubscribeEvent
    public static void registerBlockItems(RegistryEvent.Register<Item> event) {
        event.getRegistry().registerAll(
                new BlockItem(ExampleOre, new Item.Properties().group(ExampleItemGroup.DEFAULT))
                        .setRegistryName(new ResourceLocation(ExampleMod.MOD_ID, "example_ore"))
        );
    }
}

** * Addition ** It was better to define your own BlockExampleOre class that inherits the Block class instead of the Block class in order to set the experience value drop when mining.

``

BlockExampleOre.java
package jp.koteko.example_mod.blocks;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;

public class BlockExampleOre extends Block {
    public BlockExampleOre(Block.Properties properties) {
        super(properties);
    }

    @Override
    public int getExpDrop(BlockState state, net.minecraft.world.IWorldReader reader, BlockPos pos, int fortune, int silktouch) (
        return silktouch == 0 ?MathHelper.nextInt(RANDOM, 3, 7) :0;
    }
}


\src\main\resources
   ├ assets
   │ └ example_mod
   │ ├ blockstates
   │ │ └ example_ore.json
   │ ├ lang
   │ │ └ en_us.json
   │ │ └ ja_jp.json
   │ ├ models
   │ │ ├ block
   │ │ │ └ example_ore.json
   │ │ └ item
   │ │ └ example_ore.json
   │ └ textures
   │ ├ blocks
   │ │ └ example_ore.png
   │ └ items
   └ data
      └ example_mod
         └ loot_tables
            └ blocks
               └ example_ore.json

Add recipes as needed.

Ore generation

Now add the code to generate this.

\src\main\java\jp\koteko\example_mod\
   ├ items
   ├ lists
   ├ world
   │ └ WorldGenOres.java
   └ ExampleMod.java

Place WorldGenOres.java.

``

WorldGenOres.java
package jp.koteko.example_mod.world;

import jp.koteko.example_mod.lists.BlockList;
import net.minecraft.block.Block;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.GenerationStage;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.OreFeatureConfig;
import net.minecraft.world.gen.placement.CountRangeConfig;
import net.minecraft.world.gen.placement.Placement;
import net.minecraftforge.registries.ForgeRegistries;

public class WorldGenOres {
    public static void setup() {
        addOreToOverworld(
                BlockList.ExampleOre,
                17,
                new CountRangeConfig(20, 0, 0, 128)
        );
    }

    private static void addOreToOverworld(Block blockIn, int size, CountRangeConfig countRangeConfigIn) {
        for(Biome biome :ForgeRegistries.BIOMES) {
            if(!biome.getCategory().equals(Biome.Category.NETHER) && !biome.getCategory().equals(Biome.Category.THEEND)) (
                biome.addFeature(
                        GenerationStage.Decoration.UNDERGROUND_ORES,
                        Biome.createDecoratedFeature((
                                Feature.ORE,
                                new OreFeatureConfig(
                                        OreFeatureConfig.FillerBlockType.NATURAL_STONE,
                                        blockIn.getDefaultState(),
                                        size
                                ),
                                Placement.COUNT_RANGE,
                                countRangeConfigIn
                        )
                );
            }
        }
    }
}

The writing method is just an example, so you can write it more simply or with a higher degree of abstraction. ~~ The more I think about what is best, the more I don’t know. ~~ The core part is biome.addFeature(), which is a method for adding a Feature, that is, a feature, to an instance of the Biome class. This will generate features during biome generation.

``

 commentary
// Lots of examples in net\minecraft\world\biome\DefaultBiomeFeatures.java
biome.addFeature(
        // Type of feature to add
        // Look at net\minecraft\gen\GenerationStage.java and choose a good one
        GenerationStage.Decoration.UNDERGROUND_ORES,
        // Instance of configured feature
        Biome.createDecoratedFeature((// Kind of characteristics It seems that the one corresponding to the next argument is passed here
                Feature.ORE,
                // feature config
                new OreFeatureConfig(
                        // Type of block to be replaced
                        // NATURAL_STONE is STONE,GRANITE,DIORITE,ANDESITE
                        OreFeatureConfig.FillerBlockType.NATURAL_STONE,
                        // blockstate of the generated ore
                        BlockList.ExampleOre.getDefaultState(),
                        // maximum number generated in one place
                        17
                ),
                // Placement (object that handles the range?) Type It seems that the one corresponding to the next argument is passed here
                Placement.COUNT_RANGE,
                // Placement config
                // (count, bottomOffset, topOffset, maximum)
                // I'm afraid I got the details right, but
                // Randomly selected number in the range 0 to maximum-topOffset
                // It seems that it is moving like an integer value that adds bottomOffset count times
                // In short, it seems that the y coordinate to generate ore at count points per chunk is determined
                new CountRangeConfig(20, 0, 0, 128)
        )
)

Finally, call the just-defined WorldGenOres.setup() in setup in the main file.

``

ExampleMod.java
//...
public class ExampleMod
{
    //...
    private void setup(final FMLCommonSetupEvent event)
    {
        WorldGenOres.setup();
    }
    //...
}

Launch the game. Capture.PNG **Additional ore generated. **

Development

Q. I want to generate it in the Nether End Q. I want to generate only for a specific biome **A. Let’s judge the truth with biome.getCategory().equals(). ** This example was generated in all biomes on the ground. The code is the following part.

``


if(!biome.getCategory().equals(Biome.Category.NETHER) && !biome.getCategory().equals(Biome.Category.THEEND))

I turned it in for and did addFeature() to all non-nether and non-end of all biomes. I am writing this because I think that it is better to prepare a new method that changes this part appropriately. Or I think it would be better to receive the array of biomes as an argument.

Reference

Minecraft 1.14.4 Forge Mod Part 8 [Add and Generate Ore]

Next article

9. Tree addition and generation