2017年12月18日月曜日

独自の鉱石をワールド内に発生させる方法

概要

前回 独自の鉱石を作成しました
これまではインベントリから取得できましたが今回は自然の世界にランダムで発生させてみたいと思います

環境

  • macOS X 10.13.2
  • Minecraft 1.12.2
  • Forge 1.12.2 - 14.23.1.2555
  • Forge MDK 1.12.2 - 14.23.1.2555
  • Java 1.8.0_151
  • eclipse Oxygen.1a Release (4.7.1a)

各種 Java ファイルの作成

コードを書いていきます

com.sample.mod.gen パッケージの作成

  • SampleOreGen.java
package com.sample.mod.gen;

import java.util.Random;

import com.sample.mod.init.BlockInit;

import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.IChunkGenerator;
import net.minecraft.world.gen.feature.WorldGenMinable;
import net.minecraft.world.gen.feature.WorldGenerator;
import net.minecraftforge.fml.common.IWorldGenerator;

public class SampleOreGen implements IWorldGenerator {

    private WorldGenerator sample_ore;

    public SampleOreGen() {
        sample_ore = new WorldGenMinable(BlockInit.sample_ore.getDefaultState(), 9);
    }

    @Override
    public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator,
            IChunkProvider chunkProvider) {
        switch(world.provider.getDimension()) {
        case 0:
            runGenerator(sample_ore, world, random, chunkX, chunkZ, 50, 0, 50);
            break;
        case 1:
            break;
        case -1:
            break;
        }
    }

    private void runGenerator(WorldGenerator gen, World world, Random rand, int chunkX, int chunkZ, int chance, int minHeight, int maxHeight) {
        if (minHeight > maxHeight || minHeight < 0 || maxHeight > 256) throw new IllegalArgumentException("Ore generated out of bounds");
        int heightDiff = maxHeight - minHeight + 1;
        for (int i = 0; i < chance; i++) {
            int x = chunkX * 16 + rand.nextInt(16);
            int y = minHeight + rand.nextInt(heightDiff);
            int z = chunkZ * 16 + rand.nextInt(16);
            gen.generate(world, rand, new BlockPos(x, y, z));
        }
    }
}

WorldGenMinable でワールドを作成します
第二引数の 9 は鉱石が見つかった際に塊としていくつ周りに生成させるか指定できます

Override している generate でどのワールドに生成するかハンドリングします
world.provider.getDimension() で現在どのワールドタイプにいるのか取得することができます
-1 がネザーで 0 が通常世界で 1 がエンドポータルになります
今回は通常世界での鉱石は発生させるようにします

runGenerator で鉱石を配置する座標をランダムに決定し独自の鉱石が発生するワールドを作成します
まず高さのチェックをします
0 から 256 の範囲外は指定できないのでそれ以外が指定された場合はエラーとします
チャンクごとに chance で指定された回数分ワールドを作成します
chance が小さいほど 1 チャンク内に出現する鉱石の数は少なくなります
x, y, z の座標を生成しワールドを作成します
鉱石を発生させる高さを minHeight と maxHeight で指定できます
今回は 0 - 50 の高さで発生するようにしました

com.sample.mod.handlers パッケージの作成

  • RegistryHandler.java
package com.sample.mod.handlers;

import com.sample.mod.gen.SampleOreGen;
import com.sample.mod.init.BlockInit;
import com.sample.mod.init.ItemInit;

import net.minecraftforge.fml.common.registry.GameRegistry;

public class RegistyHandler {

    public static void Client() {
        RecipeHandler.registerCrafting();
        RecipeHandler.registerSmelting();
    }

    public static void Common() {
        ItemInit.init();
        ItemInit.register();
        BlockInit.init();
        BlockInit.register();
        BlockInit.registerRenders();
        GameRegistry.registerWorldGenerator(new SampleOreGen(), 0);
    }
}

GameRegistry.registerWorldGenerator(new SampleOreGen(), 0); で鉱石を発生させるワールドを登録します
第二引数はワールドの重みを指定することができます
大きければ大きいほど生成が後ろ回しになるため鉱石をあまり発生させたくない場合は値を大きくします

