Fixed up trees and spikes in the Wasteland

This commit is contained in:
Adubbz 2016-01-19 18:24:37 +11:00
parent bb2f5b99b1
commit ab98fad052
7 changed files with 258 additions and 6 deletions

View file

@ -21,6 +21,7 @@ public class BlockQueries
public static IBlockPosQuery airOrLeaves; public static IBlockPosQuery airOrLeaves;
public static IBlockPosQuery surfaceBlocks; public static IBlockPosQuery surfaceBlocks;
public static IBlockPosQuery groundBlocks; public static IBlockPosQuery groundBlocks;
public static IBlockPosQuery solid;
public static IBlockPosQuery fertile; public static IBlockPosQuery fertile;
public static IBlockPosQuery fertileOrNetherrack; public static IBlockPosQuery fertileOrNetherrack;

View file

@ -33,6 +33,7 @@ import biomesoplenty.common.world.feature.GeneratorFlora;
import biomesoplenty.common.world.feature.GeneratorGrass; import biomesoplenty.common.world.feature.GeneratorGrass;
import biomesoplenty.common.world.feature.GeneratorLakes; import biomesoplenty.common.world.feature.GeneratorLakes;
import biomesoplenty.common.world.feature.GeneratorOreSingle; import biomesoplenty.common.world.feature.GeneratorOreSingle;
import biomesoplenty.common.world.feature.GeneratorSpike;
import biomesoplenty.common.world.feature.GeneratorSplatter; import biomesoplenty.common.world.feature.GeneratorSplatter;
import biomesoplenty.common.world.feature.tree.GeneratorBasicTree; import biomesoplenty.common.world.feature.tree.GeneratorBasicTree;
import biomesoplenty.common.world.feature.tree.GeneratorBigTree; import biomesoplenty.common.world.feature.tree.GeneratorBigTree;
@ -63,11 +64,10 @@ public class BiomeGenWasteland extends BOPBiome
this.spawnableCreatureList.clear(); this.spawnableCreatureList.clear();
this.spawnableWaterCreatureList.clear(); this.spawnableWaterCreatureList.clear();
IBlockPosQuery emptyDriedDirt = BlockQuery.buildAnd().withAirAbove().states(this.topBlock).create();
// trees // trees
GeneratorWeighted treeGenerator = new GeneratorWeighted(1); GeneratorWeighted treeGenerator = new GeneratorWeighted(2.0F);
treeGenerator.add("dead_tree", 1, (new GeneratorBigTree.Builder()).amountPerChunk(1.0F).minHeight(5).maxHeight(12).placeOn(emptyDriedDirt).foliageHeight(0).foliageDensity(0.5D).log(BOPWoods.DEAD).leaves(Blocks.air.getDefaultState()).create()); this.addGenerator("trees", GeneratorStage.TREE, treeGenerator);
treeGenerator.add("dead_tree", 1, (new GeneratorBigTree.Builder()).amountPerChunk(1.0F).minHeight(5).maxHeight(12).foliageHeight(0).foliageDensity(0.5D).log(BOPWoods.DEAD).leaves(Blocks.air.getDefaultState()).create());
// grasses // grasses
GeneratorWeighted grassGenerator = new GeneratorWeighted(0.2F); GeneratorWeighted grassGenerator = new GeneratorWeighted(0.2F);
@ -81,6 +81,9 @@ public class BiomeGenWasteland extends BOPBiome
this.addGenerator("lakes", GeneratorStage.SAND, (new GeneratorLakes.Builder()).amountPerChunk(0.5F).waterLakeForBiome(this).create()); this.addGenerator("lakes", GeneratorStage.SAND, (new GeneratorLakes.Builder()).amountPerChunk(0.5F).waterLakeForBiome(this).create());
this.addGenerator("poison_lakes", GeneratorStage.SAND, (new GeneratorLakes.Builder()).amountPerChunk(0.2F).waterLakeForBiome(this).liquid(BOPBlocks.poison).frozenLiquid((IBlockState)null).create()); this.addGenerator("poison_lakes", GeneratorStage.SAND, (new GeneratorLakes.Builder()).amountPerChunk(0.2F).waterLakeForBiome(this).liquid(BOPBlocks.poison).frozenLiquid((IBlockState)null).create());
// spikes
this.addGenerator("spikes", GeneratorStage.PRE, (new GeneratorSpike.Builder()).amountPerChunk(0.5F).create());
// gem // gem
this.addGenerator("malachite", GeneratorStage.SAND, (new GeneratorOreSingle.Builder()).amountPerChunk(12).with(BOPGems.MALACHITE).create()); this.addGenerator("malachite", GeneratorStage.SAND, (new GeneratorOreSingle.Builder()).amountPerChunk(12).with(BOPGems.MALACHITE).create());

