From 5779ba020eb72ec25b8961e516827a23dd7817fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Sat, 2 Jul 2016 13:39:38 +0200 Subject: [PATCH] Limestone world gen - More testing + Feature where limestone is above ground, creating holes and pillars, sometimes with water in them. --- .../mmm/world/I_WDefaultPopulateHandler.java | 10 + src/java/mmm/world/WDefaultGenWatcher.java | 26 ++ src/java/mmm/world/World.java | 14 + .../mmm/world/biome/BiomeLimestoneHills.java | 1 - .../mmm/world/biome/WBLimestonePlateau.java | 149 +++++++++ src/java/mmm/world/gen/WGLimestoneChaos.java | 309 ++++++++++++++++++ 6 files changed, 508 insertions(+), 1 deletion(-) create mode 100644 src/java/mmm/world/I_WDefaultPopulateHandler.java create mode 100644 src/java/mmm/world/WDefaultGenWatcher.java create mode 100644 src/java/mmm/world/biome/WBLimestonePlateau.java create mode 100644 src/java/mmm/world/gen/WGLimestoneChaos.java diff --git a/src/java/mmm/world/I_WDefaultPopulateHandler.java b/src/java/mmm/world/I_WDefaultPopulateHandler.java new file mode 100644 index 0000000..3134b63 --- /dev/null +++ b/src/java/mmm/world/I_WDefaultPopulateHandler.java @@ -0,0 +1,10 @@ +package mmm.world; + +import net.minecraftforge.event.terraingen.PopulateChunkEvent; + +public interface I_WDefaultPopulateHandler +{ + + public boolean onDefaultPopulate( PopulateChunkEvent.Populate event ); + +} diff --git a/src/java/mmm/world/WDefaultGenWatcher.java b/src/java/mmm/world/WDefaultGenWatcher.java new file mode 100644 index 0000000..39cf69c --- /dev/null +++ b/src/java/mmm/world/WDefaultGenWatcher.java @@ -0,0 +1,26 @@ +package mmm.world; + + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.biome.Biome; +import net.minecraftforge.event.terraingen.PopulateChunkEvent; +import net.minecraftforge.fml.common.eventhandler.Event.Result; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + + + +public class WDefaultGenWatcher +{ + + @SubscribeEvent + public void onPopulate( final PopulateChunkEvent.Populate event ) + { + final BlockPos bp = new BlockPos( event.getChunkX( ) * 16 , 0 , event.getChunkZ( ) * 16 ); + final Biome biome = event.getWorld( ).getBiomeGenForCoords( bp ); + if ( biome instanceof I_WDefaultPopulateHandler + && ! ( (I_WDefaultPopulateHandler) biome ).onDefaultPopulate( event ) ) { + event.setResult( Result.DENY ); + } + } + +} diff --git a/src/java/mmm/world/World.java b/src/java/mmm/world/World.java index b5efb76..6eb63fe 100644 --- a/src/java/mmm/world/World.java +++ b/src/java/mmm/world/World.java @@ -2,10 +2,12 @@ package mmm.world; import mmm.world.biome.BiomeLimestoneHills; +import mmm.world.biome.WBLimestonePlateau; import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.BiomeHills; import net.minecraftforge.common.BiomeDictionary; import net.minecraftforge.common.BiomeManager; +import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.BiomeManager.BiomeType; import net.minecraftforge.fml.common.registry.GameRegistry; @@ -18,6 +20,8 @@ public class World public static final BiomeLimestoneHills BIOME_LIMESTONE_HILLS_EDGE; static { + MinecraftForge.TERRAIN_GEN_BUS.register( new WDefaultGenWatcher( ) ); + BIOME_LIMESTONE_HILLS = new BiomeLimestoneHills( BiomeHills.Type.NORMAL , new Biome.BiomeProperties( "Limestone Hills" ).setBaseHeight( 1.0F ).setHeightVariation( 0.5F ) .setTemperature( 0.2F ).setRainfall( 0.3F ) ); @@ -44,6 +48,16 @@ public class World BiomeManager.addBiome( BiomeType.COOL , new BiomeManager.BiomeEntry( BIOME_LIMESTONE_HILLS_EDGE , 5 ) ); BiomeManager.addBiome( BiomeType.WARM , new BiomeManager.BiomeEntry( BIOME_LIMESTONE_HILLS_EDGE , 5 ) ); BiomeDictionary.makeBestGuess( World.BIOME_LIMESTONE_HILLS_EDGE ); + + // TEST REMOVE THIS XXX FIXME LOL + WBLimestonePlateau testLol = new WBLimestonePlateau( false , + ( new Biome.BiomeProperties( "LOL TEST" ) ).setBaseHeight( 0.5F ).setHeightVariation( 0.02F ) + .setTemperature( 0.8F ).setRainfall( 0.4F ).setWaterColor( 0xe0ff7f ) ); + testLol.setRegistryName( "mmm:test_lol" ); + GameRegistry.register( testLol ); + BiomeManager.addBiome( BiomeType.COOL , new BiomeManager.BiomeEntry( testLol , 25 ) ); + BiomeManager.addBiome( BiomeType.WARM , new BiomeManager.BiomeEntry( testLol , 25 ) ); + BiomeDictionary.makeBestGuess( testLol ); } diff --git a/src/java/mmm/world/biome/BiomeLimestoneHills.java b/src/java/mmm/world/biome/BiomeLimestoneHills.java index 353abd4..b6e9c4e 100644 --- a/src/java/mmm/world/biome/BiomeLimestoneHills.java +++ b/src/java/mmm/world/biome/BiomeLimestoneHills.java @@ -30,7 +30,6 @@ public class BiomeLimestoneHills public void genTerrainBlocks( final World worldIn , final Random rand , final ChunkPrimer chunkPrimerIn , final int x , final int z , final double noiseVal ) { - System.err.println( "gen at " + x + " / " + z ); if ( this.type == BiomeHills.Type.EXTRA_TREES ) { this.topBlock = Blocks.GRASS.getDefaultState( ); this.fillerBlock = Materials.ROCK_LIMESTONE.getDefaultState( ); diff --git a/src/java/mmm/world/biome/WBLimestonePlateau.java b/src/java/mmm/world/biome/WBLimestonePlateau.java new file mode 100644 index 0000000..566196f --- /dev/null +++ b/src/java/mmm/world/biome/WBLimestonePlateau.java @@ -0,0 +1,149 @@ +package mmm.world.biome; + + +import java.util.Random; + +import mmm.materials.Materials; +import mmm.world.I_WDefaultPopulateHandler; +import mmm.world.gen.WGLimestoneChaos; +import net.minecraft.block.BlockDirt; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.gen.feature.WorldGenLakes; +import net.minecraftforge.event.terraingen.PopulateChunkEvent; + + + +public class WBLimestonePlateau + extends Biome + implements I_WDefaultPopulateHandler +{ + private static final IBlockState BS_COARSE_DIRT = Blocks.DIRT.getDefaultState( ).withProperty( BlockDirt.VARIANT , + BlockDirt.DirtType.COARSE_DIRT ); + private static final IBlockState BS_LIMESTONE = Materials.ROCK_LIMESTONE.getDefaultState( ); + + private final int chaosChance; + + + public WBLimestonePlateau( final boolean trees , final BiomeProperties properties ) + { + super( properties ); + + if ( trees ) { + this.theBiomeDecorator.treesPerChunk = 5; + this.theBiomeDecorator.flowersPerChunk = 2; + this.theBiomeDecorator.grassPerChunk = 0; + } else { + this.theBiomeDecorator.treesPerChunk = 0; + this.theBiomeDecorator.flowersPerChunk = 8; + this.theBiomeDecorator.grassPerChunk = 1; + } + this.theBiomeDecorator.field_189870_A = 0.1f; + this.topBlock = Blocks.GRASS.getDefaultState( ); + this.fillerBlock = Blocks.DIRT.getDefaultState( ); + this.chaosChance = 4; // XXX + } + + + @Override + public void decorate( final World worldIn , final Random rand , final BlockPos pos ) + { + if ( rand.nextInt( this.chaosChance ) == 0 ) { + final BlockPos.MutableBlockPos mbp = new BlockPos.MutableBlockPos( + pos.add( rand.nextInt( 16 ) + 8 , 0 , rand.nextInt( 16 ) + 8 ) ); + boolean found = false; + for ( int y = 255 ; y >= worldIn.getSeaLevel( ) - 20 ; y-- ) { + mbp.setY( y ); + if ( worldIn.getBlockState( mbp ).getMaterial( ) != Material.AIR ) { + found = true; + mbp.setY( y + 2 - rand.nextInt( 4 ) ); + break; + } + } + + if ( found ) { + System.err.println( "PIT AT " + mbp ); + new WGLimestoneChaos( ).generate( worldIn , rand , mbp ); + } + } + + super.decorate( worldIn , rand , pos ); + this.makeLimestoneLayer( worldIn , rand , pos ); + } + + + private void makeLimestoneLayer( final World worldIn , final Random rand , final BlockPos pos ) + { + final BlockPos.MutableBlockPos mbp = new BlockPos.MutableBlockPos( pos ); + for ( int i = 0 ; i < 16 ; i++ ) { + for ( int j = 0 ; j < 16 ; j++ ) { + mbp.setPos( pos.getX( ) + i , 255 , pos.getZ( ) + j ); + + int toDepth = -1; + for ( int y = 255 ; y >= 0 ; y-- ) { + mbp.setY( y ); + + final IBlockState bs = worldIn.getBlockState( mbp ); + if ( bs.getBlock( ) == Blocks.STONE ) { + if ( toDepth == -1 ) { + toDepth = 15 + rand.nextInt( 4 ); + this.replaceWithLimestone( worldIn , rand , mbp ); + } else if ( toDepth != 0 ) { + toDepth--; + this.replaceWithLimestone( worldIn , rand , mbp ); + } + continue; + } + if ( bs.getBlock( ) == Blocks.DIRT || bs.getBlock( ) == Blocks.GRASS + || bs.getBlock( ) == Blocks.GRAVEL ) { + this.replaceWithCoarseDirt( worldIn , rand , mbp ); + } + } + } + } + } + + + private void replaceWithLimestone( final World worldIn , final Random rand , final BlockPos.MutableBlockPos mbp ) + { + if ( rand.nextInt( 8 ) != 0 ) { + worldIn.setBlockState( mbp , BS_LIMESTONE ); + } + } + + + private void replaceWithCoarseDirt( final World worldIn , final Random rand , final BlockPos.MutableBlockPos mbp ) + { + if ( rand.nextInt( 16 ) == 0 ) { + worldIn.setBlockState( mbp , BS_COARSE_DIRT ); + } + } + + + @Override + public boolean onDefaultPopulate( final PopulateChunkEvent.Populate event ) + { + // No lava lakes at the surface of limestone plateaus or inside the limestone + if ( event.getType( ) == PopulateChunkEvent.Populate.EventType.LAVA ) { + final Random rand = event.getRand( ); + final World world = event.getWorld( ); + final int x = rand.nextInt( 16 ) + 8; + final int y = rand.nextInt( rand.nextInt( 248 ) + 8 ); + final int z = rand.nextInt( 16 ) + 8; + + if ( y < world.getSeaLevel( ) - 20 ) { + new WorldGenLakes( Blocks.LAVA ).generate( world , rand , + new BlockPos( event.getChunkX( ) * 16 + x , y , event.getChunkZ( ) * 16 + z ) ); + } + + return false; + } + + return true; + } + +} diff --git a/src/java/mmm/world/gen/WGLimestoneChaos.java b/src/java/mmm/world/gen/WGLimestoneChaos.java new file mode 100644 index 0000000..9e577ed --- /dev/null +++ b/src/java/mmm/world/gen/WGLimestoneChaos.java @@ -0,0 +1,309 @@ +package mmm.world.gen; + + +import java.util.Random; + +import mmm.materials.Materials; +import net.minecraft.block.BlockDirt; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.WorldGenerator; + + + +public class WGLimestoneChaos + extends WorldGenerator +{ + + private static final IBlockState BS_LIMESTONE = Materials.ROCK_LIMESTONE.getDefaultState( ); + private static final IBlockState BS_STONE = Blocks.STONE.getDefaultState( ); + private static final IBlockState BS_AIR = Blocks.AIR.getDefaultState( ); + private static final IBlockState BS_COARSE_DIRT = Blocks.DIRT.getDefaultState( ).withProperty( BlockDirt.VARIANT , + BlockDirt.DirtType.COARSE_DIRT ); + private static final IBlockState BS_GRAVEL = Blocks.GRAVEL.getDefaultState( ); + private static final IBlockState BS_WATER = Blocks.WATER.getDefaultState( ); + + private static final int SB_IGNORE = 0; + private static final int SB_LIMESTONE = 1; + private static final int SB_DIRT = 2; + private static final int SB_GRAVEL = 3; + private static final int SB_WATER = 4; + private static final int SB_HOLE = 5; + private static final int SB_MAYBE = 8; + + + @Override + public boolean generate( final World worldIn , final Random rand , final BlockPos position ) + { + final BlockPos.MutableBlockPos mbp = new BlockPos.MutableBlockPos( + position.add( rand.nextInt( 16 ) , 0 , rand.nextInt( 16 ) ) ); + + // Find stone + int lastAirY = 255; + int lastGroundY = 255; + for ( int y = 255 ; y >= worldIn.getSeaLevel( ) - 20 ; y-- ) { + mbp.setY( y ); + final IBlockState blockState = worldIn.getBlockState( mbp ); + if ( blockState == WGLimestoneChaos.BS_STONE || blockState == WGLimestoneChaos.BS_LIMESTONE ) { + lastGroundY = y; + break; + } + if ( blockState.getMaterial( ) == Material.AIR ) { + lastAirY = y; + } + } + if ( lastGroundY == 255 ) { + return false; + } + + final int shapeHeight = lastAirY - mbp.getY( ) + 3; + final int[] shape = this.generateShape( rand , shapeHeight ); + + if ( !this.checkLiquids( worldIn , position , mbp , lastGroundY , shapeHeight , shape ) ) { + return false; + } + + final int airCount = this.checkAirBlocks( worldIn , position , mbp , lastGroundY , shapeHeight , shape ); + if ( airCount * 2 > 16 * 16 * shapeHeight ) { + return false; + } + + this.digPit( rand , shapeHeight , shape ); + this.makePillars( rand , shapeHeight , shape ); + this.addWaterHoles( rand , shapeHeight , shape ); + + this.build( worldIn , position , mbp , lastGroundY , shapeHeight , shape ); + + return true; + } + + + private int[] generateShape( final Random rand , final int shapeHeight ) + { + final int shape[] = new int[ 16 * 16 * shapeHeight ]; + final int nCylinders = 8 + rand.nextInt( 8 ); + for ( int c = 0 ; c < nCylinders ; c++ ) { + final double xSize = rand.nextDouble( ) * 6.0D + 3.0D; + final double zSize = rand.nextDouble( ) * 6.0D + 3.0D; + final double xCenter = rand.nextDouble( ) * ( 16.0D - xSize - 2.0D ) + 1.0D + xSize / 2.0D; + final double zCenter = rand.nextDouble( ) * ( 16.0D - zSize - 2.0D ) + 1.0D + zSize / 2.0D; + final double xDelta = ( 8 - xCenter ) * .5f / shapeHeight; + final double zDelta = ( 8 - zCenter ) * .5f / shapeHeight; + + for ( int x = 1 ; x < 15 ; ++x ) { + for ( int z = 1 ; z < 15 ; ++z ) { + double xc = xCenter , zc = zCenter; + for ( int y = 1 ; y < shapeHeight - 1 ; ++y ) { + final double dx = ( x - xc ) / ( xSize / 2.0D ); + final double dz = ( z - zc ) / ( zSize / 2.0D ); + final double sqd = dx * dx + dz * dz; + + if ( sqd < 1.0D ) { + int rnd = rand.nextInt( 20 ); + int out; + switch ( rnd ) { + case 0: + out = SB_DIRT; + break; + case 1: + out = SB_GRAVEL; + break; + default: + out = SB_LIMESTONE; + break; + } + shape[ ( x * 16 + z ) * shapeHeight + y ] = out; + } + + xc += xDelta; + zc += zDelta; + } + } + } + } + return shape; + } + + + private boolean checkLiquids( final World worldIn , final BlockPos position , final BlockPos.MutableBlockPos mbp , + final int lastGroundY , final int shapeHeight , final int[] shape ) + { + for ( int x = 0 ; x < 16 ; ++x ) { + for ( int z = 0 ; z < 16 ; ++z ) { + mbp.setPos( position.getX( ) + x - 8 , 0 , position.getZ( ) + z - 8 ); + for ( int y = 0 ; y < shapeHeight ; y++ ) { + mbp.setY( lastGroundY + y ); + if ( shape[ ( x * 16 + z ) * shapeHeight + y ] != WGLimestoneChaos.SB_IGNORE + && worldIn.getBlockState( mbp ).getMaterial( ).isLiquid( ) ) { + return false; + } + } + } + } + return true; + } + + + private int checkAirBlocks( final World worldIn , final BlockPos position , final BlockPos.MutableBlockPos mbp , + final int lastGroundY , final int shapeHeight , final int[] shape ) + { + int airCount = 0; + for ( int x = 1 ; x < 15 ; ++x ) { + for ( int z = 1 ; z < 15 ; ++z ) { + mbp.setPos( position.getX( ) + x - 8 , 0 , position.getZ( ) + z - 8 ); + boolean inAir = true; + for ( int y = shapeHeight ; y > 1 ; y-- ) { + mbp.setY( lastGroundY + y ); + if ( worldIn.getBlockState( mbp ).getMaterial( ) != Material.AIR ) { + inAir = false; + } else { + airCount++; + } + if ( inAir ) { + final int v = shape[ ( x * 16 + z ) * shapeHeight + y ]; + if ( v != 0 ) { + shape[ ( x * 16 + z ) * shapeHeight + y ] += WGLimestoneChaos.SB_MAYBE; + } + } + } + } + } + return airCount; + } + + + private void digPit( final Random rand , final int shapeHeight , final int[] shape ) + { + for ( int x = 2 ; x < 14 ; ++x ) { + for ( int z = 2 ; z < 14 ; ++z ) { + if ( rand.nextInt( 32 ) == 0 ) { + continue; + } + + for ( int y = shapeHeight - 2 ; y > 1 + rand.nextInt( 3 ) ; --y ) { + final boolean digOk = WGLimestoneChaos.isSet( shape , shapeHeight , x , y , z ) // + && WGLimestoneChaos.isSet( shape , shapeHeight , x + 1 , y , z + 0 ) // + && WGLimestoneChaos.isSet( shape , shapeHeight , x + 1 , y , z + 1 ) // + && WGLimestoneChaos.isSet( shape , shapeHeight , x + 0 , y , z + 1 ) // + && WGLimestoneChaos.isSet( shape , shapeHeight , x - 1 , y , z + 1 ) // + && WGLimestoneChaos.isSet( shape , shapeHeight , x - 1 , y , z + 1 ) // + && WGLimestoneChaos.isSet( shape , shapeHeight , x - 1 , y , z - 1 ) // + && WGLimestoneChaos.isSet( shape , shapeHeight , x + 0 , y , z - 1 ) // + && WGLimestoneChaos.isSet( shape , shapeHeight , x + 1 , y , z - 1 ); + if ( digOk ) { + shape[ ( ( x + 0 ) * 16 + z + 0 ) * shapeHeight + y ] = WGLimestoneChaos.SB_HOLE; + if ( rand.nextInt( 64 ) == 0 ) { + break; + } + } + } + } + } + } + + + private void makePillars( final Random rand , final int shapeHeight , final int[] shape ) + { + for ( int x = 1 ; x < 15 ; ++x ) { + for ( int z = 1 ; z < 15 ; ++z ) { + for ( int y = 1 ; y <= shapeHeight ; y++ ) { + final int v = shape[ ( x * 16 + z ) * shapeHeight + y ]; + if ( v == WGLimestoneChaos.SB_IGNORE || v == WGLimestoneChaos.SB_HOLE ) { + break; + } + if ( v > WGLimestoneChaos.SB_MAYBE ) { + if ( rand.nextInt( 5 ) < 3 ) { + break; + } + shape[ ( x * 16 + z ) * shapeHeight + y ] = v - WGLimestoneChaos.SB_MAYBE; + } + } + } + } + } + + + private void addWaterHoles( final Random rand , final int shapeHeight , final int[] shape ) + { + for ( int x = 1 ; x < 15 ; ++x ) { + for ( int z = 1 ; z < 15 ; ++z ) { + for ( int y = 1 ; y <= shapeHeight ; y++ ) { + final boolean air = WGLimestoneChaos.isAir( shape , shapeHeight , x , y , z ); + if ( air ) { + final boolean waterOk = rand.nextInt( 3 ) == 0 // + && WGLimestoneChaos.canHoldWater( shape , shapeHeight , x + 1 , y , z ) // + && WGLimestoneChaos.canHoldWater( shape , shapeHeight , x - 1 , y , z ) // + && WGLimestoneChaos.canHoldWater( shape , shapeHeight , x , y , z + 1 ) // + && WGLimestoneChaos.canHoldWater( shape , shapeHeight , x , y , z - 1 ) // + && WGLimestoneChaos.canHoldWater( shape , shapeHeight , x , y - 1 , z ); + if ( waterOk ) { + shape[ ( x * 16 + z ) * shapeHeight + y ] = WGLimestoneChaos.SB_WATER; + } + break; + } + } + } + } + } + + + private static boolean isSet( final int[] shape , final int shapeHeight , final int x , final int y , final int z ) + { + final int value = shape[ ( x * 16 + z ) * shapeHeight + y ]; + return value != WGLimestoneChaos.SB_IGNORE; + } + + + private static boolean canHoldWater( final int[] shape , final int shapeHeight , final int x , final int y , + final int z ) + { + final int value = shape[ ( x * 16 + z ) * shapeHeight + y ]; + return value == WGLimestoneChaos.SB_DIRT || value == WGLimestoneChaos.SB_LIMESTONE; + } + + + private static boolean isAir( final int[] shape , final int shapeHeight , final int x , final int y , final int z ) + { + final int value = shape[ ( x * 16 + z ) * shapeHeight + y ]; + return value == WGLimestoneChaos.SB_IGNORE || value == WGLimestoneChaos.SB_HOLE + || value > WGLimestoneChaos.SB_MAYBE; + } + + + private void build( final World worldIn , final BlockPos position , final BlockPos.MutableBlockPos mbp , + final int lastGroundY , final int shapeHeight , final int[] shape ) + { + for ( int x = 0 ; x < 16 ; ++x ) { + for ( int z = 0 ; z < 16 ; ++z ) { + mbp.setPos( position.getX( ) + x - 8 , 0 , position.getZ( ) + z - 8 ); + for ( int y = 0 ; y < shapeHeight ; y++ ) { + mbp.setY( lastGroundY + y ); + switch ( shape[ ( x * 16 + z ) * shapeHeight + y ] ) { + default: + break; + + case SB_LIMESTONE: + worldIn.setBlockState( mbp , WGLimestoneChaos.BS_LIMESTONE , 2 ); + break; + case SB_DIRT: + worldIn.setBlockState( mbp , WGLimestoneChaos.BS_COARSE_DIRT , 2 ); + break; + case SB_GRAVEL: + worldIn.setBlockState( new BlockPos( mbp ) , WGLimestoneChaos.BS_GRAVEL , 2 ); + break; + case SB_WATER: + worldIn.setBlockState( mbp , WGLimestoneChaos.BS_WATER , 2 ); + break; + case SB_HOLE: + worldIn.setBlockState( mbp , WGLimestoneChaos.BS_AIR , 2 ); + break; + } + } + } + } + } + +}