package com.vanhal.progressiveautomation.entities.miner;
import java.util.List;
import com.vanhal.progressiveautomation.entities.UpgradeableTileEntity;
import com.vanhal.progressiveautomation.ref.ToolHelper;
import com.vanhal.progressiveautomation.upgrades.UpgradeType;
import com.vanhal.progressiveautomation.util.Point2I;
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.Blocks;
import net.minecraft.init.Enchantments;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.common.ForgeHooks;
public class TileMiner extends UpgradeableTileEntity {
protected int totalMineBlocks = -1;
protected int currentMineBlocks = 0;
//mining vars
protected int currentColumn = 0;
protected int currentYLevel = 0;
protected Block currentBlock = null;
protected int miningWith = 0;
protected int blockMineDuration = 0;
protected int elapsedDuration = 0;
public TileMiner() {
super(13);
setUpgradeLevel(ToolHelper.LEVEL_WOOD);
setAllowedUpgrades(UpgradeType.WOODEN, UpgradeType.WITHER, UpgradeType.COBBLE_GEN, UpgradeType.FILLER);
//set the slots
SLOT_PICKAXE = 2;
SLOT_SHOVEL = 3;
SLOT_UPGRADE = 4;
}
public void writeCommonNBT(NBTTagCompound nbt) {
super.writeCommonNBT(nbt);
nbt.setInteger("MineBlocks", totalMineBlocks);
nbt.setInteger("MinedBlocks", currentMineBlocks);
}
public void readCommonNBT(NBTTagCompound nbt) {
super.readCommonNBT(nbt);
if (nbt.hasKey("MineBlocks")) totalMineBlocks = nbt.getInteger("MineBlocks");
if (nbt.hasKey("MinedBlocks")) currentMineBlocks = nbt.getInteger("MinedBlocks");
}
public void update() {
super.update();
if (!worldObj.isRemote) {
checkForChanges();
checkInventory();
// If we're full, don't do anything else
if (isFull()) return;
if (isBurning()) {
useCobbleGen();
if (!isDone()) {
//mine!
mine();
}
}
}
}
public void scanBlocks() {
totalMineBlocks = currentMineBlocks = 0;
for (int i = 1; i <= getRange(); i++) {
Point2I currentPoint = spiral(i, pos.getX(), pos.getZ());
boolean bedrock = false;
int newY = this.pos.getY() - 1;
while (!bedrock) {
int result = canMineBlock(currentPoint.getX(), newY, currentPoint.getY());
if (result >= 1) {
totalMineBlocks++;
} else if (result == -1) {
totalMineBlocks++;
currentMineBlocks++;
}
newY--;
if (newY<0) bedrock = true;
}
}
addPartialUpdate("MineBlocks", totalMineBlocks);
addPartialUpdate("MinedBlocks", currentMineBlocks);
notifyUpdate();
//ProgressiveAutomation.logger.info("Update Finished: "+currentMineBlocks+"/"+totalMineBlocks);
}
/* Tests a block to see if it can be mined with the current equipment
* Returns 0 if it can't, -1 if it is cobble
* Will return 2 if mined with pick, 3 if shovel, 1 if none
* return 4 if just need to fill using the filler upgrade */
public int canMineBlock(int x, int y, int z) {
BlockPos minePos = new BlockPos(x, y, z);
IBlockState tryState = worldObj.getBlockState(minePos);
Block tryBlock = tryState.getBlock();
if (tryBlock != null) {
int meta = tryBlock.getMetaFromState(tryState);
if (
(tryBlock.getBlockHardness(tryState, worldObj, minePos)>=0) &&
(!tryBlock.isAir(tryState, worldObj, minePos))
) {
boolean mine = false;
//ProgressiveAutomation.logger.info("Tool: "+tryBlock.getHarvestTool(meta)+", Level: "+tryBlock.getHarvestLevel(meta)+", Can use Pick: "+tryBlock.isToolEffective("pickaxe", meta));
//ProgressiveAutomation.logger.info("Harvestable: "+ForgeHooks.canToolHarvestBlock(tryBlock, meta, getStackInSlot(2)));
if (tryBlock == Blocks.COBBLESTONE) {
return -1;
}
if (tryBlock.getHarvestTool(tryState)=="chisel") { //this is compatibility for chisel 1
return 2;
} else if (tryBlock.getHarvestTool(tryState)=="pickaxe") {
if (ForgeHooks.canToolHarvestBlock(worldObj, minePos, getStackInSlot(2))) {
//ProgressiveAutomation.logger.info("Tool can harvest");
return 2;
}
} else if (tryBlock.getHarvestTool(tryState)=="shovel") {
if (ForgeHooks.canToolHarvestBlock(worldObj, minePos, getStackInSlot(3))) {
return 3;
}
} else {
if (!tryBlock.getMaterial(tryState).isLiquid()) {
return 1;
}
}
}
//see if the filler upgrade is active, if it is then the block will need to be filled.
if (hasUpgrade(UpgradeType.FILLER)) {
if ( (tryBlock.isAir(tryState, worldObj, minePos)) || (tryBlock.getMaterial(tryState).isLiquid()) ) {
return 4;
}
}
}
return 0;
}
public void mine() {
if ( (slots[1]==null) || (slots[2]==null) || (slots[3]==null) ) return;
if (currentBlock!=null) {
//continue to mine this block
if (elapsedDuration >= blockMineDuration) {
//clock is done, lets mine it
Point2I currentPoint = spiral(currentColumn, pos.getX(), pos.getZ());
BlockPos currentPosition = new BlockPos(currentPoint.getX(), currentYLevel, currentPoint.getY());
//ProgressiveAutomation.logger.info("Point: "+miningWith+" "+currentPoint.getX()+","+currentYLevel+","+currentPoint.getY());
// Verify the block is what we expect, fixes race condition and item dupe effect
Block testBlock = worldObj.getBlockState(currentPosition).getBlock();
if (testBlock != currentBlock) {
//ProgressiveAutomation.logger.info("Possible race condition found, expected "+currentBlock.getUnlocalizedName()+" actually had "+testBlock.getUnlocalizedName()+".");
currentBlock = testBlock;
miningWith = canMineBlock( currentPosition.getX(), currentPosition.getY(), currentPosition.getZ() );
// Intentionally leaving cobble requirement and item durability reduction as penalty for multiple miners in same area
if (miningWith == -1) {
miningWith = 2;
}
blockMineDuration = miningDuration( currentPosition, miningWith );
// If we haven't waited enough, wait some more!
if (elapsedDuration < blockMineDuration) {
elapsedDuration++;
return;
}
}
//don't harvest anything if the block is air or liquid
if (miningWith!=4) {
//get the inventory of anything under it
if (worldObj.getTileEntity(currentPosition) instanceof IInventory) {
IInventory inv = (IInventory) worldObj.getTileEntity(currentPosition);
for (int i = 0; i < inv.getSizeInventory(); i++) {
if (inv.getStackInSlot(i)!=null) {
addToInventory(inv.getStackInSlot(i));
inv.setInventorySlotContents(i, null);
}
}
}
//silk touch the block if we have it
int silkTouch = 0;
if (miningWith!=1) {
silkTouch = EnchantmentHelper.getEnchantmentLevel(Enchantments.SILK_TOUCH, slots[miningWith]);
}
if (silkTouch>0) {
int i = 0;
Item item = Item.getItemFromBlock(currentBlock);
if (item != null && item.getHasSubtypes()) i = currentBlock.getMetaFromState(worldObj.getBlockState(currentPosition));
ItemStack addItem = new ItemStack(currentBlock, 1, i);
addToInventory(addItem);
} else {
//mine the block
int fortuneLevel = 0;
if (miningWith!=1) {
fortuneLevel = EnchantmentHelper.getEnchantmentLevel(Enchantments.FORTUNE, slots[miningWith]);
}
//then break the block
List<ItemStack> items = currentBlock.getDrops(worldObj, currentPosition,
worldObj.getBlockState(currentPosition), fortuneLevel);
//get the drops
for (ItemStack item : items) {
addToInventory(item);
}
}
if (miningWith!=1) {
if (ToolHelper.damageTool(slots[miningWith], worldObj, currentPoint.getX(), currentYLevel, currentPoint.getY())) {
destroyTool(miningWith);
}
}
}
//remove the block and entity if there is one
worldObj.removeTileEntity( currentPosition );
worldObj.setBlockState( currentPosition, Blocks.COBBLESTONE.getDefaultState());
slots[1].stackSize--;
if (slots[1].stackSize == 0) {
slots[1] = null;
}
currentMineBlocks++;
addPartialUpdate("MinedBlocks", currentMineBlocks);
currentBlock = null;
elapsedDuration = 0;
} else {
elapsedDuration++;
}
} else {
if (!isDone()) {
currentBlock = getNextBlock();
if (currentBlock != null) {
Point2I currentPoint = spiral(currentColumn, pos.getX(), pos.getZ());
BlockPos currentPosition = new BlockPos(currentPoint.getX(), currentYLevel, currentPoint.getY());
blockMineDuration = miningDuration( currentPosition, miningWith );
//ProgressiveAutomation.logger.info("Mining: "+currentBlock.getUnlocalizedName()+" in "+blockMineDuration+" ticks");
}
}
}
if (isDone()) {
//ProgressiveAutomation.logger.info("Done Update");
scanBlocks();
currentColumn = getRange();
}
}
// Determine how long it will take to mine the block at pos with the tool specified.
private int miningDuration(BlockPos pos, int tool) {
int duration = 0;
IBlockState state = worldObj.getBlockState(pos);
Block block = state.getBlock();
int normal = (int)Math.ceil( block.getBlockHardness(state, worldObj, pos) * 1.5 * 20 ) ;
switch (tool) {
case 1: // Hands
duration = normal;
break;
case 2: // Pickaxe
case 3: // Shovel
float miningSpeed = ToolHelper.getDigSpeed( slots[tool], state );
// If tool doesn't have efficiency, we're done.
if (miningSpeed <= 1) {
duration = normal;
break;
}
int eff = EnchantmentHelper.getEnchantmentLevel(Enchantments.EFFICIENCY, slots[tool]);
if (eff>0) {
for (int i = 0; i<eff; i++) {
miningSpeed = miningSpeed * 1.3f;
}
}
duration = (int) Math.ceil(normal / miningSpeed);
break;
case 4: // Liquid
duration = 1;
break;
default:
duration = 0;
break;
}
return duration;
}
public Block getNextBlock() {
Point2I currentPoint = spiral(currentColumn, pos.getX(), pos.getZ());
miningWith = canMineBlock(currentPoint.getX(), currentYLevel, currentPoint.getY());
while ( (miningWith<=0) && (currentYLevel>=0) ) {
if (miningWith>0) {
return worldObj.getBlockState(new BlockPos(currentPoint.getX(), currentYLevel, currentPoint.getY())).getBlock();
} else {
currentYLevel--;
if (currentYLevel>=0)
miningWith = canMineBlock(currentPoint.getX(), currentYLevel, currentPoint.getY());
}
}
if (miningWith>0) {
return worldObj.getBlockState(new BlockPos(currentPoint.getX(), currentYLevel, currentPoint.getY())).getBlock();
}
if (currentYLevel<0) {
currentYLevel = pos.getY() - 1;
currentColumn--;
if (currentColumn<0) {
//ProgressiveAutomation.logger.info("Last Column done Update");
scanBlocks();
currentColumn = getRange();
} else {
return getNextBlock();
}
}
return null;
}
protected int getCurrentUpgrades() {
if (SLOT_UPGRADE==-1) return 0;
if (this.getStackInSlot(SLOT_UPGRADE)==null) {
return 0;
} else {
return this.getStackInSlot(SLOT_UPGRADE).stackSize;
}
}
public int getMinedBlocks() {
return currentMineBlocks;
}
public void setMinedBlocks(int value) {
currentMineBlocks = value;
}
public int getMineBlocks() {
return totalMineBlocks;
}
public void setMineBlocks(int value) {
totalMineBlocks = value;
}
public boolean isDone() {
return (totalMineBlocks==currentMineBlocks) && (totalMineBlocks>0) && (slots[SLOT_PICKAXE]!=null) && (slots[SLOT_SHOVEL]!=null);
}
//if we have a cobblegen upgrade then this function will deal with adding cobble that is generated
public void useCobbleGen() {
if (hasUpgrade(UpgradeType.COBBLE_GEN)) {
if ( (slots[1] == null) || (slots[1].stackSize==0) ) {
if (slots[SLOT_PICKAXE]!=null) {
if (ToolHelper.damageTool(slots[SLOT_PICKAXE], worldObj, this.pos.getX(), this.pos.getY(), this.pos.getZ())) {
destroyTool(SLOT_PICKAXE);
}
slots[1] = new ItemStack(Blocks.COBBLESTONE);
}
}
}
}
/* Check for changes to tools and upgrades */
protected int lastPick = -1;
protected int lastShovel = -1;
private int previousUpgrades;
public void checkForChanges() {
boolean update = false;
//check pickaxe
if ( (slots[2] == null) && (lastPick>=0) ) {
lastPick = -1;
update = true;
} else if (slots[2] != null) {
if (ToolHelper.getLevel(slots[2]) != lastPick) {
lastPick = ToolHelper.getLevel(slots[2]);
update = true;
}
}
//check shovel
if ( (slots[3] == null) && (lastShovel>=0) ) {
lastShovel = -1;
update = true;
} else if (slots[3] != null) {
if (ToolHelper.getLevel(slots[3]) != lastShovel) {
lastShovel = ToolHelper.getLevel(slots[3]);
update = true;
}
}
//check upgrades
if (previousUpgrades != getUpgrades()) {
previousUpgrades = getUpgrades();
update = true;
}
//update
if (update) {
//ProgressiveAutomation.logger.info("INventory Changed Update");
scanBlocks();
currentColumn = getRange();
currentBlock = null;
elapsedDuration = 0;
blockMineDuration = 0;
currentYLevel = pos.getY() - 1;
}
}
/* Check if we are ready to go */
public boolean readyToBurn() {
if ( (totalMineBlocks>0) && (currentMineBlocks < totalMineBlocks) ) {
if ( ((slots[1]!=null)||(hasUpgrade(UpgradeType.COBBLE_GEN))) && (slots[2]!=null) && (slots[3]!=null) ) {
return true;
}
}
if (((slots[1] == null) || (slots[1].stackSize==0)) && (hasUpgrade(UpgradeType.COBBLE_GEN)) && (slots[2]!=null) && (slots[3]!=null) ) {
return true;
}
return false;
}
public int extraSlotCheck(ItemStack item) {
if (item.isItemEqual(new ItemStack(Blocks.COBBLESTONE))) {
return 1;
}
return super.extraSlotCheck(item);
}
/* ISided Stuff */
public boolean isItemValidForSlot(int slot, ItemStack stack) {
if ( (slot==1) && (stack.isItemEqual(new ItemStack(Blocks.COBBLESTONE))) ) {
return true;
}
return super.isItemValidForSlot(slot, stack);
}
}