net.countercraft.movecraft.async.rotation.RotationTask.java Source code

Java tutorial

Introduction

Here is the source code for net.countercraft.movecraft.async.rotation.RotationTask.java

Source

/*
 * This file is part of Movecraft.
 *
 *     Movecraft 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.
 *
 *     Movecraft 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 Movecraft.  If not, see <http://www.gnu.org/licenses/>.
 */

package net.countercraft.movecraft.async.rotation;

import com.palmergames.bukkit.towny.object.Town;
import com.palmergames.bukkit.towny.object.TownBlock;
import com.palmergames.bukkit.towny.object.TownyWorld;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.StateFlag;

import net.countercraft.movecraft.Movecraft;
import net.countercraft.movecraft.async.AsyncTask;
import net.countercraft.movecraft.config.Settings;
import net.countercraft.movecraft.craft.Craft;
import net.countercraft.movecraft.craft.CraftManager;
import net.countercraft.movecraft.localisation.I18nSupport;
import net.countercraft.movecraft.utils.BlockUtils;
import net.countercraft.movecraft.utils.EntityUpdateCommand;
import net.countercraft.movecraft.utils.MapUpdateCommand;
import net.countercraft.movecraft.utils.MapUpdateManager;
import net.countercraft.movecraft.utils.MathUtils;
import net.countercraft.movecraft.utils.MovecraftLocation;
import net.countercraft.movecraft.utils.Rotation;

import org.apache.commons.collections.ListUtils;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;

import net.countercraft.movecraft.utils.TownyUtils;
import net.countercraft.movecraft.utils.TownyWorldHeightLimits;
import net.countercraft.movecraft.utils.WGCustomFlagsUtils;

import org.bukkit.Material;

public class RotationTask extends AsyncTask {
    private final MovecraftLocation originPoint;
    private boolean failed = false;
    private String failMessage;
    private MovecraftLocation[] blockList; // used to be final, not sure why. Changed by Mark / Loraxe42
    private MapUpdateCommand[] updates;
    private EntityUpdateCommand[] entityUpdates;
    private int[][][] hitbox;
    private Integer minX, minZ;
    private final Rotation rotation;
    private final World w;
    private final boolean isSubCraft;
    private HashMap<MapUpdateCommand, Long> scheduledBlockChanges;

    public RotationTask(Craft c, MovecraftLocation originPoint, MovecraftLocation[] blockList, Rotation rotation,
            World w) {
        super(c);
        this.originPoint = originPoint;
        this.blockList = blockList;
        this.rotation = rotation;
        this.w = w;
        this.isSubCraft = false;
    }

    public RotationTask(Craft c, MovecraftLocation originPoint, MovecraftLocation[] blockList, Rotation rotation,
            World w, boolean isSubCraft) {
        super(c);
        this.originPoint = originPoint;
        this.blockList = blockList;
        this.rotation = rotation;
        this.w = w;
        this.isSubCraft = isSubCraft;
    }