動作確認

クリエイティブモードでワールドを作成しましょう
今回の設定値であればそのまま下に掘っていけば簡単に見つかると思います
指定した高さの座標内で見つかると思います
またその周辺にも鉱石が発生しているのが確認できると思いますgen_org_ore1.png

最後に

独自で作成した鉱石をゲームワールド内に発生させる方法を紹介しました
新規で作成した鉱石の重みが軽いとたくさん作成されてしまうので、既存の鉱石の発生確率が下がってしまう点は注意してください

鉱石側のチューニング (壊せる回数や壊せるピッケルレベルなど) は鉱石側の設定で行ってください

参考サイト

4 件のコメント:

  1. ネザーに鉱石を生成したいのですが、
    上記のプログラムのcase 0; とcase -1; を
    入れ替えて書き出しても、
    ネザーに生成されません。
    試しに、case 0; に同様のプログラムを
    書き出した場合は、
    オーバーワールドに生成されます。
    (エンドも生成されません)
    原因は何か教えていただけますでしょうか。
    開発環境は
    Minecraft 1.12.2
    Forge 1.12.2-14.23.5.2855
    Intelij IDEA です。

    //AncientDebrisGen.java
    package katyo.usefulplus.gen;

    import net.minecraft.util.math.BlockPos;
    import net.minecraft.world.World;
    import net.minecraft.world.chunk.IChunkProvider;
    import net.minecraft.world.gen.IChunkGenerator;
    import net.minecraft.world.gen.feature.WorldGenMinable;
    import net.minecraft.world.gen.feature.WorldGenerator;
    import net.minecraftforge.fml.common.IWorldGenerator;

    import java.util.Random;

    import katyo.usefulplus.init.BlockInit;

    public class AncientDebrisGen implements IWorldGenerator {
    private WorldGenerator ancient_debris;

    public AncientDebrisGen() {
    ancient_debris = new WorldGenMinable(BlockInit.ancient_debris.getDefaultState(), 3);
    }

    @Override
    public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider) {
    switch(world.provider.getDimension()) {
    case 0:
    break;
    case 1:
    break;
    case -1:
    runGenerator(ancient_debris, world, random, chunkX, chunkZ, 50, 13, 17);
    break;
    }
    }

    private void runGenerator(WorldGenerator gen, World world, Random rand, int chunkX, int chunkZ, int chance, int minHeight, int maxHeight) {
    if (minHeight > maxHeight || minHeight < 0 || maxHeight > 256) throw new IllegalArgumentException("Ore generated out of bounds");
    int heightDiff = maxHeight - minHeight + 1;
    for (int i = 0; i < chance; i++) {
    int x = chunkX * 16 + rand.nextInt(16);
    int y = minHeight + rand.nextInt(heightDiff);
    int z = chunkZ * 16 + rand.nextInt(16);
    gen.generate(world, rand, new BlockPos(x, y, z));
    }
    }
    }

    返信削除
    返信
    1. (すいません、スパムが多くコメントは承認制になっており投稿にラグがあります、、)

      最近全く触っていないので試せる環境がなく不確かではありますがおそらく原因は以下かなと思います。

      https://forums.minecraftforge.net/topic/63264-generate-ore-in-nether/

      自然鉱石はネザーに生成することができないようなので WorldGenMinable(IBlockState, int) ではなく WorldGenMinable(IBlockState, int, Predicate) コンストラクタを使えとのことです

      実際に動作しているコードもあり自分の記事と同じような書き方なのでそれを見ながら修正すれば動作するかなと思います
      試してみてください

      削除
  2. わかりました。試してみます!

    返信削除
  3. ancient_debris = new WorldGenMinable(BlockInit.ancient_debris.getDefaultState(), 3); を、
    ancient_debris = new WorldGenMinable(BlockInit.ancient_debris.getDefaultState(), 3, BlockMatcher.forBlock(Blocks.NETHERRACK));
    にすると、できました。ありがとうございます!!

    返信削除