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

このページはMinecraft Forge WikiHow to use NBT Tag Compoundの訳です。

NBT Tag Compoundの使い方[編集]

最終的な目標[編集]

最後にブロックを右クリックした5人のプレイヤーを記録する "last 5 visitors"ブロックを作成します

前提となる知識[編集]

Basic blocks

NBTとは?[編集]

NBTとは、Minecraftのマップ保存の為にNotchが作成したフォーマットです。ノードを基にしたファイルで、regionファイル、player.datファイル、level.datファイルに使われています。

バイナリだということを除けば、NBTの構造はとてもXMLに似ていると考えることができます。

どのNBTファイルも必ず"Tag_Compound"という種類のルートタグから始まっていて、それがこのチュートリアルの名前になっています。1つのTag_Compoundは他のノードをその中に保持することができます。そのルートタグは通常名前を持ちません。

NBTを使う理由[編集]

NBTはブロックやアイテムのデータ/メタデータに保存出来ないものを保存するのにとても優れています。例えば、チェストの全アイテムの情報は4ビットのメタデータには保存出来ません。でも、NBTなら実質無限なのです。ただ、HDDの容量が実に増えているとは言え、大量に自然に現れるブロックにNBTを使用してはいけません。

また、NBTはアイテムにも便利です。例えば、本は作者と内容を保存するためにNBTを使用しています。

MinecraftのどこにNBTが使われているでしょう?[編集]

  • 看板
  • インベントリを持つ全てのブロック(かまど、チェスト、などなど)

タグの種類[編集]

NBTには12種類ものタグがあり、様々なデータが格納可能です:

ID 名前 解説
0 TAG_End Compound Tagの終わり。通常見ることはない。
1 TAG_Byte 1バイトのデータを含むタグ
2 TAG_Short 1つのshort(数値)を含むタグ
3 TAG_Int 1つのintegerを含むタグ
4 TAG_Long 1つのlongを含むタグ
5 TAG_Float 1つのfloatを含むタグ
6 TAG_Double 1つのdoubleを含むタグ
7 TAG_Byte_Array byteの配列を含むタグ
8 TAG_String 文字列を含むタグ
9 TAG_List 同じ種類の無名タグのリスト
10 TAG_Compound 名前付きタグのリスト。それぞれのNBTファイルの起点。他のCompoundを含むことが出来る。
11 TAG_Int_Array integerの配列

MinecraftCoalitionのNBTに関する情報はこのページの「参照」以下より参照してください。

ブロックのクラスを書く[編集]

もし作っているのがアイテムなら、ItemStackからCompound Tagを取得出来ます。それについてのチュートリアルを作成する必要があるでしょう。でも今はブロックで忙しいのです。

NBTの値を保存するためにはTileEntityというものが必要です。TileEntityは基本的にブロックと繋がったエンティティで、ブロックの情報を保存するために使われます。

最初に、コンストラクタを作ります。このクラスはBlockContainerを継承することに注意してください。

public BlockVisitor(int id) {
        super(id, 35, Material.circuits);
        // TODO Auto-generated constructor stub
}

これについては説明する必要は無いでしょう。

次は、右クリックを検知するメソッドです。

public boolean onBlockActivated(World world, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
{
        if(!world.isRemote)
        {
                TileEntityVisitor t = (TileEntityVisitor) world.getBlockTileEntity(par2, par3, par4);
                t.processActivate(par5EntityPlayer, world);
        }
        return true;
}

行ごとに見て行きましょう。

if(!world.isRemote)

この行は、メソッドを呼び出しているのがサーバーかクライアントかを確認します。isRemoteはクライアントではtrueを返します。これは、1.2.5以降ではシングルでもローカルサーバー上で実行されているためです。つまり、これはサーバー/クライアントを検知する簡単な方法なのです。

TileEntityVisitor t = (TileEntityVisitor) world.getBlockTileEntity(par2, par3, par4);

この行では変数tにgetBlockTileEntityメソッドを用いてワールドからTileEntityを取得します。par2、3、4はx、y、z座標を表します。 TileEntityVisitorにキャストしていることに注意してください。

t.processActivate(par5EntityPlayer, world);

これは、登録と表示のためにTileEntityに設けた、processActivateというメソッドを呼び出しています。引数はプレイヤーとワールドです。

また、MinecraftにTileEntityを使うことを知らせるためにメソッドを追加する必要があります:

public boolean hasTileEntity(int metadata)
{
    return true;
}

ブロックのファイルの最後のメソッドはcreateNewTileEntity()です。これは非常に単純で、TileEntityVisitorの新しいインスタンスを返すのみとなっています:

public TileEntity createNewTileEntity(World par1World)
{
    try
    {
        return new TileEntityVisitor();
    }
    catch (Exception var3)
    {
        throw new RuntimeException(var3);
    }
}

これでブロックのファイルについては終わりました。TileEntityに移りましょう。

TileEntityを作る[編集]

TileEntityはコンストラクタを必要としません。実際、最初にするのは訪問者を保持する変数の定義です:

String visitor1="none";
String visitor2="none";
String visitor3="none";
String visitor4="none";
String visitor5="none";

配列は使いません。何か問題でも?

次はNBT Tag Compoundから情報を読み込むメソッドを書きます:

@Override
public void readFromNBT(NBTTagCompound nbt)
{
    super.readFromNBT(nbt);
    this.visitor1 = nbt.getString("visitor1");
    this.visitor2 = nbt.getString("visitor2");
    this.visitor3 = nbt.getString("visitor3");
    this.visitor4 = nbt.getString("visitor4");
    this.visitor5 = nbt.getString("visitor5");
}

お分かりの通り、読み込みのためにNBTTagComponundを使います。コードについては自明です。注意として、super.readFromNBT(TagCompound);の実行を忘れないでください。幾つもの情報をTileEntity自身が保存し、読み込んでいるからです。

次のメソッドはNBTへの保存です:

@Override
public void writeToNBT(NBTTagCompound nbt)
{
    super.writeToNBT(nbt);
    nbt.setString("visitor1", visitor1);
    nbt.setString("visitor2", visitor2);
    nbt.setString("visitor3", visitor3);
    nbt.setString("visitor4", visitor4);
    nbt.setString("visitor5", visitor5);
}

このコードもまた自明です。

最後のコードはブロックの方で呼び出されていたメソッドです。

public void processActivate(EntityPlayer par5EntityPlayer, World world) {
        if(!visitor1.equals(par5EntityPlayer.getEntityName()))
        {
                visitor5=visitor4;
                visitor4=visitor3;
                visitor3=visitor2;
                visitor2=visitor1;
                visitor1=par5EntityPlayer.getEntityName();
        }
        //System.out.println("Visitors: " + visitor1 + ", " + visitor2 + ", " + visitor3 + ", " + visitor4 + ", " + visitor5);
        par5EntityPlayer.addChatMessage("Visitors: " + visitor1 + ", " + visitor2 + ", " + visitor3 + ", " + visitor4 + ", " + visitor5);
        world.notifyBlockChange(xCoord, yCoord, zCoord, 2);
}

これには幾らかの説明が必要でしょう:

if(!visitor1.equals(par5EntityPlayer.getEntityName()))

これは、同じ訪問者を2度登録させないためです。

visitor5=visitor4;
visitor4=visitor3;
visitor3=visitor2;
visitor2=visitor1;
visitor1=par5EntityPlayer.getEntityName();

これは訪問者一覧を入れ替えます。

world.notifyBlockChange(xCoord, yCoord, zCoord, 2);

安全のためです。このメソッドはワールドに周囲のブロックを更新することを伝えます。チャットに訪問者を表示していることにも注意してください。

全てのコード[編集]

VisitorBlock.java(メインのコード)

package com.generic.tutorial.nbt.block;

import net.minecraft.src.*;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.Mod.PreInit;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.registry.GameRegistry;

@Mod(modid="VisitorBlock", name="VisitorBlock", version="0.0.1")
@NetworkMod(clientSideRequired=true, serverSideRequired=false)
public class VisitorBlock {
	@Instance("VisitorBlock")
	VisitorBlock instance;
	BlockVisitor visitor;
	int blockID=200;
	@PreInit
	public void preInit(FMLPreInitializationEvent event)
	{
		
	}
	@Init
	public void load(FMLInitializationEvent event) {
		visitor = new BlockVisitor(blockID);
		GameRegistry.registerBlock(visitor);
		GameRegistry.registerTileEntity(TileEntityVisitor.class, "visitorBlock");
		GameRegistry.addRecipe(new ItemStack(visitor, 1), "###", "#%#", "###", '#', Item.redstone, '%', Item.paper);
	}
}

BlockVisitor.java (ブロックのクラス)

package com.generic.tutorial.nbt.block;

import net.minecraft.src.Block;
import net.minecraft.src.BlockContainer;
import net.minecraft.src.EntityPlayer;
import net.minecraft.src.Material;
import net.minecraft.src.TileEntity;
import net.minecraft.src.World;

public class BlockVisitor extends BlockContainer {

	public BlockVisitor(int id) {
		super(id, 35, Material.circuits);
		// TODO Auto-generated constructor stub
	}
	public boolean onBlockActivated(World world, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
    {
		if(!world.isRemote)
		{
			TileEntityVisitor t = (TileEntityVisitor) world.getBlockTileEntity(par2, par3, par4);
			t.processActivate(par5EntityPlayer, world);
		}
		return true;
    }
	public boolean hasTileEntity(int metadata)
    {
        return true;
    }
	@Override
	public TileEntity createNewTileEntity(World par1World)
    {
        try
        {
            return new TileEntityVisitor();
        }
        catch (Exception var3)
        {
            throw new RuntimeException(var3);
        }
    }   

}

TileEntityVisitor.java

package com.generic.tutorial.nbt.block;

import net.minecraft.src.*;

public class TileEntityVisitor extends TileEntity{

	String visitor1="none";
	String visitor2="none";
	String visitor3="none";
	String visitor4="none";
	String visitor5="none";
	public void processActivate(EntityPlayer par5EntityPlayer, World world) {
		if(!visitor1.equals(par5EntityPlayer.getEntityName()))
		{
			visitor5=visitor4;
			visitor4=visitor3;
			visitor3=visitor2;
			visitor2=visitor1;
			visitor1=par5EntityPlayer.getEntityName();
		}
		//System.out.println("Visitors: " + visitor1 + ", " + visitor2 + ", " + visitor3 + ", " + visitor4 + ", " + visitor5);
                par5EntityPlayer.addChatMessage("Visitors: " + visitor1 + ", " + visitor2 + ", " + visitor3 + ", " + visitor4 + ", " + visitor5);
		world.notifyBlockChange(xCoord, yCoord, zCoord, 2);
	}
	
	@Override
	public void readFromNBT(NBTTagCompound nbt)
    {
        super.readFromNBT(nbt);
        this.visitor1 = nbt.getString("visitor1");
        this.visitor2 = nbt.getString("visitor2");
        this.visitor3 = nbt.getString("visitor3");
        this.visitor4 = nbt.getString("visitor4");
        this.visitor5 = nbt.getString("visitor5");
    }

    @Override
    public void writeToNBT(NBTTagCompound nbt)
    {
    	super.writeToNBT(nbt);
    	nbt.setString("visitor1", visitor1);
        nbt.setString("visitor2", visitor2);
        nbt.setString("visitor3", visitor3);
        nbt.setString("visitor4", visitor4);
        nbt.setString("visitor5", visitor5);
    }

}

注意事項[編集]

Forge(訳注:これ自体はFML)を使ってTileEntityを登録する必要があります:

GameRegistry.registerTileEntity(TileEntityVisitor.class, "visitorBlock");

=参考[編集]

Minecraft CoalitionのNBTのページ