Package com.sk89q.commandbook.util

Source Code of com.sk89q.commandbook.util.InputUtil$LocationParser

package com.sk89q.commandbook.util;

import com.google.common.collect.Lists;
import com.sk89q.commandbook.CommandBook;
import com.sk89q.commandbook.locations.*;
import com.sk89q.commandbook.util.entity.player.PlayerUtil;
import com.sk89q.commandbook.util.entity.player.comparison.PlayerComparisonUtil;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.sk89q.commandbook.util.entity.player.PlayerUtil.checkPlayer;

public class InputUtil {

    public static class TimeParser {

        /**
         * A pattern that matches time given in 12-hour form (xx:xx(am|pm))
         */
        protected static final Pattern TWELVE_HOUR_TIME = Pattern.compile("^([0-9]+(?::[0-9]+)?)([apmAPM\\.]+)$");

        public static long matchDate(String filter) throws CommandException {
            if (filter == null) return 0L;
            if (filter.equalsIgnoreCase("now")) return System.currentTimeMillis();
            String[] groupings = filter.split("-");
            if (groupings.length == 0) throw new CommandException("Invalid date specified");
            Calendar cal = new GregorianCalendar();
            cal.setTimeInMillis(0);
            for (String str : groupings) {
                int type;
                switch (str.charAt(str.length() - 1)) {
                    case 'm':
                        type = Calendar.MINUTE;
                        break;
                    case 'h':
                        type = Calendar.HOUR;
                        break;
                    case 'd':
                        type = Calendar.DATE;
                        break;
                    case 'w':
                        type = Calendar.WEEK_OF_YEAR;
                        break;
                    case 'y':
                        type = Calendar.YEAR;
                        break;
                    default:
                        throw new CommandException("Unknown date value specified");
                }
                cal.add(type, Integer.valueOf(str.substring(0, str.length() -1)));
            }
            return cal.getTimeInMillis();
        }

        public static long matchFutureDate(String filter) throws CommandException {
            return matchDate(filter) + System.currentTimeMillis();
        }

        /**
         * Parse a time string into the MC world time.
         *
         * @param timeStr the time string to parse
         * @return the world time
         * @throws com.sk89q.minecraft.util.commands.CommandException
         */
        public static int matchMCWorldTime(String timeStr) throws CommandException {
            Matcher matcher;

            try {
                int time = Integer.parseInt(timeStr);

                // People tend to enter just a number of the hour
                if (time <= 24) {
                    return ((time - 8) % 24) * 1000;
                }

                return time;
            } catch (NumberFormatException e) {
                // Not an integer!
            }

            // Tick time
            if (timeStr.matches("^*[0-9]+$")) {
                return Integer.parseInt(timeStr.substring(1));

                // Allow 24-hour time
            } else if (timeStr.matches("^[0-9]+:[0-9]+$")) {
                String[] parts = timeStr.split(":");
                int hours = Integer.parseInt(parts[0]);
                int mins = Integer.parseInt(parts[1]);
                return (int) (((hours - 8) % 24) * 1000
                        + Math.round((mins % 60) / 60.0 * 1000));

                // Or perhaps 12-hour time
            } else if ((matcher = TWELVE_HOUR_TIME.matcher(timeStr)).matches()) {
                String time = matcher.group(1);
                String period = matcher.group(2);
                int shift;

                if (period.equalsIgnoreCase("am")
                        || period.equalsIgnoreCase("a.m.")) {
                    shift = 0;
                } else if (period.equalsIgnoreCase("pm")
                        || period.equalsIgnoreCase("p.m.")) {
                    shift = 12;
                } else {
                    throw new CommandException("'am' or 'pm' expected, got '"
                            + period + "'.");
                }

                String[] parts = time.split(":");
                int hours = Integer.parseInt(parts[0]);
                int mins = parts.length >= 2 ? Integer.parseInt(parts[1]) : 0;
                return (int) ((((hours % 12) + shift - 8) % 24) * 1000
                        + (mins % 60) / 60.0 * 1000);

                // Or some shortcuts
            } else if (timeStr.equalsIgnoreCase("dawn")) {
                return (6 - 8 + 24) * 1000;
            } else if (timeStr.equalsIgnoreCase("sunrise")) {
                return (7 - 8 + 24) * 1000;
            } else if (timeStr.equalsIgnoreCase("morning")) {
                return (24) * 1000;
            } else if (timeStr.equalsIgnoreCase("day")) {
                return (24) * 1000;
            } else if (timeStr.equalsIgnoreCase("midday")
                    || timeStr.equalsIgnoreCase("noon")) {
                return (12 - 8 + 24) * 1000;
            } else if (timeStr.equalsIgnoreCase("afternoon")) {
                return (14 - 8 + 24) * 1000;
            } else if (timeStr.equalsIgnoreCase("evening")) {
                return (16 - 8 + 24) * 1000;
            } else if (timeStr.equalsIgnoreCase("sunset")) {
                return (21 - 8 + 24) * 1000;
            } else if (timeStr.equalsIgnoreCase("dusk")) {
                return (21 - 8 + 24) * 1000 + (int) (30 / 60.0 * 1000);
            } else if (timeStr.equalsIgnoreCase("night")) {
                return (22 - 8 + 24) * 1000;
            } else if (timeStr.equalsIgnoreCase("midnight")) {
                return (0 - 8 + 24) * 1000;
            }

            throw new CommandException("Time input format unknown.");
        }
    }

