package joshie.harvest.core.base.block;
import com.google.common.collect.Lists;
import joshie.harvest.core.HFTab;
import joshie.harvest.core.helpers.MCClientHelper;
import net.minecraft.block.Block;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.statemap.StateMap;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.IStringSerializable;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.common.IShearable;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Random;
import static net.minecraft.block.BlockLeaves.CHECK_DECAY;
import static net.minecraft.block.BlockLeaves.DECAYABLE;
public abstract class BlockHFLeaves<B extends BlockHFLeaves, E extends Enum<E> & IStringSerializable> extends BlockHFEnum<B, E> implements IShearable {
private int[] surroundings;
//Main Constructor
public BlockHFLeaves(Class<E> clazz, CreativeTabs tab) {
super(Material.LEAVES, clazz, tab);
setTickRandomly(true);
setHardness(0.2F);
setLightOpacity(1);
setSoundType(SoundType.PLANT);
}
//Constructor default to farming tab
public BlockHFLeaves(Class<E> clazz) {
this(clazz, HFTab.FARMING);
}
@Override
protected BlockStateContainer createBlockState() {
if(property == null) return new BlockStateContainer(this, temporary, CHECK_DECAY, DECAYABLE);
return new BlockStateContainer(this, property, CHECK_DECAY, DECAYABLE);
}
@Override
public void breakBlock(@Nonnull World worldIn, @Nonnull BlockPos pos, @Nonnull IBlockState state) {
int k = pos.getX();
int l = pos.getY();
int i1 = pos.getZ();
if (worldIn.isAreaLoaded(new BlockPos(k - 2, l - 2, i1 - 2), new BlockPos(k + 2, l + 2, i1 + 2))) {
for (int j1 = -1; j1 <= 1; ++j1) {
for (int k1 = -1; k1 <= 1; ++k1) {
for (int l1 = -1; l1 <= 1; ++l1) {
BlockPos blockpos = pos.add(j1, k1, l1);
IBlockState iblockstate = worldIn.getBlockState(blockpos);
if (iblockstate.getBlock().isLeaves(iblockstate, worldIn, blockpos)) {
iblockstate.getBlock().beginLeavesDecay(iblockstate, worldIn, blockpos);
}
}
}
}
}
}
@Override
public void updateTick(World worldIn, BlockPos pos, IBlockState state, Random rand) {
if (!worldIn.isRemote) {
if (state.getValue(CHECK_DECAY) && state.getValue(DECAYABLE)) {
int k = pos.getX();
int l = pos.getY();
int i1 = pos.getZ();
if (surroundings == null) {
surroundings = new int[32768];
}
if (worldIn.isAreaLoaded(new BlockPos(k - 5, l - 5, i1 - 5), new BlockPos(k + 5, l + 5, i1 + 5))) {
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
for (int i2 = -4; i2 <= 4; ++i2) {
for (int j2 = -4; j2 <= 4; ++j2) {
for (int k2 = -4; k2 <= 4; ++k2) {
IBlockState iblockstate = worldIn.getBlockState(blockpos$mutableblockpos.setPos(k + i2, l + j2, i1 + k2));
Block block = iblockstate.getBlock();
if (!block.canSustainLeaves(iblockstate, worldIn, blockpos$mutableblockpos.setPos(k + i2, l + j2, i1 + k2))) {
if (block.isLeaves(iblockstate, worldIn, blockpos$mutableblockpos.setPos(k + i2, l + j2, i1 + k2))) {
surroundings[(i2 + 16) * 1024 + (j2 + 16) * 32 + k2 + 16] = -2;
} else {
surroundings[(i2 + 16) * 1024 + (j2 + 16) * 32 + k2 + 16] = -1;
}
} else {
surroundings[(i2 + 16) * 1024 + (j2 + 16) * 32 + k2 + 16] = 0;
}
}
}
}
for (int i3 = 1; i3 <= 4; ++i3) {
for (int j3 = -4; j3 <= 4; ++j3) {
for (int k3 = -4; k3 <= 4; ++k3) {
for (int l3 = -4; l3 <= 4; ++l3) {
if (surroundings[(j3 + 16) * 1024 + (k3 + 16) * 32 + l3 + 16] == i3 - 1) {
if (surroundings[(j3 + 16 - 1) * 1024 + (k3 + 16) * 32 + l3 + 16] == -2) {
surroundings[(j3 + 16 - 1) * 1024 + (k3 + 16) * 32 + l3 + 16] = i3;
}
if (surroundings[(j3 + 16 + 1) * 1024 + (k3 + 16) * 32 + l3 + 16] == -2) {
surroundings[(j3 + 16 + 1) * 1024 + (k3 + 16) * 32 + l3 + 16] = i3;
}
if (surroundings[(j3 + 16) * 1024 + (k3 + 16 - 1) * 32 + l3 + 16] == -2) {
surroundings[(j3 + 16) * 1024 + (k3 + 16 - 1) * 32 + l3 + 16] = i3;
}
if (surroundings[(j3 + 16) * 1024 + (k3 + 16 + 1) * 32 + l3 + 16] == -2) {
surroundings[(j3 + 16) * 1024 + (k3 + 16 + 1) * 32 + l3 + 16] = i3;
}
if (surroundings[(j3 + 16) * 1024 + (k3 + 16) * 32 + (l3 + 16 - 1)] == -2) {
surroundings[(j3 + 16) * 1024 + (k3 + 16) * 32 + (l3 + 16 - 1)] = i3;
}
if (surroundings[(j3 + 16) * 1024 + (k3 + 16) * 32 + l3 + 16 + 1] == -2) {
surroundings[(j3 + 16) * 1024 + (k3 + 16) * 32 + l3 + 16 + 1] = i3;
}
}
}
}
}
}
}
int l2 = surroundings[16912];
if (l2 >= 0) {
worldIn.setBlockState(pos, state.withProperty(CHECK_DECAY, false), 4);
} else {
destroy(worldIn, pos);
}
}
}
}
private void destroy(World worldIn, BlockPos pos) {
dropBlockAsItem(worldIn, pos, worldIn.getBlockState(pos), 0);
worldIn.setBlockToAir(pos);
}
@Override
protected ItemStack createStackedBlock(@Nonnull IBlockState state) {
return new ItemStack(this, 1, getEnumFromState(state).ordinal());
}
@Override
public IBlockState getStateFromMeta(int meta) {
return this.getDefaultState().withProperty(property, getEnumFromMeta(meta)).withProperty(DECAYABLE, (meta & 4) == 0).withProperty(CHECK_DECAY, (meta & 8) > 0);
}
@Override
public int damageDropped(IBlockState state) {
return super.getMetaFromState(state);
}
@Override
public int getMetaFromState(IBlockState state) {
int i = 0;
i = i | super.getMetaFromState(state);
if (!(state.getValue(DECAYABLE))) {
i |= 4;
}
if (state.getValue(CHECK_DECAY)) {
i |= 8;
}
return i;
}
@SuppressWarnings("deprecation")
@SideOnly(Side.CLIENT)
@Override
public void randomDisplayTick(IBlockState stateIn, World worldIn, BlockPos pos, Random rand) {
if (worldIn.isRainingAt(pos.up()) && !worldIn.getBlockState(pos.down()).isFullyOpaque() && rand.nextInt(15) == 1) {
double d0 = (double) ((float) pos.getX() + rand.nextFloat());
double d1 = (double) pos.getY() - 0.05D;
double d2 = (double) ((float) pos.getZ() + rand.nextFloat());
worldIn.spawnParticle(EnumParticleTypes.DRIP_WATER, d0, d1, d2, 0.0D, 0.0D, 0.0D);
}
}
@Override
public int quantityDropped(Random random) {
return 0;
}
@Override
@Nullable
public Item getItemDropped(IBlockState state, Random rand, int fortune) {
return Item.getItemFromBlock(Blocks.SAPLING);
}
@Override
public boolean isOpaqueCube(IBlockState state) {
return false;
}
@SideOnly(Side.CLIENT)
public BlockRenderLayer getBlockLayer() {
return BlockRenderLayer.CUTOUT_MIPPED;
}
@Override
public boolean isVisuallyOpaque() {
return false;
}
@Override
public boolean isShearable(ItemStack item, IBlockAccess world, BlockPos pos) {
return true;
}
@Override
public boolean isLeaves(IBlockState state, IBlockAccess world, BlockPos pos) {
return true;
}
@Override
public void beginLeavesDecay(IBlockState state, World world, BlockPos pos) {
if (!state.getValue(CHECK_DECAY)) {
world.setBlockState(pos, state.withProperty(CHECK_DECAY, true), 4);
}
}
@SideOnly(Side.CLIENT)
@Override
@SuppressWarnings("deprecation")
public boolean shouldSideBeRendered(IBlockState blockState, @Nonnull IBlockAccess blockAccess, @Nonnull BlockPos pos, EnumFacing side) {
return !(!MCClientHelper.getMinecraft().gameSettings.fancyGraphics && blockAccess.getBlockState(pos.offset(side)).getBlock() == this) && super.shouldSideBeRendered(blockState, blockAccess, pos, side);
}
@Override
public List<ItemStack> onSheared(ItemStack item, IBlockAccess world, BlockPos pos, int fortune) {
return Lists.newArrayList(new ItemStack(this, 1, super.getMetaFromState(world.getBlockState(pos))));
}
@SideOnly(Side.CLIENT)
@Override
public void registerModels(Item item, String name) {
ModelLoader.setCustomStateMapper(this, new StateMap.Builder().ignore(CHECK_DECAY, DECAYABLE).build());
super.registerModels(item, name);
}
}