package com.pam.harvestcraft.worldgen;
import java.util.Random;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.block.Block;
import net.minecraft.block.BlockCocoa;
import net.minecraft.block.BlockSapling;
import net.minecraft.block.BlockVine;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.WorldGenAbstractTree;
public class FruitTreeGen extends WorldGenAbstractTree {
private final int minTreeHeight;
private final boolean vinesGrow;
private final IBlockState metaWood;
private final IBlockState metaLeaves;
private final IBlockState fruitType;
public FruitTreeGen(int minTreeHeight, IBlockState metaWood, IBlockState metaLeaves, boolean doVinesGrow, IBlockState fruitType) {
super(true);
this.minTreeHeight = minTreeHeight;
this.metaWood = metaWood;
this.metaLeaves = metaLeaves;
this.vinesGrow = doVinesGrow;
this.fruitType = fruitType;
}
@Override
@ParametersAreNonnullByDefault
public boolean generate(World worldIn, Random rand, BlockPos blockPos) {
final BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
int treeHeight = rand.nextInt(3) + this.minTreeHeight;
boolean canGenerate = true;
int treeTopPos = blockPos.getY() + treeHeight;
// Check if tree would fit and can be generated
if (blockPos.getY() >= 1 && treeTopPos <= 255) {
for (int iPosY = blockPos.getY(); iPosY <= treeTopPos + 1; ++iPosY) {
int k = 1;
if (iPosY == blockPos.getY()) {
k = 0;
}
if (iPosY >= treeTopPos - 1) {
k = 2;
}
for (int iPosX = blockPos.getX() - k, halflength = blockPos.getX() + k; iPosX <= halflength + k && canGenerate; ++iPosX) {
for (int iPosZ = blockPos.getZ() - k, halfLength = blockPos.getZ() + k; iPosZ <= halfLength + k && canGenerate; ++iPosZ) {
if (iPosY >= 0 && iPosY < 256) {
if (!this.isReplaceable(worldIn, mutableBlockPos.setPos(iPosX, iPosY, iPosZ))) {
canGenerate = false;
}
} else {
canGenerate = false;
}
}
}
}
if (!canGenerate) {
return false;
} else {
BlockPos down = blockPos.down();
IBlockState blockState = worldIn.getBlockState(down);
Block block = blockState.getBlock();
boolean isSoil = block.canSustainPlant(blockState, worldIn, down, EnumFacing.UP, (BlockSapling) Blocks.SAPLING);
if (isSoil && treeTopPos + 1 < 256) {
block.onPlantGrow(blockState, worldIn, down, blockPos);
// Generate leaves and fruits
for (int iPosY = treeTopPos - 3; iPosY <= treeTopPos; ++iPosY) {
int distanceToTop = iPosY - treeTopPos;
int margin = 1 - distanceToTop / 2;
for (int xStart = blockPos.getX() - margin, xEnd = blockPos.getX() + margin; xStart <= xEnd; ++xStart) {
int currentMarginX = Math.abs(xStart - blockPos.getX());
for (int zStart = blockPos.getZ() - margin, zEnd = blockPos.getZ() + margin; zStart <= zEnd; ++zStart) {
int currentMarginZ = Math.abs(zStart - blockPos.getZ());
if (currentMarginX != margin || currentMarginZ != margin || rand.nextInt(2) != 0 && distanceToTop != 0) {
BlockPos leavesBlockPos = new BlockPos(xStart, iPosY, zStart);
IBlockState leavesBlockState = worldIn.getBlockState(leavesBlockPos);
Block leavesBlock = worldIn.getBlockState(leavesBlockPos).getBlock();
if (leavesBlock.isAir(leavesBlockState, worldIn, leavesBlockPos) || leavesBlock.isLeaves(leavesBlockState, worldIn, leavesBlockPos)
|| leavesBlock.getMaterial(leavesBlockState) == Material.VINE) {
this.setBlockAndNotifyAdequately(worldIn, leavesBlockPos, this.metaLeaves);
BlockPos fruitBlockPos = new BlockPos(xStart, iPosY - 1, zStart);
BlockPos blockBelowFruitPos = new BlockPos(xStart, iPosY - 2, zStart);
if (worldIn.isAirBlock(fruitBlockPos)) {
if (worldIn.isAirBlock(blockBelowFruitPos) && iPosY > 2) {
if (rand.nextInt(4) == 0) {
this.setBlockAndNotifyAdequately(worldIn, fruitBlockPos, this.fruitType);
}
}
}
}
}
}
}
}
// Create log (and vines)
for (int i = 0; i < treeHeight; ++i) {
BlockPos upN = blockPos.up(i);
IBlockState blockStateUp = worldIn.getBlockState(upN);
Block blockUp = blockStateUp.getBlock();
if (blockUp.isAir(blockStateUp, worldIn, upN) || blockUp.isLeaves(blockStateUp, worldIn, upN) ||
blockUp == fruitType.getBlock()
|| blockUp.getMaterial(blockStateUp) == Material.VINE) {
this.setBlockAndNotifyAdequately(worldIn, blockPos.up(i), this.metaWood);
if (this.vinesGrow && i > 0) {
if (rand.nextInt(3) > 0 && worldIn.isAirBlock(blockPos.add(-1, i, 0))) {
this.setBlockVine(worldIn, blockPos.add(-1, i, 0), BlockVine.EAST);
}
if (rand.nextInt(3) > 0 && worldIn.isAirBlock(blockPos.add(1, i, 0))) {
this.setBlockVine(worldIn, blockPos.add(1, i, 0), BlockVine.WEST);
}
if (rand.nextInt(3) > 0 && worldIn.isAirBlock(blockPos.add(0, i, -1))) {
this.setBlockVine(worldIn, blockPos.add(0, i, -1), BlockVine.SOUTH);
}
if (rand.nextInt(3) > 0 && worldIn.isAirBlock(blockPos.add(0, i, 1))) {
this.setBlockVine(worldIn, blockPos.add(0, i, 1), BlockVine.NORTH);
}
}
}
}
// Create vines
if (this.vinesGrow) {
for (int yBottom = treeTopPos - 3; yBottom <= treeTopPos; ++yBottom) {
int distanceToTop = yBottom - treeTopPos;
int k = 2 - distanceToTop / 2;
for (int xStart = blockPos.getX() - k, xEnd = blockPos.getX() + k; xStart <= xEnd; ++xStart) {
for (int zStart = blockPos.getZ() - k, zEnd = blockPos.getZ() + k; zStart <= zEnd; ++zStart) {
mutableBlockPos.setPos(xStart, yBottom, zStart);
if (worldIn.getBlockState(mutableBlockPos).getBlock().isLeaves(
worldIn.getBlockState(mutableBlockPos), worldIn, mutableBlockPos)) {
BlockPos posWest = mutableBlockPos.west();
BlockPos posEast = mutableBlockPos.east();
BlockPos posNorth = mutableBlockPos.north();
BlockPos posSouth = mutableBlockPos.south();
if (rand.nextInt(4) == 0 && worldIn.getBlockState(posWest).getBlock().isAir(
worldIn.getBlockState(posWest), worldIn, posWest)) {
this.setVines(worldIn, posWest, BlockVine.EAST);
}
if (rand.nextInt(4) == 0 && worldIn.getBlockState(posEast).getBlock()
.isAir(worldIn.getBlockState(posEast), worldIn, posEast)) {
this.setVines(worldIn, posEast, BlockVine.WEST);
}
if (rand.nextInt(4) == 0 && worldIn.getBlockState(posNorth).getBlock().isAir(
worldIn.getBlockState(posNorth), worldIn, posNorth)) {
this.setVines(worldIn, posNorth, BlockVine.SOUTH);
}
if (rand.nextInt(4) == 0 && worldIn.getBlockState(posSouth).getBlock().isAir(
worldIn.getBlockState(posSouth), worldIn, posSouth)) {
this.setVines(worldIn, posSouth, BlockVine.NORTH);
}
}
}
}
}
if (rand.nextInt(5) == 0 && treeHeight > 5) {
for (int i = 0; i < 2; ++i) {
for (EnumFacing enumfacing : EnumFacing.Plane.HORIZONTAL) {
if (rand.nextInt(4 - i) == 0) {
EnumFacing oppositeFacing = enumfacing.getOpposite();
this.setBlockCocoa(worldIn, rand.nextInt(3), blockPos.add(oppositeFacing.getFrontOffsetX(), treeHeight - 5 + i, oppositeFacing.getFrontOffsetZ()), enumfacing);
}
}
}
}
}
return true;
} else {
return false;
}
}
} else {
return false;
}
}
private void setBlockCocoa(World world, int age, BlockPos blockPos, EnumFacing facing) {
this.setBlockAndNotifyAdequately(world, blockPos, Blocks.COCOA.getDefaultState().withProperty(BlockCocoa.AGE, age).withProperty(BlockCocoa.FACING, facing));
}
private void setBlockVine(World world, BlockPos blockPos, PropertyBool propertyBool) {
this.setBlockAndNotifyAdequately(world, blockPos, Blocks.VINE.getDefaultState().withProperty(propertyBool, true));
}
private void setVines(World world, BlockPos blockPos, PropertyBool propertyBool) {
this.setBlockVine(world, blockPos, propertyBool);
int i = 4;
for (blockPos = blockPos.down(); world.getBlockState(blockPos).getBlock().isAir(world.getBlockState(blockPos), world, blockPos) && i > 0; --i) {
this.setBlockVine(world, blockPos, propertyBool);
blockPos = blockPos.down();
}
}
}