Package com.sk89q.craftbook.mechanics.area.simple

Source Code of com.sk89q.craftbook.mechanics.area.simple.Gate$GateColumn

// $Id$
/*
* CraftBook Copyright (C) 2010 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.craftbook.mechanics.area.simple;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Block;
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.block.SignChangeEvent;
import org.bukkit.inventory.ItemStack;

import com.sk89q.craftbook.AbstractCraftBookMechanic;
import com.sk89q.craftbook.ChangedSign;
import com.sk89q.craftbook.LocalPlayer;
import com.sk89q.craftbook.bukkit.CraftBookPlugin;
import com.sk89q.craftbook.bukkit.util.BukkitUtil;
import com.sk89q.craftbook.util.BlockUtil;
import com.sk89q.craftbook.util.EventUtil;
import com.sk89q.craftbook.util.ItemInfo;
import com.sk89q.craftbook.util.ProtectionUtil;
import com.sk89q.craftbook.util.SignUtil;
import com.sk89q.craftbook.util.events.SignClickEvent;
import com.sk89q.craftbook.util.events.SourcedBlockRedstoneEvent;
import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.worldedit.BlockWorldVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.regions.CuboidRegion;

/**
* Handler for gates. Gates are merely fence blocks. When they are closed or open, a nearby fence will be found,
* the algorithm will traverse to the
* top-most connected fence block, and then proceed to recurse to the sides up to a certain number of fences. To the
* fences that it gets to, it will
* iterate over the blocks below to open or close the gate.
*
* @author sk89q
*/
public class Gate extends AbstractCraftBookMechanic {

    /**
     * Toggles the gate closest to a location.
     *
     * @param player
     * @param pt
     * @param smallSearchSize
     * @param close null to toggle, true to close, false to open
     *
     * @return true if a gate was found and blocks were changed; false otherwise.
     */
    public boolean toggleGates(LocalPlayer player, Block block, boolean smallSearchSize, Boolean close) {

        int x = block.getX();
        int y = block.getY();
        int z = block.getZ();

        boolean foundGate = false;

        Set<GateColumn> visitedColumns = new HashSet<GateColumn>();

        if (smallSearchSize) {
            // Toggle nearby gates
            for (int x1 = x - 1; x1 <= x + 1; x1++) {
                for (int y1 = y - 2; y1 <= y + 1; y1++) {
                    for (int z1 = z - 1; z1 <= z + 1; z1++) {
                        if (recurseColumn(player, BukkitUtil.toChangedSign(block), block.getWorld().getBlockAt(x1, y1, z1), visitedColumns, close, smallSearchSize)) {
                            foundGate = true;
                        }
                    }
                }
            }
        } else {
            // Toggle nearby gates
            for (int x1 = x - searchRadius; x1 <= x + searchRadius; x1++) {
                for (int y1 = y - searchRadius; y1 <= y + searchRadius*2; y1++) {
                    for (int z1 = z - searchRadius; z1 <= z + searchRadius; z1++) {
                        if (recurseColumn(player, BukkitUtil.toChangedSign(block), block.getWorld().getBlockAt(x1, y1, z1), visitedColumns, close, smallSearchSize)) {
                            foundGate = true;
                        }
                    }
                }
            }
        }

        // bag.flushChanges();

        return foundGate && visitedColumns.size() > 0;
    }

