diff --git a/src/java/mmm/materials/A_MTreeGenerator.java b/src/java/mmm/materials/A_MTreeGenerator.java new file mode 100644 index 0000000..5b2f2ef --- /dev/null +++ b/src/java/mmm/materials/A_MTreeGenerator.java @@ -0,0 +1,198 @@ +package mmm.materials; + + +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.WorldGenAbstractTree; + + + +public abstract class A_MTreeGenerator + extends WorldGenAbstractTree +{ + public static class RuntimeData + { + public final BlockPos corner; + public final int xSize; + public final int zSize; + public final int height; + protected boolean mustBeEmpty[]; + protected IBlockState blocks[]; + + + public RuntimeData( final BlockPos centre , final int radius , final int height ) + { + this( centre.add( -radius , 0 , -radius ) , radius * 2 + 1 , radius * 2 + 1 , height ); + } + + + public RuntimeData( final BlockPos corner , final int xSize , final int zSize , final int height ) + { + this.corner = corner; + this.xSize = xSize; + this.zSize = zSize; + this.height = height; + } + + + private void allocateData( ) + { + this.mustBeEmpty = new boolean[ this.xSize * this.zSize * this.height ]; + this.blocks = new IBlockState[ this.xSize * this.zSize * this.height ]; + } + + + protected int getOffset( final int i , final int j , final int k ) + { + return i + this.xSize * ( j + this.height * k ); + } + + + public boolean mustBeEmpty( final int i , final int j , final int k ) + { + return this.mustBeEmpty[ this.getOffset( i , j , k ) ]; + } + + + public IBlockState getBlockState( final int i , final int j , final int k ) + { + return this.blocks[ this.getOffset( i , j , k ) ]; + } + + + public void setBlock( final int i , final int j , final int k , final Block block , final boolean mustBeEmpty ) + { + this.setBlock( i , j , k , block.getDefaultState( ) , mustBeEmpty ); + } + + + public void setBlock( final int i , final int j , final int k , final IBlockState block , + final boolean mustBeEmpty ) + { + final int offset = this.getOffset( i , j , k ); + this.blocks[ offset ] = block; + this.mustBeEmpty[ offset ] = mustBeEmpty; + } + + + public void clearBlock( final int i , final int j , final int k ) + { + final int offset = this.getOffset( i , j , k ); + this.blocks[ offset ] = null; + this.mustBeEmpty[ offset ] = false; + } + + + public void removeCornerLeaves( final Random rand , final IBlockState leaves , final int startY , + final int endY , final float chance ) + { + for ( int y = startY ; y <= endY ; y++ ) { + for ( int x = 0 ; x < this.xSize ; x++ ) { + for ( int z = 0 ; z < this.zSize ; z++ ) { + final IBlockState bs = this.getBlockState( x , y , z ); + if ( bs != leaves ) { + continue; + } + + final boolean xp = this.isEmpty( x + 1 , y , z ); + final boolean xn = this.isEmpty( x - 1 , y , z ); + final boolean yp = this.isEmpty( x , y + 1 , z ); + final boolean yn = this.isEmpty( x , y - 1 , z ); + final boolean zp = this.isEmpty( x , y , z + 1 ); + final boolean zn = this.isEmpty( x , y , z - 1 ); + if ( xp ^ xn && yp ^ yn && zp ^ zn && rand.nextFloat( ) < chance ) { + this.clearBlock( x , y , z ); + } + } + } + } + } + + + private boolean isEmpty( final int x , final int y , final int z ) + { + if ( x < 0 || x >= this.xSize || y < 0 || y >= this.height || z < 0 || z >= this.zSize ) { + return true; + } + final IBlockState bs = this.getBlockState( x , y , z ); + return bs == null || bs.getMaterial( ) == Material.AIR; + } + + } + + private MWood wood; + + + public A_MTreeGenerator( final boolean notify ) + { + super( notify ); + } + + + public MWood getWood( ) + { + return this.wood; + } + + + void setWood( final MWood wood ) + { + this.wood = wood; + } + + + @Override + public boolean generate( final World worldIn , final Random rand , final BlockPos position ) + { + if ( position.getY( ) < 1 || !this.wood.canSaplingStay( worldIn , position ) ) { + return false; + } + + final RuntimeData rtd = this.determineTreeSize( position , rand ); + if ( rtd == null || position.getY( ) + 1 + rtd.height > 256 ) { + return false; + } + rtd.allocateData( ); + this.generateTreeBlocks( rtd , rand ); + + final BlockPos.MutableBlockPos mbp = new BlockPos.MutableBlockPos( ); + for ( int i = 0 ; i < rtd.xSize ; i++ ) { + for ( int j = 0 ; j < rtd.height ; j++ ) { + for ( int k = 0 ; k < rtd.zSize ; k++ ) { + if ( !rtd.mustBeEmpty( i , j , k ) ) { + continue; + } + mbp.setPos( rtd.corner.getX( ) + i , rtd.corner.getY( ) + j , rtd.corner.getZ( ) + k ); + if ( !this.isReplaceable( worldIn , mbp ) ) { + return false; + } + } + } + } + + for ( int i = 0 ; i < rtd.xSize ; i++ ) { + for ( int j = 0 ; j < rtd.height ; j++ ) { + for ( int k = 0 ; k < rtd.zSize ; k++ ) { + final IBlockState state = rtd.getBlockState( i , j , k ); + if ( state != null ) { + final BlockPos blockPos = rtd.corner.add( i , j , k ); + this.setBlockAndNotifyAdequately( worldIn , blockPos , state ); + } + } + } + } + return true; + } + + + protected abstract RuntimeData determineTreeSize( BlockPos position , Random rand ); + + + protected abstract void generateTreeBlocks( RuntimeData rtd , Random rand ); + +} diff --git a/src/java/mmm/materials/MHeveaGenerator.java b/src/java/mmm/materials/MHeveaGenerator.java new file mode 100644 index 0000000..2bbfc69 --- /dev/null +++ b/src/java/mmm/materials/MHeveaGenerator.java @@ -0,0 +1,78 @@ +package mmm.materials; + + +import java.util.Random; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.math.BlockPos; + + + +public class MHeveaGenerator + extends A_MTreeGenerator +{ + + public MHeveaGenerator( final boolean notify ) + { + super( notify ); + } + + + @Override + protected RuntimeData determineTreeSize( final BlockPos position , final Random rand ) + { + final int leavesHeight = rand.nextInt( 2 ) + 2; + final int totalHeight = 1 + rand.nextInt( 2 ) + leavesHeight * 5 / 2; + return new RuntimeData( position , leavesHeight , totalHeight ); + } + + + @Override + protected void generateTreeBlocks( final RuntimeData rtd , final Random rand ) + { + final int leavesHeight = ( rtd.xSize - 1 ) / 2; + final int totalLeavesHeight = leavesHeight * 5 / 2; + final int trunkBottom = rtd.height - totalLeavesHeight; + final int lowerPart = trunkBottom + leavesHeight * 2; + final int centre = leavesHeight; + final int trunkHeight = Math.max( trunkBottom + 1 , rtd.height - ( 1 + rand.nextInt( leavesHeight ) ) ); + + // Lower part of the leaves + IBlockState leaves = this.getWood( ).LEAVES.getDefaultState( ).withProperty( MLeaves.CHECK_DECAY , false ); + for ( int y = trunkBottom , i = 0 ; y < lowerPart ; y++ , i++ ) { + final int radius = ( i >> 1 ) + 1; + final int rSquare = radius * radius + ( i & 1 ); + for ( int x = -radius ; x <= radius ; x++ ) { + for ( int z = -radius ; z <= radius ; z++ ) { + if ( ( x != 0 || z != 0 ) && x * x + z * z <= rSquare ) { + rtd.setBlock( centre + x , y , centre + z , leaves , false ); + } + } + } + } + + // Higher part of the leaves + for ( int y = lowerPart , radius = leavesHeight - 1 ; y < rtd.height ; y++ , radius -= 2 ) { + if ( radius <= 0 ) { + radius = 1; + } + final int rSquare = radius * radius + 1; + for ( int x = -radius ; x <= radius ; x++ ) { + for ( int z = -radius ; z <= radius ; z++ ) { + if ( ( x != centre || z != centre || y >= trunkHeight ) && x * x + z * z <= rSquare ) { + rtd.setBlock( centre + x , y , centre + z , leaves , y == rtd.height - 1 ); + } + } + } + } + + // Randomly remove leaves from corners + rtd.removeCornerLeaves( rand , leaves , trunkBottom , rtd.height - 1 , .4f ); + + // Trunk + for ( int y = 0 ; y < trunkHeight ; y++ ) { + rtd.setBlock( centre , y , centre , this.getWood( ).LOG , true ); + } + } + +} diff --git a/src/java/mmm/materials/MLeaves.java b/src/java/mmm/materials/MLeaves.java index 85eb16e..1093440 100644 --- a/src/java/mmm/materials/MLeaves.java +++ b/src/java/mmm/materials/MLeaves.java @@ -65,10 +65,7 @@ public class MLeaves @Override public Item getItemDropped( final IBlockState state , final Random rand , final int fortune ) { - // LOL NO FIXME - // Should be - // return Item.getItemFromBlock( this.wood.SAPLING ); - return Item.getItemFromBlock( Blocks.SAPLING ); + return Item.getItemFromBlock( this.wood.SAPLING ); } diff --git a/src/java/mmm/materials/MSapling.java b/src/java/mmm/materials/MSapling.java index bcf1fae..1e7ee5f 100644 --- a/src/java/mmm/materials/MSapling.java +++ b/src/java/mmm/materials/MSapling.java @@ -11,6 +11,7 @@ import net.minecraft.block.material.Material; import net.minecraft.block.properties.PropertyInteger; import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; +import net.minecraft.creativetab.CreativeTabs; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.util.BlockRenderLayer; @@ -41,6 +42,7 @@ public class MSapling this.setTickRandomly( true ); this.setHardness( 0f ); this.setSoundType( SoundType.PLANT ); + this.setCreativeTab( CreativeTabs.DECORATIONS ); this.setDefaultState( this.blockState.getBaseState( ).withProperty( MSapling.STAGE , 0 ) ); @@ -171,7 +173,7 @@ public class MSapling public boolean canReplace( final World world , final BlockPos pos , final EnumFacing side , final ItemStack stack ) { return world.getBlockState( pos ).getBlock( ).isReplaceable( world , pos ) - && this.wood.canSaplingStay( world , pos , this.getStateFromMeta( stack.getMetadata( ) ) ); + && this.wood.canSaplingStay( world , pos ); } @@ -196,7 +198,7 @@ public class MSapling private boolean checkUproot( final World worldIn , final BlockPos pos , final IBlockState state ) { - if ( this.wood.canSaplingStay( worldIn , pos , state ) ) { + if ( this.wood.canSaplingStay( worldIn , pos ) ) { return true; } this.dropBlockAsItem( worldIn , pos , state , 0 ); diff --git a/src/java/mmm/materials/MWood.java b/src/java/mmm/materials/MWood.java index 5c6ab88..57376c1 100644 --- a/src/java/mmm/materials/MWood.java +++ b/src/java/mmm/materials/MWood.java @@ -12,9 +12,11 @@ import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.gen.feature.WorldGenAbstractTree; +import net.minecraftforge.common.IPlantable; import net.minecraftforge.fml.common.registry.GameRegistry; @@ -24,7 +26,7 @@ public class MWood { public static interface I_SaplingChecker { - public boolean canSaplingStay( World worldIn , BlockPos pos , IBlockState state ); + public boolean canSaplingStay( World worldIn , BlockPos pos ); } public final String NAME; @@ -43,7 +45,7 @@ public class MWood private int fruitDropChance = 0; private Item fruit = null; - private int saplingGrowthStages = 1; + private int saplingGrowthStages = 2; private float bonemealChance = .45f; private float growthChance = .142f; private int growthMinLight = 9; @@ -51,10 +53,12 @@ public class MWood private I_SaplingChecker saplingCheck = new I_SaplingChecker( ) { @Override - public boolean canSaplingStay( final World worldIn , final BlockPos pos , final IBlockState state ) + public boolean canSaplingStay( final World worldIn , final BlockPos pos ) { - final Block down = worldIn.getBlockState( pos.down( ) ).getBlock( ); - return down == Blocks.GLASS || down == Blocks.DIRT; + final BlockPos soilPos = pos.down( ); + final IBlockState soilState = worldIn.getBlockState( soilPos ); + final Block down = soilState.getBlock( ); + return down.canSustainPlant( soilState , worldIn , soilPos , EnumFacing.UP , (IPlantable) Blocks.SAPLING ); } }; @@ -148,32 +152,39 @@ public class MWood } - public MWood setTreeGenerator( final WorldGenAbstractTree generator ) + public MWood setTreeGenerator( final A_MTreeGenerator generator ) { this.genNormal = generator; + if ( generator != null ) { + generator.setWood( this ); + } return this; } - public MWood setBigTreeGenerator( final WorldGenAbstractTree generator ) + public MWood setBigTreeGenerator( final A_MTreeGenerator generator ) { - this.genBig = generator; - this.genBigChance = .1f; - return this; + return this.setBigTreeGenerator( generator , .1f ); } - public MWood setBigTreeGenerator( final WorldGenAbstractTree generator , final float chance ) + public MWood setBigTreeGenerator( final A_MTreeGenerator generator , final float chance ) { this.genBig = generator; this.genBigChance = chance; + if ( generator != null ) { + generator.setWood( this ); + } return this; } - public MWood setMegaTreeGenerator( final WorldGenAbstractTree generator ) + public MWood setMegaTreeGenerator( final A_MTreeGenerator generator ) { this.genMega = generator; + if ( generator != null ) { + generator.setWood( this ); + } return this; } @@ -181,13 +192,17 @@ public class MWood public MWood register( ) { URegistry.addBlock( this.LOG ); - Blocks.FIRE.setFireInfo( this.LOG , this.baseFireEncouragement , this.baseFlammability ); - URegistry.addBlock( this.LEAVES ); - Blocks.FIRE.setFireInfo( this.LEAVES , this.baseFireEncouragement * 6 , this.baseFlammability * 12 ); - URegistry.addBlock( this.PLANKS ); - Blocks.FIRE.setFireInfo( this.PLANKS , this.baseFireEncouragement , this.baseFlammability * 4 ); + final Item sapling = URegistry.addBlock( this.SAPLING ); + + if ( this.baseFlammability != 0 ) { + Blocks.FIRE.setFireInfo( this.LOG , this.baseFireEncouragement , this.baseFlammability ); + Blocks.FIRE.setFireInfo( this.LEAVES , this.baseFireEncouragement * 6 , this.baseFlammability * 12 ); + Blocks.FIRE.setFireInfo( this.PLANKS , this.baseFireEncouragement , this.baseFlammability * 4 ); + Blocks.FIRE.setFireInfo( this.SAPLING , this.baseFireEncouragement * 2 , this.baseFlammability * 8 ); + URegistry.setFuel( sapling , this.baseFlammability * 30 ); + } URegistry.addRecipeRegistrar( this ); return this; @@ -248,10 +263,10 @@ public class MWood } - public boolean canSaplingStay( final World worldIn , final BlockPos pos , final IBlockState state ) + public boolean canSaplingStay( final World worldIn , final BlockPos pos ) { if ( this.saplingCheck != null ) { - return this.saplingCheck.canSaplingStay( worldIn , pos , state ); + return this.saplingCheck.canSaplingStay( worldIn , pos ); } return true; } diff --git a/src/java/mmm/materials/Materials.java b/src/java/mmm/materials/Materials.java index 51c7c5f..e281bcd 100644 --- a/src/java/mmm/materials/Materials.java +++ b/src/java/mmm/materials/Materials.java @@ -97,6 +97,7 @@ public class Materials WOOD_HEVEA = new MWood( "hevea" ) // .setBarkColor( MapColor.GRAY ) // .setBaseFireInfo( 5 , 8 ) // + .setTreeGenerator( new MHeveaGenerator( true ) ) // .register( ); // Items that do not correspond to metals or ores diff --git a/src/java/mmm/utils/URegistry.java b/src/java/mmm/utils/URegistry.java index 02a1c47..062157e 100644 --- a/src/java/mmm/utils/URegistry.java +++ b/src/java/mmm/utils/URegistry.java @@ -118,19 +118,19 @@ public class URegistry } - public static void addBlock( final Block block ) + public static Item addBlock( final Block block ) { - URegistry.addBlock( block , true ); + return URegistry.addBlock( block , true ); } - public static void addBlock( final Block block , final Item blockItem ) + public static Item addBlock( final Block block , final Item blockItem ) { - URegistry.addBlock( block , blockItem , true ); + return URegistry.addBlock( block , blockItem , true ); } - public static void addBlock( final Block block , final boolean registerItemModel ) + public static Item addBlock( final Block block , final boolean registerItemModel ) { Item item; if ( block instanceof I_UColoredBlock ) { @@ -139,11 +139,11 @@ public class URegistry item = new ItemBlock( block ); } item.setRegistryName( block.getRegistryName( ) ); - URegistry.addBlock( block , item , registerItemModel ); + return URegistry.addBlock( block , item , registerItemModel ); } - public static void addBlock( final Block block , final Item blockItem , final boolean registerItemModel ) + public static Item addBlock( final Block block , final Item blockItem , final boolean registerItemModel ) { if ( URegistry.BLOCKS.add( block ) ) { GameRegistry.register( block ); @@ -161,6 +161,7 @@ public class URegistry URegistry.addItem( blockItem , registerItemModel ); } } + return blockItem; }