ブロック解説

他のModのブロックを取得したい

下記のコードで実装できる

import net.minecraft.block.Block;

import cpw.mods.fml.common.registry.GameRegistry;


public static void Test()

{

Block block = GameRegistry.findBlock(modId, name);

}

GameRegistry クラスの findBlock(String modId, String name) を呼び出すことで実装できる。

modId には取得したいブロックを追加する Mod の固有の ID 、name には取得したいブロックの Block ID(String) を代入する。

該当するブロックが無い場合は null が返ってくるため、 null チェックを必ずしよう。

筆者 : Megria 2023/6/2 更新

ブロックを炎で焼失されるようにしたい

下記のコードで実装できる。

import net.minecraft.block.Block;

import net.minecraft.block.BlockFire;


public static void InitFireInfo()

{

BlockFire fire = Blocks.fire;

fire.setFireInfo(block, 5, 20); // block に任意のブロックインスタンスを代入

}

BlockFire クラスの setFireInfo(Block, int, int) を呼び出すことで実装できる。

インスタンスメソッドのため、Blocks.fire 変数からインスタンスを取得してメソッドを呼び出している。

実質静的メソッドで、どこでも呼び出すことが可能だが、ブロック登録時に呼び出すのが無難だろう。

ちなみに Block のインスタンスさえ取得できれば登録できるので、既存のブロックなら Blocks クラスから、他の Mod のブロックなら GameRegistry.findBlock(String modId, String name) メソッドでインスタンスを取得すれば登録できる。

余談だが、Block の ID(int) が 4096 以上だと使えない。(内部実装が長さ 4096 の配列のため)

筆者 : Megria 2023/6/8 更新

チェストのレンダー

チェスト、ラージチェスト、トラップチェスト、トラップラージチェスト、エンダーチェストのレンダーは、 TileEntitySpecialRenderer クラスを継承した TileEntityChestRenderer クラスで実装されている。

ワールド上のレンダーでは TileEntityChestRenderer クラスの renderTileEntityAt(TileEntityChest entity, double x, double y, double z, float partialTickTime) メソッドを呼んでいる。

インベントリ上のレンダーでは TileEntityRendererChestHelper クラスの instance 変数を使用して、  renderChest(Block block, int meta, float brightness) メソッドを呼んでいる。

余談だが、 TileEntityRendererDispatcher クラスの instance 変数を使用して、 renderTileEntityAt(TileEntity entity, double x, double y, double z, float partialTickTime) メソッドを呼ぶと、 entity に応じたレンダーが行われる。

筆者 : Megria 2023/7/10 更新

TileEntity に応じた特殊レンダー

TileEntity があるブロックには、特殊レンダーを登録することができる。TileEntity のクラスオブジェクト (java 風に言うなら Class <? extends TileEntity > )を引数に登録するため、同じ TileEntity クラスに複数の特殊レンダーを登録することはできない。

特殊レンダーは TileEntitySpecialRenderer クラスを継承する。

特殊レンダーの登録は ClientRegistryクラスの bindTileEntitySpecialRenderer(Class <? extends TileEntity> tileEntityClass, TileEntitySpecialRenderer specialRenderer) を使用するか、同等の実装を行う。

バニラの特殊レンダーと、上記の方法で登録した特殊レンダーの取得TileEntityRendererDispatcher クラスの instance を使用し、getSpecialRenderer(TileEntity entity) メソッドで対応する TileEntitySpecialRenderer インスタンスを取得する。

レンダーは、取得した TileEntitySpecialRenderer オブジェクトの renderTileEntityAt(TileEntity entity, double x, double y, double z, float partialTickTime) メソッドを使用するか、 TileEntityRendererDispatcher クラスの instance を使用し、renderTileEntityAt(TileEntity entity, double x, double y, double z, float partialTickTime) メソッドを使用する。

import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;

import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;

import net.minecraft.tileentity.TileEntity;