    /**
     * Toggles one column of gate.
     *
     * @param player The Player
     * @param sign The sign block.
     * @param block A part of the column.
     * @param visitedColumns Previously visited columns.
     * @param close Should close or open.
     *
     * @return true if a gate column was found and blocks were changed; false otherwise.
     */
    private boolean recurseColumn(LocalPlayer player, ChangedSign sign, Block block, Set<GateColumn> visitedColumns, Boolean close, boolean smallSearchSize) {

        if (limitColumns && visitedColumns.size() > columnLimit)
            return false;

        if (!isValidGateBlock(sign, smallSearchSize, new ItemInfo(block), true)) return false;

        CraftBookPlugin.logDebugMessage("Found a possible gate column at " + block.getX() + ":" + block.getY() + ":" + block.getZ(), "gates.search");

        int x = block.getX();
        int z = block.getZ();

        GateColumn column = new GateColumn(sign, block, smallSearchSize);

        // The block above the gate cannot be air -- it has to be some
        // non-fence block
        if (block.getWorld().getBlockAt(x, column.getStartingY() + 1, z).getType() == Material.AIR) return false;

        if (visitedColumns.contains(column)) return false;

        visitedColumns.add(column);

        if (close == null)
            close = !isValidGateBlock(sign, smallSearchSize, new ItemInfo(block.getWorld().getBlockAt(x, column.getStartingY() - 1, z)), true);

        CraftBookPlugin.logDebugMessage("Valid column at " + block.getX() + ":" + block.getY() + ":" + block.getZ() + " is being " + (close ? "closed" : "opened"), "gates.search");
        CraftBookPlugin.logDebugMessage("Column Top: " + column.getStartingY() + " End: " + column.getEndingY(), "gates.search");
        // Recursively go to connected fence blocks of the same level
        // and 'close' or 'open' them
        return toggleColumn(player, sign, block, column, close, visitedColumns, smallSearchSize);
    }

    /**
     * Actually does the closing/opening. Also recurses to nearby columns.
     *
     * @param player The player.
     * @param signBlock The sign block.
     * @param block The top point of the gate.
     * @param close To open or close.
     * @param visitedColumns Previously searched columns.
     */
    private boolean toggleColumn(LocalPlayer player, ChangedSign sign, Block block, GateColumn column, boolean close, Set<GateColumn> visitedColumns, boolean smallSearchSize) {

        // If we want to close the gate then we replace air/water blocks
        // below with fence blocks; otherwise, we want to replace fence
        // blocks below with air
        ItemInfo item;
        if (close)
            item = new ItemInfo(column.getStartingPoint());
        else
            item = new ItemInfo(Material.AIR, 0);

        CraftBookPlugin.logDebugMessage("Setting column at " + block.getX() + ":" + block.getY() + ":" + block.getZ() + " to " + item.toString(), "gates.search");

        for (Vector bl : column.getRegion()) {

            Block blo = BukkitUtil.toBlock(new BlockWorldVector(BukkitUtil.toWorldVector(block).getWorld(), bl));

            //sign = BukkitUtil.toChangedSign(sign.getSign().getBlock());

            if(sign == null) {
                CraftBookPlugin.logDebugMessage("Invalid Sign!", "gates.search");
                return false;
            }

            ChangedSign otherSign = null;

            Block ot = SignUtil.getNextSign(BukkitUtil.toSign(sign).getBlock(), sign.getLine(1), 4);
            if(ot != null)
                otherSign = BukkitUtil.toChangedSign(ot);

            if (sign.getLine(2).equalsIgnoreCase("NoReplace")) {
                // If NoReplace is on line 3 of sign, do not replace blocks.
                if (blo.getType() != Material.AIR && !isValidGateBlock(sign, smallSearchSize, new ItemInfo(blo), true))
                    break;
            } else // Allowing water allows the use of gates as flood gates
                if (!canPassThrough(sign, smallSearchSize, blo))
                    break;

            // bag.setBlockID(w, x, y1, z, ID);
            if (CraftBookPlugin.inst().getConfiguration().safeDestruction) {
                if (!close || hasEnoughBlocks(sign, otherSign)) {
                    if (!close && isValidGateBlock(sign, smallSearchSize, new ItemInfo(blo), true))
                        addBlocks(sign, 1);
                    else if (close && canPassThrough(sign, smallSearchSize, blo) && isValidGateBlock(sign, smallSearchSize, item, true) && !item.isSame(blo))
                        removeBlocks(sign, 1);
                    blo.setTypeIdAndData(item.getId(), (byte) item.getData(), true);
                } else if (close && !hasEnoughBlocks(sign, otherSign) && isValidGateBlock(sign, smallSearchSize, item, true))
                    if (player != null) {
                        player.printError("mech.not-enough-blocks");
                        return false;
                    }
            } else
                blo.setTypeIdAndData(item.getId(), (byte) item.getData(), true);

            CraftBookPlugin.logDebugMessage("Set block " + bl.getX() + ":" + bl.getY() + ":" + bl.getZ() + " to " + item.toString(), "gates.search");

            recurseColumn(player, sign, blo.getRelative(1, 0, 0), visitedColumns, close, smallSearchSize);
            recurseColumn(player, sign, blo.getRelative(-1, 0, 0), visitedColumns, close, smallSearchSize);
            recurseColumn(player, sign, blo.getRelative(0, 0, 1), visitedColumns, close, smallSearchSize);
            recurseColumn(player, sign, blo.getRelative(0, 0, -1), visitedColumns, close, smallSearchSize);
        }

        recurseColumn(player, sign, column.getStartingPoint().getRelative(1, 0, 0), visitedColumns, close, smallSearchSize);
        recurseColumn(player, sign, column.getStartingPoint().getRelative(-1, 0, 0), visitedColumns, close, smallSearchSize);
        recurseColumn(player, sign, column.getStartingPoint().getRelative(0, 0, 1), visitedColumns, close, smallSearchSize);
        recurseColumn(player, sign, column.getStartingPoint().getRelative(0, 0, -1), visitedColumns, close, smallSearchSize);

        recurseColumn(player, sign, column.getStartingPoint().getRelative(1, 1, 0), visitedColumns, close, smallSearchSize);
        recurseColumn(player, sign, column.getStartingPoint().getRelative(-1, 1, 0), visitedColumns, close, smallSearchSize);
        recurseColumn(player, sign, column.getStartingPoint().getRelative(0, 1, 1), visitedColumns, close, smallSearchSize);
        recurseColumn(player, sign, column.getStartingPoint().getRelative(0, 1, -1), visitedColumns, close, smallSearchSize);
        return true;
    }

