I am currently in the process of implementing colored beds. BlockBed's metadata is usually its direction, which is used amongst other things for rendering its textures correctly, but I removed the direction from the metadata and made a tile entity for it so that I could store the color of the bed in the bed's metadata.
Now, this is where we run into a problem. Beds are not rendered correctly at all. Here are two screenshots of how it currently looks:
As you can see, the beds are quite near being properly rendered, save for the foot ends and head ends on some of the beds.
I have tried for many hours to fix this problem, but to no avail. Here is the complete code of the BlockBedOverride class, which is used to replace the vanilla BlockBed. I hope that with the screenshots and code I have provided, you may be able to help me out.
public class BlockBedOverride extends BlockContainer {
/** Maps the foot-of-bed block to the head-of-bed block. */
public static final int[][] footBlockToHeadBlockMap = new int[][] {{0, 1}, { -1, 0}, {0, -1}, {1, 0}};
@SideOnly(Side.CLIENT)
private Icon[][] field_94472_b;
@SideOnly(Side.CLIENT)
private Icon[][] bedSideIcons;
@SideOnly(Side.CLIENT)
private Icon[][] bedTopIcons;
public BlockBedOverride(int par1) {
super(par1, Material.cloth);
this.setBounds();
this.disableStats();
}
@Override
public TileEntity createNewTileEntity(World world) {
return new BedDirection();
}
@Override
public void breakBlock(World world, int x, int y, int z, int i, int j) {
world.removeBlockTileEntity(x, y, z);
}
@Override
public int getBedDirection(IBlockAccess world, int x, int y, int z)
{
return getDirection(((BedDirection) world.getBlockTileEntity(x, y, z)).getDirection());
}
public static int getDirection(int par0)
{
return par0 & 3;
}
/**
* Called upon block activation (right click on the block.)
*/
public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
{
if (par1World.isRemote)
{
return true;
}
else
{
int i1 = ((BedDirection) par1World.getBlockTileEntity(par2, par3, par4)).getDirection();
if (!isBlockHeadOfBed(i1))
{
int j1 = getDirection(i1);
par2 += footBlockToHeadBlockMap[j1][0];
par4 += footBlockToHeadBlockMap[j1][1];
if (par1World.getBlockId(par2, par3, par4) != this.blockID)
{
return true;
}
i1 = ((BedDirection) par1World.getBlockTileEntity(par2, par3, par4)).getDirection();
}
if (par1World.provider.canRespawnHere() && par1World.getBiomeGenForCoords(par2, par4) != BiomeGenBase.hell)
{
if (isBedOccupied(i1))
{
EntityPlayer entityplayer1 = null;
Iterator iterator = par1World.playerEntities.iterator();
while (iterator.hasNext())
{
EntityPlayer entityplayer2 = (EntityPlayer)iterator.next();
if (entityplayer2.isPlayerSleeping())
{
ChunkCoordinates chunkcoordinates = entityplayer2.playerLocation;
if (chunkcoordinates.posX == par2 && chunkcoordinates.posY == par3 && chunkcoordinates.posZ == par4)
{
entityplayer1 = entityplayer2;
}
}
}
if (entityplayer1 != null)
{
par5EntityPlayer.addChatMessage("tile.bed.occupied");
return true;
}
setBedOccupied(par1World, par2, par3, par4, false);
}
EnumStatus enumstatus = par5EntityPlayer.sleepInBedAt(par2, par3, par4);
if (enumstatus == EnumStatus.OK)
{
setBedOccupied(par1World, par2, par3, par4, true);
return true;
}
else
{
if (enumstatus == EnumStatus.NOT_POSSIBLE_NOW)
{
par5EntityPlayer.addChatMessage("tile.bed.noSleep");
}
else if (enumstatus == EnumStatus.NOT_SAFE)
{
par5EntityPlayer.addChatMessage("tile.bed.notSafe");
}
return true;
}
}
else
{
double d0 = (double)par2 + 0.5D;
double d1 = (double)par3 + 0.5D;
double d2 = (double)par4 + 0.5D;
par1World.setBlockToAir(par2, par3, par4);
int k1 = getDirection(i1);
par2 += footBlockToHeadBlockMap[k1][0];
par4 += footBlockToHeadBlockMap[k1][1];
if (par1World.getBlockId(par2, par3, par4) == this.blockID)
{
par1World.setBlockToAir(par2, par3, par4);
d0 = (d0 + (double)par2 + 0.5D) / 2.0D;
d1 = (d1 + (double)par3 + 0.5D) / 2.0D;
d2 = (d2 + (double)par4 + 0.5D) / 2.0D;
}
par1World.newExplosion((Entity)null, (double)((float)par2 + 0.5F), (double)((float)par3 + 0.5F), (double)((float)par4 + 0.5F), 5.0F, true, true);
return true;
}
}
}
@SideOnly(Side.CLIENT)
public Icon getBlockTexture(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) {
if (par5 == 0)
{
return Block.planks.getBlockTextureFromSide(par5);
}
else
{
int colorIndex = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
int dir = ((BedDirection) par1IBlockAccess.getBlockTileEntity(par2, par3, par4)).getDirection();
int k = getDirection(dir);
int l = Direction.bedDirection[k][par5];
int i1 = isBlockHeadOfBed(dir) ? 1 : 0;
return (i1 != 1 || l != 2) && (i1 != 0 || l != 3) ? (l != 5 && l != 4 ? this.bedTopIcons[colorIndex][i1] : this.bedSideIcons[colorIndex][i1]) : this.field_94472_b[colorIndex][i1];
}
}
@SideOnly(Side.CLIENT)
/**
* 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.
*/
public void registerIcons(IconRegister par1IconRegister)
{
Icon head_end = par1IconRegister.registerIcon(this.getTextureName() + "_head_end");
this.bedTopIcons = new Icon[][] {
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_white"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_white")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_orange"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_orange")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_magenta"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_magenta")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_light_blue"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_light_blue")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_yellow"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_yellow")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_lime"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_lime")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_pink"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_pink")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_gray"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_gray")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_silver"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_silver")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_cyan"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_cyan")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_purple"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_purple")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_blue"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_blue")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_brown"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_brown")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_green"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_green")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_red"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_red")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_top_black"), par1IconRegister.registerIcon(this.getTextureName() + "_head_top_black")}};
this.field_94472_b = new Icon[][] {
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_white"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_orange"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_magenta"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_light_blue"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_yellow"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_lime"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_pink"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_gray"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_silver"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_cyan"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_purple"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_blue"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_brown"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_green"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_red"), head_end},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_end_black"), head_end}};
this.bedSideIcons = new Icon[][] {
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_white"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_white")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_orange"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_orange")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_magenta"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_magenta")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_light_blue"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_light_blue")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_yellow"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_yellow")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_lime"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_lime")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_pink"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_pink")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_gray"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_gray")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_silver"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_silver")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_cyan"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_cyan")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_purple"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_purple")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_blue"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_blue")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_brown"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_brown")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_green"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_green")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_red"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_red")},
new Icon[] { par1IconRegister.registerIcon(this.getTextureName() + "_feet_side_black"), par1IconRegister.registerIcon(this.getTextureName() + "_head_side_black")}};
}
/**
* The type of render function that is called for this block
*/
public int getRenderType()
{
return 14;
}
/**
* If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
*/
public boolean renderAsNormalBlock()
{
return false;
}
/**
* 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;
}
/**
* 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.setBounds();
}
/**
* 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)
{
int i1 = ((BedDirection) par1World.getBlockTileEntity(par2, par3, par4)).getDirection();
int j1 = getDirection(i1);
if (isBlockHeadOfBed(i1))
{
if (par1World.getBlockId(par2 - footBlockToHeadBlockMap[j1][0], par3, par4 - footBlockToHeadBlockMap[j1][1]) != this.blockID)
{
par1World.setBlockToAir(par2, par3, par4);
}
}
else if (par1World.getBlockId(par2 + footBlockToHeadBlockMap[j1][0], par3, par4 + footBlockToHeadBlockMap[j1][1]) != this.blockID)
{
par1World.setBlockToAir(par2, par3, par4);
if (!par1World.isRemote)
{
this.dropBlockAsItem(par1World, par2, par3, par4, i1, 0);
}
}
}
/**
* Returns the ID of the items to drop on destruction.
*/
public int idDropped(int par1, Random par2Random, int par3)
{
return isBlockHeadOfBed(par1) ? 0 : Item.bed.itemID;
}
/**
* Set the bounds of the bed block.
*/
private void setBounds()
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.5625F, 1.0F);
}
/**
* Returns whether or not this bed block is the head of the bed.
*/
public static boolean isBlockHeadOfBed(int par0)
{
return (par0 & 8) != 0;
}
/**
* Return whether or not the bed is occupied.
*/
public static boolean isBedOccupied(int par0)
{
return (par0 & 4) != 0;
}
/**
* Sets whether or not the bed is occupied.
*/
public static void setBedOccupied(World par0World, int par1, int par2, int par3, boolean par4)
{
int l = ((BedDirection) par0World.getBlockTileEntity(par1, par2, par3)).getDirection();
if (par4)
{
l |= 4;
}
else
{
l &= -5;
}
par0World.setBlockMetadataWithNotify(par1, par2, par3, l, 4);
}
/**
* Gets the nearest empty chunk coordinates for the player to wake up from a bed into.
*/
public static ChunkCoordinates getNearestEmptyChunkCoordinates(World par0World, int par1, int par2, int par3, int par4)
{
int i1 = ((BedDirection) par0World.getBlockTileEntity(par1, par2, par3)).getDirection();
int j1 = BlockDirectional.getDirection(i1);
for (int k1 = 0; k1 <= 1; ++k1)
{
int l1 = par1 - footBlockToHeadBlockMap[j1][0] * k1 - 1;
int i2 = par3 - footBlockToHeadBlockMap[j1][1] * k1 - 1;
int j2 = l1 + 2;
int k2 = i2 + 2;
for (int l2 = l1; l2 <= j2; ++l2)
{
for (int i3 = i2; i3 <= k2; ++i3)
{
if (par0World.doesBlockHaveSolidTopSurface(l2, par2 - 1, i3) && !par0World.getBlockMaterial(l2, par2, i3).isOpaque() && !par0World.getBlockMaterial(l2, par2 + 1, i3).isOpaque())
{
if (par4 <= 0)
{
return new ChunkCoordinates(l2, par2, i3);
}
--par4;
}
}
}
}
return null;
}
/**
* Drops the block items with a specified chance of dropping the specified items
*/
public void dropBlockAsItemWithChance(World par1World, int par2, int par3, int par4, int par5, float par6, int par7)
{
int dir = ((BedDirection) par1World.getBlockTileEntity(par2, par3, par4)).getDirection();
if (!isBlockHeadOfBed(dir))
{
super.dropBlockAsItemWithChance(par1World, par2, par3, par4, dir, par6, 0);
}
}
/**
* Returns the mobility information of the block, 0 = free, 1 = can't push but can move over, 2 = total immobility
* and stop pistons
*/
public int getMobilityFlag()
{
return 1;
}
@SideOnly(Side.CLIENT)
/**
* only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative)
*/
public int idPicked(World par1World, int par2, int par3, int par4)
{
return Item.bed.itemID;
}
/**
* Called when the block is attempted to be harvested
*/
public void onBlockHarvested(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer)
{
int dir = ((BedDirection) par1World.getBlockTileEntity(par2, par3, par4)).getDirection();
if (par6EntityPlayer.capabilities.isCreativeMode && isBlockHeadOfBed(dir))
{
int i1 = getDirection(dir);
par2 -= footBlockToHeadBlockMap[i1][0];
par4 -= footBlockToHeadBlockMap[i1][1];
if (par1World.getBlockId(par2, par3, par4) == this.blockID)
{
par1World.setBlockToAir(par2, par3, par4);
}
}
}
}
Your answer definately helped me immensely, MAIDEN. I can't believe I overlooked that obvious method. Here is the code I added to BlockBedOverride:
@Override
public int getBedDirection(IBlockAccess world, int x, int y, int z)
{
return getDirection(((BedDirection) world.getBlockTileEntity(x, y, z)).getDirection());
}
It works, but not like a charm, as you can see from this screenshot:
I'm pretty sure I merely failed at copy-pasting the code from BedBlock somewhere, but until I've found what I did wrong, I'll let this problem remain unresolved for now.
Still uncertain exactly as to how the bed sides are still not being rendered properly. I have been playing around with the variables in the relevant methods, but to no avail. Bumping this to direct attention towards the as of yet unresolved problem.
i don't know if this would make any difference, but you've still got the vanilla getDirection method returning something, I don't know if that's ever called from somewhere else like in the bed render (assuming you're using the default bed rendering?)
public static int getDirection(int par0)
{
return par0 & 3;
}
edit:
nope, as far as i can tell it's only called by the getBedDirection in the Block class..
That method is indeed still present in the overridden bed block with which I replace the vanilla bed block. It's called by getBedDirection and getBlockTexture amongst other methods.
In a final, desperate attempt to resolve this issue, I made a deal with Satan and swapped the bed's direction from the tile entity back to the meta data, and the bed's color from the metadata to the tile entity. A few more tweaks later, most notably to the item dropping behavior, and the problem was resolved.
I am tagging this thread as solved. Anyone who wishes to view the solution I came up with: I invite you to take a look at BetterVanilla's source code, which is the mod for which I had been working to implement these colored beds into.
Now, this is where we run into a problem. Beds are not rendered correctly at all. Here are two screenshots of how it currently looks:
As you can see, the beds are quite near being properly rendered, save for the foot ends and head ends on some of the beds.
I have tried for many hours to fix this problem, but to no avail. Here is the complete code of the BlockBedOverride class, which is used to replace the vanilla BlockBed. I hope that with the screenshots and code I have provided, you may be able to help me out.
My mods: Archmagus, BetterBoneMeal, BetterVanilla, Brewing-API, NaturalArmors, and PluckableChickens!
My mods: Archmagus, BetterBoneMeal, BetterVanilla, Brewing-API, NaturalArmors, and PluckableChickens!
public int getBedDirection(IBlockAccess world, int x, int y, int z)
{
/* get your tile entity from the world, read its _direction and return it */
}
It works, but not like a charm, as you can see from this screenshot:
I'm pretty sure I merely failed at copy-pasting the code from BedBlock somewhere, but until I've found what I did wrong, I'll let this problem remain unresolved for now.
My mods: Archmagus, BetterBoneMeal, BetterVanilla, Brewing-API, NaturalArmors, and PluckableChickens!
My mods: Archmagus, BetterBoneMeal, BetterVanilla, Brewing-API, NaturalArmors, and PluckableChickens!
edit:
nope, as far as i can tell it's only called by the getBedDirection in the Block class..
That method is indeed still present in the overridden bed block with which I replace the vanilla bed block. It's called by getBedDirection and getBlockTexture amongst other methods.
My mods: Archmagus, BetterBoneMeal, BetterVanilla, Brewing-API, NaturalArmors, and PluckableChickens!
My mods: Archmagus, BetterBoneMeal, BetterVanilla, Brewing-API, NaturalArmors, and PluckableChickens!
My mods: Archmagus, BetterBoneMeal, BetterVanilla, Brewing-API, NaturalArmors, and PluckableChickens!
My mods: Archmagus, BetterBoneMeal, BetterVanilla, Brewing-API, NaturalArmors, and PluckableChickens!
I am tagging this thread as solved. Anyone who wishes to view the solution I came up with: I invite you to take a look at BetterVanilla's source code, which is the mod for which I had been working to implement these colored beds into.
My mods: Archmagus, BetterBoneMeal, BetterVanilla, Brewing-API, NaturalArmors, and PluckableChickens!