提供: Minecraft Modding Wiki
2014年10月4日 (土) 22:16時点におけるShift (トーク | 投稿記録)による版
移動先: 案内検索

この記事は"Minecraft Forge Universal 10.13.0.1207"を前提MODとしています。

Stone pickaxe.png
中級者向けのチュートリアルです。
C world.png
Worldに関係のあるチュートリアルです。


バイオーム構成だけを変更したディメンションを追加するサンプルです。

なお、ディメン「ジ」ョンではなくディメン「シ」ョンです。お間違えなく。

動作するソースコードはhttps://github.com/dewfalse/SampleDimensionにも置いてありますので試してみる場合にはそちらも利用可能です。

MODのエントリーポイントを作成

  • SampleModEntryPoint.java
package sample;

import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraftforge.common.DimensionManager;

@Mod(modid = SampleModEntryPoint.MODID, name = SampleModEntryPoint.MODNAME, version = SampleModEntryPoint.VERSION)
public class SampleModEntryPoint {

    public static final String MODID = "SampleDimension";
    public static final String MODNAME = "SampleDimension";
    public static final String VERSION = "1.0.0";

    // 独自ディメンションのID
    public static int dimensionID = -2;

    // 独自ディメンションへのポータルブロック
    public static Block portal;

    // 独自ディメンション用のワールドプロバイダ
    public static int providerType = -2;

    @EventHandler
    public void preInit(FMLPreInitializationEvent event) {
        // 独自ディメンションへのポータルブロックを追加
        portal = new BlockSamplePortal(Material.portal).setBlockName("SampleDimension:portal").setCreativeTab(CreativeTabs.tabMisc);
        GameRegistry.registerBlock(portal, "portal");

        // 独自ディメンション用のワールドプロバイダを登録
        DimensionManager.registerProviderType(providerType, WorldProviderSample.class, false);

        // 独自ディメンションを登録
        DimensionManager.registerDimension(dimensionID, providerType);
    }

    @EventHandler
    public void init(FMLInitializationEvent event) {
    }

    @EventHandler
    public void postInit(FMLPostInitializationEvent event) {
    }
}

独自ディメンションへ移動するためのポータルブロックを追加

  • BlockSamplePortal.java

「その他」タブから取り出して設置し、右クリックすると独自ディメンションへ移動します。

package sample;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.management.ServerConfigurationManager;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;

public class BlockSamplePortal extends Block {

    protected BlockSamplePortal(Material p_i45394_1_) {
        super(p_i45394_1_);
    }

    @Override
    public boolean onBlockActivated(World p_149727_1_, int p_149727_2_, int p_149727_3_, int p_149727_4_, EntityPlayer p_149727_5_, int p_149727_6_, float p_149727_7_, float p_149727_8_, float p_149727_9_) {
        // 現在地が独自ディメンション以外
        if (p_149727_1_.provider.dimensionId != SampleModEntryPoint.dimensionID) {
            if (p_149727_5_ instanceof EntityPlayerMP) {
                // 1行で書くと長過ぎるので一旦ローカル変数に格納
                EntityPlayerMP entityPlayerMP = (EntityPlayerMP) p_149727_5_;
                ServerConfigurationManager serverConfigurationManager = entityPlayerMP.mcServer.getConfigurationManager();
                WorldServer worldServer = entityPlayerMP.mcServer.worldServerForDimension(SampleModEntryPoint.dimensionID);

                // 移動後にネザーポータルが作成されるので即座に再送還されないように
                entityPlayerMP.timeUntilPortal = 10;
                entityPlayerMP.setInPortal();

                // 独自ディメンションに移動する
                serverConfigurationManager.transferPlayerToDimension(entityPlayerMP, SampleModEntryPoint.dimensionID, new TeleporterSample(worldServer));
            }
        }
        // 現在地が独自ディメンション
        else {
            if (p_149727_5_ instanceof EntityPlayerMP) {
                // 1行で書くと長過ぎるので一旦ローカル変数に格納
                EntityPlayerMP entityPlayerMP = (EntityPlayerMP) p_149727_5_;
                ServerConfigurationManager serverConfigurationManager = entityPlayerMP.mcServer.getConfigurationManager();

                entityPlayerMP.setInPortal();
                entityPlayerMP.timeUntilPortal = 10;

                // 独自ディメンションからはオーバーワールドに移動
                serverConfigurationManager.transferPlayerToDimension(entityPlayerMP, 0);
            }
        }
        return true;
    }
}