View file

@ -12,6 +12,7 @@ import static biomesoplenty.api.block.BlockQueries.*;
import net.minecraft.block.material.Material; import net.minecraft.block.material.Material;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.BlockPos; import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.EnumPlantType; import net.minecraftforge.common.EnumPlantType;
import biomesoplenty.api.block.BOPBlocks; import biomesoplenty.api.block.BOPBlocks;
@ -61,6 +62,17 @@ public class ModBlockQueries
} }
}; };
//Match blocks with a solid top
solid = new IBlockPosQuery()
{
// Block.setBlockUnbreakable sets the hardness value to -1.0F
@Override
public boolean matches(World world, BlockPos pos)
{
return world.isSideSolid(pos, EnumFacing.UP);
}
};
airOrLeaves = new BlockQueryMaterial(Material.air, Material.leaves); airOrLeaves = new BlockQueryMaterial(Material.air, Material.leaves);
// Match blocks which count as 'the surface' - useful for finding places to put plants, trees, lilypads etc - note plants, trees, snow all excluded because they sit or grow 'on' the surface // Match blocks which count as 'the surface' - useful for finding places to put plants, trees, lilypads etc - note plants, trees, snow all excluded because they sit or grow 'on' the surface

View file

@ -44,5 +44,6 @@ public class ModGenerators
registerGenerator("columns", GeneratorColumns.class, new GeneratorColumns.Builder()); registerGenerator("columns", GeneratorColumns.class, new GeneratorColumns.Builder());
registerGenerator("mixed_lily", GeneratorMixedLily.class, new GeneratorMixedLily.Builder()); registerGenerator("mixed_lily", GeneratorMixedLily.class, new GeneratorMixedLily.Builder());
registerGenerator("crystals", GeneratorCrystals.class, new GeneratorCrystals.Builder()); registerGenerator("crystals", GeneratorCrystals.class, new GeneratorCrystals.Builder());
registerGenerator("spike", GeneratorSpike.class, new GeneratorSpike.Builder());
} }
} }

View file