public static void bindTileEntitySpecialRenderer(Class <? extends TileEntity> tileEntityClass, TileEntitySpecialRenderer specialRenderer)

{

TileEntityRendererDispatcher.instance.mapSpecialRenderers.put(tileEntityClass, specialRenderer);

specialRenderer.func_147497_a(TileEntityRendererDispatcher.instance);

}

バニラのブロックで特殊レンダーが実装されているのは下記の通りである。

筆者 : Megria 2023/7/10 更新

ドロップするアイテムを変えたい

サバイバルモードで、石炭やダイヤモンドなどのように、採掘した時にドロップするアイテムを変えたい場合がある。

ドロップするアイテムを取得するメソッドは、Block クラスの getItemDropped(int meta, Random rand, int fortune) である。

ドロップするアイテムのダメージ値を取得するメソッドは、Block クラスの damageDropped(int meta) である。

ドロップするアイテムの数を取得するメソッドは、Block クラスの quantityDropped(int meta, int  fortune, Random random) である。必要な引数が幸運レベルのみの場合は quantityDroppedWithBonus(fortune, random) メソッド、random のみで十分な場合は quantityDropped(Random random) メソッドと使い分けると良い。

NBTTagなどを付与する場合は getDrops(World world, int x, int y, int z, int metadata, int fortune) メソッドをオーバーライドしよう。

Block クラスのコード抜粋

package net.minecraft.block;


import java.util.ArrayList;

import java.util.Random;


import net.minecraft.item.Item;

import net.minecraft.item.ItemStack;

import net.minecraft.world.World;


public class Block

{

/**

* ブロック破壊時にドロップするアイテムの数量を返します。

*/

public int quantityDropped(Random random)

{

return1;

}

/**

* ブロックによってドロップされる通常の数量に 1 のボーナスを加えた値を 'i' (両端を含む) で返します。

*/

public int quantityDroppedWithBonus(int fortune, Random random)

{

return this.quantityDropped(fortune);

}

/**

* メタデータと幸運レベルに敏感なバージョン。

* これは、1.1 の古い (int meta, Random rand) バージョンを置き換えます。

*

* @param meta ブロックメタデータ

* @param fortune 現在のアイテムの幸運レベル

* @param random 乱数発生器

* @return ドロップするアイテムの数

*/

public int quantityDropped(int meta, int  fortune, Random random)

{

/**

* ブロックによってドロップされる通常の数量に 1 のボーナスを加えた値を 'i' (両端を含む) で返します。

*/

return quantityDroppedWithBonus(fortune, random);

}

/**

* これにより、このブロックからドロップされたアイテムの完全なリストが返されます。

*

* @param world 現在の世界

* @param x X 位置

* @param y Y 位置

* @param z Z 位置

* @param metadata 現在のメタデータ

* @param fortune 採掘道具の幸運レベル

* @return このブロックがドロップするすべての要素を含む ArrayList

*/

public ArrayList<ItemStack> getDrops(World world, int x, int y, int z, int metadata, int fortune)

{

ArrayList<ItemStack> ret = new ArrayList<ItemStack>();


int count = quantityDropped(metadata, fortune, world.rand);

for(int i = 0; i < count; i++)

{

Item item = getItemDropped(metadata, world.rand, fortune);

if (item != null)

{

ret.add(new ItemStack(item, 1, damageDropped(metadata)));

}

}

return ret;

}

}

筆者 : Megria 2023/7/13 更新

ホイールクリックで取得するアイテムを変えたい

クリエイティブモードでは、ホイールクリックすると対象のブロックをアイテムとして取得する機能がある。

基本的にはそのままでも機能するが、時には意図的に取得するアイテムを変えたい場合がある。

ホイールクリックでアイテムを取得するメソッドは、Block クラスの getPickBlock(MovingObjectPosition target, World world, int x, int y, int z, EntityPlayer player) である。

取得するアイテムのダメージ値だけを変えたい場合は getDamageValue(World world, int x, int y, int z) メソッドをオーバーライドしよう。