    public static class PlayerParser {

        /**
         * Match player names.
         *
         * @param source
         * @param filter
         * @return
         */
        public static List<Player> matchPlayerNames(CommandSender source, String filter) {

            Collection<? extends Player> players = CommandBook.server().getOnlinePlayers();
            boolean useDisplayNames = CommandBook.inst().lookupWithDisplayNames;

            filter = filter.toLowerCase();

            if (filter.length() >= 2) {
                boolean exactMatch = filter.charAt(0) == '@';
                boolean startWildCard = filter.charAt(0) == '*';
                boolean endWildCard = filter.charAt(filter.length() - 1) == '*';

                if (exactMatch) { // Exact matching requested
                    try {
                        return Lists.newArrayList(matchPlayerExactly(source, filter.substring(1)));
                    } catch (CommandException e) {
                        return new ArrayList<Player>();
                    }
                } else if (startWildCard || endWildCard) { // Wild card matching requested
                    // Remove the wild cards from the string
                    if (startWildCard && endWildCard) {
                        filter = filter.substring(1, filter.length() - 1);
                    } else if (startWildCard) {
                        filter = filter.substring(1);
                    } else {
                        filter = filter.substring(0, filter.length() - 1);
                    }

                    List<Player> list = new ArrayList<Player>();

                    // Match based on the positioning of the wild card
                    for (Player player : players) {
                        String targetName = player.getName().toLowerCase();
                        String targetDisplayName = ChatColor.stripColor(player.getDisplayName().toLowerCase());
                        if (startWildCard && endWildCard) {
                            if (targetName.contains(filter)
                                    || (useDisplayNames && targetDisplayName.contains(filter))) {
                                list.add(player);
                            }
                        } else if (startWildCard) {
                            if (targetName.endsWith(filter)
                                    || (useDisplayNames && targetDisplayName.endsWith(filter))) {
                                list.add(player);
                            }
                        } else {
                            if (targetName.startsWith(filter)
                                    || (useDisplayNames && targetDisplayName.startsWith(filter))) {
                                list.add(player);
                            }
                        }
                    }

                    return PlayerComparisonUtil.prioritySort(source, list);
                }
            }
            // Start with name matching
            List<Player> list = new ArrayList<Player>();

            for (Player player : players) {
                if (player.getName().toLowerCase().startsWith(filter)
                        || (useDisplayNames
                        && ChatColor.stripColor(player.getDisplayName().toLowerCase()).startsWith(filter))) {
                    list.add(player);
                }
            }

            return PlayerComparisonUtil.prioritySort(source, list);
        }