@ -52,7 +52,7 @@ public class GeneratorCrystals extends GeneratorReplacing
public GeneratorCrystals(float amountPerChunk, IBlockPosQuery placeOn, IBlockPosQuery replace, IBlockState with, ScatterYMethod scatterYMethod, int generationAttempts, int maxRadius, int maxDepth) public GeneratorCrystals(float amountPerChunk, IBlockPosQuery placeOn, IBlockPosQuery replace, IBlockState with, ScatterYMethod scatterYMethod, int generationAttempts, int maxRadius, int maxDepth)
{ {
super(amountPerChunk, replace, replace, with, scatterYMethod); super(amountPerChunk, placeOn, replace, with, scatterYMethod);
this.generationAttempts = generationAttempts; this.generationAttempts = generationAttempts;
this.maxRadius = maxRadius; this.maxRadius = maxRadius;
this.maxDepth = maxDepth; this.maxDepth = maxDepth;

View file

@ -0,0 +1,235 @@
/*******************************************************************************
* Copyright 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;
import java.util.Random;
import java.util.function.Predicate;
import org.apache.commons.lang3.tuple.Pair;
import biomesoplenty.api.biome.generation.BOPGeneratorBase;
import biomesoplenty.api.biome.generation.IGenerator.IGeneratorBuilder;
import biomesoplenty.api.block.BOPBlocks;
import biomesoplenty.api.block.BlockQueries;
import biomesoplenty.common.util.biome.GeneratorUtils;
import biomesoplenty.common.util.biome.GeneratorUtils.ScatterYMethod;
import biomesoplenty.common.util.block.BlockQuery.BlockQueryMaterial;
import biomesoplenty.common.util.block.BlockQuery.IBlockPosQuery;
import biomesoplenty.common.util.config.BOPConfig.IConfigObj;
import biomesoplenty.common.world.feature.GeneratorBigFlower.Builder;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.BlockPos;
import net.minecraft.world.World;
public class GeneratorSpike extends GeneratorReplacing
{
public static class Builder extends GeneratorReplacing.InnerBuilder<Builder, GeneratorSpike> implements IGeneratorBuilder<GeneratorSpike>
{
protected int minHeight;
protected int maxHeight;
protected int minRadius;
protected int maxRadius;
public Builder minHeight(int a) {this.minHeight = a; return this.self();}
public Builder maxHeight(int a) {this.maxHeight = a; return this.self();}
public Builder minRadius(int a) {this.minRadius = a; return this.self();}
public Builder maxRadius(int a) {this.maxRadius = a; return this.self();}
public Builder()
{
// defaults
this.amountPerChunk = 1.0F;
this.placeOn = BlockQueries.solid;
this.replace = new BlockQueryMaterial(Material.air);
this.with = BOPBlocks.dried_dirt.getDefaultState();
this.scatterYMethod = ScatterYMethod.AT_SURFACE;
this.minHeight = 8;
this.maxHeight = 12;
this.minRadius = 3;
this.maxRadius = 3;
}
@Override
public GeneratorSpike create()
{
return new GeneratorSpike(this.amountPerChunk, this.placeOn, this.replace, this.with, this.scatterYMethod, this.minHeight, this.maxHeight, this.minRadius, this.maxRadius);
}
}
protected int minHeight;
protected int maxHeight;
protected int minRadius;
protected int maxRadius;
public GeneratorSpike(float amountPerChunk, IBlockPosQuery placeOn, IBlockPosQuery replace, IBlockState with, ScatterYMethod scatterYMethod, int minHeight, int maxHeight, int minRadius, int maxRadius)
{
super(amountPerChunk, placeOn, replace, with, scatterYMethod);
this.minHeight = minHeight;
this.maxHeight = maxHeight;
this.minRadius = minRadius;
this.maxRadius = maxRadius;
}
@Override
public boolean generate(World world, Random rand, BlockPos position)
{
int maxRadius = this.minRadius + rand.nextInt(this.maxRadius - this.minRadius + 1);
int centreHeight = this.minHeight + rand.nextInt(this.maxHeight - this.minHeight + 1);
// check that there's room and if the blocks below are suitable
if (!this.canPlaceHere(world, position, centreHeight, maxRadius)) {return false;}
//Distribute the height excluding the spire and the base between the radius (other than the base)
int layerHeight = centreHeight / (maxRadius - 1);
//
// Generate the base
//
//Fill the inner section of the circle
createCircleWithChance(world, position, this.with, maxRadius - 1, true, 1.0F);
//Randomly remove the outer edges
createCircleWithChance(world, position, this.with, maxRadius, true, 0.15F);
//
// Generate the centre and the spire
//
BlockPos layerStartPos = position.up();
//Add 2 for the spire
for (int y = 0; y <= centreHeight + 2; y++)
{
//Generate the spire
if (y > centreHeight)
{
world.setBlockState(layerStartPos.add(0, y, 0), this.with);
}
else //Generate the layers
{
//Bottom layer is 0, then 1 etc
int layer = y / layerHeight;
int layerIndex = y % layerHeight; //Get the position of y within the current layer, ignoring the base
int radius = maxRadius - 1 - layer; //The radius for this layer, with the base radius subtracted
//Treat any layers with a radius of 0 as an extension of the spire
if (radius == 0)
{
world.setBlockState(layerStartPos.add(0, y, 0), this.with);
continue;
}
if (layerIndex == layerHeight - 1) //Generate midpoints randomly
{
//Fill the inner section of the circle
createCircleWithChance(world, layerStartPos.add(0, y, 0), this.with, radius - 1, true, 1.0F);
createMidpointsWithChance(world, layerStartPos.add(0, y, 0), this.with, radius, 0.7F);
}
else if (layerIndex == layerHeight - 2)
{
//Fill the inner section of the circle
createCircleWithChance(world, layerStartPos.add(0, y, 0), this.with, radius - 1, true, 1.0F);
//Randomly remove the outer edges
createCircleWithChance(world, layerStartPos.add(0, y, 0), this.with, radius, true, 0.1F / (layer + 1));
}
else
{
createCircleWithChance(world, layerStartPos.add(0, y, 0), this.with, radius, true, 1.0F);
}
}
}
return true;
}
public boolean canPlaceHere(World world, BlockPos pos, int height, int radius)
{
if (pos.getY() < 1 || pos.getY() + height > 255)
{
return false;
}
for (int y = pos.getY(); y <= pos.getY() + 8; ++y)
{
for (int x = pos.getX() - radius; x <= pos.getX() + radius; ++x)
{
for (int z = pos.getZ() - radius; z <= pos.getZ() + radius; ++z)
{
if (y == pos.getY() && !this.placeOn.matches(world, new BlockPos(x, y - 1, z)))
{
return false;
}
if (!this.replace.matches(world, new BlockPos(x, y, z)))
{
return false;
}
}
}
}
return true;
}
@Override
public void configure(IConfigObj conf)
{
this.amountPerChunk = conf.getFloat("amountPerChunk", this.amountPerChunk);
this.placeOn = conf.getBlockPosQuery("placeUnder", this.placeOn);
this.replace = conf.getBlockPosQuery("replace", this.replace);
this.with = conf.getBlockState("with", this.with);
this.scatterYMethod = conf.getEnum("scatterYMethod", this.scatterYMethod, ScatterYMethod.class);
int minHeight = conf.getInt("minHeight", this.minHeight).intValue();
int maxHeight = conf.getInt("maxHeight", this.maxHeight).intValue();
Pair<Integer, Integer> heights = GeneratorUtils.validateMinMaxHeight(minHeight, maxHeight);
this.minHeight = heights.getLeft();
this.maxHeight = heights.getRight();
int minRadius = conf.getInt("minRadius", this.minRadius).intValue();
int maxRadius = conf.getInt("maxRadius", this.maxRadius).intValue();
Pair<Integer, Integer> radii = GeneratorUtils.validateMinMaxHeight(minRadius, maxRadius);
this.minRadius = radii.getLeft();
this.maxRadius = radii.getRight();
}
private void createCircleWithChance(World world, BlockPos middle, IBlockState state, int maxRadius, boolean fill, float chance)
{
//This may break for larger radii however it will do for this purpose
double increment = 0.05D;
for (int radius = maxRadius; radius >= 0; radius--)
{
for (double angle = 0.0F; angle <= Math.PI * 2; angle += increment)
{
BlockPos pos = middle.add(Math.round(radius * Math.cos(angle)), 0, Math.round(radius * Math.sin(angle)));
setBlockWithChance(world, pos, state, chance);
}
if (!fill) break;
}
}
private void createMidpointsWithChance(World world, BlockPos middle, IBlockState state, int radius, float chance)
{
BlockPos midpoint;
if (world.getBlockState((midpoint = middle.add(-radius, 0, 0)).down()) == state) setBlockWithChance(world, midpoint, state, chance);
if (world.getBlockState((midpoint = middle.add(radius, 0, 0)).down()) == state) setBlockWithChance(world, midpoint, state, chance);
if (world.getBlockState((midpoint = middle.add(0, 0, -radius)).down()) == state) setBlockWithChance(world, midpoint, state, chance);
if (world.getBlockState((midpoint = middle.add(0, 0, radius)).down()) == state) setBlockWithChance(world, midpoint, state, chance);
}
private void setBlockWithChance(World world, BlockPos pos, IBlockState state, float chance)
{
if (world.rand.nextFloat() < chance)
world.setBlockState(pos, state);
}
}

View file

@ -493,7 +493,7 @@ public class GeneratorBigTree extends GeneratorTreeBase
boolean isSoil = state.getBlock().canSustainPlant(this.world, down, EnumFacing.UP, ((BlockSapling)Blocks.sapling)); boolean isSoil = state.getBlock().canSustainPlant(this.world, down, EnumFacing.UP, ((BlockSapling)Blocks.sapling));
//Don't grow the tree here if the location can't sustain a sapling //Don't grow the tree here if the location can't sustain a sapling
if (!isSoil || !this.placeOn.matches(world, down)) if (!isSoil && !this.placeOn.matches(world, down))
{ {
return false; return false;
} }