diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java index ff4bfc5a6..9660e4674 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java @@ -22,6 +22,7 @@ package com.intellectualcrafters.plot.commands; import java.sql.Timestamp; +import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; @@ -34,6 +35,8 @@ import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.entity.Player; +import com.intellectualcrafters.plot.PlotMain; +import com.intellectualcrafters.plot.object.ChunkLoc; import com.intellectualcrafters.plot.object.Plot; import com.intellectualcrafters.plot.util.ExpireManager; import com.intellectualcrafters.plot.util.PlayerFunctions; @@ -51,7 +54,7 @@ public class DebugExec extends SubCommand { if (args.length > 0) { String arg = args[0].toLowerCase(); switch (arg) { - case "stop-expire": + case "stop-expire": { if (ExpireManager.task != -1) { Bukkit.getScheduler().cancelTask(ExpireManager.task); } @@ -60,7 +63,8 @@ public class DebugExec extends SubCommand { } ExpireManager.task = -1; return PlayerFunctions.sendMessage(null, "Cancelled task."); - case "start-expire": + } + case "start-expire": { if (ExpireManager.task == -1) { ExpireManager.runTask(); } @@ -68,7 +72,8 @@ public class DebugExec extends SubCommand { return PlayerFunctions.sendMessage(null, "Plot expiry task already started"); } return PlayerFunctions.sendMessage(null, "Started plot expiry task"); - case "update-expired": + } + case "update-expired": { if (args.length > 1) { World world = Bukkit.getWorld(args[1]); if (world == null) { @@ -79,7 +84,8 @@ public class DebugExec extends SubCommand { return true; } return PlayerFunctions.sendMessage(null, "Use /plot debugexec update-expired "); - case "show-expired": + } + case "show-expired": { if (args.length > 1) { World world = Bukkit.getWorld(args[1]); if (world == null || !ExpireManager.expiredPlots.containsKey(args[1])) { @@ -94,7 +100,8 @@ public class DebugExec extends SubCommand { return true; } return PlayerFunctions.sendMessage(null, "Use /plot debugexec show-expired "); - case "seen": + } + case "seen": { if (args.length != 2) { return PlayerFunctions.sendMessage(null, "Use /plot debugexec seen "); } @@ -114,6 +121,26 @@ public class DebugExec extends SubCommand { PlayerFunctions.sendMessage(null, "GMT: " + date.toGMTString()); PlayerFunctions.sendMessage(null, "Local: " + date.toLocaleString()); return true; + } + case "trim-get-chunks": { + if (args.length != 2) { + PlayerFunctions.sendMessage(null, "Use /plot debugexec trim-get-chunks "); + PlayerFunctions.sendMessage(null, "&7 - Generates a list of regions to trim"); + return PlayerFunctions.sendMessage(null, "&7 - Run after plot expiry has run"); + } + World world = Bukkit.getWorld(args[1]); + if (world == null || !PlotMain.isPlotWorld(args[1])) { + return PlayerFunctions.sendMessage(null, "Invalid world: "+args[1]); + } + ArrayList chunks0 = Trim.getTrimChunks(world); + PlayerFunctions.sendMessage(null, "BULK MCR: " + chunks0.size()); + ArrayList chunks = Trim.getTrimPlots(world); + chunks.addAll(chunks0); + PlayerFunctions.sendMessage(null, "MCR: " + chunks.size()); + PlayerFunctions.sendMessage(null, "CHUNKS: " + chunks.size() * 256); + PlayerFunctions.sendMessage(null, "Calculating size on disk..."); + PlayerFunctions.sendMessage(null, "SIZE (bytes): " + Trim.calculateSizeOnDisk(world, chunks)); + } } } PlayerFunctions.sendMessage(player, "Possible sub commands: /plot debugexec <" + StringUtils.join(allowed_params, "|") + ">"); diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/Trim.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/Trim.java index af65efa94..3882e732a 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/Trim.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/Trim.java @@ -27,6 +27,8 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.Set; import org.bukkit.Bukkit; @@ -157,7 +159,7 @@ public class Trim extends SubCommand { } } } - final Set plots = ExpireManager.getOldPlots(world.getName()).keySet(); + final Set plots = ExpireManager.getOldPlots(world.getName()).keySet(); Trim.TASK_ID = Bukkit.getScheduler().scheduleSyncRepeatingTask(PlotMain.getMain(), new Runnable() { @Override public void run() { @@ -185,8 +187,98 @@ public class Trim extends SubCommand { return true; } - private void trimPlots(World world) { - String worldname = world.getName(); + public static ArrayList expired = null; + + public static void updateUnmodifiedPlots(final World world) { + final HybridPlotManager manager = (HybridPlotManager) PlotMain.getPlotManager(world); + final HybridPlotWorld plotworld = (HybridPlotWorld) PlotMain.getWorldSettings(world); + final ArrayList expired = new ArrayList<>(); + final Set plots = ExpireManager.getOldPlots(world.getName()).keySet(); + sendMessage("Checking " + plots.size() +" plots! This may take a long time..."); + Trim.TASK_ID = Bukkit.getScheduler().scheduleSyncRepeatingTask(PlotMain.getMain(), new Runnable() { + @Override + public void run() { + if (manager != null && plots.size() > 0) { + Plot plot = plots.iterator().next(); + if (plot.hasOwner()) { + HybridPlotManager.checkModified(plot, 0); + } + if (plot.owner == null || !HybridPlotManager.checkModified(plot, plotworld.REQUIRED_CHANGES)) { + expired.add(plot); + sendMessage("found expired: " + plot); + } + } + else { + Trim.expired = expired; + Trim.TASK = false; + sendMessage("Done!"); + Bukkit.getScheduler().cancelTask(Trim.TASK_ID); + return; + } + } + }, 1, 1); + } + + public static long calculateSizeOnDisk(World world, ArrayList chunks) { + int result = 0; + for (ChunkLoc loc : chunks) { + String directory = new File(".").getAbsolutePath() + File.separator + world + File.separator + "region" + File.separator + "r." + loc.x + "." + loc.z + ".mca"; + File file = new File(directory); + result += file.getTotalSpace(); + } + return result; + } + + public static ArrayList getTrimChunks(World world) { + ArrayList toRemove = new ArrayList<>(); + String directory = new File(".").getAbsolutePath() + File.separator + world.getName() + File.separator + "region"; + File folder = new File(directory); + File[] regionFiles = folder.listFiles(); + for (File file : regionFiles) { + String name = file.getName(); + if (name.endsWith("mca")) { + if (file.getTotalSpace() <= 8192) { + try { + String[] split = name.split("\\."); + int x = Integer.parseInt(split[1]); + int z = Integer.parseInt(split[2]); + ChunkLoc loc = new ChunkLoc(x, z); + toRemove.add(loc); + } + catch (Exception e) {} + continue; + } + else { + boolean delete = false; + Path path = Paths.get(file.getPath()); + try { + BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class); + long creation = attr.creationTime().toMillis(); + long modification = file.lastModified(); + long diff = Math.abs(creation - modification); + if (diff < 10000) { + PlotMain.sendConsoleSenderMessage("&6 - Deleted region "+name+" (max 256 chunks)"); + try { + String[] split = name.split("\\."); + int x = Integer.parseInt(split[1]); + int z = Integer.parseInt(split[2]); + ChunkLoc loc = new ChunkLoc(x, z); + toRemove.add(loc); + } + catch (Exception e) {} + delete = true; + } + } catch (Exception e) { + + } + } + } + } + return toRemove; + } + + public static ArrayList getTrimPlots(World world) { + ArrayList toRemove = new ArrayList<>(); ArrayList chunks = ChunkManager.getChunkChunks(world); for (ChunkLoc loc : chunks) { int sx = loc.x << 4; @@ -205,12 +297,21 @@ public class Trim extends SubCommand { } } if (delete) { - ChunkManager.deleteRegionFile(worldname, loc); + toRemove.add(loc); } } + return toRemove; + } + + public static void trimPlots(World world) { + ArrayList chunks = getTrimPlots(world); + String worldname = world.getName(); + for (ChunkLoc loc : chunks) { + ChunkManager.deleteRegionFile(worldname, loc); + } } - private void sendMessage(final String message) { + public static void sendMessage(final String message) { PlotMain.sendConsoleSenderMessage("&3PlotSquared -> World trim&8: " + message); }