Jump to content

[1.7.2] How to do ThrowableEntity that generates particles on hitting entities?


Feldherren

Recommended Posts

I have a smokebomb.  It's kind of like a snowball, but instead of splitting into snow particles when you throw it at solid stuff, it generates a cloud of smoke instead.

Well, currently a smokecube, because I haven't yet found a good tutorial for 1.7.2 ThrowableEntity renderers, and what I've found for 1.6 doesn't seem to work. Not my current issue, at any rate.

 

I want my smokecube to explode into smoke when it hits anything. I'm not having any issues with the smokecube and the ground, but when it gets tossed at an entity, it just deals 0 damage (not a problem) and vanishes without generating any particles (problem). I want a cloud of smoke even if an entity blocks the smokecube with their face.

 

I've tried putting a copy of the particle generation loop in the conditional section that checks if it hit an entity, but that doesn't change anything whether placed before or after the line saying it deals 0 damage to the entity. I've also, by trial and error, attempted to use blockX, blockY and blockZ from par1MovingObjectPosition.entityHit in place of the this.usual posX, this.posY and this.posZ in this.worldObj.spawnParticle(), but again that did nothing.

Does anyone know how to make a ThrowableEntity do particle stuff when/after hitting an entity, rather than just dealing damage (if applicable) and vanishing?

 

package com.feldherren.smokebomb;

import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.projectile.EntityThrowable;
import net.minecraft.util.DamageSource;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.world.World;

public class EntityGreySmokebomb extends EntityThrowable
{

int amount = 10;

    public EntityGreySmokebomb(World par1World)
    {
        super(par1World);
    }

    public EntityGreySmokebomb(World par1World, EntityLivingBase par2EntityLivingBase)
    {
        super(par1World, par2EntityLivingBase);
    }

    public EntityGreySmokebomb(World par1World, double par2, double par4, double par6)
    {
        super(par1World, par2, par4, par6);
    }

    /**
     * Called when this EntityThrowable hits a block or entity.
     */
    protected void onImpact(MovingObjectPosition par1MovingObjectPosition)
    {
        if (par1MovingObjectPosition.entityHit != null)
        {            
            par1MovingObjectPosition.entityHit.attackEntityFrom(DamageSource.causeThrownDamage(this, getThrower()), 0.0F);
            
        }
        
        for (int var3 = 0; var3 < amount; ++var3)
        {
            this.worldObj.spawnParticle("hugeexplosion", this.posX, this.posY, this.posZ, 0.0D, 0.0D, 0.0D);
        }
        
        if (!this.worldObj.isRemote)
        {
            this.setDead();
        } 
    }
}

Link to comment
Share on other sites

I think I see your problem

 

int amount = 10;

 

This snippit is in the base class without any modifiers. The default one will apply but in practice it is always better to put one - and it looks out of place like that. This may not fix the problem, but change the line to

private int amount = 10;

 

After this, I would recommend putting a println inside the for loop where you spawn the particles to make sure it is running. Seeing as it's the same as in EntitySnowball it *should* be working, but it obviously isn't.

 

Also just for bug-fixing, consider changing the particle line to directly copied from the EntitySnowball class. Once you get it working with that particle you can change it. Your problem may just be that you are asking for a particle that you can't see!

Link to comment
Share on other sites

That 'int amount' was actually just there to make sure the loop that outputs particles would do the same from in the 'has hit something' part as outside, when I had two copies of it, and from when I was testing to see what works best for a cloud of smoke - ten particles look good, a hundred particles look stupidly-synchronised.

That said, tried that. Unfortunately it didn't help, but changing it didn't break anything and I should probably remember to set things private in future.

 

The problem with copying the snowball code exactly is... snowballs show exactly the same behaviour. You're assuming they emit particles when you hit an entity like a sheep with them, but they don't. The behaviour of unmodified snowballs was one of the first things I checked, since EntityGreySmokebomb here is very obviously copied from EntitySnowball. I've checked this on a vanilla copy of Minecraft, too. (This is why I asked about ThrowableEntity and not 'my throwable thing', but I thought I'd mentioned it in the original post. Checking it, I guess I didn't.)

 

These smokebombs do work when they hit the environment. They generate a very obvious cloud of smoke. The particle certainly isn't invisible.

Link to comment
Share on other sites

I don't know. Would that cause particles to be generated and visible to at least the thrower when the smokebomb or snowball entity hits a block, but cause particles to (apparently) not to be generated when the projectile hits a sheep?

 

How can I tell?

Link to comment
Share on other sites

This has been solved, but I'm not sure if I can competently explain it.

 

As far as I'm aware, when an entity rather than the environment was hit, the spawnParticle() method ended up rendering them to the server, not the client, so I as a player saw nothing.