TileEntity などに応じて取得するアイテムを変える場合や、NBTTag を付与する場合はgetPickBlock(MovingObjectPosition target, World world, int x, int y, int z, EntityPlayer player) メソッドをオーバーライドしよう。

また、target 変数を使用することで、見ている箇所に応じて取得するアイテムを変えることができる。

Block クラスのコード抜粋

package net.minecraft.block;

import net.minecraft.item.Item;

import net.minecraft.item.ItemBlock;

import net.minecraft.item.ItemStack;

import net.minecraft.util.MovingObjectPosition;

import net.minecraft.world.World;

import net.minecraft.entity.player.EntityPlayer;


public class Block

{

/**

* ユーザーがこのブロックでクリエイティブ選択ブロック ボタンを使用すると呼び出されます。

*

* @param target プレイヤーが見ている完全なターゲット

* @return プレイヤーのインベントリに追加するItemStack。何も追加しない場合はNull。

*/

public ItemStack getPickBlock(MovingObjectPosition target, World world, int x, int y, int z, EntityPlayer player)

{

return getPickBlock(target, world, x, y, z);

}

@Deprecated

public ItemStack getPickBlock(MovingObjectPosition target, World world, int x, int y, int z)

{

Item item = getItem(world, x, y, z);


if (item == null)

{

return null;

}


Block block = item instanceof ItemBlock && !isFlowerPot() ? Block.getBlockFromItem(item) : this;

return new ItemStack(item, 1, block.getDamageValue(world, x, y, z));

}

/**

* ブロックのダメージ値を取得します(ピックブロックで使用)。

*/

public int getDamageValue(World world, int x, int y, int z)

{

return this.damageDropped(world.getBlockMetadata(x, y, z));

}

}

筆者 : Megria 2023/7/12 更新

シルクタッチで取得するアイテムを変えたい

シルクタッチでアイテムを取得するメソッドは、Block クラスの createStackedBlock(int meta) で実装している。

デフォルトでは、対応する ItemBlock クラスで getHasSubtypes() が false を返す場合は meta の値を無視する。

変える場合はこのメソッドをオーバーライドしよう。

なお、この方法では TileEntity には対応できない。

対応する場合はかなり手間だが Block クラスの harvestBlock(World world, EntityPlayer player, int x, int y, int z, int meta) メソッドをオーバーライドしよう。

Block クラスのコード抜粋

package net.minecraft.block;

import net.minecraft.item.Item;

import net.minecraft.item.ItemStack;


public class Block

{

/**

* 現在のブロック タイプの単一インスタンスを含む項目スタックを返します。

* 「meta」はブロックのサブタイプ/ダメージであり、サブタイプをサポートしないブロックでは無視されます。

* 収集できないブロックは null を返す必要があります。

*/

protected ItemStack createStackedBlock(int meta)

{

int j = 0;

Item item = Item.getItemFromBlock(this);


if (item != null && item.getHasSubtypes())

{

j = meta;

}


return new ItemStack(item, 1, j);

}

}

筆者 : Megria 2023/7/12 更新

ピストンで移動可能かどうかの判定

Block クラスの getMobilityFlag() で実装している。

返り値は int 型である。それぞれの意味は下記を確認。

0 : フリー

1 : 押すことはできないが、移動することはできる

2 : 完全な不動性とピストンの停止

筆者 : Megria 2023/7/12 更新

ビーコンの土台に使用できるかどうかの判定

Block クラスの isBeaconBase(IBlockAccess worldObj, int x, int y, int z, int beaconX, int beaconY, int beaconZ) で実装している。

返り値は boolean 型である。バニラの鉱石ブロックのようにふるまうブロックを作成する場合は true を返す。

ビーコンの座標とこのブロックの座標を比較することでx段目のみ有効にしたりすることもできる。

筆者 : inurokosann 2023/7/16 更新

ブロックがRS信号を受けているかどうかの判定

