Damage knock-back help

Discussion in 'Plugin Development' started by kabbage, Jan 24, 2012.

Thread Status:
Not open for further replies.
  1. Offline

    kabbage

    EDIT: Solved

    For my plug in, I need to have it so when a player gets damaged, the damage is completely negated, but the person still gets knocked backwards from the hit.

    However, if I use
    Code:
    event.setCancelled(true); 
    the person doesn't get knocked back. Similararly, if I use
    Code:
    event.setDamage(0);
    the same happens.

    Any ideas as to how I could do this?
     
  2. Offline

    mb01

    First, you cancel the event or set the damage to 0. You can even do both, and that's probably better if mod compatibility is a concern. Finally you just call LivingEntity.damage(int amount, Entity source). As long as you provide a source a knockback will occur, even for 0 damage. But you'll have to simulate enchant damage, durability loss, invulnerability timer (after a hit) and arrow disappearance.

    Another way is to set the event damage to 1 and reset the health on every hit. Against a monster that's a bad idea, enchant damage are applied after the event so it can result in a one hit kill, but against a player I guess it could work.
     
    kabbage likes this.
  3. Offline

    kabbage

    Sadly, this didn't work. Maybe the problem is I'm using the wrong source, though. I'm using
    Code:
    Entity damager = event.getEntity()
     
  4. Offline

    mb01

    onEntityDamage?

    Code:java
    1.  
    2. Entity receiver = event.getEntity();
    3.  
    4. if (event instanceof EntityDamageByEntityEvent) {
    5. Entity dealer = ((EntityDamageByEntityEvent) event).getDamager();
    6.  
    7. //Not necessarily needed, it depend on your needs.
    8. if (dealer instanceof Projectile)
    9. dealer = ((Projectile) dealer).getShooter();
    10. }
    11.  

    I'm quoting myself here. This is only needed for swords, not bows.
     
    kabbage likes this.
  5. Offline

    romobomo

    So this is kinda crazy....

    Code:
    @EventHandler
    public void playerAttack(EntityDamageEvent e) {
    if(e instanceof EntityDamageByEntityEvent) {
    Entity damager = ((EntityDamageByEntityEvent) e).getDamager();
    plugin.log.info("Damage was done...");
    now although this little hack does work.... (I can get the damager, even though the EntityDamageByEntity event is broken to use normally) my log is now randomly filled with "Damage was done..." almost as if almost EVERY little thing that could be classified as an event causes it to fire off... ideas?

    EDIT: ok 10,000 edits later, I still can't figure out how to make the code block JAVA code.. so default code block it is.
     
  6. Offline

    mb01

    romobomo

    An EntityDamageEvent doesn't necessarily involve an entity damager (for example, drowning), that why there is no .getDamager() method and why you need a cast. Do you know about inheritance?

    Anyway it should work. If you think there's is a problem, try to replace your last line by something like that and you'll see what's going on:
    Code:java
    1. plugin.log.info("Damage to: " + entity.getClass().getSimpleName() + " By: " + damager.getClass().getSimpleName() + " For: " + event.getDamage());

    It's <syntax=java></syntax>, replace < > by [ ] :p
     
  7. Offline

    romobomo

    mb01
    I didn't say it doesn't work... works perfectly fine, I'm using it right now. The point is...

    if(e instanceof EntityDamageByEntityEvent) {
    THIS should ONLY happen in the instance of a (single) EntityDamageByENTITYevent


    https://bukkit.atlassian.net/browse/BUKKIT-147 <-- somewhat related.

    And yes, I'm well aware of how inheritance works


    Also: if EntityDamageByEntityEvent wasn't broken, a cast wouldn't be necessary at all.
     
  8. Offline

    mb01

    Yes, and that exactly what happens, otherwise you would have a class cast exception on the next line:
    2011-12-26 23:51:24 [SEVERE] Could not pass event ENTITY_DAMAGE to Likeaboss
    java.lang.ClassCastException: org.bukkit.event.entity.EntityDamageEvent cannot be cast to org.bukkit.event.entity.EntityDamageByEntityEvent

    About the issue you linked, which isn't related to your problem... An event is triggered every time you swing your sword, even if the entity will not take any damage. Only latter in the code the game decides if the entity should be damaged or not. But you can check it yourself:
    Code:java
    1.  
    2. if (entity instanceof LivingEntity) {
    3. LivingEntity livingEntity = (LivingEntity) entity;
    4.  
    5. if (livingEntity.getNoDamageTicks() > livingEntity.getMaximumNoDamageTicks() / 2.0 && event.getDamage() <= livingEntity.getLastDamage()) {
    6. //Will not be damaged!
    7. }
    8. }
    9.  

    Here I assume the event is an EntityDamageByEntityEvent, you have to halve the the maximum no damage ticks because that's just how Minecraft works. For others DamageCause the value may be different.

    Also, the entity can still be damaged if the damage are superior to the last damage it received (just be careful of swords (not bows), the event.getDamage() returns the base damage, i.e. unmodified by enchants).
    Why is that?
    Code:java
    1.  
    2. public class MyClass {
    3.  
    4. class A {}
    5.  
    6. class B extends A {
    7. public void Method() {}
    8. }
    9.  
    10. public MyClass() {
    11. A obj = new B();
    12.  
    13. obj.Method(); //Doesn't work, no such method in A, cast needed.
    14. ((B) obj).Method(); //Works, but you have to check first if obj is really an instance of B.
    15. }
    16. }
    17.  

    Please explain me how you can reach Method() without a cast.
     
  9. Offline

    romobomo

    mb01

    I think youre still mis-understanding me here. Your cast works fine... its not the issue.

    Code:java
    1.  
    2. @EventHandler
    3. public void playerAttack(EntityDamageEvent e) {
    4. if(e instanceof EntityDamageByEntityEvent) {
    5. Entity damager = ((EntityDamageByEntityEvent) e).getDamager();
    6. plugin.log.info("Damagewasdone...");
    7.  

    In the above example, whenever EntityDamageEvent is called, we check if it is an instance of EntityDamageByEntityEvent... then cast the getDamager method of that event into damager... all well and fine... the issue here is that I checked FIRST if it was an instance of EntityDamageByEntity, before the log attempt... meaning that my log should NOT be spammed, as there should not be hundreds of instances of this event every tick.

    As far as not needing to cast... the following should work, but is broken in the new event system... or was before, dont know... point is, it should work, but does not (as of 1.1R1):
    Code:java
    1.  
    2. @EventHandler
    3. public void myEvent(EntityDamageByEntityEvent e) {
    4. Entity p = e.getDamager();
    5.  
     
  10. Offline

    xasz

    You could just let the normal Damage-Event do his job with one damage and heal the player a health after he got damage.
     
  11. Offline

    mb01

    I already told you, you should use a better message. Check the damager, the target, its health and the damage done. With this you'll see exactly what's going on. I gave you an example on how you could do it.

    Anyway I'm sorry but there is a high probability that you're doing something wrong (or using a dev build?)... I just checked on my server, the event is fired once every time an entity is attacked (not necessarily damaged, as I explained earlier), not more.
    Well, it was never possible to do that: http://jd.bukkit.org/doxygen/de/d38/classorg_1_1bukkit_1_1event_1_1entity_1_1EntityListener.html
    I'm pretty sure it works as intended, but maybe it could change.
    That's the easiest way indeed. But as I said there is something strange with the event damage, sword enchants aren't applied. In other words, you set the damage to 1, but the final damage will be 1 + enchants damage (random number between 1 and SharpnessLevel*3, for example).

    It's ok against players as long as their health is never inferior or equal to 16 (so it's probably enough for romobomo). But against monsters it's a bad idea, with Smite V you can kill a Zombie in one hit, or a Spider with Bane of Arthropods IV. In that case the only way (for now) is to cancel the event.

    Don't forget that death events aren't cancelable
     
  12. Offline

    romobomo

    mb01

    Im entirely unsure of the above mentioned's behavior in RB3, the issue I encountered was as of 1.1RB1, which was current at the time of my initial post. Im at work atm, but I will do a thorough check with the curreny build when I get home.

    As far as the event handler never being able to process the aformentioned cast event, it most definately should do so (in following with its naming convention alone, if nothing else). I never had a use for it pre 1.1 so was unaware of its status (hence my statement). That being said, if its intended use is as such, then it should be documented and named as such (same goes for player death btw). This is a very minor issue though, if one at all... it would simply alleiviate confusion.

    I didnt come in here for a heated conversation on event handleing, nor do I have any desire to debug the entire process... I simply noticed a (minor) glitch and pointed it out... I can easily circumvent the issue, regardless.... I simply found it ammusing, and pointed it out. I will, however, confirm or deny its existence tonight, with a detailed debugging log.
     
Thread Status:
Not open for further replies.

Share This Page