(この記事は一連の解説記事の一つになります)
先頭記事:入門編
前の記事:7. 進捗の追加
次の記事:9. 木の追加と生成
鉱石の追加
いよいよ少し本格的な部分に入っていきます。Modの固有素材を作った場合その入手手段を用意しなければなりません。それが一次資源であった場合には、ワールド内に生成しておく必要があるでしょう。今回は鉱石の追加を学びます。
まず、既に2. ブロックの追加で説明したように、鉱石ブロックを追加しましょう。全く同じ工程なので解説は省略しますが、BlockList.ExampleOre
を追加しました。
//...
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"))
);
}
}
※追記
採掘時の経験値ドロップを設定するためにBlock
クラスでなく、Block
クラスを継承した独自のBlockExampleOre
クラスを定義したほうが良かったです。
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
レシピなども適宜追加しましょう。
鉱石の生成
さてこれを生成させるようコードを追加していきます。
\src\main\java\jp\koteko\example_mod\
├ items
├ lists
├ world
│ └ WorldGenOres.java
└ ExampleMod.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
)
);
}
}
}
}
書き方はあくまで一例なのでもっとシンプルに書いてももっと抽象度高めに書いてもよいです。何が最適か考えれば考えるほどわからん。
コアとなる部分はbiome.addFeature()
で、Biome
クラスのインスタンスにFeature
すなわち特徴を追加するメソッドです。これによってバイオーム生成時に特徴が生成されます。
// net\minecraft\world\biome\DefaultBiomeFeatures.javaに例が沢山ある
biome.addFeature(
// 追加する特徴のタイプ
// net\minecraft\gen\GenerationStage.javaを見ていい感じのものを選ぶとよい
GenerationStage.Decoration.UNDERGROUND_ORES,
// 構成した特徴のインスタンス
Biome.createDecoratedFeature(
// 特徴の種類 次の引数に対応するものをここで渡すらしい
Feature.ORE,
// 特徴のコンフィグ
new OreFeatureConfig(
// 置き換えを行う対象となるブロックの種類
// NATURAL_STONE は STONE,GRANITE,DIORITE,ANDESITE
OreFeatureConfig.FillerBlockType.NATURAL_STONE,
// 生成する鉱石のblockstate
BlockList.ExampleOre.getDefaultState(),
// 1か所に生成される最大の数
17
),
// Placement(範囲を扱うオブジェクト?)の種類 次の引数に対応するものをここで渡すらしい
Placement.COUNT_RANGE,
// Placementのコンフィグ
// (count, bottomOffset, topOffset, maximum)
// 詳細が正しくつかめているかはあやしいが、
// 0からmaximum-topOffsetまでの範囲でランダムに選んだ数に
// bottomOffsetを足した整数値をcount回抽選するような動きをしているっぽい
// 要するに、1チャンクあたりcount箇所の鉱石生成するy座標を決定しているらしい
new CountRangeConfig(20, 0, 0, 128)
)
)
最後に、今定義したWorldGenOres.setup()
をメインファイル内のsetup
中で呼びます。
//...
public class ExampleMod
{
//...
private void setup(final FMLCommonSetupEvent event)
{
WorldGenOres.setup();
}
//...
}
発展
Q. ネザー・エンドに生成したい
Q. 特定のバイオームにだけ生成したい
A. biome.getCategory().equals()
で真偽判定しましょう。
今回例示したのは地上のすべてのバイオーム中に生成していました。そのコードは以下の部分です。
if(!biome.getCategory().equals(Biome.Category.NETHER) && !biome.getCategory().equals(Biome.Category.THEEND))
forで回して全てのバイオームのうちネザーでないかつエンドでないものすべてにaddFeature()
していました。この部分を適宜変えた新しいメソッドを用意するといいんじゃないかな、と思ってこの書き方をしています。あるいはいっそ引数にバイオームの配列を受け取るようにしてしまうのもありかと思います。
参考
Minecraft 1.14.4 Forge Modの作成 その8 【鉱石の追加と生成】