diff --git a/core/src/main/java/com/boydti/fawe/command/AnvilCommands.java b/core/src/main/java/com/boydti/fawe/command/AnvilCommands.java index fd3bb15b..2441c191 100644 --- a/core/src/main/java/com/boydti/fawe/command/AnvilCommands.java +++ b/core/src/main/java/com/boydti/fawe/command/AnvilCommands.java @@ -5,6 +5,7 @@ import com.boydti.fawe.FaweCache; import com.boydti.fawe.config.BBC; import com.boydti.fawe.jnbt.anvil.MCAChunk; import com.boydti.fawe.jnbt.anvil.MCAClipboard; +import com.boydti.fawe.jnbt.anvil.MCAFile; import com.boydti.fawe.jnbt.anvil.MCAFilter; import com.boydti.fawe.jnbt.anvil.MCAFilterCounter; import com.boydti.fawe.jnbt.anvil.MCAQueue; @@ -35,6 +36,9 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.parametric.Optional; import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -89,6 +93,45 @@ public class AnvilCommands { player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(counter.getTotal())); } + @Command( + aliases = {"deleteallold"}, + usage = " [file-age=60000]", + desc = "Delete all chunks which haven't been occupied for `age-ticks` and have been accessed since `file-age` (ms) after creation", + min = 2, + max = 3 + ) + @CommandPermissions("worldedit.anvil.deleteallold") + public void deleteAllOld(Player player, EditSession editSession, String folder, int inhabitedTicks, @Optional("60000") int fileAgeMillis) throws WorldEditException { + FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(folder, true, false); + MCAQueue queue = new MCAQueue(folder, defaultQueue.getSaveFolder(), defaultQueue.hasSky()); + MCAFilterCounter result = queue.filterWorld(new MCAFilterCounter() { + @Override + public MCAFile applyFile(MCAFile mca) { + File file = mca.getFile(); + try { + BasicFileAttributes attr = Files.readAttributes(file.toPath(), BasicFileAttributes.class); + long creation = attr.creationTime().toMillis(); + long modified = attr.lastModifiedTime().toMillis(); + if (modified - creation < fileAgeMillis) { + mca.setDeleted(true); + get().add(512 * 512 * 256); + } + } catch (IOException | UnsupportedOperationException ignore) {} + return mca; + } + + @Override + public MCAChunk applyChunk(MCAChunk chunk, MutableLong count) { + if (chunk.getInhabitedTime() <= inhabitedTicks) { + count.add(16 * 16 * 256); + chunk.setDeleted(true); + } + return null; + } + }); + player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal())); + } + @Command( aliases = {"replaceallpattern", "reap", "repallpat"}, usage = " [from-block] ", diff --git a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java index c5bdff2c..46e09073 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java @@ -384,6 +384,7 @@ public class MCAFile { } public void close(ForkJoinPool pool) { + if (raf == null) return; synchronized (raf) { if (raf != null) { flush(pool); @@ -411,7 +412,7 @@ public class MCAFile { final Int2ObjectOpenHashMap append = new Int2ObjectOpenHashMap<>(); boolean modified = false; for (MCAChunk chunk : getCachedChunks()) { - if (chunk.isModified()) { + if (chunk.isModified() || chunk.isDeleted()) { modified = true; if (!chunk.isDeleted()) { pool.submit(new Runnable() { @@ -468,8 +469,8 @@ public class MCAFile { int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31)); byte[] newBytes = relocate.get(pair); if (newBytes == null) { + MCAChunk cached = getCachedChunk(cx, cz); if (offset == start) { - MCAChunk cached = getCachedChunk(cx, cz); if (cached == null || !cached.isModified()) { writeHeader(raf, cx, cz, start >> 12, size >> 12, true); start += size; @@ -481,7 +482,9 @@ public class MCAFile { } else { newBytes = compressedMap.get(pair); if (newBytes == null) { - newBytes = getChunkCompressedBytes(getOffset(cx, cz)); + if (cached == null || !cached.isDeleted()) { + newBytes = getChunkCompressedBytes(getOffset(cx, cz)); + } } } }