package de.steamwar.towerrun.generator; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.session.ClipboardHolder; import de.steamwar.sql.SchematicData; import de.steamwar.sql.SchematicNode; import de.steamwar.towerrun.TowerRun; import de.steamwar.towerrun.config.WorldConfig; import de.steamwar.towerrun.game.TowerRunGame; import lombok.Getter; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.*; import org.bukkit.block.data.Bisected; import org.bukkit.block.data.type.Door; import org.bukkit.scheduler.BukkitRunnable; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Random; public class TowerGenerator { private static final Random random = new Random(); private final WorldConfig.TowerGeneratorConfig config; private final List allSchematics; private final Clipboard roof; @Getter private int height; @Getter private Location spawn; @Getter private List keys = new ArrayList<>(); public TowerGenerator(WorldConfig.TowerGeneratorConfig config) { File file = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "Roof.schem"); if (!file.exists()) { Bukkit.shutdown(); throw new SecurityException("TowerRun schematic not found"); } roof = loadSchematic(file); this.config = config; allSchematics = SchematicNode.getAllSchematicsOfType(config.schematicType); spawn = WorldConfig.SPAWN; } private Clipboard loadSchematic(File file) { Clipboard clipboard; try (ClipboardReader reader = Objects.requireNonNull(ClipboardFormats.findByFile(file)).getReader(new FileInputStream(file))) { clipboard = reader.read(); } catch (NullPointerException | IOException e) { Bukkit.shutdown(); throw new SecurityException("TowerRun schematic not found", e); } return clipboard; } public void generate() { new BukkitRunnable() { int height = random.nextInt(config.maxHeight - config.minHeight) + config.minHeight; int y = TowerGenerator.this.config.y; int noBombFloors; int noKeyFloors; { TowerGenerator.this.height = 0; noBombFloors = random.nextInt(config.maxNoBombFloors - config.minNoBombFloors) + config.minNoBombFloors; noKeyFloors = random.nextInt(config.maxNoKeyFloors - config.minNoKeyFloors) + config.minNoKeyFloors; keys.clear(); } @Override public void run() { if (height > 0) { SchematicNode schematicNode = allSchematics.get(random.nextInt(allSchematics.size())); SchematicData schematicData = new SchematicData(schematicNode); int currentY; int width; int depth; try { Clipboard clipboard = schematicData.load(); try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorlds().get(0)), -1)) { ClipboardHolder ch = new ClipboardHolder(clipboard); Operations.completeBlindly(ch.createPaste(e).to(BlockVector3.at(config.x, y, config.z)).build()); } width = clipboard.getDimensions().getX(); depth = clipboard.getDimensions().getZ(); currentY = y; y += clipboard.getDimensions().getY(); height -= clipboard.getDimensions().getY(); TowerGenerator.this.height += clipboard.getDimensions().getY(); } catch (IOException e) { allSchematics.remove(schematicNode); return; } spawn = WorldConfig.SPAWN.clone().add(0, y, 0); List chestBlocks = new ArrayList<>(); for (int x = config.x; x < config.x + width; x++) { for (int z = config.z; z < config.z + depth; z++) { for (int y = currentY; y < this.y; y++) { Block block = Bukkit.getWorlds().get(0).getBlockAt(x, y, z); BlockState blockState = block.getState(); if (blockState instanceof Chest) { chestBlocks.add((Container) blockState); } } } } noBombFloors--; if (noBombFloors < 0 && random.nextDouble() < config.tntChance) { noBombFloors = random.nextInt(config.maxNoBombFloors - config.minNoBombFloors) + config.minNoBombFloors; int bombCount = random.nextInt(config.maxBombs - config.minBombs) + config.minBombs; for (int i = 0; i < bombCount; i++) { WorldConfig.Region region = config.tntRegions[random.nextInt(config.tntRegions.length)]; int x = random.nextInt(region.max.getBlockX() - region.min.getBlockX()) + region.min.getBlockX(); int z = random.nextInt(region.max.getBlockZ() - region.min.getBlockZ()) + region.min.getBlockZ(); int y = currentY + 1; Bukkit.getWorlds().get(0).getBlockAt(x, y, z).setType(Material.TNT, true); } } noKeyFloors--; if (!chestBlocks.isEmpty() && noKeyFloors < 0 && random.nextDouble() < config.keyChance) { noKeyFloors = random.nextInt(config.maxNoKeyFloors - config.minNoKeyFloors) + config.minNoKeyFloors; Container container = chestBlocks.get(random.nextInt(chestBlocks.size())); keys.add(container.getLocation()); for (WorldConfig.TowerGeneratorDoorBlock doorBlock : config.doorBlocks) { int x = doorBlock.getX(); int y = currentY + doorBlock.getDy(); int z = doorBlock.getZ(); Block block = Bukkit.getWorlds().get(0).getBlockAt(x, y, z); for (int i = 0; i < 5; i++) { if (block.getType().isAir()) { block.setType(Material.IRON_BLOCK, false); block = block.getRelative(0, 1, 0); } else { break; } } Bukkit.getScheduler().runTaskLater(TowerRun.getInstance(), () -> { Block door = Bukkit.getWorlds().get(0).getBlockAt(x, y, z); door.setType(Material.IRON_DOOR, false); door = door.getRelative(0, 1, 0); door.setType(Material.IRON_DOOR, false); }, 10); Bukkit.getScheduler().runTaskLater(TowerRun.getInstance(), () -> { Block door = Bukkit.getWorlds().get(0).getBlockAt(x, y, z); Door doorState = (Door) door.getBlockData(); doorState.setFacing(BlockFace.EAST); door.setBlockData(doorState, false); door = door.getRelative(0, 1, 0); doorState = (Door) door.getBlockData(); doorState.setFacing(BlockFace.EAST); doorState.setHalf(Bisected.Half.TOP); door.setBlockData(doorState, false); }, 20); } } for (WorldConfig.TowerGeneratorFillRegion fillRegion : config.fillRegions) { for (int x = fillRegion.getMinX(); x < fillRegion.getMaxX(); x++) { for (int z = fillRegion.getMinZ(); z < fillRegion.getMaxZ(); z++) { for (int y = currentY; y < this.y; y++) { Block block = Bukkit.getWorlds().get(0).getBlockAt(x, y, z); if (!block.getType().isAir()) { continue; } if (random.nextDouble() < fillRegion.getPercentage()) { block.setType(fillRegion.getMaterial(), true); } } } } } } else { cancel(); try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorlds().get(0)), -1)) { ClipboardHolder ch = new ClipboardHolder(roof); Operations.completeBlindly(ch.createPaste(e).to(BlockVector3.at(config.x, y, config.z)).build()); } TowerRunGame.start(); } } }.runTaskTimer(TowerRun.getInstance(), 0, 10); } }