Package com.sk89q.craftbook

Source Code of com.sk89q.craftbook.VehicleListener

// $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;

import com.sk89q.craftbook.access.*;
import com.sk89q.craftbook.blockbag.BlockBagException;
import com.sk89q.craftbook.blockbag.NearbyChestBlockBag;
import com.sk89q.craftbook.mech.MinecartDecayWatcher;
import com.sk89q.craftbook.util.RedstoneUtil;

import java.util.HashMap;
import java.util.Map;

/**
* Delegate listener for vehicle-related hooks and features.
*
* @author sk89q
*/
public class VehicleListener extends CraftBookDelegateListener {

    /**
     * Station to stop at.
     */
    private Map<String, String> stopStation =
            new HashMap<String, String>();
    /**
     * Last minecart message sent from a sign to a player.
     */
    private Map<String, String> lastMinecartMsg =
            new HashMap<String, String>();
    /**
     * Last time minecart message sent from a sign to a player.
     */
    private Map<String, Long> lastMinecartMsgTime =
            new HashMap<String, Long>();

    /**
     * Decay watchers. Used to remove empty minecarts.
     */
    private MinecartDecayWatcher decayWatcher;

    /**
     * Track direction for sorting.
     */
    private enum SortDir {
        FORWARD, LEFT, RIGHT
    }

    // Settings
    private boolean minecartControlBlocks = true;
    private boolean slickPressurePlates = false;
    private boolean unoccupiedCoast = true;
    private boolean inCartControl = true;
    private boolean minecartDispensers = true;
    private boolean minecartTrackMessages = true;
    private int minecart25xBoostBlock = BlockType.GOLD_ORE;
    private int minecart100xBoostBlock = BlockType.GOLD_BLOCK;
    private int minecart50xSlowBlock = BlockType.SLOW_SAND;
    private int minecart20xSlowBlock = BlockType.GRAVEL;
    private int minecartStationBlock = BlockType.OBSIDIAN;
    private int minecartReverseBlock = BlockType.CLOTH;
    private int minecartDepositBlock = BlockType.IRON_ORE;
    private int minecartEjectBlock = BlockType.IRON_BLOCK;
    private int minecartSortBlock = BlockType.NETHERSTONE;
    private boolean minecartDestroyOnExit = false;
    private boolean minecartDropOnExit = false;

    /**
     * Construct the object.
     *
     * @param craftBook
     * @param listener
     * @param properties
     */
    public VehicleListener(CraftBookCore craftBook, ServerInterface server) {

        super(craftBook, server);
    }

    /**
     * /**
     * Loads CraftBooks's configuration from file.
     */
    public void loadConfiguration() {

        Configuration c = server.getConfiguration();

        minecartControlBlocks = c.getBoolean("minecart-control-blocks", true);
        slickPressurePlates = c.getBoolean("hinder-minecart-pressure-plate-slow", true);
        unoccupiedCoast = c.getBoolean("minecart-hinder-unoccupied-slowdown", true);
        inCartControl = c.getBoolean("minecart-in-cart-control", true);
        minecartDispensers = c.getBoolean("minecart-dispensers", true);
        minecartTrackMessages = c.getBoolean("minecart-track-messages", true);
        minecart25xBoostBlock = c.getInt("minecart-25x-boost-block", BlockType.GOLD_ORE);
        minecart100xBoostBlock = c.getInt("minecart-100x-boost-block", BlockType.GOLD_BLOCK);
        minecart50xSlowBlock = c.getInt("minecart-50x-slow-block", BlockType.SLOW_SAND);
        minecart20xSlowBlock = c.getInt("minecart-20x-slow-block", BlockType.GRAVEL);
        minecartStationBlock = c.getInt("minecart-station-block", BlockType.OBSIDIAN);
        minecartReverseBlock = c.getInt("minecart-reverse-block", BlockType.CLOTH);
        minecartDepositBlock = c.getInt("minecart-deposit-block", BlockType.IRON_ORE);
        minecartEjectBlock = c.getInt("minecart-eject-block", BlockType.IRON_BLOCK);
        minecartSortBlock = c.getInt("minecart-sort-block", BlockType.NETHERSTONE);

        int decay = c.getInt("minecart-decay-time", 0);

        decayWatcher = null;

        if (decay != 0) {
            decayWatcher = new MinecartDecayWatcher(decay);
        }

        minecartDestroyOnExit = c.getBoolean("minecart-destroy-on-exit", false);
        minecartDropOnExit = c.getBoolean("minecart-drop-on-exit", false);
    }

    /**
     * Called before the command is parsed. Return true if you don't want the
     * command to be parsed.
     *
     * @param player
     * @param split
     *
     * @return false if you want the command to be parsed.
     */
    public boolean onCommand(PlayerInterface player, String[] split) {
        // /st station stop command
        if (split[0].equalsIgnoreCase("/st")) {
            if (split.length >= 2) {
                stopStation.put(player.getName(), "#" + split[1].trim());
                player.sendMessage(Colors.GOLD + "You will stop at station \""
                        + split[1].trim() + "\".");
            } else {
                player.sendMessage(Colors.RED
                        + "You need to specify a station name.");
            }
            return true;
        }
        return false;
    }