I (with the help of a better-coder friend) ended up using packets to get the client to render the particles.

 

So, should anyone need an example:

 

In preInit() in the main class:

		snw = NetworkRegistry.INSTANCE.newSimpleChannel(SmokebombMain.MODID);
		snw.registerMessage(PacketHugeExplosion.class, PacketHugeExplosion.class, 0, Side.CLIENT); 

 

EntityGreySmokebomb:

package com.feldherren.smokebomb;

import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.projectile.EntityThrowable;
import net.minecraft.util.DamageSource;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.world.World;
import cpw.mods.fml.common.network.NetworkRegistry.TargetPoint;

public class EntityGreySmokebomb extends EntityThrowable
{

private int amount = 10;

    public EntityGreySmokebomb(World par1World)
    {
        super(par1World);
    }

    public EntityGreySmokebomb(World par1World, EntityLivingBase par2EntityLivingBase)
    {
        super(par1World, par2EntityLivingBase);
    }

    public EntityGreySmokebomb(World par1World, double par2, double par4, double par6)
    {
        super(par1World, par2, par4, par6);
    }

    /**
     * Called when this EntityThrowable hits a block or entity.
     */
    protected void onImpact(MovingObjectPosition par1MovingObjectPosition)
    {
        if (par1MovingObjectPosition.entityHit != null)
        {
        	EntityPlayer player = (EntityPlayer)this.getThrower();
        	TargetPoint point = new TargetPoint(par1MovingObjectPosition.entityHit.dimension, 100, par1MovingObjectPosition.entityHit.posX, par1MovingObjectPosition.entityHit.posY, par1MovingObjectPosition.entityHit.posZ);
        	PacketHugeExplosion packetHugeExplosion = new PacketHugeExplosion(par1MovingObjectPosition.entityHit.posX,par1MovingObjectPosition.entityHit.posY, par1MovingObjectPosition.entityHit.posZ, amount);
        	SmokebombMain.snw.sendToAllAround(packetHugeExplosion, point);
        	
            par1MovingObjectPosition.entityHit.attackEntityFrom(DamageSource.causeThrownDamage(this, getThrower()), 0.0F);
        }
        
        for (int var3 = 0; var3 < amount; ++var3)
        {
            this.worldObj.spawnParticle("hugeexplosion", this.posX, this.posY, this.posZ, 0.0D, 0.0D, 0.0D);
        }
        
        if (!this.worldObj.isRemote)
        {
            this.setDead();
        } 
    }
}

 

PacketHugeExplosion:

package com.feldherren.smokebomb;

import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer;
import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;

public class PacketHugeExplosion implements IMessage, IMessageHandler<PacketHugeExplosion, IMessage>
{

double posX, posY, posZ;
int amount;

public PacketHugeExplosion()
{
}

public PacketHugeExplosion(EntityPlayer player, int amount)
{
	this(player.posX, player.posY, player.posZ, amount);
}

public PacketHugeExplosion(double posX, double posY, double posZ, int amount)
{
	this.posX = posX;
	this.posY = posY;
	this.posZ = posZ;
	this.amount = amount;
}

@Override
public void fromBytes(ByteBuf buf) 
{
	// TODO Auto-generated method stub
	this.posX = buf.readDouble();
	this.posY = buf.readDouble();
	this.posZ = buf.readDouble();
	this.amount = buf.readInt();
}

@Override
public void toBytes(ByteBuf buf) 
{
	// TODO Auto-generated method stub
	buf.writeDouble(posX);
	buf.writeDouble(posY);
	buf.writeDouble(posZ);
	buf.writeInt(amount);
}

@Override
public IMessage onMessage(PacketHugeExplosion message, MessageContext ctx)
{
        for (int var3 = 0; var3 < message.amount; ++var3)
        {
        	 FMLClientHandler.instance().getClient().theWorld.spawnParticle("hugeexplosion", message.posX, message.posY+1, message.posZ, 0.0D, 0.0D, 0.0D);
        }
	// TODO Auto-generated method stub
	return null;
}
}

 

I don't think I missed anything out here, so this should serve as an example of how to do it. Seems solved now that it does detonate on sheep, too.

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • They were already updated, and just to double check I even did a cleanup and fresh update from that same page. I'm quite sure drivers are not the problem here. 
    • i tried downloading the drivers but it says no AMD graphics hardware has been detected    
    • Update your AMD/ATI drivers - get the drivers from their website - do not update via system  
    • As the title says i keep on crashing on forge 1.20.1 even without any mods downloaded, i have the latest drivers (nvidia) and vanilla minecraft works perfectly fine for me logs: https://pastebin.com/5UR01yG9
    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
  • Topics

×
×
  • Create New...

Important Information

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