My friend and I are trying to make custom TNT and the tile entity won't render when the fuse is lit. We've googled around and we see that other people hit the same wall but we can't find a definitive solution to the problem. Does anybody know of any tutorials for the proper process of creating custom TNT in MC 1.3.2 and/or 1.4.2 using Forge?
Oops, sorry. Thought he was part of your mod team and not just some random person hijacking your thread.
Haha! Nope.
My buddy is getting the code together here, he's rushing to put it up so we can get your eyes on it. We'd love to get your thoughts on it ASAP cuz it's been killin' us for awhile now. You around for a bit?
EntityRegistry.registerGlobalEntityID(EntityNewTNTPrimed.class, "newTNTPrimed", 10);
RenderingRegistry.registerEntityRenderingHandler(EntityNewTNTPrimed.class, new RenderNewTNTPrimed());
Block:
package khufu.pack;
import java.util.Random;
import net.minecraft.src.Block;
import net.minecraft.src.CreativeTabs;
import net.minecraft.src.Entity;
import net.minecraft.src.EntityArrow;
import net.minecraft.src.EntityPlayer;
import khufu.pack.EntityNewTNTPrimed;
import net.minecraft.src.Item;
import net.minecraft.src.Material;
import net.minecraft.src.World;
public class BlockNewTNT extends Block {
public BlockNewTNT(int par1, int par2)
{
super(par1, par2, Material.tnt);
this.setCreativeTab(CreativeTabs.tabRedstone);
blockIndexInTexture = Block.tnt.blockIndexInTexture;
}
/**
* Returns the block texture based on the side being looked at. Args: side
*/
public int getBlockTextureFromSide(int par1)
{
return par1 == 0 ? this.blockIndexInTexture + 2 : (par1 == 1 ? this.blockIndexInTexture + 1 : this.blockIndexInTexture);
}
/**
* Called whenever the block is added into the world. Args: world, x, y, z
*/
public void onBlockAdded(World par1World, int par2, int par3, int par4)
{
super.onBlockAdded(par1World, par2, par3, par4);
if (par1World.isBlockIndirectlyGettingPowered(par2, par3, par4))
{
this.onBlockDestroyedByPlayer(par1World, par2, par3, par4, 1);
par1World.setBlockWithNotify(par2, par3, par4, 0);
}
}
/**
* 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)
{
if (par5 > 0 && Block.blocksList[par5].canProvidePower() && par1World.isBlockIndirectlyGettingPowered(par2, par3, par4))
{
this.onBlockDestroyedByPlayer(par1World, par2, par3, par4, 1);
par1World.setBlockWithNotify(par2, par3, par4, 0);
}
}
/**
* Returns the quantity of items to drop on block destruction.
*/
public int quantityDropped(Random par1Random)
{
return 1;
}
/**
* Called upon the block being destroyed by an explosion
*/
public void onBlockDestroyedByExplosion(World par1World, int par2, int par3, int par4)
{
if (!par1World.isRemote)
{
EntityNewTNTPrimed var5 = new EntityNewTNTPrimed(par1World, (double)((float)par2 + 0.5F), (double)((float)par3 + 0.5F), (double)((float)par4 + 0.5F));
var5.fuse = par1World.rand.nextInt(var5.fuse / 4) + var5.fuse / 8;
par1World.spawnEntityInWorld(var5);
}
}
/**
* Called right before the block is destroyed by a player. Args: world, x, y, z, metaData
*/
public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5)
{
if (!par1World.isRemote)
{
if ((par5 & 1) == 1)
{
EntityNewTNTPrimed var6 = new EntityNewTNTPrimed(par1World, (double)((float)par2 + 0.5F), (double)((float)par3 + 0.5F), (double)((float)par4 + 0.5F));
par1World.spawnEntityInWorld(var6);
par1World.playSoundAtEntity(var6, "random.fuse", 1.0F, 1.0F);
}
}
}
/**
* 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 (par5EntityPlayer.getCurrentEquippedItem() != null && par5EntityPlayer.getCurrentEquippedItem().itemID == Item.flintAndSteel.shiftedIndex)
{
this.onBlockDestroyedByPlayer(par1World, par2, par3, par4, 1);
par1World.setBlockWithNotify(par2, par3, par4, 0);
return true;
}
else
{
return super.onBlockActivated(par1World, par2, par3, par4, par5EntityPlayer, par6, par7, par8, par9);
}
}
/**
* Triggered whenever an entity collides with this block (enters into the block). Args: world, x, y, z, entity
*/
public void onEntityCollidedWithBlock(World par1World, int par2, int par3, int par4, Entity par5Entity)
{
if (par5Entity instanceof EntityArrow && !par1World.isRemote)
{
EntityArrow var6 = (EntityArrow)par5Entity;
if (var6.isBurning())
{
this.onBlockDestroyedByPlayer(par1World, par2, par3, par4, 1);
par1World.setBlockWithNotify(par2, par3, par4, 0);
}
}
}
}
Entity:
package khufu.pack;
import net.minecraft.src.Entity;
import net.minecraft.src.NBTTagCompound;
import net.minecraft.src.World;
import cpw.mods.fml.common.Side;
import cpw.mods.fml.common.asm.SideOnly;
public class EntityNewTNTPrimed extends Entity
{
/** How long the fuse is */
public int fuse;
public EntityNewTNTPrimed(World par1World)
{
super(par1World);
this.fuse = 0;
this.preventEntitySpawning = true;
this.setSize(0.98F, 0.98F);
this.yOffset = this.height / 2.0F;
}
public EntityNewTNTPrimed(World par1World, double par2, double par4, double par6)
{
this(par1World);
this.setPosition(par2, par4, par6);
float var8 = (float)(Math.random() * Math.PI * 2.0D);
this.motionX = (double)(-((float)Math.sin((double)var8)) * 0.02F);
this.motionY = 0.20000000298023224D;
this.motionZ = (double)(-((float)Math.cos((double)var8)) * 0.02F);
this.fuse = 80;
this.prevPosX = par2;
this.prevPosY = par4;
this.prevPosZ = par6;
}
protected void entityInit() {}
/**
* returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
* prevent them from trampling crops
*/
protected boolean canTriggerWalking()
{
return false;
}
/**
* Returns true if other Entities should be prevented from moving through this Entity.
*/
public boolean canBeCollidedWith()
{
return !this.isDead;
}
/**
* Called to update the entity's position/logic.
*/
public void onUpdate()
{
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
this.motionY -= 0.03999999910593033D;
this.moveEntity(this.motionX, this.motionY, this.motionZ);
this.motionX *= 0.9800000190734863D;
this.motionY *= 0.9800000190734863D;
this.motionZ *= 0.9800000190734863D;
if (this.onGround)
{
this.motionX *= 0.699999988079071D;
this.motionZ *= 0.699999988079071D;
this.motionY *= -0.5D;
}
if (this.fuse-- <= 0)
{
this.setDead();
if (!this.worldObj.isRemote)
{
this.explode();
}
}
else
{
this.worldObj.spawnParticle("smoke", this.posX, this.posY + 0.5D, this.posZ, 0.0D, 0.0D, 0.0D);
}
}
private void explode()
{
float var1 = 4.0F;
this.worldObj.createExplosion((Entity)null, this.posX, this.posY, this.posZ, var1, true);
}
/**
* (abstract) Protected helper method to write subclass entity data to NBT.
*/
protected void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
{
par1NBTTagCompound.setByte("Fuse", (byte)this.fuse);
}
/**
* (abstract) Protected helper method to read subclass entity data from NBT.
*/
protected void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
{
this.fuse = par1NBTTagCompound.getByte("Fuse");
}
@SideOnly(Side.CLIENT)
public float getShadowSize()
{
return 0.0F;
}
}
Render:
package khufu.pack;
import net.minecraft.src.Entity;
import net.minecraft.src.NBTTagCompound;
import net.minecraft.src.World;
import cpw.mods.fml.common.Side;
import cpw.mods.fml.common.asm.SideOnly;
public class EntityNewTNTPrimed extends Entity
{
/** How long the fuse is */
public int fuse;
public EntityNewTNTPrimed(World par1World)
{
super(par1World);
this.fuse = 0;
this.preventEntitySpawning = true;
this.setSize(0.98F, 0.98F);
this.yOffset = this.height / 2.0F;
}
public EntityNewTNTPrimed(World par1World, double par2, double par4, double par6)
{
this(par1World);
this.setPosition(par2, par4, par6);
float var8 = (float)(Math.random() * Math.PI * 2.0D);
this.motionX = (double)(-((float)Math.sin((double)var8)) * 0.02F);
this.motionY = 0.20000000298023224D;
this.motionZ = (double)(-((float)Math.cos((double)var8)) * 0.02F);
this.fuse = 80;
this.prevPosX = par2;
this.prevPosY = par4;
this.prevPosZ = par6;
}
protected void entityInit() {}
/**
* returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
* prevent them from trampling crops
*/
protected boolean canTriggerWalking()
{
return false;
}
/**
* Returns true if other Entities should be prevented from moving through this Entity.
*/
public boolean canBeCollidedWith()
{
return !this.isDead;
}
/**
* Called to update the entity's position/logic.
*/
public void onUpdate()
{
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
this.motionY -= 0.03999999910593033D;
this.moveEntity(this.motionX, this.motionY, this.motionZ);
this.motionX *= 0.9800000190734863D;
this.motionY *= 0.9800000190734863D;
this.motionZ *= 0.9800000190734863D;
if (this.onGround)
{
this.motionX *= 0.699999988079071D;
this.motionZ *= 0.699999988079071D;
this.motionY *= -0.5D;
}
if (this.fuse-- <= 0)
{
this.setDead();
if (!this.worldObj.isRemote)
{
this.explode();
}
}
else
{
this.worldObj.spawnParticle("smoke", this.posX, this.posY + 0.5D, this.posZ, 0.0D, 0.0D, 0.0D);
}
}
private void explode()
{
float var1 = 4.0F;
this.worldObj.createExplosion((Entity)null, this.posX, this.posY, this.posZ, var1, true);
}
/**
* (abstract) Protected helper method to write subclass entity data to NBT.
*/
protected void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
{
par1NBTTagCompound.setByte("Fuse", (byte)this.fuse);
}
/**
* (abstract) Protected helper method to read subclass entity data from NBT.
*/
protected void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
{
this.fuse = par1NBTTagCompound.getByte("Fuse");
}
@SideOnly(Side.CLIENT)
public float getShadowSize()
{
return 0.0F;
}
}
// Client stuff
public void registerRenderers () {
// Nothing here as this is the server side proxy
}
public void registerEntites() {
EntityRegistry.registerGlobalEntityID(EntityNewTNTPrimed.class, "newTNTPrimed", 10);
EntityRegistry.registerModEntity(EntityNewTNTPrimed.class, "newTNTPrimed", 10, ModRegistry.instance, 16, 1, false);
}
Client Proxy:
RenderingRegistry.registerEntityRenderingHandler(EntityNewTNTPrimed.class, new RenderNewTNTPrimed());
The Entity's render time is controlled by the first "this.fuse". The actual fuse length of the TNT is controlled by the second "this.fuse", as seen in the EntityTNTPrimed.
I have no idea why vanilla Lit TNT's render doesn't observe this behaviour, but in our custom TNT EntityCustomTNTPrimed.class, this is what fixed the render problem:
/** How long the fuse is */
public int fuse;
public EntityNewTNTPrimed(World par1World)
{
super(par1World);
this.fuse = 0; <------------------------- change this number to match below (ie. 80)
this.preventEntitySpawning = true;
this.setSize(0.98F, 0.98F);
this.yOffset = this.height / 2.0F;
}
public EntityNewTNTPrimed(World par1World, double par2, double par4, double par6)
{
this(par1World);
this.setPosition(par2, par4, par6);
float var8 = (float)(Math.random() * Math.PI * 2.0D);
this.motionX = (double)(-((float)Math.sin((double)var8)) * 0.02F);
this.motionY = 0.20000000298023224D;
this.motionZ = (double)(-((float)Math.cos((double)var8)) * 0.02F);
this.fuse = 80;
this.prevPosX = par2;
this.prevPosY = par4;
this.prevPosZ = par6;
}
Change the first "this.fuse" to match the actual "fuse" length in the second "this.fuse"… and it works as expected.
Add this to your clientside registerRenderInformation:
I'll get my code up here for you to see, the other guy's code might not be reflective of the problem we're having with our mod.
Haha! Nope.
My buddy is getting the code together here, he's rushing to put it up so we can get your eyes on it. We'd love to get your thoughts on it ASAP cuz it's been killin' us for awhile now. You around for a bit?
Code
Registry:
Block:
Entity:
Render:
PS. We're working with 1.4.4 now.
Did you registerModEntity? Is the entity ID being registered client AND server side?
Client Proxy:
That's all I have relevant to entities.
Have you tried increasing the range on registerModEntity from 16 to 160? Regular TNT is tracked up to 160 away.
Your client proxy doesn't override registerEntites(), right?
The Entity's render time is controlled by the first "this.fuse". The actual fuse length of the TNT is controlled by the second "this.fuse", as seen in the EntityTNTPrimed.
I have no idea why vanilla Lit TNT's render doesn't observe this behaviour, but in our custom TNT EntityCustomTNTPrimed.class, this is what fixed the render problem:
Change the first "this.fuse" to match the actual "fuse" length in the second "this.fuse"… and it works as expected.