Java tutorial
/* * 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.translation; import com.palmergames.bukkit.towny.object.Town; import com.sk89q.worldguard.protection.flags.StateFlag; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.async.AsyncManager; 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.BoundingBoxUtils; 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 org.apache.commons.collections.ListUtils; import org.apache.commons.lang.ArrayUtils; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Effect; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.Chest; 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.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.Random; import java.util.Set; import java.util.logging.Level; import net.countercraft.movecraft.utils.ItemDropUpdateCommand; import net.countercraft.movecraft.utils.TownyUtils; 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 net.countercraft.movecraft.utils.TownyWorldHeightLimits; import net.countercraft.movecraft.utils.WGCustomFlagsUtils; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.inventory.Inventory; public class TranslationTask extends AsyncTask { private TranslationTaskData data; public TranslationTask(Craft c, TranslationTaskData data) { super(c); this.data = data; } @Override public void excecute() { MovecraftLocation[] blocksList = data.getBlockList(); final int[] fallThroughBlocks = new int[] { 0, 8, 9, 10, 11, 31, 37, 38, 39, 40, 50, 51, 55, 59, 63, 65, 68, 69, 70, 72, 75, 76, 77, 78, 83, 85, 93, 94, 111, 141, 142, 143, 171 }; // blockedByWater=false means an ocean-going vessel boolean waterCraft = !getCraft().getType().blockedByWater(); boolean hoverCraft = getCraft().getType().getCanHover(); boolean airCraft = getCraft().getType().blockedByWater(); int hoverLimit = getCraft().getType().getHoverLimit(); Player craftPilot = CraftManager.getInstance().getPlayerFromCraft(getCraft()); int[][][] hb = getCraft().getHitBox(); if (hb == null) return; // start by finding the crafts 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]; } } } } int maxX = getCraft().getMinX() + hb.length; int 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 int minX = getCraft().getMinX(); int minZ = getCraft().getMinZ(); // treat sinking crafts specially if (getCraft().getSinking()) { waterCraft = true; hoverCraft = false; } if (getCraft().getDisabled() && (!getCraft().getSinking())) { fail(String.format(I18nSupport.getInternationalisedString("Craft is disabled!"))); } // check the maxheightaboveground limitation, move 1 down if that limit is exceeded if (getCraft().getType().getMaxHeightAboveGround() > 0 && data.getDy() >= 0) { int x = getCraft().getMaxX() + getCraft().getMinX(); x = x >> 1; int y = getCraft().getMaxY(); int z = getCraft().getMaxZ() + getCraft().getMinZ(); z = z >> 1; int cy = getCraft().getMinY(); boolean done = false; while (!done) { cy = cy - 1; if (getCraft().getW().getBlockTypeIdAt(x, cy, z) != 0) done = true; if (cy <= 1) done = true; } if (y - cy > getCraft().getType().getMaxHeightAboveGround()) { data.setDy(-1); } } // Find the waterline from the surrounding terrain or from the static level in the craft type int waterLine = 0; if (waterCraft) { if (getCraft().getType().getStaticWaterLevel() != 0) { if (waterLine <= maxY + 1) { waterLine = getCraft().getType().getStaticWaterLevel(); } } else { // figure out the water level by examining blocks next to the outer boundaries of the craft for (int posY = maxY + 1; (posY >= minY - 1) && (waterLine == 0); posY--) { int numWater = 0; int numAir = 0; int posX; int posZ; posZ = minZ - 1; for (posX = minX - 1; (posX <= maxX + 1) && (waterLine == 0); posX++) { int typeID = getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId(); if (typeID == 9) numWater++; if (typeID == 0) numAir++; } posZ = maxZ + 1; for (posX = minX - 1; (posX <= maxX + 1) && (waterLine == 0); posX++) { int typeID = getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId(); if (typeID == 9) numWater++; if (typeID == 0) numAir++; } posX = minX - 1; for (posZ = minZ; (posZ <= maxZ) && (waterLine == 0); posZ++) { int typeID = getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId(); if (typeID == 9) numWater++; if (typeID == 0) numAir++; } posX = maxX + 1; for (posZ = minZ; (posZ <= maxZ) && (waterLine == 0); posZ++) { int typeID = getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId(); if (typeID == 9) numWater++; if (typeID == 0) numAir++; } if (numWater > numAir) { waterLine = posY; } } } // now add all the air blocks found within the craft's hitbox immediately above the waterline and below to the craft blocks so they will be translated HashSet<MovecraftLocation> newHSBlockList = new HashSet<MovecraftLocation>(Arrays.asList(blocksList)); int posY = waterLine + 1; for (int posX = minX; posX < maxX; posX++) { for (int posZ = minZ; posZ < maxZ; posZ++) { if (hb[posX - minX] != null) { if (hb[posX - minX][posZ - minZ] != null) { if (getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId() == 0 && posY > hb[posX - minX][posZ - minZ][0] && posY < hb[posX - minX][posZ - minZ][1]) { MovecraftLocation l = new MovecraftLocation(posX, posY, posZ); newHSBlockList.add(l); } } } } } // dont check the hitbox for the underwater portion. Otherwise open-hulled ships would flood. for (posY = waterLine; posY >= minY; posY--) { for (int posX = minX; posX < maxX; posX++) { for (int posZ = minZ; posZ < maxZ; posZ++) { if (getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId() == 0) { MovecraftLocation l = new MovecraftLocation(posX, posY, posZ); newHSBlockList.add(l); } } } } blocksList = 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(); // going down doesn't require fuel if (data.getDy() == -1 && data.getDx() == 0 && data.getDz() == 0) fuelBurnRate = 0.0; if (fuelBurnRate != 0.0 && getCraft().getSinking() == false) { if (getCraft().getBurningFuel() < fuelBurnRate) { Block fuelHolder = null; for (MovecraftLocation bTest : blocksList) { 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) { fail(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); } } List<MovecraftLocation> tempBlockList = new ArrayList<MovecraftLocation>(); HashSet<MovecraftLocation> existingBlockSet = new HashSet<MovecraftLocation>(Arrays.asList(blocksList)); HashSet<EntityUpdateCommand> entityUpdateSet = new HashSet<EntityUpdateCommand>(); Set<MapUpdateCommand> updateSet = new HashSet<MapUpdateCommand>(); data.setCollisionExplosion(false); Set<MapUpdateCommand> explosionSet = new HashSet<MapUpdateCommand>(); List<Material> harvestBlocks = getCraft().getType().getHarvestBlocks(); List<MovecraftLocation> harvestedBlocks = new ArrayList<MovecraftLocation>(); List<MovecraftLocation> destroyedBlocks = new ArrayList<MovecraftLocation>(); List<Material> harvesterBladeBlocks = getCraft().getType().getHarvesterBladeBlocks(); int hoverOver = data.getDy(); int craftMinY = 0; int craftMaxY = 0; boolean clearNewData = false; boolean hoverUseGravity = getCraft().getType().getUseGravity(); boolean checkHover = (data.getDx() != 0 || data.getDz() != 0);// we want to check only horizontal moves boolean canHoverOverWater = getCraft().getType().getCanHoverOverWater(); boolean townyEnabled = Movecraft.getInstance().getTownyPlugin() != null; boolean explosionBlockedByTowny = false; boolean moveBlockedByTowny = false; boolean validateTownyExplosion = false; String townName = ""; 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()); if (getCraft().getType().getCollisionExplosion() != 0.0F) { validateTownyExplosion = true; } } } } else { townyEnabled = false; } for (int i = 0; i < blocksList.length; i++) { MovecraftLocation oldLoc = blocksList[i]; MovecraftLocation newLoc = oldLoc.translate(data.getDx(), data.getDy(), data.getDz()); if (newLoc.getY() > data.getMaxHeight() && newLoc.getY() > oldLoc.getY()) { fail(String.format( I18nSupport.getInternationalisedString("Translation - Failed Craft hit height limit"))); break; } else if (newLoc.getY() < data.getMinHeight() && newLoc.getY() < oldLoc.getY() && getCraft().getSinking() == false) { fail(String.format(I18nSupport .getInternationalisedString("Translation - Failed Craft hit minimum height limit"))); break; } boolean blockObstructed = false; boolean harvestBlock = false; boolean bladeOK = true; Material testMaterial; Location plugLoc = new Location(getCraft().getW(), newLoc.getX(), newLoc.getY(), newLoc.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) { fail(String.format(I18nSupport.getInternationalisedString( "Translation - Failed Player is not permitted to build in this WorldGuard region") + " @ %d,%d,%d", oldLoc.getX(), oldLoc.getY(), oldLoc.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_MOVE, lp)) { fail(String .format(I18nSupport.getInternationalisedString("WGCustomFlags - Translation Failed") + " @ %d,%d,%d", oldLoc.getX(), oldLoc.getY(), oldLoc.getZ())); break; } } if (townyEnabled) { TownBlock townBlock = TownyUtils.getTownBlock(plugLoc); if (townBlock != null && !townBlockSet.contains(townBlock)) { if (validateTownyExplosion) { if (!explosionBlockedByTowny) { if (!TownyUtils.validateExplosion(townBlock)) { explosionBlockedByTowny = true; } } } 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) { boolean failed = false; 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_MOVE, lp)) { failed = false; } } } } if (failed) { townName = town.getName(); moveBlockedByTowny = true; } } } } } } } //check for chests around testMaterial = getCraft().getW().getBlockAt(oldLoc.getX(), oldLoc.getY(), oldLoc.getZ()).getType(); if (testMaterial.equals(Material.CHEST) || testMaterial.equals(Material.TRAPPED_CHEST)) { if (!checkChests(testMaterial, newLoc, existingBlockSet)) { //prevent chests collision fail(String.format( I18nSupport.getInternationalisedString("Translation - Failed Craft is obstructed") + " @ %d,%d,%d,%s", newLoc.getX(), newLoc.getY(), newLoc.getZ(), getCraft().getW() .getBlockAt(newLoc.getX(), newLoc.getY(), newLoc.getZ()).getType().toString())); break; } } if (getCraft().getSinking()) { int testID = getCraft().getW().getBlockAt(newLoc.getX(), newLoc.getY(), newLoc.getZ()).getTypeId(); blockObstructed = !(Arrays.binarySearch(fallThroughBlocks, testID) >= 0) && !existingBlockSet.contains(newLoc); } else if (!waterCraft) { // New block is not air or a piston head and is not part of the existing ship testMaterial = getCraft().getW().getBlockAt(newLoc.getX(), newLoc.getY(), newLoc.getZ()).getType(); blockObstructed = (!testMaterial.equals(Material.AIR)) && !existingBlockSet.contains(newLoc); } else { // New block is not air or water or a piston head and is not part of the existing ship testMaterial = getCraft().getW().getBlockAt(newLoc.getX(), newLoc.getY(), newLoc.getZ()).getType(); blockObstructed = (!testMaterial.equals(Material.AIR) && !testMaterial.equals(Material.STATIONARY_WATER) && !testMaterial.equals(Material.WATER)) && !existingBlockSet.contains(newLoc); } boolean ignoreBlock = false; // air never obstructs anything (changed 4/18/2017 to prevent drilling machines) if (getCraft().getW().getBlockAt(oldLoc.getX(), oldLoc.getY(), oldLoc.getZ()).getType() .equals(Material.AIR) && blockObstructed) { ignoreBlock = true; // blockObstructed=false; } testMaterial = getCraft().getW().getBlockAt(newLoc.getX(), newLoc.getY(), newLoc.getZ()).getType(); if (blockObstructed) { if (hoverCraft || harvestBlocks.size() > 0) { // New block is not harvested block if (harvestBlocks.contains(testMaterial) && !existingBlockSet.contains(newLoc)) { Material tmpType = getCraft().getW().getBlockAt(oldLoc.getX(), oldLoc.getY(), oldLoc.getZ()) .getType(); if (harvesterBladeBlocks.size() > 0) { if (!harvesterBladeBlocks.contains(tmpType)) { bladeOK = false; } } if (bladeOK) { blockObstructed = false; harvestBlock = true; tryPutToDestroyBox(testMaterial, newLoc, harvestedBlocks, destroyedBlocks); harvestedBlocks.add(newLoc); } } } } if (blockObstructed || moveBlockedByTowny) { if (hoverCraft && checkHover) { //we check one up ever, if it is hovercraft and one down if it's using gravity if (hoverOver == 0 && newLoc.getY() + 1 <= data.getMaxHeight()) { //first was checked actual level, now check if we can go up hoverOver = 1; data.setDy(1); clearNewData = true; } else if (hoverOver >= 1) { //check other options to go up if (hoverOver < hoverLimit + 1 && newLoc.getY() + 1 <= data.getMaxHeight()) { data.setDy(hoverOver + 1); hoverOver += 1; clearNewData = true; } else { if (hoverUseGravity && newLoc.getY() - hoverOver - 1 >= data.getMinHeight()) { //we are on the maximum of top //if we can't go up so we test bottom side data.setDy(-1); hoverOver = -1; } else { // no way - back to original dY, turn off hovercraft for this move // and get original data again for all explosions data.setDy(0); hoverOver = 0; hoverCraft = false; hoverUseGravity = false; } clearNewData = true; } } else if (hoverOver <= -1) { //we cant go down for 1 block, check more to hoverLimit if (hoverOver > -hoverLimit - 1 && newLoc.getY() - 1 >= data.getMinHeight()) { data.setDy(hoverOver - 1); hoverOver -= 1; clearNewData = true; } else { // no way - back to original dY, turn off hovercraft for this move // and get original data again for all explosions data.setDy(0); hoverOver = 0; hoverUseGravity = false; clearNewData = true; hoverCraft = false; } } else { // no way - reached MaxHeight during looking new way upstairss if (hoverUseGravity && newLoc.getY() - 1 >= data.getMinHeight()) { //we are on the maximum of top //if we can't go up so we test bottom side data.setDy(-1); hoverOver = -1; } else { // - back to original dY, turn off hovercraft for this move // and get original data again for all explosions data.setDy(0); hoverOver = 0; hoverUseGravity = false; hoverCraft = false; } clearNewData = true; } // End hovercraft stuff } else { // handle sinking ship collisions if (getCraft().getSinking()) { if (getCraft().getType().getExplodeOnCrash() != 0.0F && !explosionBlockedByTowny) { int explosionKey = (int) (0 - (getCraft().getType().getExplodeOnCrash() * 100)); if (System.currentTimeMillis() - getCraft().getOrigPilotTime() > 1000) if (!getCraft().getW().getBlockAt(oldLoc.getX(), oldLoc.getY(), oldLoc.getZ()) .getType().equals(Material.AIR)) { explosionSet .add(new MapUpdateCommand(oldLoc, explosionKey, (byte) 0, getCraft())); data.setCollisionExplosion(true); } } else { // use the explosion code to clean up the craft, but not with enough force to do anything int explosionKey = 0 - 1; if (!getCraft().getW().getBlockAt(oldLoc.getX(), oldLoc.getY(), oldLoc.getZ()).getType() .equals(Material.AIR)) { explosionSet.add(new MapUpdateCommand(oldLoc, explosionKey, (byte) 0, getCraft())); data.setCollisionExplosion(true); } } } else { // Explode if the craft is set to have a CollisionExplosion. Also keep moving for spectacular ramming collisions if (getCraft().getType().getCollisionExplosion() == 0.0F) { if (moveBlockedByTowny) { fail(String.format( I18nSupport.getInternationalisedString("Towny - Translation Failed") + " %s @ %d,%d,%d", townName, oldLoc.getX(), oldLoc.getY(), oldLoc.getZ())); } else { fail(String.format( I18nSupport.getInternationalisedString( "Translation - Failed Craft is obstructed") + " @ %d,%d,%d,%s", oldLoc.getX(), oldLoc.getY(), oldLoc.getZ(), getCraft().getW().getBlockAt(newLoc.getX(), newLoc.getY(), newLoc.getZ()) .getType().toString())); if (getCraft().getNotificationPlayer() != null) { Location location = getCraft().getNotificationPlayer().getLocation(); } } break; } else if (explosionBlockedByTowny) { int explosionKey = 0 - 1; if (!getCraft().getW().getBlockAt(oldLoc.getX(), oldLoc.getY(), oldLoc.getZ()).getType() .equals(Material.AIR)) { explosionSet.add(new MapUpdateCommand(oldLoc, explosionKey, (byte) 0, getCraft())); data.setCollisionExplosion(true); } } else if (System.currentTimeMillis() - getCraft().getOrigPilotTime() > 1000) { int explosionKey; float explosionForce = getCraft().getType().getCollisionExplosion(); if (getCraft().getType().getFocusedExplosion() == true) { explosionForce = explosionForce * getCraft().getBlockList().length; } if (oldLoc.getY() < waterLine) { // underwater explosions require more force to do anything explosionForce += 25; } explosionKey = (int) (0 - (explosionForce * 100)); if (!getCraft().getW().getBlockAt(oldLoc.getX(), oldLoc.getY(), oldLoc.getZ()).getType() .equals(Material.AIR)) { explosionSet.add(new MapUpdateCommand(oldLoc, explosionKey, (byte) 0, getCraft())); data.setCollisionExplosion(true); } if (getCraft().getType().getFocusedExplosion() == true) { // don't handle any further collisions if it is set to focusedexplosion break; } } } } } else { //block not obstructed int oldID = getCraft().getW().getBlockTypeIdAt(oldLoc.getX(), oldLoc.getY(), oldLoc.getZ()); byte oldData = getCraft().getW().getBlockAt(oldLoc.getX(), oldLoc.getY(), oldLoc.getZ()).getData(); int currentID = getCraft().getW().getBlockTypeIdAt(newLoc.getX(), newLoc.getY(), newLoc.getZ()); byte currentData = getCraft().getW().getBlockAt(newLoc.getX(), newLoc.getY(), newLoc.getZ()) .getData(); // remove water from sinking crafts if (getCraft().getSinking()) { if ((oldID == 8 || oldID == 9) && oldLoc.getY() > waterLine) oldID = 0; } if (!ignoreBlock) { updateSet.add(new MapUpdateCommand(oldLoc, currentID, currentData, newLoc, oldID, oldData, getCraft())); tempBlockList.add(newLoc); } if (i == blocksList.length - 1) { if ((hoverCraft && hoverUseGravity) || (hoverUseGravity && newLoc.getY() > data.getMaxHeight() && hoverOver == 0)) { //hovecraft using gravity or something else using gravity and flying over its limit int iFreeSpace = 0; //canHoverOverWater adds 1 to dY for better check water under craft // best way should be expand selected region to each first blocks under craft if (hoverOver == 0) { //we go directly forward so we check if we can go down for (int ii = -1; ii > -hoverLimit - 2 - (canHoverOverWater ? 0 : 1); ii--) { if (!isFreeSpace(data.getDx(), hoverOver + ii, data.getDz(), blocksList, existingBlockSet, waterCraft, hoverCraft, harvestBlocks, canHoverOverWater, checkHover)) { break; } iFreeSpace++; } if (data.failed()) { break; } if (iFreeSpace > hoverLimit - (canHoverOverWater ? 0 : 1)) { data.setDy(-1); hoverOver = -1; clearNewData = true; } } else if (hoverOver == 1 && !airCraft) { //prevent fly heigher than hoverLimit for (int ii = -1; ii > -hoverLimit - 2; ii--) { if (!isFreeSpace(data.getDx(), hoverOver + ii, data.getDz(), blocksList, existingBlockSet, waterCraft, hoverCraft, harvestBlocks, canHoverOverWater, checkHover)) { break; } iFreeSpace++; } if (data.failed()) { break; } if (iFreeSpace > hoverLimit) { if (bladeOK) { fail(String.format(I18nSupport.getInternationalisedString( "Translation - Failed Craft hit height limit"))); } else { fail(String.format( I18nSupport.getInternationalisedString( "Translation - Failed Craft is obstructed") + " @ %d,%d,%d,%s", oldLoc.getX(), oldLoc.getY(), oldLoc.getZ(), getCraft().getW() .getBlockAt(newLoc.getX(), newLoc.getY(), newLoc.getZ()) .getType().toString())); } break; } } else if (hoverOver > 1) { //prevent jump thru block for (int ii = 1; ii < hoverOver - 1; ii++) { if (!isFreeSpace(0, ii, 0, blocksList, existingBlockSet, waterCraft, hoverCraft, harvestBlocks, canHoverOverWater, checkHover)) { break; } iFreeSpace++; } if (data.failed()) { break; } if (iFreeSpace + 2 < hoverOver) { data.setDy(-1); hoverOver = -1; clearNewData = true; } } else if (hoverOver < -1) { //prevent jump thru block for (int ii = -1; ii > hoverOver + 1; ii--) { if (!isFreeSpace(0, ii, 0, blocksList, existingBlockSet, waterCraft, hoverCraft, harvestBlocks, canHoverOverWater, checkHover)) { break; } iFreeSpace++; } if (data.failed()) { break; } if (iFreeSpace + 2 < -hoverOver) { data.setDy(0); hoverOver = 0; hoverCraft = false; clearNewData = true; } } if (!canHoverOverWater) { if (hoverOver >= 1) { //others hoverOver values we have checked jet for (int ii = hoverOver - 1; ii > hoverOver - hoverLimit - 2; ii--) { if (!isFreeSpace(0, ii, 0, blocksList, existingBlockSet, waterCraft, hoverCraft, harvestBlocks, canHoverOverWater, checkHover)) { break; } iFreeSpace++; } if (data.failed()) { break; } } } } } } //END OF: if (blockObstructed) if (clearNewData) { i = -1; tempBlockList.clear(); updateSet.clear(); harvestedBlocks.clear(); data.setCollisionExplosion(false); explosionSet.clear(); clearNewData = false; townBlockSet.clear(); craftMinY = 0; craftMaxY = 0; } } //END OF: for ( int i = 0; i < blocksList.length; i++ ) { // now move the scheduled block changes along with the ship HashMap<MapUpdateCommand, Long> newScheduledBlockChanges = new HashMap<MapUpdateCommand, Long>(); HashMap<MapUpdateCommand, Long> oldScheduledBlockChanges = getCraft().getScheduledBlockChanges(); if (oldScheduledBlockChanges != null) { for (MapUpdateCommand muc : oldScheduledBlockChanges.keySet()) { MovecraftLocation newLoc = muc.getNewBlockLocation().translate(data.getDx(), data.getDy(), data.getDz()); // Long newTime=oldScheduledBlockChanges.get(muc); Long newTime = System.currentTimeMillis() + 5000; MapUpdateCommand newMuc = new MapUpdateCommand(newLoc, muc.getTypeID(), muc.getDataID(), getCraft()); newScheduledBlockChanges.put(newMuc, newTime); } data.setScheduledBlockChanges(newScheduledBlockChanges); } if (data.collisionExplosion()) { // mark the craft to check for sinking, remove the exploding blocks from the blocklist, and submit the explosions for map update for (MapUpdateCommand m : explosionSet) { if (existingBlockSet.contains(m.getNewBlockLocation())) { existingBlockSet.remove(m.getNewBlockLocation()); if (Settings.FadeWrecksAfter > 0) { int typeID = getCraft().getW().getBlockAt(m.getNewBlockLocation().getX(), m.getNewBlockLocation().getY(), m.getNewBlockLocation().getZ()).getTypeId(); if (typeID != 0 && typeID != 9) { Movecraft.getInstance().blockFadeTimeMap.put(m.getNewBlockLocation(), System.currentTimeMillis()); Movecraft.getInstance().blockFadeTypeMap.put(m.getNewBlockLocation(), typeID); if (m.getNewBlockLocation().getY() <= waterLine) { Movecraft.getInstance().blockFadeWaterMap.put(m.getNewBlockLocation(), true); } else { Movecraft.getInstance().blockFadeWaterMap.put(m.getNewBlockLocation(), false); } Movecraft.getInstance().blockFadeWorldMap.put(m.getNewBlockLocation(), getCraft().getW()); } } } // if the craft is sinking, remove all solid blocks above the one that hit the ground from the craft for smoothing sinking if (getCraft().getSinking() == true && (getCraft().getType().getExplodeOnCrash() == 0.0 || explosionBlockedByTowny)) { int posy = m.getNewBlockLocation().getY() + 1; int testID = getCraft().getW() .getBlockAt(m.getNewBlockLocation().getX(), posy, m.getNewBlockLocation().getZ()) .getTypeId(); while (posy <= maxY && !(Arrays.binarySearch(fallThroughBlocks, testID) >= 0)) { MovecraftLocation testLoc = new MovecraftLocation(m.getNewBlockLocation().getX(), posy, m.getNewBlockLocation().getZ()); if (existingBlockSet.contains(testLoc)) { existingBlockSet.remove(testLoc); if (Settings.FadeWrecksAfter > 0) { int typeID = getCraft().getW() .getBlockAt(testLoc.getX(), testLoc.getY(), testLoc.getZ()).getTypeId(); if (typeID != 0 && typeID != 9) { Movecraft.getInstance().blockFadeTimeMap.put(testLoc, System.currentTimeMillis()); Movecraft.getInstance().blockFadeTypeMap.put(testLoc, typeID); if (testLoc.getY() <= waterLine) { Movecraft.getInstance().blockFadeWaterMap.put(testLoc, true); } else { Movecraft.getInstance().blockFadeWaterMap.put(testLoc, false); } Movecraft.getInstance().blockFadeWorldMap.put(testLoc, getCraft().getW()); } } } posy = posy + 1; testID = getCraft().getW() .getBlockAt(m.getNewBlockLocation().getX(), posy, m.getNewBlockLocation().getZ()) .getTypeId(); } } } MovecraftLocation[] newBlockList = (MovecraftLocation[]) existingBlockSet .toArray(new MovecraftLocation[0]); data.setBlockList(newBlockList); data.setUpdates(explosionSet.toArray(new MapUpdateCommand[1])); fail(String.format(I18nSupport.getInternationalisedString("Translation - Failed Craft is obstructed"))); if (getCraft().getSinking() == false) { // FROG changed from ==true, think that was a typo if (getCraft().getType().getSinkPercent() != 0.0) { getCraft().setLastBlockCheck(0); } getCraft().setLastCruisUpdate(System.currentTimeMillis() - 30000); } } if (!data.failed()) { MovecraftLocation[] newBlockList = (MovecraftLocation[]) tempBlockList .toArray(new MovecraftLocation[0]); data.setBlockList(newBlockList); //prevents torpedo and rocket pilots :) if (getCraft().getType().getMoveEntities() && getCraft().getSinking() == false) { // Move entities within the craft 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 = eList.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.PLAYER) { Player player = (Player) pTest; getCraft().getMovedPlayers().put(player, System.currentTimeMillis()); Location tempLoc = pTest.getLocation(); // Direct control no longer locks the player in place // if(getCraft().getPilotLocked()==true && pTest==CraftManager.getInstance().getPlayerFromCraft(getCraft())) { // tempLoc.setX(getCraft().getPilotLockedX()); // tempLoc.setY(getCraft().getPilotLockedY()); // tempLoc.setZ(getCraft().getPilotLockedZ()); // } tempLoc = tempLoc.add(data.getDx(), data.getDy(), data.getDz()); Location newPLoc = new Location(getCraft().getW(), tempLoc.getX(), tempLoc.getY(), tempLoc.getZ()); newPLoc.setPitch(pTest.getLocation().getPitch()); newPLoc.setYaw(pTest.getLocation().getYaw()); EntityUpdateCommand eUp = new EntityUpdateCommand(pTest.getLocation().clone(), newPLoc, pTest); entityUpdateSet.add(eUp); // if(getCraft().getPilotLocked()==true && pTest==CraftManager.getInstance().getPlayerFromCraft(getCraft())) { // getCraft().setPilotLockedX(tempLoc.getX()); // getCraft().setPilotLockedY(tempLoc.getY()); // getCraft().setPilotLockedZ(tempLoc.getZ()); // } } if (pTest.getType() == org.bukkit.entity.EntityType.PRIMED_TNT) { Entity ent = (Entity) pTest; Location tempLoc = pTest.getLocation(); tempLoc = tempLoc.add(data.getDx(), data.getDy(), data.getDz()); EntityUpdateCommand eUp = new EntityUpdateCommand(pTest.getLocation().clone(), tempLoc, pTest); entityUpdateSet.add(eUp); } } } } else { //add releaseTask without playermove to manager if (getCraft().getType().getCruiseOnPilot() == false && getCraft().getSinking() == false) // not necessary to release cruiseonpilot crafts, because they will already be released CraftManager.getInstance().addReleaseTask(getCraft()); } // remove water near sinking crafts if (getCraft().getSinking()) { int posX; int posY = maxY; int posZ; if (posY > waterLine) { for (posX = minX - 1; posX <= maxX + 1; posX++) { for (posZ = minZ - 1; posZ <= maxZ + 1; posZ++) { if (getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId() == 9 || getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId() == 8) { MovecraftLocation loc = new MovecraftLocation(posX, posY, posZ); updateSet.add(new MapUpdateCommand(loc, 0, (byte) 0, getCraft())); } } } } for (posY = maxY + 1; (posY >= minY - 1) && (posY > waterLine); posY--) { posZ = minZ - 1; for (posX = minX - 1; posX <= maxX + 1; posX++) { if (getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId() == 9 || getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId() == 8) { MovecraftLocation loc = new MovecraftLocation(posX, posY, posZ); updateSet.add(new MapUpdateCommand(loc, 0, (byte) 0, getCraft())); } } posZ = maxZ + 1; for (posX = minX - 1; posX <= maxX + 1; posX++) { if (getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId() == 9 || getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId() == 8) { MovecraftLocation loc = new MovecraftLocation(posX, posY, posZ); updateSet.add(new MapUpdateCommand(loc, 0, (byte) 0, getCraft())); } } posX = minX - 1; for (posZ = minZ - 1; posZ <= maxZ + 1; posZ++) { if (getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId() == 9 || getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId() == 8) { MovecraftLocation loc = new MovecraftLocation(posX, posY, posZ); updateSet.add(new MapUpdateCommand(loc, 0, (byte) 0, getCraft())); } } posX = maxX + 1; for (posZ = minZ - 1; posZ <= maxZ + 1; posZ++) { if (getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId() == 9 || getCraft().getW().getBlockAt(posX, posY, posZ).getTypeId() == 8) { MovecraftLocation loc = new MovecraftLocation(posX, posY, posZ); updateSet.add(new MapUpdateCommand(loc, 0, (byte) 0, getCraft())); } } } } //Set blocks that are no longer craft to air // /********************************************************************************************************** // * I had problems with ListUtils (I tryied commons-collections 3.2.1. and 4.0 without success) // * so I replaced Lists with Sets // * // * Caused by: java.lang.NoClassDefFoundError: org/apache/commons/collections/ListUtils // * at net.countercraft.movecraft.async.translation.TranslationTask.excecute(TranslationTask.java:716) // * mwkaicz 24-02-2015 // ***********************************************************************************************************/ // Set<MovecraftLocation> setA = new HashSet(Arrays.asList(blocksList)); // Set<MovecraftLocation> setB = new HashSet(Arrays.asList(newBlockList)); // setA.removeAll(setB); // MovecraftLocation[] arrA = new MovecraftLocation[0]; // arrA = setA.toArray(arrA); // List<MovecraftLocation> airLocation = Arrays.asList(arrA); List<MovecraftLocation> airLocation = ListUtils.subtract(Arrays.asList(blocksList), Arrays.asList(newBlockList)); for (MovecraftLocation l1 : airLocation) { // for watercraft, fill blocks below the waterline with water if (!waterCraft) { if (getCraft().getSinking()) { updateSet.add(new MapUpdateCommand(l1, 0, (byte) 0, getCraft(), getCraft().getType().getSmokeOnSink())); } else { updateSet.add(new MapUpdateCommand(l1, 0, (byte) 0, getCraft())); } } else { if (l1.getY() <= waterLine) { // if there is air below the ship at the current position, don't fill in with water MovecraftLocation testAir = new MovecraftLocation(l1.getX(), l1.getY() - 1, l1.getZ()); while (existingBlockSet.contains(testAir)) { testAir.setY(testAir.getY() - 1); } if (getCraft().getW().getBlockAt(testAir.getX(), testAir.getY(), testAir.getZ()) .getTypeId() == 0) { if (getCraft().getSinking()) { updateSet.add(new MapUpdateCommand(l1, 0, (byte) 0, getCraft(), getCraft().getType().getSmokeOnSink())); } else { updateSet.add(new MapUpdateCommand(l1, 0, (byte) 0, getCraft())); } } else { updateSet.add(new MapUpdateCommand(l1, 9, (byte) 0, getCraft())); } } else { if (getCraft().getSinking()) { updateSet.add(new MapUpdateCommand(l1, 0, (byte) 0, getCraft(), getCraft().getType().getSmokeOnSink())); } else { updateSet.add(new MapUpdateCommand(l1, 0, (byte) 0, getCraft())); } } } } //add destroyed parts of growed for (MovecraftLocation destroyedLocation : destroyedBlocks) { updateSet.add(new MapUpdateCommand(destroyedLocation, 0, (byte) 0, getCraft())); } MapUpdateCommand[] updateArray = updateSet.toArray(new MapUpdateCommand[1]); // MapUpdateManager.getInstance().sortUpdates(updateArray); data.setUpdates(updateArray); data.setEntityUpdates(entityUpdateSet.toArray(new EntityUpdateCommand[1])); if (data.getDy() != 0) { data.setHitbox(BoundingBoxUtils.translateBoundingBoxVertically(data.getHitbox(), data.getDy())); } data.setMinX(data.getMinX() + data.getDx()); data.setMinZ(data.getMinZ() + data.getDz()); } captureYield(blocksList, harvestedBlocks); } private void fail(String message) { data.setFailed(true); data.setFailMessage(message); Player craftPilot = CraftManager.getInstance().getPlayerFromCraft(getCraft()); if (craftPilot != null) { Location location = craftPilot.getLocation(); if (getCraft().getDisabled() == false) { getCraft().getW().playSound(location, Sound.BLOCK_ANVIL_LAND, 1.0f, 0.25f); getCraft().setCurTickCooldown(getCraft().getType().getCruiseTickCooldown()); } else { getCraft().getW().playSound(location, Sound.ENTITY_IRONGOLEM_DEATH, 5.0f, 5.0f); getCraft().setCurTickCooldown(getCraft().getType().getCruiseTickCooldown()); } } } public TranslationTaskData getData() { return data; } private boolean isFreeSpace(int x, int y, int z, MovecraftLocation[] blocksList, HashSet<MovecraftLocation> existingBlockSet, boolean waterCraft, boolean hoverCraft, List<Material> harvestBlocks, boolean canHoverOverWater, boolean checkHover) { boolean isFree = true; // this checking for hovercrafts should be faster with separating horizontal layers and checking only realy necesseries, // or more better: remember what checked in each translation, but it's beyond my current abilities, I will try to solve it in future for (MovecraftLocation oldLoc : blocksList) { MovecraftLocation newLoc = oldLoc.translate(x, y, z); Material testMaterial = getCraft().getW().getBlockAt(newLoc.getX(), newLoc.getY(), newLoc.getZ()) .getType(); if (!canHoverOverWater) { if (testMaterial.equals(Material.STATIONARY_WATER) || testMaterial.equals(Material.WATER)) { fail(String.format( I18nSupport.getInternationalisedString("Translation - Failed Craft over water"))); } } if (newLoc.getY() >= data.getMaxHeight() && newLoc.getY() > oldLoc.getY() && !checkHover) { //if ( newLoc.getY() >= data.getMaxHeight() && newLoc.getY() > oldLoc.getY()) { isFree = false; break; } else if (newLoc.getY() <= data.getMinHeight() && newLoc.getY() < oldLoc.getY()) { isFree = false; break; } boolean blockObstructed; if (!waterCraft) { // New block is not air or a piston head and is not part of the existing ship blockObstructed = (!testMaterial.equals(Material.AIR)) && !existingBlockSet.contains(newLoc); } else { // New block is not air or water or a piston head and is not part of the existing ship blockObstructed = (!testMaterial.equals(Material.AIR) && !testMaterial.equals(Material.STATIONARY_WATER) && !testMaterial.equals(Material.WATER)) && !existingBlockSet.contains(newLoc); } if (blockObstructed && hoverCraft) { // New block is not harvested block and is not part of the existing craft if (harvestBlocks.contains(testMaterial) && !existingBlockSet.contains(newLoc)) { blockObstructed = false; } else { blockObstructed = true; } } if (blockObstructed) { isFree = false; break; } } return isFree; } 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; } private void captureYield(MovecraftLocation[] blocksList, List<MovecraftLocation> harvestedBlocks) { if (harvestedBlocks.isEmpty()) { return; } ArrayList<Inventory> chests = new ArrayList<Inventory>(); HashSet<ItemDropUpdateCommand> itemDropUpdateSet = new HashSet<ItemDropUpdateCommand>(); HashMap<MovecraftLocation, ItemStack[]> harvestedMap = new HashMap<MovecraftLocation, ItemStack[]>(); //find chests for (MovecraftLocation loc : getCraft().getBlockList()) { Block block = getCraft().getW().getBlockAt(loc.getX(), loc.getY(), loc.getZ()); if (block.getType() == Material.CHEST || block.getType() == Material.TRAPPED_CHEST) chests.add(((InventoryHolder) (block.getState())).getInventory()); } for (MovecraftLocation harvestedBlock : harvestedBlocks) { Block block = getCraft().getW().getBlockAt(harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()); ItemStack[] drops = block.getDrops().toArray(new ItemStack[block.getDrops().size()]); //generate seed drops if (block.getType() == Material.CROPS) { Random rand = new Random(); int amount = rand.nextInt(4); if (amount > 0) { ItemStack seeds = new ItemStack(Material.SEEDS, amount); HashSet<ItemStack> d = new HashSet<ItemStack>(Arrays.asList(drops)); d.add(seeds); drops = d.toArray(new ItemStack[d.size()]); } } //get contents of inventories before deposting if (block.getState() instanceof InventoryHolder) { if (block.getState() instanceof Chest) { //Inventory inv = ((DoubleChest) block.getState()).getRightSide().getInventory().getLocation().equals(block.getLocation()) ?((DoubleChest) block.getState()).getRightSide().getInventory(): ((DoubleChest) block.getState()).getLeftSide().getInventory(); //HashSet<ItemStack> d = new HashSet<ItemStack>(Arrays.asList(inv.getContents())); HashSet<ItemStack> d = new HashSet<ItemStack>( Arrays.asList(((Chest) block.getState()).getBlockInventory().getContents())); d.addAll(block.getDrops()); drops = d.toArray(new ItemStack[d.size()]); } else { HashSet<ItemStack> d = new HashSet<ItemStack>( Arrays.asList((((InventoryHolder) block.getState()).getInventory().getContents()))); d.addAll(block.getDrops()); drops = d.toArray(new ItemStack[d.size()]); } } for (ItemStack drop : drops) { ItemStack retStack = putInToChests(drop, chests); if (retStack != null) //drop items on position itemDropUpdateSet.add(new ItemDropUpdateCommand(new Location(getCraft().getW(), harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()), retStack)); } } data.setItemDropUpdates(itemDropUpdateSet.toArray(new ItemDropUpdateCommand[1])); } private ItemStack putInToChests(ItemStack stack, ArrayList<Inventory> inventories) { if (stack == null) return null; if (inventories == null || inventories.isEmpty()) return stack; for (Inventory inv : inventories) { int capacity = 0; for (ItemStack itemStack : inv) { if (itemStack == null || itemStack.getType() == Material.AIR) { capacity += stack.getMaxStackSize(); } else if (itemStack.isSimilar(stack)) { capacity += stack.getMaxStackSize() - itemStack.getAmount(); } } if (stack.getAmount() > capacity) { ItemStack tempItem = stack.clone(); tempItem.setAmount(capacity); stack.setAmount(stack.getAmount() - capacity); inv.addItem(tempItem); } else { inv.addItem(stack); return null; } } return stack; } private void tryPutToDestroyBox(Material mat, MovecraftLocation loc, List<MovecraftLocation> harvestedBlocks, List<MovecraftLocation> destroyedBlocks) { if (mat.equals(Material.DOUBLE_PLANT) || mat.equals(Material.WOODEN_DOOR) || mat.equals(Material.IRON_DOOR_BLOCK)) { if (getCraft().getW().getBlockAt(loc.getX(), loc.getY() + 1, loc.getZ()).getType().equals(mat)) { MovecraftLocation tmpLoc = loc.translate(0, 1, 0); if (!destroyedBlocks.contains(tmpLoc) && !harvestedBlocks.contains(tmpLoc)) { destroyedBlocks.add(tmpLoc); } } else if (getCraft().getW().getBlockAt(loc.getX(), loc.getY() - 1, loc.getZ()).getType().equals(mat)) { MovecraftLocation tmpLoc = loc.translate(0, -1, 0); if (!destroyedBlocks.contains(tmpLoc) && !harvestedBlocks.contains(tmpLoc)) { destroyedBlocks.add(tmpLoc); } } } else if (mat.equals(Material.CACTUS) || mat.equals(Material.SUGAR_CANE_BLOCK)) { MovecraftLocation tmpLoc = loc.translate(0, 1, 0); Material tmpType = getCraft().getW().getBlockAt(tmpLoc.getX(), tmpLoc.getY(), tmpLoc.getZ()).getType(); while (tmpType.equals(mat)) { if (!harvestedBlocks.contains(tmpLoc)) { harvestedBlocks.add(tmpLoc); destroyedBlocks.add(tmpLoc); } tmpLoc = tmpLoc.translate(0, 1, 0); tmpType = getCraft().getW().getBlockAt(tmpLoc.getX(), tmpLoc.getY(), tmpLoc.getZ()).getType(); } } else if (mat.equals(Material.BED_BLOCK)) { if (getCraft().getW().getBlockAt(loc.getX() + 1, loc.getY(), loc.getZ()).getType().equals(mat)) { MovecraftLocation tmpLoc = loc.translate(1, 0, 0); if (!destroyedBlocks.contains(tmpLoc) && !harvestedBlocks.contains(tmpLoc)) { destroyedBlocks.add(tmpLoc); } } else if (getCraft().getW().getBlockAt(loc.getX() - 1, loc.getY(), loc.getZ()).getType().equals(mat)) { MovecraftLocation tmpLoc = loc.translate(-1, 0, 0); if (!destroyedBlocks.contains(tmpLoc) && !harvestedBlocks.contains(tmpLoc)) { destroyedBlocks.add(tmpLoc); } } if (getCraft().getW().getBlockAt(loc.getX(), loc.getY(), loc.getZ() + 1).getType().equals(mat)) { MovecraftLocation tmpLoc = loc.translate(0, 0, 1); if (!destroyedBlocks.contains(tmpLoc) && !harvestedBlocks.contains(tmpLoc)) { destroyedBlocks.add(tmpLoc); } } else if (getCraft().getW().getBlockAt(loc.getX(), loc.getY(), loc.getZ() - 1).getType().equals(mat)) { MovecraftLocation tmpLoc = loc.translate(0, 0, -1); if (!destroyedBlocks.contains(tmpLoc) && !harvestedBlocks.contains(tmpLoc)) { destroyedBlocks.add(tmpLoc); } } } //clear from previous because now it is in harvest if (destroyedBlocks.contains(loc)) { destroyedBlocks.remove(loc); } } }