Player selector (@p, @r, @a) library

Discussion in 'Plugin Development' started by saharNooby, May 15, 2015.

Thread Status:
Not open for further replies.
  1. I need to use player selectors like in vanilla commands, such as @p, @r, @a. I tried to write a class, that selects players by given selector, but it's too hard. Is there a library, or a class, that can select players?
     
  2. Offline

    timtower Administrator Administrator Moderator

    @saharNooby What part is too hard to do? Might be able to give a push in the right direction
     
  3. Lol, I can do it all, but I'm very lazy. :) If there is libs, I will use them, if there is not -- I will write selectors by myself.
     
  4. Offline

    timtower Administrator Administrator Moderator

  5. Offline

    Agentleader1

    Here:
    TargetPlayer Library Class (open)

    Code:
    @SuppressWarnings("deprecation")
    public class TargetPlayer {
    
        public static Player targetR(){
            int i = getRandomInt(0, Bukkit.getOnlinePlayers().length);
            return Bukkit.getOnlinePlayers()[i];
        }
        public static Player[] targetA(){
            return Bukkit.getOnlinePlayers();
        }
        public static Player targetP(Location loc){
            double distance = 100000;
            Player nearest = null;
            for(Player player : Bukkit.getOnlinePlayers()){
                if(loc.distance(player.getLocation()) < distance){
                    nearest = player;
                }
            }
            return nearest;
        }
        private static Random random = new Random();
        public static int getRandomInt(int min, int max){
            return (random.nextInt((max - min) + 1) + min);
        }
      
        public static double getRandomDoub(double min, double max){
            return (min + (max - min) * random.nextDouble());
        }
    }
    

    If you were looking for range setup and scoreboard checks, that'll be a lot more complicated but still doable.
     
  6. Offline

    MexMaster

    In the new bukkit versions "Bukkit.getOnlinePlayers()" returns a collection, no longer an array.
    Also for the "targetP" method i would rather do something like this:

    Code:
    public static Player targetP(Location loc){
         Player nearestPlayer = null;
         double lastDistance = Double.MAX_VALUE;
         for(Player p : loc.getWorld().getPlayers()){
              double distanceSqrd = loc.distanceSquared(p.getLocation());
              if(distanceSqrd < lastDistance){
                   lastDistance = distanceSqrd;
                   nearestPlayer = p;
              }
         }
         return nearestPlayer;
    }
    
    The maximum value of a double is much greater than the world of minecraft, so it will get all players for sure.
    In your method it would miss players further away than 100000 blocks, this can lead to unsupposed bugs.
    Also in your example the method Math.sqrt (for getting the square root) would be called multiple times. It's cpu heavy.
    distanceSquared is not using Math.sqrt and so is faster.
     
  7. Hi again. I wrote a class that selects players by simple selectors such as @a, @p[10], @r[5], @p.

    TargetSelector (open)

    Code:
    package saharnooby.selector;
    
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.regex.Pattern;
    
    import org.bukkit.Bukkit;
    import org.bukkit.Location;
    import org.bukkit.entity.Player;
    
    public class TargetSelector {
    
        private static final Pattern PATTERN = Pattern.compile("^@[par](\\[\\-?[0-9]*\\])?$");
     
        private static class PlayerDistanceComparator implements Comparator {
    
            private final Location location;
    
            public PlayerDistanceComparator(Location location) {
                this.location = location;
            }
    
            public int compare(Object o1, Object o2) {
                double a = ((Player) o1).getLocation().distanceSquared(location);
                double b = ((Player) o2).getLocation().distanceSquared(location);
                return a < b ? -1 : a > b ? 1 : 0;
            }
        }
     
        private static int getCount(String s) {
            int a = s.indexOf('['), b = s.indexOf(']');
            String count = a != -1 && b != -1 && a < b ? s.substring(a + 1, b) : null;
            return count != null ? Integer.valueOf(count) : 1;
        }
     
        private static List<Player> getPlayers(Player player, int count, boolean sort, boolean randomize) {
            List<Player> players = new LinkedList<>();
         
            for (Player p : Bukkit.getOnlinePlayers()) {
                if (p != player || randomize || count == 0) {
                    players.add(p);
                }
            }
         
            if (sort) {
                Collections.sort(players, new PlayerDistanceComparator(player.getLocation()));
             
                if (count < 0) {
                    Collections.reverse(players);
                }
            } else if (randomize) {
                Collections.shuffle(players);
            }
         
            return players.subList(0, Math.min(count < 0 ? -count : count == 0 ? players.size() : count, players.size()));
        }
     
        public static boolean isSelector(String selector) {
            return PATTERN.matcher(selector).matches();
        }
     
        public static List<Player> getPlayers(Player player, String selector) {
            if (selector.startsWith("@p")) {
                return getPlayers(player, getCount(selector), true, false);
            } else if (selector.startsWith("@r")) {
                return getPlayers(player, getCount(selector), false, true);
            } else {
                return getPlayers(player, 0, false, false);
            }
        }
     
    }


    Unfortunately, it does not suppot 'x', 'y', 'z', and 'r' parameters.
     
    Last edited: May 15, 2015
  8. Offline

    Agentleader1

    @saharNoobyc It's @p[r=range#] not @p[range]
     
  9. And what?
     
  10. Offline

    Agentleader1

    @saharNooby For example; @p[r=10] gets the nearest player in a range of 10. @p[10] does nothing.
     
  11. @p[123] selects 123 near players in my class (see above). In vanilla mc it does nothing, I know.
     
Thread Status:
Not open for further replies.

Share This Page