Snowball damage

Discussion in 'Plugin Development' started by theguynextdoor, Nov 7, 2011.

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

    theguynextdoor

    Right I've been trying to make a plugin which will make snowballs do damage. But i currently cant seem to make it do the damage. I get this error in my console.
    Code:
    17:48:42 [SEVERE] Could not pass event PROJECTILE_HIT to GreenChat
    java.lang.ClassCastException: org.bukkit.craftbukkit.entity.CraftSnowball cannot
     be cast to org.bukkit.entity.Player
            at me.theguynextdoor.greenchat.GreenChat$1.onProjectileHit(GreenChat.jav
    a:41)
            at org.bukkit.plugin.java.JavaPluginLoader$77.execute(JavaPluginLoader.j
    ava:798)
            at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.jav
    a:58)
            at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.j
    ava:339)
            at net.minecraft.server.EntitySnowball.s_(EntitySnowball.java:153)
            at net.minecraft.server.World.entityJoinedWorld(World.java:1193)
            at net.minecraft.server.WorldServer.entityJoinedWorld(WorldServer.java:1
    04)
            at net.minecraft.server.World.playerJoinedWorld(World.java:1175)
            at net.minecraft.server.World.tickEntities(World.java:1090)
            at net.minecraft.server.MinecraftServer.h(MinecraftServer.java:467)
            at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:374)
            at net.minecraft.server.ThreadServerApplication.run(SourceFile:417)
    Here is my code.
    Code:
            pm.registerEvent(Event.Type.PROJECTILE_HIT, new EntityListener() {
    
                public void onProjectileHit(ProjectileHitEvent e) {
    
                    Projectile projectile = (Projectile) e.getEntity();
                    Player target = (Player)e.getEntity();
    
                    if (projectile instanceof Snowball) {
                        target.damage(1);
                    }
                }
            }, Priority.Highest, this);
    It says the error is on line 41, which is:
    Code:
                    Player target = (Player)e.getEntity();
    I have also tried
    Code:
                    Entity target = (LivingEntity)e.getEntity();
    Any help (Either code or pointers) would be appreciated.
     
  2. Offline

    Wundark

    If you are trying to hit a Mob then you cant cast e.getEntity() to Player

    PHP:
    Entity ent = (Entity)event.getEntity();
    if(
    ent instanceof Player){
    //Insert code here.
    //This will make the code only execute if it hits a Player.
    }
     
  3. So the entity is the projectile (the snowball).
    How can it be a snowball AND a player?
     
    ItsHarry likes this.
  4. Offline

    ItsHarry

    Entity entity = e.getEntity();
    if (entity instanceof Player) {
    bladibla
    }
     
  5. @Wundark and @ItsHarry: It will never be a player as it's the snowball! See my post above.
     
  6. Offline

    theguynextdoor

    Then how do you propose i get the projectile and the player?. You definatly have a valid point. I want to check if the projectile is a snowball and if the target is a player, and if it is a player then i want it to deal a certain amount of damage.
     
  7. You could try the EntityDamageByProjectileEvent, but I doubt it will be called as a snowball doesn't make damage.
    Another, more hackish solution could be:
    Code:
    Projectile projectile = (Projectile) e.getEntity();
    Entity possibleTarget = projectile.getNearbyEntities(1).get(0);
    if(possibleTarget == null || !(possibleTarget instanceof Player)
      return; // no player hitted.
    //Maybe add some stuff to get sure the target really is the target...
    Player target = (Player)possibleTarget;
    Just out of my head and completely untested...
     
  8. Offline

    nicholasntp

    Im fairly new at java, and may not be getting this right, but what if you missed the player? It would still hurt them because they are nearby.
     
  9. How would it hurt them? How do you want to execute damage(int damage) on the player if you don't have the player?
     
  10. Offline

    nicholasntp

    See, I wasn't thinking. :p

    EDIT: wait.... It gets nearby entities though.
     
  11. Yes, and puts the first one from the list. :(
    You'll probably need some future checking to find the real target.
     
  12. Offline

    nicholasntp

    So, I was right! :D
     
  13. Offline

    theguynextdoor

    It works, thank you @V10lator

    For reference the final code i am using is,
    Code:
     		pm.registerEvent(Event.Type.PROJECTILE_HIT, new EntityListener() {
    
    			public void onProjectileHit(ProjectileHitEvent e) {
    
    				Projectile projectile = (Projectile) e.getEntity();
    				Entity possibleTarget = projectile.getNearbyEntities(1, 1, 1)
    						.get(0);
    
    				if (possibleTarget instanceof Player) {
    					Player target = (Player) possibleTarget;
    					target.damage(1);
    				}
    
    				else if (possibleTarget == null
    						|| !(possibleTarget instanceof Player)) {
    					return; // no player hitted.
    				}
    			}
    		}, Priority.Highest, this);
     
  14. Offline

    nicholasntp

    I am so using this plugin.
     
  15. Offline

    theguynextdoor

    I didn't intent to release this as a plugin, but if people do want it i will.
     
  16. Offline

    nisovin

    FYI, snowballs do fire a EntityDamageByEntityEvent, with a damage of 0. So you can use that event to get the damaged player easier.
     
    V10lator likes this.
  17. A bit of optimization:
    Code:
     		pm.registerEvent(Event.Type.PROJECTILE_HIT, new EntityListener() {
    
    			public void onProjectileHit(ProjectileHitEvent e) {
    
    				Projectile projectile = (Projectile) e.getEntity();
    				Entity possibleTarget = projectile.getNearbyEntities(1, 1, 1)
    						.get(0);
    
    				if (possibleTarget instanceof Player) {
    					Player target = (Player) possibleTarget;
    					target.damage(1);
    				}
    			}
    		}, Priority.Highest, this);
    :)
     
  18. Offline

    theguynextdoor

    Ok, so im making the actual plugin on this which i will hopefully submit. And i am trying to make it so in the config, you can turn on and off player damage and mob damage. Here is my code so far,
    Code:
    package me.theguynextdoor.snowballnextdoor;
    
    import java.util.logging.Logger;
    
    import org.bukkit.configuration.file.FileConfiguration;
    import org.bukkit.entity.Entity;
    import org.bukkit.entity.LivingEntity;
    import org.bukkit.entity.Player;
    import org.bukkit.entity.Projectile;
    import org.bukkit.event.Event;
    import org.bukkit.event.Event.Priority;
    import org.bukkit.event.entity.EntityListener;
    import org.bukkit.event.entity.ProjectileHitEvent;
    import org.bukkit.plugin.PluginDescriptionFile;
    import org.bukkit.plugin.PluginManager;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public class SnowBallNextDoor extends JavaPlugin {
    
        public final Logger logger = Logger.getLogger("Minecraft");
    
        @Override
        public void onDisable() {
            this.logger.info("Chat Disabled");
        }
    
        @Override
        public void onEnable() {
    
            final FileConfiguration config = this.getConfig();
    
            config.addDefault("Snowball.MobDamage", true);
            config.addDefault("Snowball.PlayerDamage", true);
            config.addDefault("Snowball.MobDamageInt", 2);
            config.addDefault("Snowball.PlayerDamageInt", 10);
    
            PluginManager pm = getServer().getPluginManager();
            pm.registerEvent(Event.Type.PROJECTILE_HIT, new EntityListener() {
    
                public void onProjectileHit(ProjectileHitEvent e) {
    
                    Projectile projectile = (Projectile) e.getEntity();
                    Entity possibleTarget = projectile.getNearbyEntities(1, 1, 1)
                            .get(0);
    
                    if (possibleTarget instanceof Player && config.getBoolean("Snowball.PlayerDamage")) {
                        Player target = (Player) possibleTarget;
                        target.damage(config.getInt("Snowball.PlayerDamageInt"));
    
                    } else if (!(possibleTarget instanceof Player) && config.getBoolean("Snowball.MobDamage")) {
                        Entity target = (Entity) possibleTarget;
                        ((LivingEntity) target).damage(config.getInt("Snowball.MobDamageInt"));
                    }
                }
            }, Priority.Highest, this);
    
            config.options().copyDefaults(true);
            saveConfig();
    
            PluginDescriptionFile pdfFile = this.getDescription();
            this.logger.info(pdfFile.getName() + "" + " version "
                    + pdfFile.getVersion() + " is enabled");
    
        }
    }
    And it works all handy dandy and everything, but when i turn player damage off in the config, It doesnt deal the player damage, but it spams the console with the error
    Code:
    21:56:07 [SEVERE] Could not pass event PROJECTILE_HIT to SnowBallNextDoor
    java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
            at java.util.ArrayList.RangeCheck(Unknown Source)
            at java.util.ArrayList.get(Unknown Source)
            at me.theguynextdoor.snowballnextdoor.SnowBallNextDoor$1.onProjectileHit
    (SnowBallNextDoor.java:44)
            at org.bukkit.plugin.java.JavaPluginLoader$77.execute(JavaPluginLoader.j
    ava:798)
            at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.jav
    a:58)
            at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.j
    ava:339)
            at net.minecraft.server.EntitySnowball.s_(EntitySnowball.java:153)
            at net.minecraft.server.World.entityJoinedWorld(World.java:1193)
            at net.minecraft.server.WorldServer.entityJoinedWorld(WorldServer.java:1
    04)
            at net.minecraft.server.World.playerJoinedWorld(World.java:1175)
            at net.minecraft.server.World.tickEntities(World.java:1090)
            at net.minecraft.server.MinecraftServer.h(MinecraftServer.java:467)
            at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:374)
            at net.minecraft.server.ThreadServerApplication.run(SourceFile:417)
    Any ideas/solutions?

    btw line 44 is
    Code:
                    .get(0);
     
  19. So it has nothing to do with your config. I think the error occurs when the snowball don't hit an entity. You'll have to check if the list (which getNearbyEntities returns) is empty, or, even better, do what @nisovin suggested. :)

    BTW: The lines
    Player target = (Player) possibleTarget;
    and (especially)
    Entity target = (Entity) possibleTarget;
    are useless as you get an Entity object from get(0) and can put damage to it. Leaves a bit room for improvement:
    Code:
    int damage;
    if (possibleTarget instanceof Player && config.getBoolean("Snowball.PlayerDamage"))
      damage = config.getInt("Snowball.PlayerDamageInt");
    else if ((possibleTarget instanceof LivingEntity) && config.getBoolean("Snowball.MobDamage")) //Just saw that, an entity can also be a minecart, for example, so your code will crash if the ball hits an unliving entity! Fixed. :)
      damage = config.getInt("Snowball.MobDamageInt");
     else
      return;
    ((LivingEntity) target).damage(damage);
    ;)
     
  20. Offline

    theguynextdoor

    Just curious but i was playing around and i tried the
    Code:
        pm.registerEvent(Event.Type.ENTITY_DAMAGE, new EntityListener() {
    
                public void onEntityDamageByProjectile(EntityDamageByProjectileEvent e) {
    
                    Projectile projectile = (Projectile) e.getEntity();
                    Entity possibleTarget = projectile.getNearbyEntities(1, 1, 1)
                            .get(0);
    
                    int damage;
                    if (possibleTarget instanceof Player && config.getBoolean("Snowball.PlayerDamage"))
                      damage = config.getInt("Snowball.PlayerDamageInt");
                    else if ((possibleTarget instanceof LivingEntity) && config.getBoolean("Snowball.MobDamage")) //Just saw that, an entity can also be a minecart, for example, so your code will crash if the ball hits an unliving entity! Fixed. :)
                      damage = config.getInt("Snowball.MobDamageInt");
                    else{
                      return;}
    
                    ((LivingEntity) possibleTarget).damage(damage);
    
            }}, Priority.Highest, this);
    and on the bit that says
    Code:
     public void onEntityDamageByProjectile(EntityDamageByProjectileEvent e) {
    It says that

    The method onEntityDamageByProjectile(EntityDamageByProjectileEvent) from the type new EntityListener(){} is never used locally

    And also that
    EntityDamageByProjectileEvent is deprecated.

    I dunno what this means entirely but what i do know is it doesn't work. So why doesn't it work?
     
  21. Offline

    nisovin

    The onEntityDamageByProjectile() method is not a method of the EntityListener class. You need to use onEntityDamage() and cast the event object to what you need. This is why you always prefix your overridden methods with @Override. And, EntityDamageByProjectileEvent is deprecated, that's why it's telling you that. Use EntityDamageByEntity instead.
     
  22. Offline

    theguynextdoor

    I have now got the code sorted and working thanks to some help from Nossr50. The code i am now using to damage the player is as follows.
    Code:
            pm.registerEvent(Event.Type.ENTITY_DAMAGE, new EntityListener() {
    
                public void onEntityDamage(EntityDamageEvent event) {
    
                    if (event instanceof EntityDamageByEntityEvent) {
    
                        Entity attacker = ((EntityDamageByEntityEvent) event)
                                .getDamager();
    
                        if (attacker instanceof Projectile) {
                            if (attacker instanceof Snowball) {
                                int damage;
                                if (event.getEntity() instanceof Player
                                        && config
                                                .getBoolean("Snowball.PlayerDamage"))
                                    damage = config
                                            .getInt("Snowball.PlayerDamageInt");
                                else if (event.getEntity() instanceof LivingEntity
                                        && !(event.getEntity() instanceof Player)
                                        && config.getBoolean("Snowball.MobDamage"))
                                    damage = config.getInt("Snowball.MobDamageInt");
                                else
                                    return;
                                event.setDamage(damage);
    
                            }
    
                        }
                    }
                }
            }, Priority.Highest, this);
    I will finish adding commands and will then set to getting this plugin released
     
  23. The first check is useless, simply make it to:
    Code:
    if (attacker instanceof Snowball) {
    :)
     
  24. Offline

    theguynextdoor

    Changed, thank you

    Now i have the plugin sorted out and ready to submit, and it has a few commands aswell.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 21, 2016
  25. Offline

    nicholasntp

    Yes, I would love this. Thanks so much.
     
  26. Offline

    theguynextdoor

Thread Status:
Not open for further replies.

Share This Page