package com.vanhal.progressiveautomation.entities.chopper; import java.util.List; import com.vanhal.progressiveautomation.PAConfig; import com.vanhal.progressiveautomation.ProgressiveAutomation; import com.vanhal.progressiveautomation.compat.ModHelper; import com.vanhal.progressiveautomation.entities.UpgradeableTileEntity; import com.vanhal.progressiveautomation.ref.ToolHelper; import com.vanhal.progressiveautomation.upgrades.UpgradeType; import com.vanhal.progressiveautomation.util.CoordList; import com.vanhal.progressiveautomation.util.OreHelper; import com.vanhal.progressiveautomation.util.Point2I; import com.vanhal.progressiveautomation.util.Point3I; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.init.Enchantments; import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraftforge.common.IPlantable; import net.minecraftforge.common.IShearable; public class TileChopper extends UpgradeableTileEntity { /** * This is the extra range above planting range used during tree cutting */ protected final int CUTTING_EXTRA_RANGE = 6; private boolean forceRecalculate; protected int maxCuttingX; protected int minCuttingX; protected int maxCuttingZ; protected int minCuttingZ; protected int searchBlock = -1; protected boolean plantSapling; protected boolean chopping; protected CoordList blockList = new CoordList(); protected Point3I currentBlock = null; protected int choppingTime = 0; public int SLOT_SAPLINGS = 1; public int SLOT_SHEARS = 4; public TileChopper() { super(13); setUpgradeLevel(ToolHelper.LEVEL_WOOD); setAllowedUpgrades(UpgradeType.WOODEN, UpgradeType.WITHER); allowSheer(); forceRecalculate = true; //slots SLOT_AXE = 2; SLOT_UPGRADE = 3; } protected boolean removeShears = false; protected void allowSheer() { if ( (PAConfig.shearTrees) && (PAConfig.allowShearingUpgrade) ) { if (!isAllowedUpgrade(UpgradeType.SHEARING)) { addAllowedUpgrade(UpgradeType.SHEARING); } } else { removeShears = true; } } @Override public void writeNonSyncableNBT(NBTTagCompound nbt) { super.writeNonSyncableNBT(nbt); //save the current block if (currentBlock!=null) { nbt.setTag("CurrentBlock", currentBlock.getNBT()); } else if (nbt.hasKey("CurrentBlock")) { nbt.removeTag("CurrentBlock"); } //save the block list nbt.setTag("BlockList", blockList.saveToNBT()); } @Override public void writeCommonNBT(NBTTagCompound nbt) { super.writeCommonNBT(nbt); //save the current chopping time nbt.setInteger("choppingTime", choppingTime); } @Override public void writeSyncOnlyNBT(NBTTagCompound nbt) { super.writeSyncOnlyNBT(nbt); nbt.setBoolean("chopping", chopping); nbt.setBoolean("planting", plantSapling); } @Override public void readNonSyncableNBT(NBTTagCompound nbt) { super.readNonSyncableNBT(nbt); //Load the current Block if (nbt.hasKey("CurrentBlock")) { currentBlock = new Point3I(); currentBlock.setNBT((NBTTagCompound)nbt.getTag("CurrentBlock")); } else { currentBlock = null; } //get the current tag list NBTTagList contents = nbt.getTagList("BlockList", 10); blockList.loadFromNBT(contents); forceRecalculate = true; if (blockList.size() > 0) { chopping = true; } if (removeShears) { if (slots[SLOT_SHEARS]!=null) slots[SLOT_SHEARS] = null; if (hasUpgrade(UpgradeType.SHEARING)) removeUpgradeCompletely(UpgradeType.SHEARING); removeShears = false; } } @Override public void readCommonNBT(NBTTagCompound nbt) { super.readCommonNBT(nbt); //load the current chopping time choppingTime = nbt.getInteger("choppingTime"); } @Override public void readSyncOnlyNBT(NBTTagCompound nbt) { super.readSyncOnlyNBT(nbt); if (nbt.hasKey("chopping")) chopping = nbt.getBoolean("chopping"); if (nbt.hasKey("planting")) plantSapling = nbt.getBoolean("planting"); } @Override public void update() { super.update(); if (!worldObj.isRemote) { checkForChanges(); checkInventory(); // Pause if we're full and told to if (isFull()) return; if (isBurning()) { if (chopping && blockList.size() == 0) { chopping = false; addPartialUpdate("chopping", false); } //do tree stuff if (blockList.size()>0) { //cut tree cutTree(); } else if (plantSapling) { plantSaplings(searchBlock, true); plantSapling = false; addPartialUpdate("planting", false); } scanBlocks(); } } } protected boolean scanBlocks() { //this should scan the available range and return true if we can do something //scan for trees, we will always leave the base till last so that it doesn't plant more saplings.... for (int i = 0; i < this.getRange(); i++) { findTree(i); } if (blockList.size()>0) return true; //if we can harvest some trees lets do that before planting more //scan for blocks that we can plant on for (int i = 0; i < this.getRange(); i++) { if (plantSaplings(i, false)) { searchBlock = i; plantSapling = true; addPartialUpdate("planting", true); return true; } } return false; } protected void cutTree() { if (slots[SLOT_AXE]==null) return; if (currentBlock!=null) { if (choppingTime<=0) { //finished chopping choppingTime = 0; BlockPos currentPosition = currentBlock.toPosition(); if (validBlock(currentPosition)) { boolean targetTree = isTree(currentPosition); //I'm fairly sure this doesn't actually do anything, but gonna leave it here anyway int fortuneLevel = 0; if (targetTree) { fortuneLevel = EnchantmentHelper.getEnchantmentLevel(Enchantments.FORTUNE, slots[SLOT_AXE]); } //then break the block IBlockState actualBlockState = worldObj.getBlockState(currentPosition); Block actualBlock = actualBlockState.getBlock(); int metaData = actualBlock.getMetaFromState(actualBlockState); List<ItemStack> items = actualBlock.getDrops(worldObj, currentPosition, actualBlockState, fortuneLevel); if ( (!targetTree) && (slots[SLOT_SHEARS]!=null) && (hasUpgrade(UpgradeType.SHEARING)) ) { int i = 0; //shear leaves if (actualBlock instanceof IShearable) { IShearable shearBlock = (IShearable)actualBlock; if (shearBlock.isShearable(slots[SLOT_SHEARS], worldObj, currentPosition)) { items = shearBlock.onSheared(slots[SLOT_SHEARS], worldObj, currentPosition, EnchantmentHelper.getEnchantmentLevel(net.minecraft.init.Enchantments.FORTUNE, slots[SLOT_SHEARS])); } } else { Item item = Item.getItemFromBlock(actualBlock); if (item != null && item.getHasSubtypes()) i = metaData; items.add(new ItemStack(item, 1, i)); } if (ToolHelper.damageTool(slots[SLOT_SHEARS], worldObj, currentBlock.getX(), currentBlock.getY(), currentBlock.getZ())) { destroyTool(SLOT_SHEARS); } } else { items = actualBlock.getDrops(worldObj, currentBlock.toPosition(), actualBlockState, fortuneLevel); } //get the drops for (ItemStack item : items) { addToInventory(item); } //if we're chopping a tree, then damage the tool, otherwise don't if (targetTree) { if (ToolHelper.damageTool(slots[SLOT_AXE], worldObj, currentBlock.getX(), currentBlock.getY(), currentBlock.getZ())) { destroyTool(SLOT_AXE); } } //remove the block and entity if there is one worldObj.removeTileEntity( currentPosition ); worldObj.setBlockToAir(currentPosition); } currentBlock = null; } else { // chop some more? choppingTime--; } } else { //start cutting something why don't we? if (blockList.size()>0) { currentBlock = blockList.pop(); BlockPos currentPosition = currentBlock.toPosition(); if (validBlock(currentPosition)) { IBlockState actualBlockState = worldObj.getBlockState(currentPosition); Block actualBlock = actualBlockState.getBlock(); int metaData = actualBlock.getMetaFromState(actualBlockState); choppingTime = (int)Math.ceil( actualBlock.getBlockHardness(actualBlockState, worldObj, currentPosition) * 1.5 * 20 ); Item tool = (Item)slots[SLOT_AXE].getItem(); float choppingSpeed = 1.0f; if (isTree(currentPosition)) { choppingSpeed = ToolHelper.getDigSpeed( slots[SLOT_AXE], actualBlockState ); //check for efficiency on the tool, only for the wood though! int eff = EnchantmentHelper.getEnchantmentLevel(Enchantments.EFFICIENCY, slots[SLOT_AXE]); if (eff>0) { for (int i = 0; i<eff; i++) { choppingSpeed = choppingSpeed * 1.3f; } } } else { choppingSpeed = (float)ToolHelper.getSpeed(getUpgradeLevel()-1); } choppingTime = (int) Math.ceil(choppingTime / choppingSpeed); //ProgressiveAutomation.logger.info("Target: "+actualBlock.getLocalizedName()+" <"+currentBlock.toString()+"> with time of "+choppingTime); } } } } protected void findTree(int n) { Point2I p1 = spiral(n + 2, getPos().getX(), getPos().getZ()); //see if we already have the block first Point3I point = new Point3I(p1.getX(), getPos().getY(), p1.getY()); if (!blockList.inList(point)) { if (validBlock(point.toPosition())) { blockList.push(point); if (!chopping) { chopping = true; addPartialUpdate("chopping", true); } point.stepUp(); searchTree(point); } } } protected void searchTree(Point3I point) { //recursively search for the other blocks of a tree if (validBlock(point.toPosition())) { //add this block blockList.push(point); //now we want to search in the 8 directions around this block and 1 above for (int i = 0; i < 8; i++) { Point3I newPoint = new Point3I(point); Point2I spiralPoint = spiral(2 + i, newPoint.getX(), newPoint.getZ()); newPoint.setX(spiralPoint.getX()); newPoint.setZ(spiralPoint.getY()); if (isWithinCuttingRange(spiralPoint.getX(), spiralPoint.getY()) && !blockList.inList(newPoint)) { searchTree(newPoint); } } Point3I origPoint = new Point3I(point); origPoint.stepUp(); searchTree(origPoint); } } protected boolean validBlock(BlockPos point) { if (!worldObj.isAirBlock(point)) { if (isTree(point)) return true; else return isLeaf(point); } return false; } protected boolean validBlock(int x, int y, int z) { return validBlock(new BlockPos(x, y, z)); } protected boolean isTree(BlockPos point) { return (OreHelper.testOreBlock("logWood", point, worldObj)) || (OreHelper.testOreBlock("woodRubber", point, worldObj)) || isTree(testBlock(point)); } protected boolean isTree(int x, int y, int z) { return isTree(new BlockPos(x,y,z)); } protected boolean isTree(String type) { if ( (type.equalsIgnoreCase("logWood")) || (type.equalsIgnoreCase("woodRubber")) ) { return true; } return false; } protected boolean isLeaf(BlockPos point) { return (OreHelper.testOreBlock("treeLeaves", point, worldObj)) || (OreHelper.testOreBlock("leavesRubber", point, worldObj)) || isLeaf(testBlock(point)); } protected boolean isLeaf(int x, int y, int z) { return isLeaf(new BlockPos(x,y,z)); } protected boolean isLeaf(String type) { if ( (type.equalsIgnoreCase("treeLeaves")) || (type.equalsIgnoreCase("leavesRubber")) ) { return true; } return false; } protected String testBlock(BlockPos pos) { IBlockState _blockState = worldObj.getBlockState(pos); Block _block = _blockState.getBlock(); int metaData = _block.getMetaFromState(_blockState); ItemStack testItem = new ItemStack(_block, 1, metaData); if (ModHelper.isLeaf(testItem)) return "treeLeaves"; if (ModHelper.isLog(testItem)) return "logWood"; return "Unknown"; } @Override public boolean readyToBurn() { if (slots[SLOT_AXE]!=null) { if (scanBlocks()) { if ( (plantSapling && (slots[SLOT_SAPLINGS]!=null)) || (blockList.size()>0) ) return true; } } return false; } protected boolean plantSaplings(int n, boolean doAction) { //so this method will attempt to plant saplings on anything that they can be planted on if (slots[SLOT_SAPLINGS]!=null) { if (slots[SLOT_SAPLINGS].stackSize>0) { Point2I p1 = spiral(n + 2, getPos().getX(), getPos().getZ()); //ProgressiveAutomation.logger.debug("Plant: "+p1.getX()+", "+getPos().getY()+", "+p1.getY()); if (Block.getBlockFromItem(slots[SLOT_SAPLINGS].getItem()) instanceof IPlantable) { Block tree = (Block)Block.getBlockFromItem(slots[SLOT_SAPLINGS].getItem()); BlockPos plantPos = new BlockPos(p1.getX(), getPos().getY(), p1.getY()); if ( (tree.canPlaceBlockAt(worldObj, plantPos)) && (worldObj.getBlockState(plantPos).getBlock().canReplace(worldObj, plantPos, EnumFacing.DOWN, slots[SLOT_SAPLINGS])) && (worldObj.getBlockState(plantPos).getBlock() != tree) ) { if (doAction) { worldObj.setBlockState(plantPos, tree.getStateFromMeta(slots[SLOT_SAPLINGS].getItem().getDamage(slots[SLOT_SAPLINGS])), 7); slots[SLOT_SAPLINGS].stackSize--; if (slots[SLOT_SAPLINGS].stackSize==0) { slots[SLOT_SAPLINGS] = null; } } return true; } } } } return false; } public boolean isPlanting() { return plantSapling; } public boolean isChopping() { return chopping; } protected int lastAxe = -1; private int previousUpgrades; public void checkForChanges() { boolean update = false; //check axe if ( (slots[SLOT_AXE] == null) && (lastAxe>=0) ) { lastAxe = -1; update = true; } else if (slots[SLOT_AXE] != null) { if (ToolHelper.getLevel(slots[SLOT_AXE]) != lastAxe) { lastAxe = ToolHelper.getLevel(slots[SLOT_AXE]); update = true; } } //check upgrades if (forceRecalculate || previousUpgrades != getUpgrades()) { forceRecalculate = false; previousUpgrades = getUpgrades(); recalculateChoppingRange(); update = true; } //update if (update) { //ProgressiveAutomation.logger.info("Inventory Changed Update"); scanBlocks(); } } public int extraSlotCheck(ItemStack item) { if (checkSapling(item)) { return SLOT_SAPLINGS; } return super.extraSlotCheck(item); } /* ISided Stuff */ public boolean isItemValidForSlot(int slot, ItemStack stack) { if ( (slot == this.SLOT_SHEARS) && (stack.getItem() == Items.SHEARS) && (hasUpgrade(UpgradeType.SHEARING)) ) { return true; } else if ( (slot == SLOT_SAPLINGS) && (checkSapling(stack)) ) { return true; } return super.isItemValidForSlot(slot, stack); } public static boolean checkSapling(ItemStack stack) { if (ModHelper.checkSapling(stack)) { return true; } else { return false; } } private void recalculateChoppingRange() { int cuttingSideSize = CUTTING_EXTRA_RANGE + (int)Math.ceil( (Math.sqrt(getUpgrades() + 1)-1)/2); maxCuttingX = this.getPos().getX() + cuttingSideSize; minCuttingX = this.getPos().getX() - cuttingSideSize; maxCuttingZ = this.getPos().getZ() + cuttingSideSize; minCuttingZ = this.getPos().getZ() - cuttingSideSize; } private boolean isWithinCuttingRange(int x, int z) { if (x >= minCuttingX && x <= maxCuttingX && z >= minCuttingZ && z <= maxCuttingZ) return true; return false; } @Override protected Point3I adjustedSpiral(int n) { Point3I point = super.adjustedSpiral(n + 1); return point; } }