• new
  • Powered by GeSHi
package schempaster;
 
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.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Sign;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
 
public class SchemPaster extends JavaPlugin
{
 
    private World world;
    private EditSession session;
    private String folder = "";
    private YamlConfiguration yaml = new YamlConfiguration();
 
    private List<Long> pasttimes = new ArrayList();
    private double tps;
    private final Object tpslock = new Object();
 
    @Override
    public void onEnable()
    {
        pasttimes = new ArrayList(Arrays.asList(0l, 0l));
        Bukkit.getScheduler().scheduleSyncRepeatingTask(this() ->
                                                {
                                                    synchronized (tpslock)
                                                    {
                                                        pasttimes.add(System.currentTimeMillis());
                                                        if (pasttimes.size() > 20)
                                                            pasttimes.remove((int) 0);
                                                        tps = IntStream.range(0, pasttimes.size() - 1)
                                                                .map(-> (int) (pasttimes.get(+ 1) - pasttimes.get(i)))
                                                                .sum() / (double) (pasttimes.size() - 1) / 50d * 20d;
                                                    }
                                                }01);
    }
 
    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args)
    {
        if (sender != Bukkit.getConsoleSender())
        {
            sender.sendMessage(ChatColor.RED + "Console only!");
            return true;
        }
        if (Bukkit.isPrimaryThread())
        {
            if (args.length != 1 && args.length != 2)
            {
                getLogger().severe("/schempaster <world> [schematic folder]");
                return true;
            }
            world = Bukkit.getWorld(args[0]);
            if (world == null)
            {
                getLogger().severe("World not found");
                return true;
            }
            session = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(world)-1);
            folder = "";
            if (args.length == 2)
            {
                folder = args[1] + "/";
            }
 
            new Thread(() -> onCommand(sender, command, label, args)).start();
            return true;
        }
 
        System.out.println("searching " + new File(folder).getAbsolutePath());
        List<File> files = getAllFiles(new File(folder));
        files = files.stream().filter(-> !("" + e).endsWith(".yml")).collect(Collectors.toList());
        getLogger().info("Found " + files.size() + " files. Pasting now ...");
 
        List<Map.Entry<Long, Integer>> timings = new ArrayList();
        int currentx = 0;
        for (File f : files)
        {
            getLogger().info("---------------------------------------------------------------------------");
            long now = System.currentTimeMillis();
            if (!timings.isEmpty())
            {
                float schempm = (float) (timings.stream().filter(-> e.getKey() > now - 5 * 60 * 1000).count() / 5d);
                schempm = (float) (Math.floor(100 * schempm) / 100);
                int eta = (int) ((files.size() - files.indexOf(f)) / (schempm / 60));
                float progress = 100f * files.indexOf(f) / files.size();
                progress = (float) (Math.floor(100 * progress) / 100);
                getLogger().info("Status"
                                 + " " + (files.indexOf(f) + 1) + "/" + files.size() + "(" + progress + "%);"
                                 + " eta: " + (eta / 60) + ":" + (eta % 60) + ";"
                                 + " " + schempm + " Schem/m");
            }
            getLogger().info("Pasting " + f);
 
            //load
            Clipboard c;
            ClipboardFormat format = ClipboardFormats.findByFile(f);
            try(FileInputStream fis = new FileInputStream(f);
                BufferedInputStream bis = new BufferedInputStream(fis);
                ClipboardReader reader = format.getReader(bis);)
            {
                c = reader.read();
            }
            catch (Exception e)
            {
                getLogger().severe("Failed to load schematic: " + f.getAbsolutePath());
                e.printStackTrace();
                continue;
            }
 
            //compute paste point
            BlockVector3 min = BlockVector3.at(currentx, 10);
            BlockVector3 max = min.add(c.getRegion().getMaximumPoint().subtract(c.getRegion().getMinimumPoint()));
            BlockVector3 rel2schematicpastepoint = c.getOrigin().subtract(c.getRegion().getMinimumPoint());
            BlockVector3 pastepoint = min.add(rel2schematicpastepoint);
            ProtectedCuboidRegion pr = new ProtectedCuboidRegion(f.toString().replaceAll("\\..*?$""").replaceAll("[^a-zA-Z0-9]""_"),
                                                                 min, max);
            List<BlockVector2> chunks = chunks(min.subtract(111), max.add(111));
            List<Location> box = box(min.subtract(111), max.add(111));
            List<Location> outline = outline(min.subtract(111), max.add(111));
//            System.out.println("min " + min);
//            System.out.println("max " + max);
//            System.out.println("pp " + pastepoint);
            getLogger().info("Pasting " + c.getDimensions() + " (" + c.getRegion().getArea() + " blocks) ...");
 
            //paste
            Operation op = new ClipboardHolder(c)
                    .createPaste(session)
                    .to(pastepoint)
                    .copyBiomes(false)
                    .copyEntities(true)
                    .build();
            BukkitTask task = Bukkit.getScheduler().runTask(this() ->
                                                    {
                                                        chunks.forEach(-> world.getChunkAt(e.getBlockX(), e.getBlockZ()).load(true));
                                                        session.setFastMode(true);
                                                        Operations.completeBlindly(op);
                                                        session.flushSession();
 
                                                        WorldEdit.getInstance().flushBlockBag(null, session);
                                                        box.forEach(-> e.getBlock().setType(Material.BARRIER));
                                                        outline.forEach(-> e.getBlock().setType(Material.BEDROCK));
 
                                                        world.getBlockAt(min.getBlockX(), min.getBlockY() + 4, min.getBlockZ() - 2).setType(Material.LAPIS_BLOCK);
                                                        world.getBlockAt(min.getBlockX(), min.getBlockY() + 5, min.getBlockZ() - 2).setType(Material.REDSTONE_BLOCK);
                                                        world.getBlockAt(min.getBlockX() + 1, min.getBlockY() + 4, min.getBlockZ() - 2).setType(Material.OBSIDIAN);
                                                        world.getBlockAt(min.getBlockX() + 1, min.getBlockY() + 4, min.getBlockZ() - 3).setType(Material.OAK_WALL_SIGN);
                                                        Sign s = (Sign) world.getBlockAt(min.getBlockX() + 1, min.getBlockY() + 4, min.getBlockZ() - 3).getState();
                                                        String sx = "" + f;
                                                        sx = sx.substring(Math.max(0, sx.length() - 15 * 4), sx.length());
 
                                                        s.setLine(0, sx.substring(0Math.min(15, sx.length())));
                                                        s.setLine(1, sx.substring(Math.min(15, sx.length())Math.min(30, sx.length())));
                                                        s.setLine(2, sx.substring(Math.min(30, sx.length())Math.min(45, sx.length())));
                                                        s.setLine(3, sx.substring(Math.min(45, sx.length())Math.min(60, sx.length())));
                                                        s.update();
                                                        RegionManager rm = WorldGuard.getInstance().getPlatform().getRegionContainer().get(new BukkitWorld(world));
                                                        rm.addRegion(pr);
                                                        try
                                                        {
                                                            rm.save();
                                                        }
                                                        catch (Exception e)
                                                        {
                                                            getLogger().severe("WG failed to save regions!");
                                                            e.printStackTrace();
                                                        }
                                                    });
 
            //wait for copy
            while (Bukkit.getScheduler().isQueued(task.getTaskId()) || Bukkit.getScheduler().isCurrentlyRunning(task.getTaskId()))
            {
                try
                {
                    Thread.sleep(5000);
                }
                catch (InterruptedException ex)
                {
                }
            }
 
            yaml.set(pr.getId() + ".file""" + f);
            yaml.set(pr.getId() + ".origin.x", rel2schematicpastepoint.getX());
            yaml.set(pr.getId() + ".origin.y", rel2schematicpastepoint.getY());
            yaml.set(pr.getId() + ".origin.z", rel2schematicpastepoint.getZ());
 
            currentx += c.getRegion().getWidth() + 10;
 
            try
            {
                getLogger().info("Waiting for server to recover.");
//                Thread.sleep(2000);
 
                long lastprint = 0;
                while (tps < 10 || tps > 20.5 || System.currentTimeMillis() - lastTick() > 100)
                {
                    long ago = System.currentTimeMillis() - lastTick();
                    if (ago > 2000 && ago % 5000 < 100 && (ago - lastprint) > 5000)
                    {
                        getLogger().info("tps: " + tps + "; last tick " + (System.currentTimeMillis() - lastTick()) + "ms ago");
                        lastprint = ago;
                    }
                    Thread.sleep(500);
                }
//                getLogger().info("Continuing");
            }
            catch (InterruptedException ex)
            {
            }
 
            int dur = (int) (System.currentTimeMillis() - now);
            timings.add(new SimpleEntry(now, dur));
        }
        try
        {
            getLogger().info("Save paste infos ...");
            yaml.save(new File(getDataFolder().getAbsolutePath() + "/" + folder, "pastes.yml"));
        }
        catch (IOException ex)
        {
            sender.sendMessage("Failed to save import data.");
            ex.printStackTrace();
        }
        getLogger().info("Finished!");
        return true;
    }
 
    private List<File> getAllFiles(File f)
    {
        List<File> ret = new ArrayList();
        String[] list = f.list();
        Arrays.sort(list, (l, r) -> l.toLowerCase().compareTo(r.toLowerCase()));
        Arrays.stream(list).map(-> new File(f, e)).forEach(->
        {
            if (e.isDirectory())
                ret.addAll(getAllFiles(e));
            else if (e.isFile())
            {
                ret.add(e);
            }
        });
        return ret;
    }
 
    private List<BlockVector2> chunks(BlockVector3 min, BlockVector3 max)
    {
        min = min.subtract(48048);
        max = max.add(48048);
        BlockVector2 min2 = BlockVector2.at(min.getBlockX() >> 4, min.getBlockZ() >> 4);
        BlockVector2 max2 = BlockVector2.at(max.getBlockX() >> 4, max.getBlockZ() >> 4);
        return IntStream.range(min2.getBlockX(), max2.getBlockX() + 1)
                .mapToObj(x
                        -> IntStream.range(min2.getBlockZ(), max2.getBlockZ() + 1)
                        .mapToObj(-> BlockVector2.at(x, z)))
                .flatMap(-> e)
                .collect(Collectors.toList());
    }
 
    private List<Location> box(BlockVector3 min, BlockVector3 max)
    {
        return IntStream.range(min.getBlockX(), max.getBlockX() + 1)
                .mapToObj(x
                        -> IntStream.range(min.getBlockY(), max.getBlockY() + 1)
                        .mapToObj(y
                                -> IntStream.range(min.getBlockZ(), max.getBlockZ() + 1)
                                .mapToObj(-> new Location(world, x, y, z)))
                        .flatMap(-> e))
                .flatMap(-> e)
                .filter(-> ((e.getBlockX() == min.getBlockX() || e.getBlockX() == max.getBlockX()) ? 1 : 0)
                             + ((e.getBlockY() == min.getBlockY() || e.getBlockY() == max.getBlockY()) ? 1 : 0)
                             + ((e.getBlockZ() == min.getBlockZ() || e.getBlockZ() == max.getBlockZ()) ? 1 : 0) >= 1)
                .collect(Collectors.toList());
    }
 
    private List<Location> outline(BlockVector3 min, BlockVector3 max)
    {
        return IntStream.range(min.getBlockX(), max.getBlockX() + 1)
                .mapToObj(x
                        -> IntStream.range(min.getBlockY(), max.getBlockY() + 1)
                        .mapToObj(y
                                -> IntStream.range(min.getBlockZ(), max.getBlockZ() + 1)
                                .mapToObj(-> new Location(world, x, y, z)))
                        .flatMap(-> e))
                .flatMap(-> e)
                .filter(-> ((e.getBlockX() == min.getBlockX() || e.getBlockX() == max.getBlockX()) ? 1 : 0)
                             + ((e.getBlockY() == min.getBlockY() || e.getBlockY() == max.getBlockY()) ? 1 : 0)
                             + ((e.getBlockZ() == min.getBlockZ() || e.getBlockZ() == max.getBlockZ()) ? 1 : 0) >= 2)
                .collect(Collectors.toList());
    }
 
    private long lastTick()
    {
        synchronized (tpslock)
        {
            return pasttimes.get(pasttimes.size() - 1);
        }
    }
}