# Source code
source: package: co.aikar.commands, class: BukkitCommandContexts

    001/*
    002 * Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License
    003 *
    004 *  Permission is hereby granted, free of charge, to any person obtaining
    005 *  a copy of this software and associated documentation files (the
    006 *  "Software"), to deal in the Software without restriction, including
    007 *  without limitation the rights to use, copy, modify, merge, publish,
    008 *  distribute, sublicense, and/or sell copies of the Software, and to
    009 *  permit persons to whom the Software is furnished to do so, subject to
    010 *  the following conditions:
    011 *
    012 *  The above copyright notice and this permission notice shall be
    013 *  included in all copies or substantial portions of the Software.
    014 *
    015 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    016 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    017 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    018 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    019 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    020 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    021 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    022 */
    023
    024package co.aikar.commands;
    025
    026import co.aikar.commands.bukkit.contexts.OnlinePlayer;
    027import org.bukkit.Bukkit;
    028import org.bukkit.ChatColor;
    029import org.bukkit.Location;
    030import org.bukkit.OfflinePlayer;
    031import org.bukkit.World;
    032import org.bukkit.command.BlockCommandSender;
    033import org.bukkit.command.CommandSender;
    034import org.bukkit.entity.Entity;
    035import org.bukkit.entity.Player;
    036import org.bukkit.inventory.PlayerInventory;
    037import org.jetbrains.annotations.Contract;
    038
    039import java.util.HashSet;
    040import java.util.Set;
    041import java.util.UUID;
    042import java.util.regex.Pattern;
    043import java.util.stream.Collectors;
    044import java.util.stream.Stream;
    045
    046import static co.aikar.commands.ACFBukkitUtil.isValidName;
    047
    048@SuppressWarnings("WeakerAccess")
    049public class BukkitCommandContexts extends CommandContexts<BukkitCommandExecutionContext> {
    050
    051    public BukkitCommandContexts(BukkitCommandManager manager) {
    052        super(manager);
    053
    054        registerContext(OnlinePlayer.class, c -> getOnlinePlayer(c.getIssuer(), c.popFirstArg(), false));
    055        registerContext(co.aikar.commands.contexts.OnlinePlayer.class, c -> {
    056            OnlinePlayer onlinePlayer = getOnlinePlayer(c.getIssuer(), c.popFirstArg(), false);
    057            return new co.aikar.commands.contexts.OnlinePlayer(onlinePlayer.getPlayer());
    058        });
    059        registerContext(OnlinePlayer[].class, (c) -> {
    060            BukkitCommandIssuer issuer = c.getIssuer();
    061            final String search = c.popFirstArg();
    062            boolean allowMissing = c.hasFlag("allowmissing");
    063            Set<OnlinePlayer> players = new HashSet<>();
    064            Pattern split = ACFPatterns.COMMA;
    065            String splitter = c.getFlagValue("splitter", (String) null);
    066            if (splitter != null) {
    067                split = Pattern.compile(Pattern.quote(splitter));
    068            }
    069            for (String lookup : split.split(search)) {
    070                OnlinePlayer player = getOnlinePlayer(issuer, lookup, allowMissing);
    071                if (player != null) {
    072                    players.add(player);
    073                }
    074            }
    075            if (players.isEmpty() && !c.hasFlag("allowempty")) {
    076                issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER,
    077                        "{search}", search);
    078
    079                throw new InvalidCommandArgument(false);
    080            }
    081            return players.toArray(new OnlinePlayer[players.size()]);
    082        });
    083        registerIssuerAwareContext(World.class, (c) -> {
    084            String firstArg = c.getFirstArg();
    085            World world = firstArg != null ? Bukkit.getWorld(firstArg) : null;
    086            if (world != null) {
    087                c.popFirstArg();
    088            }
    089            if (world == null && c.getSender() instanceof Player) {
    090                world = ((Entity) c.getSender()).getWorld();
    091            }
    092            if (world == null) {
    093                throw new InvalidCommandArgument(MinecraftMessageKeys.INVALID_WORLD);
    094            }
    095            return world;
    096        });
    097        registerIssuerAwareContext(CommandSender.class, BukkitCommandExecutionContext::getSender);
    098        registerIssuerAwareContext(Player.class, (c) -> {
    099            boolean isOptional = c.isOptional();
    100            CommandSender sender = c.getSender();
    101            boolean isPlayerSender = sender instanceof Player;
    102            if (!c.hasFlag("other")) {
    103                Player player = isPlayerSender ? (Player) sender : null;
    104                if (player == null && !isOptional) {
    105                    throw new InvalidCommandArgument(MessageKeys.NOT_ALLOWED_ON_CONSOLE, false);
    106                }
    107                PlayerInventory inventory = player != null ? player.getInventory() : null;
    108                if (inventory != null && c.hasFlag("itemheld") && !ACFBukkitUtil.isValidItem(inventory.getItem(inventory.getHeldItemSlot()))) {
    109                    throw new InvalidCommandArgument(MinecraftMessageKeys.YOU_MUST_BE_HOLDING_ITEM, false);
    110                }
    111                return player;
    112            } else {
    113                String arg = c.popFirstArg();
    114                if (arg == null && isOptional) {
    115                    if (c.hasFlag("defaultself")) {
    116                        if (isPlayerSender) {
    117                            return (Player) sender;
    118                        } else {
    119                            throw new InvalidCommandArgument(MessageKeys.NOT_ALLOWED_ON_CONSOLE, false);
    120                        }
    121                    } else {
    122                        return null;
    123                    }
    124                } else if (arg == null) {
    125                    throw new InvalidCommandArgument();
    126                }
    127
    128                OnlinePlayer onlinePlayer = getOnlinePlayer(c.getIssuer(), arg, false);
    129                return onlinePlayer.getPlayer();
    130            }
    131        });
    132        registerContext(OfflinePlayer.class, c -> {
    133            String name = c.popFirstArg();
    134            OfflinePlayer offlinePlayer;
    135            if (c.hasFlag("uuid")) {
    136                UUID uuid;
    137                try {
    138                    uuid = UUID.fromString(name);
    139                } catch (IllegalArgumentException e) {
    140                    throw new InvalidCommandArgument(MinecraftMessageKeys.NO_PLAYER_FOUND_OFFLINE,
    141                            "{search}", name);
    142                }
    143                offlinePlayer = Bukkit.getOfflinePlayer(uuid);
    144            } else {
    145                offlinePlayer = Bukkit.getOfflinePlayer(name);
    146            }
    147            if (offlinePlayer == null || (!offlinePlayer.hasPlayedBefore() && !offlinePlayer.isOnline())) {
    148                if (!c.hasFlag("uuid") && !manager.isValidName(name)) {
    149                    throw new InvalidCommandArgument(MinecraftMessageKeys.IS_NOT_A_VALID_NAME, "{name}", name);
    150                }
    151                throw new InvalidCommandArgument(MinecraftMessageKeys.NO_PLAYER_FOUND_OFFLINE,
    152                        "{search}", name);
    153            }
    154            return offlinePlayer;
    155        });
    156        registerContext(ChatColor.class, c -> {
    157            String first = c.popFirstArg();
    158            Stream<ChatColor> colors = Stream.of(ChatColor.values());
    159            if (c.hasFlag("colorsonly")) {
    160                colors = colors.filter(color -> color.ordinal() <= 0xF);
    161            }
    162            String filter = c.getFlagValue("filter", (String) null);
    163            if (filter != null) {
    164                filter = ACFUtil.simplifyString(filter);
    165                String finalFilter = filter;
    166                colors = colors.filter(color -> finalFilter.equals(ACFUtil.simplifyString(color.name())));
    167            }
    168
    169            ChatColor match = ACFUtil.simpleMatch(ChatColor.class, first);
    170            if (match == null) {
    171                String valid = colors
    172                        .map(color -> "<c2>" + ACFUtil.simplifyString(color.name()) + "</c2>")
    173                        .collect(Collectors.joining("<c1>,</c1> "));
    174
    175                throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, "{valid}", valid);
    176            }
    177            return match;
    178        });
    179        registerContext(Location.class, c -> {
    180            String input = c.popFirstArg();
    181            CommandSender sender = c.getSender();
    182            String[] split = ACFPatterns.COLON.split(input, 2);
    183            if (split.length == 0) {
    184                throw new InvalidCommandArgument(true);
    185            }
    186            if (split.length < 2 && !(sender instanceof Player) && !(sender instanceof BlockCommandSender)) {
    187                throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_PLEASE_SPECIFY_WORLD);
    188            }
    189            final String world;
    190            final String rest;
    191            Location sourceLoc = null;
    192            if (split.length == 2) {
    193                world = split[0];
    194                rest = split[1];
    195            } else if (sender instanceof Player) {
    196                sourceLoc = ((Player) sender).getLocation();
    197                world = sourceLoc.getWorld().getName();
    198                rest = split[0];
    199            } else if (sender instanceof BlockCommandSender) {
    200                sourceLoc = ((BlockCommandSender) sender).getBlock().getLocation();
    201                world = sourceLoc.getWorld().getName();
    202                rest = split[0];
    203            } else {
    204                throw new InvalidCommandArgument(true);
    205            }
    206
    207            boolean rel = rest.startsWith("~");
    208            split = ACFPatterns.COMMA.split(rel ? rest.substring(1) : rest);
    209            if (split.length < 3) {
    210                throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_PLEASE_SPECIFY_XYZ);
    211            }
    212
    213            Double x = ACFUtil.parseDouble(split[0], rel ? 0.0D : null);
    214            Double y = ACFUtil.parseDouble(split[1], rel ? 0.0D : null);
    215            Double z = ACFUtil.parseDouble(split[2], rel ? 0.0D : null);
    216
    217            if (sourceLoc != null && rel) {
    218                x += sourceLoc.getX();
    219                y += sourceLoc.getY();
    220                z += sourceLoc.getZ();
    221            } else if (rel) {
    222                throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_CONSOLE_NOT_RELATIVE);
    223            }
    224
    225            if (x == null || y == null || z == null) {
    226                throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_PLEASE_SPECIFY_XYZ);
    227            }
    228
    229            World worldObj = Bukkit.getWorld(world);
    230            if (worldObj == null) {
    231                throw new InvalidCommandArgument(MinecraftMessageKeys.INVALID_WORLD);
    232            }
    233
    234            if (split.length >= 5) {
    235                Float yaw = ACFUtil.parseFloat(split[3]);
    236                Float pitch = ACFUtil.parseFloat(split[4]);
    237
    238                if (pitch == null || yaw == null) {
    239                    throw new InvalidCommandArgument(MinecraftMessageKeys.LOCATION_PLEASE_SPECIFY_XYZ);
    240                }
    241                return new Location(worldObj, x, y, z, yaw, pitch);
    242            } else {
    243                return new Location(worldObj, x, y, z);
    244            }
    245        });
    246
    247        if (manager.mcMinorVersion >= 12) {
    248            BukkitCommandContexts_1_12.register(this);
    249        }
    250    }
    251
    252    @Contract("_,_,false -> !null")
    253    OnlinePlayer getOnlinePlayer(BukkitCommandIssuer issuer, String lookup, boolean allowMissing) throws InvalidCommandArgument {
    254        Player player = ACFBukkitUtil.findPlayerSmart(issuer, lookup);
    255        //noinspection Duplicates
    256        if (player == null) {
    257            if (allowMissing) {
    258                return null;
    259            }
    260            throw new InvalidCommandArgument(false);
    261        }
    262        return new OnlinePlayer(player);
    263    }
    264}