package joshie.harvest.crops.block; import joshie.harvest.api.HFApi; import joshie.harvest.api.animals.AnimalFoodType; import joshie.harvest.api.animals.AnimalStats; import joshie.harvest.api.animals.IAnimalFeeder; import joshie.harvest.api.crops.Crop; import joshie.harvest.api.crops.IStateHandler.PlantSection; import joshie.harvest.api.trees.Tree; import joshie.harvest.core.base.block.BlockHFEnum; import joshie.harvest.core.base.item.ItemBlockHF; import joshie.harvest.core.entity.EntityBasket; import joshie.harvest.core.helpers.EntityHelper; import joshie.harvest.core.lib.HFModInfo; import joshie.harvest.crops.CropData; import joshie.harvest.crops.CropHelper; import joshie.harvest.crops.HFCrops; import joshie.harvest.crops.block.BlockHFCrops.CropType; import joshie.harvest.crops.tile.TileCrop; import joshie.harvest.crops.tile.TileWithered; 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.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.*; 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.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.common.EnumPlantType; import net.minecraftforge.common.IPlantable; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Locale; import java.util.Random; import static joshie.harvest.api.crops.IStateHandler.PlantSection.BOTTOM; import static joshie.harvest.api.crops.IStateHandler.PlantSection.TOP; import static joshie.harvest.core.helpers.MCServerHelper.markTileForUpdate; import static joshie.harvest.crops.CropHelper.harvestCrop; import static joshie.harvest.crops.block.BlockHFCrops.CropType.*; public class BlockHFCrops extends BlockHFEnum<BlockHFCrops, CropType> implements IPlantable, IGrowable, IAnimalFeeder { public enum CropType implements IStringSerializable { FRESH(BOTTOM), WITHERED(BOTTOM), FRESH_DOUBLE(TOP), WITHERED_DOUBLE(TOP); private final PlantSection section; CropType(PlantSection section) { this.section = section; } @Override public String getName() { return toString().toLowerCase(Locale.ENGLISH); } public boolean isWithered() { return this == WITHERED || this == WITHERED_DOUBLE; } public PlantSection getSection() { return section; } } public static final AxisAlignedBB CROP_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.5D, 1.0D); public BlockHFCrops() { super(Material.PLANTS, CropType.class, null); setSoundType(SoundType.GROUND); if (!HFCrops.GROWS_DAILY) setTickRandomly(true); disableStats(); } @Override public int getMetaFromState(IBlockState state) { if (state.getPropertyNames().contains(property)) return (state.getValue(property)).ordinal(); else return 0; } @Override public boolean isOpaqueCube(IBlockState state) { return false; } @Override public boolean isFullCube(IBlockState state) { return false; } @SideOnly(Side.CLIENT) public BlockRenderLayer getBlockLayer() { return BlockRenderLayer.CUTOUT; } //Only called if crops are set to tick randomly @Override public void updateTick(World world, BlockPos pos, IBlockState state, Random rand) { if (!HFCrops.GROWS_DAILY && !world.isRemote) { CropType stage = getEnumFromState(state); if (stage == CropType.WITHERED) return; //If withered do nothing if (world.getLightFromNeighbors(pos.up()) >= 9) { if (rand.nextInt(20) == 0) { //We are Growing! grow(world, rand, pos, state); } } } } @SuppressWarnings("deprecation") @Override public float getBlockHardness(IBlockState state, World world, BlockPos pos) { CropType type = getEnumFromState(state); if (type.isWithered()) return 0.5F; else return isWood(world, pos) ? 2F : 0.1F; } @Override public boolean isWood(IBlockAccess world, BlockPos pos) { CropData data = CropHelper.getCropDataAt(world, pos); if (data != null && data.getCrop() instanceof Tree) { if (data.getStage() >= ((Tree)data.getCrop()).getStagesToMaturity()) return true; } return false; } @Override @Nonnull @SuppressWarnings("deprecation") public SoundType getSoundType(IBlockState state, World world, BlockPos pos, @Nullable Entity entity) { CropData data = CropHelper.getCropDataAt(world, pos); return data != null && data.getCrop() instanceof Tree ? SoundType.WOOD : getSoundType(); } public static PlantSection getSection(IBlockState state) { if (state.getBlock() != HFCrops.CROPS) return null; int stage = state.getBlock().getMetaFromState(state); //Can't get the Enum from state, because this method is static. PlantSection section = BOTTOM; if (stage == CropType.WITHERED_DOUBLE.ordinal() || stage == CropType.FRESH_DOUBLE.ordinal()) { section = PlantSection.TOP; } return section; } public static boolean isWithered(IBlockState state) { int stage = state.getBlock().getMetaFromState(state); //Can't get the Enum from state, because this method is static. return stage == CropType.WITHERED.ordinal() || stage == CropType.WITHERED_DOUBLE.ordinal(); } @Override public Item getItemDropped(IBlockState state, Random rand, int fortune) { return null; } @SuppressWarnings("unchecked") private boolean canStay(World world, BlockPos pos) { CropData data = CropHelper.getCropDataAt(world, pos); if (data != null) { Crop crop = data.getCrop(); if (crop.getGrowthHandler() != null) { IBlockState down = world.getBlockState(pos.down()); return down.getBlock() == this || down.getBlock().canSustainPlant(down, world, pos, EnumFacing.UP, crop); } } return false; } private int getXMinus(EnumFacing facing, int x) { return facing.getAxis() == Axis.Z ? x - 1 : x; } private int getXPlus(EnumFacing facing, int x) { return facing.getAxis() == Axis.Z ? x + 1 : x; } private int getZMinus(EnumFacing facing, int z) { return facing.getAxis() == Axis.X ? z - 1 : z; } private int getZPlus(EnumFacing facing, int z) { return facing.getAxis() == Axis.X ? z + 1 : z; } @Override public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, ItemStack heldItem, EnumFacing side, float hitX, float hitY, float hitZ) { CropType stage = getEnumFromState(state); if (stage == CropType.WITHERED || stage == CropType.WITHERED_DOUBLE) return false; //If Withered with suck! if (player.isSneaking()) return false; else { PlantSection section = getSection(state); CropData data = CropHelper.getCropDataAt(world, pos); if (data == null || data.getCrop().requiresSickle() || data.getCrop() instanceof Tree) { return false; } else { EnumFacing front = EntityHelper.getFacingFromEntity(player); if (EntityBasket.isWearingBasket(player)) { for (int x2 = getXMinus(front, pos.getX()); x2 <= getXPlus(front, pos.getX()); x2++) { for (int z2 = getZMinus(front, pos.getZ()); z2 <= getZPlus(front, pos.getZ()); z2++) { BlockPos position = new BlockPos(x2, pos.getY(), z2); IBlockState theState = world.getBlockState(position); PlantSection theSection = BlockHFCrops.getSection(theState); CropData theData = CropHelper.getCropDataAt(world, position); if (!(theData == null || theData.getCrop().requiresSickle() || theData.getCrop() instanceof Tree)) { if (theSection == BOTTOM) harvestCrop(player, world, position); else harvestCrop(player, world, position.down()); } } } } if (section == BOTTOM) { return harvestCrop(player, world, pos); } else return harvestCrop(player, world, pos.down()); } } } @SuppressWarnings("deprecation") @Override public void neighborChanged(IBlockState state, World world, BlockPos pos, Block neighborBlock) { if (!world.isRemote) { if (!canStay(world, pos)) { world.setBlockToAir(pos); } } } @SuppressWarnings("deprecation") @Override public float getPlayerRelativeBlockHardness(IBlockState state, @Nonnull EntityPlayer player, @Nonnull World world, @Nonnull BlockPos pos) { if (isWood(world, pos)) return super.getPlayerRelativeBlockHardness(state, player, world, pos); float hardness = state.getBlockHardness(world, pos); if (hardness < 0.0F) { return 0.0F; } ItemStack held = player.getHeldItemMainhand(); if (held != null && HFApi.crops.isSickle(held)) { return player.getDigSpeed(state, pos) / hardness / 10F; } else { return player.getDigSpeed(state, pos) / hardness / 100F; } } @Override public boolean removedByPlayer(@Nonnull IBlockState state, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EntityPlayer player, boolean willHarvest) { CropType stage = getEnumFromState(state); if (stage == CropType.WITHERED || stage == CropType.WITHERED_DOUBLE) return world.setBlockToAir(pos); //JUST KILL IT IF WITHERED PlantSection section = getSection(state); CropData data = CropHelper.getCropDataAt(world, pos); if (data == null) { return super.removedByPlayer(state, world, pos, player, willHarvest); } Crop crop = data.getCrop(); int originalStage = data.getStage(); boolean isSickle = player.getHeldItemMainhand() != null && HFApi.crops.isSickle(player.getHeldItemMainhand()); if (isSickle || !crop.requiresSickle()) { if (section == BOTTOM) { harvestCrop(player, world, pos); } else harvestCrop(player, world, pos.down()); } if (crop.isCurrentlyDouble(data.getStage())) { if (section == PlantSection.BOTTOM) { IBlockState stateUp = world.getBlockState(pos.up()); if (stateUp.getBlock() == this) { CropHelper.onBottomBroken(pos.up(), getActualState(stateUp, world, pos.up())); } } } if (isSickle && crop.getMinimumCut() != 0 && crop.requiresSickle() && originalStage >= crop.getMinimumCut()) { return data.markSafe(world, pos, section); } return world.setBlockToAir(pos); } @Override public void breakBlock(@Nonnull World world, @Nonnull BlockPos pos, @Nonnull IBlockState state) { CropType stage = getEnumFromState(state); if (stage == FRESH || stage == CropType.WITHERED) { CropData data = CropHelper.getCropDataAt(world, pos); if (data == null || data.isClearable()) { if (world.getBlockState(pos.up()).getBlock() == this) { CropType above = getEnumFromState(world.getBlockState(pos.up())); if (above == FRESH_DOUBLE || above == WITHERED_DOUBLE) { world.setBlockToAir(pos.up()); } } } else { if (world.getBlockState(pos.up()).getBlock() == this && !data.getCrop().isCurrentlyDouble(data.getStage())) data.markSafe(world, pos.up(), PlantSection.TOP); HFApi.crops.plantCrop(null, world, pos, data.getCrop(), data.getCrop().getRegrowStage()); } } else if (stage == CropType.FRESH_DOUBLE || stage == CropType.WITHERED_DOUBLE) { CropData data = CropHelper.getCropDataAt(world, pos.down()); if (data == null || data.isClearable()) { world.setBlockToAir(pos.down()); } } super.breakBlock(world, pos, state); //Break them crops } @Override @SuppressWarnings("deprecation, unchecked") @Nonnull public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos) { CropType stage = getEnumFromState(state); CropData data = CropHelper.getCropDataAt(world, pos); return data != null ? data.getCrop().getStateHandler().getBoundingBox(world, pos, stage.getSection(), data.getCrop(), data.getStage(), stage.isWithered()) : CROP_AABB; } @Override @SuppressWarnings("deprecation, unchecked") public AxisAlignedBB getCollisionBoundingBox(IBlockState state, @Nonnull World world, @Nonnull BlockPos pos) { CropType stage = getEnumFromState(state); CropData data = CropHelper.getCropDataAt(world, pos); return data != null ? data.getCrop().getStateHandler().getCollisionBoundingBox(world, pos, stage.getSection(), data.getCrop(), data.getStage(), stage.isWithered()) : NULL_AABB; } @Override @Nonnull public ItemStack getPickBlock(@Nonnull IBlockState state, RayTraceResult target, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player) { if (getEnumFromState(state) == CropType.WITHERED) return new ItemStack(Blocks.DEADBUSH); //It's Dead soo??? CropData data = CropHelper.getCropDataAt(world, pos); return data == null ? new ItemStack(Blocks.DEADBUSH) : HFCrops.SEEDS.getStackFromCrop(data.getCrop()); } @Override @SuppressWarnings("deprecation, unchecked") @Nonnull public IBlockState getActualState(@Nonnull IBlockState state, IBlockAccess world, BlockPos pos) { CropType stage = getEnumFromState(state); TileWithered crop = CropHelper.getTile(world, pos, stage.getSection()); if (stage.getSection() == PlantSection.TOP && crop == null) { IBlockState theState = CropHelper.getTempState(pos); return theState == null ? Blocks.GRASS.getDefaultState(): theState; } if (crop != null) return crop.getData().getCrop().getStateHandler().getState(world, pos, stage.getSection(), crop.getData().getCrop(), crop.getData().getStage(), stage.isWithered()); else return Blocks.DEADBUSH.getDefaultState(); } @Override public EnumPlantType getPlantType(IBlockAccess world, BlockPos pos) { CropData data = CropHelper.getCropDataAt(world, pos); return data == null ? EnumPlantType.Crop : data.getCrop().getPlantType(); } @Override public IBlockState getPlant(IBlockAccess world, BlockPos pos) { return getActualState(world.getBlockState(pos.down()), world, pos.down()); } //Can Apply Bonemeal (Not Fully Grown) @Override @SuppressWarnings("unchecked") public boolean canGrow(@Nonnull World world, @Nonnull BlockPos pos, @Nonnull IBlockState state, boolean isClient) { if (getEnumFromState(state) == CropType.WITHERED) return false; //It's dead it can't grow... if (HFCrops.ENABLE_BONEMEAL) { if (HFCrops.SEASONAL_BONEMEAL) { CropData data = CropHelper.getCropDataAt(world, pos); return data != null && data.getCrop().getGrowthHandler().canGrow(world, pos, data.getCrop()) && canGrow(world, pos, state); } else return canGrow(world, pos, state); } else return false; } private boolean canGrow(World world, BlockPos pos, IBlockState state) { TileWithered crop = CropHelper.getTile(world, pos, getSection(state)); return crop != null && crop.getData().getStage() < crop.getData().getCrop().getStages(); } /* Only called server side **/ //Whether the bonemeal has been used and we should call the function below to make the plant grow @Override public boolean canUseBonemeal(@Nonnull World world, @Nonnull Random rand, @Nonnull BlockPos pos, @Nonnull IBlockState state) { return true; } /* Only called server side **/ //Apply the bonemeal and grow! @Override public void grow(@Nonnull World world, @Nonnull Random rand, @Nonnull BlockPos pos, @Nonnull IBlockState state) { PlantSection section = getSection(state); TileWithered crop = CropHelper.getTile(world, pos, section); if (crop != null) { crop.getData().grow(world, section == BOTTOM ? pos: pos.down()); crop.saveAndRefresh(); markTileForUpdate(crop); } } @Override @SuppressWarnings("deprecation") public boolean feedAnimal(AnimalStats stats, World world, BlockPos pos, IBlockState state, boolean simulate) { if (HFApi.animals.canAnimalEatFoodType(stats, AnimalFoodType.GRASS)) { CropData data = CropHelper.getCropDataAt(world, pos); if (data != null) { if (data.getCrop() == HFCrops.GRASS) { int stage = data.getStage(); if (stage > 5) { if (simulate) return true; HFApi.crops.plantCrop(null, world, pos, data.getCrop(), stage - 5); return true; } } } } return false; } @Override public boolean hasTileEntity(IBlockState state) { return getEnumFromState(state).section == BOTTOM; } @Override @Nonnull public TileEntity createTileEntity(@Nonnull World world, @Nonnull IBlockState state) { return !getEnumFromState(state).isWithered() ? new TileCrop() : new TileWithered(); } @Override public ItemBlockHF getItemBlock() { return null; } @SideOnly(Side.CLIENT) @Override public boolean addHitEffects(IBlockState state, World worldObj, RayTraceResult target, ParticleManager manager) { return true; } @Override @SideOnly(Side.CLIENT) public void registerModels(Item item, String name) { for (int i = 0; i < values.length; i++) { ModelLoader.setCustomModelResourceLocation(item, i, new ModelResourceLocation(new ResourceLocation(HFModInfo.MODID, property.getName() + "_" + getEnumFromMeta(i).getName()), "inventory")); } } }