Package com.sk89q.commandbook.locations

Source Code of com.sk89q.commandbook.locations.TeleportComponent$Commands

/*
* CommandBook
* Copyright (C) 2011 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.sk89q.commandbook.locations;

import com.google.common.collect.Lists;
import com.sk89q.commandbook.CommandBook;
import com.sk89q.commandbook.session.SessionComponent;
import com.sk89q.commandbook.session.SessionFactory;
import com.sk89q.commandbook.util.ChatUtil;
import com.sk89q.commandbook.util.InputUtil;
import com.sk89q.commandbook.util.LocationUtil;
import com.sk89q.commandbook.util.entity.player.PlayerUtil;
import com.sk89q.commandbook.util.entity.player.iterators.TeleportPlayerIterator;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.zachsthings.libcomponents.ComponentInformation;
import com.zachsthings.libcomponents.Depend;
import com.zachsthings.libcomponents.InjectComponent;
import com.zachsthings.libcomponents.bukkit.BasePlugin;
import com.zachsthings.libcomponents.bukkit.BukkitComponent;
import com.zachsthings.libcomponents.config.ConfigurationBase;
import com.zachsthings.libcomponents.config.Setting;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;

@ComponentInformation(friendlyName = "Teleports", desc = "Teleport-related commands")
@Depend(components = SessionComponent.class)
public class TeleportComponent extends BukkitComponent implements Listener {

    @InjectComponent private SessionComponent sessions;
    private LocalConfiguration config;

    @Override
    public void enable() {
        CommandBook.registerEvents(this);
        registerCommands(Commands.class);
        config = configure(new LocalConfiguration());
        sessions.registerSessionFactory(TeleportSession.class, new SessionFactory<TeleportSession>() {
            @Override
            public TeleportSession createSession(CommandSender user) {
                return new TeleportSession(TeleportComponent.this);
            }
        });
    }

    @Override
    public void reload() {
        configure(config);
    }

    public LocalConfiguration getConfig() {
        return config;
    }

    public static class LocalConfiguration extends ConfigurationBase {
        @Setting("call-message.sender") public String callMessageSender = "`yTeleport request sent.";
        @Setting("call-message.target") public String callMessageTarget =
                "`c**TELEPORT** %cname%`c requests a teleport! Use /bring <name> to accept.";
        @Setting("call-message.too-soon") public String callMessageTooSoon = "Wait a bit before asking again.";
        @Setting("bring-message.sender") public String bringMessageSender = "`yPlayer teleported.";
        @Setting("bring-message.target") public String bringMessageTarget =
                "`yYour teleport request to %cname%`y was accepted.";
        @Setting("bring-message.no-perm") public String bringMessageNoPerm = "That person didn't request a " +
                "teleport (recently) and you don't have permission to teleport anyone.";
    }

    // -- Event handlers

    @EventHandler
    public void onRespawn(PlayerRespawnEvent event) {
        sessions.getSession(TeleportSession.class, event.getPlayer()).rememberLocation(event.getPlayer());
    }

    @EventHandler
    public void onTeleport(PlayerTeleportEvent event) {

        Location loc = event.getTo();
        Player player = event.getPlayer();
        if (event.isCancelled()) {
            return;
        }

        Location ignored = sessions.getSession(TeleportSession.class, player).getIgnoreLocation();
        if (ignored != null) {
            if (ignored.getWorld().equals(loc.getWorld()) && ignored.distanceSquared(loc) <= 2) {
                return;
            } else {
                sessions.getSession(TeleportSession.class, player).setIgnoreLocation(null);
            }
        }
        sessions.getSession(TeleportSession.class, player).rememberLocation(event.getPlayer());
    }

    public class Commands {

        @Command(aliases = {"teleport", "tp"}, usage = "[target] <destination>",
                desc = "Teleport to a location",
                flags = "s", min = 1, max = 4)
        @CommandPermissions({"commandbook.teleport"})
        public void teleport(CommandContext args, CommandSender sender) throws CommandException {

            Iterable<Player> targets;
            final Location loc;
            boolean[] relative = new boolean[]{false, false, false};

            /*
            1. /tp playerTarget x y z (4 args) - VANILLA

            2. /tp x y z (3 args)
            3. /tp playerTarget x z (3 args) - NOT SUPPORTED

            4. /tp playerTarget x,y,z (2 args)
            5. /tp playerTarget playerDest (2 args) - VANILLA
            6. /tp x z (2 args) - NOT SUPPORTED

            7. /tp x,y,z (1 arg)
            8. /tp playerDest (1 arg) - VANILLA
             */
            // TODO: reduce code duplication, currently just trying to catch every case
            if (args.argsLength() == 1) {
                loc = InputUtil.LocationParser.matchLocation(sender, args.getString(0)); // matches both #7 and #8
                // go to the center of the block if we're on the edge
                if (loc.getX() == loc.getBlockX()) loc.add(0.5, 0, 0);
                if (loc.getZ() == loc.getBlockZ()) loc.add(0, 0, 0.5);
                targets = Lists.newArrayList(PlayerUtil.checkPlayer(sender));
            } else if (args.argsLength() == 2) {
                targets = InputUtil.PlayerParser.matchPlayers(sender, args.getString(0));
                loc = InputUtil.LocationParser.matchLocation(sender, args.getString(1)); // matches both #4 and #5
                if (loc.getX() == loc.getBlockX()) loc.add(0.5, 0, 0);
                if (loc.getZ() == loc.getBlockZ()) loc.add(0, 0, 0.5);
            } else if (args.argsLength() == 3) {
                // matches #2 - can only be used by a player
                targets = Lists.newArrayList(PlayerUtil.checkPlayer(sender));
                double x = args.getDouble(0);
                double y = args.getDouble(1);
                double z = args.getDouble(2);
                loc = new Location((PlayerUtil.checkPlayer(sender)).getWorld(), x, y, z);
                if (loc.getX() == loc.getBlockX()) loc.add(0.5, 0, 0);
                if (loc.getZ() == loc.getBlockZ()) loc.add(0, 0, 0.5);
                // check location permission
                CommandBook.inst().checkPermission(sender, loc.getWorld(), "commandbook.locations.coords");
            } else if (args.argsLength() == 4) {
                targets = InputUtil.PlayerParser.matchPlayers(sender, args.getString(0)); // matches #1
                // support relative location (~5 -> current coord + 5)
                String xArg = args.getString(1);
                String yArg = args.getString(2);
                String zArg = args.getString(3);
                CommandBook.inst().checkPermission(sender, "commandbook.locations.coords");
                if (xArg.startsWith("~")) relative[0] = true;
                if (yArg.startsWith("~")) relative[1] = true;
                if (zArg.startsWith("~")) relative[2] = true;
                if (relative[0] || relative[1] || relative[2]) {
                    CommandBook.inst().checkPermission(sender, "commandbook.locations.coords.relative");
                }
                double x = Double.parseDouble(xArg.replace("~", ""));
                double y = Double.parseDouble(yArg.replace("~", ""));
                double z = Double.parseDouble(zArg.replace("~", ""));
                World world;
                try { // for CommandBlock support
                    world = LocationUtil.extractWorld(sender);
                } catch (Throwable t) {
                    if (sender instanceof Player) {
                        world = ((Player) sender).getWorld();
                    } else {
                        world = BasePlugin.server().getWorlds().get(0);
                    }
                }
                loc = new Location(world, x, y, z);
                if (loc.getX() == loc.getBlockX()) loc.add(0.5, 0, 0);
                if (loc.getZ() == loc.getBlockZ()) loc.add(0, 0, 0.5);

            } else { // this can't actually happen unless someone constructs their own CommandContext
                throw new CommandException("Invalid number of args.");
            }

            boolean hasTeleOtherCurrent = CommandBook.inst().hasPermission(sender, "commandbook.teleport.other");
            boolean hasTeleOtherTo = CommandBook.inst().hasPermission(sender, loc.getWorld(), "commandbook.teleport.other");

            for (Player target : targets) {
                if (target != sender) {
                    // If any of the targets is not the sender, we need to check .other
                    // we must check for the from (target's world), current (sender's world),
                    // and to (target location's world).
                    if (!loc.getWorld().equals(target.getWorld())) {
                        CommandBook.inst().checkPermission(sender, target.getWorld(), "commandbook.teleport.other");
                    }

                    // If either check has failed, check both to get the proper exception response
                    if (!hasTeleOtherCurrent || !hasTeleOtherTo) {
                        CommandBook.inst().checkPermission(sender, "commandbook.teleport.other");
                        CommandBook.inst().checkPermission(sender, loc.getWorld(), "commandbook.teleport.other");
                    }
                } else {
                    // If the target is the sender, just check the to (target location's world)
                    // the current has already been checked
                    CommandBook.inst().checkPermission(sender, loc.getWorld(), "commandbook.teleport");
                }
            }

            (new TeleportPlayerIterator(sender, loc, args.hasFlag('s'), relative)).iterate(targets);
        }

        @Command(aliases = {"call", "tpa"}, usage = "<target>", desc = "Request a teleport", min = 1, max = 1)
        @CommandPermissions({"commandbook.call"})
        public void requestTeleport(CommandContext args, CommandSender sender) throws CommandException {
            Player player = PlayerUtil.checkPlayer(sender);
            Player target = InputUtil.PlayerParser.matchSinglePlayer(sender, args.getString(0));

            CommandBook.inst().checkPermission(sender, target.getWorld(), "commandbook.call");

            sessions.getSession(TeleportSession.class, player).checkLastTeleportRequest(target);
            sessions.getSession(TeleportSession.class, target).addBringable(player);

            String senderMessage = ChatUtil.replaceColorMacros(
                    ChatUtil.replaceMacros(sender, config.callMessageSender))
                    .replaceAll("%ctarget%", ChatUtil.toColoredName(target, null))
                    .replaceAll("%target%", ChatUtil.toName(target));
            String targetMessage = ChatUtil.replaceColorMacros(
                    ChatUtil.replaceMacros(sender, config.callMessageTarget))
                    .replaceAll("%ctarget%", ChatUtil.toColoredName(target, null))
                    .replaceAll("%target%", ChatUtil.toName(target));
            sender.sendMessage(senderMessage);
            target.sendMessage(targetMessage);
        }

        @Command(aliases = {"bring", "tphere", "grab", "g"}, usage = "<target>", desc = "Bring a player to you", min = 1, max = 1)
        public void bring(CommandContext args, CommandSender sender) throws CommandException {
            Player player = PlayerUtil.checkPlayer(sender);
            Player target = null;

            // If we have a single player match, check that for bringable. If we do not,
            // then check to see if the player can bring multiple players in his current
            // world. If that is the case then allow this to continue.
            try {
                target = InputUtil.PlayerParser.matchSinglePlayer(sender, args.getString(0));
            } catch (CommandException ex) {
                if (!CommandBook.inst().hasPermission(sender, "commandbook.teleport.other")) {
                    // There was not a single player match, and the player does not have
                    // permission to teleport players in his/her current world.
                    throw ex;
                }
            }

            if (target != null) {
                if (sessions.getSession(TeleportSession.class, player).isBringable(target)) {
                    final String senderMessage = ChatUtil.replaceColorMacros(
                            ChatUtil.replaceMacros(sender, config.bringMessageSender))
                            .replaceAll("%ctarget%", ChatUtil.toColoredName(target, null))
                            .replaceAll("%target%", target.getName());
                    final String targetMessage = ChatUtil.replaceColorMacros(
                            ChatUtil.replaceMacros(sender, config.bringMessageTarget))
                            .replaceAll("%ctarget%", ChatUtil.toColoredName(target, null))
                            .replaceAll("%target%", target.getName());

                    (new TeleportPlayerIterator(sender, player.getLocation()) {
                        @Override
                        public void onVictim(CommandSender sender, Player player) {
                            player.sendMessage(targetMessage);
                        }

                        @Override
                        public void onInformMany(CommandSender sender, int affected) {
                            sender.sendMessage(senderMessage);
                        }
                    }).iterate(Lists.newArrayList(target));
                    return;
                } else if (!CommandBook.inst().hasPermission(sender, "commandbook.teleport.other")) {
                    // There was a single player match, but, the target was not bringable, and the player
                    // does not have permission to teleport players in his/her current world.
                    throw new CommandException(config.bringMessageNoPerm);
                }
            }

            Location loc = player.getLocation();

            // There was not a single player match, or that single player match did not request
            // to be brought. The player does have permission to teleport players in his/her
            // current world. However, we're now teleporting in targets from potentially different worlds,
            // and we should ensure that the sender has permission to teleport players in those worlds.
            Iterable<Player> targets = InputUtil.PlayerParser.matchPlayers(sender, args.getString(0));
            for (Player aTarget : targets) {
                // We have already checked the from and current locations, we must now check the to if the world does not match
                if (!loc.getWorld().equals(aTarget.getWorld())) {
                    CommandBook.inst().checkPermission(sender, aTarget.getWorld(), "commandbook.teleport.other");
                }
            }

            (new TeleportPlayerIterator(sender, loc)).iterate(targets);
        }

        @Command(aliases = {"put", "place"}, usage = "<target>",
                desc = "Put a player at where you are looking", min = 1, max = 1)
        @CommandPermissions({"commandbook.teleport.other"})
        public void put(CommandContext args, CommandSender sender) throws CommandException {
            Iterable<Player> targets = InputUtil.PlayerParser.matchPlayers(sender, args.getString(0));
            Location loc = InputUtil.LocationParser.matchLocation(sender, "#target");

            for (Player target : targets) {
                // We have already checked the from and current locations, we must now check the to if the world does not match
                if (!loc.getWorld().equals(target.getWorld())) {
                    CommandBook.inst().checkPermission(sender, target.getWorld(), "commandbook.teleport.other");
                }
            }

            (new TeleportPlayerIterator(sender, loc)).iterate(targets);
        }

        @Command(aliases = {"return", "ret"}, usage = "[player]", desc = "Teleport back to your last location", min = 0, max = 1)
        @CommandPermissions({"commandbook.return"})
        public void ret(CommandContext args, CommandSender sender) throws CommandException {
            Player player;
            if (args.argsLength() > 0) {
                player = InputUtil.PlayerParser.matchSinglePlayer(sender, args.getString(0));
                if (player != sender) {
                    CommandBook.inst().checkPermission(sender, "commandbook.return.other");
                }
            } else {
                player = PlayerUtil.checkPlayer(sender);
            }
            Location lastLoc = sessions.getSession(TeleportSession.class, player).popLastLocation();

            if (lastLoc != null) {
                sessions.getSession(TeleportSession.class, player).setIgnoreLocation(lastLoc);
                lastLoc.getChunk().load(true);
                (new TeleportPlayerIterator(sender, lastLoc) {
                    @Override
                    public void onCaller(Player player) {
                        sender.sendMessage(ChatColor.YELLOW + "You've been returned.");
                    }

                    @Override
                    public void onVictim(CommandSender sender, Player player) {
                        player.sendMessage(ChatColor.YELLOW + "You've been returned by "
                                + ChatUtil.toColoredName(sender, ChatColor.YELLOW) + ".");
                    }

                    @Override
                    public void onInformMany(CommandSender sender, int affected) {
                        sender.sendMessage(ChatColor.YELLOW.toString() + affected + " returned.");
                    }
                }).iterate(Lists.newArrayList(player));
            } else {
                sender.sendMessage(ChatColor.RED + "There's no past location in your history.");
            }
        }
    }
}
TOP

Related Classes of com.sk89q.commandbook.locations.TeleportComponent$Commands

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.