    @Override
    public void excecute() {

        int waterLine = 0;

        int[][][] hb = getCraft().getHitBox();
        if (hb == null)
            return;

        // Determine craft borders
        int minY = 65535;
        int maxY = -65535;
        for (int[][] i1 : hb) {
            for (int[] i2 : i1) {
                if (i2 != null) {
                    if (i2[0] < minY) {
                        minY = i2[0];
                    }
                    if (i2[1] > maxY) {
                        maxY = i2[1];
                    }
                }
            }
        }
        Integer maxX = getCraft().getMinX() + hb.length;
        Integer maxZ = getCraft().getMinZ() + hb[0].length; // safe because if the first x array doesn't have a z array, then it wouldn't be the first x array
        minX = getCraft().getMinX();
        minZ = getCraft().getMinZ();

        int distX = maxX - minX;
        int distZ = maxZ - minZ;

        Player craftPilot = CraftManager.getInstance().getPlayerFromCraft(getCraft());

        if (getCraft().getDisabled() && (!getCraft().getSinking())) {
            failed = true;
            failMessage = String.format(I18nSupport.getInternationalisedString("Craft is disabled!"));
        }

        // blockedByWater=false means an ocean-going vessel
        boolean waterCraft = !getCraft().getType().blockedByWater();

        if (waterCraft) {
            // next figure out the water level by examining blocks next to the outer boundaries of the craft
            for (int posY = maxY; (posY >= minY) && (waterLine == 0); posY--) {
                int posX;
                int posZ;
                posZ = getCraft().getMinZ() - 1;
                for (posX = getCraft().getMinX() - 1; (posX <= maxX + 1) && (waterLine == 0); posX++) {
                    if (w.getBlockAt(posX, posY, posZ).getTypeId() == 9) {
                        waterLine = posY;
                    }
                }
                posZ = maxZ + 1;
                for (posX = getCraft().getMinX() - 1; (posX <= maxX + 1) && (waterLine == 0); posX++) {
                    if (w.getBlockAt(posX, posY, posZ).getTypeId() == 9) {
                        waterLine = posY;
                    }
                }
                posX = getCraft().getMinX() - 1;
                for (posZ = getCraft().getMinZ(); (posZ <= maxZ) && (waterLine == 0); posZ++) {
                    if (w.getBlockAt(posX, posY, posZ).getTypeId() == 9) {
                        waterLine = posY;
                    }
                }
                posX = maxX + 1;
                for (posZ = getCraft().getMinZ(); (posZ <= maxZ) && (waterLine == 0); posZ++) {
                    if (w.getBlockAt(posX, posY, posZ).getTypeId() == 9) {
                        waterLine = posY;
                    }
                }
            }

            // now add all the air blocks found within the crafts borders below the waterline to the craft blocks so they will be rotated
            HashSet<MovecraftLocation> newHSBlockList = new HashSet<MovecraftLocation>(Arrays.asList(blockList));
            for (int posY = waterLine; posY >= minY; posY--) {
                for (int posX = getCraft().getMinX(); posX <= maxX; posX++) {
                    for (int posZ = getCraft().getMinZ(); posZ <= maxZ; posZ++) {
                        if (w.getBlockAt(posX, posY, posZ).getTypeId() == 0) {
                            MovecraftLocation l = new MovecraftLocation(posX, posY, posZ);
                            newHSBlockList.add(l);
                        }
                    }
                }
            }
            blockList = newHSBlockList.toArray(new MovecraftLocation[newHSBlockList.size()]);
        }

        // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal
        double fuelBurnRate = getCraft().getType().getFuelBurnRate();
        if (fuelBurnRate != 0.0 && getCraft().getSinking() == false) {
            if (getCraft().getBurningFuel() < fuelBurnRate) {
                Block fuelHolder = null;
                for (MovecraftLocation bTest : blockList) {
                    Block b = getCraft().getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ());
                    if (b.getTypeId() == 61) {
                        InventoryHolder inventoryHolder = (InventoryHolder) b.getState();
                        if (inventoryHolder.getInventory().contains(263)
                                || inventoryHolder.getInventory().contains(173)) {
                            fuelHolder = b;
                        }
                    }
                }
                if (fuelHolder == null) {
                    failed = true;
                    failMessage = String.format(
                            I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel"));
                } else {
                    InventoryHolder inventoryHolder = (InventoryHolder) fuelHolder.getState();
                    if (inventoryHolder.getInventory().contains(263)) {
                        ItemStack iStack = inventoryHolder.getInventory()
                                .getItem(inventoryHolder.getInventory().first(263));
                        int amount = iStack.getAmount();
                        if (amount == 1) {
                            inventoryHolder.getInventory().remove(iStack);
                        } else {
                            iStack.setAmount(amount - 1);
                        }
                        getCraft().setBurningFuel(getCraft().getBurningFuel() + 7.0);
                    } else {
                        ItemStack iStack = inventoryHolder.getInventory()
                                .getItem(inventoryHolder.getInventory().first(173));
                        int amount = iStack.getAmount();
                        if (amount == 1) {
                            inventoryHolder.getInventory().remove(iStack);
                        } else {
                            iStack.setAmount(amount - 1);
                        }
                        getCraft().setBurningFuel(getCraft().getBurningFuel() + 79.0);

                    }
                }
            } else {
                getCraft().setBurningFuel(getCraft().getBurningFuel() - fuelBurnRate);
            }
        }

        // Rotate the block set
        MovecraftLocation[] centeredBlockList = new MovecraftLocation[blockList.length];
        MovecraftLocation[] originalBlockList = blockList.clone();
        HashSet<MovecraftLocation> existingBlockSet = new HashSet<MovecraftLocation>(
                Arrays.asList(originalBlockList));
        Set<MapUpdateCommand> mapUpdates = new HashSet<MapUpdateCommand>();
        HashSet<EntityUpdateCommand> entityUpdateSet = new HashSet<EntityUpdateCommand>();

        boolean townyEnabled = Movecraft.getInstance().getTownyPlugin() != null;
        Set<TownBlock> townBlockSet = new HashSet<TownBlock>();
        TownyWorld townyWorld = null;
        TownyWorldHeightLimits townyWorldHeightLimits = null;

        if (townyEnabled && Settings.TownyBlockMoveOnSwitchPerm) {
            townyWorld = TownyUtils.getTownyWorld(getCraft().getW());
            if (townyWorld != null) {
                townyEnabled = townyWorld.isUsingTowny();
                if (townyEnabled)
                    townyWorldHeightLimits = TownyUtils.getWorldLimits(getCraft().getW());
            }
        } else {
            townyEnabled = false;
        }

        // if a subcraft, find the parent craft. If not a subcraft, it is it's own parent
        Craft[] craftsInWorld = CraftManager.getInstance().getCraftsInWorld(getCraft().getW());
        Craft parentCraft = getCraft();
        for (Craft craft : craftsInWorld) {
            if (BlockUtils.arrayContainsOverlap(craft.getBlockList(), originalBlockList) && craft != getCraft()) {
                // found a parent craft
                //            if(craft.isNotProcessing()==false) {
                //               failed=true;
                //               failMessage = String.format( I18nSupport.getInternationalisedString( "Parent Craft is busy" ));
                //               return;
                //            } else {
                //               craft.setProcessing(true); // prevent the parent craft from moving or updating until the subcraft is done
                parentCraft = craft;
                //            }
            }
        }

        int craftMinY = 0;
        int craftMaxY = 0;
        // make the centered block list
        for (int i = 0; i < blockList.length; i++) {
            centeredBlockList[i] = blockList[i].subtract(originPoint);

        }

        for (int i = 0; i < blockList.length; i++) {

            blockList[i] = MathUtils.rotateVec(rotation, centeredBlockList[i]).add(originPoint);
            int typeID = w.getBlockTypeIdAt(blockList[i].getX(), blockList[i].getY(), blockList[i].getZ());

            Material testMaterial = w.getBlockAt(originalBlockList[i].getX(), originalBlockList[i].getY(),
                    originalBlockList[i].getZ()).getType();

            if (testMaterial.equals(Material.CHEST) || testMaterial.equals(Material.TRAPPED_CHEST)) {
                if (!checkChests(testMaterial, blockList[i], existingBlockSet)) {
                    //prevent chests collision
                    failed = true;
                    failMessage = String
                            .format(I18nSupport.getInternationalisedString("Rotation - Craft is obstructed")
                                    + " @ %d,%d,%d", blockList[i].getX(), blockList[i].getY(), blockList[i].getZ());
                    break;
                }
            }
            Location plugLoc = new Location(w, blockList[i].getX(), blockList[i].getY(), blockList[i].getZ());
            if (craftPilot != null) {
                // See if they are permitted to build in the area, if WorldGuard integration is turned on
                if (Movecraft.getInstance().getWorldGuardPlugin() != null
                        && Settings.WorldGuardBlockMoveOnBuildPerm) {
                    if (Movecraft.getInstance().getWorldGuardPlugin().canBuild(craftPilot, plugLoc) == false) {
                        failed = true;
                        failMessage = String.format(I18nSupport.getInternationalisedString(
                                "Rotation - Player is not permitted to build in this WorldGuard region")
                                + " @ %d,%d,%d", blockList[i].getX(), blockList[i].getY(), blockList[i].getZ());
                        break;
                    }
                }
            }

            Player p;
            if (craftPilot == null) {
                p = getCraft().getNotificationPlayer();
            } else {
                p = craftPilot;
            }
            if (p != null) {
                if (Movecraft.getInstance().getWorldGuardPlugin() != null
                        && Movecraft.getInstance().getWGCustomFlagsPlugin() != null
                        && Settings.WGCustomFlagsUsePilotFlag) {
                    LocalPlayer lp = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(p);
                    WGCustomFlagsUtils WGCFU = new WGCustomFlagsUtils();
                    if (!WGCFU.validateFlag(plugLoc, Movecraft.FLAG_ROTATE, lp)) {
                        failed = true;
                        failMessage = String.format(
                                I18nSupport.getInternationalisedString("WGCustomFlags - Rotation Failed")
                                        + " @ %d,%d,%d",
                                blockList[i].getX(), blockList[i].getY(), blockList[i].getZ());
                        break;
                    }
                }

                if (townyEnabled) {
                    TownBlock townBlock = TownyUtils.getTownBlock(plugLoc);
                    if (townBlock != null && !townBlockSet.contains(townBlock)) {
                        if (TownyUtils.validateCraftMoveEvent(p, plugLoc, townyWorld)) {
                            townBlockSet.add(townBlock);
                        } else {
                            int y = plugLoc.getBlockY();
                            boolean oChange = false;
                            if (craftMinY > y) {
                                craftMinY = y;
                                oChange = true;
                            }
                            if (craftMaxY < y) {
                                craftMaxY = y;
                                oChange = true;
                            }
                            if (oChange) {
                                Town town = TownyUtils.getTown(townBlock);
                                if (town != null) {
                                    Location locSpawn = TownyUtils.getTownSpawn(townBlock);
                                    if (locSpawn != null) {
                                        if (!townyWorldHeightLimits.validate(y, locSpawn.getBlockY())) {
                                            failed = true;
                                        }
                                    } else {
                                        failed = true;
                                    }
                                    if (failed) {
                                        if (Movecraft.getInstance().getWorldGuardPlugin() != null
                                                && Movecraft.getInstance().getWGCustomFlagsPlugin() != null
                                                && Settings.WGCustomFlagsUsePilotFlag) {
                                            LocalPlayer lp = Movecraft.getInstance().getWorldGuardPlugin()
                                                    .wrapPlayer(p);
                                            ApplicableRegionSet regions = Movecraft.getInstance()
                                                    .getWorldGuardPlugin().getRegionManager(plugLoc.getWorld())
                                                    .getApplicableRegions(plugLoc);
                                            if (regions.size() != 0) {
                                                WGCustomFlagsUtils WGCFU = new WGCustomFlagsUtils();
                                                if (WGCFU.validateFlag(plugLoc, Movecraft.FLAG_ROTATE, lp)) {
                                                    failed = false;
                                                }
                                            }
                                        }
                                    }
                                    if (failed) {
                                        failMessage = String.format(
                                                I18nSupport.getInternationalisedString("Towny - Rotation Failed")
                                                        + " %s @ %d,%d,%d",
                                                town.getName(), blockList[i].getX(), blockList[i].getY(),
                                                blockList[i].getZ());
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (!waterCraft) {
                if ((typeID != 0 && typeID != 34) && !existingBlockSet.contains(blockList[i])) {
                    failed = true;
                    failMessage = String
                            .format(I18nSupport.getInternationalisedString("Rotation - Craft is obstructed")
                                    + " @ %d,%d,%d", blockList[i].getX(), blockList[i].getY(), blockList[i].getZ());
                    break;
                } else {
                    int id = w.getBlockTypeIdAt(originalBlockList[i].getX(), originalBlockList[i].getY(),
                            originalBlockList[i].getZ());
                    byte data = w.getBlockAt(originalBlockList[i].getX(), originalBlockList[i].getY(),
                            originalBlockList[i].getZ()).getData();
                    int currentID = w.getBlockTypeIdAt(blockList[i].getX(), blockList[i].getY(),
                            blockList[i].getZ());
                    byte currentData = w.getBlockAt(blockList[i].getX(), blockList[i].getY(), blockList[i].getZ())
                            .getData();
                    if (BlockUtils.blockRequiresRotation(id)) {
                        data = BlockUtils.rotate(data, id, rotation);
                    }
                    mapUpdates.add(new MapUpdateCommand(originalBlockList[i], currentID, currentData, blockList[i],
                            id, data, rotation, parentCraft));
                }
            } else {
                // allow watercraft to rotate through water
                if ((typeID != 0 && typeID != 9 && typeID != 34) && !existingBlockSet.contains(blockList[i])) {
                    failed = true;
                    failMessage = String
                            .format(I18nSupport.getInternationalisedString("Rotation - Craft is obstructed")
                                    + " @ %d,%d,%d", blockList[i].getX(), blockList[i].getY(), blockList[i].getZ());
                    break;
                } else {
                    int id = w.getBlockTypeIdAt(originalBlockList[i].getX(), originalBlockList[i].getY(),
                            originalBlockList[i].getZ());
                    byte data = w.getBlockAt(originalBlockList[i].getX(), originalBlockList[i].getY(),
                            originalBlockList[i].getZ()).getData();
                    int currentID = w.getBlockTypeIdAt(blockList[i].getX(), blockList[i].getY(),
                            blockList[i].getZ());
                    byte currentData = w.getBlockAt(blockList[i].getX(), blockList[i].getY(), blockList[i].getZ())
                            .getData();
                    if (BlockUtils.blockRequiresRotation(id)) {
                        data = BlockUtils.rotate(data, id, rotation);
                    }
                    mapUpdates.add(new MapUpdateCommand(originalBlockList[i], currentID, currentData, blockList[i],
                            id, data, rotation, parentCraft));
                }
            }

        }

        if (!failed) {
            //rotate entities in the craft
            Location tOP = new Location(getCraft().getW(), originPoint.getX(), originPoint.getY(),
                    originPoint.getZ());

            List<Entity> eList = null;
            int numTries = 0;

            while ((eList == null) && (numTries < 100)) {
                try {
                    eList = getCraft().getW().getEntities();
                } catch (java.util.ConcurrentModificationException e) {
                    numTries++;
                }
            }
            Iterator<Entity> i = getCraft().getW().getEntities().iterator();
            while (i.hasNext()) {
                Entity pTest = i.next();
                //            if ( MathUtils.playerIsWithinBoundingPolygon( getCraft().getHitBox(), getCraft().getMinX(), getCraft().getMinZ(), MathUtils.bukkit2MovecraftLoc( pTest.getLocation() ) ) ) {
                if (MathUtils.locIsNearCraftFast(getCraft(), MathUtils.bukkit2MovecraftLoc(pTest.getLocation()))) {
                    if (pTest.getType() != org.bukkit.entity.EntityType.DROPPED_ITEM) {
                        // Player is onboard this craft
                        tOP.setX(tOP.getBlockX() + 0.5);
                        tOP.setZ(tOP.getBlockZ() + 0.5);
                        Location playerLoc = pTest.getLocation();
                        // direct control no longer locks the player in place                  
                        //                  if(getCraft().getPilotLocked()==true && pTest==CraftManager.getInstance().getPlayerFromCraft(getCraft())) {
                        //                     playerLoc.setX(getCraft().getPilotLockedX());
                        //                     playerLoc.setY(getCraft().getPilotLockedY());
                        //                     playerLoc.setZ(getCraft().getPilotLockedZ());
                        //                     }
                        Location adjustedPLoc = playerLoc.subtract(tOP);

                        double[] rotatedCoords = MathUtils.rotateVecNoRound(rotation, adjustedPLoc.getX(),
                                adjustedPLoc.getZ());
                        Location rotatedPloc = new Location(getCraft().getW(), rotatedCoords[0], playerLoc.getY(),
                                rotatedCoords[1]);
                        Location newPLoc = rotatedPloc.add(tOP);

                        newPLoc.setPitch(playerLoc.getPitch());
                        float newYaw = playerLoc.getYaw();
                        if (rotation == Rotation.CLOCKWISE) {
                            newYaw = newYaw + 90.0F;
                            if (newYaw >= 360.0F) {
                                newYaw = newYaw - 360.0F;
                            }
                        }
                        if (rotation == Rotation.ANTICLOCKWISE) {
                            newYaw = newYaw - 90;
                            if (newYaw < 0.0F) {
                                newYaw = newYaw + 360.0F;
                            }
                        }
                        newPLoc.setYaw(newYaw);

                        //                  if(getCraft().getPilotLocked()==true && pTest==CraftManager.getInstance().getPlayerFromCraft(getCraft())) {
                        //                     getCraft().setPilotLockedX(newPLoc.getX());
                        //                     getCraft().setPilotLockedY(newPLoc.getY());
                        //                     getCraft().setPilotLockedZ(newPLoc.getZ());
                        //                     }
                        EntityUpdateCommand eUp = new EntityUpdateCommand(pTest.getLocation().clone(), newPLoc,
                                pTest);
                        entityUpdateSet.add(eUp);
                        //                  if(getCraft().getPilotLocked()==true && pTest==CraftManager.getInstance().getPlayerFromCraft(getCraft())) {
                        //                     getCraft().setPilotLockedX(newPLoc.getX());
                        //                     getCraft().setPilotLockedY(newPLoc.getY());
                        //                     getCraft().setPilotLockedZ(newPLoc.getZ());
                        //                  }
                    } else {
                        //   pTest.remove();   removed to test cleaner fragile item removal
                    }
                }

            }

            /*         //update player spawn locations if they spawned where the ship used to be
                     for(Player p : Movecraft.getInstance().getServer().getOnlinePlayers()) {
                        if(p.getBedSpawnLocation()!=null) {
                           if( MathUtils.playerIsWithinBoundingPolygon( getCraft().getHitBox(), getCraft().getMinX(), getCraft().getMinZ(), MathUtils.bukkit2MovecraftLoc( p.getBedSpawnLocation() ) ) ) {
              Location spawnLoc = p.getBedSpawnLocation();
              Location adjustedPLoc = spawnLoc.subtract( tOP ); 
                
              double[] rotatedCoords = MathUtils.rotateVecNoRound( rotation, adjustedPLoc.getX(), adjustedPLoc.getZ() );
              Location rotatedPloc = new Location( getCraft().getW(), rotatedCoords[0], spawnLoc.getY(), rotatedCoords[1] );
              Location newBedSpawn = rotatedPloc.add( tOP );
                
              p.setBedSpawnLocation(newBedSpawn, true);
                           }
                        }
                     }*/

            // Calculate air changes
            List<MovecraftLocation> airLocation = ListUtils.subtract(Arrays.asList(originalBlockList),
                    Arrays.asList(blockList));

            for (MovecraftLocation l1 : airLocation) {
                if (waterCraft) {
                    // if its below the waterline, fill in with water. Otherwise fill in with air.
                    if (l1.getY() <= waterLine) {
                        mapUpdates.add(new MapUpdateCommand(l1, 9, (byte) 0, parentCraft));
                    } else {
                        mapUpdates.add(new MapUpdateCommand(l1, 0, (byte) 0, parentCraft));
                    }
                } else {
                    mapUpdates.add(new MapUpdateCommand(l1, 0, (byte) 0, parentCraft));
                }
            }

            // rotate scheduled block changes
            HashMap<MapUpdateCommand, Long> newScheduledBlockChanges = new HashMap<MapUpdateCommand, Long>();
            HashMap<MapUpdateCommand, Long> oldScheduledBlockChanges = getCraft().getScheduledBlockChanges();
            for (MapUpdateCommand muc : oldScheduledBlockChanges.keySet()) {
                MovecraftLocation newLoc = muc.getNewBlockLocation();
                newLoc = newLoc.subtract(originPoint);
                newLoc = MathUtils.rotateVec(rotation, newLoc).add(originPoint);
                Long newTime = System.currentTimeMillis() + 5000;
                MapUpdateCommand newMuc = new MapUpdateCommand(newLoc, muc.getTypeID(), muc.getDataID(),
                        parentCraft);
                newScheduledBlockChanges.put(newMuc, newTime);
            }
            this.scheduledBlockChanges = newScheduledBlockChanges;

            MapUpdateCommand[] updateArray = mapUpdates.toArray(new MapUpdateCommand[1]);
            //            MapUpdateManager.getInstance().sortUpdates(updateArray);
            this.updates = updateArray;
            this.entityUpdates = entityUpdateSet.toArray(new EntityUpdateCommand[1]);

            maxX = null;
            maxZ = null;
            minX = null;
            minZ = null;

            for (MovecraftLocation l : blockList) {
                if (maxX == null || l.getX() > maxX) {
                    maxX = l.getX();
                }
                if (maxZ == null || l.getZ() > maxZ) {
                    maxZ = l.getZ();
                }
                if (minX == null || l.getX() < minX) {
                    minX = l.getX();
                }
                if (minZ == null || l.getZ() < minZ) {
                    minZ = l.getZ();
                }
            }

            // Rerun the polygonal bounding formula for the newly formed craft
            int sizeX, sizeZ;
            sizeX = (maxX - minX) + 1;
            sizeZ = (maxZ - minZ) + 1;

            int[][][] polygonalBox = new int[sizeX][][];

            for (MovecraftLocation l : blockList) {
                if (polygonalBox[l.getX() - minX] == null) {
                    polygonalBox[l.getX() - minX] = new int[sizeZ][];
                }

                if (polygonalBox[l.getX() - minX][l.getZ() - minZ] == null) {

                    polygonalBox[l.getX() - minX][l.getZ() - minZ] = new int[2];
                    polygonalBox[l.getX() - minX][l.getZ() - minZ][0] = l.getY();
                    polygonalBox[l.getX() - minX][l.getZ() - minZ][1] = l.getY();

                } else {
                    minY = polygonalBox[l.getX() - minX][l.getZ() - minZ][0];
                    maxY = polygonalBox[l.getX() - minX][l.getZ() - minZ][1];

                    if (l.getY() < minY) {
                        polygonalBox[l.getX() - minX][l.getZ() - minZ][0] = l.getY();
                    }
                    if (l.getY() > maxY) {
                        polygonalBox[l.getX() - minX][l.getZ() - minZ][1] = l.getY();
                    }

                }

            }

            this.hitbox = polygonalBox;
            if (getCraft().getCruising()) {
                if (rotation == Rotation.ANTICLOCKWISE) {
                    // ship faces west
                    if (getCraft().getCruiseDirection() == 0x5) {
                        getCraft().setCruiseDirection((byte) 0x2);
                    } else
                    // ship faces east
                    if (getCraft().getCruiseDirection() == 0x4) {
                        getCraft().setCruiseDirection((byte) 0x3);
                    } else
                    // ship faces north
                    if (getCraft().getCruiseDirection() == 0x2) {
                        getCraft().setCruiseDirection((byte) 0x4);
                    } else
                    // ship faces south
                    if (getCraft().getCruiseDirection() == 0x3) {
                        getCraft().setCruiseDirection((byte) 0x5);
                    }
                } else if (rotation == Rotation.CLOCKWISE) {
                    // ship faces west
                    if (getCraft().getCruiseDirection() == 0x5) {
                        getCraft().setCruiseDirection((byte) 0x3);
                    } else
                    // ship faces east
                    if (getCraft().getCruiseDirection() == 0x4) {
                        getCraft().setCruiseDirection((byte) 0x2);
                    } else
                    // ship faces north
                    if (getCraft().getCruiseDirection() == 0x2) {
                        getCraft().setCruiseDirection((byte) 0x5);
                    } else
                    // ship faces south
                    if (getCraft().getCruiseDirection() == 0x3) {
                        getCraft().setCruiseDirection((byte) 0x4);
                    }
                }
            }

            // if you rotated a subcraft, update the parent with the new blocks
            if (this.isSubCraft) {
                // also find the furthest extent from center and notify the player of the new direction
                int farthestX = 0;
                int farthestZ = 0;
                for (MovecraftLocation loc : blockList) {
                    if (Math.abs(loc.getX() - originPoint.getX()) > Math.abs(farthestX))
                        farthestX = loc.getX() - originPoint.getX();
                    if (Math.abs(loc.getZ() - originPoint.getZ()) > Math.abs(farthestZ))
                        farthestZ = loc.getZ() - originPoint.getZ();
                }
                if (Math.abs(farthestX) > Math.abs(farthestZ)) {
                    if (farthestX > 0) {
                        if (getCraft().getNotificationPlayer() != null)
                            getCraft().getNotificationPlayer().sendMessage("The farthest extent now faces East");
                    } else {
                        if (getCraft().getNotificationPlayer() != null)
                            getCraft().getNotificationPlayer().sendMessage("The farthest extent now faces West");
                    }
                } else {
                    if (farthestZ > 0) {
                        if (getCraft().getNotificationPlayer() != null)
                            getCraft().getNotificationPlayer().sendMessage("The farthest extent now faces South");
                    } else {
                        if (getCraft().getNotificationPlayer() != null)
                            getCraft().getNotificationPlayer().sendMessage("The farthest extent now faces North");
                    }
                }

                craftsInWorld = CraftManager.getInstance().getCraftsInWorld(getCraft().getW());
                for (Craft craft : craftsInWorld) {
                    if (BlockUtils.arrayContainsOverlap(craft.getBlockList(), originalBlockList)
                            && craft != getCraft()) {
                        List<MovecraftLocation> parentBlockList = ListUtils
                                .subtract(Arrays.asList(craft.getBlockList()), Arrays.asList(originalBlockList));
                        parentBlockList.addAll(Arrays.asList(blockList));
                        craft.setBlockList(parentBlockList.toArray(new MovecraftLocation[1]));

                        // Rerun the polygonal bounding formula for the parent craft
                        Integer parentMaxX = null;
                        Integer parentMaxZ = null;
                        Integer parentMinX = null;
                        Integer parentMinZ = null;
                        for (MovecraftLocation l : parentBlockList) {
                            if (parentMaxX == null || l.getX() > parentMaxX) {
                                parentMaxX = l.getX();
                            }
                            if (parentMaxZ == null || l.getZ() > parentMaxZ) {
                                parentMaxZ = l.getZ();
                            }
                            if (parentMinX == null || l.getX() < parentMinX) {
                                parentMinX = l.getX();
                            }
                            if (parentMinZ == null || l.getZ() < parentMinZ) {
                                parentMinZ = l.getZ();
                            }
                        }
                        int parentSizeX, parentSizeZ;
                        parentSizeX = (parentMaxX - parentMinX) + 1;
                        parentSizeZ = (parentMaxZ - parentMinZ) + 1;
                        int[][][] parentPolygonalBox = new int[parentSizeX][][];
                        for (MovecraftLocation l : parentBlockList) {
                            if (parentPolygonalBox[l.getX() - parentMinX] == null) {
                                parentPolygonalBox[l.getX() - parentMinX] = new int[parentSizeZ][];
                            }
                            if (parentPolygonalBox[l.getX() - parentMinX][l.getZ() - parentMinZ] == null) {
                                parentPolygonalBox[l.getX() - parentMinX][l.getZ() - parentMinZ] = new int[2];
                                parentPolygonalBox[l.getX() - parentMinX][l.getZ() - parentMinZ][0] = l.getY();
                                parentPolygonalBox[l.getX() - parentMinX][l.getZ() - parentMinZ][1] = l.getY();
                            } else {
                                int parentMinY = parentPolygonalBox[l.getX() - parentMinX][l.getZ()
                                        - parentMinZ][0];
                                int parentMaxY = parentPolygonalBox[l.getX() - parentMinX][l.getZ()
                                        - parentMinZ][1];

                                if (l.getY() < parentMinY) {
                                    parentPolygonalBox[l.getX() - parentMinX][l.getZ() - parentMinZ][0] = l.getY();
                                }
                                if (l.getY() > parentMaxY) {
                                    parentPolygonalBox[l.getX() - parentMinX][l.getZ() - parentMinZ][1] = l.getY();
                                }
                            }
                        }
                        craft.setMinX(parentMinX);
                        craft.setMinZ(parentMinZ);
                        craft.setHitBox(parentPolygonalBox);
                    }
                }
            }

        } else { // this else is for "if(!failed)"
            if (this.isSubCraft) {
                if (parentCraft != getCraft()) {
                    parentCraft.setProcessing(false);
                }
            }
        }
    }

    public HashMap<MapUpdateCommand, Long> getScheduledBlockChanges() {
        return scheduledBlockChanges;
    }

    public void setScheduledBlockChanges(HashMap<MapUpdateCommand, Long> scheduledBlockChanges) {
        this.scheduledBlockChanges = scheduledBlockChanges;
    }

    public MovecraftLocation getOriginPoint() {
        return originPoint;
    }

    public boolean isFailed() {
        return failed;
    }

    public String getFailMessage() {
        return failMessage;
    }

    public MovecraftLocation[] getBlockList() {
        return blockList;
    }

    public MapUpdateCommand[] getUpdates() {
        return updates;
    }

    public EntityUpdateCommand[] getEntityUpdates() {
        return entityUpdates;
    }

    public int[][][] getHitbox() {
        return hitbox;
    }

    public int getMinX() {
        return minX;
    }

    public int getMinZ() {
        return minZ;
    }

    public Rotation getRotation() {
        return rotation;
    }

    public boolean getIsSubCraft() {
        return isSubCraft;
    }

    private boolean checkChests(Material mBlock, MovecraftLocation newLoc,
            HashSet<MovecraftLocation> existingBlockSet) {
        Material testMaterial;
        MovecraftLocation aroundNewLoc;

        aroundNewLoc = newLoc.translate(1, 0, 0);
        testMaterial = getCraft().getW().getBlockAt(aroundNewLoc.getX(), aroundNewLoc.getY(), aroundNewLoc.getZ())
                .getType();
        if (testMaterial.equals(mBlock)) {
            if (!existingBlockSet.contains(aroundNewLoc)) {
                return false;
            }
        }

        aroundNewLoc = newLoc.translate(-1, 0, 0);
        testMaterial = getCraft().getW().getBlockAt(aroundNewLoc.getX(), aroundNewLoc.getY(), aroundNewLoc.getZ())
                .getType();
        if (testMaterial.equals(mBlock)) {
            if (!existingBlockSet.contains(aroundNewLoc)) {
                return false;
            }
        }

        aroundNewLoc = newLoc.translate(0, 0, 1);
        testMaterial = getCraft().getW().getBlockAt(aroundNewLoc.getX(), aroundNewLoc.getY(), aroundNewLoc.getZ())
                .getType();
        if (testMaterial.equals(mBlock)) {
            if (!existingBlockSet.contains(aroundNewLoc)) {
                return false;
            }
        }

        aroundNewLoc = newLoc.translate(0, 0, -1);
        testMaterial = getCraft().getW().getBlockAt(aroundNewLoc.getX(), aroundNewLoc.getY(), aroundNewLoc.getZ())
                .getType();
        if (testMaterial.equals(mBlock)) {
            if (!existingBlockSet.contains(aroundNewLoc)) {
                return false;
            }
        }
        return true;
    }
}