Solved Damage effect with no damage

Discussion in 'Plugin Development' started by BeMacized, Mar 23, 2013.

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

    BeMacized

    Hi there,

    Again, I ran into some trouble when playing around a bit with Bukkit.
    I'd like my plugin to cancel any damage done to the player in the EntityDamageEvent.
    Now, this is not so much trouble, and I was able to accomplish this quite easily with the following code:
    Code:
    @EventHandler
        public void onEntityDamage(EntityDamageEvent evt) {
            if (evt.getEntity() instanceof Player && !evt.getCause().equals(DamageCause.ENTITY_ATTACK)) {            
                    evt.setDamage(0);            
            }
        }
    This removed any damage done, but it also removed the damage effect which you get when you, for example, take fall damage. I just plainly land on the ground as I would do in creative mode.
    If I set the damage to 0 in the EntityDamageByEntityEvent, the damage is cancelled, but I still get the damage effect. Is there any way I can still simulate the player getting damage?

    ~BeMacized
     
  2. Offline

    nitrousspark

    event.setCancelled(true);
     
  3. Offline

    BeMacized

    nitrousspark
    That just cancels the whole event, and accomplishes the same effect. Still no damage effect.
     
  4. Offline

    nitrousspark

    BeMacized

    im being a derp. you could probably use this, event.setDamage((float) 0.1);
    or player.damage((float) 0.1);
     
  5. Offline

    BeMacized

    nitrousspark that would be kind of useless, as neither of the two functions accept floats, just integers :/
     
  6. Offline

    nitrousspark

    i use this for explosions, if i do world.createExplosion((float) 0.01) it creates an explosion that doesnt do any damage or break blocks.
     
  7. Offline

    BeMacized

    nitrousspark
    Uhh, that would indeed be a quick and dirty solution, however that would create an explosion effect & sound effect for every time someone takes damage, which is kinda messy. Is there really no way of just doing the damage effect?
     
  8. Offline

    nitrousspark

    no i meant that i can do that, which means you might be able to use player.damage((float) 0.1);
     
  9. Offline

    Scyntrus

    If all else fails, you can dive into the net.minecraft code and see what causes the "damage effect".
    Now the damage effect is pretty much just a knockback and a hurt sound, so you'll have to cancel the event and cause the knockback and hurt sound yourself.
     
  10. Offline

    BeMacized

    nitrousspark that's because createExplosion does take floats, damage does not, only integers.

    Scyntrus That would indeed be an option, but I'm afraid I would not even know how I would be able to find such a thing in the minecraft sauce, or even start on finding it.
     
  11. Offline

    nitrousspark

    well you can do player.damage(1); which will only do half a heart and with armor it wont do anything
     
  12. Offline

    Ranzdo

    The minecraft protocol premits you to send an package from the server to the client to trigger an damage animation.
    Packet 0x12 (http://mc.kev009.com/Protocol#Animation_.280x12.29) can do it, just construct one using an entity and the animation id (2). I am sure there are some packet libraries in the resource section that you can use to easily send this packet.

    Good luck and /)
     
  13. Offline

    Comphenix

    Looks like packet 0x12 only triggers the rolling screen effect, it doesn't "toggle" the health bar nor play the hurt sound.

    Instead, use entity status (here using ProtocolLib):
    Code:java
    1. public class ExampleMod extends JavaPlugin implements Listener {
    2. @Override
    3. public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
    4. if (sender instanceof Player) {
    5. Player player = (Player) sender;
    6. PacketContainer entityStatus = new PacketContainer(Packets.Server.ENTITY_STATUS);
    7.  
    8. entityStatus.getIntegers().write(0, player.getEntityId());
    9. entityStatus.getBytes().write(0, (byte) 2);
    10.  
    11. try {
    12. ProtocolLibrary.getProtocolManager().sendServerPacket(player, entityStatus);
    13. e.printStackTrace();
    14. }
    15. return true;
    16. }
    17. return false;
    18. }
    19. }

    You can also do this directly in CraftBukkit - but now you must recompile your plugin for every new Minecraft version:
    Code:java
    1. import net.minecraft.server.v1_5_R2.Packet38EntityStatus;
    2. import org.bukkit.craftbukkit.v1_5_R2.entity.CraftPlayer;
    3.  
    4. public class ExampleMod extends JavaPlugin implements Listener {
    5. @Override
    6. public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
    7. if (sender instanceof Player) {
    8. Player player = (Player) sender;
    9. Packet38EntityStatus status = new Packet38EntityStatus(player.getEntityId(), (byte) 2);
    10.  
    11. ((CraftPlayer) player).getHandle().playerConnection.sendPacket(status);
    12. return true;
    13. }
    14. return false;
    15. }
    16. }

    But you don't need packets in the first place - why don't you simply heal the player before or after the smallest amount of damage you can reliably set?
    Code:java
    1. public class ExampleMod extends JavaPlugin implements Listener {
    2. @Override
    3. public void onEnable() {
    4. getServer().getPluginManager().registerEvents(this, this);
    5. }
    6.  
    7. @EventHandler
    8. public void onDamageEvent(EntityDamageEvent e) {
    9. final LivingEntity living = (LivingEntity) e.getEntity();
    10. final Runnable incrementHealth = new Runnable() {
    11. @Override
    12. public void run() {
    13. living.setHealth(
    14. Math.min(living.getHealth() + 1, living.getMaxHealth())
    15. );
    16. }
    17. };
    18.  
    19. if (e.getCause() == DamageCause.FALL) {
    20. e.setDamage(1);
    21.  
    22. if (living.getHealth() < living.getMaxHealth()) {
    23. // Heal before damage - thus we avoid accidentally killing the entity if the health is one
    24. incrementHealth.run();
    25. } else {
    26. // Heal after damage
    27. getServer().getScheduler().scheduleSyncDelayedTask(this, incrementHealth);
    28. }
    29. }
    30. }
    31. }

    That should work as well as the packet solutions, and you avoid depending on either CraftBukkit or ProtocolLib.
     
    TigerHix likes this.
  14. Offline

    BeMacized

    Thank you for the info, even though Comphenix' code fixed my problem, that really got me started on understanding these packet related functions :) Thanks for that (\



    Thanks a bunch! This worked perfectly ^^. I chose for the second option, as I'm not planning on releasing the plugin anyways, so I'll only have to recompile the plugin for myself.

    Thank you all for helping me out, I really appreciate the help I receive here on the forums! ^^
     
Thread Status:
Not open for further replies.

Share This Page