package net.mcft.copy.backpacks.block;
import java.util.Random;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.Explosion;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumFacing.Axis;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.mcft.copy.backpacks.api.BackpackHelper;
import net.mcft.copy.backpacks.api.IBackpack;
import net.mcft.copy.backpacks.block.entity.TileEntityBackpack;
import net.mcft.copy.backpacks.misc.util.LangUtils;
import net.mcft.copy.backpacks.misc.util.MiscUtils;
import net.mcft.copy.backpacks.misc.util.WorldUtils;
public class BlockBackpack extends BlockContainer {
/** Number of ticks a backpack will be resistant
* to explosions for after being placed. */
public static final int EXPLOSION_RESIST_TICKS = 10;
private final AxisAlignedBB[] _boundsFromFacing = new AxisAlignedBB[4];
public BlockBackpack() {
super(Material.CLOTH);
setSoundType(SoundType.SNOW);
setHardness(1.5F);
initBlockBounds();
}
@Override
public String getUnlocalizedName() {
// Just use the item's unlocalized name for this block.
return MiscUtils.getItemFromBlock(this).getUnlocalizedName();
}
@Override
public TileEntity createNewTileEntity(World worldIn, int meta) {
return new TileEntityBackpack();
}
// Block properties
@Override
public int quantityDropped(Random random) { return 0; }
@Override
public boolean isOpaqueCube(IBlockState state) { return false; }
@Override
public boolean isFullCube(IBlockState state) { return false; }
@Override
public EnumBlockRenderType getRenderType(IBlockState state) { return EnumBlockRenderType.INVISIBLE; }
// Block bounds
protected float getBoundsWidth() { return 12 / 16.0F; }
protected float getBoundsHeight() { return 13 / 16.0F; }
protected float getBoundsDepth() { return 10 / 16.0F; }
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) {
TileEntity entity = source.getTileEntity(pos);
EnumFacing facing = (entity instanceof TileEntityBackpack)
? ((TileEntityBackpack)entity).facing
: EnumFacing.NORTH;
return _boundsFromFacing[facing.ordinal() - 2];
}
private void initBlockBounds() {
float w = getBoundsWidth();
float h = getBoundsHeight();
float d = getBoundsDepth();
for (int i = 0; i < _boundsFromFacing.length; i++) {
EnumFacing facing = EnumFacing.getFront(i + 2);
_boundsFromFacing[i] = ((facing.getAxis() == Axis.Z)
? new AxisAlignedBB(0.5F - w / 2, 0.0F, 0.5F - d / 2, 0.5F + w / 2, h, 0.5F + d / 2)
: new AxisAlignedBB(0.5F - d / 2, 0.0F, 0.5F - w / 2, 0.5F + d / 2, h, 0.5F + w / 2));
}
}
// Block methods / events
// TODO: Fixed crash, but still doesn't return functioning ItemStack.
@Override
public ItemStack getPickBlock(IBlockState state, RayTraceResult target,
World world, BlockPos pos, EntityPlayer player) {
IBackpack backpack = BackpackHelper.getBackpack(world.getTileEntity(pos));
return (backpack != null)
? backpack.getStack().copy()
: super.getPickBlock(state, target, world, pos, player);
}
@Override
public void onBlockPlacedBy(World worldIn, BlockPos pos, IBlockState state,
EntityLivingBase placer, ItemStack stack) {
// Set the facing value of the backpack when placed.
TileEntity tileEntity = worldIn.getTileEntity(pos);
if (tileEntity instanceof TileEntityBackpack)
((TileEntityBackpack)tileEntity).facing = placer.getHorizontalFacing();
}
@Override
@SuppressWarnings("deprecation")
public float getPlayerRelativeBlockHardness(IBlockState state, EntityPlayer player, World worldIn, BlockPos pos) {
// Equipping a backpack is faster than breaking it.
// Trying to equip a backpack when not possible will make it appear unbreakable.
float hardness = super.getPlayerRelativeBlockHardness(state, player, worldIn, pos);
boolean sneaking = player.isSneaking();
boolean canEquip = BackpackHelper.canEquipBackpack(player);
return (sneaking && !canEquip)
? -1.0F /* Unbreakable */
: (hardness * (sneaking ? 4 : 1));
}
private long _lastHelpMessage = System.currentTimeMillis();
@Override
public void onBlockClicked(World world, BlockPos pos, EntityPlayer player) {
// Show a help message if the local player is trying to equip a backpack when it's not possible.
if (world.isRemote && player.isSneaking() && !BackpackHelper.canEquipBackpack(player) &&
(System.currentTimeMillis() > _lastHelpMessage + 10 * 1000)) {
boolean backpack = (BackpackHelper.getBackpack(player) != null);
LangUtils.displayChatMessage("cantEquip" + (!backpack ? ".chestplate" : ""));
_lastHelpMessage = System.currentTimeMillis();
}
}
@Override
public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state,
EntityPlayer player, EnumHand hand,
EnumFacing side, float hitX, float hitY, float hitZ) {
if (worldIn.isRemote) return true;
TileEntity entity = worldIn.getTileEntity(pos);
IBackpack backpack = BackpackHelper.getBackpack(entity);
if (backpack != null) backpack.getType().onPlacedInteract(player, entity, backpack);
return true;
}
// Equipping / block breaking / drops related
@Override
public void onBlockHarvested(World worldIn, BlockPos pos, IBlockState state, EntityPlayer player) {
if (!worldIn.isRemote && player.isSneaking() &&
BackpackHelper.canEquipBackpack(player))
// On the server, try to equip the backpack
// if the player is sneaking while breaking it.
BackpackHelper.equipBackpack(player, worldIn.getTileEntity(pos));
}
@Override
public boolean removedByPlayer(IBlockState state, World world, BlockPos pos,
EntityPlayer player, boolean willHarvest) {
// The super method will set the block to air before getDrops.
// But we need the tile entity there to drop the backpack item.
// Fun fact:
// "willHarvest" depends on if the block can be harvested with the current tool.
// For example stone can only be harvested with a pick. Without, harvestBlock and
// therefore getDrops aren't called and no items are dropped. This will always be
// true since we don't require a specific tool, but for correctness' sake, ...
if (willHarvest) {
// Super method calls this usually, we need to do it manually.
onBlockHarvested(world, pos, state, player);
return true;
} else return super.removedByPlayer(state, world, pos, player, willHarvest);
}
@Override
public void harvestBlock(World worldIn, EntityPlayer player, BlockPos pos,
IBlockState state, TileEntity entity, ItemStack stack) {
// The super method calls getDrops and spawns the items in-world.
super.harvestBlock(worldIn, player, pos, state, entity, stack);
worldIn.setBlockToAir(pos); // Set block to air, as it was delayed from removedByPlayer.
}
@Override
public void breakBlock(World worldIn, BlockPos pos, IBlockState state) {
// This is called when the block is set to air by any means.
// Afterward, the tile entity is also removed automatically.
TileEntity entity = worldIn.getTileEntity(pos);
IBackpack backpack = BackpackHelper.getBackpack(entity);
if ((backpack != null) && (backpack.getType() != null)) {
// Drop backpack item if it hasn't been equipped (getStack is empty).
WorldUtils.dropStackFromBlock(worldIn, pos, backpack.getStack());
// This would drop the contents of a normal backpack.
backpack.getType().onBlockBreak(entity, backpack);
}
}
public void onBlockExploded(World world, BlockPos pos, Explosion explosion) {
// Only destroy the backpack block if its age isn't negative.
// (Age is set to -EXPLOSION_RESIST_TICKS after being dropped on death.)
TileEntity entity = world.getTileEntity(pos);
if ((entity instanceof TileEntityBackpack) &&
(((TileEntityBackpack)entity).getAge() < 0)) return;
super.onBlockExploded(world, pos, explosion);
}
}