Package com.sk89q.craftbook.mechanics

Source Code of com.sk89q.craftbook.mechanics.Chair

package com.sk89q.craftbook.mechanics;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.material.Directional;
import org.bukkit.util.Vector;

import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.ListenerOptions;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import com.sk89q.craftbook.AbstractCraftBookMechanic;
import com.sk89q.craftbook.LocalPlayer;
import com.sk89q.craftbook.bukkit.CraftBookPlugin;
import com.sk89q.craftbook.util.BlockUtil;
import com.sk89q.craftbook.util.EventUtil;
import com.sk89q.craftbook.util.ItemInfo;
import com.sk89q.craftbook.util.LocationUtil;
import com.sk89q.craftbook.util.ProtectionUtil;
import com.sk89q.craftbook.util.SignUtil;
import com.sk89q.craftbook.util.Tuple2;
import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.worldedit.blocks.BlockType;


/**
* @author Me4502
*/
public class Chair extends AbstractCraftBookMechanic {

    public Map<String, Tuple2<Entity, Block>> chairs;

    public void addChair(final Player player, Block block) {

        Entity ar = null;
        if(chairs.containsKey(player.getName()))
            ar = chairs.get(player.getName()).a;
        boolean isNew = false;

        if(ar == null || !ar.isValid() || ar.isDead() || !ar.getLocation().getBlock().equals(block)) {
            if(ar != null && !ar.getLocation().getBlock().equals(block))
                ar.remove();
            ar = block.getWorld().spawnArrow(BlockUtil.getBlockCentre(block).subtract(0, 0.5, 0), new Vector(0,-0.1,0), 0.01f, 0);
            isNew = true;
        }
        if (!chairs.containsKey(player.getName()))
            CraftBookPlugin.inst().wrapPlayer(player).print("mech.chairs.sit");
        // Attach the player to said arrow.
        final Entity far = ar;
        if(ar.isEmpty() && isNew) {
            Bukkit.getScheduler().runTask(CraftBookPlugin.inst(), new Runnable() {
                @Override
                public void run () {
                    far.setPassenger(player);
                }
            });
        } else if (ar.isEmpty()) {
            removeChair(player);
            return;
        }

        ar.setTicksLived(1);

        chairs.put(player.getName(), new Tuple2<Entity, Block>(ar, block));
    }

    public void removeChair(final Player player) {

        CraftBookPlugin.inst().wrapPlayer(player).print("mech.chairs.stand");
        final Entity ent = chairs.get(player.getName()).a;
        final Block block = chairs.get(player.getName()).b;
        if(ent != null) {
            player.eject();
            player.teleport(block.getLocation().add(0, 1, 0));
            ent.remove();
            Bukkit.getScheduler().runTaskLater(CraftBookPlugin.inst(), new Runnable() {
                @Override
                public void run () {
                    player.teleport(block.getLocation().add(0, 1, 0));
                    player.setSneaking(false);
                }
            }, 1L);
        }
        chairs.remove(player.getName());
    }

    public boolean hasSign(Block block, List<Location> searched, Block original) {

        boolean found = false;

        for (BlockFace face : LocationUtil.getDirectFaces()) {
            Block otherBlock = block.getRelative(face);

            if(searched.contains(otherBlock.getLocation())) continue;
            searched.add(otherBlock.getLocation());

            if (found) break;

            if(block.getLocation().distanceSquared(original.getLocation()) > Math.pow(chairMaxDistance, 2)) continue;

            if (SignUtil.isSign(otherBlock) && SignUtil.getFront(otherBlock) == face) {
                found = true;
                break;
            }

            if (BlockUtil.areBlocksIdentical(block, otherBlock))
                found = hasSign(otherBlock, searched, original);
        }

        return found;
    }

    public Tuple2<Entity, Block> getChair(Player player) {

        return chairs.get(player.getName());
    }

    public boolean hasChair(Player player) {

        return chairs.containsKey(player.getName());
    }

