提供: Minecraft Modding Wiki
移動先: 案内検索

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

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

概要[編集]

流体追加のチュートリアルです。
1.6.x用Forgeから、アイテム・ブロックなどの実体を持たない流体情報のみを追加することができるようになりました。
また、Forgeに流体ブロックの実装を簡単にする基礎クラスが用意され、流体ブロックの実装が簡単になりました
※ブロックIDが1つで、水源 水流を実装できます。
そのため合わせてForgeで用意される基礎クラスを使った流体ブロック、容器入り流体の簡易チュートリアルも併記しています。
このチュートリアルで追加した流体は流体APIをサポートする他のMODで扱うことが出来る可能性があります。

ソースコード[編集]

  • SampleFluid.java
package samplefluid;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Icon;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.ForgeSubscribe;
import net.minecraftforge.fluids.BlockFluidClassic;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidRegistry;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;

@Mod(modid="samplefluid.SampleFluid", name="SampleFluid", version="1.0")
public class SampleFluid {

	//流体ブロックID
	public static int sampleFluidBlockID = 2892;
	//流体ブロック
	public static BlockFluidClassic sampleFluidBlock;

	//容器入り流体のアイテムID
	public static int sampleFluidID = 28000;
	//容器入り流体アイテム
	public static Item itemSampleFluid;

	//流体クラス
	public static Fluid sampleFluid ;

	//ドメイン名
	//他mod等との競合を避けるための識別用の名前です。 ※英数字小文字 及び "." 等が使えます。大文字や"/"は使えません。
	public static final String DOMAIN_NAME = "samplefluid";

	@EventHandler
	public void preInit(FMLPreInitializationEvent evt) {
		//Fluidクラスのインスタンスを生成
		sampleFluid = new Fluid("FluidSample")
			.setViscosity(1000)
				//流れる速度
				//小さいほど早い(アイテムを押す速さではない
				//水 1000 溶岩6000 ネザー溶岩2000
			    //溶岩のように、状況で変化させるには BlockFluidBase.tickRate をオーバーライド実装ください。
			.setLuminosity(15)
				//流体の明るさ
				//流れの先のように水位が下がるのに比例して暗くなる
			.setDensity(500);
				//0以上で下へ、0未満で上へ流れます
				//また密度が高い方の流体が、設置されている流体を押しのけて流れ込みます
				//BC原油は800となっています。
				//水や溶岩には密度設定がないので、無条件で押しのけ流れ込むため、後述を参考に別途実装が必要です。


		//流体レジストリに追加
		FluidRegistry.registerFluid(sampleFluid);

		//Materialは別途実装しましょう。
		//ちなみにWaterを設定すると、水同様溶岩を固める能力を持ちます。
		sampleFluidBlock = (BlockFluidClassic)new BlockFluidClassic(sampleFluidBlockID, sampleFluid, Material.water)
			.setUnlocalizedName(DOMAIN_NAME + ".liquidSample")
			//※一枚textureならこれでよいですが、side,meta(8面別、水位)で別にする場合getIconをオーバーライド実装下さい
			.func_111022_d(DOMAIN_NAME + ":" + sampleFluid.getName())
			.setCreativeTab(CreativeTabs.tabDecorations);

		/*
		 * 流れ込んでブロックを上書きするかどうか個別に登録する方法
		 *
		 * BlockFluidClassicを継承したクラスで
		 * displacementIds.put(blockID, [上書きする:true/しない:false]);
		 * のように追加します。
		 * displacementIds.put(Block.waterStill.blockID,false);
		 * と追加すれば、水源に流れ込まなくなります。
		 *
		 * 別方法としては下記のようにすると、バニラ式の流体には流れこまず、それ以外にはForge式判定を行うようになります。
		 *
		 * public boolean canDisplace(IBlockAccess world, int x, int y, int z){
		 * 	int bId = world.getBlockId(x, y, z);
		 * 	if(!(Block.blocksList[bId] instanceof BlockFluidBase))
		 * 		if(world.getBlockMaterial(x,  y,  z).isLiquid()) return false;
		 * 	return super.canDisplace(world, x, y, z);
		 * }
		 *
		 * public boolean displaceIfPossible(World world, int x, int y, int z) {
		 * 	int bId = world.getBlockId(x, y, z);
		 * 	if(!(Block.blocksList[bId] instanceof BlockFluidBase))
		 * 		if(world.getBlockMaterial(x,  y,  z).isLiquid()) return false;
		 * 	return super.displaceIfPossible(world, x, y, z);
		 * }
		 */

		/*
		 * 流体の混合反応について
		 * 溶岩の接触による黒曜石化、丸石化は
		 * BlockFluid.checkForHardenを参考に実装するとよいでしょう。
		 *
		 * public void onBlockAdded(World par1World, int par2, int par3, int par4){
		 * 	super.onBlockAdded(par1World, par2, par3, par4);
		 * 	checkForHarden(par1World, par2, par3, par4);
		 * }
		 * public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5){
		 * 	super.onNeighborBlockChange(par1World, par2, par3, par4, par5);
		 * 	checkForHarden(par1World, par2, par3, par4);
		 * }
		 *
		 * 溶岩が水に流れ込むことによる、焼き石化は下記のような処理でできます。
		 * protected void flowIntoBlock(World world, int x, int y, int z, int meta){
		 * 	if (meta < 0) return;
		 * 	if (displaceIfPossible(world, x, y, z)){
		 * 		流れ込んで上書きした場合(溶岩が焼き石化する状態
		 * 	}else{
		 * 		流れ込まず上に乗った場合
		 *  }
		 *  super.flowIntoBlock(world, x, y, z, meta);
		 * }
		 */

		/*
		 * 無限水源化したい場合
		 * updateTickをオーバーライドし
		 * BlockFlowingの64行目から103行目までを参考に周囲の水源、直下ブロックの判定をしましょう
		 * numAdjacentSourcesが、周囲の水源の数で、上記例であればj1が0であれば、水源化です。
		 */

		GameRegistry.registerBlock(sampleFluidBlock, sampleFluidBlock.getUnlocalizedName());


        //TextureStitchEvent.Preイベントのためにイベントバスに登録します。
		MinecraftForge.EVENT_BUS.register(this);
	}

