From 2c38bbd4e0ba4123672979e154c3112174ddab97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Wed, 20 Jul 2016 20:11:18 +0200 Subject: [PATCH] Flora registration and generation Also, TOMATOES! --- src/java/mmm/core/CRegistry.java | 30 ++++- src/java/mmm/core/api/I_FloraRegistrar.java | 15 +++ .../mmm/core/api/world/I_BiomeWithFlora.java | 15 +++ .../mmm/core/api/world/I_LocationCheck.java | 32 +---- src/java/mmm/plants/PTomato.java | 28 ++++- src/java/mmm/world/WDefaultGenWatcher.java | 12 ++ src/java/mmm/world/WLocation.java | 8 ++ src/java/mmm/world/WLocationRainfall.java | 38 ++++++ src/java/mmm/world/WLocationTemperature.java | 38 ++++++ src/java/mmm/world/gen/WGFlora.java | 109 ++++++++++++++++++ src/java/mmm/world/gen/WGFloraParameters.java | 62 ++++++++++ 11 files changed, 353 insertions(+), 34 deletions(-) create mode 100644 src/java/mmm/core/api/I_FloraRegistrar.java create mode 100644 src/java/mmm/core/api/world/I_BiomeWithFlora.java create mode 100644 src/java/mmm/world/WLocationRainfall.java create mode 100644 src/java/mmm/world/WLocationTemperature.java create mode 100644 src/java/mmm/world/gen/WGFlora.java create mode 100644 src/java/mmm/world/gen/WGFloraParameters.java diff --git a/src/java/mmm/core/CRegistry.java b/src/java/mmm/core/CRegistry.java index 1237085..c25e101 100644 --- a/src/java/mmm/core/CRegistry.java +++ b/src/java/mmm/core/CRegistry.java @@ -8,6 +8,7 @@ import java.util.HashMap; import java.util.HashSet; import mmm.Mmm; +import mmm.core.api.I_FloraRegistrar; import mmm.core.api.I_OreGenerationRegistrar; import mmm.core.api.I_RecipeRegistrar; import mmm.core.api.I_RequiresClientInit; @@ -64,6 +65,8 @@ public class CRegistry private static final HashSet< I_RecipeRegistrar > RECIPE_REGISTRARS = new HashSet<>( ); private static final HashSet< I_OreGenerationRegistrar > ORE_GEN_REGISTRARS = new HashSet<>( ); + private static final HashSet< I_FloraRegistrar > FLORA_REGISTRARS = new HashSet<>( ); + private static final HashSet< Item > ITEMS = new HashSet< Item >( ); private static final HashSet< Block > BLOCKS = new HashSet< Block >( ); @@ -114,7 +117,7 @@ public class CRegistry { if ( CRegistry.ITEMS.add( item ) ) { GameRegistry.register( item ); - CRegistry.addRecipeRegistrar( item ); + CRegistry.addRegistrar( item ); if ( item instanceof I_RequiresClientInit ) { CRegistry.ITEMS_CLIENT_INIT.add( item ); } @@ -139,8 +142,7 @@ public class CRegistry { if ( CRegistry.BLOCKS.add( block ) ) { GameRegistry.register( block ); - CRegistry.addRecipeRegistrar( block ); - CRegistry.addOreGenerationRegistrar( block ); + CRegistry.addRegistrar( block ); if ( block instanceof I_RequiresClientPreInit ) { CRegistry.BLOCKS_CLIENT_PREINIT.add( block ); } @@ -186,6 +188,14 @@ public class CRegistry } + public static void addRegistrar( final Object object ) + { + CRegistry.addRecipeRegistrar( object ); + CRegistry.addOreGenerationRegistrar( object ); + CRegistry.addFloraRegistrar( object ); + } + + public static void addRecipeRegistrar( final Object object ) { if ( object instanceof I_RecipeRegistrar ) { @@ -202,12 +212,26 @@ public class CRegistry } + public static void addFloraRegistrar( final Object object ) + { + if ( object instanceof I_FloraRegistrar ) { + CRegistry.FLORA_REGISTRARS.add( (I_FloraRegistrar) object ); + } + } + + public static Collection< I_OreGenerationRegistrar > getOreGenerationRegistrars( ) { return Collections.unmodifiableCollection( CRegistry.ORE_GEN_REGISTRARS ); } + public static Collection< I_FloraRegistrar > getFloraRegistrars( ) + { + return Collections.unmodifiableCollection( CRegistry.FLORA_REGISTRARS ); + } + + public static void registerRecipes( ) { for ( final I_RecipeRegistrar registrar : CRegistry.RECIPE_REGISTRARS ) { diff --git a/src/java/mmm/core/api/I_FloraRegistrar.java b/src/java/mmm/core/api/I_FloraRegistrar.java new file mode 100644 index 0000000..722c32d --- /dev/null +++ b/src/java/mmm/core/api/I_FloraRegistrar.java @@ -0,0 +1,15 @@ +package mmm.core.api; + + +import java.util.List; + +import mmm.world.gen.WGFloraParameters; + + + +public interface I_FloraRegistrar +{ + + public void getFloraGeneration( List< WGFloraParameters > output ); + +} diff --git a/src/java/mmm/core/api/world/I_BiomeWithFlora.java b/src/java/mmm/core/api/world/I_BiomeWithFlora.java new file mode 100644 index 0000000..ca3be90 --- /dev/null +++ b/src/java/mmm/core/api/world/I_BiomeWithFlora.java @@ -0,0 +1,15 @@ +package mmm.core.api.world; + + +import java.util.List; + +import mmm.world.gen.WGFloraParameters; + + + +public interface I_BiomeWithFlora +{ + + public void addFloraParameters( List< WGFloraParameters > output ); + +} diff --git a/src/java/mmm/core/api/world/I_LocationCheck.java b/src/java/mmm/core/api/world/I_LocationCheck.java index 3229037..4a2af86 100644 --- a/src/java/mmm/core/api/world/I_LocationCheck.java +++ b/src/java/mmm/core/api/world/I_LocationCheck.java @@ -14,45 +14,19 @@ public interface I_LocationCheck default I_LocationCheck and( final I_LocationCheck other ) { - final I_LocationCheck self = this; - return new I_LocationCheck( ) { - @Override - public boolean checkLocation( final World world , final int chunkX , final int chunkZ , - final IChunkProvider provider ) - { - return self.checkLocation( world , chunkX , chunkZ , provider ) - && other.checkLocation( world , chunkX , chunkZ , provider ); - } - }; + return ( w , x , z , p ) -> this.checkLocation( w , x , z , p ) && other.checkLocation( w , x , z , p ); } default I_LocationCheck or( final I_LocationCheck other ) { - final I_LocationCheck self = this; - return new I_LocationCheck( ) { - @Override - public boolean checkLocation( final World world , final int chunkX , final int chunkZ , - final IChunkProvider provider ) - { - return self.checkLocation( world , chunkX , chunkZ , provider ) - || other.checkLocation( world , chunkX , chunkZ , provider ); - } - }; + return ( w , x , z , p ) -> this.checkLocation( w , x , z , p ) || other.checkLocation( w , x , z , p ); } default I_LocationCheck invert( ) { - final I_LocationCheck self = this; - return new I_LocationCheck( ) { - @Override - public boolean checkLocation( final World world , final int chunkX , final int chunkZ , - final IChunkProvider provider ) - { - return !self.checkLocation( world , chunkX , chunkZ , provider ); - } - }; + return ( w , x , z , p ) -> !this.checkLocation( w , x , z , p ); } } diff --git a/src/java/mmm/plants/PTomato.java b/src/java/mmm/plants/PTomato.java index 2bac0ff..8586cef 100644 --- a/src/java/mmm/plants/PTomato.java +++ b/src/java/mmm/plants/PTomato.java @@ -8,9 +8,14 @@ import java.util.Random; import javax.annotation.Nullable; import mmm.core.CRegistry; +import mmm.core.api.I_FloraRegistrar; import mmm.core.api.I_RecipeRegistrar; import mmm.core.api.blocks.I_StateMapperProvider; import mmm.utils.UMaths; +import mmm.world.WLocation; +import mmm.world.WLocationRainfall; +import mmm.world.WLocationTemperature; +import mmm.world.gen.WGFloraParameters; import net.minecraft.block.Block; import net.minecraft.block.BlockBush; import net.minecraft.block.IGrowable; @@ -40,7 +45,7 @@ import net.minecraftforge.fml.common.registry.GameRegistry; public class PTomato - implements I_RecipeRegistrar + implements I_RecipeRegistrar , I_FloraRegistrar { public static final PropertyInteger AGE = PropertyInteger.create( "age" , 0 , 15 ); public static final PropertyInteger SIZE = PropertyInteger.create( "size" , 0 , 3 ); @@ -401,7 +406,7 @@ public class PTomato CRegistry.addBlock( this.CROP = new Plant( ) , null ); this.SEEDS = PPlantsHelper.makeSeeds( "tomato" , this.CROP ); this.FRUIT = PPlantsHelper.makeFruit( "tomato" , 2 , .15f ); - CRegistry.addRecipeRegistrar( this ); + CRegistry.addRegistrar( this ); } @@ -412,4 +417,23 @@ public class PTomato new ItemStack( this.FRUIT ) ); } + + @Override + public void getFloraGeneration( final List< WGFloraParameters > output ) + { + output.add( new WGFloraParameters( this.WILD.getDefaultState( ) , 1 , + WLocation.inOverworld( )// + .and( new WLocationTemperature( 0.4f , 1f ) ) // + .and( new WLocationRainfall( 0.2f , 0.8f ) ) ) ); + output.add( new WGFloraParameters( this.WILD.getDefaultState( ) , 1 , + WLocation.inOverworld( )// + .and( new WLocationTemperature( 0.7f , 1f ) ) // + .and( new WLocationRainfall( 0.3f , 0.5f ) ) ) ); + output.add( new WGFloraParameters( // + this.WILD.getDefaultState( ).withProperty( PTomato.WITH_FRUITS , true ) , 1 , + WLocation.inOverworld( )// + .and( new WLocationTemperature( 0.8f , 0.9f ) ) // + .and( new WLocationRainfall( 0.4f , 0.5f ) ) ) ); + } + } diff --git a/src/java/mmm/world/WDefaultGenWatcher.java b/src/java/mmm/world/WDefaultGenWatcher.java index aabfe09..1deffdf 100644 --- a/src/java/mmm/world/WDefaultGenWatcher.java +++ b/src/java/mmm/world/WDefaultGenWatcher.java @@ -6,11 +6,13 @@ import java.util.Random; import mmm.core.api.world.I_DefaultPopulateHandler; import mmm.core.api.world.I_TrappedBiome; import mmm.world.gen.WGBasalt; +import mmm.world.gen.WGFlora; import mmm.world.gen.WGTrapBlocks; import net.minecraft.util.math.BlockPos; import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.BiomeDesert; import net.minecraft.world.biome.BiomeSwamp; +import net.minecraftforge.event.terraingen.DecorateBiomeEvent; import net.minecraftforge.event.terraingen.PopulateChunkEvent; import net.minecraftforge.fml.common.eventhandler.Event.Result; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @@ -19,6 +21,8 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; public class WDefaultGenWatcher { + private final WGFlora floraGenerator = new WGFlora( ); + @SubscribeEvent public void onPopulate( final PopulateChunkEvent.Populate event ) @@ -61,4 +65,12 @@ public class WDefaultGenWatcher traps.generate( world , rand , bp ); } + + @SubscribeEvent + public void onBiomeDecorate( DecorateBiomeEvent.Decorate event ) + { + if ( event.getType( ) == DecorateBiomeEvent.Decorate.EventType.GRASS ) { + this.floraGenerator.generate( event.getWorld( ) , event.getRand( ) , event.getPos( ) ); + } + } } diff --git a/src/java/mmm/world/WLocation.java b/src/java/mmm/world/WLocation.java index 010238d..148aeda 100644 --- a/src/java/mmm/world/WLocation.java +++ b/src/java/mmm/world/WLocation.java @@ -8,6 +8,8 @@ import net.minecraft.world.biome.Biome; public class WLocation { + private static final I_LocationCheck ANYWHERE = ( w , x , z , p ) -> true; + private static I_LocationCheck inOverworld; private static I_LocationCheck inTheNether; @@ -40,4 +42,10 @@ public class WLocation { return new WLocationInBiomeClass<>( biomeType ); } + + + public static I_LocationCheck anywhere( ) + { + return WLocation.ANYWHERE; + } } diff --git a/src/java/mmm/world/WLocationRainfall.java b/src/java/mmm/world/WLocationRainfall.java new file mode 100644 index 0000000..e5f701c --- /dev/null +++ b/src/java/mmm/world/WLocationRainfall.java @@ -0,0 +1,38 @@ +package mmm.world; + + +import mmm.core.api.world.I_LocationCheck; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.chunk.IChunkProvider; + + + +public class WLocationRainfall + implements I_LocationCheck +{ + public final float minRainfall; + public final float maxRainfall; + + + public WLocationRainfall( final float minRainfall , final float maxRainfall ) + { + if ( maxRainfall < minRainfall ) { + throw new IllegalArgumentException( "minimal rainfall is higher than maximal rainfall" ); + } + this.minRainfall = minRainfall; + this.maxRainfall = maxRainfall; + } + + + @Override + public boolean checkLocation( final World world , final int chunkX , final int chunkZ , + final IChunkProvider provider ) + { + final Biome biome = world.getBiomeGenForCoords( new BlockPos( chunkX * 16 , 0 , chunkZ * 16 ) ); + final float rf = biome.getRainfall( ); + return rf >= this.minRainfall && rf <= this.maxRainfall; + } + +} diff --git a/src/java/mmm/world/WLocationTemperature.java b/src/java/mmm/world/WLocationTemperature.java new file mode 100644 index 0000000..e34d3df --- /dev/null +++ b/src/java/mmm/world/WLocationTemperature.java @@ -0,0 +1,38 @@ +package mmm.world; + + +import mmm.core.api.world.I_LocationCheck; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.chunk.IChunkProvider; + + + +public class WLocationTemperature + implements I_LocationCheck +{ + public final float minTemperature; + public final float maxTemperature; + + + public WLocationTemperature( final float minTemperature , final float maxTemperature ) + { + if ( maxTemperature < minTemperature ) { + throw new IllegalArgumentException( "minimal temperature is higher than maximal temperature" ); + } + this.minTemperature = minTemperature; + this.maxTemperature = maxTemperature; + } + + + @Override + public boolean checkLocation( final World world , final int chunkX , final int chunkZ , + final IChunkProvider provider ) + { + final Biome biome = world.getBiomeGenForCoords( new BlockPos( chunkX * 16 , 0 , chunkZ * 16 ) ); + final float t = biome.getTemperature( ); + return t >= this.minTemperature && t <= this.maxTemperature; + } + +} diff --git a/src/java/mmm/world/gen/WGFlora.java b/src/java/mmm/world/gen/WGFlora.java new file mode 100644 index 0000000..141b2b5 --- /dev/null +++ b/src/java/mmm/world/gen/WGFlora.java @@ -0,0 +1,109 @@ +package mmm.world.gen; + + +import java.util.ArrayList; +import java.util.Random; + +import mmm.core.CRegistry; +import mmm.core.api.I_FloraRegistrar; +import mmm.core.api.world.I_BiomeWithFlora; +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.gen.feature.WorldGenerator; + + + +public class WGFlora + extends WorldGenerator +{ + + private final ArrayList< WGFloraParameters > allConditions; + + + public WGFlora( ) + { + final ArrayList< WGFloraParameters > conditions = new ArrayList<>( ); + for ( final I_FloraRegistrar registrar : CRegistry.getFloraRegistrars( ) ) { + registrar.getFloraGeneration( conditions ); + } + this.allConditions = conditions; + } + + + @Override + public boolean generate( final World worldIn , final Random rand , final BlockPos position ) + { + final ArrayList< WGFloraParameters > candidates = this.getValidFlora( worldIn , position ); + final int nCandidates = candidates.size( ); + if ( nCandidates == 0 ) { + return false; + } + + for ( int i = 0 ; i < nCandidates ; i++ ) { + this.tryGenerate( worldIn , rand , position , candidates.get( i ) ); + } + return true; + } + + + private ArrayList< WGFloraParameters > getValidFlora( final World worldIn , final BlockPos position ) + { + final ArrayList< WGFloraParameters > output = new ArrayList<>( ); + for ( final WGFloraParameters item : this.allConditions ) { + if ( item.location.checkLocation( worldIn , position.getX( ) >> 4 , position.getZ( ) >> 4 , + worldIn.getChunkProvider( ) ) ) { + output.add( item ); + } + } + + final Biome biome = worldIn.getBiomeGenForCoords( position ); + if ( biome instanceof I_BiomeWithFlora ) { + ( (I_BiomeWithFlora) biome ).addFloraParameters( output ); + } + + return output; + } + + + private void tryGenerate( final World worldIn , final Random rand , final BlockPos position , + final WGFloraParameters parameters ) + { + for ( int i = 0 ; i < parameters.perChunk ; ++i ) { + final int x = rand.nextInt( 16 ) + 8; + final int z = rand.nextInt( 16 ) + 8; + + final int height = worldIn.getHeight( position.add( x , 0 , z ) ).getY( ) * 2; + if ( height <= 0 ) { + continue; + } + + this.tryGeneratePlant( worldIn , rand , position.add( x , rand.nextInt( height ) , z ) , parameters ); + } + } + + + private void tryGeneratePlant( final World worldIn , final Random rand , BlockPos position , + final WGFloraParameters parameters ) + { + IBlockState bs = worldIn.getBlockState( position ); + while ( ( bs.getBlock( ).isAir( bs , worldIn , position ) + || bs.getBlock( ).isLeaves( bs , worldIn , position ) ) && position.getY( ) > 0 ) { + position = position.down( ); + bs = worldIn.getBlockState( position ); + } + + for ( int i = 0 ; i < 128 ; ++i ) { + final BlockPos blockpos = position.add( // + rand.nextInt( 8 ) - rand.nextInt( 8 ) , // + rand.nextInt( 4 ) - rand.nextInt( 4 ) , // + rand.nextInt( 8 ) - rand.nextInt( 8 ) ); + if ( parameters.placementCheck.test( worldIn , blockpos ) ) { + worldIn.setBlockState( blockpos , parameters.floraType , 2 ); + break; + } + } + } + +} diff --git a/src/java/mmm/world/gen/WGFloraParameters.java b/src/java/mmm/world/gen/WGFloraParameters.java new file mode 100644 index 0000000..0dff406 --- /dev/null +++ b/src/java/mmm/world/gen/WGFloraParameters.java @@ -0,0 +1,62 @@ +package mmm.world.gen; + + +import java.util.function.BiPredicate; + +import mmm.core.api.world.I_LocationCheck; +import mmm.world.WLocation; +import net.minecraft.block.Block; +import net.minecraft.block.BlockBush; +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + + + +public class WGFloraParameters +{ + + private static BiPredicate< World , BlockPos > getDefaultPlacementCheck( final IBlockState bs ) + { + final Block block = bs.getBlock( ); + if ( block instanceof BlockBush ) { + return ( w , p ) -> w.isAirBlock( p ) && ( (BlockBush) block ).canBlockStay( w , p , bs ); + } + return ( w , p ) -> w.isAirBlock( p ) && !w.isAirBlock( p.down( ) ); + } + + public final IBlockState floraType; + public final int perChunk; + public final I_LocationCheck location; + public final BiPredicate< World , BlockPos > placementCheck; + + + public WGFloraParameters( final IBlockState floraType , final int perChunk ) + { + this( floraType , perChunk , WLocation.anywhere( ) , WGFloraParameters.getDefaultPlacementCheck( floraType ) ); + } + + + public WGFloraParameters( final IBlockState floraType , final int perChunk , + final BiPredicate< World , BlockPos > placementCheck ) + { + this( floraType , perChunk , WLocation.anywhere( ) , placementCheck ); + } + + + public WGFloraParameters( final IBlockState floraType , final int perChunk , final I_LocationCheck location ) + { + this( floraType , perChunk , location , WGFloraParameters.getDefaultPlacementCheck( floraType ) ); + } + + + public WGFloraParameters( final IBlockState floraType , final int perChunk , final I_LocationCheck location , + final BiPredicate< World , BlockPos > placementCheck ) + { + this.floraType = floraType; + this.perChunk = perChunk; + this.location = location; + this.placementCheck = placementCheck; + } + +}