So, I'm working on a block that's basically a copy of the BlockLadder class, but what I want to do is use the extra metadata values to allow you to right click the block and it will keep it's orientation but have a different texture.
The problem I am having is that it will not render above the default metadata values of a ladder. The block will be there with the correct bounding box as I've set it, but I can't figure out how to actually make it render with the set texture.
Keep in mind that it does actually have the texture set to it as if I break it, I can see particles for that texture.
Basically, I just need help in figuring out which function I should look for to fix the issue.
So, I'm working on a block that's basically a copy of the BlockLadder class, but what I want to do is use the extra metadata values to allow you to right click the block and it will keep it's orientation but have a different texture.
The problem I am having is that it will not render above the default metadata values of a ladder. The block will be there with the correct bounding box as I've set it, but I can't figure out how to actually make it render with the set texture.
Keep in mind that it does actually have the texture set to it as if I break it, I can see particles for that texture.
Basically, I just need help in figuring out which function I should look for to fix the issue.
Try using tileEntity, because with TE's you can save rotation or stuff like that
You can save rotation with metadata as well. What you can do is grab the ForgeDirection entry when the player places the block, set the block metadata to the ordinal value of the instance, then when you want to fetch the rotated block, use the metadata as the index for the ForgeDirection array.
Rollback Post to RevisionRollBack
Author of the Clarity, Serenity, Sapphire & Halcyon shader packs for Minecraft: Java Edition.
You can save rotation with metadata as well. What you can do is grab the ForgeDirection entry when the player places the block, set the block metadata to the ordinal value of the instance, then when you want to fetch the rotated block, use the metadata as the index for the ForgeDirection array.
Here's my code. I've only started learning Java a couple weeks ago so it's probably not the best. A lot of trial and error.
package toast.modysseyExtras;
import java.util.Random;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
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.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.Icon;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
import static net.minecraftforge.common.ForgeDirection.*;
public class BlockCard extends Block
{
@SideOnly(Side.CLIENT)
private Icon[] iconArray;
public BlockCard (int id, Material material)
{
super(id, material);
}
/**
* Called upon block activation (right click on the block.)
*/
@Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float xOff, float yOff, float zOff)
{
if (!world.isRemote) {
if (world.getBlockMetadata(x, y, z) < 6) {
int newMeta = world.getBlockMetadata(x, y, z) + 4;
world.setBlockMetadataWithNotify(x, y, z, newMeta, 2);
} else if (world.getBlockMetadata(x, y, z) > 5) {
int newMeta = world.getBlockMetadata(x, y, z) - 4;
world.setBlockMetadataWithNotify(x, y, z, newMeta, 2);
}
player.addChatMessage("Tex: " + this.getTextureName());
return true;
}
return false;
}
@SideOnly(Side.CLIENT)
/**
* From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
*/
public Icon getIcon(int par1, int par2)
{
return this.iconArray[par2 % this.iconArray.length];
}
@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)
{
this.iconArray = new Icon[10];
for (int i = 0; i < 6; ++i)
{
this.iconArray = par1IconRegister.registerIcon(this.getTextureName() + "_b");
}
for (int i = 6; i < 10; ++i)
{
this.iconArray = par1IconRegister.registerIcon(this.getTextureName() + "_r");
}
}
/**
* 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)
{
this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
return super.getCollisionBoundingBoxFromPool(par1World, par2, par3, par4);
}
@SideOnly(Side.CLIENT)
/**
* Returns the bounding box of the wired rectangular prism to render.
*/
public AxisAlignedBB getSelectedBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
{
this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
return super.getSelectedBoundingBoxFromPool(par1World, par2, par3, par4);
}
/**
* 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.updateLadderBounds(par1IBlockAccess.getBlockMetadata(par2, par3, par4));
}
/**
* Update the ladder block bounds based on the given metadata value.
*/
public void updateLadderBounds(int par1)
{
float f = 0.125F;
if (par1 == 2)
{
this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F);
}
if (par1 == 3)
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f);
}
if (par1 == 4)
{
this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
if (par1 == 5)
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F);
}
if (par1 == 6)
{
this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F);
}
if (par1 == 7)
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f);
}
if (par1 == 8)
{
this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
if (par1 == 9)
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F);
}
}
/**
* 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;
}
/**
* The type of render function that is called for this block
*/
public int getRenderType()
{
return 8;
}
/**
* 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)
{
return par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST) ||
par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST) ||
par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH) ||
par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH);
}
/**
* Called when a block is placed using its ItemBlock. Args: World, X, Y, Z, side, hitX, hitY, hitZ, block metadata
*/
public int onBlockPlaced(World par1World, int par2, int par3, int par4, int par5, float par6, float par7, float par8, int par9)
{
int j1 = par9;
if ((j1 == 0 || par5 == 2) && par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH))
{
j1 = 2;
}
if ((j1 == 0 || par5 == 3) && par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH))
{
j1 = 3;
}
if ((j1 == 0 || par5 == 4) && par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST))
{
j1 = 4;
}
if ((j1 == 0 || par5 == 5) && par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST))
{
j1 = 5;
}
return j1;
}
/**
* 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 = par1World.getBlockMetadata(par2, par3, par4);
boolean flag = false;
if (i1 == 2 && par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH))
{
flag = true;
}
if (i1 == 3 && par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH))
{
flag = true;
}
if (i1 == 4 && par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST))
{
flag = true;
}
if (i1 == 5 && par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST))
{
flag = true;
}
if (i1 == 6 && par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH))
{
flag = true;
}
if (i1 == 7 && par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH))
{
flag = true;
}
if (i1 == 8 && par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST))
{
flag = true;
}
if (i1 == 9 && par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST))
{
flag = true;
}
if (!flag)
{
this.dropBlockAsItem(par1World, par2, par3, par4, i1, 0);
par1World.setBlockToAir(par2, par3, par4);
}
super.onNeighborBlockChange(par1World, par2, par3, par4, par5);
}
/**
* Returns the quantity of items to drop on block destruction.
*/
public int quantityDropped(Random par1Random)
{
return 1;
}
@Override
public boolean isLadder(World world, int x, int y, int z, EntityLivingBase entity)
{
return false;
}
}
Here's my code. I've only started learning Java a couple weeks ago so it's probably not the best. A lot of trial and error.
package toast.modysseyExtras;
import java.util.Random;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
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.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.Icon;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
import static net.minecraftforge.common.ForgeDirection.*;
public class BlockCard extends Block
{
@SideOnly(Side.CLIENT)
private Icon[] iconArray;
public BlockCard (int id, Material material)
{
super(id, material);
}
/**
* Called upon block activation (right click on the block.)
*/
@Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float xOff, float yOff, float zOff)
{
if (!world.isRemote) {
if (world.getBlockMetadata(x, y, z) < 6) {
int newMeta = world.getBlockMetadata(x, y, z) + 4;
world.setBlockMetadataWithNotify(x, y, z, newMeta, 2);
} else if (world.getBlockMetadata(x, y, z) > 5) {
int newMeta = world.getBlockMetadata(x, y, z) - 4;
world.setBlockMetadataWithNotify(x, y, z, newMeta, 2);
}
player.addChatMessage("Tex: " + this.getTextureName());
return true;
}
return false;
}
@SideOnly(Side.CLIENT)
/**
* From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
*/
public Icon getIcon(int par1, int par2)
{
return this.iconArray[par2 % this.iconArray.length];
}
@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)
{
this.iconArray = new Icon[10];
for (int i = 0; i < 6; ++i)
{
this.iconArray = par1IconRegister.registerIcon(this.getTextureName() + "_b");
}
for (int i = 6; i < 10; ++i)
{
this.iconArray = par1IconRegister.registerIcon(this.getTextureName() + "_r");
}
}
/**
* 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)
{
this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
return super.getCollisionBoundingBoxFromPool(par1World, par2, par3, par4);
}
@SideOnly(Side.CLIENT)
/**
* Returns the bounding box of the wired rectangular prism to render.
*/
public AxisAlignedBB getSelectedBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
{
this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
return super.getSelectedBoundingBoxFromPool(par1World, par2, par3, par4);
}
/**
* 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.updateLadderBounds(par1IBlockAccess.getBlockMetadata(par2, par3, par4));
}
/**
* Update the ladder block bounds based on the given metadata value.
*/
public void updateLadderBounds(int par1)
{
float f = 0.125F;
if (par1 == 2)
{
this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F);
}
if (par1 == 3)
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f);
}
if (par1 == 4)
{
this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
if (par1 == 5)
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F);
}
if (par1 == 6)
{
this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F);
}
if (par1 == 7)
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f);
}
if (par1 == 8)
{
this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
if (par1 == 9)
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F);
}
}
/**
* 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;
}
/**
* The type of render function that is called for this block
*/
public int getRenderType()
{
return 8;
}
/**
* 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)
{
return par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST) ||
par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST) ||
par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH) ||
par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH);
}
/**
* Called when a block is placed using its ItemBlock. Args: World, X, Y, Z, side, hitX, hitY, hitZ, block metadata
*/
public int onBlockPlaced(World par1World, int par2, int par3, int par4, int par5, float par6, float par7, float par8, int par9)
{
int j1 = par9;
if ((j1 == 0 || par5 == 2) && par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH))
{
j1 = 2;
}
if ((j1 == 0 || par5 == 3) && par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH))
{
j1 = 3;
}
if ((j1 == 0 || par5 == 4) && par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST))
{
j1 = 4;
}
if ((j1 == 0 || par5 == 5) && par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST))
{
j1 = 5;
}
return j1;
}
/**
* 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 = par1World.getBlockMetadata(par2, par3, par4);
boolean flag = false;
if (i1 == 2 && par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH))
{
flag = true;
}
if (i1 == 3 && par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH))
{
flag = true;
}
if (i1 == 4 && par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST))
{
flag = true;
}
if (i1 == 5 && par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST))
{
flag = true;
}
if (i1 == 6 && par1World.isBlockSolidOnSide(par2, par3, par4 + 1, NORTH))
{
flag = true;
}
if (i1 == 7 && par1World.isBlockSolidOnSide(par2, par3, par4 - 1, SOUTH))
{
flag = true;
}
if (i1 == 8 && par1World.isBlockSolidOnSide(par2 + 1, par3, par4, WEST))
{
flag = true;
}
if (i1 == 9 && par1World.isBlockSolidOnSide(par2 - 1, par3, par4, EAST))
{
flag = true;
}
if (!flag)
{
this.dropBlockAsItem(par1World, par2, par3, par4, i1, 0);
par1World.setBlockToAir(par2, par3, par4);
}
super.onNeighborBlockChange(par1World, par2, par3, par4, par5);
}
/**
* Returns the quantity of items to drop on block destruction.
*/
public int quantityDropped(Random par1Random)
{
return 1;
}
@Override
public boolean isLadder(World world, int x, int y, int z, EntityLivingBase entity)
{
return false;
}
}
Is your code ever called? Does the message get sent to the player?
You should also remove the isRemote check. Doing things such as setting metadata or blocks should be done on both client and server, not just one or the other.
Rollback Post to RevisionRollBack
Author of the Clarity, Serenity, Sapphire & Halcyon shader packs for Minecraft: Java Edition.
The code is called and the message is sent to the player. I put in the isRemote check because it would call it twice. I should have mentioned too that this is 1.6.4.
The code is called and the message is sent to the player. I put in the isRemote check because it would call it twice. I should have mentioned too that this is 1.6.4.
The reason why the message is sent twice is because the code is ran twice, once on the client, and once on the server. For things like sending messages to players, or rendering, or spawning particles, you should do these on one side of the logic (AFAIK server for message, and client for rendering and particles). However, for things like setting data in a tile entity, or setting a block, or setting a block's metadata, or changing data tied to an entity, you typically should do these on both sides of logic.
The server is what actually stores the data, the server data will overwrite the client data for data that is common on both sides of the logic. The client is what controls rendering, sounds and particles, and for some things, sends data to the server, such as a key being pressed or the camera being moved.
Rollback Post to RevisionRollBack
Author of the Clarity, Serenity, Sapphire & Halcyon shader packs for Minecraft: Java Edition.
The reason why the message is sent twice is because the code is ran twice, once on the client, and once on the server. For things like sending messages to players, or rendering, or spawning particles, you should do these on one side of the logic (AFAIK server for message, and client for rendering and particles). However, for things like setting data in a tile entity, or setting a block, or setting a block's metadata, or changing data tied to an entity, you typically should do these on both sides of logic.
The server is what actually stores the data, the server data will overwrite the client data for data that is common on both sides of the logic. The client is what controls rendering, sounds and particles, and for some things, sends data to the server, such as a key being pressed or the camera being moved.
Alright, I changed it as you suggested although it doesn't fix the original issue. The message was actually just for debugging.
The problem I am having is that it will not render above the default metadata values of a ladder. The block will be there with the correct bounding box as I've set it, but I can't figure out how to actually make it render with the set texture.
Keep in mind that it does actually have the texture set to it as if I break it, I can see particles for that texture.
Basically, I just need help in figuring out which function I should look for to fix the issue.
Can I take a look at your code?
You can save rotation with metadata as well. What you can do is grab the ForgeDirection entry when the player places the block, set the block metadata to the ordinal value of the instance, then when you want to fetch the rotated block, use the metadata as the index for the ForgeDirection array.
Author of the Clarity, Serenity, Sapphire & Halcyon shader packs for Minecraft: Java Edition.
My Github page.
The entire Minecraft shader development community now has its own Discord server! Feel free to join and chat with all the developers!
Here's my code. I've only started learning Java a couple weeks ago so it's probably not the best. A lot of trial and error.
Is your code ever called? Does the message get sent to the player?
You should also remove the isRemote check. Doing things such as setting metadata or blocks should be done on both client and server, not just one or the other.
Author of the Clarity, Serenity, Sapphire & Halcyon shader packs for Minecraft: Java Edition.
My Github page.
The entire Minecraft shader development community now has its own Discord server! Feel free to join and chat with all the developers!
The reason why the message is sent twice is because the code is ran twice, once on the client, and once on the server. For things like sending messages to players, or rendering, or spawning particles, you should do these on one side of the logic (AFAIK server for message, and client for rendering and particles). However, for things like setting data in a tile entity, or setting a block, or setting a block's metadata, or changing data tied to an entity, you typically should do these on both sides of logic.
The server is what actually stores the data, the server data will overwrite the client data for data that is common on both sides of the logic. The client is what controls rendering, sounds and particles, and for some things, sends data to the server, such as a key being pressed or the camera being moved.
Author of the Clarity, Serenity, Sapphire & Halcyon shader packs for Minecraft: Java Edition.
My Github page.
The entire Minecraft shader development community now has its own Discord server! Feel free to join and chat with all the developers!
Alright, I changed it as you suggested although it doesn't fix the original issue. The message was actually just for debugging.