/******************************************************************************* * This file is part of ASkyBlock. * * ASkyBlock 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. * * ASkyBlock 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 ASkyBlock. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ package com.wasteofplastic.askyblock; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.bukkit.Chunk; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.inventory.InventoryHolder; import org.bukkit.scheduler.BukkitRunnable; import com.wasteofplastic.askyblock.nms.NMSAbstraction; import com.wasteofplastic.askyblock.util.Pair; import com.wasteofplastic.askyblock.util.Util; //import com.wasteofplastic.askyblock.nms.NMSAbstraction; /** * Deletes islands fast using chunk regeneration * * @author tastybento * */ public class DeleteIslandChunk { private Set<Pair> chunksToClear = new HashSet<Pair>(); //private HashMap<Location, Material> blocksToClear = new HashMap<Location,Material>(); private NMSAbstraction nms = null; public DeleteIslandChunk(final ASkyBlock plugin, final Island island) { final World world = island.getCenter().getWorld(); if (world == null) return; // Determine if blocks need to be cleaned up or not boolean cleanUpBlocks = false; if (Settings.islandDistance - island.getProtectionSize() < 16) { cleanUpBlocks = true; } int range = island.getProtectionSize() / 2 * +1; final int minx = island.getMinProtectedX(); final int minz = island.getMinProtectedZ(); final int maxx = island.getMinProtectedX() + island.getProtectionSize(); final int maxz = island.getMinProtectedZ() + island.getProtectionSize(); // plugin.getLogger().info("DEBUG: protection limits are: " + minx + // ", " + minz + " to " + maxx + ", " + maxz ); int islandSpacing = Settings.islandDistance - island.getProtectionSize(); int minxX = (island.getCenter().getBlockX() - range - islandSpacing); int minzZ = (island.getCenter().getBlockZ() - range - islandSpacing); int maxxX = (island.getCenter().getBlockX() + range + islandSpacing); int maxzZ = (island.getCenter().getBlockZ() + range + islandSpacing); // plugin.getLogger().info("DEBUG: absolute max limits are: " + minxX + // ", " + minzZ + " to " + maxxX + ", " + maxzZ ); // get the chunks for these locations final Chunk minChunk = world.getBlockAt(minx,0,minz).getChunk(); final Chunk maxChunk = world.getBlockAt(maxx, 0, maxz).getChunk(); // Find out what chunks are within the island protection range // plugin.getLogger().info("DEBUG: chunk limits are: " + // (minChunk.getBlock(0, 0, 0).getLocation().getBlockX()) + ", " + // (minChunk.getBlock(0, 0, 0).getLocation().getBlockZ()) // + " to " + (maxChunk.getBlock(15, 0, 15).getLocation().getBlockX()) + // ", " + (maxChunk.getBlock(15, 0, 15).getLocation().getBlockZ())); for (int x = minChunk.getX(); x <= maxChunk.getX(); x++) { for (int z = minChunk.getZ(); z <= maxChunk.getZ(); z++) { boolean regen = true; if (world.getChunkAt(x, z).getBlock(0, 0, 0).getX() < minxX) { // plugin.getLogger().info("DEBUG: min x coord is less than absolute min! " // + minxX); regen = false; } if (world.getChunkAt(x, z).getBlock(0, 0, 0).getZ() < minzZ) { // plugin.getLogger().info("DEBUG: min z coord is less than absolute min! " // + minzZ); regen = false; } if (world.getChunkAt(x, z).getBlock(15, 0, 15).getX() > maxxX) { // plugin.getLogger().info("DEBUG: max x coord is more than absolute max! " // + maxxX); regen = false; } if (world.getChunkAt(x, z).getBlock(15, 0, 15).getZ() > maxzZ) { // plugin.getLogger().info("DEBUG: max z coord in chunk is more than absolute max! " // + maxzZ); regen = false; } if (regen) { world.regenerateChunk(x, z); if (Settings.newNether && Settings.createNether) { if (world.equals(ASkyBlock.getIslandWorld())) { ASkyBlock.getNetherWorld().regenerateChunk(x, z); } if (world.equals(ASkyBlock.getNetherWorld())) { ASkyBlock.getIslandWorld().regenerateChunk(x, z); } } } else { // Add to clear up list if requested if (cleanUpBlocks) { chunksToClear.add(new Pair(x,z)); } } } } // Remove from grid plugin.getGrid().deleteIsland(island.getCenter()); // Clear up any chunks if (!chunksToClear.isEmpty()) { try { nms = Util.checkVersion(); } catch (Exception ex) { plugin.getLogger().warning("Cannot clean up blocks because there is no NMS acceleration available"); return; } plugin.getLogger().info("Island delete: There are " + chunksToClear.size() + " chunks that need to be cleared up."); plugin.getLogger().info("Clean rate is " + Settings.cleanRate + " chunks per second. Should take ~" + Math.round(chunksToClear.size()/Settings.cleanRate) + "s"); new BukkitRunnable() { @SuppressWarnings("deprecation") @Override public void run() { Iterator<Pair> it = chunksToClear.iterator(); int count = 0; while (it.hasNext() && count++ < Settings.cleanRate) { Pair pair = it.next(); //plugin.getLogger().info("DEBUG: There are " + chunksToClear.size() + " chunks that need to be cleared up"); //plugin.getLogger().info("DEBUG: Deleting chunk " + pair.getLeft() + ", " + pair.getRight()); // Check if coords are in island space for (int x = 0; x < 16; x ++) { for (int z = 0; z < 16; z ++) { int xCoord = pair.getLeft() * 16 + x; int zCoord = pair.getRight() * 16 + z; if (island.inIslandSpace(xCoord, zCoord)) { //plugin.getLogger().info(xCoord + "," + zCoord + " is in island space - deleting column"); // Delete all the blocks here for (int y = 0; y < ASkyBlock.getIslandWorld().getMaxHeight(); y ++) { // Overworld Block b = ASkyBlock.getIslandWorld().getBlockAt(xCoord, y, zCoord); Material bt = b.getType(); Material setTo = Material.AIR; // Split depending on below or above water line if (y < Settings.seaHeight) { setTo = Material.STATIONARY_WATER; } // Grab anything out of containers (do that it is // destroyed) switch (bt) { case CHEST: case TRAPPED_CHEST: case FURNACE: case DISPENSER: case HOPPER: final InventoryHolder ih = ((InventoryHolder)b.getState()); ih.getInventory().clear(); b.setType(setTo); break; case AIR: if (setTo.equals(Material.STATIONARY_WATER)) { nms.setBlockSuperFast(b, setTo.getId(), (byte)0, false); } case STATIONARY_WATER: if (setTo.equals(Material.AIR)) { nms.setBlockSuperFast(b, setTo.getId(), (byte)0, false); } default: nms.setBlockSuperFast(b, setTo.getId(), (byte)0, false); break; } // Nether, if it exists if (Settings.newNether && Settings.createNether && y < ASkyBlock.getNetherWorld().getMaxHeight() - 8) { b = ASkyBlock.getNetherWorld().getBlockAt(xCoord, y, zCoord); bt = b.getType(); if (!b.equals(Material.AIR)) { setTo = Material.AIR; // Grab anything out of containers (do that it is // destroyed) switch (bt) { case CHEST: case TRAPPED_CHEST: case FURNACE: case DISPENSER: case HOPPER: final InventoryHolder ih = ((InventoryHolder)b.getState()); ih.getInventory().clear(); b.setType(setTo); break; default: nms.setBlockSuperFast(b, setTo.getId(), (byte)0, false); break; } } } } } } } it.remove(); } if (chunksToClear.isEmpty()){ plugin.getLogger().info("Finished island deletion"); this.cancel(); } } }.runTaskTimer(plugin, 0L, 20L); } } }