Re-added normal tree gen
This commit is contained in:
parent
17dfb6a377
commit
d16d851619
2 changed files with 357 additions and 0 deletions
|
@ -8,6 +8,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.TaigaTreeFeature;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.world.gen.feature.AbstractTreeFeature;
|
||||
|
@ -17,6 +18,7 @@ import net.minecraft.world.gen.surfacebuilders.SurfaceBuilderConfig;
|
|||
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 SurfaceBuilderConfig LOAMY_GRASS_DIRT_GRAVEL_SURFACE = new SurfaceBuilderConfig(BOPBlocks.loamy_grass_block.getDefaultState(), BOPBlocks.loamy_dirt.getDefaultState(), Blocks.GRAVEL.getDefaultState());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,355 @@
|
|||
/*******************************************************************************
|
||||
* 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.common.util.block.IBlockPosQuery;
|
||||
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.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
public class BasicTreeFeature extends TreeFeatureBase
|
||||
{
|
||||
public static class Builder extends BuilderBase<BasicTreeFeature.Builder, BasicTreeFeature>
|
||||
{
|
||||
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) -> true;
|
||||
this.replace = (world, pos) ->
|
||||
{
|
||||
Material mat = world.getBlockState(pos).getMaterial();
|
||||
return mat == Material.AIR || mat == Material.LEAVES;
|
||||
};
|
||||
this.minHeight = 4;
|
||||
this.maxHeight = 7;
|
||||
this.updateNeighbours = false;
|
||||
this.leafLayers = 4;
|
||||
this.leavesOffset = 1;
|
||||
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 BasicTreeFeature create()
|
||||
{
|
||||
return new BasicTreeFeature(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 BasicTreeFeature(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)
|
||||
{
|
||||
if (!this.replace.matches(world, new BlockPos(x, y, z)))
|
||||
{
|
||||
hasSpace = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hasSpace = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasSpace)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockPos soilPos = pos.down();
|
||||
Block soil = world.getBlockState(soilPos).getBlock();
|
||||
boolean isSoil = soil.canSustainPlant(world.getBlockState(soilPos), world, soilPos, EnumFacing.UP, (BlockSapling) Blocks.OAK_SAPLING);
|
||||
|
||||
if (this.placeOn.matches(world, soilPos) && isSoil && 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();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue