Flora registration and generation

Also, TOMATOES!
This commit is contained in:
Emmanuel BENOîT 2016-07-20 20:11:18 +02:00
parent 2bb8764543
commit 2c38bbd4e0
11 changed files with 353 additions and 34 deletions

View file

@ -8,6 +8,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import mmm.Mmm; import mmm.Mmm;
import mmm.core.api.I_FloraRegistrar;
import mmm.core.api.I_OreGenerationRegistrar; import mmm.core.api.I_OreGenerationRegistrar;
import mmm.core.api.I_RecipeRegistrar; import mmm.core.api.I_RecipeRegistrar;
import mmm.core.api.I_RequiresClientInit; 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_RecipeRegistrar > RECIPE_REGISTRARS = new HashSet<>( );
private static final HashSet< I_OreGenerationRegistrar > ORE_GEN_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< Item > ITEMS = new HashSet< Item >( );
private static final HashSet< Block > BLOCKS = new HashSet< Block >( ); private static final HashSet< Block > BLOCKS = new HashSet< Block >( );
@ -114,7 +117,7 @@ public class CRegistry
{ {
if ( CRegistry.ITEMS.add( item ) ) { if ( CRegistry.ITEMS.add( item ) ) {
GameRegistry.register( item ); GameRegistry.register( item );
CRegistry.addRecipeRegistrar( item ); CRegistry.addRegistrar( item );
if ( item instanceof I_RequiresClientInit ) { if ( item instanceof I_RequiresClientInit ) {
CRegistry.ITEMS_CLIENT_INIT.add( item ); CRegistry.ITEMS_CLIENT_INIT.add( item );
} }
@ -139,8 +142,7 @@ public class CRegistry
{ {
if ( CRegistry.BLOCKS.add( block ) ) { if ( CRegistry.BLOCKS.add( block ) ) {
GameRegistry.register( block ); GameRegistry.register( block );
CRegistry.addRecipeRegistrar( block ); CRegistry.addRegistrar( block );
CRegistry.addOreGenerationRegistrar( block );
if ( block instanceof I_RequiresClientPreInit ) { if ( block instanceof I_RequiresClientPreInit ) {
CRegistry.BLOCKS_CLIENT_PREINIT.add( block ); 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 ) public static void addRecipeRegistrar( final Object object )
{ {
if ( object instanceof I_RecipeRegistrar ) { 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( ) public static Collection< I_OreGenerationRegistrar > getOreGenerationRegistrars( )
{ {
return Collections.unmodifiableCollection( CRegistry.ORE_GEN_REGISTRARS ); return Collections.unmodifiableCollection( CRegistry.ORE_GEN_REGISTRARS );
} }
public static Collection< I_FloraRegistrar > getFloraRegistrars( )
{
return Collections.unmodifiableCollection( CRegistry.FLORA_REGISTRARS );
}
public static void registerRecipes( ) public static void registerRecipes( )
{ {
for ( final I_RecipeRegistrar registrar : CRegistry.RECIPE_REGISTRARS ) { for ( final I_RecipeRegistrar registrar : CRegistry.RECIPE_REGISTRARS ) {

View file

@ -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 );
}

View file

@ -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 );
}

View file

@ -14,45 +14,19 @@ public interface I_LocationCheck
default I_LocationCheck and( final I_LocationCheck other ) default I_LocationCheck and( final I_LocationCheck other )
{ {
final I_LocationCheck self = this; return ( w , x , z , p ) -> this.checkLocation( w , x , z , p ) && other.checkLocation( w , x , z , p );
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 );
}
};
} }
default I_LocationCheck or( final I_LocationCheck other ) default I_LocationCheck or( final I_LocationCheck other )
{ {
final I_LocationCheck self = this; return ( w , x , z , p ) -> this.checkLocation( w , x , z , p ) || other.checkLocation( w , x , z , p );
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 );
}
};
} }
default I_LocationCheck invert( ) default I_LocationCheck invert( )
{ {
final I_LocationCheck self = this; return ( w , x , z , p ) -> !this.checkLocation( w , x , z , p );
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 );
}
};
} }
} }

View file

@ -8,9 +8,14 @@ import java.util.Random;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import mmm.core.CRegistry; import mmm.core.CRegistry;
import mmm.core.api.I_FloraRegistrar;
import mmm.core.api.I_RecipeRegistrar; import mmm.core.api.I_RecipeRegistrar;
import mmm.core.api.blocks.I_StateMapperProvider; import mmm.core.api.blocks.I_StateMapperProvider;
import mmm.utils.UMaths; 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.Block;
import net.minecraft.block.BlockBush; import net.minecraft.block.BlockBush;
import net.minecraft.block.IGrowable; import net.minecraft.block.IGrowable;
@ -40,7 +45,7 @@ import net.minecraftforge.fml.common.registry.GameRegistry;
public class PTomato 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 AGE = PropertyInteger.create( "age" , 0 , 15 );
public static final PropertyInteger SIZE = PropertyInteger.create( "size" , 0 , 3 ); public static final PropertyInteger SIZE = PropertyInteger.create( "size" , 0 , 3 );
@ -401,7 +406,7 @@ public class PTomato
CRegistry.addBlock( this.CROP = new Plant( ) , null ); CRegistry.addBlock( this.CROP = new Plant( ) , null );
this.SEEDS = PPlantsHelper.makeSeeds( "tomato" , this.CROP ); this.SEEDS = PPlantsHelper.makeSeeds( "tomato" , this.CROP );
this.FRUIT = PPlantsHelper.makeFruit( "tomato" , 2 , .15f ); this.FRUIT = PPlantsHelper.makeFruit( "tomato" , 2 , .15f );
CRegistry.addRecipeRegistrar( this ); CRegistry.addRegistrar( this );
} }
@ -412,4 +417,23 @@ public class PTomato
new ItemStack( this.FRUIT ) ); 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 ) ) ) );
}
} }