        /**
         * Checks permissions and throws an exception if permission is not met.
         *
         * @param source
         * @param filter
         * @return iterator for players
         * @throws CommandException no matches found
         */
        public static List<Player> matchPlayers(CommandSender source, String filter) throws CommandException {

            if (CommandBook.server().getOnlinePlayers().isEmpty()) {
                throw new CommandException("No players matched query.");
            }

            if (filter.equals("*")) {
                CommandBook.inst().checkPermission(source, "commandbook.targets.everyone");
                return checkPlayerMatch(Lists.newArrayList(CommandBook.server().getOnlinePlayers()));
            }

            // Handle special hash tag groups
            if (filter.charAt(0) == '#') {
                // Handle #world, which matches player of the same world as the
                // calling source
                if (filter.equalsIgnoreCase("#world")) {
                    World sourceWorld = checkPlayer(source).getWorld();
                    CommandBook.inst().checkPermission(source, "commandbook.targets.world." + sourceWorld.getName());
                    return checkPlayerMatch(sourceWorld.getPlayers());

                    // Handle #near, which is for nearby players.
                } else if (filter.startsWith("#near")) {
                    CommandBook.inst().checkPermission(source, "commandbook.targets.near");
                    List<Player> players = new ArrayList<Player>();
                    Player sourcePlayer = checkPlayer(source);
                    World sourceWorld = sourcePlayer.getWorld();
                    Location sourceLocation = sourcePlayer.getLocation();

                    double targetDistance = 30;

                    String[] split = filter.split(":");
                    if (split.length == 2) {
                        try {
                            targetDistance = Double.parseDouble(split[1]);
                        } catch (NumberFormatException ignored) { }
                    }

                    // Square the target distance so that we don't have to calculate the
                    // square root in this distance calculation
                    targetDistance = Math.pow(targetDistance, 2);

                    Location k = sourceLocation.clone(); // Included for optimization
                    for (Player player : CommandBook.server().getOnlinePlayers()) {
                        if (!player.getWorld().equals(sourceWorld)) continue;
                        if (player.getLocation(k).distanceSquared(sourceLocation) < targetDistance) {
                            players.add(player);
                        }
                    }

                    return checkPlayerMatch(players);

                } else {
                    throw new CommandException("Invalid group '" + filter + "'.");
                }
            }

            return checkPlayerMatch(matchPlayerNames(source, filter));
        }

        /**
         * Match a single player exactly.
         *
         * @param sender
         * @param filter
         * @return
         * @throws CommandException
         */
        public static Player matchPlayerExactly(CommandSender sender, String filter) throws CommandException {
            Collection<? extends Player> players = CommandBook.server().getOnlinePlayers();
            for (Player player : players) {
                if (player.getName().equalsIgnoreCase(filter)
                        || (CommandBook.inst().lookupWithDisplayNames
                        && player.getDisplayName().equalsIgnoreCase(filter))) {
                    return player;
                }
            }

            throw new CommandException("No player found!");
        }

        /**
         * Match only a single player.
         *
         * @param sender
         * @param filter
         * @return
         * @throws CommandException
         */
        public static Player matchSinglePlayer(CommandSender sender, String filter) throws CommandException {
            return checkSinglePlayerMatch(matchPlayers(sender, filter));
        }

        /**
         * Match only a single player or console.
         *
         * @param sender
         * @param filter
         * @return
         * @throws CommandException
         */
        public static CommandSender matchPlayerOrConsole(CommandSender sender, String filter) throws CommandException {

            // Let's see if console is wanted
            if (filter.equalsIgnoreCase("#console")
                    || filter.equalsIgnoreCase("*console*")
                    || filter.equalsIgnoreCase("!")) {
                return CommandBook.server().getConsoleSender();
            }

            return matchSinglePlayer(sender, filter);
        }

        public static Iterable<Player> detectTargets(CommandSender sender, CommandContext args, String perm) throws CommandException {
            List<Player> targets;
            // Detect targets based on the number of arguments provided
            if (args.argsLength() == 0) {
                targets = Lists.newArrayList(PlayerUtil.checkPlayer(sender));
            } else {
                targets = InputUtil.PlayerParser.matchPlayers(sender, args.getString(0));
            }
            InputUtil.PlayerParser.checkPlayerMatch(targets);
            // Check permissions!
            for (Player player : targets) {
                if (player.equals(sender)) {
                    CommandBook.inst().checkPermission(sender, perm);
                } else {
                    CommandBook.inst().checkPermission(sender, perm + ".other");
                    break;
                }
            }
            return targets;
        }

        /**
         * Checks if the given list of players is greater than size 0, otherwise
         * throw an exception.
         *
         * @param players
         * @return
         * @throws CommandException
         */
        @Deprecated
        public static List<Player> checkPlayerMatch(List<Player> players) throws CommandException {
            // Check to see if there were any matches
            if (players.isEmpty()) {
                throw new CommandException("No players matched query.");
            }
            return players;
        }

