Fixed up trees and spikes in the Wasteland
This commit is contained in:
parent
bb2f5b99b1
commit
ab98fad052
7 changed files with 258 additions and 6 deletions
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue