package in.twizmwaz.cardinal.module.modules.fallingBlocks; import com.google.common.collect.Lists; import in.twizmwaz.cardinal.Cardinal; import in.twizmwaz.cardinal.module.Module; import in.twizmwaz.cardinal.module.modules.filter.FilterState; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.util.Vector; import java.util.List; import java.util.Set; public class FallingBlocksModule implements Module { private static BlockFace[] FACES = {BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST, BlockFace.UP, BlockFace.DOWN}; private Set<Rule> rules; public FallingBlocksModule(Set<Rule> rules) { this.rules = rules; } @Override public void unload() { HandlerList.unregisterAll(this); } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onBlockPlace(BlockPlaceEvent event) { scheduleUpdate(event.getBlock()); } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onBlockBreak(BlockBreakEvent event) { scheduleUpdate(event.getBlock()); } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onBlockUpdate(BlockPhysicsEvent event) { scheduleUpdate(event.getBlock()); } private void scheduleUpdate(final Block block) { for (final Rule rule : rules) { Bukkit.getScheduler().runTaskLater(Cardinal.getInstance(), new Runnable() { @Override public void run() { updateBlock(block, rule); } }, rule.getDelay()); } } private void updateBlock(Block block, Rule rule) { if(rule.getFilter().evaluate(block).equals(FilterState.ALLOW)) { if (!isBlockAttached(block, rule)) { if (block.getRelative(BlockFace.DOWN).getType().equals(Material.AIR)) { Material material = block.getType(); byte data = block.getData(); block.setType(Material.AIR); Cardinal.getInstance().getGameHandler().getMatchWorld().spawnFallingBlock(block.getLocation(), material, data); } else { updateBlock(block.getRelative(BlockFace.DOWN), rule); } } } } private boolean isBlockAttached(Block source, Rule rule) { List<Block> nextScan = Lists.newArrayList(); List<Vector> alreadyScanned = Lists.newArrayList(); nextScan.add(source); alreadyScanned.add(source.getLocation().toVector()); return isBlockAttached(nextScan, rule, alreadyScanned); } private boolean isBlockAttached(List<Block> scan, Rule rule, List<Vector> alreadyScanned) { if (scan.size() == 0) return false; List<Block> nextScan = Lists.newArrayList(); for (Block scanning : scan) { if (alreadyScanned.size() > 4096) { Bukkit.getConsoleSender().sendMessage("Maximim scan area (4096 blocks) was reached."); return true; } for (BlockFace face : FACES) { Block block = scanning.getRelative(face); if (alreadyScanned.contains(block.getLocation().toVector())) continue; if (rule.getSticky().evaluate(block).equals(FilterState.ALLOW) || (face.equals(BlockFace.DOWN) && !block.getType().equals(Material.AIR))) { if (rule.getFilter().evaluate(block).equals(FilterState.ALLOW)) { nextScan.add(block); alreadyScanned.add(block.getLocation().toVector()); } else return true; } } } return isBlockAttached(nextScan, rule, alreadyScanned); } }