        /**
         * Checks if the given list of players is greater than size 0, otherwise
         * throw an exception.
         *
         * @param players
         * @return
         * @throws CommandException
         */
        public static <T extends Collection<? extends Player>> T checkPlayerMatch(T players) throws CommandException {
            // Check to see if there were any matches
            if (players.isEmpty()) {
                throw new CommandException("No players matched query.");
            }
            return players;
        }

        /**
         * Checks if the given list of players contains only one player, otherwise
         * throw an exception.
         *
         * @param players
         * @return
         * @throws CommandException
         */
        public static Player checkSinglePlayerMatch(List<Player> players) throws CommandException {
            if (players.size() > 1) {
                throw new CommandException("More than one player found! Use @<name> for exact matching.");
            }
            return players.get(0);
        }
    }

    public static class LocationParser {

        /**
         * Match a world.
         * @param sender
         *
         * @param filter
         * @return
         * @throws com.sk89q.minecraft.util.commands.CommandException
         */
        public static World matchWorld(CommandSender sender, String filter) throws CommandException {
            List<World> worlds = CommandBook.server().getWorlds();

            // Handle special hash tag groups
            if (filter.charAt(0) == '#') {
                // #main for the main world
                if (filter.equalsIgnoreCase("#main")) {
                    return worlds.get(0);

                    // #normal for the first normal world
                } else if (filter.equalsIgnoreCase("#normal")) {
                    for (World world : worlds) {
                        if (world.getEnvironment() == World.Environment.NORMAL) {
                            return world;
                        }
                    }

                    throw new CommandException("No normal world found.");

                    // #nether for the first nether world
                } else if (filter.equalsIgnoreCase("#nether")) {
                    for (World world : worlds) {
                        if (world.getEnvironment() == World.Environment.NETHER) {
                            return world;
                        }
                    }

                    throw new CommandException("No nether world found.");

                    // #theend for the first end world
                } else if (filter.equalsIgnoreCase("#theend") || filter.equalsIgnoreCase("#end")) {
                    for (World world : worlds) {
                        if (world.getEnvironment() == World.Environment.THE_END) {
                            return world;
                        }
                    }

                    throw new CommandException("No end world found.");
                    // Handle getting a world from a player
                } else if (filter.matches("^#player$")) {
                    String parts[] = filter.split(":", 2);

                    // They didn't specify an argument for the player!
                    if (parts.length == 1) {
                        throw new CommandException("Argument expected for #player.");
                    }

                    return PlayerParser.matchPlayers(sender, parts[1]).iterator().next().getWorld();
                } else {
                    throw new CommandException("Invalid identifier '" + filter + "'.");
                }
            }

            for (World world : worlds) {
                if (world.getName().equals(filter)) {
                    return world;
                }
            }

            throw new CommandException("No world by that exact name found.");
        }

        /**
         * Match a target.
         *
         * @param source
         * @param filter
         * @return first result of matchLocations
         * @throws CommandException no matches found
         */
        public static Location matchLocation(CommandSender source, String filter)
                throws CommandException {

            return matchLocations(source, filter, true).get(0);
        }

        /**
         * Match multiple targets.
         *
         * @param source
         * @param filter
         * @return list of locations
         * @throws CommandException no matches found
         */
        public static List<Location> matchLocations(CommandSender source, String filter)
                throws CommandException {

            return matchLocations(source, filter, false);
        }