ポータル生成を担当するテレポータークラスを作成

  • TeleporterSample.java

ネザーポータルが生成されます。

独自のポータルを生成する場合にはこのクラスの処理を変更してください。

package sample;

import net.minecraft.entity.Entity;
import net.minecraft.world.Teleporter;
import net.minecraft.world.WorldServer;

public class TeleporterSample extends Teleporter {

    public TeleporterSample(WorldServer p_i1963_1_) {
        super(p_i1963_1_);
    }

    // 近くにポータルがあったらそこに出現させる処理
    // このサンプルではネザーポータルの処理をそのまま利用する
    @Override
    public boolean placeInExistingPortal(Entity p_77184_1_, double p_77184_2_, double p_77184_4_, double p_77184_6_, float p_77184_8_) {
        return super.placeInExistingPortal(p_77184_1_, p_77184_2_, p_77184_4_, p_77184_6_, p_77184_8_);
    }

    // ポータルを作成する処理
    // このサンプルではネザーポータルの処理をそのまま利用する
    @Override
    public boolean makePortal(Entity p_85188_1_) {
        return super.makePortal(p_85188_1_);
    }

    // プレイヤーをポータルに出現させる処理
    // このサンプルではネザーポータルの処理をそのまま利用する
    @Override
    public void placeInPortal(Entity p_77185_1_, double p_77185_2_, double p_77185_4_, double p_77185_6_, float p_77185_8_) {
        super.placeInPortal(p_77185_1_, p_77185_2_, p_77185_4_, p_77185_6_, p_77185_8_);
    }
}

独自ディメンションのワールド管理クラスを作成

  • WorldProviderSample.java
package sample;

import net.minecraft.world.WorldProvider;
import net.minecraft.world.chunk.IChunkProvider;

public class WorldProviderSample extends WorldProvider {

    @Override
    public String getDimensionName() {
        return "Sample";
    }

    // 独自のワールドタイプやワールドチャンクマネージャーを設定
    @Override
    protected void registerWorldChunkManager() {
        worldObj.getWorldInfo().setTerrainType(WorldTypeSample.worldTypeSample);
        worldChunkMgr = new WorldChunkManagerSample(worldObj);
        setDimension(SampleModEntryPoint.dimensionID);
        hasNoSky = false;
    }

    // チャンク生成は独自のチャンクプロバイダが担当する
    @Override
    public IChunkProvider createChunkGenerator() {
        return new ChunkProviderSample(worldObj, worldObj.getSeed(), true);
    }
}

独自ディメンションのチャンク生成担当クラスを作成

  • ChunkProviderSample.java
package sample;

import net.minecraft.world.World;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.ChunkProviderGenerate;

// チャンクへのアクセスやチャンク生成を担当するクラス
// ここではオーバーワールドのものを流用する
public class ChunkProviderSample extends ChunkProviderGenerate implements IChunkProvider {

    public ChunkProviderSample(World par1World, long par2, boolean par4) {
        super(par1World, par2, par4);
    }

}

独自ディメンションのワールドタイプを追加

  • WorldTypeSample.java
package sample;

import net.minecraft.world.World;
import net.minecraft.world.WorldType;
import net.minecraft.world.biome.WorldChunkManager;
import net.minecraft.world.chunk.IChunkProvider;

public class WorldTypeSample extends WorldType {

    public static WorldType worldTypeSample = new WorldTypeSample("Sample");

    private WorldTypeSample(String name) {
        super(name);
    }

    @Override
    public WorldChunkManager getChunkManager(World world) {
        return new WorldChunkManagerSample(world);
    }

    @Override
    public IChunkProvider getChunkGenerator(World world, String generatorOptions) {
        return new ChunkProviderSample(world, world.getSeed(), world.getWorldInfo().isMapFeaturesEnabled());
    }
}

独自ディメンションのチャンク管理クラスを作成

  • WorldChunkManagerSample.java

