提供: Minecraft Modding Wiki
この記事は"Minecraft Forge Universal 9.11.1.xxx~"を前提MODとしています。 |
TileEntityの追加[編集]
かまどとほぼ同じ機能を果たすブロックを作る
ソースコード[編集]
- SampleTileEntityCore.java
package mods.samplemod; import net.minecraft.block.Block; import net.minecraft.block.material.Material; 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.network.NetworkMod; import cpw.mods.fml.common.network.NetworkRegistry; import cpw.mods.fml.common.registry.GameRegistry; import cpw.mods.fml.common.registry.LanguageRegistry; @Mod(modid="TileEntitySampleMod", name="TileEntitySampleMod", version="1.0") @NetworkMod(clientSideRequired = true, serverSideRequired = false) public class SampleTileEntityCore { public static Block blockSample; public static int blockSampleID = 4087; public static int guiSampleID = 1000; //SampleTileEntityCoreクラスのインスタンス @Instance("TileEntitySampleMod") public static SampleTileEntityCore instance; @EventHandler public void init(FMLInitializationEvent event) { //表示名の登録 LanguageRegistry.addName(blockSample, "Sample Block"); LanguageRegistry.instance().addNameForObject(blockSample, "ja_JP", "サンプル ブロック"); //TileEntityの登録 GameRegistry.registerTileEntity(TileEntitySample.class, "TileEntitySample"); //GUIの登録 NetworkRegistry.instance().registerGuiHandler(this, new GuiHandler()); } @EventHandler public void preInit(FMLPreInitializationEvent event) { //ブロックの登録 blockSample = new BlockContainerSample(blockSampleID, Material.rock); GameRegistry.registerBlock(blockSample, "blockSample"); } }
- BlockContainerSample.java
package mods.samplemod; import net.minecraft.block.BlockContainer; import net.minecraft.block.material.Material; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; public class BlockContainerSample extends BlockContainer { protected BlockContainerSample(int par1, Material par2Material) { super(par1, par2Material); } //右クリックされた時の処理 @Override public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9){ if (par1World.isRemote) { return true; } else { // GUIを開く par5EntityPlayer.openGui(SampleTileEntityCore.instance, SampleTileEntityCore.instance.guiSampleID, par1World, par2, par3, par4); return true; } } //ブロックが壊れた時の処理 //周辺に中に入っていたアイテムをまき散らす @Override public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6) { TileEntitySample tileentity = (TileEntitySample) par1World.getBlockTileEntity(par2, par3, par4); if (tileentity != null) { for (int j1 = 0; j1 < tileentity.getSizeInventory(); ++j1) { ItemStack itemstack = tileentity.getStackInSlot(j1); if (itemstack != null) { float f = par1World.rand.nextFloat() * 0.8F + 0.1F; float f1 = par1World.rand.nextFloat() * 0.8F + 0.1F; float f2 = par1World.rand.nextFloat() * 0.8F + 0.1F; while (itemstack.stackSize > 0) { int k1 = par1World.rand.nextInt(21) + 10; if (k1 > itemstack.stackSize) { k1 = itemstack.stackSize; } itemstack.stackSize -= k1; EntityItem entityitem = new EntityItem(par1World, (double)((float)par2 + f), (double)((float)par3 + f1), (double)((float)par4 + f2), new ItemStack(itemstack.itemID, k1, itemstack.getItemDamage())); if (itemstack.hasTagCompound()) { entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy()); } float f3 = 0.05F; entityitem.motionX = (double)((float)par1World.rand.nextGaussian() * f3); entityitem.motionY = (double)((float)par1World.rand.nextGaussian() * f3 + 0.2F); entityitem.motionZ = (double)((float)par1World.rand.nextGaussian() * f3); par1World.spawnEntityInWorld(entityitem); } } } par1World.func_96440_m(par2, par3, par4, par5); } super.breakBlock(par1World, par2, par3, par4, par5, par6); } @Override public TileEntity createNewTileEntity(World world) { // TileEntityの生成 return new TileEntitySample(); } }
- TileEntitySample.java
package mods.samplemod; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemHoe; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemSword; import net.minecraft.item.ItemTool; import net.minecraft.item.crafting.FurnaceRecipes; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.network.INetworkManager; import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.Packet132TileEntityData; import net.minecraft.tileentity.TileEntity; import cpw.mods.fml.common.registry.GameRegistry; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; public class TileEntitySample extends TileEntity implements ISidedInventory { //燃焼時間 public int burnTime; public int currentItemBurnTime; //調理時間 public int cookTime; private static final int[] slots_top = new int[] {0}; private static final int[] slots_bottom = new int[] {2, 1}; private static final int[] slots_sides = new int[] {1}; public ItemStack[] sampleItemStacks = new ItemStack[3]; @Override public void readFromNBT(NBTTagCompound par1NBTTagCompound) { super.readFromNBT(par1NBTTagCompound); //アイテムの読み込み NBTTagList nbttaglist = par1NBTTagCompound.getTagList("Items"); this.sampleItemStacks = new ItemStack[this.getSizeInventory()]; for (int i = 0; i < nbttaglist.tagCount(); ++i) { NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i); byte b0 = nbttagcompound1.getByte("Slot"); if (b0 >= 0 && b0 < this.sampleItemStacks.length) { this.sampleItemStacks[b0] = ItemStack.loadItemStackFromNBT(nbttagcompound1); } } //燃焼時間や調理時間などの読み込み this.burnTime = par1NBTTagCompound.getShort("BurnTime"); this.cookTime = par1NBTTagCompound.getShort("CookTime"); this.currentItemBurnTime = getItemBurnTime(this.sampleItemStacks[1]); } @Override public void writeToNBT(NBTTagCompound par1NBTTagCompound) { super.writeToNBT(par1NBTTagCompound); //燃焼時間や調理時間などの書き込み par1NBTTagCompound.setShort("BurnTime", (short)this.burnTime); par1NBTTagCompound.setShort("CookTime", (short)this.cookTime); //アイテムの書き込み NBTTagList nbttaglist = new NBTTagList(); for (int i = 0; i < this.sampleItemStacks.length; ++i) { if (this.sampleItemStacks[i] != null) { NBTTagCompound nbttagcompound1 = new NBTTagCompound(); nbttagcompound1.setByte("Slot", (byte)i); this.sampleItemStacks[i].writeToNBT(nbttagcompound1); nbttaglist.appendTag(nbttagcompound1); } } par1NBTTagCompound.setTag("Items", nbttaglist); } @Override public Packet getDescriptionPacket() { NBTTagCompound nbtTagCompound = new NBTTagCompound(); this.writeToNBT(nbtTagCompound); return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, 1, nbtTagCompound); } @Override public void onDataPacket(INetworkManager net, Packet132TileEntityData pkt) { this.readFromNBT(pkt.data); } //かまどの処理 @SideOnly(Side.CLIENT) public int getCookProgressScaled(int par1) { return this.cookTime * par1 / 200; } //かまどの処理 @SideOnly(Side.CLIENT) public int getBurnTimeRemainingScaled(int par1) { if (this.currentItemBurnTime == 0) { this.currentItemBurnTime = 200; } return this.burnTime * par1 / this.currentItemBurnTime; } //かまどの処理 public boolean isBurning() { return this.burnTime > 0; } //更新時に呼び出される //かまどの処理 public void updateEntity() { boolean flag = this.burnTime > 0; boolean flag1 = false; if (this.burnTime > 0) { --this.burnTime; } if (!this.worldObj.isRemote) { if (this.burnTime == 0 && this.canSmelt()) { this.currentItemBurnTime = this.burnTime = getItemBurnTime(this.sampleItemStacks[1]); if (this.burnTime > 0) { flag1 = true; if (this.sampleItemStacks[1] != null) { --this.sampleItemStacks[1].stackSize; if (this.sampleItemStacks[1].stackSize == 0) { this.sampleItemStacks[1] = this.sampleItemStacks[1].getItem().getContainerItemStack(this.sampleItemStacks[1]); } } } } if (this.isBurning() && this.canSmelt()) { ++this.cookTime; if (this.cookTime == 200) { this.cookTime = 0; this.smeltItem(); flag1 = true; } } else { this.cookTime = 0; } if (flag != this.burnTime > 0) { flag1 = true; } } if (flag1) { this.onInventoryChanged(); } } //かまどの処理 private boolean canSmelt() { if (this.sampleItemStacks[0] == null) { return false; } else { ItemStack itemstack = FurnaceRecipes.smelting().getSmeltingResult(this.sampleItemStacks[0]); if (itemstack == null) return false; if (this.sampleItemStacks[2] == null) return true; if (!this.sampleItemStacks[2].isItemEqual(itemstack)) return false; int result = this.sampleItemStacks[2].stackSize + itemstack.stackSize; return (result <= this.getInventoryStackLimit() && result <= itemstack.getMaxStackSize()); } } //かまどの処理 public void smeltItem() { if (this.canSmelt()) { ItemStack itemstack = FurnaceRecipes.smelting().getSmeltingResult(this.sampleItemStacks[0]); if (this.sampleItemStacks[2] == null) { this.sampleItemStacks[2] = itemstack.copy(); } else if (this.sampleItemStacks[2].isItemEqual(itemstack)) { this.sampleItemStacks[2].stackSize += itemstack.stackSize; } --this.sampleItemStacks[0].stackSize; if (this.sampleItemStacks[0].stackSize <= 0) { this.sampleItemStacks[0] = null; } } } //かまどの処理 public static int getItemBurnTime(ItemStack par0ItemStack) { if (par0ItemStack == null) { return 0; } else { int i = par0ItemStack.getItem().itemID; Item item = par0ItemStack.getItem(); if (par0ItemStack.getItem() instanceof ItemBlock && Block.blocksList[i] != null) { Block block = Block.blocksList[i]; if (block == Block.woodSingleSlab) { return 150; } if (block.blockMaterial == Material.wood) { return 300; } if (block == Block.coalBlock) { return 16000; } } if (item instanceof ItemTool && ((ItemTool) item).getToolMaterialName().equals("WOOD")) return 200; if (item instanceof ItemSword && ((ItemSword) item).getToolMaterialName().equals("WOOD")) return 200; if (item instanceof ItemHoe && ((ItemHoe) item).getMaterialName().equals("WOOD")) return 200; if (i == Item.stick.itemID) return 100; if (i == Item.coal.itemID) return 1600; if (i == Item.bucketLava.itemID) return 20000; if (i == Block.sapling.blockID) return 100; if (i == Item.blazeRod.itemID) return 2400; return GameRegistry.getFuelValue(par0ItemStack); } } //かまどの処理 public static boolean isItemFuel(ItemStack par0ItemStack) { return getItemBurnTime(par0ItemStack) > 0; } // スロット数 @Override public int getSizeInventory() { return this.sampleItemStacks.length; } // インベントリ内の任意のスロットにあるアイテムを取得 @Override public ItemStack getStackInSlot(int par1) { return this.sampleItemStacks[par1]; } @Override public ItemStack decrStackSize(int par1, int par2) { if (this.sampleItemStacks[par1] != null) { ItemStack itemstack; if (this.sampleItemStacks[par1].stackSize <= par2) { itemstack = this.sampleItemStacks[par1]; this.sampleItemStacks[par1] = null; return itemstack; } else { itemstack = this.sampleItemStacks[par1].splitStack(par2); if (this.sampleItemStacks[par1].stackSize == 0) { this.sampleItemStacks[par1] = null; } return itemstack; } } else { return null; } } @Override public ItemStack getStackInSlotOnClosing(int par1) { if (this.sampleItemStacks[par1] != null) { ItemStack itemstack = this.sampleItemStacks[par1]; this.sampleItemStacks[par1] = null; return itemstack; } else { return null; } } // インベントリ内のスロットにアイテムを入れる @Override public void setInventorySlotContents(int par1, ItemStack par2ItemStack) { this.sampleItemStacks[par1] = par2ItemStack; if (par2ItemStack != null && par2ItemStack.stackSize > this.getInventoryStackLimit()) { par2ItemStack.stackSize = this.getInventoryStackLimit(); } } // インベントリの名前 @Override public String getInvName() { return "Sample"; } // 多言語対応かどうか @Override public boolean isInvNameLocalized() { return false; } // インベントリ内のスタック限界値 @Override public int getInventoryStackLimit() { return 64; } @Override public void onInventoryChanged() { this.onInventoryChanged(); } // par1EntityPlayerがTileEntityを使えるかどうか @Override public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer) { return this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord) != this ? false : par1EntityPlayer.getDistanceSq((double) this.xCoord + 0.5D, (double) this.yCoord + 0.5D, (double) this.zCoord + 0.5D) <= 64.0D; } @Override public void openChest() {} @Override public void closeChest() {} @Override public boolean isItemValidForSlot(int par1, ItemStack par2ItemStack) { return par1 == 2 ? false : (par1 == 1 ? this.isItemFuel(par2ItemStack) : true); } //ホッパーにアイテムの受け渡しをする際の優先度 @Override public int[] getAccessibleSlotsFromSide(int par1) { return par1 == 0 ? slots_bottom : (par1 == 1 ? slots_top : slots_sides); } //ホッパーからアイテムを入れられるかどうか @Override public boolean canInsertItem(int par1, ItemStack par2ItemStack, int par3) { return this.isItemValidForSlot(par1, par2ItemStack); } //隣接するホッパーにアイテムを送れるかどうか @Override public boolean canExtractItem(int par1, ItemStack par2ItemStack, int par3) { return par3 != 0 || par1 != 1 || par2ItemStack.itemID == Item.bucketEmpty.itemID; } }
- ContainerSample.java
package mods.samplemod; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.Container; import net.minecraft.inventory.ICrafting; import net.minecraft.inventory.Slot; import net.minecraft.inventory.SlotFurnace; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.FurnaceRecipes; import net.minecraft.tileentity.TileEntityFurnace; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; public class ContainerSample extends Container { private TileEntitySample tileentity; private int lastCookTime; private int lastBurnTime; private int lastItemBurnTime; public ContainerSample(EntityPlayer player, TileEntitySample par2TileEntity) { this.tileentity = par2TileEntity; // InventorySampleで追加するインベントリ this.addSlotToContainer(new Slot(this.tileentity, 0, 56, 17)); this.addSlotToContainer(new Slot(this.tileentity, 1, 56, 53)); this.addSlotToContainer(new SlotFurnace(player, this.tileentity, 2, 116, 35)); int i; // 1 ~ 3段目のインベントリ for (i = 0; i < 3; ++i) { for (int j = 0; j < 9; ++j) { this.addSlotToContainer(new Slot(player.inventory, j + i * 9 + 9, 8 + j * 18, 84 + i * 18)); } } // 4段目のインベントリ for (i = 0; i < 9; ++i) { this.addSlotToContainer(new Slot(player.inventory, i, 8 + i * 18, 142)); } } public void addCraftingToCrafters(ICrafting par1ICrafting) { super.addCraftingToCrafters(par1ICrafting); par1ICrafting.sendProgressBarUpdate(this, 0, this.tileentity.cookTime); par1ICrafting.sendProgressBarUpdate(this, 1, this.tileentity.burnTime); par1ICrafting.sendProgressBarUpdate(this, 2, this.tileentity.currentItemBurnTime); } // 更新を送る public void detectAndSendChanges() { super.detectAndSendChanges(); for (int i = 0; i < this.crafters.size(); ++i) { ICrafting icrafting = (ICrafting)this.crafters.get(i); if (this.lastCookTime != this.tileentity.cookTime) { icrafting.sendProgressBarUpdate(this, 0, this.tileentity.cookTime); } if (this.lastBurnTime != this.tileentity.burnTime) { icrafting.sendProgressBarUpdate(this, 1, this.tileentity.burnTime); } if (this.lastItemBurnTime != this.tileentity.currentItemBurnTime) { icrafting.sendProgressBarUpdate(this, 2, this.tileentity.currentItemBurnTime); } } this.lastCookTime = this.tileentity.cookTime; this.lastBurnTime = this.tileentity.burnTime; this.lastItemBurnTime = this.tileentity.currentItemBurnTime; } // 更新する @SideOnly(Side.CLIENT) public void updateProgressBar(int par1, int par2) { if (par1 == 0) { this.tileentity.cookTime = par2; } if (par1 == 1) { this.tileentity.burnTime = par2; } if (par1 == 2) { this.tileentity.currentItemBurnTime = par2; } } // InventorySample内のisUseableByPlayerメソッドを参照 @Override public boolean canInteractWith(EntityPlayer par1EntityPlayer) { return this.tileentity.isUseableByPlayer(par1EntityPlayer); } // Shiftクリック public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int par2) { ItemStack itemstack = null; Slot slot = (Slot)this.inventorySlots.get(par2); if (slot != null && slot.getHasStack()) { ItemStack itemstack1 = slot.getStack(); itemstack = itemstack1.copy(); //スロット番号が2の時 if (par2 == 2) { //アイテムの移動(スロット3~39へ) if (!this.mergeItemStack(itemstack1, 3, 39, true)) { return null; } slot.onSlotChange(itemstack1, itemstack); } //スロット番号が0、1でない時 else if (par2 != 1 && par2 != 0) { if (FurnaceRecipes.smelting().getSmeltingResult(itemstack1) != null) { //アイテムの移動(スロット0~1へ) if (!this.mergeItemStack(itemstack1, 0, 1, false)) { return null; } } else if (TileEntityFurnace.isItemFuel(itemstack1)) { //アイテムの移動(スロット1~2へ) if (!this.mergeItemStack(itemstack1, 1, 2, false)) { return null; } } else if (par2 >= 3 && par2 < 30) { //アイテムの移動(スロット30~39へ) if (!this.mergeItemStack(itemstack1, 30, 39, false)) { return null; } } else if (par2 >= 30 && par2 < 39 && !this.mergeItemStack(itemstack1, 3, 30, false)) { return null; } } //アイテムの移動(スロット3~39へ) else if (!this.mergeItemStack(itemstack1, 3, 39, false)) { return null; } if (itemstack1.stackSize == 0) { slot.putStack((ItemStack)null); } else { slot.onSlotChanged(); } if (itemstack1.stackSize == itemstack.stackSize) { return null; } slot.onPickupFromSlot(par1EntityPlayer, itemstack1); } return itemstack; } }
- GuiSample.java
package mods.samplemod; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.ResourceLocation; import net.minecraft.util.StatCollector; import org.lwjgl.opengl.GL11; public class GuiSample extends GuiContainer { private TileEntitySample tileentity; //ResourceLocationの第一引数を付け足してドメインを指定することもできる //例:new ResourceLocation("sample", "textures/gui/container/furnace.png") private static final ResourceLocation GUITEXTURE = new ResourceLocation("textures/gui/container/furnace.png"); public GuiSample(EntityPlayer player, TileEntitySample par2TileEntity) { super(new ContainerSample(player, par2TileEntity)); this.tileentity = par2TileEntity; } @Override protected void drawGuiContainerForegroundLayer(int par1, int par2) { //インベントリ名の描画 String s = this.tileentity.isInvNameLocalized() ? this.tileentity.getInvName() : StatCollector.translateToLocal(this.tileentity.getInvName()); this.fontRenderer.drawString(s, this.xSize / 2 - this.fontRenderer.getStringWidth(s) / 2, 6, 4210752); this.fontRenderer.drawString(StatCollector.translateToLocal("container.inventory"), 8, this.ySize - 96 + 2, 4210752); } @Override protected void drawGuiContainerBackgroundLayer(float par1, int par2, int par3) { GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); //テクスチャの指定 this.mc.getTextureManager().bindTexture(GUITEXTURE); //かまど描画処理 int k = (this.width - this.xSize) / 2; int l = (this.height - this.ySize) / 2; this.drawTexturedModalRect(k, l, 0, 0, this.xSize, this.ySize); int i1; if (this.tileentity.isBurning()) { i1 = this.tileentity.getBurnTimeRemainingScaled(12); this.drawTexturedModalRect(k + 56, l + 36 + 12 - i1, 176, 12 - i1, 14, i1 + 2); } i1 = this.tileentity.getCookProgressScaled(24); this.drawTexturedModalRect(k + 79, l + 34, 176, 14, i1 + 1, 16); } }
- GuiHandler.java
package mods.samplemod; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; import cpw.mods.fml.common.network.IGuiHandler; public class GuiHandler implements IGuiHandler { @Override public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { if (!world.blockExists(x, y, z)) return null; TileEntity tileentity = world.getBlockTileEntity(x, y, z); if (tileentity instanceof TileEntitySample) { return new ContainerSample(player, (TileEntitySample) tileentity); } return null; } @Override public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { if (!world.blockExists(x, y, z)) return null; TileEntity tileentity = world.getBlockTileEntity(x, y, z); if (tileentity instanceof TileEntitySample) { return new GuiSample(player, (TileEntitySample) tileentity); } return null; } }
解説[編集]
SampleTileEntityCore.java[編集]
ブロックの追加方法の解説は1.6のブロック追加
GameRegistry.registerTileEntity(TileEntitySample.class, "TileEntitySample");
TileEntityの登録を行います。 第一引数がTileEntityを継承したクラス、第二引数は他と被らない文字列。
NetworkRegistry.instance().registerGuiHandler(this, new GuiHandler());
Guiを扱うGuiHandlerの登録を登録します。
TileEntitySample.java[編集]
@Override public void readFromNBT(NBTTagCompound par1NBTTagCompound) { super.readFromNBT(par1NBTTagCompound); ~ 中略 ~ } @Override public void writeToNBT(NBTTagCompound par1NBTTagCompound) { super.writeToNBT(par1NBTTagCompound); ~ 中略 ~ }
上記2つのメソッドを使ってTileEntityの情報をNBTに保存します。
@Override public Packet getDescriptionPacket() { NBTTagCompound nbtTagCompound = new NBTTagCompound(); this.writeToNBT(nbtTagCompound); return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, 1, nbtTagCompound); } @Override public void onDataPacket(INetworkManager net, Packet132TileEntityData pkt) { this.readFromNBT(pkt.data); }
NBTに保存した情報をパケットで飛ばすことができる。