World クラスの onNeighborBlockChange(World world, int x, int y, int z, Block block) で実装している。

返り値は boolean 型で、RS信号が入力されている場合は true が返ってくる。

このメソッドをBlockやTileEntityのメソッド内で動かすことで、レッドストーンランプやドアなどを作成することができる。

クリックして例文を表示

例:RS入力があるときmatadataを1へ、RS入力がない時は0に変更するBlockの作成


import net.minecraft.block.Block;

import net.minecraft.world.World;

@Override//周りのブロックが更新されたときに呼ばれます

public void onNeighborBlockChange(World world, int x, int y, int z, Block block) {

super.onNeighborBlockChange(world, x, y, z, block);

int meta  = world.getBlockMetadata(x, y, z);


//ここが本題のRS入力がされているかどうかの判定をするメソッドです

boolean RSsignal = world.isBlockIndirectlyGettingPowered(x,y,z);

if(meta == 0&&RSsignal) {

world.setBlockMetadataWithNotify(x, y, z, 1, 2);

}

if(meta == 1&&!RSsignal) {

world.setBlockMetadataWithNotify(x, y, z, 0, 2);

}

}

@Override//ブロックが設置されたときに呼ばれます

public void onBlockAdded(World world, int x, int y, int z) {

super.onBlockAdded(world, x, y, z);

int meta  = world.getBlockMetadata(x, y, z);


//ここが本題のRS入力がされているかどうかの判定をするメソッドです

boolean RSsignal = world.isBlockIndirectlyGettingPowered(x,y,z);

if(meta == 0&&RSsignal) {

world.setBlockMetadataWithNotify(x, y, z, 1, 2);

}

if(meta == 1&&!RSsignal) {

world.setBlockMetadataWithNotify(x, y, z, 0, 2);

}

}


筆者 : inurokosann 2023/7/16 更新

ブロックの当たり判定を変えたい

ブロックの当たり判定を取得するメソッドは、Block クラスの getCollisionBoundingBoxFromPool(World world, int x, int y, int z) で実装している。

このメソッドは単純な四角形の当たり判定しか返せないので注意。

Entity に対しての当たり判定は Block クラスの addCollisionBoxesToList(World world, int x, int y, int z, AxisAlignedBB mask, List list, Entity entiy) で実装している。

複雑な当たり判定を設定するならこのメソッドを使用しよう。

Block クラスのコード抜粋

package net.minecraft.block;

import net.minecraft.world.World;

import net.minecraft.util.AxisAlignedBB;


public class Block

{

/**

* 交差するすべてのコリジョン ボックスをリストに追加します。 (マスクと交差するボックスのみをリストに追加してください。)

* パラメータ: world, x, y, z, mask, list, 衝突 entity

*/

public void addCollisionBoxesToList(World world, int x, int y, int z, AxisAlignedBB mask, List list, Entity entity)

{

//mask は entity の当たり判定です。

//block の当たり判定は list に追加する。

AxisAlignedBB axisalignedbb1 = this.getCollisionBoundingBoxFromPool(world, x, y, z);


if (axisalignedbb1 != null && mask.intersectsWith(axisalignedbb1))

{

list.add(axisalignedbb1);

}

}

/**

* 境界ボックスのプールから境界ボックスを返します (これは、プールが再利用のためにクリアされた後にこのボックスが変更される可能性があることを意味します)

 */

public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z)

{

return AxisAlignedBB.getBoundingBox((double)x + this.minX, (double)y + this.minY, (double)z + this.minZ, (double)x + this.maxX, (double)y + this.maxY, (double)z + this.maxZ);

}

}

筆者 : Megria 2024/1/7 更新

ブロックが設置されているときに定期的にメソッドを実行したい

TileEntityには.updateEntity()があるが、ブロック単体で同じようなことはできないのでしょうか?

もちろんできます(inurokoは最近知った)。作物の成長などで使用してください。

Block.classをextendsしたクラス内に記述

@Override//どれくらいの間隔で実行するか

public int tickRate(World p_149738_1_) {

return 2;

}

@Override//ブロックを設置した際にBlockUpdateのスケジュールを送る。

public int onBlockPlaced(World w, int x, int y, int z, int side, float hX, float hY, float hZ, int meta) {

world.scheduleBlockUpdate(x, y, z, this, this.tickRate(w));

return super.onBlockPlaced(w, x, y, z, side, hX, hY, hZ, meta);

}

@Override//スケジュールされると定期的に呼ばれるメソッド、このメソッド内でもスケジュールを送ることでループさせる。

     public void updateTick(World w, int x, int y, int z, Random p_149674_5_) { 

//ここに定期的に実行したい内容(植物の成長判定など)を記述する


//再度スケジュールを送る。

world.scheduleBlockUpdate(x, y, z, this, this.tickRate(w));

} 

使用例(一定範囲のコウモリを駆除する撮影用ブロック)

Block.classをextendsしたクラス内に記述

@Override

public int tickRate(World world) {

return 10;

}

@Override

public int onBlockPlaced(World w, int x, int y, int z, int s, float hitX, float hitY, float hitZ, int meta) {

world.scheduleBlockUpdate(x, y, z, this, this.tickRate(w));

return super.onBlockPlaced(w, x, y, z, s, hitX, hitY, hitZ, meta);

}

@Override

public void updateTick(World world, int x, int y, int z, Random random) {

     double d0 = 255;

     AxisAlignedBB axisalignedbb = AxisAlignedBB.getBoundingBox((double)x, (double)y, (double)z, (double)(x + 1), (double)(y + 5), (double)(z + 1)).expand(d0, d0, d0);

         List list = world.getEntitiesWithinAABB(EntityBat.class, axisalignedbb);

         Iterator iterator = list.iterator();

         EntityBat entityBat;

         while (iterator.hasNext()) {

         entityBat = (EntityBat)iterator.next();

         if(entityBat != null) {

         entityBat.setDead();

         }

         }

         world.scheduleBlockUpdate(x, y, z, this, this.tickRate(world));

} 

筆者 : inurokosann 2024/4/22 更新

その他メソッド解説

public void setBlockBoundsBasedOnState(IBlockAccess world, int x, int y, int z) [net.minecraft.block.Block]

/** 現在の状態に基づいてブロックの境界を更新します。

* @param world: ワールドオブジェクト

* @param x: ブロックの x 座標

* @param y: ブロックの y 座標

* @param z: ブロックの z 座標 */

public void setBlockBoundsBasedOnState(IBlockAccess world, int x, int y, int z)

{

}

ブロックのサイズや形を更新するメソッド。

ブロックのレンダリングの前に実行されるほか、Block クラスの collisionRayTrace(World world, int x, int y, int z, Vec3 startVec, Vec3 endVec) メソッドでも呼ばれ、透視判定にも用いられる。

筆者 : Megria 2024/1/4 更新

public boolean renderAsNormalBlock() [net.minecraft.block.Block]

/** このブロックが通常のブロックとしてレンダリングされない場合は、False が返されます (例: 看板、ボタン、階段など)。 */

public boolean renderAsNormalBlock()

{

return true;

}

ブロックの光源処理やレッドストーンの処理、ボタンや松明が設置可能かどうか判定に用いられるメソッド。

ブロックの形が 1m 四方の立方体でない場合は False を返すのが無難だろう。

筆者 : Megria 2024/1/4 更新

public boolean isOpaqueCube() [net.minecraft.block.Block]

/** このブロックは (a) 不透明で、(b) 完全な 1 メートルの立方体ですか?

* これにより、隣接する 2 つのブロックの共有面をレンダリングするかどうか、またプレイヤーがこのブロックに松明やレッドストーン ワイヤーなどを取り付けられるかどうかが決まります。 */

public boolean isOpaqueCube()

{

return true;

}

