diff --git a/src/main/java/biomesoplenty/api/block/BOPBlocks.java b/src/main/java/biomesoplenty/api/block/BOPBlocks.java index e0b56e4cc..749cf1b74 100644 --- a/src/main/java/biomesoplenty/api/block/BOPBlocks.java +++ b/src/main/java/biomesoplenty/api/block/BOPBlocks.java @@ -117,6 +117,8 @@ public class BOPBlocks public static Block pine_sapling; public static Block mahogany_sapling; + public static Block double_foliage; + } diff --git a/src/main/java/biomesoplenty/common/block/BlockDecoration.java b/src/main/java/biomesoplenty/common/block/BlockDecoration.java index 0419f2046..3267713a5 100644 --- a/src/main/java/biomesoplenty/common/block/BlockDecoration.java +++ b/src/main/java/biomesoplenty/common/block/BlockDecoration.java @@ -55,21 +55,20 @@ public class BlockDecoration extends Block implements IBOPBlock } // utility function for setting the block bounds - typically decoration blocks are smaller than full block size - public BlockDecoration setBlockBoundsByRadiusAndHeight(float radius, float height) + public void setBlockBoundsByRadiusAndHeight(float radius, float height) { - return this.setBlockBoundsByRadiusAndHeight(radius,height,false); + this.setBlockBoundsByRadiusAndHeight(radius,height,false); } - public BlockDecoration setBlockBoundsByRadiusAndHeight(float radius, float height, boolean fromTop) + public void setBlockBoundsByRadiusAndHeight(float radius, float height, boolean fromTop) { this.setBlockBounds(0.5F - radius, (fromTop ? 1.0F - height : 0.0F), 0.5F - radius, 0.5F + radius, (fromTop ? 1.0F : height), 0.5F + radius); - return this; } // add a canBlockStay() check before placing this block @Override public boolean canReplace(World world, BlockPos pos, EnumFacing side, ItemStack stack) { - return super.canReplace(world, pos, side, stack) && this.canBlockStay(world, pos, this.getStateFromMeta(stack.getMetadata())); + return world.getBlockState(pos).getBlock().isReplaceable(world, pos) && this.canBlockStay(world, pos, this.getStateFromMeta(stack.getMetadata())); } // check this block is still able to remain after neighbor change diff --git a/src/main/java/biomesoplenty/common/block/BlockDoubleDecoration.java b/src/main/java/biomesoplenty/common/block/BlockDoubleDecoration.java new file mode 100644 index 000000000..78ee2035f --- /dev/null +++ b/src/main/java/biomesoplenty/common/block/BlockDoubleDecoration.java @@ -0,0 +1,229 @@ +/******************************************************************************* + * Copyright 2014, 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.List; + +import net.minecraft.block.material.Material; +import net.minecraft.block.properties.IProperty; +import net.minecraft.block.properties.PropertyEnum; +import net.minecraft.block.state.BlockState; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.util.BlockPos; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.IStringSerializable; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +class BlockDoubleDecoration extends BlockDecoration { + + // add half property + public static enum Half implements IStringSerializable {LOWER, UPPER; public String getName() {return this.name().toLowerCase();}}; + public static final PropertyEnum HALF = PropertyEnum.create("half", Half.class); + protected BlockState createBlockState() {return new BlockState(this, new IProperty[] { HALF });} + + public float radius; + public float height; + public boolean fromTop; + + public BlockDoubleDecoration() + { + this(Material.plants); + } + public BlockDoubleDecoration(Material material) + { + super(material); + this.radius = 0.5F; + this.height = 1.0F; + this.fromTop = false; + this.setDefaultState(this.blockState.getBaseState().withProperty(HALF, Half.LOWER)); + } + + // map from state to meta and vice verca + @Override + public IBlockState getStateFromMeta(int meta) + { + return this.getDefaultState().withProperty(HALF, Half.values()[meta]); + } + @Override + public int getMetaFromState(IBlockState state) + { + return ((Half) state.getValue(HALF)).ordinal(); + } + + + + + // utility functions + public BlockPos getLowerPos(IBlockAccess world, BlockPos pos) + { + IBlockState state = world.getBlockState(pos); + if (state.getBlock() != this) {return pos;} + return world.getBlockState(pos).getValue(HALF) == Half.UPPER ? pos.down() : pos; + } + public BlockPos getUpperPos(IBlockAccess world, BlockPos pos) + { + IBlockState state = world.getBlockState(pos); + if (state.getBlock() != this) {return pos.up();} + return world.getBlockState(pos).getValue(HALF) == Half.UPPER ? pos : pos.up(); + } + public IBlockState getLowerState(IBlockAccess world, BlockPos pos) + { + return world.getBlockState(this.getLowerPos(world, pos)); + } + public IBlockState getUpperState(IBlockAccess world, BlockPos pos) + { + return world.getBlockState(this.getUpperPos(world, pos)); + } + public boolean isValidDoubleBlock(IBlockAccess world, BlockPos pos) + { + IBlockState lowerState = this.getLowerState(world, pos); + IBlockState upperState = this.getUpperState(world, pos); + return lowerState.getBlock() == this && lowerState.getValue(HALF) == Half.LOWER && upperState.getBlock() == this && upperState.getValue(HALF) == Half.UPPER; + } + + + + // drop block as item if it cannot remain here - return whether on not it could stay + @Override + protected boolean checkAndDropBlock(World worldIn, BlockPos pos, IBlockState state) + { + if (this.isValidDoubleBlock(worldIn, pos) && this.canBlockStay(worldIn, this.getLowerPos(worldIn, pos), state)) + { + return true; + } + else + { + this.dropBlockAsItem(worldIn, pos, state, 0); + worldIn.setBlockState(pos, Blocks.air.getDefaultState(), 3); + return false; + } + } + + // This DoubleDecoration can replace the block at pos if both the block and the one above it are replaceable and the environment is suitable (canBlockStay) + @Override + public boolean canReplace(World world, BlockPos pos, EnumFacing side, ItemStack stack) + { + return world.getBlockState(pos).getBlock().isReplaceable(world, pos) && world.getBlockState(pos.up()).getBlock().isReplaceable(world, pos.up()) && this.canBlockStay(world, pos, this.getStateFromMeta(stack.getMetadata())); + } + + // Called by ItemBlock before the block is placed - the placed block must always be Half.LOWER + public IBlockState onBlockPlaced(World worldIn, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer) + { + return this.getStateFromMeta(meta).withProperty(HALF, Half.LOWER); + } + + // Called by ItemBlock after the (lower) block has been placed + // Use it to add the top half of the block + public void onBlockPlacedBy(World worldIn, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) { + worldIn.setBlockState(pos.up(), this.getStateFromMeta(stack.getMetadata()).withProperty(HALF, Half.UPPER), 3); + } + + @Override + // child classes should put code in here which checks the ground is ok + public boolean canBlockStay(World world, BlockPos lowerPos, IBlockState state) + { + return true; + } + + + + + + @Override + // utility function for setting the block bounds - + public void setBlockBoundsByRadiusAndHeight(float radius, float height, boolean fromTop) + { + this.radius = radius; + this.height = height; + this.fromTop = fromTop; + } + @Override + public void setBlockBoundsBasedOnState(IBlockAccess worldIn, BlockPos pos) + { + IBlockState state = worldIn.getBlockState(pos); + switch ((Half) state.getValue(HALF)) + { + case LOWER: + super.setBlockBoundsByRadiusAndHeight(this.radius, this.fromTop ? this.height : 1.0F, this.fromTop); + break; + case UPPER: + super.setBlockBoundsByRadiusAndHeight(this.radius, this.fromTop ? 1.0F : this.height, this.fromTop); + break; + } + } + + + // handle drops from UPPER and LOWER separately + @Override + public List getDrops(IBlockAccess world, BlockPos pos, IBlockState state, int fortune) + { + if (state.getValue(HALF) == Half.UPPER) + { + return this.getUpperDrops(world, this.getUpperPos(world, pos), this.getUpperState(world, pos), fortune); + } + else + { + return this.getLowerDrops(world, this.getLowerPos(world, pos), this.getLowerState(world, pos), fortune); + } + } + + // default behavior is that UPPER drops nothing, and LOWER drops the default item + public List getUpperDrops(IBlockAccess world, BlockPos upperPos, IBlockState upperState, int fortune) + { + return new java.util.ArrayList(); + } + public List getLowerDrops(IBlockAccess world, BlockPos lowerPos, IBlockState lowerState, int fortune) + { + return super.getDrops(world, lowerPos, lowerState, fortune); + } + + // if a child class chooses to implement IShearable make shearing the upper or lower block act as shearing both + public List onSheared(ItemStack item, IBlockAccess world, BlockPos pos, int fortune) { + + List drops = new java.util.ArrayList(); + drops.addAll( this.getUpperShearDrops(item, world, this.getUpperPos(world, pos), this.getUpperState(world, pos), fortune) ); + drops.addAll( this.getLowerShearDrops(item, world, this.getLowerPos(world, pos), this.getLowerState(world, pos), fortune) ); + + // whichever half was sheared, turn the other to air (to prevent it dropping an additional item when it pops) + if (world instanceof World) + { + ((World)world).setBlockToAir( pos.add(0, world.getBlockState(pos).getValue(HALF) == Half.UPPER ? -1 : 1, 0) ); + } + + return drops; + } + + // default behavior is that UPPER drops nothing, and LOWER drops the default item + public List getUpperShearDrops(ItemStack item, IBlockAccess world, BlockPos upperPos, IBlockState upperState, int fortune) { + return new java.util.ArrayList(); + } + public List getLowerShearDrops(ItemStack item, IBlockAccess world, BlockPos lowerPos, IBlockState lowerState, int fortune) { + return super.getDrops(world, lowerPos, lowerState, fortune); + } + + + + // discard the HALF info in the items dropped - make them all Half.LOWER so that they can stack - keep other state info such as VARIANT + @Override + public int damageDropped(IBlockState state) + { + return this.getMetaFromState( state.withProperty(HALF, Half.LOWER) ); + } + + + + + + + +} \ No newline at end of file diff --git a/src/main/java/biomesoplenty/common/block/BlockDoubleFoliage.java b/src/main/java/biomesoplenty/common/block/BlockDoubleFoliage.java new file mode 100644 index 000000000..eb7095427 --- /dev/null +++ b/src/main/java/biomesoplenty/common/block/BlockDoubleFoliage.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright 2014, 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.List; +import java.util.Random; + +import biomesoplenty.api.block.BOPBlocks; +import net.minecraft.block.Block; +import net.minecraft.block.properties.IProperty; +import net.minecraft.block.properties.PropertyEnum; +import net.minecraft.block.state.BlockState; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.util.BlockPos; +import net.minecraft.util.IStringSerializable; +import net.minecraft.world.ColorizerGrass; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeColorHelper; +import net.minecraftforge.common.ForgeHooks; +import net.minecraftforge.common.IShearable; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class BlockDoubleFoliage extends BlockDoubleDecoration implements IShearable +{ + + // add properties (note we inherit HALF from BlockDoubleDecoration) + public static enum FoliageType implements IStringSerializable {FLAX; public String getName() {return this.name().toLowerCase();}}; + public static final PropertyEnum VARIANT = PropertyEnum.create("variant", FoliageType.class); + @Override + protected BlockState createBlockState() {return new BlockState(this, new IProperty[] { HALF, VARIANT });} + + public BlockDoubleFoliage() + { + super(); + + // define named states + for(FoliageType foliageType : FoliageType.values()) + { + this.namedStates.put(foliageType.getName(), this.blockState.getBaseState().withProperty(HALF, Half.LOWER) .withProperty(VARIANT, foliageType)); + } + this.setDefaultState(this.getNamedState("flax")); + } + + // map from state to meta and vice verca - use highest bit for Half, and lower bits for variant + @Override + public IBlockState getStateFromMeta(int meta) + { + return this.getDefaultState().withProperty(HALF, Half.values()[meta >> 3]).withProperty(VARIANT, FoliageType.values()[meta & 7]); + } + @Override + public int getMetaFromState(IBlockState state) + { + return ((Half) state.getValue(HALF)).ordinal() * 8 + ((FoliageType) state.getValue(VARIANT)).ordinal(); + } + + + + // TODO: comment these + @Override + @SideOnly(Side.CLIENT) + public int getBlockColor() + { + return ColorizerGrass.getGrassColor(0.5D, 1.0D); + } + + @Override + @SideOnly(Side.CLIENT) + public int getRenderColor(IBlockState state) + { + return this.getBlockColor(); + } + + @Override + @SideOnly(Side.CLIENT) + public int colorMultiplier(IBlockAccess worldIn, BlockPos pos, int renderPass) + { + switch ((FoliageType) worldIn.getBlockState(pos).getValue(VARIANT)) + { + default: + return BiomeColorHelper.getGrassColorAtPos(worldIn, pos); + } + } + + + // different variants have different sizes + @Override + public void setBlockBoundsBasedOnState(IBlockAccess worldIn, BlockPos pos) + { + switch ((FoliageType) worldIn.getBlockState(pos).getValue(VARIANT)) + { + default: + this.setBlockBoundsByRadiusAndHeight(0.4F, 0.8F); + break; + } + } + + + + @Override + public boolean canBlockStay(World world, BlockPos lowerPos, IBlockState state) + { + IBlockState groundState = world.getBlockState(lowerPos.down()); + Block groundBlock = groundState.getBlock(); + boolean onFertile = (groundBlock == Blocks.dirt || groundBlock == BOPBlocks.dirt || groundBlock == Blocks.mycelium || groundBlock == Blocks.grass); + if (groundBlock instanceof BlockBOPGrass) + { + switch ((BlockBOPGrass.BOPGrassType) groundState.getValue(BlockBOPGrass.VARIANT)) + { + case SPECTRAL_MOSS: case SMOLDERING: + break; + case OVERGROWN_NETHERRACK: case LOAMY: case SANDY: case SILTY: case ORIGIN: default: + onFertile = true; + break; + } + } + return onFertile; + + } + + + // get the items dropped when you bash the bush + @Override + public List getLowerDrops(IBlockAccess world, BlockPos lowerPos, IBlockState lowerState, int fortune) + { + Random rand = world instanceof World ? ((World)world).rand : RANDOM; + + // start with an empty stack + List ret = new java.util.ArrayList(); + + // add items based on the VARIANT - default is to return nothing (require shears to collect the block) + switch ((FoliageType) lowerState.getValue(VARIANT)) + { + case FLAX: + if (rand.nextInt(8) == 0) + { + // 1 in 8 chance of getting a seed from this grass + ret.add(ForgeHooks.getGrassSeed(rand)); + } + + default: + break; + } + return ret; + } + + + @Override + public boolean isShearable(ItemStack item, IBlockAccess world, BlockPos pos) { + return true; + } + + @Override + public List getLowerShearDrops(ItemStack item, IBlockAccess world, BlockPos lowerPos, IBlockState lowerState, int fortune) { + // start with an empty stack + List ret = new java.util.ArrayList(); + + // add items based on the VARIANT + switch ((FoliageType) lowerState.getValue(VARIANT)) + { + default: + // default is to get the (lower) block unaltered + ret.add(new ItemStack(this, 1, this.getMetaFromState(lowerState.withProperty(HALF, Half.LOWER) ))); + } + return ret; + } + + +} \ No newline at end of file diff --git a/src/main/java/biomesoplenty/common/init/ModBlocks.java b/src/main/java/biomesoplenty/common/init/ModBlocks.java index bb1a4ddd2..f96d0c939 100644 --- a/src/main/java/biomesoplenty/common/init/ModBlocks.java +++ b/src/main/java/biomesoplenty/common/init/ModBlocks.java @@ -46,6 +46,7 @@ import biomesoplenty.common.block.BlockBamboo; import biomesoplenty.common.block.BlockBones; import biomesoplenty.common.block.BlockCoral; import biomesoplenty.common.block.BlockCrystal; +import biomesoplenty.common.block.BlockDoubleFoliage; import biomesoplenty.common.block.BlockFoliage; import biomesoplenty.common.block.BlockFruit; import biomesoplenty.common.block.BlockGem; @@ -231,7 +232,7 @@ public class ModBlocks dark_leaves = registerBlock( new BlockBOPLeaves( new ItemStack(dark_sapling, 1, 0), new ItemStack(Items.apple, 1, 0), 20, true ), "dark_leaves" ); bamboo_leaves = registerBlock( new BlockBOPLeaves( new ItemStack(bamboo_sapling, 1, 0), new ItemStack(Items.apple, 1, 0), 20, true ), "bamboo_leaves" ); - + double_foliage = registerBlock( new BlockDoubleFoliage(), "double_foliage" ); } diff --git a/src/main/resources/assets/biomesoplenty/blockstates/double_foliage.json b/src/main/resources/assets/biomesoplenty/blockstates/double_foliage.json new file mode 100644 index 000000000..3e645d109 --- /dev/null +++ b/src/main/resources/assets/biomesoplenty/blockstates/double_foliage.json @@ -0,0 +1,6 @@ +{ + "variants": { + "half=upper,variant=flax": { "model": "biomesoplenty:flax_upper" }, + "half=lower,variant=flax": { "model": "biomesoplenty:flax_lower" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/biomesoplenty/models/block/flax_lower.json b/src/main/resources/assets/biomesoplenty/models/block/flax_lower.json new file mode 100644 index 000000000..3d976e09c --- /dev/null +++ b/src/main/resources/assets/biomesoplenty/models/block/flax_lower.json @@ -0,0 +1,6 @@ +{ + "parent": "block/tallgrass", + "textures": { + "cross": "biomesoplenty:blocks/flax_lower" + } +} diff --git a/src/main/resources/assets/biomesoplenty/models/block/flax_upper.json b/src/main/resources/assets/biomesoplenty/models/block/flax_upper.json new file mode 100644 index 000000000..dfab1d144 --- /dev/null +++ b/src/main/resources/assets/biomesoplenty/models/block/flax_upper.json @@ -0,0 +1,8 @@ +{ + "parent": "biomesoplenty:block/cross_with_overlay", + "textures": { + "colored": "biomesoplenty:blocks/flax_flowers", + "greyscale": "biomesoplenty:blocks/flax_upper", + "particle": "biomesoplenty:blocks/flax_upper" + } +} diff --git a/src/main/resources/assets/biomesoplenty/models/item/flax.json b/src/main/resources/assets/biomesoplenty/models/item/flax.json new file mode 100644 index 000000000..020c4d495 --- /dev/null +++ b/src/main/resources/assets/biomesoplenty/models/item/flax.json @@ -0,0 +1,18 @@ +{ + "parent": "builtin/generated", + "textures": { + "layer0": "biomesoplenty:items/flax" + }, + "display": { + "thirdperson": { + "rotation": [ -90, 0, 0 ], + "translation": [ 0, 1, -3 ], + "scale": [ 0.55, 0.55, 0.55 ] + }, + "firstperson": { + "rotation": [ 0, -135, 25 ], + "translation": [ 0, 4, 2 ], + "scale": [ 1.7, 1.7, 1.7 ] + } + } +} diff --git a/src/main/resources/assets/biomesoplenty/textures/blocks/flax_flowers.png b/src/main/resources/assets/biomesoplenty/textures/blocks/flax_flowers.png new file mode 100644 index 000000000..f13699032 Binary files /dev/null and b/src/main/resources/assets/biomesoplenty/textures/blocks/flax_flowers.png differ diff --git a/src/main/resources/assets/biomesoplenty/textures/blocks/flax_lower.png b/src/main/resources/assets/biomesoplenty/textures/blocks/flax_lower.png new file mode 100644 index 000000000..c7417022e Binary files /dev/null and b/src/main/resources/assets/biomesoplenty/textures/blocks/flax_lower.png differ diff --git a/src/main/resources/assets/biomesoplenty/textures/blocks/flax_upper.png b/src/main/resources/assets/biomesoplenty/textures/blocks/flax_upper.png new file mode 100644 index 000000000..69fbfd8d9 Binary files /dev/null and b/src/main/resources/assets/biomesoplenty/textures/blocks/flax_upper.png differ diff --git a/src/main/resources/assets/biomesoplenty/textures/items/flax.png b/src/main/resources/assets/biomesoplenty/textures/items/flax.png new file mode 100644 index 000000000..dba5ace06 Binary files /dev/null and b/src/main/resources/assets/biomesoplenty/textures/items/flax.png differ