package com.boydti.fawe.regions.general.plot; import com.boydti.fawe.jnbt.anvil.MCAChunk; import com.boydti.fawe.jnbt.anvil.MCAFile; import com.boydti.fawe.jnbt.anvil.MCAFilter; import com.boydti.fawe.jnbt.anvil.MCAQueue; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.SetQueue; import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.object.ChunkLoc; import com.intellectualcrafters.plot.object.Location; import com.intellectualcrafters.plot.object.Plot; import com.intellectualcrafters.plot.object.PlotArea; import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.util.expiry.ExpireManager; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import static com.google.common.base.Preconditions.checkNotNull; public class PlotTrim { private final MCAQueue queue; private final PlotArea area; private final PlotPlayer player; private final MCAQueue originalQueue; private final File root; private final File originalRoot; private byte[][] ids; private boolean deleteUnowned = true; public PlotTrim(PlotPlayer player, PlotArea area, String worldName, boolean deleteUnowned) { FaweQueue tmpQueue = SetQueue.IMP.getNewQueue(worldName, true, false); File saveFolder = tmpQueue.getSaveFolder(); this.root = new File(saveFolder.getParentFile().getParentFile(), worldName + "-Copy" + File.separator + "region"); this.originalRoot = saveFolder; this.originalQueue = new MCAQueue(worldName, originalRoot, true); this.queue = new MCAQueue(worldName + "-Copy", root, true); this.area = area; this.player = player; this.deleteUnowned = deleteUnowned; } public void setChunk(byte[][] ids) { checkNotNull(ids); this.ids = ids; } public void setChunk(int x, int z) { this.ids = ((MCAChunk) originalQueue.getFaweChunk(x, z)).ids; } private Map chunks = new ConcurrentHashMap<>(); private Object PRESENT = new Object(); private void removeChunks(Plot plot) { Location pos1 = plot.getBottom(); Location pos2 = plot.getTop(); int ccx1 = pos1.getX() >> 4; int ccz1 = pos1.getZ() >> 4; int ccx2 = pos2.getX() >> 4; int ccz2 = pos2.getZ() >> 4; for (int x = ccx1; x <= ccx2; x++) { for (int z = ccz1; z <= ccz2; z++) { long pair = MathMan.pairInt(x, z); chunks.remove(pair); } } } public void run() { final Set mcas = new HashSet<>(); if (deleteUnowned && area != null) { originalQueue.filterWorld(new MCAFilter() { @Override public boolean appliesFile(int mcaX, int mcaZ) { mcas.add(new ChunkLoc(mcaX, mcaZ)); return false; } }); ArrayList plots = new ArrayList<>(); plots.addAll(PS.get().getPlots(area)); if (ExpireManager.IMP != null) { plots.removeAll(ExpireManager.IMP.getPendingExpired()); } for (Plot plot : plots) { Location pos1 = plot.getBottom(); Location pos2 = plot.getTop(); int ccx1 = pos1.getX() >> 9; int ccz1 = pos1.getZ() >> 9; int ccx2 = pos2.getX() >> 9; int ccz2 = pos2.getZ() >> 9; for (int x = ccx1; x <= ccx2; x++) { for (int z = ccz1; z <= ccz2; z++) { ChunkLoc loc = new ChunkLoc(x, z); mcas.remove(loc); } } } for (ChunkLoc mca : mcas) { int bx = mca.x << 5; int bz = mca.z << 5; for (int x = 0; x < 32; x++) { for (int z = 0; z < 32; z++) { long pair = MathMan.pairInt(bx + x, bz + z); chunks.put(pair, PRESENT); } } } for (Plot plot : plots) { removeChunks(plot); } } originalQueue.filterWorld(new MCAFilter() { @Override public boolean appliesFile(int mcaX, int mcaZ) { ChunkLoc loc = new ChunkLoc(mcaX, mcaZ); if (mcas.contains(loc)) { return false; } return true; } @Override public MCAFile applyFile(MCAFile mca) { int mcaX = mca.getX(); int mcaZ = mca.getZ(); ChunkLoc loc = new ChunkLoc(mcaX, mcaZ); if (mcas.contains(loc)) { player.sendMessage("Delete MCA " + mca); mca.setDeleted(true); return null; } try { File copy = new File(root, mca.getFile().getName()); if (!copy.exists()) { copy = MainUtil.copyFile(mca.getFile(), copy); player.sendMessage("Filter copy -> " + copy); } else { player.sendMessage("Filter existing: " + mcaX + "," + mcaZ); } return new MCAFile(mca.getParent(), copy); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } @Override public boolean appliesChunk(int cx, int cz) { return true; } @Override public MCAChunk applyChunk(MCAChunk chunk, Object ignore) { long pair = MathMan.pairInt(chunk.getX(), chunk.getZ()); if (chunks.containsKey(pair)) { chunk.setDeleted(true); return null; } if (ids != null) { for (int i = 0; i < ids.length; i++) { if (!isEqual(ids[i], chunk.ids[i])) { return null; } } chunk.setDeleted(true); } return null; } }); player.sendMessage("Done!"); } private int count = 0; private boolean isEqual(byte[] a, byte[] b) { if (a == b) { return true; } if (a != null) { if (b != null) { return Arrays.equals(a, b); } return isEmpty(a); } return isEmpty(b); } private boolean isEmpty(byte[] a) { for (byte b : a) { if (b != 0) { return false; } } return true; } }