    /**
     * Raised when a block is right clicked.
     *
     * @param event
     */
    @EventHandler(priority = EventPriority.HIGH)
    public void onRightClick(SignClickEvent event) {

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

        if(event.getAction() != Action.RIGHT_CLICK_BLOCK) return;

        LocalPlayer player = CraftBookPlugin.inst().wrapPlayer(event.getPlayer());

        ChangedSign sign = event.getSign();

        if (!sign.getLine(1).equals("[Gate]") && !sign.getLine(1).equals("[DGate]")) return;

        boolean smallSearchSize = sign.getLine(1).equals("[DGate]");

        ItemInfo gateBlock = getGateBlock(sign, smallSearchSize);

        if (CraftBookPlugin.inst().getConfiguration().safeDestruction && (gateBlock == null || gateBlock.getType() == Material.AIR || gateBlock.getType() == player.getHeldItemInfo().getType()) && isValidGateBlock(sign, smallSearchSize, player.getHeldItemInfo(), false)) {

            if (!player.hasPermission("craftbook.mech.gate.restock")) {
                if(CraftBookPlugin.inst().getConfiguration().showPermissionMessages)
                    player.printError("mech.restock-permission");
                return;
            }

            int amount = 1;
            if (event.getPlayer().isSneaking())
                amount = Math.min(5, event.getPlayer().getItemInHand().getAmount());
            addBlocks(sign, amount);

            if (!(event.getPlayer().getGameMode() == GameMode.CREATIVE))
                if (event.getPlayer().getItemInHand().getAmount() <= amount)
                    event.getPlayer().setItemInHand(null);
                else
                    event.getPlayer().getItemInHand().setAmount(event.getPlayer().getItemInHand().getAmount() - amount);

            player.print("mech.restock");
            event.setCancelled(true);
            return;
        }

        if (!player.hasPermission("craftbook.mech.gate.use")) {
            if(CraftBookPlugin.inst().getConfiguration().showPermissionMessages)
                player.printError("mech.use-permission");
            return;
        }

        if(!ProtectionUtil.canUse(event.getPlayer(), event.getClickedBlock().getLocation(), event.getBlockFace(), event.getAction())) {
            if(CraftBookPlugin.inst().getConfiguration().showPermissionMessages)
                player.printError("area.use-permissions");
            return;
        }

        if (toggleGates(player, event.getClickedBlock(), smallSearchSize, null))
            player.print("mech.gate.toggle");
        else
            player.printError("mech.gate.not-found");

        event.setCancelled(true);
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onBlockRedstoneChange(final SourcedBlockRedstoneEvent event) {

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

        if (!allowRedstone) return;

        if (event.isMinor()) return;

        if (!SignUtil.isSign(event.getBlock())) return;

        final ChangedSign sign = BukkitUtil.toChangedSign(event.getBlock());
        if (!sign.getLine(1).equals("[Gate]") && !sign.getLine(1).equals("[DGate]")) return;

        CraftBookPlugin.inst().getServer().getScheduler().runTaskLater(CraftBookPlugin.inst(), new Runnable() {

            @Override
            public void run() {

                toggleGates(null, event.getBlock(), sign.getLine(1).equals("[DGate]"), event.getNewCurrent() > 0);
            }
        }, 2);
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onSignChange(SignChangeEvent event) {

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

        if(!event.getLine(1).equalsIgnoreCase("[Gate]") && !event.getLine(1).equalsIgnoreCase("[DGate]")) return;

        LocalPlayer player = CraftBookPlugin.inst().wrapPlayer(event.getPlayer());

        if (event.getLine(1).equalsIgnoreCase("[Gate]")) {
            if(!player.hasPermission("craftbook.mech.gate")) {
                if(CraftBookPlugin.inst().getConfiguration().showPermissionMessages)
                    player.printError("mech.create-permission");
                SignUtil.cancelSign(event);
                return;
            }
            // get the material that this gate should toggle and verify it
            String line0 = event.getLine(0).trim();
            if (line0 != null && !line0.isEmpty()) {
                if (!isValidGateBlock(new ItemInfo(line0))) {
                    player.printError("Line 1 needs to be a valid block id.");
                    SignUtil.cancelSign(event);
                    return;
                }
            }
            event.setLine(1, "[Gate]");
            if (event.getLine(3).equalsIgnoreCase("infinite") && !player.hasPermission("craftbook.mech.gate.infinite"))
                event.setLine(3, "0");
            else if (!event.getLine(3).equalsIgnoreCase("infinite"))
                event.setLine(3, "0");
            player.print("mech.gate.create");
        } else if (event.getLine(1).equalsIgnoreCase("[DGate]")) {
            if (!player.hasPermission("craftbook.mech.gate") && !player.hasPermission("craftbook.mech.dgate")) {
                if(CraftBookPlugin.inst().getConfiguration().showPermissionMessages)
                    player.printError("mech.create-permission");
                SignUtil.cancelSign(event);
                return;
            }
            // get the material that this gate should toggle and verify it
            String line0 = event.getLine(0).trim();
            if (line0 != null && !line0.isEmpty()) {
                if (!isValidGateBlock(new ItemInfo(line0))) {
                    player.printError("mech.gate.valid-item");
                    SignUtil.cancelSign(event);
                    return;
                }
            }
            event.setLine(1, "[DGate]");
            if (event.getLine(3).equalsIgnoreCase("infinite") && !player.hasPermission("craftbook.mech.gate.infinite"))
                event.setLine(3, "0");
            else if (!event.getLine(3).equalsIgnoreCase("infinite"))
                event.setLine(3, "0");
            player.print("mech.dgate.create");
        }
    }

    public boolean isValidGateBlock(ItemInfo block) {

        return blocks.contains(block);
    }

    /**
     * Checks if a block can be used in gate.
     *
     * @param signBlock The sign block.
     * @param smallSearchSize Search small or large.
     * @param block The block to check.
     * @param check Should search.
     * @return
     */
    public boolean isValidGateBlock(ChangedSign sign, boolean smallSearchSize, ItemInfo block, boolean check) {

        ItemInfo type;

        if (sign != null && !sign.getLine(0).isEmpty()) {
            try {
                ItemInfo def = new ItemInfo(sign.getLine(0));
                return block.equals(def);
            } catch (Exception e) {
                if (check) {
                    type = getGateBlock(sign, smallSearchSize);
                    if(type == null || type.getType() == Material.AIR)
                        return block.equals(type);
                }
                return blocks.contains(block);
            }
        } else if(check && (type = getGateBlock(sign, smallSearchSize)) != null)
            return block.equals(type);
        else
            return blocks.contains(block);
    }

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

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

        if (!SignUtil.isSign(event.getBlock())) return;

        final ChangedSign sign = BukkitUtil.toChangedSign(event.getBlock());
        if (!sign.getLine(1).equals("[Gate]") && !sign.getLine(1).equals("[DGate]")) return;

        LocalPlayer player = CraftBookPlugin.inst().wrapPlayer(event.getPlayer());

        if(!ProtectionUtil.canBuild(event.getPlayer(), event.getBlock().getLocation(), false)) {
            if(CraftBookPlugin.inst().getConfiguration().showPermissionMessages)
                player.printError("area.break-permissions");
            return;
        }

        int amount = getBlocks(sign);
        if (amount > 0) {
            ItemInfo type = getGateBlock(sign, sign.getLine(1).equals("[DGate]"));
            if(type == null || type.getType() == Material.AIR)
                type = new ItemInfo(Material.FENCE, 0);
            ItemStack toDrop = new ItemStack(type.getType(), amount, (short) type.getData());
            event.getBlock().getWorld().dropItemNaturally(BlockUtil.getBlockCentre(event.getBlock()), toDrop);
        }
    }

    private boolean canPassThrough(ChangedSign sign, boolean smallSearchSize, Block t) {

        Material[] passableBlocks = new Material[9];
        passableBlocks[0] = Material.WATER;
        passableBlocks[1] = Material.STATIONARY_WATER;
        passableBlocks[2] = Material.LAVA;
        passableBlocks[3] = Material.STATIONARY_LAVA;
        passableBlocks[4] = Material.SNOW;
        passableBlocks[5] = Material.LONG_GRASS;
        passableBlocks[6] = Material.VINE;
        passableBlocks[7] = Material.DEAD_BUSH;
        passableBlocks[8] = Material.AIR;

        for (Material aPassableBlock : passableBlocks) { if (aPassableBlock == t.getType()) return true; }

        return isValidGateBlock(sign, smallSearchSize, new ItemInfo(t), true);
    }

    public ItemInfo getGateBlock(ChangedSign sign, boolean smallSearchSize) {

        ItemInfo gateBlock = null;

        if (sign != null) {
            if(!sign.getLine(0).isEmpty()) {
                try {
                    return new ItemInfo(sign.getLine(0));
                } catch (Exception ignored) {
                }
            }

            int x = sign.getX();
            int y = sign.getY();
            int z = sign.getZ();

            if (smallSearchSize) {
                for (int x1 = x - 1; x1 <= x + 1; x1++) {
                    for (int y1 = y - 2; y1 <= y + 1; y1++) {
                        for (int z1 = z - 1; z1 <= z + 1; z1++) {
                            if (getFirstBlock(sign, sign.getSign().getBlock().getWorld().getBlockAt(x1, y1, z1), smallSearchSize) != null) {
                                gateBlock = new ItemInfo(getFirstBlock(sign, sign.getSign().getBlock().getWorld().getBlockAt(x1, y1, z1), smallSearchSize));
                            }
                        }
                    }
                }
            } else {
                for (int x1 = x - searchRadius; x1 <= x + searchRadius; x1++) {
                    for (int y1 = y - searchRadius; y1 <= y + searchRadius*2; y1++) {
                        for (int z1 = z - searchRadius; z1 <= z + searchRadius; z1++) {
                            if (getFirstBlock(sign, sign.getSign().getBlock().getWorld().getBlockAt(x1, y1, z1), smallSearchSize) != null) {
                                gateBlock = new ItemInfo(getFirstBlock(sign, sign.getSign().getBlock().getWorld().getBlockAt(x1, y1, z1), smallSearchSize));
                            }
                        }
                    }
                }
            }

            if(enforceType && gateBlock != null && gateBlock.getType() != Material.AIR && sign != null) {
                sign.setLine(0, gateBlock.toString());
                sign.update(false);
            }
        }

        return gateBlock;
    }

    public Block getFirstBlock(ChangedSign sign, Block block, boolean smallSearchSize) {

        if (!isValidGateBlock(sign, smallSearchSize, new ItemInfo(block), false)) return null;

        return block;
    }

    public void removeBlocks(ChangedSign s, int amount) {

        if (s.getLine(3).equalsIgnoreCase("infinite")) return;
        setBlocks(s, getBlocks(s) - amount);
    }

    public void addBlocks(ChangedSign s, int amount) {

        if (s.getLine(3).equalsIgnoreCase("infinite")) return;
        setBlocks(s, getBlocks(s) + amount);
    }

    public void setBlocks(ChangedSign s, int amount) {

        if (s.getLine(3).equalsIgnoreCase("infinite")) return;
        s.setLine(3, String.valueOf(amount));
        s.update(false);
    }

    public int getBlocks(ChangedSign s) {

        if (s.getLine(3).equalsIgnoreCase("infinite")) return 0;
        return getBlocks(s, null);
    }

    public int getBlocks(ChangedSign s, ChangedSign other) {

        if (s.getLine(3).equalsIgnoreCase("infinite") || other != null && other.getLine(3).equalsIgnoreCase("infinite"))
            return 0;
        int curBlocks = 0;
        try {
            curBlocks = Integer.parseInt(s.getLine(3));
            if(other != null && other.getLine(0).equals(s.getLine(0))) {
                try {
                    curBlocks += Integer.parseInt(other.getLine(3));
                    setBlocks(s, curBlocks);
                    setBlocks(other, 0);
                } catch (Exception ignored) {
                }
            }
        } catch (Exception e) {
            curBlocks = 0;
        }
        return curBlocks;
    }

    public boolean hasEnoughBlocks(ChangedSign s) {

        return s.getLine(3).equalsIgnoreCase("infinite") || getBlocks(s) > 0;
    }

    public boolean hasEnoughBlocks(ChangedSign s, ChangedSign other) {

        if(other == null)
            return hasEnoughBlocks(s);
        else
            return s.getLine(3).equalsIgnoreCase("infinite") || other.getLine(3).equalsIgnoreCase("infinite") || getBlocks(s, other) > 0;
    }

    protected class GateColumn {

        private final ChangedSign sign;
        private final Block block;
        private final boolean smallSearchSize;

        private int minY = -1, maxY = -1;
        private int remainingColumnHeight;

        public GateColumn(ChangedSign sign, Block block, boolean smallSearchSize) {

            this.sign = sign;
            this.block = block;
            this.smallSearchSize = smallSearchSize;

            remainingColumnHeight = columnHeight;
        }

        public Block getStartingPoint() {

            return block.getWorld().getBlockAt(block.getX(), getStartingY(), block.getZ());
        }

        public Block getEndingPoint() {

            return block.getWorld().getBlockAt(block.getX(), getEndingY(), block.getZ());
        }

        public int getStartingY() {

            if(maxY == -1) {
                int max = Math.min(block.getWorld().getMaxHeight()-1, block.getY() + remainingColumnHeight);
                for (int y1 = block.getY() + 1; y1 <= max; y1++) {
                    if(remainingColumnHeight <= 0) break;
                    if (isValidGateBlock(sign, smallSearchSize, new ItemInfo(block.getWorld().getBlockAt(block.getX(), y1, block.getZ())), true)) {
                        maxY = y1;
                        remainingColumnHeight --;
                    } else
                        break;
                }

                if(maxY == -1) maxY = block.getY();
            }

            return maxY;
        }

        public int getEndingY() {

            if(minY == -1) {
                int min = Math.max(0, block.getY() - remainingColumnHeight);
                for (int y = block.getY(); y >= min; y--) {
                    if(remainingColumnHeight <= 0) break;
                    if (canPassThrough(sign, smallSearchSize, block.getWorld().getBlockAt(block.getX(), y, block.getZ())) || isValidGateBlock(sign, smallSearchSize, new ItemInfo(block.getWorld().getBlockAt(block.getX(), y, block.getZ())), true)) {
                        minY = y;
                        remainingColumnHeight --;
                    } else
                        break;
                }
                if(minY == -1) minY = block.getY();
            }

            return minY;
        }

        public int getX() {

            return block.getX();
        }

        public int getZ() {

            return block.getZ();
        }

        public CuboidRegion getRegion() {

            return new CuboidRegion(BukkitUtil.toWorldVector(getStartingPoint().getRelative(0, -1, 0)), BukkitUtil.toWorldVector(getEndingPoint()));
        }

        @Override
        public boolean equals(Object o) {

            return o instanceof GateColumn && ((GateColumn) o).getX() == getX() && ((GateColumn) o).getZ() == getZ() && block.getWorld().getName().equals(((GateColumn) o).block.getWorld().getName());
        }

        @Override
        public int hashCode() {
            // Constants correspond to glibc's lcg algorithm parameters
            return (getX() * 1103515245 + 12345 ^ getZ() * 1103515245 + 12345) * 1103515245 + 12345;
        }
    }

    boolean allowRedstone;
    boolean limitColumns;
    int columnLimit;
    List<ItemInfo> blocks;
    boolean enforceType;
    int columnHeight;
    int searchRadius;

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

        config.setComment(path + "allow-redstone", "Allows the gate mechanic to be toggled via redstone.");
        allowRedstone = config.getBoolean(path + "allow-redstone", true);

        config.setComment(path + "limit-columns", "Limit the amount of columns a gate can toggle.");
        limitColumns = config.getBoolean(path + "limit-columns", true);

        config.setComment(path + "max-columns", "If limit-columns is enabled, the maximum number of columns that a gate can toggle.");
        columnLimit = config.getInt(path + "max-columns", 14);

        config.setComment(path + "blocks", "The list of blocks that a gate can use.");
        blocks = ItemInfo.parseListFromString(config.getStringList(path + "blocks", Arrays.asList("FENCE", "IRON_FENCE", "THIN_GLASS", "NETHER_FENCE")));

        config.setComment(path + "enforce-type", "Make sure gates are only able to toggle a specific material type. This prevents transmutation.");
        enforceType = config.getBoolean(path + "enforce-type", true);

        config.setComment(path + "max-column-height", "The max height of a column.");
        columnHeight = config.getInt(path + "max-column-height", 12);

        config.setComment(path + "gate-search-radius", "The radius around the sign the gate checks for fences in. Note: This is doubled upwards.");
        searchRadius = config.getInt(path + "gate-search-radius", 3);
    }
}
TOP

Related Classes of com.sk89q.craftbook.mechanics.area.simple.Gate$GateColumn

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.