View file

@ -6,11 +6,13 @@ import java.util.Random;
import mmm.core.api.world.I_DefaultPopulateHandler; import mmm.core.api.world.I_DefaultPopulateHandler;
import mmm.core.api.world.I_TrappedBiome; import mmm.core.api.world.I_TrappedBiome;
import mmm.world.gen.WGBasalt; import mmm.world.gen.WGBasalt;
import mmm.world.gen.WGFlora;
import mmm.world.gen.WGTrapBlocks; import mmm.world.gen.WGTrapBlocks;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeDesert; import net.minecraft.world.biome.BiomeDesert;
import net.minecraft.world.biome.BiomeSwamp; import net.minecraft.world.biome.BiomeSwamp;
import net.minecraftforge.event.terraingen.DecorateBiomeEvent;
import net.minecraftforge.event.terraingen.PopulateChunkEvent; import net.minecraftforge.event.terraingen.PopulateChunkEvent;
import net.minecraftforge.fml.common.eventhandler.Event.Result; import net.minecraftforge.fml.common.eventhandler.Event.Result;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@ -19,6 +21,8 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
public class WDefaultGenWatcher public class WDefaultGenWatcher
{ {
private final WGFlora floraGenerator = new WGFlora( );
@SubscribeEvent @SubscribeEvent
public void onPopulate( final PopulateChunkEvent.Populate event ) public void onPopulate( final PopulateChunkEvent.Populate event )
@ -61,4 +65,12 @@ public class WDefaultGenWatcher
traps.generate( world , rand , bp ); 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( ) );
}
}
} }

View file

@ -8,6 +8,8 @@ import net.minecraft.world.biome.Biome;
public class WLocation public class WLocation
{ {
private static final I_LocationCheck ANYWHERE = ( w , x , z , p ) -> true;
private static I_LocationCheck inOverworld; private static I_LocationCheck inOverworld;
private static I_LocationCheck inTheNether; private static I_LocationCheck inTheNether;
@ -40,4 +42,10 @@ public class WLocation
{ {
return new WLocationInBiomeClass<>( biomeType ); return new WLocationInBiomeClass<>( biomeType );
} }
public static I_LocationCheck anywhere( )
{
return WLocation.ANYWHERE;
}
} }

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}
}

View file

@ -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;
}
}