Package com.sk89q.craftbook.bukkit

Source Code of com.sk89q.craftbook.bukkit.MechanicListenerAdapter

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

import java.util.HashSet;
import java.util.Set;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Minecart;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.BlockRedstoneEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.vehicle.VehicleEnterEvent;
import org.bukkit.event.vehicle.VehicleMoveEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.material.Attachable;
import org.bukkit.material.Directional;
import org.bukkit.material.PressureSensor;

import com.sk89q.craftbook.mechanics.minecart.blocks.CartBlockMechanism;
import com.sk89q.craftbook.mechanics.minecart.blocks.CartMechanismBlocks;
import com.sk89q.craftbook.mechanics.minecart.events.CartBlockEnterEvent;
import com.sk89q.craftbook.mechanics.minecart.events.CartBlockImpactEvent;
import com.sk89q.craftbook.mechanics.minecart.events.CartBlockRedstoneEvent;
import com.sk89q.craftbook.util.EventUtil;
import com.sk89q.craftbook.util.LocationUtil;
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.craftbook.util.exceptions.InvalidMechanismException;
import com.sk89q.worldedit.BlockWorldVector;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.WorldVector;
import com.sk89q.worldedit.blocks.BlockID;
import com.sk89q.worldedit.blocks.BlockType;
import com.sk89q.worldedit.bukkit.BukkitUtil;

/**
* This adapter hooks a mechanic manager up to Bukkit.
*
* @author sk89q
*/
public class MechanicListenerAdapter implements Listener {

    Set<String> signClickTimer = new HashSet<String>();

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

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

        Block block = null;
        Action action = null;
        if(event.getAction() == Action.RIGHT_CLICK_AIR) {
            try {
                block = event.getPlayer().getTargetBlock(null, 5);
                if(block != null && block.getType() != Material.AIR)
                    action = Action.RIGHT_CLICK_BLOCK;
                else
                    action = Action.RIGHT_CLICK_AIR;
            } catch(Exception e) {
                //Bukkit randomly errors. Catch the error.
            }
        } else {
            block = event.getClickedBlock();
            action = event.getAction();
        }

