Jump to content

Manipulating TNT Explosions, Explosion Events


strumshot

Recommended Posts

Due to the popularity of the question on how to stop or manipulate explosions without needing a core mod, I decided to tackle/post the following.

 

What I've illustrated here is how to silently replace tnt with custom tnt, with the players being none-the-wiser. This allows you to write a custom tnt that looks/feels just like tnt, but you can override methods and add custom fields/methods/etc, giving you complete manipulation of tnt on your server.

 

Just replace bedrock in the following example with your custom tnt and voila!

 

 

import java.util.List;

import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItemFrame;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.util.AxisAlignedBB;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;

import cpw.mods.fml.common.eventhandler.SubscribeEvent;

public class BuildEventHook {	

@SubscribeEvent
public void onClick(PlayerInteractEvent event) {		

	if (event.action == event.action.RIGHT_CLICK_BLOCK) {			

		if(event.entityPlayer.inventory.mainInventory[event.entityPlayer.inventory.currentItem].getItem() == Item.getItemFromBlock(Blocks.tnt)){
			int i = event.face;
			int x = event.x;
			int y = event.y;
			int z = event.z;
			boolean can = false;

			// bottom top north south west east
			if(i == 0){
				y--;
			}
			else if(i == 1){
				y++;
			}
			else if(i == 2){
				z--;
			}
			else if(i == 3){
				z++;
			}
			else if(i == 4){
				x--;
			}
			else if(i == 5){
				x++;
			}

			if(event.world.isAirBlock(x, y, z))
				can = true;

			List l = event.world.getEntitiesWithinAABB(
					Entity.class,
					AxisAlignedBB.getBoundingBox(
							(double) x,
							(double) y,
							(double) z,
							(double) x + 1.0d,
							(double) y + 1.0d,
							(double) z + 1.0d));
			if(l.size() > 0)
				can = false;

			if(can){
				event.world.setBlock(x, y, z, Blocks.bedrock);					
			}
			event.setCanceled(true);
		}
	}

}	

}

I'll need help, and I'll give help. Just ask, you know I will!

Link to comment
Share on other sites

Note: to use a clone of vanilla tnt, you will have to create and register a new entity for the tnt, which can be cloned from EntityTNTPrimed (notice it extends the vanilla):

 

 

public class NewTNTPrimed extends EntityTNTPrimed
{
    /** How long the fuse is */
    public int fuse;
    private EntityLivingBase tntPlacedBy;
    
    public NewTNTPrimed(World p_i1729_1_)
    {
        super(p_i1729_1_);
        this.preventEntitySpawning = true;
        this.setSize(0.98F, 0.98F);
        this.yOffset = this.height / 2.0F;
        this.fuse = 80;
        
    }

    public NewTNTPrimed(World p_i1730_1_, double p_i1730_2_, double p_i1730_4_, double p_i1730_6_, EntityLivingBase p_i1730_8_)
    {
        this(p_i1730_1_);
        this.setPosition(p_i1730_2_, p_i1730_4_, p_i1730_6_);
        float f = (float)(Math.random() * Math.PI * 2.0D);
        this.motionX = (double)(-((float)Math.sin((double)f)) * 0.02F);
        this.motionY = 0.20000000298023224D;
        this.motionZ = (double)(-((float)Math.cos((double)f)) * 0.02F);
        this.fuse = 80;
        this.prevPosX = p_i1730_2_;
        this.prevPosY = p_i1730_4_;
        this.prevPosZ = p_i1730_6_;
        this.tntPlacedBy = p_i1730_8_;
    }

    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)
            {
            	if(Events.onTNTExplode(this, (EntityPlayer)this.tntPlacedBy))
            		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 f = 4.0F;
        this.worldObj.createExplosion(this, this.posX, this.posY, this.posZ, f, true);
    }

    /**
     * (abstract) Protected helper method to write subclass entity data to NBT.
     */
    protected void writeEntityToNBT(NBTTagCompound p_70014_1_)
    {
        p_70014_1_.setByte("NFuse", (byte)this.fuse);
    }

    /**
     * (abstract) Protected helper method to read subclass entity data from NBT.
     */
    protected void readEntityFromNBT(NBTTagCompound p_70037_1_)
    {
        this.fuse = p_70037_1_.getByte("NFuse");
    }

    @SideOnly(Side.CLIENT)
    public float getShadowSize()
    {
        return 0.0F;
    }

    /**
     * returns null or the entityliving it was placed or ignited by
     */
    public EntityLivingBase getTntPlacedBy()
    {
        return this.tntPlacedBy;
    }
}

 

take note of this line:

if(Events.onTNTExplode(this, (EntityPlayer)this.tntPlacedBy)) this.explode();

 

...it will let you create an explosion event handler as such:

 

	/**
 * Fired just before a tnt explosion
 * @param tnt
 * @param player = null often! be careful!
 * @return false will cancel the explosion
 */
public static boolean onTNTExplode(NewTNTPrimed tnt, EntityPlayer player) {



	return true;
}

 

Also, your tnt may not render correctly after lighting it. Be sure to register the renderer in your proxy! I suggest using the same renderer as vanilla tnt.

 

RenderingRegistry.registerEntityRenderingHandler(NewTNTPrimed.class, new RenderTNTPrimed());

 

I'll need help, and I'll give help. Just ask, you know I will!

Link to comment
Share on other sites

Edit: Sorry, be sure to put

if(!event.world.isRemote){

in your PlayerInteractEvent check. The check should actually look as follows.

if(!event.world.isRemote){
			if(event.entityPlayer.inventory.mainInventory[event.entityPlayer.inventory.currentItem].getItem() == Item.getItemFromBlock(Blocks.tnt)){
				int i = event.face;
				int x = event.x;
				int y = event.y;
				int z = event.z;
				boolean can = false;

				// bottom top north south west east
				if(i == 0){
					y--;
				}
				else if(i == 1){
					y++;
				}
				else if(i == 2){
					z--;
				}
				else if(i == 3){
					z++;
				}
				else if(i == 4){
					x--;
				}
				else if(i == 5){
					x++;
				}

				if(event.world.isAirBlock(x, y, z))
					can = true;

				List l = event.world.getEntitiesWithinAABB(
						Entity.class,
						AxisAlignedBB.getBoundingBox(
								(double) x,
								(double) y,
								(double) z,
								(double) x + 1.0d,
								(double) y + 1.0d,
								(double) z + 1.0d));
				if(l.size() > 0)
					can = false;

				if(can){
					event.world.setBlock(x, y, z, IFaction.NewTNT);		
					event.world.notifyBlockOfNeighborChange(x, y, z, IFaction.NewTNT);
				}
				event.setCanceled(true);
			}

I'll need help, and I'll give help. Just ask, you know I will!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.