package minefantasy.block.tileentity; import java.util.Random; import com.google.common.io.ByteArrayDataInput; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.registry.GameRegistry; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import minefantasy.api.aesthetic.IChimney; import minefantasy.api.cooking.OvenRecipes; import minefantasy.system.data_minefantasy; import minefantasy.system.network.PacketManagerMF; import minefantasy.system.network.PacketUserMF; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemFood; 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.packet.Packet; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.StatCollector; import net.minecraft.world.World; public class TileEntityOven extends TileEntity implements IInventory, PacketUserMF, ISidedInventory { private int ticksExisted; private ItemStack[] items; public int direction; public int itemMeta; public int fuel; private Random rand = new Random(); /** * The number of ticks that a fresh copy of the currently-burning item would keep the furnace burning for */ public int maxFuel; /** The number of ticks that the current item has been cooking for */ public int progress; //ANIMATE public int numUsers; public int doorAngle; public boolean isBurningClient; public TileEntityOven() { items = new ItemStack[3]; } public TileEntityOven(int meta) { this(); itemMeta = meta; } @Override public int getSizeInventory() { return items.length; } @Override public ItemStack getStackInSlot(int i) { return items[i]; } public void onInventoryChanged() { super.onInventoryChanged(); if(worldObj != null && !worldObj.isRemote) { syncItems(); } } @Override public ItemStack decrStackSize(int slot, int ammount) { onInventoryChanged(); if (this.items[slot] != null) { ItemStack var3; if (this.items[slot].stackSize <= ammount) { var3 = this.items[slot]; this.items[slot] = null; return var3; } else { var3 = this.items[slot].splitStack(ammount); if (this.items[slot].stackSize == 0) { this.items[slot] = null; } return var3; } } else { return null; } } @Override public ItemStack getStackInSlotOnClosing(int slot) { if (this.items[slot] != null) { ItemStack var2 = this.items[slot]; this.items[slot] = null; return var2; } else { return null; } } @Override public void setInventorySlotContents(int i, ItemStack itemstack) { items[i] = itemstack; } @Override public String getInvName() { int t = getType(); String tier = ""; if(t == 0) { tier = StatCollector.translateToLocal("tier.bronze"); } if(t == 1) { tier = StatCollector.translateToLocal("tier.iron"); } if(t == 2) { tier = StatCollector.translateToLocal("tier.steel"); } if(t == 3) { tier = StatCollector.translateToLocal("tier.iron.deep"); } return tier + " " + StatCollector.translateToLocal("container.oven"); } @Override public boolean isInvNameLocalized() { return false; } @Override public int getInventoryStackLimit() { return 64; } @Override public boolean isUseableByPlayer(EntityPlayer entityplayer) { return entityplayer.getDistance(xCoord+0.5D, yCoord+0.5D, zCoord+0.5D) < 8F; } public void openChest() { if(numUsers == 0) { this.worldObj.playSoundEffect(xCoord+0.5D, (double)this.yCoord + 0.5D, zCoord+0.5D, data_minefantasy.sound("furnaceOpen"), 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 1.4F); } ++numUsers; } public void closeChest() { --numUsers; if(numUsers == 0 && doorAngle >= 10) { this.worldObj.playSoundEffect(xCoord+0.5D, (double)this.yCoord + 0.5D, zCoord+0.5D, data_minefantasy.sound("furnaceClose"), 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 1.4F); } } @SideOnly(Side.CLIENT) /** * Returns an integer between 0 and the passed value representing how close the current item is to being completely * cooked */ public int getCookProgressScaled(int width) { return this.progress * width / 400; } @SideOnly(Side.CLIENT) /** * Returns an integer between 0 and the passed value representing how much burn time is left on the current fuel * item, where 0 means that the item is exhausted and the passed value means that the item is fresh */ public int getBurnTimeRemainingScaled(int width) { if (this.maxFuel == 0) { this.maxFuel = 200; } return this.fuel * width / this.maxFuel; } /** * Returns true if the furnace is currently burning */ public boolean isBurning() { return this.fuel > 0; } /** * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count * ticks and creates a new spawn inside its implementation. */ public void updateEntity() { ++ticksExisted; boolean flag = this.fuel > 0; boolean flag1 = false; if (this.fuel > 0) { --this.fuel; } if (!this.worldObj.isRemote) { if (this.fuel == 0 && this.canSmelt()) { this.maxFuel = this.fuel = getItemBurnTime(this.items[1]); if (this.fuel > 0) { flag1 = true; if (this.items[1] != null) { --this.items[1].stackSize; if (this.items[1].stackSize == 0) { this.items[1] = this.items[1].getItem().getContainerItemStack(items[1]); } } } } if (this.isBurning() && this.canSmelt()) { this.progress += getCookSpeed(); if (this.progress >= 400) { this.progress = 0; this.smeltItem(); flag1 = true; } } else { this.progress = 0; } int off = getOffMetadata(); int on = getOnMetadata(); if(isBurning() && worldObj.getBlockMetadata(xCoord, yCoord, zCoord) != on) { worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, on, 3); worldObj.updateAllLightTypes(xCoord, yCoord, zCoord); } if(!isBurning() && worldObj.getBlockMetadata(xCoord, yCoord, zCoord) != off) { worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, off, 3); worldObj.updateAllLightTypes(xCoord, yCoord, zCoord); } if(numUsers > 0 && doorAngle < 15) { doorAngle ++; } if(numUsers <= 0 && doorAngle > 0) { doorAngle --; } if(doorAngle < 0)doorAngle = 0; if(doorAngle > 15)doorAngle = 15; if(ticksExisted % 20 == 0) { syncItems(); } sendPacketToClients(); } if (flag1) { this.onInventoryChanged(); } if(worldObj.isRemote) { if(isBurning()) { puffSmoke(new Random(), worldObj, xCoord, yCoord, zCoord); if(rand.nextInt(10)==0) worldObj.spawnParticle("flame", xCoord+(rand.nextDouble()*0.8D)+0.1D, yCoord + 0.4D, zCoord+(rand.nextDouble()*0.8D)+0.1D, 0, 0.01, 0); } return; } } private int getCookSpeed() { int tier = getType(); return 1 + tier; } /** * Returns true if the furnace can smelt an item, i.e. has a source item, destination stack isn't full, etc. */ private boolean canSmelt() { if (this.items[0] == null) { return false; } else { ItemStack itemstack = getResult(); if (itemstack == null) return false; if (this.items[2] == null) return true; if (!this.items[2].isItemEqual(itemstack)) return false; int result = items[2].stackSize + itemstack.stackSize; return (result <= getInventoryStackLimit() && result <= itemstack.getMaxStackSize()); } } public ItemStack getResult() { return getResult(this.items[0]); } public ItemStack getResult(ItemStack item) { ItemStack result = OvenRecipes.getSmeltingResult(item); if(result != null) { return result; } result = FurnaceRecipes.smelting().getSmeltingResult(item); if(result != null && result.getItem() instanceof ItemFood) { return result; } return null; } /** * Turn one item from the furnace source stack into the appropriate smelted item in the furnace result stack */ public void smeltItem() { if (this.canSmelt()) { ItemStack itemstack = getResult(); if (this.items[2] == null) { this.items[2] = itemstack.copy(); } else if (this.items[2].isItemEqual(itemstack)) { items[2].stackSize += itemstack.stackSize; } --this.items[0].stackSize; if (this.items[0].stackSize <= 0) { this.items[0] = null; } } } public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); NBTTagList nbttaglist = nbt.getTagList("Items"); items = new ItemStack[getSizeInventory()]; for (int i = 0; i < nbttaglist.tagCount(); i++) { NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i); byte byte0 = nbttagcompound1.getByte("Slot"); if (byte0 >= 0 && byte0 < items.length) { items[byte0] = ItemStack.loadItemStackFromNBT(nbttagcompound1); } } fuel = nbt.getInteger("Fuel"); maxFuel = nbt.getInteger("FuelMax"); progress = nbt.getInteger("Progress"); direction = nbt.getInteger("Dir"); } public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); nbt.setInteger("Dir", direction); NBTTagList nbttaglist = new NBTTagList(); for (int i = 0; i < items.length; i++) { if (items[i] != null) { NBTTagCompound nbttagcompound1 = new NBTTagCompound(); nbttagcompound1.setByte("Slot", (byte)i); items[i].writeToNBT(nbttagcompound1); nbttaglist.appendTag(nbttagcompound1); } } nbt.setInteger("Fuel", fuel); nbt.setInteger("FuelMax", maxFuel); nbt.setInteger("Progress", progress); nbt.setTag("Items", nbttaglist); } public static int getItemBurnTime(ItemStack input) { if (input == null) { return 0; } else { int i = input.getItem().itemID; Item item = input.getItem(); if (input.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(input); } } /** * Returns true if automation is allowed to insert the given stack (ignoring stack size) into the given slot. */ public boolean isItemValidForSlot(int slot, ItemStack item) { if(item == null)return false; if(slot == 0) { return getResult(item) != null; } if(slot == 1) { return isItemFuel(item); } return false; } public boolean isItemFuel(ItemStack item) { return getItemBurnTime(item) > 0; } /** * Returns an array containing the indices of the slots that can be accessed by automation on the given side of this * block. */ @Override public int[] getAccessibleSlotsFromSide(int side) { return side == 0 ? slots_bottom : (side == 1 ? slots_top : slots_sides); } /** * Returns true if automation can insert the given item in the given slot from the given side. Args: Slot, item, * side */ @Override public boolean canInsertItem(int slot, ItemStack item, int side) { return this.isItemValidForSlot(slot, item); } /** * Returns true if automation can extract the given item in the given slot from the given side. Args: Slot, item, * side */ @Override public boolean canExtractItem(int slot, ItemStack item, int side) { if(slot == 1) { return item != null && item.itemID == Item.bucketEmpty.itemID; } return slot == 2; } 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}; @Override public int getBlockMetadata() { if(worldObj == null) return itemMeta; if (this.blockMetadata == -1) { this.blockMetadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord); } return this.blockMetadata; } /** * Heater:0||Bronze:1||Iron:2||Steel:3||; */ public int getType() { int meta = getBlockMetadata(); return (int)Math.floor(meta/2); } private int getOnMetadata() { return getType()*2 + 1; } private int getOffMetadata() { return getType()*2; } private void sendPacketToClients() { if (!worldObj.isRemote) { try { Packet packet = PacketManagerMF.getPacketIntegerArray(this, new int[] { (int)fuel, progress, direction, isBurning() ? 1 : 0, doorAngle }); FMLCommonHandler.instance().getMinecraftServerInstance() .getConfigurationManager() .sendPacketToAllPlayers(packet); } catch (Exception e) { e.printStackTrace(); } } } @Override public void recievePacket(ByteArrayDataInput data) { fuel = data.readInt(); progress = data.readInt(); direction = data.readInt(); int burn = data.readInt(); isBurningClient = burn == 1; doorAngle = data.readInt(); } public String getTexture() { switch(getType()) { case 0://BRONZE return "oven_bronze"; case 1://IRON return "oven_iron"; case 2://STEEL return "oven_steel"; case 3://DEEP IRON return "oven_deep"; } return "oven"; } public void syncItems() { if(!worldObj.isRemote) { for(int a = 0; a < items.length; a ++) { Packet packet = PacketManagerMF.getPacketItemStackArray(this, a, items[a]); try { FMLCommonHandler.instance().getMinecraftServerInstance().getConfigurationManager().sendPacketToAllPlayers(packet); } catch(NullPointerException e) { System.out.println("MineFantasy: Client connection lost"); return; } } } } public void puffSmoke(Random rand, World world, int x, int y, int z) { if(rand.nextInt(10) != 0) { return; } Block block = Block.blocksList[world.getBlockId(x, y+1, z)]; IChimney chimney = null; if(block instanceof IChimney) chimney = (IChimney)block; if(chimney != null && chimney.puffSmoke(world, x, y+1, z, (float)1/12, 1, 1)) { return; } world.spawnParticle("largesmoke", x+0.5F, y+1, z+0.5F, (rand.nextFloat()-0.5F)/6, 0.065F, (rand.nextFloat()-0.5F)/6); } }