package tconstruct.library.tools;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.PlayerControllerMP;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.play.client.C07PacketPlayerDigging;
import net.minecraft.network.play.server.S23PacketBlockChange;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeHooks;
import tconstruct.tools.TinkerTools;
import tconstruct.util.config.PHConstruct;
import java.util.HashSet;
import java.util.Set;
/* Base class for tools that should be harvesting blocks */
public abstract class HarvestTool extends ToolCore
{
public HarvestTool(int baseDamage)
{
super(baseDamage);
}
@Override
public boolean onBlockStartBreak (ItemStack stack, int x, int y, int z, EntityPlayer player)
{
return super.onBlockStartBreak(stack, x,y,z, player);
}
@Override
public int getHarvestLevel(ItemStack stack, String toolClass) {
// well, we can only get the harvestlevel if we have an item to get it from!
if(stack == null || !(stack.getItem() instanceof HarvestTool))
return -1;
// invalid query or wrong toolclass
if(toolClass == null || !this.getHarvestType().equals(toolClass))
return -1;
if(!stack.hasTagCompound())
return -1;
NBTTagCompound tags = stack.getTagCompound().getCompoundTag("InfiTool");
// broken tools suck.
if (tags.getBoolean("Broken"))
return -1;
// tadaaaa
return tags.getInteger("HarvestLevel");
}
@Override
public float getDigSpeed (ItemStack stack, Block block, int meta)
{
if (!stack.hasTagCompound())
return 1.0f;
NBTTagCompound tags = stack.getTagCompound().getCompoundTag("InfiTool");
if (tags.getBoolean("Broken"))
return 0.1f;
if(isEffective(block, meta))
return calculateStrength(tags, block, meta);
return super.getDigSpeed(stack, block, meta);
}
public float calculateStrength (NBTTagCompound tags, Block block, int meta)
{
int hlvl = block.getHarvestLevel(meta);
if (hlvl > tags.getInteger("HarvestLevel"))
return 0.1f;
return AbilityHelper.calcToolSpeed(this, tags);
}
public float breakSpeedModifier ()
{
return 1.0f;
}
public float stoneboundModifier ()
{
return 72f;
}
@Override
public boolean func_150897_b (Block block)
{
if (block.getMaterial().isToolNotRequired())
{
return true;
}
return isEffective(block.getMaterial());
}
@Override
public boolean canHarvestBlock (Block block, ItemStack itemStack)
{
return func_150897_b(block);
}
@Override
public String[] getTraits ()
{
return new String[] { "harvest" };
}
protected abstract Material[] getEffectiveMaterials ();
protected abstract String getHarvestType ();
@Override
public Set<String> getToolClasses(ItemStack stack) {
Set<String> set = new HashSet<String>();
if(stack != null && stack.getItem() instanceof HarvestTool) {
set.add(((HarvestTool) stack.getItem()).getHarvestType());
}
return set;
}
public boolean isEffective (Block block, int meta)
{
if(this.getHarvestType().equals(block.getHarvestTool(meta)))
return true;
else return isEffective(block.getMaterial());
}
public boolean isEffective (Material material)
{
for (Material m : getEffectiveMaterials())
if (m == material)
return true;
return false;
}
//Right-click
@Override
public boolean onItemUse (ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float clickX, float clickY, float clickZ)
{
/*if (world.isRemote)
return true;*/
boolean used = false;
int hotbarSlot = player.inventory.currentItem;
int itemSlot = hotbarSlot == 0 ? 8 : hotbarSlot + 1;
ItemStack nearbyStack = null;
if (hotbarSlot < 8)
{
nearbyStack = player.inventory.getStackInSlot(itemSlot);
if (nearbyStack != null)
{
Item item = nearbyStack.getItem();
if (item instanceof ItemBlock || (item != null && item == TinkerTools.openBlocksDevNull))
{
int posX = x;
int posY = y;
int posZ = z;
int playerPosX = (int) Math.floor(player.posX);
int playerPosY = (int) Math.floor(player.posY);
int playerPosZ = (int) Math.floor(player.posZ);
if (side == 0)
{
--posY;
}
if (side == 1)
{
++posY;
}
if (side == 2)
{
--posZ;
}
if (side == 3)
{
++posZ;
}
if (side == 4)
{
--posX;
}
if (side == 5)
{
++posX;
}
if (posX == playerPosX && (posY == playerPosY || posY == playerPosY + 1 || posY == playerPosY - 1) && posZ == playerPosZ)
{
return false;
}
int dmg = nearbyStack.getItemDamage();
int count = nearbyStack.stackSize;
if (item == TinkerTools.openBlocksDevNull)
{
//Openblocks uses current inventory slot, so we have to do this...
player.inventory.currentItem=itemSlot;
item.onItemUse(nearbyStack, player, world, x, y, z, side, clickX, clickY, clickZ);
player.inventory.currentItem=hotbarSlot;
player.swingItem();
}
else
used = item.onItemUse(nearbyStack, player, world, x, y, z, side, clickX, clickY, clickZ);
// handle creative mode
if(player.capabilities.isCreativeMode) {
// fun fact: vanilla minecraft does it exactly the same way
nearbyStack.setItemDamage(dmg);
nearbyStack.stackSize = count;
}
if (nearbyStack.stackSize < 1)
{
nearbyStack = null;
player.inventory.setInventorySlotContents(itemSlot, null);
}
}
}
}
/*
if (used) //Update client
{
Packet103SetSlot packet = new Packet103SetSlot(player.openContainer.windowId, itemSlot, nearbyStack);
((EntityPlayerMP)player).playerNetServerHandler.sendPacketToPlayer(packet);
}
*/
return used;
}
protected void breakExtraBlock(World world, int x, int y, int z, int sidehit, EntityPlayer player, int refX, int refY, int refZ) {
// prevent calling that stuff for air blocks, could lead to unexpected behaviour since it fires events
if (world.isAirBlock(x, y, z))
return;
// check if the block can be broken, since extra block breaks shouldn't instantly break stuff like obsidian
// or precious ores you can't harvest while mining stone
Block block = world.getBlock(x, y, z);
int meta = world.getBlockMetadata(x, y, z);
// only effective materials
if (!isEffective(block, meta))
return;
Block refBlock = world.getBlock(refX, refY, refZ);
float refStrength = ForgeHooks.blockStrength(refBlock, player, world, refX, refY, refZ);
float strength = ForgeHooks.blockStrength(block, player, world, x,y,z);
// only harvestable blocks that aren't impossibly slow to harvest
if (!ForgeHooks.canHarvestBlock(block, player, meta) || refStrength/strength > 10f)
return;
if (player.capabilities.isCreativeMode) {
block.onBlockHarvested(world, x, y, z, meta, player);
if (block.removedByPlayer(world, player, x, y, z, false))
block.onBlockDestroyedByPlayer(world, x, y, z, meta);
// send update to client
if (!world.isRemote) {
((EntityPlayerMP)player).playerNetServerHandler.sendPacket(new S23PacketBlockChange(x, y, z, world));
}
return;
}
// callback to the tool the player uses. Called on both sides. This damages the tool n stuff.
player.getCurrentEquippedItem().func_150999_a(world, block, x, y, z, player);
// server sided handling
if (!world.isRemote) {
// serverside we reproduce ItemInWorldManager.tryHarvestBlock
// ItemInWorldManager.removeBlock
block.onBlockHarvested(world, x,y,z, meta, player);
if(block.removedByPlayer(world, player, x,y,z, true)) // boolean is if block can be harvested, checked above
{
block.onBlockDestroyedByPlayer( world, x,y,z, meta);
block.harvestBlock(world, player, x,y,z, meta);
}
// always send block update to client
EntityPlayerMP mpPlayer = (EntityPlayerMP) player;
mpPlayer.playerNetServerHandler.sendPacket(new S23PacketBlockChange(x, y, z, world));
}
// client sided handling
else {
PlayerControllerMP pcmp = Minecraft.getMinecraft().playerController;
// clientside we do a "this clock has been clicked on long enough to be broken" call. This should not send any new packets
// the code above, executed on the server, sends a block-updates that give us the correct state of the block we destroy.
// following code can be found in PlayerControllerMP.onPlayerDestroyBlock
world.playAuxSFX(2001, x, y, z, Block.getIdFromBlock(block) + (meta << 12));
if(block.removedByPlayer(world, player, x,y,z))
{
block.onBlockDestroyedByPlayer(world, x,y,z, meta);
}
pcmp.onPlayerDestroyBlock(x, y, z, sidehit);
// send an update to the server, so we get an update back
if(PHConstruct.extraBlockUpdates)
Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C07PacketPlayerDigging(2, x,y,z, Minecraft.getMinecraft().objectMouseOver.sideHit));
}
}
}