[SPIGOT-6227] EntityDeathEvent and EntityDamageEvent not called when entity falls in the void Created: 07/Nov/20  Updated: 12/Nov/20  Resolved: 09/Nov/20

Status: Resolved
Project: Spigot
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Minor
Reporter: Frank van der Heijden Assignee: Unassigned
Resolution: Cannot Reproduce Votes: 0
Labels: None
Environment:

Empty spigot server.


Version: 37d799b-3eb7236 1.16.4
Guidelines Read: Yes

 Description   

EntityDeathEvent and EntityDamageEvent are not called when entity falls in the void, however, if you jump together with the entity into the void – the two events are called. It seems like spigot is just magically removing the entity below a certain y-level without calling any event when no player is nearby.

With the same setup on a PaperMC server, their event `com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent` does fire when the entity is removed.



 Comments   
Comment by Airtheon Thesalion [ 12/Nov/20 ]

So I looked into this and actually it has to do with how Minecraft handles hostile mob existence ranges.
When non-special hostile entities, like creepers, have no players nearby, Minecraft just straight up unregisters them.
The limit is about a cube of 128 blocks in each of the 6 directions with the creeper in the center.
For special entities, like named mobs and some passive mobs like the cow that md_5 used, this limit does not apply.

How to test this?
Using your plugin do the following:

Experiment 1:

  1. Make an enclosed space so the mob can't walk around.
  2. Spawn a normal creeper in this space.
  3. Give it the regen 5 and poison 1 effects for a very long time. (900 seconds is more than plenty)
  4. Now see the messages flowing in and start to move in one direction away from the creeper.
  5. At around 128 blocks distance, the messages will stop.
  6. Return and notice that the creeper has disappeared.

Now I could NOT have died, but maybe spigot just unregisters entities that take damage? Well let's try another experiment for that.

Experiment 2:

  1. Repeat steps 1 and 2 of experiment 1.
  2. Do NOT give it regen or poison whatsoever.
  3. Move at least 128 blocks away and return, the creeper will be gone.

Okay so now we know that it has nothing to do with damage, just with distance. The next step is to see if the limit applies to special mobs, even if they are hostile.

Experiment 3:

  1. Make an enclosed space so the mob can't walk around.
  2. Spawn a normal creeper in this space.
  3. Give the creeper a NAME, by using a named nametag on it.
  4. Give it the regen 5 and poison 1 effects for a very long time. (900 seconds is more than plenty)
  5. Now see the messages flowing in and start to move in one direction away from the creeper.
  6. At around 128 blocks distance, the messages will happily continue
  7. Return and notice that the creeper is still there and your chat is still being flooded with messages.

 

So all in all, there is nothing wrong with the EntityDeathEvent and EntityDamageEvent. This is just a side effect of Minecraft's optimization, where hostile mobs are unregistered when there are now players around them. And yes you are reading that right, this has nothing to do with Spigot whatsoever, try it in a singleplayer Minecraft world and the creeper will have despawned as well.

Comment by Frank van der Heijden [ 09/Nov/20 ]

To illustrate the behaviour I meant I made a recording: https://frankheijden.stackstorage.com/s/A6RwvMLfQzUhouay

The plugin visible in-game is practically the same as the plugin @md_5 described above:

public class Spigot6227 extends JavaPlugin implements Listener {

    @Override
    public void onEnable() {
        super.onEnable();
        getServer().getPluginManager().registerEvents(this, this);
    }

    @EventHandler
    public void onEntityDamage(EntityDamageEvent event) {
        getServer().broadcastMessage(event.getEntityType().name() + ": " + event.getCause().name());
    }

    @EventHandler
    public void onEntityDeath(EntityDeathEvent event) {
        getServer().broadcastMessage(event.getEntityType().name() + ": Death");
    }
}

I think this has to do with the entity tracking range of spigot, but I still find it weird that it doesn't call the EntityDeathEvent, even though the entity technically died (but not with a player nearby).

Comment by md_5 [ 09/Nov/20 ]

    @EventHandler
    public void event(EntityDeathEvent event)
    {
        getServer().broadcastMessage( ReflectionToStringBuilder.toString( event ) );
    }

    @EventHandler
    public void event(EntityDamageEvent event)
    {
        getServer().broadcastMessage( ReflectionToStringBuilder.toString( event ) );
    }


