1.16.5 EntityDamageByEntity fire three times using registerEvent

Discussion in 'Spigot Plugin Development' started by etwxr9, Jul 13, 2021.

  1. Code (Text):
        @Override
        public void onEnable() {
            Bukkit.getLogger().info("rb start");
            getServer().getPluginManager().registerEvent(EntityDamageByEntityEvent.class, new Listener() {
            }, EventPriority.NORMAL, new myExecutor(), this, false);
            getServer().getPluginManager().registerEvent(EntityDamageByBlockEvent.class, new Listener() {
            }, EventPriority.NORMAL, new myExecutor(), this, false);
            getServer().getPluginManager().registerEvent(EntityDamageEvent.class, new Listener() {
            }, EventPriority.NORMAL, new myExecutor(), this, false);
        }

        public class myExecutor implements EventExecutor {
            @Override
            public void execute(Listener arg0, Event arg1) throws EventException {
                if (arg1.getEventName().equals("EntityDamageByEntityEvent")) {
                    Bukkit.getLogger().info("Event Fire1");
                }
                if (arg1.getEventName().equals("EntityDamageEvent")) {
                    Bukkit.getLogger().info("Event Fire2");
                }

            }
        }
    I encountered this problem when developing a plugin.

    The above is a simple test I wrote. Basically, the whole plugin only has these codes.

    After testing, I think it should be because when spigot triggers the event, it triggers three events: EntityDamageEvent, EntityDamageByEntityEvent and EntityDamageByBlockEvent.

    The situation of the test is as follows:
    When a player is attacked, "event fire1" outputs three times.
    When the player falls, "event fire2" outputs three times.

    When I unsubscribe from two of these events, the console outputs only once.

    I think it's a bug.
     
  2. Can you specify what is attacking the player? Is it another player? Or a random entity?
     
  3. A zombie or a skeleton.
    When a zombie(or skeleton) is attacked, "event fire1" outputs three times, too.
     
  4. I do not know if that is how it is intended, but that is quite odd
     
  5. I noticed that entitydamagebyblockevent and entitydamagebyentityevent are subclasses of entitydamageevent. This may lead to such a bug.
    I will test this bug on other events with subclasses.
     
  6. Its not a bug, its expected behavior since you already said, both events are subclasses of EntityDamageEvent
     
  7. It is a bug.
    You see, whether the player is attacked or dropped, the event triggers three times.
    Why is EntityDamageByBlockEvent triggered as EntityDamageByEntityEvent when a player is attacked?
    Similarly, I did a test, I only subscribe to EntityDamageByEntityEvent, and when the player falls, EntityDamageEvent triggers
     
  8. I did another test. When I subscribe to PlayerDeathEvent, I kill a skeleton, and EntityDeathEvent triggers.
     
  9. Because PlayerDeathEvent is a subclass of EntityDeathEvent. It‘s not a bug
     
  10. Have you ever read my code at top?
    here is the new test.

    Code (Text):
        @Override
        public void onEnable() {
            getServer().getPluginManager().registerEvent(PlayerDeathEvent.class, new Listener() {
            }, EventPriority.NORMAL, new myExecutor(), this, false);
        }

        public class myExecutor implements EventExecutor {
            @Override
            public void execute(Listener arg0, Event arg1) throws EventException {
                if (arg1.getEventName().equals("PlayerDeathEvent")) {
                    var e = (PlayerDeathEvent) arg1;
                    Bukkit.getLogger().info("PlayerDeathEvent Fire " + e.getEntity().getType().toString());
                }
                if (arg1.getEventName().equals("EntityDeathEvent")) {
                    var e = (EntityDeathEvent) arg1;
                    Bukkit.getLogger().info("EntityDeathEvent " + e.getEntity().getType().toString());
                }
            }
        }
    I didn't subscribe to EntityDeathEvent at all.
    I only subscribed to PlayerDeathEvent, with a custom EventExecutor
    But when a chicken dies, myExecutor executes, and it output "EntityDeathEvent CHICKEN".
    Is that normal?
     
  11. This is normal, a chicken is an entity, and it died, hence the entity death event is fired. I think this whole thread is a bit confusing - I don't think you understand how the event system works. Further, I am confused why you are registering events like this rather than creating an actual listener class and then registering and instaciating it using the bukkit.getpluginmanager().registerevents(listener, plugin); method.
     
    • Like Like x 1
  12. Code (Text):
        @Override
        public void onEnable() {
            getServer().getPluginManager().registerEvent(PlayerDeathEvent.class, new Listener() {
            }, EventPriority.NORMAL, new myExecutor(), this, false);
        }

        public class myExecutor implements EventExecutor {
            @Override
            public void execute(Listener arg0, Event arg1) throws EventException {
                if (arg1.getEventName().equals("EntityDeathEvent")) {
                    var e = (EntityDeathEvent) arg1;
                    Bukkit.getLogger().info("EntityDeathEvent Fire " + e.getEntity().getType().toString());
                }
            }
        }
    This output "EntityDeathEvent CHICKEN"

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

        @EventHandler
        public void onPlayerDeath(PlayerDeathEvent e) {
            if (e.getEventName().equals("EntityDeathEvent")) {
                Bukkit.getLogger().info("EntityDeathEvent Fire " + e.getEntity().getType().toString());
            }
        }
    This output nothing

    If this is normal, then I think I really don't know much about this event system.And I really need a way to not let PlayerDeathEvent executed as EntityDeathEvent.(Using registerEvent method)

    The reason for using this function is that I need to make the plugin automatically subscribe to all spigot events, and then let the external script (Lua) subscribe to these events. I've done it, but only these events have encountered this problem.
     
  13. You are taking the PlayerDeathEvent as a parameter and then checking if the event name = EntityDeathEvent, this will always be false. I think now that you are registering the events in the recommended way it will work as you thought it would.
     
  14. I know it will be false.
    And I know it's a recommended way.
    But I can't write like that. I've said the reason.
    I just think it's intuitively hard to understand, because in this way there's no difference between
    Code (Text):
    getServer().getPluginManager().registerEvent(PlayerDeathEvent.class, new Listener() {
            }, EventPriority.NORMAL, new myExecutor(), this, false);
    and
    Code (Text):
    getServer().getPluginManager().registerEvent(EntityDeathEvent.class, new Listener() {
            }, EventPriority.NORMAL, new myExecutor(), this, false);
    By the way I have solved my problem by add extra listener.
    I'm just expressing my confusion...
     
    #14 etwxr9, Jul 13, 2021
    Last edited: Jul 13, 2021
  15. Of course there‘s a difference - the PlayerDeathEvent only fires when players die, the EntityDeathEvent fires for all entities
     
  16. wrong
    didn't you see my test above?
    I first subscribe to EntityDeathEvent only, and it execute when chicken die
    I then subscribe to PlayerDeathEvent only and it execute when chicken die
     
  17. I didn't test your code, but this definitely works:

    Code (Java):
            getServer().getPluginManager().registerEvent(PlayerDeathEvent.class, new Listener() {}, EventPriority.NORMAL, (listener, event) -> {
                if(!(event instanceof PlayerDeathEvent)) return;
                PlayerDeathEvent deathEvent = (PlayerDeathEvent) event;
                System.out.println("Player Death Event: " + deathEvent.getEntity().getName() + " died.");
            }, this, false);
    By the way, why are you identifying the event by its name?
     

  18. Code (Text):
    if(!(event instanceof PlayerDeathEvent)) return;
    You determined the type of the parameter event.
    If you dont do that, It won't make difference whether subscribe to PlayerDeathEvent or EntityDeathEvent.