BiomesOPlenty/src/main/java/biomesoplenty/common/block/BlockBOPSapling.java

336 lines
15 KiB
Java

/*******************************************************************************
* Copyright 2014-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.block;
import java.util.Random;
import biomesoplenty.api.biome.generation.GeneratorStage;
import biomesoplenty.api.block.BOPBlocks;
import biomesoplenty.api.block.BlockQueries;
import biomesoplenty.common.enums.BOPTrees;
import biomesoplenty.common.enums.BOPWoods;
import biomesoplenty.common.item.ItemBOPSapling;
import biomesoplenty.common.util.block.VariantPagingHelper;
import biomesoplenty.common.world.feature.tree.GeneratorBasicTree;
import biomesoplenty.common.world.feature.tree.GeneratorBayouTree;
import biomesoplenty.common.world.feature.tree.GeneratorBigTree;
import biomesoplenty.common.world.feature.tree.GeneratorBulbTree;
import biomesoplenty.common.world.feature.tree.GeneratorMahoganyTree;
import biomesoplenty.common.world.feature.tree.GeneratorMangroveTree;
import biomesoplenty.common.world.feature.tree.GeneratorPalmTree;
import biomesoplenty.common.world.feature.tree.GeneratorPineTree;
import biomesoplenty.common.world.feature.tree.GeneratorRedwoodTree;
import biomesoplenty.common.world.feature.tree.GeneratorTaigaTree;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLeaves;
import net.minecraft.block.BlockOldLeaf;
import net.minecraft.block.BlockPlanks;
import net.minecraft.block.IGrowable;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.properties.PropertyInteger;
import net.minecraft.block.state.BlockState;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemBlock;
import net.minecraft.util.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.WorldGenTrees;
import net.minecraft.world.gen.feature.WorldGenerator;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class BlockBOPSapling extends BlockBOPDecoration implements IGrowable {
// setup paged variant property
// STAGE requires one bit, so we have 3 bits left for the VARIANT which means we can have eight per instance
public static VariantPagingHelper<BlockBOPSapling, BOPTrees> paging = new VariantPagingHelper<BlockBOPSapling, BOPTrees>(8, BOPTrees.class, BOPTrees.withSaplings);
// Slightly naughty hackery here
// The constructor of Block() calls createBlockState() which needs to know the particular instance's variant property
// There is no way to set the individual block instance's variant property before this, because the super() has to be first
// So, we use the static variable currentVariantProperty to provide each instance access to its variant property during creation
private static IProperty currentVariantProperty;
// Create an instance for each page
public static void createAllPages()
{
int numPages = paging.getNumPages();
for (int i = 0; i < numPages; ++i)
{
currentVariantProperty = paging.getVariantProperty(i);
paging.addBlock(i, new BlockBOPSapling());
}
}
// Each instance has a reference to its own variant property
public IProperty variantProperty;
public static final PropertyInteger STAGE = PropertyInteger.create("stage", 0, 1);
@Override
protected BlockState createBlockState()
{
this.variantProperty = currentVariantProperty; // get from static variable
return new BlockState(this, new IProperty[] { STAGE, this.variantProperty });
}
// implement IBOPBlock
@Override
public Class<? extends ItemBlock> getItemClass() { return ItemBOPSapling.class; }
@Override
public IProperty[] getPresetProperties() { return new IProperty[] {this.variantProperty}; }
@Override
public IProperty[] getNonRenderingProperties() { return new IProperty[] {STAGE}; }
@Override
public String getStateName(IBlockState state)
{
return ((BOPTrees) state.getValue(this.variantProperty)).getName() + "_sapling";
}
public BlockBOPSapling()
{
super();
this.setStepSound(Block.soundTypeGrass);
this.setBlockBoundsByRadiusAndHeight(0.4F, 0.8F);
this.setDefaultState(this.blockState.getBaseState().withProperty(STAGE, Integer.valueOf(0)));
}
// map from meta to state and vice verca. Use the highest bit for STAGE and the other 3 for VARIANT (so we can have 8 per instance)
@Override
public IBlockState getStateFromMeta(int meta)
{
return this.getDefaultState().withProperty(this.variantProperty, paging.getVariant(this, meta & 7)).withProperty(STAGE, Integer.valueOf(meta >> 3));
}
@Override
public int getMetaFromState(IBlockState state)
{
BOPTrees tree = (BOPTrees)state.getValue(this.variantProperty);
return ((Integer)state.getValue(STAGE)).intValue() * 8 + paging.getIndex(tree);
}
// TODO: override for loftwood - what is that?
@Override
public boolean canBlockStay(World world, BlockPos pos, IBlockState state)
{
return BlockQueries.fertile.matches(world, pos.down());
}
@Override
public void updateTick(World worldIn, BlockPos pos, IBlockState state, Random rand)
{
if (!worldIn.isRemote)
{
super.updateTick(worldIn, pos, state, rand);
if (worldIn.getLightFromNeighbors(pos.up()) >= 9 && rand.nextInt(7) == 0)
{
this.grow(worldIn, rand, pos, state);
}
}
}
@Override
public int damageDropped(IBlockState state)
{
//We don't want item drops to have metadata for the stage
return this.getMetaFromState(state) & 7;
}
@Override
@SideOnly(Side.CLIENT)
public Block.EnumOffsetType getOffsetType()
{
return Block.EnumOffsetType.NONE;
}
/***** stuff for growing trees *****/
// TODO: specify generator for each sapling
protected WorldGenerator getSmallTreeGenerator(BOPTrees treeType)
{
switch (treeType)
{
case YELLOW_AUTUMN:
return new GeneratorBasicTree.Builder().log(BlockPlanks.EnumType.BIRCH).leaves(BOPTrees.YELLOW_AUTUMN).minHeight(5).maxHeight(8).create();
case ORANGE_AUTUMN:
return new GeneratorBasicTree.Builder().log(BlockPlanks.EnumType.DARK_OAK).leaves(BOPTrees.ORANGE_AUTUMN).minHeight(5).maxHeight(8).create();
case BAMBOO:
return new GeneratorBulbTree.Builder().minHeight(6).maxHeight(18).log(BOPBlocks.bamboo.getDefaultState()).leaves(BOPTrees.BAMBOO).create();
case MAGIC:
return new GeneratorBasicTree.Builder().log(BOPWoods.MAGIC).leaves(BOPTrees.MAGIC).create();
case UMBRAN:
return new GeneratorTaigaTree.Builder().log(BOPWoods.UMBRAN).leaves(BOPTrees.UMBRAN).maxHeight(20).create();
case DEAD:
return new GeneratorBasicTree.Builder().log(BlockPlanks.EnumType.OAK).leaves(BOPTrees.DEAD).minHeight(5).maxHeight(8).create();
case FIR:
return new GeneratorTaigaTree.Builder().log(BOPWoods.FIR).leaves(BOPTrees.FIR).minHeight(5).maxHeight(28).create();
case ETHEREAL: //Not implemented
return new WorldGenTrees(true);
case ORIGIN:
return new GeneratorBasicTree.Builder().minHeight(5).maxHeight(8).leaves(BOPTrees.ORIGIN).create();
case PINK_CHERRY:
return new GeneratorBasicTree.Builder().log(BOPWoods.CHERRY).leaves(BOPTrees.PINK_CHERRY).create();
case WHITE_CHERRY:
return new GeneratorBasicTree.Builder().log(BOPWoods.CHERRY).leaves(BOPTrees.WHITE_CHERRY).create();
case MAPLE:
return new GeneratorBasicTree.Builder().log(BlockPlanks.EnumType.OAK).leaves(BOPTrees.MAPLE).minHeight(5).maxHeight(10).create();
case HELLBARK: //Not implemented
return new WorldGenTrees(true);
case FLOWERING:
return new GeneratorBasicTree.Builder().altLeaves(BOPTrees.FLOWERING).create();
case JACARANDA:
return new GeneratorBasicTree.Builder().minHeight(4).maxHeight(7).log(BOPWoods.JACARANDA).leaves(BOPTrees.JACARANDA).create();
case SACRED_OAK:
return new GeneratorBigTree.Builder().log(BOPWoods.SACRED_OAK).leaves(BOPTrees.SACRED_OAK).minHeight(35).maxHeight(45).trunkWidth(2).foliageDensity(1.25D).create();
case MANGROVE:
return new GeneratorMangroveTree.Builder().log(BOPWoods.MANGROVE).leaves(BOPTrees.MANGROVE).create();
case PALM:
return new GeneratorPalmTree.Builder().log(BOPWoods.PALM).leaves(BlockBOPLeaves.paging.getVariantState(BOPTrees.PALM).withProperty(BlockOldLeaf.CHECK_DECAY, Boolean.valueOf(false))).create();
case REDWOOD:
return new GeneratorRedwoodTree.Builder().create();
case WILLOW:
return new GeneratorBasicTree.Builder().log(BOPWoods.WILLOW).leaves(BlockBOPLeaves.paging.getVariantState(BOPTrees.WILLOW).withProperty(BlockOldLeaf.CHECK_DECAY, Boolean.valueOf(false))).minHeight(8).maxHeight(12).maxLeavesRadius(2).vine(BlockBOPLeaves.paging.getVariantState(BOPTrees.WILLOW).withProperty(BlockOldLeaf.CHECK_DECAY, Boolean.valueOf(false))).leavesOffset(0).create();
case PINE:
return new GeneratorPineTree.Builder().minHeight(6).maxHeight(18).log(BOPWoods.PINE).leaves(BOPTrees.PINE).create();
case MAHOGANY:
return new GeneratorMahoganyTree.Builder().create();
case EBONY:
return new GeneratorBigTree.Builder().log(BOPWoods.EBONY).leaves(BOPTrees.EBONY).minHeight(4).maxHeight(10).foliageHeight(1).create();
case EUCALYPTUS:
return new GeneratorBulbTree.Builder().minHeight(15).maxHeight(30).log(BOPWoods.EUCALYPTUS).leaves(BOPTrees.EUCALYPTUS).create();
default:
return null;
}
}
// TODO: specify generator for each sapling
protected WorldGenerator getBigTreeGenerator(BOPTrees treeType)
{
return null;
}
// TODO: specify generator for each sapling
protected WorldGenerator getMegaTreeGenerator(BOPTrees treeType)
{
return null;
}
@Override
public boolean canGrow(World worldIn, BlockPos pos, IBlockState state, boolean isClient)
{
return true;
}
@Override
public boolean canUseBonemeal(World worldIn, Random rand, BlockPos pos, IBlockState state)
{
return (double)worldIn.rand.nextFloat() < 0.45D;
}
@Override
public void grow(World worldIn, Random rand, BlockPos pos, IBlockState state)
{
if (((Integer)state.getValue(STAGE)).intValue() == 0)
{
worldIn.setBlockState(pos, state.cycleProperty(STAGE), 4);
}
else
{
this.generateTree(worldIn, pos, state, rand);
}
}
public boolean thisSaplingHere(World world, BlockPos pos)
{
return world.getBlockState(pos).getBlock() == this;
}
// try to generate a tree at the specified location, return true on success and false on failure
public boolean generateTree(World worldIn, BlockPos pos, IBlockState state, Random rand)
{
if (!net.minecraftforge.event.terraingen.TerrainGen.saplingGrowTree(worldIn, rand, pos)) {return false;}
BOPTrees treeType = ((BOPTrees) state.getValue(this.variantProperty));
WorldGenerator smallTreeGenerator = this.getSmallTreeGenerator(treeType);
WorldGenerator bigTreeGenerator = this.getBigTreeGenerator(treeType);
WorldGenerator megaTreeGenerator = this.getMegaTreeGenerator(treeType);
if (megaTreeGenerator != null)
{
// if we have 4 saplings in a square, then try to grow a mega tree
int i;
int j;
for (i = 0; i >= -1; --i)
{
for (j = 0; j >= -1; --j)
{
if (this.thisSaplingHere(worldIn, pos.add(i, 0, j)) && this.thisSaplingHere(worldIn, pos.add(i + 1, 0, j)) && this.thisSaplingHere(worldIn, pos.add(i, 0, j + 1)) && this.thisSaplingHere(worldIn, pos.add(i + 1, 0, j + 1)))
{
if (this.generateMegaTree(worldIn, pos.add(i, 0, j), state, rand, megaTreeGenerator)) {return true;}
}
}
}
}
if (bigTreeGenerator != null)
{
// with a one in 10 chance, try to grow a big tree
if (rand.nextInt(10) == 0)
{
if (this.generateSmallOrBigTree(worldIn, pos, state, rand, bigTreeGenerator)) {return true;}
}
}
// otherwise, try to grow a small tree
if (smallTreeGenerator != null)
{
if (this.generateSmallOrBigTree(worldIn, pos, state, rand, smallTreeGenerator)) {return true;}
}
return false;
}
public boolean generateSmallOrBigTree(World worldIn, BlockPos pos, IBlockState state, Random rand, WorldGenerator generator)
{
// remove the sapling
worldIn.setBlockState(pos, Blocks.air.getDefaultState(), 4);
// try to grow the tree
boolean success = generator.generate(worldIn, rand, pos);
// put the sapling back if we failed
if (!success) {worldIn.setBlockState(pos, state, 4);}
return success;
}
public boolean generateMegaTree(World worldIn, BlockPos pos, IBlockState state, Random rand, WorldGenerator generator)
{
// remove the saplings
IBlockState air = Blocks.air.getDefaultState();
worldIn.setBlockState(pos, air, 4);
worldIn.setBlockState(pos.add(1, 0, 0), air, 4);
worldIn.setBlockState(pos.add(0, 0, 1), air, 4);
worldIn.setBlockState(pos.add(1, 0, 1), air, 4);
// try to grow the tree
boolean success = generator.generate(worldIn, rand, pos);
if (!success)
{
// put the saplings back if we failed
worldIn.setBlockState(pos, air, 4);
worldIn.setBlockState(pos.add(1, 0, 0), state, 4);
worldIn.setBlockState(pos.add(0, 0, 1), state, 4);
worldIn.setBlockState(pos.add(1, 0, 1), state, 4);
}
return success;
}
}