[18:24:07] [Server thread/INFO]: org.bukkit.event.entity.EntityDamageByBlockEvent@1ecf1ed2[damager=<null>,modifiers={BASE=4.0, ARMOR=-0.0, RESISTANCE=-0.0, MAGIC=-0.0, ABSORPTION=-0.0},modifierFunctions={BASE=Functions.constant(-0.0), ARMOR=net.minecraft.server.EntityLiving$3@4cf4c8ec, RESISTANCE=net.minecraft.server.EntityLiving$4@12c6d11e, MAGIC=net.minecraft.server.EntityLiving$5@2e163a8c, ABSORPTION=net.minecraft.server.EntityLiving$6@48c99812},originals={BASE=4.0, ARMOR=-0.0, RESISTANCE=-0.0, MAGIC=-0.0, ABSORPTION=-0.0},cancelled=false,cause=VOID,entity=CraftCow,name=<null>,async=false]
[18:24:08] [Server thread/INFO]: org.bukkit.event.entity.EntityDamageByBlockEvent@22108a4f[damager=<null>,modifiers={BASE=4.0, ARMOR=-0.0, RESISTANCE=-0.0, MAGIC=-0.0, ABSORPTION=-0.0},modifierFunctions={BASE=Functions.constant(-0.0), ARMOR=net.minecraft.server.EntityLiving$3@67ae132, RESISTANCE=net.minecraft.server.EntityLiving$4@19a7792b, MAGIC=net.minecraft.server.EntityLiving$5@1daa7b05, ABSORPTION=net.minecraft.server.EntityLiving$6@3b4ec80d},originals={BASE=4.0, ARMOR=-0.0, RESISTANCE=-0.0, MAGIC=-0.0, ABSORPTION=-0.0},cancelled=false,cause=VOID,entity=CraftCow,name=<null>,async=false]
[18:24:08] [Server thread/INFO]: org.bukkit.event.entity.EntityDamageByBlockEvent@48a09f70[damager=<null>,modifiers={BASE=4.0, ARMOR=-0.0, RESISTANCE=-0.0, MAGIC=-0.0, ABSORPTION=-0.0},modifierFunctions={BASE=Functions.constant(-0.0), ARMOR=net.minecraft.server.EntityLiving$3@69cb732, RESISTANCE=net.minecraft.server.EntityLiving$4@4b5f194c, MAGIC=net.minecraft.server.EntityLiving$5@4756e0e5, ABSORPTION=net.minecraft.server.EntityLiving$6@b41bc60},originals={BASE=4.0, ARMOR=-0.0, RESISTANCE=-0.0, MAGIC=-0.0, ABSORPTION=-0.0},cancelled=false,cause=VOID,entity=CraftCow,name=<null>,async=false]
[18:24:08] [Server thread/INFO]: org.bukkit.event.entity.EntityDeathEvent@6887af1d[drops=[ItemStack{LEATHER x 2}, ItemStack{BEEF x 3}],dropExp=0,entity=CraftCow,name=<null>,async=false]

As you can see both events are called correctly.

Comment by Frank van der Heijden [ 08/Nov/20 ]

Yup! This means that the entity magically disappears (as the PaperMC EntityRemoveFromWorldEvent does catch it as being unregistered), but without calling an EntityDeathEvent nor the damage chain before dying.

The EntityDamageEvent and EntityDeathEvent aren't called for both the Spigot and Paper server setups.

Comment by Airtheon Thesalion [ 08/Nov/20 ]

Actually PaperMC's `com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent` is fundamentally different.

It is called from WorldServer whenever an entity is unregistered, instead of when an entity dies or takes damages.

The reason this is so different is that after an entity death, it can be revived, but an unregistered entity cannot be reregistered.

Also EntityDeathEvent and EntityDamageEvent are Paper events as well. Are they fired on the PaperMC setup?

Generated at Wed Dec 17 17:29:05 UTC 2025 using Jira 10.3.15#10030015-sha1:909cc43d292ca09e774c1a243d9819be3f2628cd.