package com.infinityraider.agricraft.blocks;
import com.infinityraider.agricraft.farming.growthrequirement.GrowthRequirementHandler;
import com.infinityraider.agricraft.init.AgriItems;
import com.infinityraider.agricraft.reference.AgriProperties;
import com.infinityraider.agricraft.reference.Constants;
import com.infinityraider.agricraft.reference.Reference;
import com.infinityraider.agricraft.renderers.blocks.RenderCrop;
import com.infinityraider.agricraft.tiles.TileEntityCrop;
import com.infinityraider.infinitylib.utility.WorldHelper;
import java.util.*;
import com.infinityraider.infinitylib.block.BlockTileCustomRenderedBase;
import com.infinityraider.infinitylib.block.blockstate.InfinityProperty;
import net.minecraft.block.Block;
import net.minecraft.block.IGrowable;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.particle.ParticleManager;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.EnumPlantType;
import net.minecraftforge.common.IPlantable;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.IUnlistedProperty;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nullable;
public class BlockCrop extends BlockTileCustomRenderedBase<TileEntityCrop> implements IGrowable, IPlantable {
public static final AxisAlignedBB BOX = new AxisAlignedBB(Constants.UNIT * 2, 0, Constants.UNIT * 2, Constants.UNIT * (Constants.WHOLE - 2), Constants.UNIT * (Constants.WHOLE - 3), Constants.UNIT * (Constants.WHOLE - 2));
public BlockCrop() {
super("crop", Material.PLANTS);
this.setTickRandomly(true);
this.isBlockContainer = true;
this.setSoundType(SoundType.PLANT);
this.setHardness(0.0F);
//this.disableStats();
this.setCreativeTab(null);
}
@Override
public int getMetaFromState(IBlockState state) {
return 0;
}
@Override
public TileEntityCrop createNewTileEntity(World world, int meta) {
return new TileEntityCrop();
}
public Optional<TileEntityCrop> getCrop(IBlockAccess world, BlockPos pos) {
return WorldHelper.getTile(world, pos, TileEntityCrop.class);
}
@Override
public void updateTick(World world, BlockPos pos, IBlockState state, Random rand) {
if (!world.isRemote) {
this.getCrop(world, pos).ifPresent(TileEntityCrop::growthTick);
}
}
/**
* Handles right-clicks from the player (a.k.a usage).
* <br>
* When the block is right clicked, the behaviour depends on the crop, and
* what item it was clicked with.
*/
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand,
ItemStack heldItem, EnumFacing side, float hitX, float hitY, float hitZ) {
return this.getCrop(world, pos).map(crop -> crop.onCropRightClicked(player, heldItem)).orElse(false);
}
/**
* Handles left-clicks from the player (a.k.a hits).
* <br>
* When the block is left clicked, it breaks.
*/
@Override
public void onBlockClicked(World world, BlockPos pos, EntityPlayer player) {
if (!world.isRemote) {
this.getCrop(world, pos).ifPresent(crop -> crop.onCropBroken(!player.capabilities.isCreativeMode));
}
}
/**
* Handles the block being harvested by calling
* {@link #onBlockClicked(World, BlockPos pos, EntityPlayer)}.
*/
@Override
public void onBlockHarvested(World world, BlockPos pos, IBlockState state, EntityPlayer player) {
this.onBlockClicked(world, pos, player);
}
/**
* Handles the block drops. Called when the block is broken (not left
* clicked).
*/
@Override
public void dropBlockAsItemWithChance(World world, BlockPos pos, IBlockState state, float chance, int fortune) {
if (!world.isRemote) {
this.getCrop(world, pos).ifPresent(c -> c.onCropBroken(true));
}
}
/**
* Determines if bonemeal may be applied to the plant contained in the
* crops.
*
* @return if bonemeal may be applied.
*/
@Override
public boolean canGrow(World world, BlockPos pos, IBlockState state, boolean isClient) {
return this.getCrop(world, pos).map(crop -> !crop.isMature()).orElse(false);
}
/**
* Determines if bonemeal speeds up the GROWTH of the contained plant.
*
* @return false, so that we have full control over fertilizers.
*/
@Override
public boolean canUseBonemeal(World world, Random rand, BlockPos pos, IBlockState state) {
return false;
}
/**
* Increments the contained plant's GROWTH stage. Called when bonemeal is
* applied to the block.
*/
@Override
public void grow(World world, Random rand, BlockPos pos, IBlockState state) {
this.getCrop(world, pos).ifPresent(TileEntityCrop::applyBoneMeal);
}
/**
* Handles changes in the crop's neighbors.
*/
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn) {
if (!this.canBlockStay(worldIn, pos)) {
this.dropBlockAsItem(worldIn, pos, state, 0);
worldIn.removeTileEntity(pos);
worldIn.setBlockToAir(pos);
}
}
/**
* Tests to see if the crop is still on valid soil.
*
* @return if the crop is placed in a valid location.
*/
public boolean canBlockStay(IBlockAccess world, BlockPos pos) {
return GrowthRequirementHandler.isSoilValid(world, pos.down());
}
/**
* Determines if the the plant is fertile, and can grow.
*
* @return if the plant can grow.
*/
@Override
public boolean isFertile(World world, BlockPos pos) {
return this.getCrop(world, pos).map(TileEntityCrop::isFertile).orElse(false);
}
/**
* Determines if the crops contain a mature plant by checking if the
* metadata matches {@link Constants#MATURE}.
*
* @return if the crop is done growing.
*/
public boolean isMature(World world, BlockPos pos) {
return this.getCrop(world, pos).map(TileEntityCrop::isMature).orElse(false);
}
/**
* Retrieves the block's item form to be dropped when the block is broken.
*
* @return the item form of the crop.
*/
@Override
public Item getItemDropped(IBlockState state, Random rand, int fortune) {
return AgriItems.getInstance().CROPS;
}
/**
* Determines a list of what is dropped when the crops are broken.
*
* @return a list of the items to drop.
*/
@Override
public List<ItemStack> getDrops(IBlockAccess world, BlockPos pos, IBlockState state, int fortune) {
List<ItemStack> drops = new ArrayList<>();
this.getCrop(world, pos).ifPresent(c -> c.getDrops(drops::add, true));
return drops;
}
/**
* Handles the block being broken.
*/
@Override
public void breakBlock(World world, BlockPos pos, IBlockState state) {
super.breakBlock(world, pos, state);
world.removeTileEntity(pos);
}
/**
* Retrieves the item form of the block.
*
* @return the block's item form.
*/
@Override
@SideOnly(Side.CLIENT)
public ItemStack getPickBlock(IBlockState state, RayTraceResult target, World world, BlockPos pos, EntityPlayer player) {
return new ItemStack(AgriItems.getInstance().CROPS);
}
@Override
@Deprecated
@SuppressWarnings("deprecation")
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) {
return BOX;
}
@Override
@Nullable
@Deprecated
@SuppressWarnings("deprecation")
public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, World worldIn, BlockPos pos) {
return Block.NULL_AABB;
}
@Override
@Deprecated
@SideOnly(Side.CLIENT)
@SuppressWarnings("deprecation")
public AxisAlignedBB getSelectedBoundingBox(IBlockState state, World worldIn, BlockPos pos) {
return BOX.offset(pos);
}
/**
* Determines if the block is a normal block, such as cobblestone. This
* tells Minecraft if crops are not a normal block (meaning no levers can be
* placed on it, it's transparent, ...).
*
* @return false - the block is not a normal block.
*/
@Override
@SuppressWarnings("deprecation")
public boolean isOpaqueCube(IBlockState state) {
return false;
}
/**
* Determines if a side of the block should be rendered, such as one flush
* with a wall that wouldn't need rendering.
*
* @return false - all of the crop's sides need to be rendered.
*/
@Override
@SuppressWarnings("deprecation")
public boolean shouldSideBeRendered(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing side) {
return true;
}
@Override
public boolean doesSideBlockRendering(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing side) {
return false;
}
@Override
@SuppressWarnings("deprecation")
public boolean isFullCube(IBlockState state) {
return false;
}
/**
* Renders the hit effects, such as the flying particles when the block is
* hit.
*
* @return false - the block is one-shot and needs no hit particles.
*/
@Override
@SideOnly(value = Side.CLIENT)
public boolean addHitEffects(IBlockState state, World worldObj, RayTraceResult target, ParticleManager manager) {
return false;
}
/**
* Tells Minecraft if there should be destroy effects, such as particles.
*
* @return false - there are no destroy particles.
*/
@Override
@SideOnly(value = Side.CLIENT)
public boolean addDestroyEffects(World world, BlockPos pos, ParticleManager manager) {
return false;
}
/**
* Retrieves the custom renderer for the crops.
*
* @return the block's renderer.
*/
@Override
@SideOnly(Side.CLIENT)
public RenderCrop getRenderer() {
return new RenderCrop(this);
}
@Override
@SideOnly(Side.CLIENT)
public ModelResourceLocation getBlockModelResourceLocation() {
return new ModelResourceLocation(Reference.MOD_ID.toLowerCase() + ":" + getInternalName());
}
@Override
public List<String> getOreTags() {
return Collections.emptyList();
}
@Override
protected InfinityProperty[] getPropertyArray() {
return new InfinityProperty[]{};
}
@Override
public Class<? extends ItemBlock> getItemBlockClass() {
return null;
}
/**
* Retrieves the type of plant growing within the crops.
*
* @return the plant type in the crops.
*/
@Override
public EnumPlantType getPlantType(IBlockAccess world, BlockPos pos) {
return EnumPlantType.Crop;
}
@Override
public IBlockState getPlant(IBlockAccess world, BlockPos pos) {
// TODO: Fix propertycropplant
// TileEntity tile = world.getTileEntity(pos);
return world.getBlockState(pos);
}
public Optional<TileEntityCrop> getCropTile(IBlockAccess world, BlockPos pos) {
return WorldHelper.getTile(world, pos, TileEntityCrop.class);
}
@Override
public BlockRenderLayer getBlockLayer() {
return BlockRenderLayer.CUTOUT_MIPPED;
}
@Override
public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos) {
Optional<TileEntityCrop> tile = getCropTile(world, pos);
return ((IExtendedBlockState) state)
.withProperty(AgriProperties.CROP_PLANT, tile.flatMap(TileEntityCrop::getPlant).orElse(null))
.withProperty(AgriProperties.GROWTH_STAGE, tile.map(TileEntityCrop::getGrowthStage).orElse(0))
.withProperty(AgriProperties.CROSS_CROP, tile.map(TileEntityCrop::isCrossCrop).orElse(false));
}
@Override
public IUnlistedProperty[] getUnlistedPropertyArray() {
return new IUnlistedProperty[]{
AgriProperties.CROP_PLANT,
AgriProperties.GROWTH_STAGE,
AgriProperties.CROSS_CROP
};
}
}