Re-added bayou trees

This commit is contained in:
Adubbz 2019-02-24 21:32:12 +11:00
parent d16d851619
commit 890f7308db
3 changed files with 358 additions and 1 deletions

View File

@ -9,6 +9,7 @@ package biomesoplenty.common.world.gen.feature;
import biomesoplenty.api.block.BOPBlocks;
import biomesoplenty.common.world.gen.feature.tree.BasicTreeFeature;
import biomesoplenty.common.world.gen.feature.tree.BayouTreeFeature;
import biomesoplenty.common.world.gen.feature.tree.TaigaTreeFeature;
import net.minecraft.init.Blocks;
import net.minecraft.world.gen.feature.AbstractTreeFeature;
@ -19,6 +20,7 @@ public class BOPBiomeFeatures
{
public static final AbstractTreeFeature<NoFeatureConfig> CONIFEROUS_TREE = new TaigaTreeFeature.Builder().log(BOPBlocks.fir_log.getDefaultState()).leaves(BOPBlocks.fir_leaves.getDefaultState()).minHeight(5).maxHeight(28).create();
public static final AbstractTreeFeature<NoFeatureConfig> OAK_TREE = new BasicTreeFeature.Builder().create();
public static final AbstractTreeFeature<NoFeatureConfig> BAYOU_TREE = new BayouTreeFeature.Builder().create();
public static final SurfaceBuilderConfig LOAMY_GRASS_DIRT_GRAVEL_SURFACE = new SurfaceBuilderConfig(BOPBlocks.loamy_grass_block.getDefaultState(), BOPBlocks.loamy_dirt.getDefaultState(), Blocks.GRAVEL.getDefaultState());
}

View File

