Solved Checking if a player can be attacked

Discussion in 'Spigot Plugin Development' started by FiXed, May 28, 2016.

  1. So I was making a little bit of code and with the plugin I'm making I need to check if any other plugins cancel the attack event from one player to another to allow my plugin to do something and I was wondering if this was a safe and correct way of doing it, because a couple of people have told me not to do stuff like this before (hope I explained all that well):
    Code (Java):
    Player p1 = null; // Simulates the first player in this example
    Player p2 = null; // Simulates the second player in this example
    EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(p1, p2, DamageCause.ENTITY_ATTACK, 1.0);
    Bukkit.getPluginManager().callEvent(event);
    if(!event.isCancelled() || event.getDamage() != 0) {
        // They can be attacked regularly
    }
    Yes I know the players are null but in the actual code I wouldn't have them as null.
    I was also wondering, running this event like this, would p2 actually be damaged from this?
     
  2. Code (Text):

      @EventHandler

      public void onAttack(EntityDamageByEntityEvent event) {
         Player attacker = null;
         Player defender = null;
         if (event.getDamager() instanceof Player) { //checker if it is a player.
           attacker = (Player) event.getDamager();
         }
       }
     
    Also you need to register event
     
  3. Like @KingLinux01 showed, use a listener instead and add checks there. Don't call the event.

    EDIT: Don't do as he did though, not exactly the best way.
     
  4. He is calling the event (which is unnecessary) to check for if it is cancelled.
     
  5. That's not what I'm going for. I want to see if any other plugins cancel it then run my code, I don't want to listen for a real attack event. I think you misunderstand what I'm going after.
     
  6. Ohh ok. I see now. In that case yes that's a good way to do it.
     
  7. Ah okay, thank you, sorry for not giving out a good explanation.
     
  8. You code was confusing.
    I knew there was a entity attack event So I made some code.
     
  9. I know how to check during an event, I wanted to create a fake non-running event. :)
     
  10. Code (Java):
    Player p1 =null;// Simulates the first player in this example
    Player p2 =null;// Simulates the second player in this example
    EntityDamageByEntityEvent event =new EntityDamageByEntityEvent(p1, p2, DamageCause.ENTITY_ATTACK, 1.0);
    Bukkit.getPluginManager().callEvent(event);
    if(!event.isCancelled()|| event.getDamage()!=0){
        p2.setHealth(p2.getHealth() - event.getDamage());
    }
    I do not believe calling an EntityDamageByEntityEvent will automatically damage the entity.
    Sources:
    https://hub.spigotmc.org/stash/proj...va/org/bukkit/plugin/SimplePluginManager.java [See fireEvent(Event), does not check anything after firing]
    https://hub.spigotmc.org/stash/proj...t/event/entity/EntityDamageByEntityEvent.java [See extends EntityDamageEvent]
    https://hub.spigotmc.org/stash/proj...rg/bukkit/event/entity/EntityDamageEvent.java [Nowhere does it damage any Entities]
     
  11. Okay good, in this fake call I don't want the target damaged at all. Thank you for confirming.
     
  12. Why not just actually use a listener and have it on monitor priority? This priority is pretty much for what you're doing since it is called last.

    Code (Java):
    @EventHandler(priority = EventPriority.MONITOR)
    public void onDamage(EntityDamageByEntityEvent event)
    {
      // check if other plugin cancelled then ignore forever
    }
    I really don't see a need to actually call the event. Pretty sure this would actually cause some overhead if there are some plugins that have to do some calculations during this event.

    Not sure if this is what you want since it's a bit vague, but you can just check one time to know if any other plugins are cancelling the event and then ignore the event after checking.
     
  13. it's not what I'm looking for actually, I'm trying to allow a player to run a command to check if a player can be damaged by the player running the command.
    This should work effectively:
    Code (Java):
        @SuppressWarnings("deprecation")
        public final boolean canDamage(Player attacker, Player damaged) {
            EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(attacker, damaged, DamageCause.ENTITY_ATTACK, 1.0);
            Bukkit.getPluginManager().callEvent(event);
            return !event.isCancelled();
        }
     
    #14 FiXed, May 28, 2016
    Last edited: May 28, 2016
    • Informative Informative x 1
  14. That is a terrible solution.

    The algorithm you have setup to test here is "nondeterministic", meaning the results can vary on different executions. An example of a nondeterministic algorithm is a random number generator.

    Why is your algorithm nondeterministic?
    • Plugins may use a random number generator to cancel damage events.
    • Plugins may cancel damage events based upon a current circumstance (i.e player has invulnerability powerup)
    That's the first problem here. The second involves the "genuinity" of the event.

    EntityDamageByEntityEvent:
    The above quote documents that the above event is called when one entity is damaged by another entity.
    But when you call the event, that's not actually happening. So plugins which rely on the "genuinity" of the event (such as data loggers, combat loggers, etc) listen to your event call, they will treat it as a genuine event, when it is really not.
     
  15. That's what I want to check for, invuln abilities and random number gens to dodge. I'm looking for the final product because of what I'm trying to do. I understand it will treat it as a genuine event and that's exactly what I'm looking for. Combat log won't be tripped simply because if they can't be attacked than it won't care, you can't just sit in a hubs spawn and hit people triggering Combat logger, that plugin has it's own checks on it's "MONITOR" setting I believe.

    When I made this code I thought of everything thinking it was a genuine event and decided it's exactly hat I wanted. Data loggers don't usually look for number of attacks btw.
     
  16. You completely missed the "nondeterministic" part of my point.

    You DON'T know if a combat logger will trip, you DON'T know the results of the event going through as uncancelled, you CANNOT predict ambiguous random number generators, you CANNOT predict if an ambiguous combat logger will log players "in a hub", you HAVE NO CONTROL over the results of calling a dishonest event because the listeners WILL NOT KNOW whether the event is GENUINE OR NOT.


    Of course listeners would want a genuine event: that's where they would perform actions on events (such as cancelling and other undefined actions).

    My point is that you CANNOT predict what will happen with the event call, because you DO NOT KNOW what can happen.
     
  17. Except for the fact that it's a private plugin and I know what my other plugins are doing and I'm fine with the random number gens and random cancelling. I've thought about this long and hard.
     
  18. If you want to get rid of the deprecated constructor you can use this
    Code (Text):

    new EntityDamageByEntityEvent(attacker, damaged, EntityDamageEvent.DamageCause.ENTITY_ATTACK,
            new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, Double.valueOf(1.0D))),
            new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, Functions.constant(Double.valueOf(-0.0D)))));
     
    It is what the deprecated constructor does.. You will need to add these additional imports:
    Code (Text):

    import java.util.EnumMap;
    import org.bukkit.event.entity.EntityDamageEvent;
    import com.google.common.base.Functions;
    import com.google.common.collect.ImmutableMap;
     
    Just thought I would mention it.

    EDIT: Updated to match the code in the API, when I had used this before I copied the code from the decompiled Jar(was in a hurry).
    Code (Text):

    new EntityDamageByEntityEvent(attacker, damaged, EntityDamageEvent.DamageCause.ENTITY_ATTACK,
            new EnumMap<>(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, 1.0D)),
            new EnumMap<EntityDamageEvent.DamageModifier, Function<? super Double, Double>>(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, Functions.constant(-0.0D))));
     
    Additional import
    Code (Text):

    import com.google.common.base.Function;
     
     
    #19 NinjaStix, May 28, 2016
    Last edited: May 28, 2016
  19. I would but I'm not worried about the depricated mark, it's still the same in 1.9.4 from 1.8.8 so I'm not worried about it not working (made this plugin fro 1.8.8) but thank you very much for the code. It will probably help people who come here to look for help as well.
     
    • Friendly Friendly x 1