Solved Arrow cannot be cast to player?

Discussion in 'Spigot Plugin Development' started by Pr0Pancakeslol, Sep 12, 2019 at 2:18 AM.

  1. Hey,

    I just wrote a small plugin to check if a player had permission to shoot or punch an endercrystal.

    It works perfectly neither punching or shooting an arrow will explode a crystal however I get a huge error saying that a player cannot be cast to an Arrow type

    https://hastebin.com/efiguhevog.java - code
    https://pastebin.com/KVqh3ubY - big ass error

    There must be a better way to attach these two together
     
  2. Code (Text):
    @EventHandler public void onEntityEntity(EntityDamageByEntityEvent e) {
            if(e.getEntity().getType().equals(EntityType.ENDER_CRYSTAL)) {
                Player player = (Player) e.getDamager();
                if(e.getDamager() instanceof Player && !player.hasPermission("endercrystal.break")) {
                    e.setCancelled(true);
                }
            }
        }
    }
    You're setting a player object before you check if the damager is an instance of Player. Since the event checks any entity, it will also fire for arrows. When the arrow hits the ender crystal, it tries setting the player object to the arrow, giving you that error.
     
    #2 firewolf8385, Sep 12, 2019 at 2:38 AM
    Last edited: Sep 12, 2019 at 2:46 AM
  3. if attacker instanceof Projectile
    use Projectile#getProjectileSource()
    and check if it is instanceof Player
     
  4. hmm i cant seem to get it right

    Code (Java):
        @EventHandler public void onEntityArrowEntity(EntityDamageByEntityEvent e) {  
            if(e.getDamager() instanceof Projectile) {
                ProjectileSource s = (ProjectileSource) e.getDamager();
                if(s instanceof Player) {
                    Player player = (Player) e.getDamager();
                    if(!player.hasPermission("endercrystal.break")) {
                        e.setCancelled(true);
                    }      
                }
            }
        }
     
  5. The code you posted only checks for projectiles launched by a player, but not for a player directly punching the ender crystal.

    What I would do is make a separate method that gets the player involved with the event (if present, otherwise returns null). In that method, I'd do the checks you're doing, but if the damager is not a projectile, you'd see if it was a player and if true, return the player. Now in the event handler, I'd call said method and check for null. If not null, check for perms. If no perms, cancel.
     
  6. hey guys thanks for all the responses

    I used allot of info I got another method here for the player punching the endercrystal however when playing around with it i couldn't quite get the player involved or figure out how to call my event into my arrow method but I played with the Arrow some more because I couldn't get the player so I figure I could at least get the shooter and figure out how to cast it right everything seems okay now no errors but my permission system doesn't work. Whether I am op or not I can't break or shoot endercrystals.



    https://hatebin.com/sbfhhhpnmq
     
  7. I noticed you cancel the event if it's not in the end, or if the arrow is not hitting an end crystal. This could be problematic because it will cancel the event even if someone is shooting arrows in other worlds. But to your question about the permissions, a good way to test if your code is cancelling where you think it is would be to add some System.out.println("1").. 2.. etc. To make sure your code is actually reaching the Player#hasPermission() line. If it is, then it may be something with the permission plugin you are using.
     
    • Like Like x 1
  8. mmmm, try with this, it's more easy and efiency
    Code (Java):
    @EventHandler public void onEntityArrowEntity(EntityDamageByEntityEvent e) {

    if(e.getDamager() instanceof Projectile && e.getEntity() instanceof EnderCrystal ){
         Projectile projectile = (Projectile)e.getDamager();
         EnderCyrstal crystal = (EnderCrystal)e.getEntity();
                  if(projectile.getShooter() instanceof Player){
                      Player player = (Player)projectile.getShooter();
                                        if(crystal.getWorld().getEnvironment().equals(Environment.THE_END)){
                                               e.setCancelled(true);
                                   }
    }
     
        }
     
    • Winner Winner x 1
  9. @KarateMan2400 Being pedantic here, but technically it's discouraged to use System.out for debugging the API, a logger object or server-broadcast is preferred. (That being said, I use sysout because I'm lazy, but do as I say, not as I do.)

    @Pr0Pancakeslol Hatebin?? Are you full of hate, boy?

    Code (Java):
    package com.Pr0Pancakes.EBC;

    import org.bukkit.entity.Arrow;
    import org.bukkit.entity.EntityType;
    import org.bukkit.entity.Player;
    import org.bukkit.entity.Projectile;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.entity.EntityDamageByEntityEvent;
    import org.bukkit.plugin.java.JavaPlugin;

    public class Listeners extends JavaPlugin implements Listener{
       
        public void onEnable() {
            this.getServer().getPluginManager().registerEvents(this, this);
           
        }
       
        public void onDisable() {
           
        }
        @EventHandler public void onEntityArrowEntity(EntityDamageByEntityEvent e) {
            if(!(e.getDamager() instanceof Arrow &&
                    (!e.getDamager().getWorld().getName().equalsIgnoreCase("world_the_end")))) {
                e.setCancelled(true);
            }
            if(!e.getEntity().getType().equals(EntityType.ENDER_CRYSTAL)) {
                e.setCancelled(true);
            }
            if(e.getDamager() instanceof Arrow) {

                Arrow a = (Arrow) e.getDamager();
                Projectile arrow = (Projectile) a;
                Player player = (Player) a.getShooter();
                if(!(arrow.getShooter() instanceof Player)) {
                    e.setCancelled(true);
                }
                if(!player.hasPermission("endercrystal.break")) {
                    e.setCancelled(true);
                }      
            }
        }
       
        @EventHandler public void onEntityEntity(EntityDamageByEntityEvent e, Player player) {
            if(!e.getEntity().getType().equals(EntityType.ENDER_CRYSTAL)) {
                e.setCancelled(true);
            }
            Player players = (Player) e.getDamager();
            if(!players.hasPermission("endercrystal.break")) {
                e.setCancelled(true);
            }
        }
    }
    A couple things about this code:
    1. I feel like it'd be best to return anytime you cancel the event, so that you can eliminate any potential runtime overhead, unless your logic flow relies on not returning (it doesn't appear to).
    2. If your "endercrystal.break" permission isn't listed in the plugin.yml, then the server won't grant it automatically to ops (Consult the permissions table from this link.)
    3. Your onEntityEntity method will not work. The event method must only contain a single parameter, that being the event you're listening to.
    i.e.:
    Code (Java):
    Valid Cases:

    @EventHandler
    public void onEntityEntity(EntityDamageByEntityEvent e) {
        //impl.
    }

    @EventHandler
    public void exampleText(EntityDamageByEntityEvent e) {
        //impl.
    }

    Invalid Cases:

    @EventHandler
    public void doesntMatter(EntityDamageByEntityEvent e, Object o) {
        //impl.
    }

    @EventHandler
    public void couldBeAnythingHere(EntityDamageByEntityEvent e, Player p) {
        //impl.
    }

    @EventHandler
    public void onlyOneEventParameterThough(EntityDamageByEntityEvent e, EntityDamageEvent ev) {
        //impl.
    }

    @EventHandler
    public void yeahThisBadToo(Player p) {
        //impl.
    }
     
    • Winner Winner x 1
  10. Hey, first of all I can't believe I really got scammed into using Hatebin lmao All that stuff is very informative! I had no idea I couldn't use second parameters in events, I was wondering about returning allot and where I should. I added my permission into my config as well.

    Everything seems to work great now thanks everyone for the replies.
     
    • Friendly Friendly x 1