オーバーワールドとバイオーム構成だけを変更した地形生成を行います。

package sample;

import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.world.ChunkPosition;
import net.minecraft.world.World;
import net.minecraft.world.WorldType;
import net.minecraft.world.biome.BiomeCache;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraft.world.biome.WorldChunkManager;
import net.minecraft.world.gen.layer.GenLayer;
import net.minecraft.world.gen.layer.IntCache;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

import static net.minecraft.world.biome.BiomeGenBase.mesa;
import static net.minecraft.world.biome.BiomeGenBase.mushroomIsland;

public class WorldChunkManagerSample extends WorldChunkManager {

    // WorldChunkManagerのプライベート変数にはアクセスできないので専用の変数を作成
    private GenLayer genBiomes;
    private GenLayer biomeIndexLayer;
    private BiomeCache biomeCache;
    private List biomesToSpawnIn;

    // 独自ディメンションにはメサとキノコバイオームのみ
    private static ArrayList<BiomeGenBase> allowedBiomes = new ArrayList<BiomeGenBase>(Arrays.asList(mushroomIsland, mesa));

    public static final BiomeGenBase[] biomeList = new BiomeGenBase[256];

    static {
        for (int i = 0; i < 256; ++i) {
            if (i % 2 == 0) {
                biomeList[i] = mushroomIsland;
            } else if (i % 2 == 1) {
                biomeList[i] = mesa;
            }
        }
    }

    protected WorldChunkManagerSample() {
        this.biomeCache = new BiomeCache(this);
        this.biomesToSpawnIn = new ArrayList();
        this.biomesToSpawnIn.addAll(allowedBiomes);
    }

    public WorldChunkManagerSample(long par1, WorldType par3WorldType) {
        this();
        GenLayer[] var4 = GenLayer.initializeAllBiomeGenerators(par1, par3WorldType);
        this.genBiomes = var4[0];
        this.biomeIndexLayer = var4[1];
    }

    public WorldChunkManagerSample(World par1World) {
        this(par1World.getSeed(), par1World.getWorldInfo().getTerrainType());
    }

    ///////////////////////////////////////////////////////////////////////
    // WorldChunkManagerのプライベート変数を使用するメソッドはすべて再実装

    @Override
    public List getBiomesToSpawnIn() {
        return this.biomesToSpawnIn;
    }

    @Override
    public BiomeGenBase getBiomeGenAt(int par1, int par2) {
        return this.biomeCache.getBiomeGenAt(par1, par2);
    }

    @Override
    public float[] getRainfall(float[] par1ArrayOfFloat, int par2, int par3, int par4, int par5) {
        IntCache.resetIntCache();

        if (par1ArrayOfFloat == null || par1ArrayOfFloat.length < par4 * par5) {
            par1ArrayOfFloat = new float[par4 * par5];
        }

        int[] var6 = this.biomeIndexLayer.getInts(par2, par3, par4, par5);

        for (int var7 = 0; var7 < par4 * par5; ++var7) {
            float var8 = (float) biomeList[var6[var7]].getIntRainfall() / 65536.0F;

            if (var8 > 1.0F) {
                var8 = 1.0F;
            }

            par1ArrayOfFloat[var7] = var8;
        }

        return par1ArrayOfFloat;
    }

    @SideOnly(Side.CLIENT)
    @Override
    public float getTemperatureAtHeight(float par1, int par2) {
        return par1;
    }

    @Override
    public BiomeGenBase[] getBiomesForGeneration(BiomeGenBase[] par1ArrayOfBiomeGenBase, int par2, int par3, int par4, int par5) {
        IntCache.resetIntCache();

        if (par1ArrayOfBiomeGenBase == null || par1ArrayOfBiomeGenBase.length < par4 * par5) {
            par1ArrayOfBiomeGenBase = new BiomeGenBase[par4 * par5];
        }

        int[] var6 = this.genBiomes.getInts(par2, par3, par4, par5);

        for (int var7 = 0; var7 < par4 * par5; ++var7) {
            par1ArrayOfBiomeGenBase[var7] = biomeList[var6[var7]];
        }

        return par1ArrayOfBiomeGenBase;
    }

