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

警告: ログインしていません。編集を行うと、あなたの IP アドレスが公開されます。ログインまたはアカウントを作成すれば、あなたの編集はその利用者名とともに表示されるほか、その他の利点もあります。

この編集を取り消せます。 下記の差分を確認して、本当に取り消していいか検証してください。よろしければ変更を保存して取り消しを完了してください。
最新版 編集中の文章
1行目: 1行目:
{{前提MOD|reqmod="Minecraft Forge 10.13.4.1448+"}}
+
{{前提MOD|reqmod="Minecraft Forge Universal"}}{{チュートリアルカテゴリー ‎|type=TileEntity| difficulty=0}}
{{チュートリアル難易度|difficulty=1|clear=none}}
+
==チェストにアイテムを入れる==
{{チュートリアルカテゴリー|difficulty=1|type=Item|clear=none}}
+
今回は右クリックされると、一つ上のチェスト(インベントリを持つTileEntity)
{{チュートリアルカテゴリー ‎|type=Block|difficulty=1}}
+
にアイテムを入れる。
 
+
<source lang="java">
 
+
package sample;
== IInventoryとは ==
 
 
 
マインクラフトには、"'''内部にアイテム(ItemStack)を持っているオブジェクト'''"が色々なところで存在します。これらは「'''インベントリ'''」と呼ばれ、チェストのようなTileEntityに限らず、Entity(プレイヤーやロバなど)、アイテム(一部MODで追加されるような、右クリックでインベントリGUIを開けるアイテムなど)にも実装できます。
 
IInventoryは、これらのインベントリを実装・操作するためのインターフェイスです。
 
 
 
取得したBlockやItemが具体的にどのブロックか調べることなく、'''IInventoryを実装しているかどうか'''を判定することで、そのオブジェクトからアイテムを取り出したり、または挿入することが出来ます。
 
  
IInventoryは、これを継承して機能を増やしたインターフェイスもあります。
+
//import省略
;ISidedInventory:バニラではカマドなどに実装されています。主にTileEntityなどワールドへの設置物に実装されるもので、操作されている"Side"(面や方角)によって操作できるスロットが異なるようにしたり、アクセス出来るスロットを制限できる機能があります。<br />例:バニラのカマドは、完成品スロットにアイテムを挿入できないよう制限されています。
 
