package com.zpig333.runesofwizardry.block;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyInteger;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.particle.ParticleManager;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.Explosion;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
import com.zpig333.runesofwizardry.api.IDust;
import com.zpig333.runesofwizardry.api.RuneEntity;
import com.zpig333.runesofwizardry.core.References;
import com.zpig333.runesofwizardry.core.WizardryLogger;
import com.zpig333.runesofwizardry.core.WizardryRegistry;
import com.zpig333.runesofwizardry.core.rune.RunesUtil;
import com.zpig333.runesofwizardry.item.ItemBroom;
import com.zpig333.runesofwizardry.item.ItemDustPouch;
import com.zpig333.runesofwizardry.item.ItemRunicStaff;
import com.zpig333.runesofwizardry.item.dust.DustPlaceholder;
import com.zpig333.runesofwizardry.tileentity.TileEntityDustActive;
import com.zpig333.runesofwizardry.tileentity.TileEntityDustDead;
import com.zpig333.runesofwizardry.tileentity.TileEntityDustPlaced;
import com.zpig333.runesofwizardry.util.RayTracer;
/**
* This class creates the block that holds placed dust
*
*/
public class BlockDustPlaced extends Block{
public BlockDustPlaced(){
super(Material.CIRCUITS);
this.setSoundType(SoundType.SAND);
this.disableStats();
this.setBlockUnbreakable();
this.setUnlocalizedName(References.modid+"_dust_placed");
//Could also register with null ItemBlock instead of hiding it in NEI
ResourceLocation res = new ResourceLocation(References.modid,"dust_placed");
GameRegistry.register(this, res);
GameRegistry.register(new ItemBlock(this), res);
this.setDefaultState(getDefaultState().withProperty(PROPERTYSTATE, STATE_NORMAL));
}
/**
* Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two
* adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
* @deprecated
*/
@Deprecated
@Override
public boolean isOpaqueCube(IBlockState state)
{
return false;
}
@Deprecated
@Override
public boolean isFullCube(IBlockState state){
return false;
}
@Deprecated
@Override
public AxisAlignedBB getCollisionBoundingBox(IBlockState state,IBlockAccess worldIn, BlockPos pos)
{ //No collision
//return new AxisAlignedBB(pos.getX(), pos.getY(), pos.getZ(), pos.getX()+1, pos.getY()+0.0625F, pos.getZ()+1.0F);
//return new AxisAlignedBB(pos, pos.add(1,1,1));
return null;
//return super.getCollisionBoundingBox(worldIn, pos, state);
}
/* (non-Javadoc)
* @see net.minecraft.block.Block#onEntityCollidedWithBlock(net.minecraft.world.World, net.minecraft.util.BlockPos, net.minecraft.block.state.IBlockState, net.minecraft.entity.Entity)
*/
@Override
public void onEntityCollidedWithBlock(World worldIn, BlockPos pos,IBlockState state, Entity entityIn) {
TileEntity te = worldIn.getTileEntity(pos);
if(te instanceof TileEntityDustPlaced){
TileEntityDustPlaced ted = (TileEntityDustPlaced)te;
if(ted.isInRune() && ted.getRune().handleEntityCollision(worldIn, pos, state, entityIn))return;
}
if(entityIn instanceof EntityItem){
EntityItem ei = (EntityItem) entityIn;
//these make the item look "stuck" and glitchy
//ReflectionHelper.setPrivateValue(EntityItem.class, ei, 0, "age","field_70292_b");
//ei.setNoDespawn();
EntityPlayer p = worldIn.getClosestPlayerToEntity(ei, 0.4);
if (p == null) {//if there is no player near enough, keep resetting the pickup delay
ei.setPickupDelay(20);
}else{
//double dist = p.getDistanceToEntity(ei);
//WizardryLogger.logInfo("Distance: "+dist);
Integer pickupDelay = ReflectionHelper.getPrivateValue(EntityItem.class, ei, "delayBeforeCanPickup","field_145804_b");
if (pickupDelay > 10) {
ei.setPickupDelay(10);//10 is the default, but there's no getDefaultPickupDelay, so its better to hardcode it in both uses
//ei.setDefaultPickupDelay();
}
}
}else{
super.onEntityCollidedWithBlock(worldIn, pos, state, entityIn);
}
}
@Deprecated
@Override
public EnumBlockRenderType getRenderType(IBlockState state){
return EnumBlockRenderType.ENTITYBLOCK_ANIMATED;//render type 2 is TESR
}
@Deprecated
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) {
return new AxisAlignedBB(0.0F, 0.0F, 0.0F, 1.0F, 0.0625F, 1.0F);
}
@Override
public boolean canHarvestBlock(net.minecraft.world.IBlockAccess world, BlockPos pos, net.minecraft.entity.player.EntityPlayer player) {
//this block is never harvested
return false;
};
@Override
public boolean canPlaceBlockAt(World world, BlockPos pos)
{
//get the block 1 lower
IBlockState state = world.getBlockState(pos.down());
Block block = state.getBlock();
if (block == null)
{
return false;
} else{
//FUTURE maybe tweak to use the oredict to allow other types of glass
return block.isSideSolid(state, world, pos.down(), EnumFacing.UP) || block == Blocks.GLASS;
}
}
/* (non-Javadoc)
* @see net.minecraft.block.Block#hasTileEntity(net.minecraft.block.state.IBlockState)
*/
@Override
public boolean hasTileEntity(IBlockState state) {
if(state.getBlock()==this)return true;
return false;
}
/* (non-Javadoc)
* @see net.minecraft.block.Block#createTileEntity(net.minecraft.world.World, net.minecraft.block.state.IBlockState)
*/
@Override
public TileEntity createTileEntity(World world, IBlockState state) {
if(state.getBlock()==this){
switch(state.getValue(PROPERTYSTATE)){
case STATE_ACTIVE: return new TileEntityDustActive();
case STATE_DEAD: return new TileEntityDustDead();
default: return new TileEntityDustPlaced();
}
}
return super.createTileEntity(world, state);
}
public static final int STATE_NORMAL=0,STATE_ACTIVE=1,STATE_DEAD=2;
//this block has 1 property: active or not.
public static final PropertyInteger PROPERTYSTATE = PropertyInteger.create("state", 0, 2);
@Deprecated
@Override
public IBlockState getStateFromMeta(int meta) {
return this.getDefaultState().withProperty(PROPERTYSTATE,meta);
}
@Override
public int getMetaFromState(IBlockState state) {
return state.getValue(PROPERTYSTATE);
}
@Override
protected BlockStateContainer createBlockState() {
return new BlockStateContainer(this, PROPERTYSTATE);
}
@Override
public void breakBlock(World worldIn, BlockPos pos, IBlockState state)
{ //drop the items
TileEntityDustPlaced tileentityDustPlaced = (TileEntityDustPlaced) worldIn.getTileEntity(pos);
if (tileentityDustPlaced != null) {
if(tileentityDustPlaced.isInRune()&&!worldIn.restoringBlockSnapshots){
tileentityDustPlaced.getRune().onPatternBroken();
}
Random random = new Random();
for (int i1 = 0; i1 < tileentityDustPlaced.getSizeInventory(); i1++) {
ItemStack itemstack = tileentityDustPlaced.getStackInSlot(i1);
if (!itemstack.isEmpty() && itemstack.getItem()!=WizardryRegistry.dust_dead) {
float f = random.nextFloat() * 0.8F + 0.1F;
float f1 = random.nextFloat() * 0.8F + 0.1F;
EntityItem entityitem;
for (float f2 = random.nextFloat() * 0.8F + 0.1F; itemstack.getCount() > 0; worldIn.spawnEntity(entityitem)) {
int j1 = random.nextInt(21) + 10;
if (j1 > itemstack.getCount()) {
j1 = itemstack.getCount();
}
entityitem = new EntityItem(worldIn, pos.getX() + f, pos.getY() + f1, pos.getZ() + f2, new ItemStack(itemstack.getItem(), j1, itemstack.getItemDamage()));
float f3 = 0.05F;
entityitem.motionX = (float) random.nextGaussian() * f3;
entityitem.motionY = (float) random.nextGaussian() * f3 + 0.2F;
entityitem.motionZ = (float) random.nextGaussian() * f3;
if (itemstack.hasTagCompound()) {
entityitem.getEntityItem().setTagCompound((NBTTagCompound) itemstack.getTagCompound().copy());
}
itemstack.setCount(itemstack.getCount() - j1);
}
}
}
worldIn.notifyNeighborsOfStateChange(pos, state.getBlock(),true);
}
super.breakBlock(worldIn, pos, state);
worldIn.removeTileEntity(pos);
TileEntityDustPlaced.updateNeighborConnectors(worldIn, pos);
}
/* (non-Javadoc)
* @see net.minecraft.block.Block#onBlockDestroyedByPlayer(net.minecraft.world.World, net.minecraft.util.BlockPos, net.minecraft.block.state.IBlockState)
*/
@Override
public void onBlockDestroyedByPlayer(World worldIn, BlockPos pos,IBlockState state) {
TileEntityDustPlaced.updateNeighborConnectors(worldIn, pos);
}
/* (non-Javadoc)
* @see net.minecraft.block.Block#onBlockDestroyedByExplosion(net.minecraft.world.World, net.minecraft.util.BlockPos, net.minecraft.world.Explosion)
*/
@Override
public void onBlockDestroyedByExplosion(World worldIn, BlockPos pos,Explosion explosionIn) {
TileEntityDustPlaced.updateNeighborConnectors(worldIn, pos);
}
@Override
public Item getItemDropped(IBlockState state, Random rand, int fortune){
return null;//this block should not be dropped!
}
@Override
public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand,EnumFacing side, float hitX, float hitY, float hitZ) {
TileEntity tile = worldIn.getTileEntity(pos);
if(playerIn.isSneaking() || tile==null){
return false;
}
//WizardryLogger.logInfo("DustPlaced block activated. pos= "+pos+" hitX: "+hitX+" hitY: "+hitY+" hitZ: "+hitZ);
if(! (tile instanceof TileEntityDustPlaced)){
//something is wrong
WizardryLogger.logError("The TileEntity attached to the BlockDustPlaced at "+pos+" has bad type: "+tile.getClass());
return false;
}
TileEntityDustPlaced tileDust = (TileEntityDustPlaced) tile;
if(tileDust.isInRune()){
RuneEntity rune = tileDust.getRune();
if(rune.handleRightClick(worldIn,pos, state, playerIn, side, hitX, hitY, hitZ)) return true;
}
//NW corner has hitX:0.09 hitZ:0.09
//NE corner has hitX:0.9 hitZ 0.09
//SE Corner has hitX 0.9 hitZ 0.9
//SW corner has hitX:0.02 hitZ 0.9
float posX = hitX * TileEntityDustPlaced.COLS;
float posZ = hitZ * TileEntityDustPlaced.ROWS;
int row = (int) posZ;
int col = (int) posX;
//WizardryLogger.logInfo("Slot coords is "+row+" "+col);
//make sure we are within bounds
if(row<0)row=0;
if(row>TileEntityDustPlaced.ROWS-1)row=TileEntityDustPlaced.ROWS-1;
if(col<0)col=0;
if(col>TileEntityDustPlaced.COLS-1)col=TileEntityDustPlaced.COLS-1;
int slotID = TileEntityDustPlaced.getSlotIDfromPosition(row, col);
ItemStack dustStack = tileDust.getStackInSlot(slotID);
ItemStack heldItem = playerIn.getHeldItem(hand);
if(heldItem.isEmpty()){
if (!dustStack.isEmpty()){
//drop the dust piece
if(tileDust.isInRune()){
tileDust.getRune().onPatternBrokenByPlayer(playerIn);
dustStack = tileDust.getStackInSlot(slotID);//re-grab the stack in case the rune changed it
}
tileDust.setInventorySlotContents(slotID, ItemStack.EMPTY);
worldIn.playSound(null,pos.getX() + 0.5F, pos.getY() + 0.5F, pos.getZ() + 0.5F, SoundType.SAND.getBreakSound(), SoundCategory.BLOCKS, (SoundType.SAND.getVolume() + 1.0F) / 2.0F, SoundType.GROUND.getPitch() * 0.8F);
//drop the itemStack
if(!playerIn.capabilities.isCreativeMode&& !dustStack.isEmpty() && !(dustStack.getItem() instanceof DustPlaceholder))spawnAsEntity(worldIn, pos, dustStack);
if(tileDust.isEmpty()){//if there is no more dust, break the block
this.breakBlock(worldIn, pos, state);
worldIn.setBlockToAir(pos);
}
return true;
}else{
return false;
}
}
//convert dust pouch to dust
if(heldItem.getItem() instanceof ItemDustPouch&& (dustStack.isEmpty()||dustStack.getItem() instanceof DustPlaceholder)){//XXX could be switched to a capability
heldItem = ((ItemDustPouch)heldItem.getItem()).getDustStack(heldItem, 1);
if(heldItem.isEmpty() || heldItem.getCount()<1)return false;
}
if(heldItem.getItem() instanceof IDust && (dustStack.isEmpty()||dustStack.getItem() instanceof DustPlaceholder)){
//place dust in the inventory
ItemStack newItem=ItemStack.EMPTY;
if(!playerIn.capabilities.isCreativeMode){
newItem= heldItem.splitStack(1);//grab one item from the stack
}else{
newItem = heldItem.copy();
newItem.setCount(1);
}
tileDust.setInventorySlotContents(slotID, newItem);
worldIn.playSound(null,pos.getX() + 0.5F, pos.getY() + 0.5F, pos.getZ() + 0.5F, SoundType.SAND.getPlaceSound(),SoundCategory.BLOCKS, (SoundType.SAND.getVolume() + 1.0F) / 2.0F, SoundType.GROUND.getPitch() * 0.8F);
//if the dust block was "dead", mark it as normal (and change the TE)
if(state.getValue(PROPERTYSTATE)==STATE_DEAD){
ItemStack[][] contents = tileDust.getContents();
worldIn.removeTileEntity(pos);
worldIn.setBlockState(pos, getDefaultState().withProperty(PROPERTYSTATE, STATE_NORMAL));
TileEntity te = worldIn.getTileEntity(pos);
if(!(te instanceof TileEntityDustPlaced))throw new IllegalStateException("TileEntity not formed!");
tileDust=(TileEntityDustPlaced)te;
tileDust.setContents(contents);
}
if(tileDust.isInRune()){
tileDust.getRune().onPatternBrokenByPlayer(playerIn);
}
return true;
}
if(heldItem.getItem() instanceof ItemBroom){
if(! worldIn.isRemote){
if(tileDust.isInRune()){
tileDust.getRune().onPatternBrokenByPlayer(playerIn);
}
worldIn.playSound(null,pos.getX() + 0.5F, pos.getY() + 0.5F, pos.getZ() + 0.5F, SoundType.SAND.getBreakSound(),SoundCategory.BLOCKS, (SoundType.SAND.getVolume() + 1.0F) / 2.0F, SoundType.GROUND.getPitch() * 0.8F);
if(playerIn.capabilities.isCreativeMode)RunesUtil.killDusts(worldIn, pos);
this.breakBlock(worldIn, pos, state);
worldIn.setBlockToAir(pos);
}
tileDust.clear();
TileEntityDustPlaced.updateNeighborConnectors(worldIn, pos);
}
//activate the rune with the staff
if(!tileDust.isInRune() && heldItem.getItem() instanceof ItemRunicStaff){
RunesUtil.activateRune(worldIn, pos, playerIn);
return true;
}
return false;
}
/* (non-Javadoc)
* @see net.minecraft.block.Block#onNeighborBlockChange(net.minecraft.world.World, net.minecraft.util.BlockPos, net.minecraft.block.state.IBlockState, net.minecraft.block.Block)
*/
@Deprecated
@Override
//public void neighborChanged(IBlockState state,World worldIn, BlockPos pos, Block neighborBlock) {
public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos){
if(worldIn.isAirBlock(pos.down())&&!worldIn.restoringBlockSnapshots){
this.breakBlock(worldIn, pos, state);
worldIn.setBlockToAir(pos);
return;
}
TileEntity te = worldIn.getTileEntity(pos);
if(te instanceof TileEntityDustPlaced){
RuneEntity rune = ((TileEntityDustPlaced)te).getRune();
if(rune!=null){
rune.handleBlockUpdate(worldIn, pos,state, fromPos);
}
}
}
/* (non-Javadoc)
* @see net.minecraft.block.Block#onBlockClicked(net.minecraft.world.World, net.minecraft.util.BlockPos, net.minecraft.entity.player.EntityPlayer)
*/
@Override
public void onBlockClicked(World worldIn, BlockPos pos, EntityPlayer playerIn) {
//called when the block is left-clicked, but does not have hitX Y Z ...
TileEntity tile = worldIn.getTileEntity(pos);
if(! (tile instanceof TileEntityDustPlaced)){
WizardryLogger.logError("The TileEntity attached to the BlockDustPlaced at "+pos+" has bad type: "+tile.getClass());
}
TileEntityDustPlaced tileDust = (TileEntityDustPlaced) tile;
if(!worldIn.isRemote){
//Raytrace for the hit position
RayTraceResult hitPos = RayTracer.retraceBlock(worldIn, playerIn, pos);
Vec3d hit = hitPos.hitVec;//this is null client side
//WizardryLogger.logInfo("DustPlaced block clicked. pos= "+pos+" lookX: "+look.xCoord+" lookY: "+look.yCoord+" lookZ: "+look.zCoord);
if(tileDust.isInRune()){
RuneEntity rune = tileDust.getRune();
if(rune.handleLeftClick(worldIn, pos, playerIn, hit))return;
}
//make it relative to the block hit and find the row/column hit
double posX = (hit.xCoord - pos.getX() )* TileEntityDustPlaced.COLS;
double posZ = (hit.zCoord - pos.getZ() )* TileEntityDustPlaced.ROWS;
int row = (int) posZ;
int col = (int) posX;
//WizardryLogger.logInfo("Slot coords is "+row+" "+col);
//make sure we are within bounds
if(row<0)row=0;
if(row>TileEntityDustPlaced.ROWS-1)row=TileEntityDustPlaced.ROWS-1;
if(col<0)col=0;
if(col>TileEntityDustPlaced.COLS-1)col=TileEntityDustPlaced.COLS-1;
int slotID = TileEntityDustPlaced.getSlotIDfromPosition(row, col);
ItemStack dustStack = tileDust.getStackInSlot(slotID);
if (!dustStack.isEmpty()){
//drop the dust piece
if(tileDust.isInRune()){
tileDust.getRune().onPatternBrokenByPlayer(playerIn);
dustStack = tileDust.getStackInSlot(slotID);
}
tileDust.setInventorySlotContents(slotID, ItemStack.EMPTY);
worldIn.playSound(null,pos.getX() + 0.5F, pos.getY() + 0.5F, pos.getZ() + 0.5F, SoundType.SAND.getPlaceSound(),SoundCategory.BLOCKS, (SoundType.SAND.getVolume() + 1.0F) / 2.0F, SoundType.GROUND.getPitch() * 0.8F);
//drop the itemStack
if(!playerIn.capabilities.isCreativeMode && !dustStack.isEmpty() && !(dustStack.getItem() instanceof DustPlaceholder))spawnAsEntity(worldIn, pos, dustStack);
if(tileDust.isEmpty()){//if there is no more dust, break the block
this.breakBlock(worldIn, pos, worldIn.getBlockState(pos));
worldIn.setBlockToAir(pos);
}
}
//update the client
//worldIn.markBlockForUpdate(pos);
IBlockState state = worldIn.getBlockState(pos);
worldIn.notifyBlockUpdate(pos, state, state, 3);
}
}
/* (non-Javadoc)
* @see net.minecraft.block.Block#addDestroyEffects(net.minecraft.world.World, net.minecraft.util.BlockPos, net.minecraft.client.particle.EffectRenderer)
*/
@Override
public boolean addDestroyEffects(World world, BlockPos pos, ParticleManager particleManager) {
return true;//should remove the break particles
}
/* (non-Javadoc)
* @see net.minecraft.block.Block#addHitEffects(net.minecraft.world.World, net.minecraft.util.RayTraceResult, net.minecraft.client.particle.EffectRenderer)
*/
@Override
public boolean addHitEffects(IBlockState state,World world, RayTraceResult target,ParticleManager particleManager) {
return true;//should remove "breaking" particles
}
@Override
public boolean canDropFromExplosion(Explosion explosionIn)
{
return false;
}
}