    @Override
    public BiomeGenBase[] loadBlockGeneratorData(BiomeGenBase[] par1ArrayOfBiomeGenBase, int par2, int par3, int par4, int par5) {
        return this.getBiomeGenAt(par1ArrayOfBiomeGenBase, par2, par3, par4, par5, true);
    }

    @Override
    public BiomeGenBase[] getBiomeGenAt(BiomeGenBase[] par1ArrayOfBiomeGenBase, int par2, int par3, int par4, int par5, boolean par6) {
        IntCache.resetIntCache();

        if (par1ArrayOfBiomeGenBase == null || par1ArrayOfBiomeGenBase.length < par4 * par5) {
            par1ArrayOfBiomeGenBase = new BiomeGenBase[par4 * par5];
        }

        if (par6 && par4 == 16 && par5 == 16 && (par2 & 15) == 0 && (par3 & 15) == 0) {
            BiomeGenBase[] var9 = this.biomeCache.getCachedBiomes(par2, par3);
            System.arraycopy(var9, 0, par1ArrayOfBiomeGenBase, 0, par4 * par5);
            return par1ArrayOfBiomeGenBase;
        } else {
            int[] var7 = this.biomeIndexLayer.getInts(par2, par3, par4, par5);

            for (int var8 = 0; var8 < par4 * par5; ++var8) {
                par1ArrayOfBiomeGenBase[var8] = biomeList[var7[var8]];
            }

            return par1ArrayOfBiomeGenBase;
        }
    }

    @Override
    public boolean areBiomesViable(int par1, int par2, int par3, List par4List) {
        IntCache.resetIntCache();
        int var5 = par1 - par3 >> 2;
        int var6 = par2 - par3 >> 2;
        int var7 = par1 + par3 >> 2;
        int var8 = par2 + par3 >> 2;
        int var9 = var7 - var5 + 1;
        int var10 = var8 - var6 + 1;
        int[] var11 = this.genBiomes.getInts(var5, var6, var9, var10);

        for (int var12 = 0; var12 < var9 * var10; ++var12) {
            BiomeGenBase var13 = biomeList[var11[var12]];

            if (!par4List.contains(var13)) {
                return false;
            }
        }

        return true;
    }

    @Override
    public ChunkPosition findBiomePosition(int par1, int par2, int par3, List par4List, Random par5Random) {
        IntCache.resetIntCache();
        int var6 = par1 - par3 >> 2;
        int var7 = par2 - par3 >> 2;
        int var8 = par1 + par3 >> 2;
        int var9 = par2 + par3 >> 2;
        int var10 = var8 - var6 + 1;
        int var11 = var9 - var7 + 1;
        int[] var12 = this.genBiomes.getInts(var6, var7, var10, var11);
        ChunkPosition var13 = null;
        int var14 = 0;

        for (int var15 = 0; var15 < var10 * var11; ++var15) {
            int var16 = var6 + var15 % var10 << 2;
            int var17 = var7 + var15 / var10 << 2;
            BiomeGenBase var18 = biomeList[var12[var15]];

            if (par4List.contains(var18) && (var13 == null || par5Random.nextInt(var14 + 1) == 0)) {
                var13 = new ChunkPosition(var16, 0, var17);
                ++var14;
            }
        }

        return var13;
    }

    @Override
    public void cleanupCache() {
        this.biomeCache.cleanupCache();
    }
}

おまけ・ベッドで寝た時の爆発を防ぐ

  • WorldProviderSample.java

今はもっといい方法があるかも。

public class WorldProviderSample extends WorldProvider {

	@Override
	public boolean canRespawnHere() {
		return true;
	}

	@Override
	public void resetRainAndThunder() {
		super.resetRainAndThunder();

		if(this.worldObj.getGameRules().getGameRuleBooleanValue("doDaylightCycle")) {

			WorldInfo worldInfo = ObfuscationReflectionHelper.getPrivateValue(DerivedWorldInfo.class, (DerivedWorldInfo)worldObj.getWorldInfo(), "theWorldInfo", "field_76115_a");
			long i = worldInfo.getWorldTime() + 24000L;
			worldInfo.setWorldTime(i - i % 24000L);
		}
	}
}