Solved Trying to select an online player when clicking a compass

Discussion in 'Spigot Plugin Development' started by Gravydigger, Jan 28, 2020.

Thread Status:
Not open for further replies.
  1. Hello!

    This is the first plugin I'm trying to do, but I objective is when a player right clicks on a compass, it selects an online player, and when the player right-clicks again, it selects the next online player, etc. until it loops back again.

    Here is my attempt at it:
    Code (Text):
    Main m;
        PlayerSelector pl;
        public Listener instance = this;
        ArrayList<Player> onlinePlayers = new ArrayList<Player>();
       
       
        //Constructor
        public Listener(Main plugin) {...}
       
        //Add them to an online list to cycle who is online
        @EventHandler
        public void onPlayerJoin(PlayerJoinEvent event) {
           
            Player player = (Player) event.getPlayer();
           
            onlinePlayers.add(player);
           
            //player.sendMessage("Hello!");
           
        }
       
        //Removes them from the online list to cycle who is online
        @EventHandler
        public void onPlayerLeave(PlayerQuitEvent event) {
           
            Player player = (Player) event.getPlayer();
           
            onlinePlayers.remove(player);
        }
       
       
        @EventHandler
        public void onRightClick(PlayerInteractEvent event) {
           
            Player player = event.getPlayer();
           
            PlayerInventory playerInv = event.getPlayer().getInventory();
           
            if ((event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK )) {
                player.sendMessage("You right clicked.");
               
                if (playerInv.getItemInMainHand().getType() == Material.COMPASS || playerInv.getItemInOffHand().getType() == Material.COMPASS) {
                    player.sendMessage("...and had a compass.");
                   
                    //Finds an online player
                    Player target = pl.selectedPlayer();
                    player.sendMessage("The selected player is " + target + ".");
                }
            }
        }

    Code (Java):
    public PlayerSelector instance = this;
        public Listener listener;
        int i = 0;
       
        //When the function is called, return an online player, and loop back when at the end of the list
        public Player selectedPlayer() {
           
            if (i > listener.onlinePlayers.size())
                i = 0;
           
            Player target = listener.onlinePlayers.get(i);
            i++;
           
            return target;
        }

    However, when I attempt to right-click, I get an error:

    Code (Text):
    [11:40:26] [Server thread/ERROR]: Could not pass event PlayerInteractEvent to CompassPlayerFinder v1.0
    org.bukkit.event.EventException: null
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:320) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:529) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:514) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at org.bukkit.craftbukkit.v1_14_R1.event.CraftEventFactory.callPlayerInteractEvent(CraftEventFactory.java:437) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at org.bukkit.craftbukkit.v1_14_R1.event.CraftEventFactory.callPlayerInteractEvent(CraftEventFactory.java:404) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at org.bukkit.craftbukkit.v1_14_R1.event.CraftEventFactory.callPlayerInteractEvent(CraftEventFactory.java:400) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.PlayerConnection.a(PlayerConnection.java:1277) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.PacketPlayInBlockPlace.a(PacketPlayInBlockPlace.java:28) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.PacketPlayInBlockPlace.a(PacketPlayInBlockPlace.java:1) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.PlayerConnectionUtils.lambda$0(PlayerConnectionUtils.java:19) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.TickTask.run(SourceFile:18) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.IAsyncTaskHandler.executeTask(SourceFile:144) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.IAsyncTaskHandlerReentrant.executeTask(SourceFile:23) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.IAsyncTaskHandler.executeNext(SourceFile:118) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.MinecraftServer.aX(MinecraftServer.java:909) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.MinecraftServer.executeNext(MinecraftServer.java:902) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.IAsyncTaskHandler.awaitTasks(SourceFile:127) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.MinecraftServer.sleepForTick(MinecraftServer.java:886) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.MinecraftServer.run(MinecraftServer.java:819) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at java.lang.Thread.run(Unknown Source) [?:1.8.0_241]
    Caused by: java.lang.NullPointerException
            at com.gravy.compassPlayerFinder.CPF_Listener.onRightClick(CPF_Listener.java:71) ~[?:?]
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_241]
            at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_241]
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_241]
            at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_241]
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:316) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            ... 20 more

    I know that this segment in Listener.java is causing me trouble:
    Code (Java):
    Player target = pl.selectedPlayer();
                    player.sendMessage("The selected player is " + target + ".");
    However, I'm not quite sure how to solve it. It could be I'm doing something really stupid and easy to fix.

    Any help is appreciated!
     
  2. 1) pl is probably null, check that you have initialized that in your constructor
    2)
    Code (Text):
    if (i > listener.onlinePlayers.size())
    will return an ArrayIndexOutOfBoundsException, you’ll need to check for greater than or equal (since Array indexes go from 0 to size-1)
    3) Using target in that string will return a description of the Object (something like {CraftPlayer...}), what you probably want is target.getName() or target.getDisplayName()
    4) Bukkit already provides a Method that returns all online players as a List (Bukkit#getOnlinePlayers()), no need to write that yourself
     
  3. Thank you, I still get a null error.

    1) Looked at a few references, and I think I initialized the constructor correctly but providing that it does not work, probably not ^^;
    Code (Java):
    Main m;
        PlayerSelector pl;
        public Listener instance = this;
        ArrayList<Player> onlinePlayers = new ArrayList<Player>();
       
       
        //Constructor
        public Listener(Main plugin) {
            pl = new PlayerSelector();
        }
       
        //Add them to an online list to cycle who is online
        @EventHandler
        public void onPlayerJoin(PlayerJoinEvent event) {
           
            Player player = (Player) event.getPlayer();
           
            onlinePlayers.add(player);
           
            //player.sendMessage("Hello!");
           
        }
       
        //Removes them from the online list to cycle who is online
        @EventHandler
        public void onPlayerLeave(PlayerQuitEvent event) {
           
            Player player = (Player) event.getPlayer();
           
            onlinePlayers.remove(player);
        }
       
       
        @EventHandler
        public void onRightClick(PlayerInteractEvent event) {
           
            Player player = event.getPlayer();
           
            PlayerInventory playerInv = event.getPlayer().getInventory();
           
            if ((event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK )) {
                player.sendMessage("You right clicked.");
               
                if (playerInv.getItemInMainHand().getType() == Material.COMPASS || playerInv.getItemInOffHand().getType() == Material.COMPASS) {
                    player.sendMessage("...and had a compass.");
                   
                    //Finds an online player
                    Player target = pl.selectedPlayer();
                    player.sendMessage("The selected player is " + target.getName() + ".");
                }
            }
        }
       

    2) Thank you, that would have given me hassle.
    3) At this stage, I just what the message sent through ^^;
    4) I understand that, but my knowledge of collections is limited, and I'm trying to understand it all.

    I'm not too familiar with Java, but I have coded stuff in C# (but its been a while). That you for your help so far.
     
  4. No, this actually looks fine. What I could imagine it being now is that the PlayerSelector has no reference (resp, null reference) to your listener, where you define your Player-Array. You initialize it with an empty constructor in the constructor of your listener; probably that's the reason...
     
  5. Is this what you mean?
    Code (Java):
    public Listener listener;
        int i = 0;
     
        //Constructer
        public PlayerSelector(Listener plugin) {

        }
     
        //When the function is called, return an online player, and loop back when at the end of the list
        public Player selectedPlayer() {
         
            if (i > listener.onlinePlayers.size())
                i = 0;
         
            Player target = listener.onlinePlayers.get(i);
            i++;
         
            return target;
        }

    Sadly, I still get a null error:
    Code (Text):
    [16:19:08] [Server thread/ERROR]: Could not pass event PlayerInteractEvent to CompassPlayerFinder v1.0
    org.bukkit.event.EventException: null
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:320) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:529) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:514) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at org.bukkit.craftbukkit.v1_14_R1.event.CraftEventFactory.callPlayerInteractEvent(CraftEventFactory.java:437) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.PlayerInteractManager.a(PlayerInteractManager.java:431) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.PlayerConnection.a(PlayerConnection.java:1238) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.PacketPlayInUseItem.a(PacketPlayInUseItem.java:27) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.PacketPlayInUseItem.a(PacketPlayInUseItem.java:1) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.PlayerConnectionUtils.lambda$0(PlayerConnectionUtils.java:19) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.TickTask.run(SourceFile:18) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.IAsyncTaskHandler.executeTask(SourceFile:144) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.IAsyncTaskHandlerReentrant.executeTask(SourceFile:23) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.IAsyncTaskHandler.executeNext(SourceFile:118) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.MinecraftServer.aX(MinecraftServer.java:909) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.MinecraftServer.executeNext(MinecraftServer.java:902) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.IAsyncTaskHandler.awaitTasks(SourceFile:127) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.MinecraftServer.sleepForTick(MinecraftServer.java:886) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at net.minecraft.server.v1_14_R1.MinecraftServer.run(MinecraftServer.java:819) [spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            at java.lang.Thread.run(Unknown Source) [?:1.8.0_241]
    Caused by: java.lang.NullPointerException
            at com.gravy.compassPlayerFinder.CPF_Listener.onRightClick(CPF_Listener.java:64) ~[?:?]
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_241]
            at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_241]
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_241]
            at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_241]
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:316) ~[spigot-1.14.4.jar:git-Spigot-cbd1a1b-009d8af]
            ... 19 more
     
  6. Code (Java):
    public Listener listener;
        int i = 0;
     
        //Constructer
        public PlayerSelector(Listener plugin) {
            // is this line there?
            this.listener = plugin;
        }
     
        //When the function is called, return an online player, and loop back when at the end of the list
        public Player selectedPlayer() {
         
            if (i > listener.onlinePlayers.size())
                i = 0;
         
            Player target = listener.onlinePlayers.get(i);
            i++;
         
            return target;
        }
     
  7. I
    I have put it in now, but the error still occurred. Is there any more information I could provide to help you?
     
  8. Ah maybe the whole class because some things seem a bit fishy here... Listener doesn‘t have a member onlineMembers, so you might have Naming problems...
    Other than that, you could only try to print out what exactly is null (System.out.println(pr==null) for example)
     

  9. Code (Java):
    package com.gravy.compassPlayerFinder;

    import org.bukkit.entity.Player;

    public class PlayerSelector {

        public Listener listener;
        int i = 0;
     
        //Constructer
        public PlayerSelector(Listener plugin) {
            this.listener = plugin;
        }
     
        //When the function is called, return an online player, and loop back when at the end of the list
        public Player selectedPlayer() {
         
            if (i > listener.onlinePlayers.size())
                i = 0;
         
            Player target = listener.onlinePlayers.get(i);
            i++;
         
            return target;
        }
     
    }
     

    Thanks for the help regardless ^^. I appreciate it.
     
  10. The other class as well please... and did you try to see what exactly is null?
     
  11. Code (Java):
    package com.gravy.compassPlayerFinder;

    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.plugin.PluginManager;
    import org.bukkit.plugin.java.JavaPlugin;

    public class Main extends JavaPlugin {
     
        Main instance = this;
        Listener listener;
        public Player target = Bukkit.getPlayer("Gravydigger");
        public Player player;
     
     
        @Override //Shows a message to the console that the plugin as been enabled
        public void onEnable() {
            getLogger().info("CompassPlayerFinder has been enabled.");
         
            PluginManager pm = getServer().getPluginManager();
         
            Listener listener = new Listener(this);
            pm.registerEvents(listener, this);
         
            listener.onlinePlayers.addAll(getServer().getOnlinePlayers());
        }
     
        @Override //Shows a message to the console that the plugin as been enabled
        public void onDisable() {
            getLogger().info("CompassPlayerFinder has been disabled.");
        }
     
        public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
         
            player = (Player) sender;
         
            if (sender instanceof Player) {
                String lowerCmd = cmd.getName().toLowerCase();
             
                switch (lowerCmd) {
                //Gives the player a compass
                case "givecompass":
                    ItemStack item = new ItemSmith().buildItem(1);
                    player.getInventory().addItem(item);
                    getServer().broadcastMessage(ChatColor.DARK_RED + player.getName() + ChatColor.RESET + " gave himself a finder compass.");
                    return true;
                default:
                    player.sendMessage("Your command was not reconised1.");
                }
                return true;
            }
         
            player.sendMessage("Your command was not reconised2.");
            return true;
        }
     
    }
    Code (Java):
    package com.gravy.compassPlayerFinder;

    import org.bukkit.entity.Player;

    public class PlayerSelector {

        public Listener listener;
        int i = 0;
     
        //Constructer
        public PlayerSelector(Listener plugin) {
            this.listener = plugin;
        }
     
        //When the function is called, return an online player, and loop back when at the end of the list
        public Player selectedPlayer() {
         
            if (i > listener.onlinePlayers.size())
                i = 0;
         
            Player target = listener.onlinePlayers.get(i);
            i++;
         
            return target;
        }
     
    }
    Code (Java):
    package com.gravy.compassPlayerFinder;

    import java.util.ArrayList;

    import org.bukkit.ChatColor;
    import org.bukkit.Material;
    import org.bukkit.inventory.ItemFlag;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.meta.ItemMeta;

    public class ItemSmith {

        //A generalized meta data changer for items
        public ItemStack makeItem(Material m, String name, String desc, int amount) {
         
            ItemStack item = new ItemStack(m, amount);
         
            //Create item meta data (name, lore/desc, etc.)
            ItemMeta im = item.getItemMeta();
            im.setDisplayName(name);
         
            //lore
            ArrayList<String> lore = new ArrayList<String>();
            lore.add(desc);
            im.setLore(lore);
         
            //Hides vanilla tool tip Text
            im.addItemFlags(ItemFlag.HIDE_ENCHANTS);
            im.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
         
            //Changes the meta data of the from vanilla to the custom meta data
            item.setItemMeta(im);
         
            return item;
        }
     
        public ItemStack buildItem(int amount) {
         
            Material m = Material.COMPASS;
            String name = (ChatColor.GREEN + "Player Finder");
            String desc = (ChatColor.translateAlternateColorCodes('&', "&2&oRight-click to track a player!"));
         
            return makeItem(m, name, desc, 1);
        }
     
     
    }

    Where about would you place (System.out.println(pl==null)? Do you need to place it after the null, or does it actively look for when pl is null? Sorry, this is inexperience talking, I'm used to using breaking points for debugging ^^;
     
  12. You place it like a probe to figure out at which point in your code the variable holds null. so start above where you get the error, and move it up until you find the place that makes it null.
     
    • Informative Informative x 1
  13. Wait, what is Listener?
    If Listener is the Bukkit Listener, you can't just say
    Code (Java):
    Listener listener = new Listener();
    in fact, that shouldn't even compile... Other than that, where is the method you are listening to? I think you linked the wrong class ;)
     
  14. Code (Java):
    Listener listener = new Listener();
    Is linking Main.java and CPFListener.java (renamed from Listener.java). I'm trying to link CPFListener.java and PlayerSelector.java together. is that even possible, or does everything need to link back to Main.java?

    Also would static also work as well?

    So it is kinda like breakpoints. Thank you for the clarification.

    EDIT: Yeah, it looks like pl is null. Basically its boiling down too "How do I connect two classes together".
     
  15. well, I'm not quite sure what you mean by "linking two classes together" because you can only "connect" objects. I don't think that's much different from C#.
    Never use static, unless you know exactly why you use static. Most of the time it's not a viable solution when your IDE tells that a certain variable can be made static to solve a certain problem.
    Now for your error; since I don't know what your CPFListener-class is, here's what you (probably) need to do (or at least what I would do):
    Code (Java):
    public class Main extends JavaPlugin {
        // You should consider moving that player-list in here
        // Also, this could be a Set, not a List (more performant), but let's just keep that for now
        private final List<Player> onlinePlayers = new ArrayList<>();
        private PlayerSelector playerSelector;
        @Override
        public void onEnable() {
            this.getPluginManager().registerEvents(new CPFListener(this), this);
            this.playerSelector = new PlayerSelector(this);
       }

       public void addPlayer(Player player) {
            this.onlinePlayers.add(player);
        }

        public void removePlayer(Player player) {
            this.onlinePlayers.remove(player);
        }

        public PlayerSelector getPlayerSelector() {
            return this.playerSelector;
        }
    }
    Listener:
    Code (Java):
    public class CPFListener{
        private Main main;

        public CPFListener(Main main) {
            this.main = main;
        }

        @EventHandler
        public void onLogin(PlayerLoginEvent event) {
            //...
            main.addPlayer(event.getPlayer());
        }

        @EventHandler
        public void onLogin(PlayerLogoutEvent event) {
            //...
            main.removePlayer(event.getPlayer());
        }
    }
    and finally, you can do what you want to do when the player clicks that compass:
    Code (Java):
    @EventHandler
    public void onInteract(PlayerInteractEvent event) {
        //...
        Player target = main.getPlayerSelector().selectPlayer();
        //...
    }
    You could also consider having the PlayerSelector as a field inside the Listener. But that's how you'd link those two classes together.
     
    • Winner Winner x 1
  16. Yes! You did it, it's finally working! Thank you, good sir, thank you!
     
Thread Status:
Not open for further replies.