    public boolean hasChair(Block player) {

        for(Tuple2<Entity, Block> tup : chairs.values())
            if(player.equals(tup.b))
                return true;

        return false;
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onBlockBreak(BlockBreakEvent event) {

        if(!EventUtil.passesFilter(event)) return;

        if (hasChair(event.getBlock())) {
            event.setCancelled(true);
            CraftBookPlugin.inst().wrapPlayer(event.getPlayer()).printError("mech.chairs.in-use");
        }
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onRightClick(PlayerInteractEvent event) {

        if (!EventUtil.passesFilter(event))
            return;

        if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
        if (event.getClickedBlock() == null || !chairBlocks.contains(new ItemInfo(event.getClickedBlock())))
            return;

        LocalPlayer lplayer = CraftBookPlugin.inst().wrapPlayer(event.getPlayer());
        if (lplayer.isSneaking()) return;
        Player player = event.getPlayer();

        // Now everything looks good, continue;
        if (chairAllowHeldBlock || !lplayer.isHoldingBlock() && lplayer.getHeldItemInfo().getType() != Material.SIGN || lplayer.getHeldItemInfo().getType() == Material.AIR) {
            if (chairRequireSign && !hasSign(event.getClickedBlock(), new ArrayList<Location>(), event.getClickedBlock()))
                return;
            if (!lplayer.hasPermission("craftbook.mech.chair.use")) {
                if(CraftBookPlugin.inst().getConfiguration().showPermissionMessages)
                    lplayer.printError("mech.use-permission");
                return;
            }
            if(!ProtectionUtil.canUse(event.getPlayer(), event.getClickedBlock().getLocation(), event.getBlockFace(), event.getAction())) {
                if(CraftBookPlugin.inst().getConfiguration().showPermissionMessages)
                    lplayer.printError("area.use-permissions");
                return;
            }

            if(event.getPlayer().getLocation().distanceSquared(event.getClickedBlock().getLocation().add(0.5, 0.5, 0.5)) > Math.pow(chairMaxClickRadius, 2)) {
                lplayer.printError("mech.chairs.too-far");
                return;
            }

            if (hasChair(player.getPlayer())) { // Stand
                removeChair(player.getPlayer());
            } else { // Sit
                if (hasChair(event.getClickedBlock())) {
                    lplayer.print("mech.chairs.in-use");
                    return;
                }
                if (BlockType.canPassThrough(event.getClickedBlock().getRelative(0, -1, 0).getTypeId())) {

                    lplayer.printError("mech.chairs.floating");
                    return;
                } else if(!BlockType.canPassThrough(event.getClickedBlock().getRelative(0, 1, 0).getTypeId())) {

                    lplayer.printError("mech.chairs.obstructed");
                    return;
                }

                Location chairLoc = event.getClickedBlock().getLocation().add(0.5,0,0.5);

                if(chairFacing && event.getClickedBlock().getState().getData() instanceof Directional) {

                    BlockFace direction = ((Directional) event.getClickedBlock().getState().getData()).getFacing();

                    double dx = direction.getModX();
                    double dy = direction.getModY();
                    double dz = direction.getModZ();

                    if (dx != 0) {
                        if (dx < 0)
                            chairLoc.setYaw((float) (1.5 * Math.PI));
                        else
                            chairLoc.setYaw((float) (0.5 * Math.PI));
                        chairLoc.setYaw((float)(chairLoc.getYaw() - Math.atan(dz / dx)));
                    } else if (dz < 0)
                        chairLoc.setYaw((float) Math.PI);

                    double dxz = Math.sqrt(Math.pow(dx, 2) + Math.pow(dz, 2));

                    chairLoc.setPitch((float) -Math.atan(dy / dxz));

                    chairLoc.setYaw(-chairLoc.getYaw() * 180f / (float) Math.PI);
                    chairLoc.setPitch(chairLoc.getPitch() * 180f / (float) Math.PI);
                } else {
                    chairLoc.setPitch(player.getPlayer().getLocation().getPitch());
                    chairLoc.setYaw(player.getPlayer().getLocation().getYaw());
                }
                player.getPlayer().teleport(chairLoc);
                addChair(player.getPlayer(), event.getClickedBlock());
                event.setCancelled(true);
            }
        }
    }

    public class ChairChecker implements Runnable {

        @Override
        public void run() {

            for (String pl : chairs.keySet()) {
                Player p = Bukkit.getPlayerExact(pl);
                if (p == null  || p.isDead()) {
                    chairs.remove(pl);
                    continue;
                }

                if (!chairBlocks.contains(new ItemInfo(getChair(p).b)) || !p.getWorld().equals(getChair(p).b.getWorld()) || LocationUtil.getDistanceSquared(p.getLocation(), getChair(p).b.getLocation()) > 1.5)
                    removeChair(p);
                else {
                    addChair(p, getChair(p).b); // For any new players.

                    if (chairHealth && p.getHealth() < p.getMaxHealth())
                        p.setHealth(Math.min(p.getHealth() + chairHealAmount, p.getMaxHealth()));
                    if (p.getExhaustion() > -20d) p.setExhaustion((float)(p.getExhaustion() - 0.1d));
                }
            }
        }
    }

    @Override
    public boolean enable () {

        chairs = new ConcurrentHashMap<String, Tuple2<Entity, Block>>();

        Bukkit.getScheduler().runTaskTimer(CraftBookPlugin.inst(), new ChairChecker(), 20L, 20L);

        try {
            Class.forName("com.comphenix.protocol.events.PacketListener");
            ProtocolLibrary.getProtocolManager().getAsynchronousManager().registerAsyncHandler(new PacketAdapter(PacketAdapter.params(CraftBookPlugin.inst(), PacketType.Play.Client.STEER_VEHICLE).clientSide().listenerPriority(ListenerPriority.HIGHEST).options(ListenerOptions.INTERCEPT_INPUT_BUFFER)) {
                @Override
                public void onPacketReceiving(PacketEvent e) {
                    if (!e.isCancelled()) {
                        Player player = e.getPlayer();
                        if (e.getPacket().getBooleans().getValues().get(1))
                            if(hasChair(player))
                                removeChair(player);
                    }
                }
            }).syncStart();

            ProtocolLibrary.getProtocolManager().getAsynchronousManager().registerAsyncHandler(new PacketAdapter(PacketAdapter.params(CraftBookPlugin.inst(), PacketType.Play.Client.ENTITY_ACTION).clientSide().listenerPriority(ListenerPriority.HIGHEST).options(ListenerOptions.INTERCEPT_INPUT_BUFFER)) {
                @Override
                public void onPacketReceiving(PacketEvent e) {
                    if (!e.isCancelled()) {
                        Player player = e.getPlayer();
                        if(hasChair(player))
                            removeChair(player);
                    }
                }
            }).syncStart();

            ProtocolLibrary.getProtocolManager().getAsynchronousManager().registerAsyncHandler(new PacketAdapter(PacketAdapter.params(CraftBookPlugin.inst(), PacketType.Play.Client.POSITION, PacketType.Play.Client.POSITION_LOOK).clientSide().listenerPriority(ListenerPriority.HIGHEST).options(ListenerOptions.INTERCEPT_INPUT_BUFFER)) {
                @Override
                public void onPacketReceiving(PacketEvent e) {
                    if (!e.isCancelled()) {
                        for(double d : e.getPacket().getDoubles().getValues())
                            if(Double.isNaN(d)) {
                                e.setCancelled(true);
                                return;
                            }
                    }
                }
            }).syncStart();
        } catch(Throwable e) {
            CraftBookPlugin.inst().getLogger().warning("ProtocolLib is required for chairs! Disabling chairs!");
            return false;
        }

        return true;
    }

    @Override
    public void disable () {
        chairs = null;
        try {
            ProtocolLibrary.getProtocolManager().getAsynchronousManager().unregisterAsyncHandlers(CraftBookPlugin.inst());
        } catch(Throwable e) {
        }
    }

    boolean chairAllowHeldBlock;
    boolean chairHealth;
    double chairHealAmount;
    List<ItemInfo> chairBlocks;
    boolean chairFacing;
    boolean chairRequireSign;
    int chairMaxDistance;
    int chairMaxClickRadius;

    @Override
    public void loadConfiguration (YAMLProcessor config, String path) {

        config.setComment(path + "allow-holding-blocks", "Allow players to sit in chairs when holding blocks.");
        chairAllowHeldBlock = config.getBoolean(path + "allow-holding-blocks", false);

        config.setComment(path + "regen-health", "Regenerate health passively when sitting down.");
        chairHealth = config.getBoolean(path + "regen-health", true);

        config.setComment(path + "regen-health-amount", "The amount of health regenerated passively. (Can be decimal)");
        chairHealAmount = config.getDouble(path + "regen-health-amount", 1);

        config.setComment(path + "blocks", "A list of blocks that can be sat on.");
        chairBlocks = ItemInfo.parseListFromString(config.getStringList(path + "blocks", Arrays.asList("WOOD_STAIRS", "COBBLESTONE_STAIRS", "BRICK_STAIRS", "SMOOTH_STAIRS", "NETHER_BRICK_STAIRS", "SANDSTONE_STAIRS", "SPRUCE_WOOD_STAIRS", "BIRCH_WOOD_STAIRS", "JUNGLE_WOOD_STAIRS", "QUARTZ_STAIRS", "ACACIA_STAIRS")));

        config.setComment(path + "face-correct-direction", "When the player sits, automatically face them the direction of the chair. (If possible)");
        chairFacing = config.getBoolean(path + "face-correct-direction", true);

        config.setComment(path + "require-sign", "Require a sign to be attached to the chair in order to work!");
        chairRequireSign = config.getBoolean(path + "require-sign", false);

        config.setComment(path + "max-distance", "The maximum distance between the click point and the sign. (When require sign is on)");
        chairMaxDistance = config.getInt(path + "max-distance", 3);

        config.setComment(path + "max-click-radius", "The maximum distance the player can be from the sign.");
        chairMaxClickRadius = config.getInt(path + "max-click-radius", 5);
    }
}
TOP

Related Classes of com.sk89q.craftbook.mechanics.Chair

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.