I'm making a "grass cover" block, which is meant to mimic the behavior of snow (except melting) but look like grass. So far I have the snow behavior working perfectly, but the grass shading has problem to be a bit challenging. The top of the block uses the correct color, but the sides are all completely gray! What am I doing wrong? Here's the source code for the block:
package hvh.mod.coverblocks;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.Icon;
import net.minecraft.world.ColorizerFoliage;
import net.minecraft.world.ColorizerGrass;
import net.minecraft.world.EnumSkyBlock;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class BlockGrassCover extends Block
{
public BlockGrassCover(int id)
{
super(id, Material.grass);
setHardness(0.3f);
setStepSound(soundGrassFootstep);
setCreativeTab(CreativeTabs.tabDecorations);
}
/**
* When this method is called, your block should register all the icons it needs with the given IconRegister. This
* is the only chance you get to register icons.
*/
@SideOnly(Side.CLIENT)
public void registerIcons(IconRegister par1IconRegister)
{
this.blockIcon = par1IconRegister.registerIcon("grass_top");
}
/**
* Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
* cleared to be reused)
*/
public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
{
int l = par1World.getBlockMetadata(par2, par3, par4) & 7;
float f = 0.125F;
return AxisAlignedBB.getAABBPool().getAABB((double)par2 + this.minX, (double)par3 + this.minY, (double)par4 + this.minZ, (double)par2 + this.maxX, (double)((float)par3 + (float)l * f), (double)par4 + this.maxZ);
}
/**
* Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two
* adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
*/
public boolean isOpaqueCube()
{
return false;
}
/**
* If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
*/
public boolean renderAsNormalBlock()
{
return false;
}
/**
* Sets the block's bounds for rendering it as an item
*/
public void setBlockBoundsForItemRender()
{
this.setBlockBoundsForSnowDepth(0);
}
/**
* Updates the blocks bounds based on its current state. Args: world, x, y, z
*/
public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
{
this.setBlockBoundsForSnowDepth(par1IBlockAccess.getBlockMetadata(par2, par3, par4));
}
/**
* calls setBlockBounds based on the depth of the snow. Int is any values 0x0-0x7, usually this blocks metadata.
*/
protected void setBlockBoundsForSnowDepth(int par1)
{
int j = par1 & 7;
float f = (float)(2 * (1 + j)) / 16.0F;
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, f, 1.0F);
}
/**
* Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
*/
public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
{
int l = par1World.getBlockId(par2, par3 - 1, par4);
Block block = Block.blocksList[l];
if (block == null) return false;
if (block == this) return true;
if (block == this && (par1World.getBlockMetadata(par2, par3 - 1, par4) & 7) == 7) return true;
if (!block.isLeaves(par1World, par2, par3 - 1, par4) && !Block.blocksList[l].isOpaqueCube()) return false;
return par1World.getBlockMaterial(par2, par3 - 1, par4).blocksMovement();
}
/**
* Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
* their own) Args: x, y, z, neighbor blockID
*/
public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
{
this.canSnowStay(par1World, par2, par3, par4);
}
/**
* Checks if this snow block can stay at this location.
*/
private boolean canSnowStay(World par1World, int par2, int par3, int par4)
{
if (!this.canPlaceBlockAt(par1World, par2, par3, par4))
{
par1World.setBlockToAir(par2, par3, par4);
return false;
}
else
{
return true;
}
}
/**
* Called when the player destroys a block with an item that can harvest it. (i, j, k) are the coordinates of the
* block and l is the block's subtype/damage.
*/
public void harvestBlock(World par1World, EntityPlayer par2EntityPlayer, int par3, int par4, int par5, int par6)
{
super.harvestBlock(par1World, par2EntityPlayer, par3, par4, par5, par6);
par1World.setBlockToAir(par3, par4, par5);
}
/**
* Returns the quantity of items to drop on block destruction.
*/
public int quantityDropped(Random par1Random)
{
return 0;
}
@Override
public int quantityDropped(int meta, int fortune, Random random)
{
return 0;
}
@SideOnly(Side.CLIENT)
public int getBlockColor()
{
double d0 = 0.5D;
double d1 = 1.0D;
return ColorizerGrass.getGrassColor(d0, d1);
}
@SideOnly(Side.CLIENT)
/**
* Returns the color this block should be rendered. Used by leaves.
*/
public int getRenderColor(int par1)
{
return this.getBlockColor();
}
/**
* Returns a integer with hex for 0xrrggbb with this color multiplied against the blocks color. Note only called
* when first determining what to render.
*/
@SideOnly(Side.CLIENT)
public int colorMultiplier(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
{
int i1 = 0;
int j1 = 0;
int k1 = 0;
for (int l1 = -1; l1 <= 1; ++l1)
{
for (int i2 = -1; i2 <= 1; ++i2)
{
int j2 = par1IBlockAccess.getBiomeGenForCoords(par2 + i2, par4 + l1).getBiomeGrassColor();
i1 += (j2 & 16711680) >> 16;
j1 += (j2 & 65280) >> 8;
k1 += j2 & 255;
}
}
return (i1 / 9 & 255) << 16 | (j1 / 9 & 255) << 8 | k1 / 9 & 255;
}
@SideOnly(Side.CLIENT)
public static Icon getIconSideOverlay()
{
return CoverBlocksMod.grassCover.getIcon(0, 0);
}
}
Any advice? Thanks in advance.