	@EventHandler
	public void load(FMLInitializationEvent event) {
		//容器入り流体の登録です。
		//通常のアイテム作成と同様なので省略します。
		//バケツのような動作には別途実装が必要です。
		itemSampleFluid = new Item(sampleFluidID)
				.setUnlocalizedName(DOMAIN_NAME + ".fluidSample")//内部アイテム名の登録
				//テクスチャ名の登録 func_111206_dはForgeバージョンによって名称が変わることがあります。
				//assets/samplefluid/textures/item/bottoledLiquidSample.png が必要です。
				.func_111206_d(DOMAIN_NAME + ":bottled" + sampleFluid.getName());

		ItemStack filledContainer = new ItemStack(itemSampleFluid);
		FluidContainerRegistry.registerFluidContainer(sampleFluid, filledContainer);

		//ボトル入り流体のローカライズ表示名の登録
		LanguageRegistry.addName(itemSampleFluid, "bottledSampleFluid");
		LanguageRegistry.instance().addNameForObject(itemSampleFluid, "ja-JP", "ボトル要りサンプル流体");

		//流体のローカライズ表示名の登録
		LanguageRegistry.instance().addStringLocalization(sampleFluid.getUnlocalizedName(), "SampleFluid");
		LanguageRegistry.instance().addStringLocalization(sampleFluid.getUnlocalizedName(), "ja-JP", "サンプル流体");

		//流体ブロックのローカライズ表示名の登録
		LanguageRegistry.addName(sampleFluidBlock, "SampleFluid");
		LanguageRegistry.instance().addNameForObject(sampleFluidBlock, "ja-JP", "サンプル流体");

	}