    /**
     * Handles the wire input at a block in the case when the wire is
     * directly connected to the block in question only.
     *
     * @param x
     * @param y
     * @param z
     * @param isOn
     */
    public void onWireInput(WorldInterface world, Vector pt, boolean isOn, Vector changed) {

        int type = world.getId(pt);

        // Minecart dispenser
        if (minecartDispensers && type == BlockType.CHEST
                && (world.getId(pt.add(0, -2, 0)) == BlockType.SIGN_POST
                || world.getId(pt.add(0, -1, 0)) == BlockType.SIGN_POST)) {

            // Rising edge-triggered only
            if (!isOn) {
                return;
            }

            Vector signPos = pt.add(0, -2, 0);

            SignInterface sign = getControllerSign(world, pt.add(0, -1, 0), "[Dispenser]");

            if (sign == null) {
                return;
            }

            String collectType = sign != null ? sign.getLine2() : "";
            boolean push = sign != null ? sign.getLine4().contains("Push") : false;

            Vector dir = MinecraftUtil.getSignPostOrthogonalBack(world, signPos, 1)
                    .subtract(signPos);
            Vector depositPt = pt.add(dir.multiply(2.5));

            /*if (CraftBook.getBlockID(depositPt) != BlockType.MINECART_TRACKS) {
                return;
            }*/

            NearbyChestBlockBag blockBag = new NearbyChestBlockBag(pt);
            blockBag.addSingleSourcePosition(world, pt);
            blockBag.addSingleSourcePosition(world, pt.add(1, 0, 0));
            blockBag.addSingleSourcePosition(world, pt.add(-1, 0, 0));
            blockBag.addSingleSourcePosition(world, pt.add(0, 0, 1));
            blockBag.addSingleSourcePosition(world, pt.add(0, 0, -1));

            try {
                MinecartInterface minecart;

                if (collectType.equalsIgnoreCase("Storage")) {
                    try {
                        blockBag.fetchBlock(ItemType.STORAGE_MINECART);
                    } catch (BlockBagException e) {
                        // Okay, no storage minecarts... but perhaps we can
                        // craft a minecart + chest!
                        if (blockBag.peekBlock(BlockType.CHEST)) {
                            blockBag.fetchBlock(ItemType.MINECART);
                            blockBag.fetchBlock(BlockType.CHEST);
                        } else {
                            throw new BlockBagException();
                        }
                    }

                    minecart = world.spawnMinecart(
                            depositPt.getX(),
                            depositPt.getY(),
                            depositPt.getZ(),
                            MinecartInterface.Type.STORAGE);
                } else if (collectType.equalsIgnoreCase("Powered")) {
                    try {
                        blockBag.fetchBlock(ItemType.POWERED_MINECART);
                    } catch (BlockBagException e) {
                        // Okay, no storage minecarts... but perhaps we can
                        // craft a minecart + chest!
                        if (blockBag.peekBlock(BlockType.FURNACE)) {
                            blockBag.fetchBlock(ItemType.MINECART);
                            blockBag.fetchBlock(BlockType.FURNACE);
                        } else {
                            throw new BlockBagException();
                        }
                    }

                    minecart = world.spawnMinecart(
                            depositPt.getX(),
                            depositPt.getY(),
                            depositPt.getZ(),
                            MinecartInterface.Type.POWERED);
                } else {
                    blockBag.fetchBlock(ItemType.MINECART);
                    minecart = world.spawnMinecart(
                            depositPt.getX(),
                            depositPt.getY(),
                            depositPt.getZ(),
                            MinecartInterface.Type.REGULAR);
                }

                if (push) {
                    int data = world.getData(signPos);

                    if (data == 0x0) {
                        minecart.setXSpeed(0);
                        minecart.setYSpeed(0);
                        minecart.setZSpeed(-0.3);
                    } else if (data == 0x4) {
                        minecart.setXSpeed(0.3);
                        minecart.setYSpeed(0);
                        minecart.setZSpeed(0);
                    } else if (data == 0x8) {
                        minecart.setXSpeed(0);
                        minecart.setYSpeed(0);
                        minecart.setZSpeed(0.3);
                    } else if (data == 0xC) {
                        minecart.setXSpeed(-0.3);
                        minecart.setYSpeed(0);
                        minecart.setZSpeed(0);
                    }
                }
            } catch (BlockBagException e) {
                // No minecarts
            }
            // Minecart station
        } else if (minecartControlBlocks && type == minecartStationBlock
                && world.getId(pt.add(0, 1, 0)) == BlockType.MINECART_TRACKS
                && (world.getId(pt.add(0, -2, 0)) == BlockType.SIGN_POST
                || world.getId(pt.add(0, -1, 0)) == BlockType.SIGN_POST)) {
            BlockEntity cblock = world.getBlockEntity(
                    pt.getBlockX(), pt.getBlockY() - 2, pt.getBlockZ());

            // Maybe it's the sign directly below
            if (cblock == null || !(cblock instanceof SignInterface)) {
                cblock = world.getBlockEntity(
                        pt.getBlockX(), pt.getBlockY() - 1, pt.getBlockZ());
            }

            if (cblock == null || !(cblock instanceof SignInterface)) {
                return;
            }

            SignInterface sign = (SignInterface) cblock;
            String line2 = sign.getLine2();

            if (!line2.equalsIgnoreCase("[Station]")) {
                return;
            }

            Vector motion;
            int data = world.getData(
                    pt.getBlockX(), cblock.getPosition().getBlockY(), pt.getBlockZ());

            if (data == 0x0) {
                motion = new Vector(0, 0, -0.3);
            } else if (data == 0x4) {
                motion = new Vector(0.3, 0, 0);
            } else if (data == 0x8) {
                motion = new Vector(0, 0, 0.3);
            } else if (data == 0xC) {
                motion = new Vector(-0.3, 0, 0);
            } else {
                return;
            }

            for (MinecartInterface minecart : world.getMinecartList()) {
                int cartX = (int) Math.floor(minecart.getX());
                int cartY = (int) Math.floor(minecart.getY());
                int cartZ = (int) Math.floor(minecart.getZ());

                if (cartX == pt.getBlockX()
                        && cartY == pt.getBlockY() + 1
                        && cartZ == pt.getBlockZ()) {
                    minecart.setXSpeed(motion.getX());
                    minecart.setYSpeed(motion.getY());
                    minecart.setZSpeed(motion.getZ());
                }
            }
        }
    }

    /**
     * Called when a vehicle changes block
     *
     * @param vehicle the vehicle
     * @param blockX  coordinate x
     * @param blockY  coordinate y
     * @param blockZ  coordinate z
     */
    @Override
    public void onMinecartPositionChange(WorldInterface world, MinecartInterface minecart,
                                         int blockX, int blockY, int blockZ) {

        if (!minecartControlBlocks && !minecartTrackMessages && !minecartDispensers) {
            return;
        }

        Vector underPt = new Vector(blockX, blockY - 1, blockZ);
        int under = world.getId(blockX, blockY - 1, blockZ);

        if (minecartControlBlocks) {
            // Overflow prevention
            if (Math.abs(minecart.getXSpeed()) > 100) {
                minecart.setXSpeed(Math.signum(minecart.getXSpeed()) * 100);
            }

            if (Math.abs(minecart.getZSpeed()) > 100) {
                minecart.setZSpeed(Math.signum(minecart.getZSpeed()) * 100);
            }

            if (under == minecart25xBoostBlock) {
                Boolean test = RedstoneUtil.testAnyInput(world, underPt);

                if (test == null || test) {
                    minecart.setXSpeed(minecart.getXSpeed() * 1.25);
                    minecart.setZSpeed(minecart.getZSpeed() * 1.25);
                    return;
                }
            } else if (under == minecart100xBoostBlock) {
                Boolean test = RedstoneUtil.testAnyInput(world, underPt);

                if (test == null || test) {
                    minecart.setXSpeed(minecart.getXSpeed() * 2);
                    minecart.setZSpeed(minecart.getZSpeed() * 2);
                    return;
                }
            } else if (under == minecart50xSlowBlock) {
                Boolean test = RedstoneUtil.testAnyInput(world, underPt);

                if (test == null || test) {
                    minecart.setXSpeed(minecart.getXSpeed() * 0.5);
                    minecart.setZSpeed(minecart.getZSpeed() * 0.5);
                    return;
                }
            } else if (under == minecart20xSlowBlock) {
                Boolean test = RedstoneUtil.testAnyInput(world, underPt);

                if (test == null || test) {
                    minecart.setXSpeed(minecart.getXSpeed() * 0.8);
                    minecart.setZSpeed(minecart.getZSpeed() * 0.8);
                    return;
                }
            } else if (under == minecartReverseBlock) {
                Boolean test = RedstoneUtil.testAnyInput(world, underPt);

                if (test == null || test) {
                    Vector signPos = new Vector(blockX, blockY - 2, blockZ);
                    boolean reverseX = true;
                    boolean reverseZ = true;

                    // Directed reverse block
                    if (world.getId(signPos) == BlockType.SIGN_POST
                            && MinecraftUtil.doesSignSay(world, signPos, 1, "[Reverse]")) {
                        Vector dir = MinecraftUtil.getSignPostOrthogonalBack(world, signPos, 1)
                                .subtract(signPos);

                        // Acceptable sign direction
                        if (dir != null) {
                            if (CraftBookUtil.isSameSign(minecart.getXSpeed(),
                                    dir.getBlockX())) {
                                reverseX = false;
                            }
                            if (CraftBookUtil.isSameSign(minecart.getZSpeed(),
                                    dir.getBlockZ())) {
                                reverseZ = false;
                            }
                        }
                    }

                    if (reverseX) {
                        minecart.setXSpeed(minecart.getXSpeed() * -1);
                    }
                    if (reverseZ) {
                        minecart.setZSpeed(minecart.getZSpeed() * -1);
                    }

                    return;
                }
            } else if (under == minecartDepositBlock) {
                Boolean test = RedstoneUtil.testAnyInput(world, underPt);

                if (test == null || test) {
                    if (minecart.getType() == MinecartInterface.Type.STORAGE) {
                        Vector pt = new Vector(blockX, blockY, blockZ);
                        NearbyChestBlockBag bag = new NearbyChestBlockBag(pt);

                        for (int y = -1; y <= 0; y++) {
                            bag.addSingleSourcePosition(world, pt.add(1, y, 0));
                            bag.addSingleSourcePosition(world, pt.add(2, y, 0));
                            bag.addSingleSourcePosition(world, pt.add(-1, y, 0));
                            bag.addSingleSourcePosition(world, pt.add(-2, y, 0));
                            bag.addSingleSourcePosition(world, pt.add(0, y, 1));
                            bag.addSingleSourcePosition(world, pt.add(0, y, 2));
                            bag.addSingleSourcePosition(world, pt.add(0, y, -1));
                            bag.addSingleSourcePosition(world, pt.add(0, y, -2));
                        }

                        if (bag.getChestBlockCount() > 0) {
                            if (getControllerSign(world, pt.add(0, -1, 0), "[Deposit]") != null) {
                                InventoryUtil.moveChestBagToItemArray(
                                        (StorageMinecartInterface) minecart, bag);
                            } else {
                                InventoryUtil.moveItemArrayToChestBag(
                                        (StorageMinecartInterface) minecart, bag);
                            }
                        }
                    }
                }

                return;
            } else if (under == minecartEjectBlock) {
                Boolean test = RedstoneUtil.testAnyInput(world, underPt);

                if (test == null || test) {
                    PlayerInterface player = minecart.getPlayer();
                    if (player != null) {
                        // Let's find a place to put the player
                        Tuple3<Integer, Integer, Integer> loc =
                                new Tuple3<Integer, Integer, Integer>(blockX, blockY, blockZ);
                        Vector signPos = new Vector(blockX, blockY - 2, blockZ);

                        if (world.getId(signPos) == BlockType.SIGN_POST
                                && MinecraftUtil.doesSignSay(world, signPos, 1, "[Eject]")) {
                            Vector pos = MinecraftUtil.getSignPostOrthogonalBack(world, signPos, 1);

                            // Acceptable sign direction
                            if (pos != null) {
                                pos = pos.setY(blockY);

                                // Is the spot free?
                                if (BlockType.canPassThrough(world.getId(pos.add(0, 1, 0)))
                                        && BlockType.canPassThrough(world.getId(pos))) {
                                    loc = new Tuple3<Integer, Integer, Integer>(
                                            pos.getBlockX(),
                                            pos.getBlockY(),
                                            pos.getBlockZ());

                                    BlockEntity cBlock = world.getBlockEntity(
                                            blockX, blockY - 2, blockZ);

                                    if (cBlock instanceof SignInterface) {
                                        SignInterface sign = (SignInterface) cBlock;
                                        String text = sign.getLine1();
                                        if (text.length() > 0) {
                                            player.sendMessage(Colors.GOLD + "You've arrived at: "
                                                    + text);
                                        }
                                    }
                                }
                            }
                        }

                        player.setX(loc.a + 0.5);
                        player.setY(loc.b + 0.1);
                        player.setX(loc.c + 0.5);
                    }
                }

                return;
            } else if (under == minecartSortBlock) {
                Boolean test = RedstoneUtil.testAnyInput(world, underPt);

                if (test == null || test) {
                    SignInterface sign =
                            getControllerSign(world, blockX, blockY - 1, blockZ, "[Sort]");

                    if (sign != null) {
                        SortDir dir = SortDir.FORWARD;

                        if (satisfiesCartSort(sign.getLine3(), minecart,
                                new Vector(blockX, blockY, blockZ))) {
                            dir = SortDir.LEFT;
                        } else if (satisfiesCartSort(sign.getLine4(), minecart,
                                new Vector(blockX, blockY, blockZ))) {
                            dir = SortDir.RIGHT;
                        }

                        int signData = world.getData(
                                sign.getX(), sign.getY(), sign.getZ());
                        int newData = 0;
                        Vector targetTrack = null;

                        if (signData == 0x8) { // West
                            if (dir == SortDir.LEFT) {
                                newData = 9;
                            } else if (dir == SortDir.RIGHT) {
                                newData = 8;
                            } else {
                                newData = 0;
                            }
                            targetTrack = new Vector(blockX, blockY, blockZ + 1);
                        } else if (signData == 0x0) { // East
                            if (dir == SortDir.LEFT) {
                                newData = 7;
                            } else if (dir == SortDir.RIGHT) {
                                newData = 6;
                            } else {
                                newData = 0;
                            }
                            targetTrack = new Vector(blockX, blockY, blockZ - 1);
                        } else if (signData == 0xC) { // North
                            if (dir == SortDir.LEFT) {
                                newData = 6;
                            } else if (dir == SortDir.RIGHT) {
                                newData = 9;
                            } else {
                                newData = 1;
                            }
                            targetTrack = new Vector(blockX - 1, blockY, blockZ);
                        } else if (signData == 0x4) { // South
                            if (dir == SortDir.LEFT) {
                                newData = 8;
                            } else if (dir == SortDir.RIGHT) {
                                newData = 7;
                            } else {
                                newData = 1;
                            }
                            targetTrack = new Vector(blockX + 1, blockY, blockZ);
                        }

                        if (targetTrack != null
                                && world.getId(targetTrack) == BlockType.MINECART_TRACKS) {
                            world.setData(targetTrack, newData);
                        }
                    }
                }

                return;
            }
        }

        if (minecartTrackMessages
                && world.getId(underPt.add(0, -1, 0)) == BlockType.SIGN_POST) {
            Vector signPos = underPt.add(0, -1, 0);

            Boolean test = RedstoneUtil.testAnyInput(world, signPos);

            if (test == null || test) {
                BlockEntity cblock = world.getBlockEntity(
                        signPos.getBlockX(), signPos.getBlockY(), signPos.getBlockZ());

                if (!(cblock instanceof SignInterface)) {
                    return;
                }

                SignInterface sign = (SignInterface) cblock;
                String line1 = sign.getLine1();

                if (line1.equalsIgnoreCase("[Print]")) {
                    if (!minecart.hasPlayer()) {
                        return;
                    }
                    PlayerInterface player = minecart.getPlayer();

                    String name = player.getName();
                    String msg = sign.getLine2() + sign.getLine3() + sign.getLine4();
                    long now = System.currentTimeMillis();

                    if (lastMinecartMsg.containsKey(name)) {
                        String lastMessage = lastMinecartMsg.get(name);
                        if (lastMessage.equals(msg)
                                && now < lastMinecartMsgTime.get(name) + 3000) {
                            return;
                        }
                    }

                    lastMinecartMsg.put(name, msg);
                    lastMinecartMsgTime.put(name, now);
                    player.sendMessage("> " + msg);
                }
            }
        }

        if (minecartDispensers) {
            Vector pt = new Vector(blockX, blockY, blockZ);
            Vector depositPt = null;

            if (world.getId(pt.add(1, 0, 0)) == BlockType.CHEST
                    && (world.getId(pt.add(-1, 0, 0)) == BlockType.MINECART_TRACKS
                    || world.getId(pt.add(-1, -1, 0)) == BlockType.MINECART_TRACKS
                    || world.getId(pt.add(-1, 1, 0)) == BlockType.MINECART_TRACKS)) {
                depositPt = pt.add(1, 0, 0);
            } else if (world.getId(pt.add(-1, 0, 0)) == BlockType.CHEST
                    && (world.getId(pt.add(1, 0, 0)) == BlockType.MINECART_TRACKS
                    || world.getId(pt.add(1, -1, 0)) == BlockType.MINECART_TRACKS
                    || world.getId(pt.add(1, 1, 0)) == BlockType.MINECART_TRACKS)) {
                depositPt = pt.add(-1, 0, 0);
            } else if (world.getId(pt.add(0, 0, 1)) == BlockType.CHEST
                    && (world.getId(pt.add(0, 0, -1)) == BlockType.MINECART_TRACKS
                    || world.getId(pt.add(0, -1, -1)) == BlockType.MINECART_TRACKS
                    || world.getId(pt.add(0, 1, -1)) == BlockType.MINECART_TRACKS)) {
                depositPt = pt.add(0, 0, 1);
            } else if (world.getId(pt.add(0, 0, -1)) == BlockType.CHEST
                    && (world.getId(pt.add(0, 0, 1)) == BlockType.MINECART_TRACKS
                    || world.getId(pt.add(0, -1, 1)) == BlockType.MINECART_TRACKS
                    || world.getId(pt.add(0, 1, 1)) == BlockType.MINECART_TRACKS)) {
                depositPt = pt.add(0, 0, -1);
            }

            if (depositPt != null) {
                SignInterface sign =
                        getControllerSign(world, depositPt.add(0, -1, 0), "[Dispenser]");
                String collectType = sign != null ? sign.getLine2() : "";

                NearbyChestBlockBag blockBag = new NearbyChestBlockBag(depositPt);
                blockBag.addSingleSourcePosition(world, depositPt);
                blockBag.addSingleSourcePosition(world, depositPt.add(1, 0, 0));
                blockBag.addSingleSourcePosition(world, depositPt.add(-1, 0, 0));
                blockBag.addSingleSourcePosition(world, depositPt.add(0, 0, 1));
                blockBag.addSingleSourcePosition(world, depositPt.add(0, 0, -1));

                MinecartInterface.Type type = minecart.getType();

                if (type == MinecartInterface.Type.REGULAR) {
                    try {
                        blockBag.storeBlock(ItemType.MINECART);
                        minecart.remove();
                    } catch (BlockBagException e) {
                    }
                } else if (type == MinecartInterface.Type.STORAGE) {
                    try {
                        InventoryUtil.moveItemArrayToChestBag(
                                (StorageMinecartInterface) minecart, blockBag);

                        if (collectType.equalsIgnoreCase("Storage")) {
                            blockBag.storeBlock(ItemType.STORAGE_MINECART);
                        } else {
                            blockBag.storeBlock(ItemType.MINECART);
                            blockBag.storeBlock(BlockType.CHEST);
                        }

                        minecart.remove();
                    } catch (BlockBagException e) {
                        // Ran out of space
                    }
                } else if (type == MinecartInterface.Type.POWERED) {
                    try {
                        if (collectType.equalsIgnoreCase("Powered")) {
                            blockBag.storeBlock(ItemType.POWERED_MINECART);
                        } else {
                            blockBag.storeBlock(ItemType.MINECART);
                            blockBag.storeBlock(BlockType.FURNACE);
                        }
                        minecart.remove();
                    } catch (BlockBagException e) {
                        // Ran out of space
                    }
                }

                blockBag.flushChanges();
            }
        }
    }

    /**
     * Called when a vehicle enters or leaves a block
     *
     * @param vehicle the vehicle
     */
    @Override
    public void onMinecartVelocityChange(WorldInterface world, MinecartInterface minecart) {

        if (!minecartControlBlocks && !unoccupiedCoast) {
            return;
        }

        int blockX = (int) Math.floor(minecart.getX());
        int blockY = (int) Math.floor(minecart.getY());
        int blockZ = (int) Math.floor(minecart.getZ());
        Vector underPt = new Vector(blockX, blockY - 1, blockZ);
        int under = world.getId(blockX, blockY - 1, blockZ);

        if (minecartControlBlocks) {
            if (under == minecartStationBlock) {
                Boolean test = RedstoneUtil.testAnyInput(world, underPt);

                if (test != null) {
                    if (!test) {
                        minecart.setXSpeed(0);
                        minecart.setYSpeed(0);
                        minecart.setZSpeed(0);
                        return;
                    } else {
                        BlockEntity cblock = world.getBlockEntity(
                                blockX, blockY - 2, blockZ);

                        // Maybe it's the sign directly below
                        if (cblock == null || !(cblock instanceof SignInterface)) {
                            cblock = world.getBlockEntity(
                                    blockX, blockY - 3, blockZ);
                        }

                        if (cblock != null && cblock instanceof SignInterface) {
                            SignInterface sign = (SignInterface) cblock;
                            String line2 = sign.getLine2();

                            if (!line2.equalsIgnoreCase("[Station]")) {
                                return;
                            }

                            String line3 = sign.getLine3();
                            String line4 = sign.getLine4();

                            if (line3.equalsIgnoreCase("Pulse")
                                    || line4.equalsIgnoreCase("Pulse")) {
                                return;
                            }

                            Vector motion = null;
                            int data = world.getData(
                                    blockX, cblock.getPosition().getBlockY(), blockZ);

                            if (data == 0x0) {
                                motion = new Vector(0, 0, -0.3);
                            } else if (data == 0x4) {
                                motion = new Vector(0.3, 0, 0);
                            } else if (data == 0x8) {
                                motion = new Vector(0, 0, 0.3);
                            } else if (data == 0xC) {
                                motion = new Vector(-0.3, 0, 0);
                            }

                            if (motion != null) {
                                if (!CraftBookUtil.isSameSign(minecart.getXSpeed(), motion.getX())
                                        || minecart.getXSpeed() < motion.getX()) {
                                    minecart.setXSpeed(motion.getX());
                                }
                                if (!CraftBookUtil.isSameSign(minecart.getYSpeed(), motion.getY())
                                        || minecart.getYSpeed() < motion.getY()) {
                                    minecart.setYSpeed(motion.getY());
                                }
                                if (!CraftBookUtil.isSameSign(minecart.getZSpeed(), motion.getZ())
                                        || minecart.getZSpeed() < motion.getZ()) {
                                    minecart.setZSpeed(motion.getZ());
                                }

                                return;
                            }
                        }
                    }
                }
            }
        }

        int block = world.getId(blockX, blockY, blockZ);
        if (slickPressurePlates
                && (block == BlockType.STONE_PRESSURE_PLATE
                || block == BlockType.WOODEN_PRESSURE_PLATE)) {
            // Numbers from code
            minecart.setXSpeed(minecart.getXSpeed() / 0.55);
            minecart.setYSpeed(0);
            minecart.setZSpeed(minecart.getZSpeed() / 0.55);
        }

        if (unoccupiedCoast && minecart.getPlayer() == null) {
            minecart.setXSpeed(minecart.getXSpeed() * 1.018825);
            minecart.setZSpeed(minecart.getZSpeed() * 1.018825);
        }
    }

    /**
     * Called when vehicle receives damage
     *
     * @param vehicle
     * @param attacker entity that dealt the damage
     * @param damage
     *
     * @return false to set damage
     */
    @Override
    public boolean onMinecartDamage(WorldInterface world, MinecartInterface cart,
                                    BaseEntityInterface attacker, int damage) {

        if (!inCartControl) {
            return false;
        }

        PlayerInterface passenger = cart.getPlayer();

        // Player.equals() now works correctly as of recent hMod versions
        if (passenger != null) {
            double speed2 = cart.getXSpeed() * cart.getXSpeed() +
                    cart.getYSpeed() * cart.getYSpeed() +
                    cart.getZSpeed() * cart.getZSpeed();

            if (speed2 > 0.01 * 0.01) { // Stop the cart
                cart.setXSpeed(0);
                cart.setYSpeed(0);
                cart.setZSpeed(0);
            } else {
                // From hey0's code, and then stolen from WorldEdit
                double rot = (passenger.getYaw() - 90) % 360;
                if (rot < 0) {
                    rot += 360.0;
                }

                if (0 <= rot && rot < 22.5) {
                    cart.setXSpeed(-0.1);
                    cart.setYSpeed(0);
                    cart.setZSpeed(0);
                } else if (22.5 <= rot && rot < 67.5) {
                    cart.setXSpeed(-0.1);
                    cart.setYSpeed(0);
                    cart.setZSpeed(-0.1);
                } else if (67.5 <= rot && rot < 112.5) {
                    cart.setXSpeed(0);
                    cart.setYSpeed(0);
                    cart.setZSpeed(-0.1);
                } else if (112.5 <= rot && rot < 157.5) {
                    cart.setXSpeed(0.1);
                    cart.setYSpeed(0);
                    cart.setZSpeed(-0.1);
                } else if (157.5 <= rot && rot < 202.5) {
                    cart.setXSpeed(0.1);
                    cart.setYSpeed(0);
                    cart.setZSpeed(0);
                } else if (202.5 <= rot && rot < 247.5) {
                    cart.setXSpeed(0.1);
                    cart.setYSpeed(0);
                    cart.setZSpeed(0.1);
                } else if (247.5 <= rot && rot < 292.5) {
                    cart.setXSpeed(0);
                    cart.setYSpeed(0);
                    cart.setZSpeed(0.1);
                } else if (292.5 <= rot && rot < 337.5) {
                    cart.setXSpeed(-0.1);
                    cart.setYSpeed(0);
                    cart.setZSpeed(0.1);
                } else if (337.5 <= rot && rot < 360.0) {
                    cart.setXSpeed(-0.1);
                    cart.setYSpeed(0);
                    cart.setZSpeed(0);
                }
            }

            return true;
        }

        return false;
    }

    /**
     * Called when someone places a block. Return true to prevent the placement.
     *
     * @param player
     * @param blockPlaced
     * @param blockClicked
     * @param itemInHand
     *
     * @return true if you want to undo the block placement
     */
    public boolean onBlockPlace(WorldInterface world, PlayerInterface player,
                                Vector blockPlaced, Vector blockClicked, int itemInHand) {

        if (world.getId(blockPlaced) == BlockType.MINECART_TRACKS) {
            int under = world.getId(blockPlaced.getBlockX(),
                    blockPlaced.getBlockY() - 1, blockPlaced.getBlockZ());

            if (minecartControlBlocks && under == minecartStationBlock) {
                SignInterface sign = getControllerSign(world, blockPlaced.getBlockX(),
                        blockPlaced.getBlockY() - 1, blockPlaced.getBlockZ(), "[Station]");
                Vector pt = new Vector(blockPlaced.getX(),
                        blockPlaced.getBlockY() - 1, blockPlaced.getBlockZ());

                boolean needsRedstone = RedstoneUtil.testAnyInput(world, pt) == null;

                if (sign == null && needsRedstone) {
                    player.sendMessage(Colors.GOLD
                            + "Two things to do: Wire the block and place a [Station] sign.");
                } else if (sign == null) {
                    player.sendMessage(Colors.RED
                            + "Place a [Station] sign 1-2 blocks underneath.");
                } else if (needsRedstone) {
                    player.sendMessage(Colors.RED
                            + "To make the station work, wire it up with redstone.");
                } else {
                    player.sendMessage(Colors.RED
                            + "Minecart station created.");
                }
            } else if (minecartControlBlocks && under == minecart25xBoostBlock) {
                player.sendMessage(Colors.GOLD + "Minecart boost block created.");
            } else if (minecartControlBlocks && under == minecart100xBoostBlock) {
                player.sendMessage(Colors.GOLD + "Minecart boost block created.");
            } else if (minecartControlBlocks && under == minecart50xSlowBlock) {
                player.sendMessage(Colors.GOLD + "Minecart brake block created.");
            } else if (minecartControlBlocks && under == minecart20xSlowBlock) {
                player.sendMessage(Colors.GOLD + "Minecart brake block created.");
            } else if (minecartControlBlocks && under == minecartReverseBlock) {
                player.sendMessage(Colors.GOLD + "Minecart reverse block created.");
            } else if (minecartControlBlocks && under == minecartSortBlock) {
                SignInterface sign = getControllerSign(world, blockPlaced.getBlockX(),
                        blockPlaced.getBlockY() - 1, blockPlaced.getBlockZ(), "[Sort]");
                //Vector pt = new Vector(blockPlaced.getX(),
                //    blockPlaced.getY() - 1, blockPlaced.getZ());

                if (sign == null) {
                    player.sendMessage(Colors.RED
                            + "A [Sort] sign is still needed.");
                } else {
                    player.sendMessage(Colors.GOLD
                            + "Minecart sort block created.");
                }
            }
        }

        return false;
    }

    /**
     * Called when a sign is updated.
     *
     * @param player
     * @param cblock
     *
     * @return
     */
    public boolean onSignChange(PlayerInterface player, WorldInterface world, Vector v, SignInterface s) {

        int type = world.getId(
                s.getX(), s.getY(), s.getZ());

        String line1 = s.getLine1();
        String line2 = s.getLine2();

        // Station
        if (line2.equalsIgnoreCase("[Station]")) {
            craftBook.informUser(player);

            s.setLine2("[Station]");
            s.flushChanges();

            if (minecartControlBlocks) {
                int data = world.getData(
                        s.getX(), s.getY(), s.getZ());

                if (type == BlockType.WALL_SIGN) {
                    player.sendMessage(Colors.RED + "The sign must be a sign post.");
                    MinecraftUtil.dropSign(world, s.getX(), s.getY(), s.getZ());
                    return true;
                } else if (data != 0x0 && data != 0x4 && data != 0x8 && data != 0xC) {
                    player.sendMessage(Colors.RED + "The sign cannot be at an odd angle.");
                    MinecraftUtil.dropSign(world, s.getX(), s.getY(), s.getZ());
                    return true;
                }

                player.sendMessage(Colors.GOLD + "Station sign detected.");
            } else {
                player.sendMessage(Colors.RED
                        + "Minecart control blocks are disabled on this server.");
            }
            // Sort
        } else if (line2.equalsIgnoreCase("[Sort]")) {
            craftBook.informUser(player);

            s.setLine2("[Sort]");
            s.flushChanges();

            if (minecartControlBlocks) {
                int data = world.getData(
                        s.getX(), s.getY(), s.getZ());

                if (type == BlockType.WALL_SIGN) {
                    player.sendMessage(Colors.RED + "The sign must be a sign post.");
                    MinecraftUtil.dropSign(world, s.getX(), s.getY(), s.getZ());
                    return true;
                } else if (data != 0x0 && data != 0x4 && data != 0x8 && data != 0xC) {
                    player.sendMessage(Colors.RED + "The sign cannot be at an odd angle.");
                    MinecraftUtil.dropSign(world, s.getX(), s.getY(), s.getZ());
                    return true;
                }

                player.sendMessage(Colors.GOLD + "Sort sign detected.");
            } else {
                player.sendMessage(Colors.RED
                        + "Minecart control blocks are disabled on this server.");
            }
            // Dispenser
        } else if (line2.equalsIgnoreCase("[Dispenser]")) {
            craftBook.informUser(player);

            s.setLine2("[Dispenser]");
            s.flushChanges();

            player.sendMessage(Colors.GOLD + "Dispenser sign detected.");
            // Print
        } else if (line1.equalsIgnoreCase("[Print]")) {
            craftBook.informUser(player);

            s.setLine1("[Print]");
            s.flushChanges();

            player.sendMessage(Colors.GOLD + "Message print block detected.");
        }

        return false;
    }

    /**
     * Called when a player enter or leaves a vehicle
     *
     * @param vehicle the vehicle
     * @param player  the player
     */
    public void onMinecartEnter(WorldInterface world, MinecartInterface cart,
                                BaseEntityInterface entity, boolean entering) {

        if (decayWatcher != null) {
            decayWatcher.trackEnter(world, cart);
        }

        if (minecartDestroyOnExit && entering) {
            cart.remove();

            if (minecartDropOnExit && cart.getPlayer() != null) {
                cart.getPlayer().giveItem(ItemType.MINECART, 1);
            }
        }
    }

    /**
     * Called when a vehicle is destroyed
     *
     * @param vehicle the vehicle
     */
    public void onMinecartDestroyed(WorldInterface world, MinecartInterface cart) {

        if (decayWatcher != null) {
            decayWatcher.forgetMinecart(cart);
        }
    }

    public void onWorldUnload(WorldInterface world) {

        decayWatcher.removeWorld(world);
    }

    /**
     * Called on plugin unload.
     */
    public void disable() {

        if (decayWatcher != null) {
            decayWatcher.disable();
        }
    }

    /**
     * Get the controller sign for a block type. The coordinates provided
     * are those of the block (signs are to be underneath). The provided
     * text must be on the second line of the sign.
     *
     * @param pt
     * @param text
     *
     * @return
     */
    private SignInterface getControllerSign(WorldInterface w, Vector pt, String text) {

        return getControllerSign(w, pt.getBlockX(), pt.getBlockY(),
                pt.getBlockZ(), text);
    }

    /**
     * Get the controller sign for a block type. The coordinates provided
     * are those of the block (signs are to be underneath). The provided
     * text must be on the second line of the sign.
     *
     * @param x
     * @param y
     * @param z
     * @param text
     *
     * @return
     */
    private SignInterface getControllerSign(WorldInterface w, int x, int y, int z, String text) {

        BlockEntity cblock = w.getBlockEntity(x, y - 1, z);

        if (cblock instanceof SignInterface
                && ((SignInterface) cblock).getLine2().equalsIgnoreCase(text)) {
            return (SignInterface) cblock;
        }

        cblock = w.getBlockEntity(x, y - 2, z);

        if (cblock instanceof SignInterface
                && ((SignInterface) cblock).getLine2().equalsIgnoreCase(text)) {
            return (SignInterface) cblock;
        }

        return null;
    }

    /**
     * Returns true if a filter line satisfies the conditions.
     *
     * @param line
     * @param minecart
     * @param trackPos
     *
     * @return
     */
    public boolean satisfiesCartSort(String line, MinecartInterface minecart, Vector trackPos) {

        PlayerInterface player = minecart.getPlayer();

        if (line.equalsIgnoreCase("All")) {
            return true;
        }

        if ((line.equalsIgnoreCase("Unoccupied")
                || line.equalsIgnoreCase("Empty"))
                && !minecart.hasPassenger()) {
            return true;
        }

        if (line.equalsIgnoreCase("Storage")
                && minecart.getType() == MinecartInterface.Type.STORAGE) {
            return true;
        }

        if (line.equalsIgnoreCase("Powered")
                && minecart.getType() == MinecartInterface.Type.POWERED) {
            return true;
        }

        if (line.equalsIgnoreCase("Minecart")
                && minecart.getType() == MinecartInterface.Type.REGULAR) {
            return true;
        }

        if ((line.equalsIgnoreCase("Occupied")
                || line.equalsIgnoreCase("Full"))
                && minecart.hasPassenger()) {
            return true;
        }

        if (line.equalsIgnoreCase("Animal")
                && minecart.hasAnimal()) {
            return true;
        }

        if (line.equalsIgnoreCase("Mob")
                && minecart.hasMob()) {
            return true;
        }

        if ((line.equalsIgnoreCase("Player")
                || line.equalsIgnoreCase("Ply"))
                && minecart.hasPlayer()) {
            return true;
        }

        if (minecart.hasPlayer()) {
            String stop = stopStation.get(player.getName());
            if (stop != null && stop.equals(line)) {
                return true;
            }
        }

        String[] parts = line.split(":");

        if (parts.length >= 2) {
            if (minecart.hasPlayer() && parts[0].equalsIgnoreCase("Held")) {
                try {
                    int item = Integer.parseInt(parts[1]);
                    if (player.getItemInHand() == item) {
                        return true;
                    }
                } catch (NumberFormatException e) {
                }
            } else if (minecart.hasPlayer() && parts[0].equalsIgnoreCase("Group")) {
                if (player.isInGroup(parts[1])) {
                    return true;
                }
            } else if (minecart.hasPlayer() && parts[0].equalsIgnoreCase("Ply")) {
                if (parts[1].equalsIgnoreCase(player.getName())) {
                    return true;
                }
            } else if (parts[0].equalsIgnoreCase("Mob")) {
                String testMob = parts[1];
                minecart.isMobType(testMob);
            }
        }

        return false;
    }

    /**
     * @param player
     */
    @Override
    public void onDisconnect(PlayerInterface player) {

        lastMinecartMsg.remove(player.getName());
        lastMinecartMsgTime.remove(player.getName());
        stopStation.remove(player.getName());
    }
}
TOP

Related Classes of com.sk89q.craftbook.VehicleListener

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.