Added proper Mangrove trees

This commit is contained in:
Forstride 2016-04-06 23:27:37 -04:00
parent 8427e01748
commit ba6d47938d
4 changed files with 306 additions and 20 deletions

View file

@ -10,36 +10,26 @@ package biomesoplenty.common.biome.overworld;
import java.util.Random;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.world.World;
import net.minecraft.world.chunk.ChunkPrimer;
import biomesoplenty.api.biome.BOPBiome;
import biomesoplenty.api.biome.generation.GeneratorStage;
import biomesoplenty.api.biome.generation.GeneratorWeighted;
import biomesoplenty.api.block.BOPBlocks;
import biomesoplenty.common.block.BlockBOPLeaves;
import biomesoplenty.common.block.BlockBOPSand;
import biomesoplenty.common.entities.EntityButterfly;
import biomesoplenty.common.enums.BOPFlowers;
import biomesoplenty.common.enums.BOPGems;
import biomesoplenty.common.enums.BOPPlants;
import biomesoplenty.common.enums.BOPTrees;
import biomesoplenty.common.enums.BOPWoods;
import biomesoplenty.common.util.block.BlockQuery;
import biomesoplenty.common.util.block.BlockQuery.IBlockPosQuery;
import biomesoplenty.common.util.config.BOPConfig.IConfigObj;
import biomesoplenty.common.world.BOPWorldSettings;
import biomesoplenty.common.world.feature.GeneratorFlora;
import biomesoplenty.common.world.feature.GeneratorGrass;
import biomesoplenty.common.world.feature.GeneratorLakes;
import biomesoplenty.common.world.feature.GeneratorOreSingle;
import biomesoplenty.common.world.feature.tree.GeneratorBasicTree;
import biomesoplenty.common.world.feature.tree.GeneratorBayouTree;
import net.minecraft.block.BlockFlower;
import net.minecraft.block.BlockOldLeaf;
import net.minecraft.block.BlockTallGrass;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.world.World;
import net.minecraft.world.chunk.ChunkPrimer;
import biomesoplenty.common.world.feature.tree.GeneratorMangroveTree;
public class BiomeGenMangrove extends BOPBiome
{
@ -75,9 +65,9 @@ public class BiomeGenMangrove extends BOPBiome
// trees & logs
IBlockPosQuery emptySandMud = BlockQuery.buildAnd().states(this.usualTopBlock).create();
GeneratorWeighted treeGenerator = new GeneratorWeighted(10);
GeneratorWeighted treeGenerator = new GeneratorWeighted(7);
this.addGenerator("trees", GeneratorStage.TREE, treeGenerator);
treeGenerator.add("mangrove", 1, (new GeneratorBayouTree.Builder()).placeOn(emptySandMud).log(BOPWoods.MANGROVE).leaves(BOPTrees.MANGROVE).minHeight(6).maxHeight(8).minLeavesRadius(1).vine(null).leavesGradient(1).create());
treeGenerator.add("mangrove", 1, (new GeneratorMangroveTree.Builder()).placeOn(emptySandMud).log(BOPWoods.MANGROVE).leaves(BOPTrees.MANGROVE).create());
// gem
this.addGenerator("sapphire", GeneratorStage.SAND, (new GeneratorOreSingle.Builder()).amountPerChunk(12).with(BOPGems.SAPPHIRE).create());

View file

@ -20,6 +20,7 @@ import biomesoplenty.common.world.feature.tree.GeneratorBasicTree;
import biomesoplenty.common.world.feature.tree.GeneratorBigTree;
import biomesoplenty.common.world.feature.tree.GeneratorBulbTree;
import biomesoplenty.common.world.feature.tree.GeneratorMahoganyTree;
import biomesoplenty.common.world.feature.tree.GeneratorMangroveTree;
import biomesoplenty.common.world.feature.tree.GeneratorPalmTree;
import biomesoplenty.common.world.feature.tree.GeneratorPineTree;
import biomesoplenty.common.world.feature.tree.GeneratorRedwoodTree;
@ -202,7 +203,7 @@ public class BlockBOPSapling extends BlockBOPDecoration implements IGrowable {
case SACRED_OAK:
return new GeneratorBigTree.Builder().log(BOPWoods.SACRED_OAK).leaves(BOPTrees.SACRED_OAK).minHeight(35).maxHeight(45).trunkWidth(2).foliageDensity(1.25D).create();
case MANGROVE: //Not implemented
return new WorldGenTrees(true);
return new GeneratorMangroveTree.Builder().log(BOPWoods.MANGROVE).leaves(BOPTrees.MANGROVE).create();
case PALM:
return new GeneratorPalmTree.Builder().log(BOPWoods.PALM).leaves(BlockBOPLeaves.paging.getVariantState(BOPTrees.PALM).withProperty(BlockOldLeaf.CHECK_DECAY, Boolean.valueOf(false))).create();
case REDWOOD:

View file

@ -9,7 +9,6 @@
package biomesoplenty.common.init;
import static biomesoplenty.api.biome.generation.GeneratorRegistry.registerGenerator;
import biomesoplenty.api.biome.generation.GeneratorWeighted;
import biomesoplenty.common.world.feature.GeneratorBigFlower;
import biomesoplenty.common.world.feature.GeneratorBigMushroom;
@ -34,6 +33,7 @@ import biomesoplenty.common.world.feature.tree.GeneratorBigTree;
import biomesoplenty.common.world.feature.tree.GeneratorBulbTree;
import biomesoplenty.common.world.feature.tree.GeneratorBush;
import biomesoplenty.common.world.feature.tree.GeneratorMahoganyTree;
import biomesoplenty.common.world.feature.tree.GeneratorMangroveTree;
import biomesoplenty.common.world.feature.tree.GeneratorMegaJungleTree;
import biomesoplenty.common.world.feature.tree.GeneratorPalmTree;
import biomesoplenty.common.world.feature.tree.GeneratorPineTree;
@ -57,6 +57,7 @@ public class ModGenerators
registerGenerator("bulb_tree", GeneratorBulbTree.class, new GeneratorBulbTree.Builder());
registerGenerator("mega_jungle_tree", GeneratorMegaJungleTree.class, new GeneratorMegaJungleTree.Builder());
registerGenerator("bayou_tree", GeneratorBayouTree.class, new GeneratorBayouTree.Builder());
registerGenerator("mangrove_tree", GeneratorMangroveTree.class, new GeneratorMangroveTree.Builder());
registerGenerator("taiga_tree", GeneratorTaigaTree.class, new GeneratorTaigaTree.Builder());
registerGenerator("profile_tree", GeneratorProfileTree.class, new GeneratorProfileTree.Builder());
registerGenerator("flora", GeneratorFlora.class, new GeneratorFlora.Builder());

View file

@ -0,0 +1,294 @@
/*******************************************************************************
* Copyright 2015-2016, 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.feature.tree;
import java.util.Random;
import biomesoplenty.api.block.BlockQueries;
import biomesoplenty.common.util.biome.GeneratorUtils;
import biomesoplenty.common.util.block.BlockQuery;
import biomesoplenty.common.util.block.BlockQuery.BlockQueryBlock;
import biomesoplenty.common.util.block.BlockQuery.BlockQueryParseException;
import biomesoplenty.common.util.block.BlockQuery.BlockQueryState;
import biomesoplenty.common.util.block.BlockQuery.IBlockPosQuery;
import biomesoplenty.common.util.config.BOPConfig.IConfigObj;
import net.minecraft.block.Block;
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;
public class GeneratorMangroveTree extends GeneratorTreeBase
{
public static class Builder extends GeneratorTreeBase.InnerBuilder<Builder, GeneratorMangroveTree> implements IGeneratorBuilder<GeneratorMangroveTree>
{
protected int minLeavesRadius;
protected int leavesGradient;
protected int vineAttempts;
protected int maxVineLength;
protected IBlockPosQuery rootsReplace;
public Builder minLeavesRadius(int a) {this.minLeavesRadius = a; return this.self();}
public Builder leavesGradient(int a) {this.leavesGradient = a; return this.self();}
public Builder vineAttempts(int a) {this.vineAttempts = a; return this.self();}
public Builder maxVineLength(int a) {this.maxVineLength = a; return this.self();}
public Builder rootsReplace(IBlockPosQuery a) {this.replace = a; return this.self();}
public Builder rootsReplace(String a) throws BlockQueryParseException {this.replace = BlockQuery.parseQueryString(a); return this.self();}
public Builder rootsReplace(Block a) {this.replace = new BlockQueryBlock(a); return this.self();}
public Builder rootsReplace(IBlockState a) {this.replace = new BlockQueryState(a); return this.self();}
public Builder()
{
// defaults
this.amountPerChunk = 1.0F;
this.placeOn = BlockQueries.fertile;
this.replace = BlockQueries.airOrLeaves;
this.rootsReplace = BlockQueries.rootsCanDigThrough;
this.log = Blocks.log.getDefaultState();
this.leaves = Blocks.leaves.getDefaultState();
this.vine = null;
this.hanging = null;
this.altLeaves = null;
this.minHeight = 8;
this.maxHeight = 10;
this.minLeavesRadius = 1;
this.leavesGradient = 1;
this.vineAttempts = 20;
this.maxVineLength = 20;
}
@Override
public GeneratorMangroveTree create()
{
return new GeneratorMangroveTree(this.amountPerChunk, this.placeOn, this.replace, this.log, this.leaves, this.vine, this.hanging, this.altLeaves, this.minHeight, this.maxHeight, this.minLeavesRadius, this.leavesGradient, this.vineAttempts, this.maxVineLength, this.rootsReplace);
}
}
private int minLeavesRadius;
private int leavesGradient;
private int vineAttempts;
private int maxVineLength;
private IBlockPosQuery rootsReplace;
public GeneratorMangroveTree(float amountPerChunk, IBlockPosQuery placeOn, IBlockPosQuery replace, IBlockState log, IBlockState leaves, IBlockState vine, IBlockState hanging, IBlockState altLeaves, int minHeight, int maxHeight, int minLeavesRadius, int leavesGradient, int vineAttempts, int maxVineLength, IBlockPosQuery rootsReplace)
{
super(amountPerChunk, placeOn, replace, log, leaves, vine, hanging, altLeaves, minHeight, maxHeight);
this.minLeavesRadius = minLeavesRadius;
this.leavesGradient = leavesGradient;
this.vineAttempts = vineAttempts;
this.maxVineLength = maxVineLength;
this.rootsReplace = rootsReplace;
}
@Override
public BlockPos getScatterY(World world, Random random, int x, int z)
{
// always at ground (sometimes underwater)
return GeneratorUtils.ScatterYMethod.AT_GROUND.getBlockPos(world, random, x, z);
}
public boolean setRoot(World world, BlockPos pos)
{
if (this.rootsReplace.matches(world, pos))
{
world.setBlockState(pos, this.log, 2);
return true;
}
return false;
}
public boolean checkRootViable(World world, BlockPos pos, int rootHeight, EnumFacing direction)
{
// a viable root has an path which roots can dig through from trunk to some fertile ground
pos = pos.offset(direction).up(rootHeight - 1);
for (int i = 0; i < rootHeight; i++)
{
if (!this.rootsReplace.matches(world, pos)) {return false;}
pos = pos.down();
if (this.placeOn.matches(world, pos)) {return true;}
}
return false;
}
public boolean checkSpace(World world, BlockPos pos, int rootHeight, int middleHeight, int height)
{
// we want at least 2 of the roots to be viable
int rootsOk = 0;
for (EnumFacing direction : EnumFacing.Plane.HORIZONTAL)
{
if (this.checkRootViable(world, pos, rootHeight, direction)) {rootsOk++;}
}
if (rootsOk < 2) {return false;}
// check there's some space for the trunk and leaves too
for (int y = rootHeight; y <= height; y++)
{
// require 1x1 for the trunk, 3x3 for the leaves
int radius = (y <= (rootHeight + middleHeight) ? 0 : 1);
for (int x = -radius; x <= radius; x++)
{
for (int z = -radius; z <= radius; z++)
{
BlockPos pos1 = pos.add(x, y, z);
// note, there may be a sapling on the first layer - make sure this.replace matches it!
if (pos1.getY() >= 255 || !this.replace.matches(world, pos1))
{
return false;
}
}
}
}
return true;
}
public void generateTop(World world, Random random, BlockPos pos, int topHeight)
{
for (int y = 0; y < topHeight; y++)
{
int radius = Math.min(3, this.minLeavesRadius + (topHeight - y) / this.leavesGradient);
for (int x = -radius; x <= radius; ++x)
{
for (int z = -radius; z <= radius; ++z)
{
// too far away and the leaves will decay
int dist = Math.abs(x) + Math.abs(z);
if (dist < 4 || (dist == 4 && random.nextInt(2) == 0))
{
this.setLeaves(world, pos.add(x, y, z));
}
}
}
if (y < topHeight - 1)
{
// add the trunk in the middle
this.setLog(world, pos.add(0, y, 0));
} else {
// add leaves on top for certain
this.setLeaves(world, pos.add(0, y, 0));
}
}
}
public void generateRoots(World world, Random random, BlockPos pos, int rootHeight)
{
this.setRoot(world, pos.north().add(0, rootHeight, 0));
this.setRoot(world, pos.east().add(0, rootHeight, 0));
this.setRoot(world, pos.south().add(0, rootHeight, 0));
this.setRoot(world, pos.west().add(0, rootHeight, 0));
for (int i = 0; i < rootHeight; i++)
{
this.setRoot(world, pos.north().north());
this.setRoot(world, pos.east().east());
this.setRoot(world, pos.south().south());
this.setRoot(world, pos.west().west());
pos = pos.up();
}
//this.setRoot(world, pos.down());
}
@Override
public boolean generate(World world, Random random, BlockPos startPos)
{
if (!this.placeOn.matches(world, startPos.down()))
{
// Abandon if we can't place the tree on this block
return false;
}
// Choose heights
int height = GeneratorUtils.nextIntBetween(random, this.minHeight, this.maxHeight);
int topHeight = Math.min(6, GeneratorUtils.nextIntBetween(random, height / 5, height / 3));
int rootHeight = Math.min(5, GeneratorUtils.nextIntBetween(random, height / 4, height / 2));
int middleHeight = height - topHeight - rootHeight;
if (middleHeight < 1) {return false;}
// Start in the ground block
BlockPos pos = startPos.down();
if (!this.checkSpace(world, pos, rootHeight, middleHeight, height))
{
// Abandon if there isn't enough room
return false;
}
// Generate roots
this.generateRoots(world, random, pos, rootHeight);
pos = pos.up(rootHeight);
// Generate middle of tree (trunk only)
for(int i = 0; i < middleHeight; i++)
{
this.setLog(world, pos);
pos = pos.up();
}
// Generate the top of the tree
this.generateTop(world, random, pos, topHeight);
// Add vines
if (this.vine != null)
{
int maxLeavesRadius = this.minLeavesRadius + topHeight / this.leavesGradient;
this.addVines(world, random, startPos, height, maxLeavesRadius, this.vineAttempts);
}
return true;
}
protected void addVines(World world, Random rand, BlockPos startPos, int height, int leavesRadius, int generationAttempts)
{
for (int i = 0; i < generationAttempts; i++)
{
// choose a random direction
EnumFacing direction = EnumFacing.Plane.HORIZONTAL.random(rand);
EnumFacing back = direction.getOpposite();
EnumFacing sideways = direction.rotateY();
// choose a random starting point somewhere just outside the boundary of the tree
BlockPos pos = startPos.up(GeneratorUtils.nextIntBetween(rand, 2, height)).offset(direction, leavesRadius + 1).offset(sideways, GeneratorUtils.nextIntBetween(rand, -leavesRadius, leavesRadius));
// move back towards the center until we meet a leaf or log, then stick a vine on it
IBlockState state;
for (int l = 0; l < leavesRadius; l++)
{
state = world.getBlockState(pos.offset(back, 1 + l));
if (state == this.leaves || state == this.log) {
this.setVine(world, rand, pos.offset(back, l), back, this.maxVineLength);
break;
}
}
}
}
@Override
public void configure(IConfigObj conf)
{
this.amountPerChunk = conf.getFloat("amountPerChunk", this.amountPerChunk);
this.minHeight = conf.getInt("minHeight", this.minHeight);
this.minLeavesRadius = conf.getInt("minLeavesRadius", this.minLeavesRadius);
this.leavesGradient = conf.getInt("leavesGradient", this.leavesGradient);
this.vineAttempts = conf.getInt("vineAttempts", this.vineAttempts);
this.maxVineLength = conf.getInt("maxVineLength", this.maxVineLength);
this.placeOn = conf.getBlockPosQuery("placeOn", this.placeOn);
this.replace = conf.getBlockPosQuery("replace", this.replace);
this.rootsReplace = conf.getBlockPosQuery("rootsReplace", this.rootsReplace);
this.log = conf.getBlockState("logState", this.log);
this.leaves = conf.getBlockState("leavesState", this.leaves);
this.vine = conf.getBlockState("vinesState", this.vine);
}
}