;IHopper:バニラではホッパーに実装されています。機能追加と言うよりは、"ホッパーであるかどうか"の判定に利用されているようです。(ホッパーブロックやホッパーカート)
 
  
IInventoryの実装例については別のチュートリアルで解説しますので、ここでは、他のクラスで実装されているIInventoryを操作する手段の説明を記述します。
+
public class chestinitem extends Block {
 +
@SideOnly(Side.CLIENT)
 +
    private IIcon TopIcon;
  
=== 操作の流れ ===
+
    @SideOnly(Side.CLIENT)
 +
    private IIcon SideIcon;
  
#TileEntity、Entity、Itemなどのインスタンスを取得する
+
public open() {
#インベントリを実装しているかを確かめるため、IInventoryを実装しているかを判定する
+
        super(Material.rock);
#そのインベントリが利用可能な状態かどうかを判定する
+
        //省略
#アイテムを取り出したり、挿入する操作をする
+
    }
 +
@Override
 +
    public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float posX, float posY, float posZ){
 +
if (!world.isRemote)
 +
            {
 +
              Block block = world.getBlock(x, y+1, z);
 +
              int meta = world.getBlockMetadata(x, y+1, z);
  
== 実例 ==
 
  
===IInventoryの判定===
+
              if (block.hasTileEntity(meta))
 +
              {
 +
                  TileEntity tile = world.getTileEntity(x, y+1, z);
  
必要な部分でTileEntityやEntityのインスタンスを取得し、instanceofで判定するだけです。
+
                  if (tile != null)
 +
                  {
  
*TileEntity
+
                    if (tile instanceof IInventory)
 +
                    {
 +
                        IInventory inventory = (IInventory)tile;
  
よく利用されるのは、WorldとXYZ座標が得られるところで、.getTileEntityメソッドを利用してTileEntityを調べる方法ですね。<br />
 
引数にWorldとXYZ座標を持つメソッド内であれば色々な場所で利用できます。<br />
 
別のTileEntityからの参照、Block.onBlockActivatedメソッド、Item.onItemUseメソッド等々。<br />
 
操作する場合、サーバー側で処理を行うよう注意して下さい。
 
  
<source lang="java">
+
                        for (int pl = 0; pl < inventory.getSizeInventory(); ++pl)
TileEntity tile = world.getTileEntity(x, y, z);
+
                        {
if (tile != null && tile instanceof IInventory) {
+
                          ItemStack itemstack = inventory.getStackInSlot(pl);
  /* インベントリ操作をここで行う */
 
}
 
</source>
 
  
*Entityの場合
 
  
EntityでIInventoryを実装しているのは、バニラであればチェスト付きカートなど。<br />
+
                          if (itemstack == null)
但し、馬(EntityHorse)は持っているインベントリがアクセス出来ないよう隠蔽されているので、馬のチェストは操作できません。
+
                          {
  
引数にEntityを持つメソッド内で行うのであれば、そのEntityについて調べるだけでOK。例えば、Block.onEntityCollidedWithBlockメソッド内で接触中のEntityを操作したい場合など。
 
  
それ以外の場所では、AABB等を使って調べたい場所のEntityを取得する方法もあります。<br />※この方法の場合、サーバー側とクライアント側で得られるEntityの結果が異なるので、サーバー側のみで行うよう注意して下さい。
+
                              inventory.setInventorySlotContents(pl, new ItemStack(items.diamond));//ダイヤを一個入れる
 +
                              return true;
  
<source lang="java">
+
                          }
if (!world.isRemote){
+
                        }
  // 範囲内のEntityを調べるメソッド
+
                    }
  List<Entity> entities = world.getEntitiesWithinAABB(Entity.class,
+
                  }
AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ));
+
              }
 
+
            }
  // 範囲内に含まれていた全てのEntityを順に調査する
 
  if (entities != null && !entities.isEmpty()) {
 
for (Entity entity : entities) {
 
if (entity != null && entity instanceof IInventory) {
 
/* インベントリ操作部分 */
 
}
 
        }
 
  }
 
 
</source>
 
</source>
  
*Item
+
==解説==
 
+
変数plにTileEntity毎のインベントリ情報を入れ、<br>
ItemStackを取得できる場所は多く、これが得られればItemStack.getItemメソッドでItemのインスタンスを得られます。<br />
+
空いているスロットに入れている。
但し、インベントリを操作する場合はTileEntityと同様、サーバー側でのみ操作する方が望ましいです。<br />
 
(インベントリに限らず多くの処理は基本的にサーバー側で行い、クライアントへは後から処理結果を伝えるのみという方式が多いです。)
 
 
 
<source lang="java">
 
if (itemStack != null && itemStack.getItem() != null && itemStack.getItem() instanceof IInventory) {
 
  /* インベントリ操作をここで行う */
 
}
 
</source>
 
 
 
=== インベントリの操作 ===
 
 
 
IInventoryの種類の判定、利用可能判定、そしてItemStack操作を行います。
 
 
 
以下は、拙作FluidHopperでの一例です。<br />
 
FluidHopperのTileEntityのアップデート処理での、「真下にあるTileEntityのインベントリにアイテムを挿入する」という部分の実装例。<br />
 
※関係するメソッド部分のみの抜粋のため、以下のソースのみでは動作しない点に注意して下さい。
 
 
 
<source lang="java">
 
private void extractItemFromHopper() {
 
        /* 調べているのは、FluidHopperの真下の位置にあるTileEntity */
 
TileEntity tile = worldObj.getTileEntity(xCoord, yCoord - 1, zCoord);
 
 
 
if (tile != null && tile instanceof IInventory) {
 
IInventory inv = (IInventory) tile;
 
 
 
                /* このcurrentとは、これから真下に挿入される予定の、FluidHopper自身のインベントリのアイテムです。 */
 
ItemStack current = this.getStackInSlot(1);
 
if (current == null)
 
return;
 
 
 
                /* 真下がSidedInventoryの場合。この場合はアクセス出来るスロットかどうかを判定し、可能なスロットだけを挿入先スロットの候補とします。 */
 
if (tile instanceof ISidedInventory) {
 
ISidedInventory sided = (ISidedInventory) tile;
 
 
 
                        /* アクセス可能なスロットの番号のリストを得ます */
 
int[] accessible = sided.getAccessibleSlotsFromSide(1);
 
 
 
ItemStack ret = null;
 
int slot = 0;
 
 
 
for (int i : accessible) {
 
ItemStack item = sided.getStackInSlot(i);
 
 
 
                                /* 挿入しようとしているアイテムが、その番号のスロットに挿入可能かの判定を行います。
 
                                * falseの場合は挿入処理を止めます。
 
                 */
 
if (!sided.isItemValidForSlot(i, current))
 
continue;
 
 
 
 
 
                                /* スロットが空であるか、挿入しようとしているアイテムとスタックが重ねられる場合。
 
                                * ここではアイテム挿入処理をせずに、挿入予定のItemStackとスロット番号だけ記憶させています。
 
                                * 単なる作者の趣味なので、必ずしもこのような実装にする必要はないと思われます。
 
                                */
 
if (item == null
 
|| this.isItemStackable(new ItemStack(current.getItem(), 1, current.getItemDamage()), item)) {
 
ret = new ItemStack(current.getItem(), 1, current.getItemDamage());
 
slot = i;
 
break;
 
}
 
}
 
 
 
                        /* 挿入可能なアイテムが無事に取得できたならば、挿入処理をします。 */
 
if (ret != null) {
 
                                /* スロットが空であれば、挿入予定のItemStackがそのままSlotにはいります。 */
 
if (sided.getStackInSlot(slot) == null) {
 
sided.setInventorySlotContents(slot, ret);
 
} else {
 
                                /* 空で無かった場合は、挿入予定の個数分だけ、移送先Slotのスタック数を増加させます。 */
 
sided.getStackInSlot(slot).stackSize++;
 
}
 
 
 
                                /* 最後に、挿入完了したあと、FluidHopper側のアイテムは減少させます。 */
 
this.decrStackSize(1, 1);
 
 
 
                                /* インベントリ内容に変更があったため、変更を更新させる処理を呼びます。 */
 
inv.markDirty();
 
this.markDirty();
 
}
 
} else {
 
                        /* 以下はSidedInventoryで無かった場合の処理。基本は上記と同様の流れです。 */
 
ItemStack ret = null;
 
int slot = 0;
 
 
 
                        /* Sidedと異なり、スロットごとにアクセス不可の判定がないので、全スロットを走査します。 */
 
for (int i = 0; i < inv.getSizeInventory(); i++) {
 
ItemStack item = inv.getStackInSlot(i);
 
if (!inv.isItemValidForSlot(i, current))
 
continue;
 
 
 
if (item == null
 
|| this.isItemStackable(new ItemStack(current.getItem(), 1, current.getItemDamage()), item)) {
 
ret = new ItemStack(current.getItem(), 1, current.getItemDamage());
 
slot = i;
 
break;
 
}
 
}
 
 
 
if (ret != null) {
 
if (inv.getStackInSlot(slot) == null) {
 
inv.setInventorySlotContents(slot, ret);
 
} else {
 
inv.getStackInSlot(slot).stackSize++;
 
}
 
 
 
this.decrStackSize(1, 1);
 
inv.markDirty();
 
this.markDirty();
 
}
 
}
 
}
 
}
 
 
 
/* 上記extractItemFromHopper()内で使用しているメソッド。スタック可能なアイテムかどうかの判定です。 */
 
private static boolean isItemStackable(ItemStack target, ItemStack current) {
 
if (target == null || current == null)
 
return false;
 
 
 
if (target.getItem() == current.getItem() && target.getItemDamage() == current.getItemDamage()) {
 
return (current.stackSize + target.stackSize) <= current.getMaxStackSize();
 
}
 
 
 
return false;
 
}
 
</source>
 

Minecraft Modding Wikiへの投稿はすべて、他の投稿者によって編集、変更、除去される場合があります。 自分が書いたものが他の人に容赦なく編集されるのを望まない場合は、ここに投稿しないでください。
また、投稿するのは、自分で書いたものか、パブリック ドメインまたはそれに類するフリーな資料からの複製であることを約束してください(詳細はMinecraft Modding Wiki:著作権を参照)。 著作権保護されている作品は、許諾なしに投稿しないでください!

このページを編集するには、下記の確認用の質問に回答してください (詳細):

取り消し 編集の仕方 (新しいウィンドウで開きます)