        private static List<Location> matchLocations(CommandSender source, String filter,
                                                     boolean strictMatching)
                throws CommandException {

            // Handle coordinates
            if (filter.matches("^[\\-0-9\\.]+,[\\-0-9\\.]+,[\\-0-9\\.]+(?:.+)?$")) {
                CommandBook.inst().checkPermission(source, "commandbook.locations.coords");

                String[] args = filter.split(":");
                String[] parts = args[0].split(",");
                double x, y, z;

                try {
                    x = Double.parseDouble(parts[0]);
                    y = Double.parseDouble(parts[1]);
                    z = Double.parseDouble(parts[2]);
                } catch (NumberFormatException e) {
                    throw new CommandException("Coordinates expected numbers!");
                }

                if (args.length > 1) {
                    return Lists.newArrayList(new Location(matchWorld(source, args[1]), x, y, z));
                } else {
                    Player player = checkPlayer(source);
                    return Lists.newArrayList(new Location(player.getWorld(), x, y, z));
                }

                // Handle special hash tag groups
            } else if (filter.charAt(0) == '#') {
                String[] args = filter.split(":");

                // Handle #world, which matches player of the same world as the
                // calling source
                if (args[0].equalsIgnoreCase("#spawn")) {
                    CommandBook.inst().checkPermission(source, "commandbook.spawn");
                    if (args.length > 1) {
                        return Lists.newArrayList(matchWorld(source, args[1]).getSpawnLocation());
                    } else {
                        Player sourcePlayer = checkPlayer(source);
                        return Lists.newArrayList(sourcePlayer.getLocation().getWorld().getSpawnLocation());
                    }

                    // Handle #target, which matches the player's target position
                } else if (args[0].equalsIgnoreCase("#target")) {
                    CommandBook.inst().checkPermission(source, "commandbook.locations.target");
                    Player player = checkPlayer(source);
                    Location playerLoc = player.getLocation();
                    Block targetBlock = player.getTargetBlock(null, 100);

                    if (targetBlock == null) {
                        throw new CommandException("Failed to find a block in your target!");
                    } else {
                        Location loc = targetBlock.getLocation();
                        playerLoc.setX(loc.getX());
                        playerLoc.setY(loc.getY());
                        playerLoc.setZ(loc.getZ());
                        return Lists.newArrayList(LocationUtil.findFreePosition(playerLoc));
                    }
                    // Handle #home and #warp, which matches a player's home or a warp point
                } else if (args[0].equalsIgnoreCase("#home")
                        || args[0].equalsIgnoreCase("#warp")) {
                    String type = args[0].substring(1);
                    CommandBook.inst().checkPermission(source, "commandbook.locations." + type);
                    LocationsComponent component = type.equalsIgnoreCase("warp")
                            ? CommandBook.inst().getComponentManager().getComponent(WarpsComponent.class)
                            : CommandBook.inst().getComponentManager().getComponent(HomesComponent.class);
                    if (component == null)  {
                        throw new CommandException("This type of location is not enabled!");
                    }
                    RootLocationManager<NamedLocation> manager = component.getManager();
                    if (args.length == 1) {
                        if (type.equalsIgnoreCase("warp")) {
                            throw new CommandException("Please specify a warp name.");
                        }
                        // source player home
                        Player ply = checkPlayer(source);
                        NamedLocation loc = manager.get(ply.getWorld(), ply.getName());
                        if (loc == null) {
                            throw new CommandException("You have not set your home yet.");
                        }
                        return Lists.newArrayList(loc.getLocation());
                    } else if (args.length == 2) {
                        if (source instanceof Player) {
                            Player player = (Player) source;
                            NamedLocation loc = manager.get(player.getWorld(), args[1]);
                            if (loc != null && !(loc.getCreatorName().equalsIgnoreCase(player.getName()))) {
                                CommandBook.inst().checkPermission(source, "commandbook.locations." + type + ".other");
                            }
                        }
                        return Lists.newArrayList(LocationUtil.getManagedLocation(manager, checkPlayer(source).getWorld(), args[1]));
                    } else if (args.length == 3) {
                        if (source instanceof Player) {
                            Player player = (Player) source;
                            NamedLocation loc = manager.get(matchWorld(source, args[2]), args[1]);
                            if (loc != null && !(loc.getCreatorName().equalsIgnoreCase(player.getName()))) {
                                CommandBook.inst().checkPermission(source, "commandbook.locations." + type + ".other");
                            }
                        }
                        return Lists.newArrayList(LocationUtil.getManagedLocation(manager, matchWorld(source, args[2]), args[1]));
                    }
                    // Handle #me, which is for when a location argument is required
                } else if (args[0].equalsIgnoreCase("#me")) {
                    return Lists.newArrayList(checkPlayer(source).getLocation());
                } else {
                    throw new CommandException("Invalid group '" + filter + "'.");
                }
            }

            List<Player> players;

            if (strictMatching) {
                players = PlayerParser.matchPlayerNames(source, filter);
            } else {
                players = PlayerParser.matchPlayers(source, filter);
            }

            // Check to see if there were any matches
            PlayerParser.checkPlayerMatch(players);

            List<Location> locations = new ArrayList<Location>();
            for (Player player : players) {
                locations.add(player.getLocation());
            }
            return locations;
        }
    }
}
TOP

Related Classes of com.sk89q.commandbook.util.InputUtil$LocationParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.