diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/MainCommand.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/MainCommand.java index 9d068cd40..ea9149cd3 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/MainCommand.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/MainCommand.java @@ -48,7 +48,7 @@ public class MainCommand implements CommandExecutor, TabCompleter { */ public static final String MAIN_PERMISSION = "plots.use"; - private final static SubCommand[] _subCommands = new SubCommand[]{new DebugSaveTest(), new DebugLoadTest(), new CreateRoadSchematic(), new RegenAllRoads(), new DebugClear(), new Ban(), new Unban(), new OP(), new DEOP(), new Claim(), new Paste(), new Copy(), new Clipboard(), new Auto(), new Home(), new Visit(), new TP(), new Set(), new Clear(), new Delete(), new SetOwner(), new Denied(), new Helpers(), new Trusted(), new Info(), new list(), new Help(), new Debug(), new Schematic(), new plugin(), new Inventory(), new Purge(), new Reload(), new Merge(), new Unlink(), new Kick(), new Setup(), new Rate(), new DebugClaimTest(), new Inbox(), new Comment(), new Database(), new Unclaim(), new Swap(), new MusicSubcommand(), new DebugRoadRegen()}; + private final static SubCommand[] _subCommands = new SubCommand[]{new DebugSaveTest(), new DebugLoadTest(), new CreateRoadSchematic(), new RegenAllRoads(), new DebugClear(), new Ban(), new Unban(), new OP(), new DEOP(), new Claim(), new Paste(), new Copy(), new Clipboard(), new Auto(), new Home(), new Visit(), new TP(), new Set(), new Clear(), new Delete(), new SetOwner(), new Denied(), new Helpers(), new Trusted(), new Info(), new list(), new Help(), new Debug(), new Schematic(), new plugin(), new Inventory(), new Purge(), new Reload(), new Merge(), new Unlink(), new Kick(), new Setup(), new Rate(), new DebugClaimTest(), new Inbox(), new Comment(), new Database(), new Unclaim(), new Swap(), new MusicSubcommand(), new DebugRoadRegen(), new Trim()}; public final static ArrayList subCommands = new ArrayList() { { diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/Purge.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/Purge.java index 117edc2bb..227be2d2b 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/Purge.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/Purge.java @@ -64,29 +64,29 @@ import org.bukkit.entity.Player; if (args.length == 1) { String arg = args[0].toLowerCase(); PlotId id = getId(arg); - if (id != null || arg.equals("plotid")) { - PlayerFunctions.sendMessage(plr, "/plot x;z &l"); + if (id != null) { + PlayerFunctions.sendMessage(plr, "/plot purge x;z &l"); return false; } UUID uuid = UUIDHandler.getUUID(args[0]); if (uuid != null) { - PlayerFunctions.sendMessage(plr, "/plot "+args[0]+" &l"); + PlayerFunctions.sendMessage(plr, "/plot purge "+args[0]+" &l"); return false; } if (arg.equals("player")) { - PlayerFunctions.sendMessage(plr, "/plot &l "); + PlayerFunctions.sendMessage(plr, "/plot purge &l "); return false; } if (arg.equals("unowned")) { - PlayerFunctions.sendMessage(plr, "/plot unowned &l"); + PlayerFunctions.sendMessage(plr, "/plot purge unowned &l"); return false; } if (arg.equals("unknown")) { - PlayerFunctions.sendMessage(plr, "/plot unknown &l"); + PlayerFunctions.sendMessage(plr, "/plot purge unknown &l"); return false; } if (arg.equals("all")) { - PlayerFunctions.sendMessage(plr, "/plot all &l"); + PlayerFunctions.sendMessage(plr, "/plot purge all &l"); return false; } PlayerFunctions.sendMessage(plr, C.PURGE_SYNTAX); @@ -133,7 +133,7 @@ import org.bukkit.entity.Player; Set ids = new HashSet<>(); for (Plot plot : plots) { if (plot.owner != null) { - String name = UUIDHandler.getName(plot.owner); + String name = UUIDHandler.getName(plot.owner); if (name == null) { ids.add(plot.id); } diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/Trim.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/Trim.java new file mode 100644 index 000000000..eb6605ebd --- /dev/null +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/Trim.java @@ -0,0 +1,229 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////// +// PlotSquared - A plot manager and world generator for the Bukkit API / +// Copyright (c) 2014 IntellectualSites/IntellectualCrafters / +// / +// This program is free software; you can redistribute it and/or modify / +// it under the terms of the GNU General Public License as published by / +// the Free Software Foundation; either version 3 of the License, or / +// (at your option) any later version. / +// / +// This program is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the / +// GNU General Public License for more details. / +// / +// You should have received a copy of the GNU General Public License / +// along with this program; if not, write to the Free Software Foundation, / +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA / +// / +// You can contact us via: support@intellectualsites.com / +//////////////////////////////////////////////////////////////////////////////////////////////////// + +package com.intellectualcrafters.plot.commands; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import com.intellectualcrafters.plot.PlotMain; +import com.intellectualcrafters.plot.config.C; +import com.intellectualcrafters.plot.config.Settings; +import com.intellectualcrafters.plot.database.DBFunc; +import com.intellectualcrafters.plot.generator.HybridPlotManager; +import com.intellectualcrafters.plot.generator.HybridPlotWorld; +import com.intellectualcrafters.plot.object.ChunkLoc; +import com.intellectualcrafters.plot.object.Plot; +import com.intellectualcrafters.plot.object.PlotId; +import com.intellectualcrafters.plot.object.PlotManager; +import com.intellectualcrafters.plot.util.PlayerFunctions; +import com.intellectualcrafters.plot.util.PlotHelper; +import com.intellectualcrafters.plot.util.UUIDHandler; + +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.entity.Player; + +@SuppressWarnings({"unused", "deprecated", "javadoc"}) public class Trim extends SubCommand { + + public Trim() { + super("trim", "plots.admin", "Delete unmodified portions of your plotworld", "trim", "", CommandCategory.DEBUG, false); + } + + public PlotId getId(String id) { + try { + String[] split = id.split(";"); + return new PlotId(Integer.parseInt(split[0]), Integer.parseInt(split[1])); + } + catch (Exception e) { + return null; + } + } + + @Override + public boolean execute(final Player plr, final String... args) { + if (plr != null) { + PlayerFunctions.sendMessage(plr, (C.NOT_CONSOLE)); + return false; + } + if (args.length == 1) { + String arg = args[0].toLowerCase(); + PlotId id = getId(arg); + if (id != null) { + PlayerFunctions.sendMessage(plr, "/plot trim x;z &l"); + return false; + } + if (arg.equals("all")) { + PlayerFunctions.sendMessage(plr, "/plot trim all &l"); + return false; + } + PlayerFunctions.sendMessage(plr, C.TRIM_SYNTAX); + return false; + } + if (args.length != 2) { + PlayerFunctions.sendMessage(plr, C.TRIM_SYNTAX); + return false; + } + World world = Bukkit.getWorld(args[1]); + if (world == null) { + PlayerFunctions.sendMessage(plr, C.NOT_VALID_WORLD); + return false; + } + HybridPlotManager manager = (HybridPlotManager) PlotMain.getPlotManager(world); + HybridPlotWorld plotworld = (HybridPlotWorld) PlotMain.getWorldSettings(world); + String worldname = world.getName(); + String arg = args[0].toLowerCase(); + PlotId id = getId(arg); + if (id != null) { + if (manager == null) { + PlotMain.sendConsoleSenderMessage(C.NOT_VALID_HYBRID_PLOT_WORLD); + return false; + } + Plot plot = PlotHelper.getPlot(world, id); + boolean modified = false; + if (plot.hasOwner()) { + modified = HybridPlotManager.checkModified(plot, 0); + } + PlayerFunctions.sendMessage(plr, "Modified: "+modified); + // trim ID + } + if (arg.equals("all")) { + sendMessage("Initializing..."); + String directory = new File(".").getAbsolutePath() + File.separator + world.getName() + File.separator + "region"; + File folder = new File(directory); + File[] regionFiles = folder.listFiles(); + ArrayList chunks = new ArrayList<>(); + sendMessage("Step 1: Bulk chunk trim"); + + int count = 0; + for (File file : regionFiles) { + String name = file.getName(); + if (name.endsWith("mca")) { + if (file.getTotalSpace() <= 8192) { + file.delete(); + } + 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) { + count++; + file.delete(); + delete = true; + } + } catch (Exception e) { + + } + if (!delete) { + String[] split = name.split("\\."); + try { + int x = Integer.parseInt(split[1]); + int z = Integer.parseInt(split[2]); + ChunkLoc loc = new ChunkLoc(x, z); + chunks.add(loc); + } + catch (Exception e) { } + } + } + } + } + + count = 0; + PlotMain.sendConsoleSenderMessage("&6 - bulk trim removed " + (count * 256) + " chunks"); + sendMessage("Step 2: Plot trim"); + { + Set plots = getOldPlots(world.getName()); + PlotMain.sendConsoleSenderMessage("&6 - found "+plots.size()+" expired plots"); + for (Plot plot : plots) { + boolean modified = false; + if (plot.hasOwner()) { + modified = HybridPlotManager.checkModified(plot, 0); + } + if (plot.owner == null || HybridPlotManager.checkModified(plot, manager.REQUIRED_CHANGES)); + } + } + + + PlotMain.sendConsoleSenderMessage("&6 - plot trim removed " + count + " plots"); + sendMessage("Step 3: Chunk trim"); + + } + PlayerFunctions.sendMessage(plr, C.TRIM_SYNTAX); + return false; + } + + public Set getOldPlots(String world) { + final Collection plots = PlotMain.getPlots(world).values(); + final Set toRemove = new HashSet<>(); + Set remove = new HashSet<>(); + Set keep = new HashSet<>(); + for (Plot plot : plots) { + UUID uuid = plot.owner; + if (uuid == null || remove.contains(uuid)) { + toRemove.add(plot); + continue; + } + if (keep.contains(uuid)) { + continue; + } + OfflinePlayer op = UUIDHandler.uuidWrapper.getOfflinePlayer(uuid); + if (!op.hasPlayedBefore()) { + toRemove.add(plot); + PlotMain.removePlot(plot.world, plot.id, true); + continue; + } + long last = op.getLastPlayed(); + long compared = System.currentTimeMillis() - last; + if (TimeUnit.MILLISECONDS.toDays(compared) >= Settings.AUTO_CLEAR_DAYS) { + toRemove.add(plot); + remove.add(uuid); + } + keep.add(uuid); + } + return toRemove; + } + + private void sendMessage(final String message) { + PlotMain.sendConsoleSenderMessage("&3PlotSquared -> World trim&8: " + message); + } + + private void runTask(final Runnable r) { + PlotMain.getMain().getServer().getScheduler().runTaskAsynchronously(PlotMain.getMain(), r); + } + +} diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/config/C.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/config/C.java index a3efabd3d..8b571af65 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/config/C.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/config/C.java @@ -182,8 +182,13 @@ public enum C { /* * purge */ - PURGE_SYNTAX("Use /plot "), + PURGE_SYNTAX("Use /plot purge "), PURGE_SUCCESS("Successfully purge %s plots"), + /* + * trim + */ + TRIM_SYNTAX("Use /plot trim "), + NOT_VALID_HYBRID_PLOT_WORLD("The hybrid plot manager is required to perform this action"), /* * No */ diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotManager.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotManager.java index d58150ade..5e4e6b5e0 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotManager.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotManager.java @@ -66,6 +66,71 @@ import java.util.HashSet; private int task; private static boolean UPDATE = false; + public static boolean checkModified(Plot plot, int requiredChanges) { + World world = Bukkit.getWorld(plot.world); + Location bottom = PlotHelper.getPlotBottomLoc(world, plot.id).add(1, 0, 1); + Location top = PlotHelper.getPlotTopLoc(world, plot.id); + + int botx = bottom.getBlockX(); + int boty = bottom.getBlockY(); + int botz = bottom.getBlockZ(); + + int topx = top.getBlockX(); + int topy = top.getBlockY(); + int topz = top.getBlockZ(); + + HybridPlotWorld hpw = (HybridPlotWorld) PlotMain.getWorldSettings(world); + + PlotBlock[] air = new PlotBlock[] {new PlotBlock((short) 0, (byte) 0)}; + + int changes = checkModified(requiredChanges, world, botx, topx, hpw.PLOT_HEIGHT, hpw.PLOT_HEIGHT, botz, topz, hpw.TOP_BLOCK); + if (changes == -1) { + return true; + } + requiredChanges -= changes; + changes = checkModified(requiredChanges, world, botx, topx, hpw.PLOT_HEIGHT + 1, hpw.PLOT_HEIGHT + 1, botz, topz, air); + if (changes == -1) { + return true; + } + requiredChanges -= changes; + changes = checkModified(requiredChanges, world, botx, topx, hpw.PLOT_HEIGHT + 2, world.getMaxHeight(), botz, topz, air); + if (changes == -1) { + return true; + } + requiredChanges -= changes; + changes = checkModified(requiredChanges, world, botx, topx, 1, hpw.PLOT_HEIGHT, botz, topz, hpw.MAIN_BLOCK); + if (changes == -1) { + return true; + } + return false; + } + + public static int checkModified(int threshhold, World world, int x1, int x2, int y1, int y2, int z1, int z2, PlotBlock[] blocks) { + int count = 0; + for (int y = y1; y <= y2; y++) { + for (int x = x1; x <= x2; x++) { + for (int z = z1; z <= z2; z++) { + Block block = world.getBlockAt(x, y, z); + int id = block.getTypeId(); + boolean same = false; + for (PlotBlock p : blocks) { + if (id == p.id) { + same = true; + break; + } + } + if (!same) { + count++; + if (count > threshhold) { + return -1; + } + } + } + } + } + return count; + } + public boolean setupRoadSchematic(Plot plot) { World world = Bukkit.getWorld(plot.world); diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/util/PlotHelper.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/util/PlotHelper.java index 279eaf2d7..4217850a8 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/util/PlotHelper.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/util/PlotHelper.java @@ -1055,71 +1055,6 @@ import java.util.UUID; return manager.getPlotBottomLocAbs(plotworld, id); } - public static boolean checkModified(Plot plot, int requiredChanges) { - World world = Bukkit.getWorld(plot.world); - Location bottom = PlotHelper.getPlotBottomLoc(world, plot.id).add(1, 0, 1); - Location top = PlotHelper.getPlotTopLoc(world, plot.id); - - int botx = bottom.getBlockX(); - int boty = bottom.getBlockY(); - int botz = bottom.getBlockZ(); - - int topx = top.getBlockX(); - int topy = top.getBlockY(); - int topz = top.getBlockZ(); - - HybridPlotWorld hpw = (HybridPlotWorld) PlotMain.getWorldSettings(world); - - PlotBlock[] air = new PlotBlock[] {new PlotBlock((short) 0, (byte) 0)}; - - int changes = checkModified(requiredChanges, world, botx, topx, hpw.PLOT_HEIGHT, hpw.PLOT_HEIGHT, botz, topz, hpw.TOP_BLOCK); - if (changes == -1) { - return true; - } - requiredChanges -= changes; - changes = checkModified(requiredChanges, world, botx, topx, hpw.PLOT_HEIGHT + 1, hpw.PLOT_HEIGHT + 1, botz, topz, air); - if (changes == -1) { - return true; - } - requiredChanges -= changes; - changes = checkModified(requiredChanges, world, botx, topx, hpw.PLOT_HEIGHT + 2, world.getMaxHeight(), botz, topz, air); - if (changes == -1) { - return true; - } - requiredChanges -= changes; - changes = checkModified(requiredChanges, world, botx, topx, 1, hpw.PLOT_HEIGHT, botz, topz, hpw.MAIN_BLOCK); - if (changes == -1) { - return true; - } - return false; - } - - public static int checkModified(int threshhold, World world, int x1, int x2, int y1, int y2, int z1, int z2, PlotBlock[] blocks) { - int count = 0; - for (int y = y1; y <= y2; y++) { - for (int x = x1; x <= x2; x++) { - for (int z = z1; z <= z2; z++) { - Block block = world.getBlockAt(x, y, z); - int id = block.getTypeId(); - boolean same = false; - for (PlotBlock p : blocks) { - if (id == p.id) { - same = true; - break; - } - } - if (!same) { - count++; - if (count > threshhold) { - return -1; - } - } - } - } - } - return count; - } - /** * Fetches the plot from the main class * diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/util/UUIDHandler.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/util/UUIDHandler.java index 89ff1bed7..04cc5306f 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/util/UUIDHandler.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/util/UUIDHandler.java @@ -82,9 +82,7 @@ public class UUIDHandler { } public static void cacheAll() { - UUIDHandler.CACHED = true; - HashSet players = new HashSet<>(); HashSet worlds = new HashSet<>(); worlds.add(Bukkit.getWorlds().get(0).getName()); worlds.add("world");