Jump to content

Recommended Posts

Posted

Hi. I'm working on an item that shoots projectiles. The projectiles explode when they hit a block/entity, when a timer expires, or when the player swings his held item. The issue I am having is that although all three call the same explosion method, the explosion doesn't render when the player swings the held item. It does, however, destroy blocks, damage entities and play sound as intended.

 

Youtube video to demonstrate:

 

Here are the item and throwable entity classes. It normally calls a custom explosion method but I've replaced it with vanillaExplode for debugging purposes. Sorry in advance that this isn't in a code block, the code button wasn't working and I don't know what the tag is.

public class SuperItem extends Item {
@SideOnly(Side.CLIENT) protected IIcon itemIcon;
private EntitySuperEgg lastEgg;
int i= 0;

public SuperItem() {
	this.setCreativeTab(SuperCool.tabSuperCool);
	setMaxStackSize(1);
}

@Override
public ItemStack onItemRightClick(ItemStack held, World world, EntityPlayer player) {
    if(player.capabilities.isCreativeMode||player.inventory.consumeInventoryItem(SuperCool.superEgg))
    {
        world.playSoundAtEntity(player, "random.bow", 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F));
        lastEgg = new EntitySuperEgg(world, player);
        if (!world.isRemote)
        {
            world.spawnEntityInWorld(lastEgg);
        }
    }
        return held;
}

@Override
public boolean onEntitySwing(EntityLivingBase living, ItemStack stack) {
	super.onEntitySwing(living, stack);
	if( living instanceof EntityPlayer && lastEgg!= null && !lastEgg.isDead){
			lastEgg.vanillaExplode();
	}
	return false;
}
}

public class EntitySuperEgg extends EntityThrowable {

private float explosionSize = 1.5F; 
private float explosionDamage = 25.0F;
private float explosionDamageSize = 8.0F;
private int ticks =0;

  public EntitySuperEgg(World world)
    {
        super(world);
    }
  
    public EntitySuperEgg(World world, EntityLivingBase thrower)
    {
        super(world, thrower);
    }
    
    public EntitySuperEgg(World world, double par2, double par4, double par6)
    {
        super(world, par2, par4, par6);
    }
    
    @Override
    protected void onImpact(MovingObjectPosition pos){
    	explode();
    }
    
    public void explode(){
    	double x = this.posX;
    	double y = this.posY;
    	double z = this.posZ;
        SuperEggExplosion explosion = new SuperEggExplosion(this.worldObj, this, x, y, z, explosionSize, explosionDamage, explosionDamageSize );
        explosion.isFlaming = false;
        explosion.isSmoking = true;
        if(!this.worldObj.isRemote){
        	explosion.doExplosionA();
        }
        explosion.doExplosionB(true);
        this.setDead();
    }
    
    public void vanillaExplode(){
    	double x = this.posX;
    	double y = this.posY;
    	double z = this.posZ;
        Explosion explosion = new Explosion(this.worldObj, this, x, y, z, explosionSize);
        explosion.isFlaming = false;
        explosion.isSmoking = true;
        if(!this.worldObj.isRemote){
        	explosion.doExplosionA();
        }
        explosion.doExplosionB(true);
        this.setDead();
    }
    
    @Override
    public void onUpdate(){
    	super.onUpdate();
    	if(++ticks > 100){
    		vanillaExplode();
    	}
    }
    
    @Override
    protected float getGravityVelocity()
    {
        return 0.02F;
    }
}

Posted

After more debugging I think I am finally getting close to the answer. When I take the if statement out of onEntity swing and replace it with a print statement to see which side is calling it like so.

 

        @Override
public boolean onEntitySwing(EntityLivingBase living, ItemStack stack) {
	super.onEntitySwing(living, stack);
		String side = living.worldObj != null && living.worldObj.isRemote ? "Client": "Server";
        System.out.println("exploding" + " on " + side);
		lastEgg.explode();
	return false;
}

 

And then insert a similar print statement my slightly altered explosion I get:

 

exploding on Client

explosionB at 829.4343427877122 76.91994773243071 -234.44541408084183 on Server

exploding on Server

explosionB at 829.4343427877122 76.91994773243071 -234.44541408084183 on Server

 