        if(block != null && SignUtil.isSign(block)) {
            if(CraftBookPlugin.inst().getConfiguration().signClickTimeout > 0) {
                if(signClickTimer.contains(event.getPlayer().getName())) {
                    return;
                } else {
                    signClickTimer.add(event.getPlayer().getName());
                    Bukkit.getScheduler().runTaskLater(CraftBookPlugin.inst(), new Runnable() {
                        @Override
                        public void run () {
                            signClickTimer.remove(event.getPlayer().getName());
                        }
                    }, CraftBookPlugin.inst().getConfiguration().signClickTimeout);
                }
            }
            SignClickEvent ev = new SignClickEvent(event.getPlayer(), action, event.getItem(), block, event.getBlockFace());
            CraftBookPlugin.inst().getServer().getPluginManager().callEvent(ev);
            if(ev.isCancelled())
                event.setCancelled(true);
        }
    }

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

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

        if(!(CraftBookPlugin.inst().getConfiguration().advancedBlockChecks && event.isCancelled())) {
            checkBlockChange(event.getPlayer(), event.getBlock(), false);
        }
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onBlockPlace(BlockPlaceEvent event) {

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

        if(!(CraftBookPlugin.inst().getConfiguration().advancedBlockChecks && event.isCancelled())) {
            checkBlockChange(event.getPlayer(), event.getBlock(), true);
        }
    }

    public void checkBlockChange(Player player, Block block, boolean build) {
        switch(block.getType()) {

            case REDSTONE_TORCH_ON:
            case DIODE_BLOCK_ON:
            case REDSTONE_BLOCK:
            case REDSTONE_COMPARATOR_ON:
                if(CraftBookPlugin.inst().getConfiguration().pedanticBlockChecks && !ProtectionUtil.canBuild(player, block.getLocation(), build))
                    break;
                handleRedstoneForBlock(block, build ? 0 : 15, build ? 15 : 0);
                break;
            case REDSTONE_WIRE:
                if(CraftBookPlugin.inst().getConfiguration().pedanticBlockChecks && !ProtectionUtil.canBuild(player, block.getLocation(), build))
                    break;
                if(block.getData() > 0)
                    handleRedstoneForBlock(block, block.getData(), 0);
                break;
            case LEVER:
                if(CraftBookPlugin.inst().getConfiguration().pedanticBlockChecks && !ProtectionUtil.canBuild(player, block.getLocation(), build))
                    break;
                if(((org.bukkit.material.Lever) block.getState().getData()).isPowered())
                    handleRedstoneForBlock(block, build ? 0 : 15, build ? 15 : 0);
                break;
            case WOOD_BUTTON:
            case STONE_BUTTON:
                if(CraftBookPlugin.inst().getConfiguration().pedanticBlockChecks && !ProtectionUtil.canBuild(player, block.getLocation(), build))
                    break;
                if(((org.bukkit.material.Button) block.getState().getData()).isPowered())
                    handleRedstoneForBlock(block, build ? 0 : 15, build ? 15 : 0);
                break;
            case STONE_PLATE:
            case WOOD_PLATE:
            case GOLD_PLATE:
            case IRON_PLATE:
            case DETECTOR_RAIL:
                if(CraftBookPlugin.inst().getConfiguration().pedanticBlockChecks && !ProtectionUtil.canBuild(player, block.getLocation(), build))
                    break;
                if(block.getState().getData() instanceof PressureSensor && ((PressureSensor) block.getState().getData()).isPressed())
                    handleRedstoneForBlock(block, build ? 0 : 15, build ? 15 : 0);
                break;
            default:
                break;
        }
    }

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

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

        handleRedstoneForBlock(event.getBlock(), event.getOldCurrent(), event.getNewCurrent());
    }

    public void handleRedstoneForBlock(Block block, int oldLevel, int newLevel) {

        World world = block.getWorld();
        BlockWorldVector v = BukkitUtil.toWorldVector(block);

        // Give the method a BlockWorldVector instead of a Block
        boolean wasOn = oldLevel >= 1;
        boolean isOn = newLevel >= 1;
        boolean wasChange = wasOn != isOn;

        // For efficiency reasons, we're only going to consider changes between
        // off and on state, and ignore simple current changes (i.e. 15->13)
        if (!wasChange) return;

        LocalWorld w = BukkitUtil.getLocalWorld(world);
        int x = v.getBlockX();
        int y = v.getBlockY();
        int z = v.getBlockZ();

        // When this hook has been called, the level in the world has not
        // yet been updated, so we're going to do this very ugly thing of
        // faking the value with the new one whenever the data value of this
        // block is requested -- it is quite ugly
        switch(block.getTypeId()) {
            case BlockID.REDSTONE_WIRE:
                if (CraftBookPlugin.inst().getConfiguration().indirectRedstone) {

                    // power all blocks around the redstone wire on the same y level
                    // north/south
                    handleDirectWireInput(new WorldVector(w, x - 1, y, z), block, oldLevel, newLevel);
                    handleDirectWireInput(new WorldVector(w, x + 1, y, z), block, oldLevel, newLevel);
                    // east/west
                    handleDirectWireInput(new WorldVector(w, x, y, z - 1), block, oldLevel, newLevel);
                    handleDirectWireInput(new WorldVector(w, x, y, z + 1), block, oldLevel, newLevel);

                    // Can be triggered from below
                    handleDirectWireInput(new WorldVector(w, x, y + 1, z), block, oldLevel, newLevel);

                    // Can be triggered from above (Eg, glass->glowstone like redstone lamps)
                    handleDirectWireInput(new WorldVector(w, x, y - 1, z), block, oldLevel, newLevel);
                } else {

                    int above = world.getBlockTypeIdAt(x, y + 1, z);

                    int westSide = world.getBlockTypeIdAt(x, y, z + 1);
                    int westSideAbove = world.getBlockTypeIdAt(x, y + 1, z + 1);
                    int westSideBelow = world.getBlockTypeIdAt(x, y - 1, z + 1);
                    int eastSide = world.getBlockTypeIdAt(x, y, z - 1);
                    int eastSideAbove = world.getBlockTypeIdAt(x, y + 1, z - 1);
                    int eastSideBelow = world.getBlockTypeIdAt(x, y - 1, z - 1);

                    int northSide = world.getBlockTypeIdAt(x - 1, y, z);
                    int northSideAbove = world.getBlockTypeIdAt(x - 1, y + 1, z);
                    int northSideBelow = world.getBlockTypeIdAt(x - 1, y - 1, z);
                    int southSide = world.getBlockTypeIdAt(x + 1, y, z);
                    int southSideAbove = world.getBlockTypeIdAt(x + 1, y + 1, z);
                    int southSideBelow = world.getBlockTypeIdAt(x + 1, y - 1, z);

                    // Make sure that the wire points to only this block
                    if (!BlockType.isRedstoneBlock(westSide) && !BlockType.isRedstoneBlock(eastSide)
                            && (!BlockType.isRedstoneBlock(westSideAbove) || westSide == 0 || above != 0)
                            && (!BlockType.isRedstoneBlock(eastSideAbove) || eastSide == 0 || above != 0)
                            && (!BlockType.isRedstoneBlock(westSideBelow) || westSide != 0)
                            && (!BlockType.isRedstoneBlock(eastSideBelow) || eastSide != 0)) {
                        // Possible blocks north / south
                        handleDirectWireInput(new WorldVector(w, x - 1, y, z), block, oldLevel, newLevel);
                        handleDirectWireInput(new WorldVector(w, x + 1, y, z), block, oldLevel, newLevel);
                        handleDirectWireInput(new WorldVector(w, x - 1, y - 1, z), block, oldLevel, newLevel);
                        handleDirectWireInput(new WorldVector(w, x + 1, y - 1, z), block, oldLevel, newLevel);
                    }

                    if (!BlockType.isRedstoneBlock(northSide) && !BlockType.isRedstoneBlock(southSide)
                            && (!BlockType.isRedstoneBlock(northSideAbove) || northSide == 0 || above != 0)
                            && (!BlockType.isRedstoneBlock(southSideAbove) || southSide == 0 || above != 0)
                            && (!BlockType.isRedstoneBlock(northSideBelow) || northSide != 0)
                            && (!BlockType.isRedstoneBlock(southSideBelow) || southSide != 0)) {
                        // Possible blocks west / east
                        handleDirectWireInput(new WorldVector(w, x, y, z - 1), block, oldLevel, newLevel);
                        handleDirectWireInput(new WorldVector(w, x, y, z + 1), block, oldLevel, newLevel);
                        handleDirectWireInput(new WorldVector(w, x, y - 1, z - 1), block, oldLevel, newLevel);
                        handleDirectWireInput(new WorldVector(w, x, y - 1, z + 1), block, oldLevel, newLevel);
                    }

                    // Can be triggered from below
                    handleDirectWireInput(new WorldVector(w, x, y + 1, z), block, oldLevel, newLevel);

                    // Can be triggered from above
                    handleDirectWireInput(new WorldVector(w, x, y - 1, z), block, oldLevel, newLevel);
                }
                return;
            case BlockID.REDSTONE_REPEATER_OFF:
            case BlockID.REDSTONE_REPEATER_ON:
            case BlockID.COMPARATOR_OFF:
            case BlockID.COMPARATOR_ON:
                Directional diode = (Directional) block.getState().getData();
                BlockFace f = diode.getFacing();
                handleDirectWireInput(new WorldVector(w, x + f.getModX(), y, z + f.getModZ()), block, oldLevel, newLevel);
                if(block.getRelative(f).getTypeId() != 0) {
                    handleDirectWireInput(new WorldVector(w, x + f.getModX(), y - 1, z + f.getModZ()), block, oldLevel, newLevel);
                    handleDirectWireInput(new WorldVector(w, x + f.getModX(), y + 1, z + f.getModZ()), block, oldLevel, newLevel);
                    handleDirectWireInput(new WorldVector(w, x + f.getModX() + 1, y - 1, z + f.getModZ()), block, oldLevel, newLevel);
                    handleDirectWireInput(new WorldVector(w, x + f.getModX() - 1, y - 1, z + f.getModZ()), block, oldLevel, newLevel);
                    handleDirectWireInput(new WorldVector(w, x + f.getModX() + 1, y - 1, z + f.getModZ() + 1), block, oldLevel, newLevel);
                    handleDirectWireInput(new WorldVector(w, x + f.getModX() - 1, y - 1, z + f.getModZ() - 1), block, oldLevel, newLevel);
                }
                return;
            case BlockID.STONE_BUTTON:
            case BlockID.WOODEN_BUTTON:
            case BlockID.LEVER:
                Attachable button = (Attachable) block.getState().getData();
                if(button != null) {
                    BlockFace face = button.getAttachedFace();
                    if(face != null)
                        handleDirectWireInput(new WorldVector(w, x + face.getModX()*2, y, z + face.getModZ()*2), block, oldLevel, newLevel);
                }
        }

        // For redstone wires and repeaters, the code already exited this method
        // Non-wire blocks proceed

        handleDirectWireInput(new WorldVector(w, x - 1, y, z), block, oldLevel, newLevel);
        handleDirectWireInput(new WorldVector(w, x + 1, y, z), block, oldLevel, newLevel);
        handleDirectWireInput(new WorldVector(w, x - 1, y - 1, z), block, oldLevel, newLevel);
        handleDirectWireInput(new WorldVector(w, x + 1, y - 1, z), block, oldLevel, newLevel);
        handleDirectWireInput(new WorldVector(w, x, y, z - 1), block, oldLevel, newLevel);
        handleDirectWireInput(new WorldVector(w, x, y, z + 1), block, oldLevel, newLevel);
        handleDirectWireInput(new WorldVector(w, x, y - 1, z - 1), block, oldLevel, newLevel);
        handleDirectWireInput(new WorldVector(w, x, y - 1, z + 1), block, oldLevel, newLevel);

        // Can be triggered from below
        handleDirectWireInput(new WorldVector(w, x, y + 1, z), block, oldLevel, newLevel);

        // Can be triggered from above
        handleDirectWireInput(new WorldVector(w, x, y - 1, z), block, oldLevel, newLevel);
    }

    /**
     * Handle the direct wire input.
     *
     * @param pt
     * @param sourceBlock
     * @param oldLevel
     * @param newLevel
     */
    protected void handleDirectWireInput(WorldVector pt, Block sourceBlock, int oldLevel, int newLevel) {

        Block block = sourceBlock.getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
        if(BukkitUtil.equals(sourceBlock.getLocation(), block.getLocation())) //The same block, don't run.
            return;
        final SourcedBlockRedstoneEvent event = new SourcedBlockRedstoneEvent(sourceBlock, block, oldLevel, newLevel);

        CraftBookPlugin.inst().getServer().getPluginManager().callEvent(event);

        CraftBookPlugin.server().getScheduler().runTask(CraftBookPlugin.inst(), new Runnable() {

            @Override
            public void run () {
                try {
                    CartMechanismBlocks cmb = CartMechanismBlocks.find(event.getBlock());
                    CartBlockRedstoneEvent ev = new CartBlockRedstoneEvent(event.getBlock(), event.getSource(), event.getOldCurrent(), event.getNewCurrent(), cmb, CartBlockMechanism.getCart(cmb.rail));
                    CraftBookPlugin.inst().getServer().getPluginManager().callEvent(ev);
                } catch (InvalidMechanismException ignored) {
                }
            }
        });
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onVehicleMove(VehicleMoveEvent event) {

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

        if(event.getVehicle() instanceof Minecart) {
            try {
                Minecart cart = (Minecart) event.getVehicle();
                CartMechanismBlocks cmb = CartMechanismBlocks.findByRail(event.getTo().getBlock());
                cmb.setFromBlock(event.getFrom().getBlock());
                Location from = event.getFrom();
                Location to = event.getTo();
                if(LocationUtil.getDistanceSquared(from, to) > 2*2) //Further than max distance
                    return;
                boolean minor = from.getBlockX() == to.getBlockX() && from.getBlockY() == to.getBlockY() && from.getBlockZ() == to.getBlockZ();
                CartBlockImpactEvent ev = new CartBlockImpactEvent(cart, from, to, cmb, minor);
                CraftBookPlugin.inst().getServer().getPluginManager().callEvent(ev);
            } catch (InvalidMechanismException ignored) {
            }
        }
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onVehicleEnter(VehicleEnterEvent event) {

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

        if(!event.getVehicle().getWorld().isChunkLoaded(event.getVehicle().getLocation().getBlockX() >> 4, event.getVehicle().getLocation().getBlockZ() >> 4))
            return;

        if(event.getVehicle() instanceof Minecart) {
            try {
                Minecart cart = (Minecart) event.getVehicle();
                Block block = event.getVehicle().getLocation().getBlock();
                CartMechanismBlocks cmb = CartMechanismBlocks.findByRail(block);
                cmb.setFromBlock(block); // WAI
                CartBlockEnterEvent ev = new CartBlockEnterEvent(cart, event.getEntered(), cmb);
                CraftBookPlugin.inst().getServer().getPluginManager().callEvent(ev);
                if(ev.isCancelled())
                    event.setCancelled(true);
            } catch (InvalidMechanismException ignored) {
            }
        }
    }

    /**
     * Called when a chunk is loaded.
     */
    @EventHandler(priority = EventPriority.HIGH)
    public void onChunkLoad(final ChunkLoadEvent event) {

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

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

            @Override
            public void run() {

                CraftBookPlugin.inst().getSelfTriggerManager().registerSelfTrigger(event.getChunk());
            }
        }, 2);
    }

    /**
     * Called when a chunk is unloaded.
     */
    @EventHandler(priority = EventPriority.HIGH)
    public void onChunkUnload(ChunkUnloadEvent event) {

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

        CraftBookPlugin.inst().getSelfTriggerManager().unregisterSelfTrigger(event.getChunk());
    }
}
TOP

Related Classes of com.sk89q.craftbook.bukkit.MechanicListenerAdapter

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.