	/**
	 * IconはResourceパックを変更する際、新しいインスタンスが生成されるため
	 * TextureMapの生成タイミングをフックして登録し直す必要があります。
	 *
	 * また、ブロック無し流体の場合ここでRegisterIconを呼ぶ必要があるため
	 * TextureStitchEvent.Pre で処理します。
	 */
	@ForgeSubscribe
	public void PreTextureStitchEvent(TextureStitchEvent.Pre event){
		//必ず 0:"/terain.png"(※ブロックと共有) のTextureMapに画像を登録する必要があります。
		if(event.map.textureType == 0){

			//初期化時に保存しておいた流体クラスを利用する
			//または流体名を指定してFluidRegistoryからFluidインスタンスを取得します。

			Fluid f = sampleFluid;
			//Fluid f = FluidRegistry.getFluid("LiquidSample");

			if(f != null){
				if(f.getBlockID() != -1){
					//流体ブロックを実装している場合は、ブロックからの流用が可能です。
					//getIcon(int side,int meta) getBlockTextureFromSide(int side)等。

					f.setIcons(Block.blocksList[f.getBlockID()].getBlockTextureFromSide(1));
				}else{
					//ブロックのIcon登録と同様です。

					//この例の場合 assets/samplefluid/textures/blocks/LiquidSample.png が必要です。
					//※本チュートリアルでは DOMAIN_NAME = samplefluid , f.getName() == "LiquidSample" となっています。
					Icon commonIcon = event.map.registerIcon(DOMAIN_NAME + ":" + f.getName());

					//下記のように、ドメインを省略した場合はデフォルトでminecraftドメインとなり
					//event.map.registerIcon("name");
					//必要な画像は assets/minecraft/textures/blocks/name.png となります。
					//できるだけ重複を避けるために、独自ドメインを指定しましょう。

					f.setIcons(commonIcon);


					//また、静止状態 still / 流動状態 flowingを別々に指定できます。
					//f.setIcons(stillIcon, flowingIcon);
					//f.setStillIcon(stillIcon);
					//f.setFlowingIcon(flowingIcon);
				}
			}
		}
	}

}

解説[編集]

sampleFluid = new Fluid("LiquidSample");

Fluidインスタンスを作成する際に指定する名前が、辞書登録される名称となります。
この段階ではまだ辞書登録されません。

FluidRegistry.registerFluid(sampleFluid);

流体を辞書へ登録します。
登録に成功すれば:True
既に登録済みの流体名であれば:Falseが戻り値となります。

FluidContainerRegistry.registerFluidContainer(sampleFluid, filledContainer);

容器入り流体の登録です。例の場合バケツ1杯分(内部数値1000)で登録されます。

Fluidには、アイテムやブロックを関連付ける必要性は必ずしも無いため
別途Icon登録処理が必要になります。(ブロックがある場合流用はできます。

@EventHandler
	public void preInit(FMLPreInitializationEvent evt) {
		//TextureStitchEvent.Preイベントのためにイベントバスに登録します。
		MinecraftForge.EVENT_BUS.register(this);
	}

TextureStitchEvent.Preイベントのためにイベントバスに登録します。
ブロック無し流体の場合RegisterIconを呼ぶために TextureStitchEvent.Pre である必要があります。

PreTextureStitchEventに関しては、複数登録する場合は、流体の取得方法の工夫とループを組むなどの改変が必要となります。、

テクスチャ[編集]

今回の場合は、容器テクスチャに
"assets/samplefluid/textures/items/LiquidSample.png"
流体用テクスチャに
"assets/samplefluid/textures/blocks/LiquidSample.png"
が使用されます。

その他[編集]

1.5.2までのMinecraft ForgeではBCで使われていた液体APIを改修したものが実装されていました。
1.6.xからはLiquidDictionary→FluidDictionaryに刷新され多くの機能が増えました。
これにより、アイテムやブロックの実体を持たずに流体のみが存在する物を追加できるようになりました。
詳しくは、Fluidクラスを見てください。(液体の明るさや、密度などが設定できるようです)


自分のコメントを追加
Minecraft Modding Wikiはすべてのコメントを歓迎します。匿名で投稿したくない場合は、アカウント作成またはログインしてください。無料です。