ブロックの光源処理やレッドストーンの処理、ボタンや松明が設置可能かどうかの判定に用いられるメソッド。

ブロックが透過ブロックの場合や、形が 1m 四方の立方体でない場合は False を返す。

筆者 : Megria 2024/1/4 更新

public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z) [net.minecraft.block.Block]

/** 境界ボックスのプールから境界ボックスを返します (これは、プールが再利用のためにクリアされた後にこのボックスが変更される可能性があることを意味します) */

public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z)

{

return AxisAlignedBB.getBoundingBox((double)x + this.minX, (double)y + this.minY, (double)z + this.minZ, (double)x + this.maxX, (double)y + this.maxY, (double)z + this.maxZ);

}

単純な四角形で表すことができる基本的な当たり判定。

ブロックが透過ブロックの場合や、形が 1m 四方の立方体でない場合は False を返す。

筆者 : Megria 2024/1/6 更新

public void onNeighborChange(IBlockAccess world, int x, int y, int z, int tileX, int tileY, int tileZ) [net.minecraft.block.Block]

/** 

 * このブロックの側面の TileEntity が変更されるときに呼び出されます。または、 TileEntity が作成または破棄されます。

 * @param world: ワールドオブジェクト

 * @param x: このブロックインスタンスの x 座標

 * @param y: このブロックインスタンスの y 座標

 * @param z: このブロックインスタンスの z 座標

 * @param tileX: 変更された TileEntity の x 座標

 * @param tileY: 変更された TileEntity の y 座標

 * @param tileZ: 変更された TileEntity の z 座標

 */

public void onNeighborChange(IBlockAccess world, int x, int y, int z, int tileX, int tileY, int tileZ)

{


}

周囲のブロックの TileEntity がセットまたは削除された時に呼ばれる。

x、y、z にはこのブロックオブジェクトの座標が与えられ、 tileX、tileY、tileZ には変更された TileEntity の座標が与えられるので、座標が異なる。

また、このブロックの hasComparatorInputOverride() メソッドが true の場合、ブロックを設置またはメタデータ変更時にも呼ばれる模様(要検証)。

筆者 : Megria 2024/1/18 更新

public void setBlockUnbreakable() [net.minecraft.block.Block]

/** 

 * このメソッドはブロックの硬度を -1 に設定し、破壊できなくなります。

 * This method will set the hardness of the block to -1, making it indestructible

 */

public Block setBlockUnbreakable()

{

true.setHardness(-1.0F);

return this;

}

ブロックを破壊不可能にする。厳密にはブロックの硬さを0未満に設定して、採掘進行度を進めなくする。

岩盤のような仕切り用のブロックやエンドポータルのような構造物やクリエイティブ用途のブロックの作成時に最適。

なお記事の作成時に気になりTNTで爆破してみたが爆発の耐性は下記の別メソッドで設定する模様(知らなかった)

筆者 : inurokosann 2024/4/22 更新

public void setResistance(float r) [net.minecraft.block.Block]

/** 

 * 爆発に対するブロックの耐性を設定します。 構築の便宜のためにオブジェクトを返します。

 * Sets the the blocks resistance to explosions. Returns the object for convenience in constructing.

 */

public Block setResistance(float r)

{

true.blockResistance = r * 3.0F;

return this;

}

ブロックの爆発耐性を決めるメソッド。爆発耐性を設定したい場合はこのメソッドを使用する。

なお、Blockクラス内のsetHardness(float h)にて設定される数字が上書きされる可能性がある。


引数:rに入れるべき数字の目安を用意したので参考程度に(計算で求めさせたので一部小数点が循環している。)

木材:5.0F
丸石:10.0F
土:0.8333333...F
ネザーラック:0.6666666...F
鉄ブロック:10.0F
黒曜石:2000.0F
岩盤:6000000.0F

求め方:block.getExplosionResistance(new EntityTNTPrimed(world)) * 5.0f)/3.0f

筆者 : inurokosann 2024/4/22 更新