@ -45,7 +45,10 @@ public class BasicTreeFeature extends TreeFeatureBase
public Builder()
{
this.placeOn = (world, pos) -> true;
this.placeOn = (world, pos) ->
{
return world.getBlockState(pos).isSolid();
};
this.replace = (world, pos) ->
{
Material mat = world.getBlockState(pos).getMaterial();

View File

@ -0,0 +1,352 @@
/*******************************************************************************
* Copyright 2014-2019, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.common.world.gen.feature.tree;
import biomesoplenty.api.block.BOPBlocks;
import biomesoplenty.common.util.block.IBlockPosQuery;
import net.minecraft.block.Block;
import net.minecraft.block.BlockCocoa;
import net.minecraft.block.BlockVine;
import net.minecraft.block.material.Material;
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.IWorld;
import java.util.Random;
import java.util.Set;
public class BayouTreeFeature extends TreeFeatureBase
{
public static class Builder extends BuilderBase<BayouTreeFeature.Builder, BayouTreeFeature>
{
protected int leafLayers;
protected int leavesOffset;
protected int maxLeavesRadius;
protected int leavesLayerHeight;
protected IBlockPosQuery placeVinesOn;
protected float hangingChance;
public Builder leafLayers(int a) {this.leafLayers = a; return this;}
public Builder leavesOffset(int a) {this.leavesOffset = a; return this;}
public Builder leavesLayerHeight(int a) {this.leavesLayerHeight = a; return this;}
public Builder maxLeavesRadius(int a) {this.maxLeavesRadius = a; return this;}
public Builder placeVinesOn(IBlockPosQuery a) {this.placeVinesOn = a; return this;}
public Builder hangingChance(float a) {this.hangingChance = a; return this;}
public Builder()
{
this.placeOn = (world, pos) ->
{
return world.getBlockState(pos).isSolid();
};
this.replace = (world, pos) ->
{
Material mat = world.getBlockState(pos).getMaterial();
return mat == Material.AIR || mat == Material.LEAVES || mat == Material.VINE || mat == Material.WATER;
};
this.log = BOPBlocks.willow_log.getDefaultState();
this.leaves = BOPBlocks.willow_leaves.getDefaultState();
this.vine = BOPBlocks.willow_vine.getDefaultState();
this.minHeight = 12;
this.maxHeight = 20;
this.updateNeighbours = false;
this.leafLayers = 4;
this.leavesOffset = 0;
this.maxLeavesRadius = 1;
this.leavesLayerHeight = 2;
this.placeVinesOn = (world, pos) ->
{
Material mat = world.getBlockState(pos).getMaterial();
return mat == Material.AIR;
};
this.hangingChance = 0.0F;
}
@Override
public BayouTreeFeature create()
{
return new BayouTreeFeature(this.updateNeighbours, this.placeOn, this.replace, this.log, this.leaves, this.altLeaves, this.vine, this.hanging, this.trunkFruit, this.minHeight, this.maxHeight, this.leafLayers, this.leavesOffset, this.maxLeavesRadius, this.leavesLayerHeight, this.placeVinesOn, this.hangingChance);
}
}
private int leafLayers;
private int leavesOffset;
private int maxLeavesRadius;
private int leavesLayerHeight;
private IBlockPosQuery placeVinesOn;
private float hangingChance;
protected BayouTreeFeature(boolean notify, IBlockPosQuery placeOn, IBlockPosQuery replace, IBlockState log,
IBlockState leaves, IBlockState altLeaves, IBlockState vine, IBlockState hanging, IBlockState trunkFruit,
int minHeight, int maxHeight, int leafLayers, int leavesOffset, int maxLeavesRadius, int leavesLayerHeight,
IBlockPosQuery placeVinesOn, float hangingChance)
{
super(notify, placeOn, replace, log, leaves, altLeaves, vine, hanging, trunkFruit, minHeight, maxHeight);
this.leafLayers = leafLayers;
this.leavesOffset = leavesOffset;
this.maxLeavesRadius = maxLeavesRadius;
this.leavesLayerHeight = leavesLayerHeight;
this.placeVinesOn = placeVinesOn;
this.hangingChance = hangingChance;
}
@Override
protected boolean place(Set<BlockPos> changedBlocks, IWorld world, Random random, BlockPos pos)
{
int height = random.nextInt(this.maxHeight - this.minHeight) + this.minHeight;
boolean hasSpace = true;
//Generate only if we are above the lowest bedrock level (1) and reach less than the world height
//There must be a gap of 1 between the top leaf block and the world height
if (pos.getY() >= 1 && pos.getY() + height + 1 <= 256)
{
int radius;
for (int y = pos.getY(); y <= pos.getY() + 1 + height; y++)
{
radius = 1;
//Don't check for space on the first level, if we are a sapling then there will
//already be a block here (the sapling itself)
if (y == pos.getY())
{
radius = 0;
}
//At and above the top log block, require a radius of 2 to be empty
if (y >= pos.getY() + 1 + height - 2)
{
radius = 2;
}
for (int x = pos.getX() - radius; x <= pos.getX() + radius && hasSpace; ++x)
{
for (int z = pos.getZ() - radius; z <= pos.getZ() + radius && hasSpace; ++z)
{
if (y < 0 || y > 256)
{
hasSpace = false;
}
}
}
}
if (!hasSpace)
{
return false;
}
else
{
BlockPos soilPos = pos.down();
Block soil = world.getBlockState(soilPos).getBlock();
if (this.placeOn.matches(world, soilPos) && pos.getY() < 256 - height - 1)
{
soil.onPlantGrow(world.getBlockState(soilPos), world, soilPos, pos);
int leavesLayers = (this.leafLayers - 1);
//Generates leaves at the top of the tree, going one block above the top log (<= rather than <)
for (int y = pos.getY() + height - leavesLayers; y <= pos.getY() + height; y++)
{
//Determines the distance from the top of the tree as a negative number
int currentLayer = y - (pos.getY() + height);
//Uses integer division truncation (-3 / 2 = -1, -2 / 2 = -1) to reduce
//the radius closer to the top of the tree. (2, 2, 1, 1)
int leavesRadius = this.maxLeavesRadius - currentLayer / this.leavesLayerHeight;
for (int x = pos.getX() - leavesRadius; x <= pos.getX() + leavesRadius; x++)
{
int xDiff = x - pos.getX();
for (int z = pos.getZ() - leavesRadius; z <= pos.getZ() + leavesRadius; ++z)
{
int zDiff = z - pos.getZ();
//Randomly prevent the generation of leaves on the corners of each layer
//If the layer is the top layer, never generate the corners
if (Math.abs(xDiff) != leavesRadius || Math.abs(zDiff) != leavesRadius || random.nextInt(2) != 0 && currentLayer != 0)
{
BlockPos leavesPos = new BlockPos(x, y, z);
if (this.replace.matches(world, leavesPos))
{
if (this.altLeaves != Blocks.AIR.getDefaultState())
{
if (random.nextInt(4) == 0)
{
this.setAltLeaves(world, leavesPos);
}
else
{
this.setLeaves(world, leavesPos);
}
}
else
{
this.setLeaves(world, leavesPos);
}
}
}
}
}
}
this.generateTrunk(changedBlocks, world, pos, height);
if (this.vine != Blocks.AIR.getDefaultState())
{
for (int y = pos.getY() - leavesLayers + height; y <= pos.getY() + height; y++)
{
//Determines the distance from the top of the tree as a negative number
int currentLayer = y - (pos.getY() + height);
//Uses integer division truncation (-3 / 2 = -1, -2 / 2 = -1) to reduce
//the radius closer to the top of the tree. (3, 3, 2, 2)
int leavesRadius = (this.maxLeavesRadius + this.leavesOffset) - currentLayer / this.leavesLayerHeight;
for (int x = pos.getX() - leavesRadius; x <= pos.getX() + leavesRadius; x++)
{
for (int z = pos.getZ() - leavesRadius; z <= pos.getZ() + leavesRadius; z++)
{
BlockPos blockpos3 = new BlockPos(x, y, z);
//Surround leaves on the edge of the tree with vines and extend them downwards
if (world.getBlockState(blockpos3).getMaterial() == Material.LEAVES)
{
BlockPos westPos = blockpos3.west();
BlockPos eastPos = blockpos3.east();
BlockPos northPos = blockpos3.north();
BlockPos southPos = blockpos3.south();
if (random.nextInt(4) == 0 && this.placeVinesOn.matches(world, westPos))
{
this.extendVines(world, westPos, EnumFacing.EAST);
}
if (random.nextInt(4) == 0 && this.placeVinesOn.matches(world, eastPos))
{
this.extendVines(world, eastPos, EnumFacing.WEST);
}
if (random.nextInt(4) == 0 && this.placeVinesOn.matches(world, northPos))
{
this.extendVines(world, northPos, EnumFacing.SOUTH);
}
if (random.nextInt(4) == 0 && this.placeVinesOn.matches(world, southPos))
{
this.extendVines(world, southPos, EnumFacing.NORTH);
}
}
}
}
}
}
//Generate fruit or any other blocks that may hang off of the tree
if (this.hanging != Blocks.AIR.getDefaultState()) this.generateHanging(world, pos, random, height);
if (this.trunkFruit != Blocks.AIR.getDefaultState())
{
if (random.nextInt(5) == 0 && height > 5)
{
for (int l3 = 0; l3 < 2; ++l3)
{
for (EnumFacing enumfacing : EnumFacing.Plane.HORIZONTAL)
{
if (random.nextInt(4 - l3) == 0)
{
EnumFacing enumfacing1 = enumfacing.getOpposite();
this.generateTrunkFruit(world, random.nextInt(3), pos.add(enumfacing1.getXOffset(), height - 5 + l3, enumfacing1.getZOffset()), enumfacing);
}
}
}
}
}
return true;
}
else
{
return false;
}
}
}
else
{
return false;
}
}
protected void generateTrunk(Set<BlockPos> changedBlocks, IWorld world, BlockPos start, int height)
{
//Create the trunk from the bottom up, using < to ensure it is covered with one layer of leaves
for (int layer = 0; layer < height; ++layer)
{
BlockPos blockpos2 = start.up(layer);
if (this.replace.matches(world, blockpos2))
{
this.setLog(changedBlocks, world, start.up(layer));
}
}
}
protected void generateHanging(IWorld world, BlockPos start, Random rand, int height)
{
//Generate below the bottom layer of leaves
int y = start.getY() + (height - this.leafLayers);
for (int x = start.getX() - (maxLeavesRadius + 1); x <= start.getX() + (maxLeavesRadius + 1); x++)
{
for (int z = start.getZ() - (maxLeavesRadius + 1); z <= start.getZ() + (maxLeavesRadius + 1); z++)
{
BlockPos hangingPos = new BlockPos(x, y, z);
if (!world.isAirBlock(hangingPos.up()) && (world.isAirBlock(hangingPos)) && rand.nextFloat() <= this.hangingChance)
{
this.setHanging(world, hangingPos);
}
}
}
}
private void generateTrunkFruit(IWorld world, int age, BlockPos pos, EnumFacing direction)
{
if (this.trunkFruit == Blocks.COCOA.getDefaultState())
{
this.setBlockState(world, pos, this.trunkFruit.with(BlockCocoa.AGE, Integer.valueOf(age)).with(BlockCocoa.HORIZONTAL_FACING, direction));
}
else
{
this.setBlockState(world, pos, this.trunkFruit.with(BlockCocoa.HORIZONTAL_FACING, direction));
}
}
private IBlockState getVineStateForSide(EnumFacing side)
{
return this.vine.getBlock() instanceof BlockVine ? this.vine.with(BlockVine.getPropertyFor(side), Boolean.valueOf(true)) : this.vine;
}
private void extendVines(IWorld world, BlockPos pos, EnumFacing side)
{
IBlockState vineState = this.getVineStateForSide(side);
this.setBlockState(world, pos, vineState);
int length = 4;
//Extend vine downwards for a maximum of 4 blocks
for (pos = pos.down(); this.placeVinesOn.matches(world, pos) && length > 0; length--)
{
this.setBlockState(world, pos, vineState);
pos = pos.down();
}
}
}