It seems to tell the server version of lastEgg to explode, regardless of if the client or server is saying it. The lastEgg reference is being updated to the server version I guess. How might I reference the client version of the entity so I can explode that for the clientside? I recognize, of course, at this point I could get the coordinates of lastEgg and have the client spawn the particles I want it to but I am curious if it is possible to get the client version of the entity.

Posted

Alright I fixed it. For those wondering since the client was getting the server version of lastEgg (the EntityItem that explodes), when I told it to explode like this

 

Explosion explosion = new Explosion(lastEgg.worldObj, lastEgg, x, y, z, lastEgg.explosionSize);

 

it would always use the server version of worldObj.

 

 

Instead I made a new explosion with the player's world object and it worked fine. I need to make a note that the player and entity could unexpectedly be in different worlds and account for that but for now it works.

 

Explosion explosion = new Expolosion(living.worldObj, lastEgg, x, y, z, lastEgg.explosionSize);

Posted

This is wearing on me. I just can't leave it alone! I hate that half-assed solution I posted (in any case it doesn't work in multiplayer, it spawns the explosion particles at the egg's initial position, right in the player's head).

 

Any ideas on how to reference the most recent projectile that is relevant for client/server? lastEgg, as it stands, always references an EntityThrowable with a serverside World object even if on the client version of things.

Posted

Hi

 

I think you need to trigger the explosion on the server only, and not on the client.  If you do it right (WorldServer.newExplosion() or .createExplosion(), I think), the server will then send a packet (S27PacketExplosion) to the client and everything will synch itself up properly.

 

You also need to remember that the server has only one SuperItem but lots of players.  Which means that if more than one player is using an egg, they will explode the wrong egg.  You need to store a last egg for each player.

 

-TGG

Posted

Thanks for the reply! It makes me feel great seeing someone trying to help and I really appreciate it.

 

You are right about the packet sending thing. It happens when when you use World.createExplosion(), though it doesn't happen if I copy the same code. Really strange but I do notice something I didn't notice before in teh source code 

 

/**

    * returns a new explosion. Does initiation (at time of writing Explosion is not finished)

    */

 

Maybe that's part of what is unfinished? I guess if I am going to do custom explosions I will have to add it myself. Now I know what I need to learn. This is progress!

 

Keeping each players egg's separate is certainly on my todo list but thanks for catching that!

 

Edit: to clarify, this works as intended.

public void explode(){
    	if(!this.worldObj.isRemote && !isDead){
    		worldObj.createExplosion(this, posX, posY, posZ, explosionSize, true);
    		this.setDead();
    	}
    }

 

but this does not send packets to client.

	    public void explode(){
    	if(!this.worldObj.isRemote && !isDead){
    		Explosion explosion = new Explosion(this.worldObj, this, posX, posY, posZ, explosionSize);
    		explosion.isFlaming = false;
    		explosion.isSmoking = true;
    		explosion.doExplosionA();
    		explosion.doExplosionB(true);
    		this.setDead();
    	}
    }

Posted

Hi

 

No problem :)

 

The reason it doesn't send a packet is easy to miss

 

World.createExplosion calls World.newExplosion

 

On the client, this executes the code you copied, but on the server, it is overridden by WorldServer.newExplosion

    public Explosion newExplosion(Entity p_72885_1_, double p_72885_2_, double p_72885_4_, double p_72885_6_, float p_72885_8_, boolean p_72885_9_, boolean p_72885_10_)
    {
        Explosion explosion = new Explosion(this, p_72885_1_, p_72885_2_, p_72885_4_, p_72885_6_, p_72885_8_);
        explosion.isFlaming = p_72885_9_;
        explosion.isSmoking = p_72885_10_;
        explosion.doExplosionA();
        explosion.doExplosionB(false);

        if (!p_72885_10_)
        {
            explosion.affectedBlockPositions.clear();
        }

        Iterator iterator = this.playerEntities.iterator();

        while (iterator.hasNext())
        {
            EntityPlayer entityplayer = (EntityPlayer)iterator.next();

            if (entityplayer.getDistanceSq(p_72885_2_, p_72885_4_, p_72885_6_) < 4096.0D)
            {
                ((EntityPlayerMP)entityplayer).playerNetServerHandler.sendPacket(new S27PacketExplosion(p_72885_2_, p_72885_4_, p_72885_6_, p_72885_8_, explosion.affectedBlockPositions, (Vec3)explosion.func_77277_b().get(entityplayer)));
            }
        }

        return explosion;
    }

 

-TGG

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.