diff --git a/src/main/java/com/intellectualcrafters/plot/PS.java b/src/main/java/com/intellectualcrafters/plot/PS.java index 1ddbbce40..5995d189e 100644 --- a/src/main/java/com/intellectualcrafters/plot/PS.java +++ b/src/main/java/com/intellectualcrafters/plot/PS.java @@ -543,6 +543,181 @@ public class PS { return result; } + public static ArrayList sortPlotsByTimestamp(Collection input) { + List list; + if (input instanceof ArrayList) { + list = (List) input; + } + else { + list = new ArrayList(input); + } + long min = Integer.MAX_VALUE; + long max = 0; + int size = list.size(); + int limit = Math.min(1048576, size * 2); + for (int i = 0; i < size; i++) { + Plot plot = list.get(i); + long time = plot.getTimestamp(); + if (time < min) { + min = time; + } + if (time > max) { + max = time; + } + } + long range = max - min; + Plot[] plots; + try { + ArrayList overflow = new ArrayList<>(); + if (range > limit && size > 1024) { + plots = new Plot[Math.min((int) range, limit)]; + int factor = (int) ((range / limit)); + for (int i = 0; i < size; i++) { + Plot plot = list.get(i); + int index = (int) (plot.getTimestamp() - min) / factor; + if (index < 0) { + index = 0; + } + if (index >= plots.length) { + overflow.add(plot); + continue; + } + Plot current = plots[index]; + while (true) { + if (current == null) { + plots[index] = plot; + break; + } + if (current.getTimestamp() > plot.getTimestamp()) { + plots[index] = plot; + plot = current; + } + index++; + if (index >= plots.length) { + overflow.add(plot); + break; + } + current = plots[index]; + } + } + } + else if (range < size || size < 1024) { + ArrayList result = new ArrayList(list); + Collections.sort(result, new Comparator() { + @Override + public int compare(Plot a, Plot b) { + if (a.getTimestamp() > b.getTimestamp()) { + return -1; + } + else if (b.getTimestamp() > a.getTimestamp()) { + return 1; + } + return 0; + } + }); + return result; + } + else if (min != 0) { + plots = new Plot[(int) range]; + for (int i = 0; i < size; i++) { + Plot plot = list.get(i); + int index = (int) (plot.getTimestamp() - min); + if (index >= plots.length) { + overflow.add(plot); + continue; + } + Plot current = plots[index]; + while (true) { + if (current == null) { + plots[index] = plot; + break; + } + if (current.getTimestamp() > plot.getTimestamp()) { + plots[index] = plot; + plot = current; + } + index++; + if (index >= plots.length) { + overflow.add(plot); + break; + } + current = plots[index]; + } + } + } + else { + plots = new Plot[(int) range]; + for (int i = 0; i < size; i++) { + Plot plot = list.get(i); + int index = (int) (plot.getTimestamp()); + if (index >= plots.length) { + overflow.add(plot); + continue; + } + Plot current = plots[index]; + // Move everything along until a free spot is found + while (true) { + if (current == null) { + plots[index] = plot; + break; + } + if (current.getTimestamp() > plot.getTimestamp()) { + plots[index] = plot; + plot = current; + } + index++; + if (index >= plots.length) { + overflow.add(plot); + break; + } + current = plots[index]; + } + } + } + ArrayList result = new ArrayList<>(size); + if (overflow.size() > 0) { + Collections.sort(overflow, new Comparator() { + @Override + public int compare(Plot a, Plot b) { + if (a.getTimestamp() > b.getTimestamp()) { + return -1; + } + else if (b.getTimestamp() > a.getTimestamp()) { + return 1; + } + return 0; + } + }); + for (Plot plot : overflow) { + result.add(plot); + } + } + for (int i = plots.length - 1; i >= 0; i--) { + if (plots[i] != null) { + result.add(plots[i]); + } + } + return result; + } + catch (Exception e) { + e.printStackTrace(); + ArrayList result = new ArrayList(list); + Collections.sort(result, new Comparator() { + @Override + public int compare(Plot a, Plot b) { + if (a.getTimestamp() > b.getTimestamp()) { + return -1; + } + else if (b.getTimestamp() > a.getTimestamp()) { + return 1; + } + return 0; + } + }); + return result; + } + } + public static void sortPlotsByHash(Plot[] input) { final int SIZE = 100; List[] bucket = new ArrayList[SIZE]; @@ -571,6 +746,34 @@ public class PS { } } + public static void sortPlotsByTimestamp(Plot[] input) { + final int SIZE = 100; + List[] bucket = new ArrayList[SIZE]; + for (int i = 0; i < bucket.length; i++) { + bucket[i] = new ArrayList(); + } + boolean maxLength = false; + int tmp = -1, placement = 1; + while (!maxLength) { + maxLength = true; + for (Plot i : input) { + tmp = MathMan.getPositiveId(i.hashCode()) / placement; + bucket[tmp % SIZE].add(i); + if (maxLength && tmp > 0) { + maxLength = false; + } + } + int a = 0; + for (int b = 0; b < SIZE; b++) { + for (Plot i : bucket[b]) { + input[a++] = i; + } + bucket[b].clear(); + } + placement *= SIZE; + } + } + /** * Sort a collection of plots by world (with a priority world), then by hashcode * @param plots @@ -613,7 +816,7 @@ public class PS { Collections.sort(worlds, new Comparator() { @Override public int compare(String a, String b) { - if (StringMan.isEqual(a, priorityWorld)) { + if (priorityWorld != null && StringMan.isEqual(a, priorityWorld)) { return -1; } return a.hashCode() - b.hashCode(); diff --git a/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java b/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java index 0cdfb02a2..bfa2a0009 100644 --- a/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java +++ b/src/main/java/com/intellectualcrafters/plot/commands/DebugExec.java @@ -92,7 +92,10 @@ public class DebugExec extends SubCommand { if (engine != null) { return; } - engine = (new ScriptEngineManager()).getEngineByName("JavaScript"); + engine = (new ScriptEngineManager()).getEngineByName("nashorn"); + if (engine == null) { + engine = (new ScriptEngineManager()).getEngineByName("JavaScript"); + } ScriptContext context = new SimpleScriptContext(); scope = context.getBindings(ScriptContext.ENGINE_SCOPE); @@ -128,21 +131,14 @@ public class DebugExec extends SubCommand { scope.put("MainCommand", MainCommand.getInstance()); // enums - for (Enum value : C.values()) { + for (Enum value : C.values()) { scope.put("C_" + value.name(), value); } - for (Enum value : Permissions.values()) { + for (Enum value : Permissions.values()) { scope.put("Permissions_" + value.name(), value); } - addEnums(scope, C.values()); } - - private void addEnums(Bindings scope2, C[] values) { - // TODO Auto-generated method stub - } - - @Override public boolean onCommand(final PlotPlayer player, String[] args) { final List allowed_params = Arrays.asList("calibrate-analysis", "remove-flag", "stop-expire", "start-expire", "show-expired", "update-expired", "seen", "trim-check"); diff --git a/src/main/java/com/intellectualcrafters/plot/commands/Delete.java b/src/main/java/com/intellectualcrafters/plot/commands/Delete.java index 8c54d5dd5..0498af26c 100644 --- a/src/main/java/com/intellectualcrafters/plot/commands/Delete.java +++ b/src/main/java/com/intellectualcrafters/plot/commands/Delete.java @@ -40,7 +40,7 @@ import com.plotsquared.general.commands.CommandDeclaration; permission = "plots.delete", description = "Delete a plot", usage = "/plot delete", - aliases = "dispose", + aliases = {"dispose", "del"}, category = CommandCategory.ACTIONS, requiredType = RequiredType.NONE ) diff --git a/src/main/java/com/intellectualcrafters/plot/commands/SetOwner.java b/src/main/java/com/intellectualcrafters/plot/commands/SetOwner.java index 6c4ccfda3..9ad41c2b3 100644 --- a/src/main/java/com/intellectualcrafters/plot/commands/SetOwner.java +++ b/src/main/java/com/intellectualcrafters/plot/commands/SetOwner.java @@ -62,7 +62,7 @@ public class SetOwner extends SubCommand { public boolean onCommand(final PlotPlayer plr, final String[] args) { final Location loc = plr.getLocation(); final Plot plot = MainUtil.getPlot(loc); - if ((plot == null) || (plot.owner == null)) { + if ((plot == null) || (plot.owner == null && !Permissions.hasPermission(plr, "plots.admin.command.setowner"))) { MainUtil.sendMessage(plr, C.NOT_IN_PLOT); return false; } @@ -107,10 +107,17 @@ public class SetOwner extends SubCommand { return false; } for (final PlotId id : plots) { - final Plot current = PS.get().getPlots(world).get(id); - current.owner = uuid; + Plot current = PS.get().getPlots(world).get(id); + if (current == null) { + current = MainUtil.getPlot(world, id); + current.owner = uuid; + current.create(); + } + else { + current.owner = uuid; + DBFunc.setOwner(current, current.owner); + } PS.get().updatePlot(current); - DBFunc.setOwner(current, current.owner); } MainUtil.setSign(args[0], plot); MainUtil.sendMessage(plr, C.SET_OWNER); diff --git a/src/main/java/com/intellectualcrafters/plot/commands/Visit.java b/src/main/java/com/intellectualcrafters/plot/commands/Visit.java index bc2ba53e1..ca6e27893 100644 --- a/src/main/java/com/intellectualcrafters/plot/commands/Visit.java +++ b/src/main/java/com/intellectualcrafters/plot/commands/Visit.java @@ -67,10 +67,10 @@ public class Visit extends SubCommand { UUID user = UUIDHandler.getCachedUUID(args[0], null); if (user != null ) { // do plots by username - plots.addAll(PS.get().getPlots(user)); + plots = PS.get().sortPlots(PS.get().getPlots(user), null); } else if (PS.get().isPlotWorld(args[0])) { // do plots by world - plots.addAll(PS.get().getPlots(args[0]).values()); + plots = PS.get().sortPlots(PS.get().getPlots(args[0]).values(), null); } else { Plot plot = MainUtil.getPlotFromString(plr, args[0], true); diff --git a/src/main/java/com/intellectualcrafters/plot/commands/list.java b/src/main/java/com/intellectualcrafters/plot/commands/list.java index 790e08d71..27d22462c 100644 --- a/src/main/java/com/intellectualcrafters/plot/commands/list.java +++ b/src/main/java/com/intellectualcrafters/plot/commands/list.java @@ -303,12 +303,7 @@ public class list extends SubCommand { public void displayPlots(PlotPlayer player, List plots, int pageSize, int page, String world, String[] args, boolean sort) { if (sort) { - if (world != null) { - plots = PS.get().sortPlots(plots, world); - } - else { - plots = PS.get().sortPlots(plots); - } + plots = PS.get().sortPlots(plots, world); } if (page < 0) { page = 0; diff --git a/src/main/java/com/intellectualcrafters/plot/database/SQLManager.java b/src/main/java/com/intellectualcrafters/plot/database/SQLManager.java index 3e461857d..dd4539cfa 100644 --- a/src/main/java/com/intellectualcrafters/plot/database/SQLManager.java +++ b/src/main/java/com/intellectualcrafters/plot/database/SQLManager.java @@ -84,10 +84,10 @@ public class SQLManager implements AbstractDB { // Public final this.SET_OWNER = "UPDATE `" + this.prefix + "plot` SET `owner` = ? WHERE `plot_id_x` = ? AND `plot_id_z` = ? AND `world` = ?"; this.GET_ALL_PLOTS = "SELECT `id`, `plot_id_x`, `plot_id_z`, `world` FROM `" + this.prefix + "plot`"; - this.CREATE_PLOTS = "INSERT INTO `" + this.prefix + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`) values "; + this.CREATE_PLOTS = "INSERT INTO `" + this.prefix + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) values "; this.CREATE_SETTINGS = "INSERT INTO `" + this.prefix + "plot_settings` (`plot_plot_id`) values "; this.CREATE_TIERS = "INSERT INTO `" + this.prefix + "plot_%tier%` (`plot_plot_id`, `user_uuid`) values "; - this.CREATE_PLOT = "INSERT INTO `" + this.prefix + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`) VALUES(?, ?, ?, ?)"; + this.CREATE_PLOT = "INSERT INTO `" + this.prefix + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) VALUES(?, ?, ?, ?, ?)"; this.CREATE_CLUSTER = "INSERT INTO `" + this.prefix + "cluster`(`pos1_x`, `pos1_z`, `pos2_x`, `pos2_z`, `owner`, `world`) VALUES(?, ?, ?, ?, ?, ?)"; // schedule reconnect if (Settings.DB.USE_MYSQL) { @@ -296,7 +296,7 @@ public class SQLManager implements AbstractDB { final StmtMod mod = new StmtMod() { @Override public String getCreateMySQL(int size) { - return getCreateMySQL(size, CREATE_PLOTS, 4); + return getCreateMySQL(size, CREATE_PLOTS, 5); } @Override @@ -311,14 +311,15 @@ public class SQLManager implements AbstractDB { @Override public void setMySQL(PreparedStatement stmt, int i, Plot plot) throws SQLException { - stmt.setInt((i * 4) + 1, plot.id.x); - stmt.setInt((i * 4) + 2, plot.id.y); + stmt.setInt((i * 5) + 1, plot.id.x); + stmt.setInt((i * 5) + 2, plot.id.y); try { stmt.setString((i * 4) + 3, plot.owner.toString()); } catch (final Exception e) { stmt.setString((i * 4) + 3, DBFunc.everyone.toString()); } - stmt.setString((i * 4) + 4, plot.world); + stmt.setString((i * 5) + 4, plot.world); + stmt.setTimestamp((i * 5) + 5, new Timestamp(plot.getTimestamp())); } @Override @@ -332,7 +333,7 @@ public class SQLManager implements AbstractDB { stmt.setString((i * 6) + 4, DBFunc.everyone.toString()); } stmt.setString((i * 6) + 5, plot.world); - stmt.setString((i * 6) + 6, System.currentTimeMillis() + ""); + stmt.setTimestamp((i * 6) + 6, new Timestamp(plot.getTimestamp())); } @Override @@ -341,6 +342,8 @@ public class SQLManager implements AbstractDB { stmt.setInt(2, plot.id.y); stmt.setString(3, plot.owner.toString()); stmt.setString(4, plot.world); + stmt.setTimestamp(5, new Timestamp(plot.getTimestamp())); + } }; setBulk(myList, mod, whenDone); @@ -642,6 +645,7 @@ public class SQLManager implements AbstractDB { stmt.setInt(2, plot.id.y); stmt.setString(3, plot.owner.toString()); stmt.setString(4, plot.world); + stmt.setTimestamp(5, new Timestamp(plot.getTimestamp())); stmt.executeUpdate(); stmt.close(); } catch (final Exception e) { @@ -664,6 +668,7 @@ public class SQLManager implements AbstractDB { stmt.setInt(2, plot.id.y); stmt.setString(3, plot.owner.toString()); stmt.setString(4, plot.world); + stmt.setTimestamp(5, new Timestamp(plot.getTimestamp())); stmt.executeUpdate(); stmt.close(); final int id = getId(plot.world, plot.id); @@ -879,13 +884,13 @@ public class SQLManager implements AbstractDB { for (String table : new String[]{"plot_denied", "plot_helpers", "plot_trusted"} ) { ResultSet result = statement.executeQuery("SELECT plot_plot_id, user_uuid, COUNT(*) FROM " + this.prefix + table + " GROUP BY plot_plot_id, user_uuid HAVING COUNT(*) > 1"); if (result.next()) { - PS.debug("BACKING UP: " + table); + PS.debug("BACKING UP: " + this.prefix + table); result.close(); - statement.executeUpdate("CREATE TABLE " + table + "_tmp AS SELECT * FROM " + this.prefix + table + " GROUP BY plot_plot_id, user_uuid"); + statement.executeUpdate("CREATE TABLE " + this.prefix + table + "_tmp AS SELECT * FROM " + this.prefix + table + " GROUP BY plot_plot_id, user_uuid"); statement.executeUpdate("DROP TABLE " + this.prefix + table); - statement.executeUpdate("CREATE TABLE " + this.prefix + table + " AS SELECT * FROM " + table + "_tmp"); + statement.executeUpdate("CREATE TABLE " + this.prefix + table + " AS SELECT * FROM " + this.prefix + table + "_tmp"); statement.executeUpdate("DROP TABLE " + this.prefix + table + "_tmp"); - PS.debug("RESTORING: " + table); + PS.debug("RESTORING: " + this.prefix + table); } } statement.close(); @@ -919,7 +924,7 @@ public class SQLManager implements AbstractDB { * Getting plots */ stmt = this.connection.createStatement(); - ResultSet r = stmt.executeQuery("SELECT `id`, `plot_id_x`, `plot_id_z`, `owner`, `world` FROM `" + this.prefix + "plot`"); + ResultSet r = stmt.executeQuery("SELECT `id`, `plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp` FROM `" + this.prefix + "plot`"); PlotId plot_id; int id; Plot p; @@ -942,7 +947,15 @@ public class SQLManager implements AbstractDB { user = UUID.fromString(o); uuids.put(o, user); } - p = new Plot(plot_id, user, new HashSet(), new HashSet(), new HashSet(), "", null, null, worldname, new boolean[]{false, false, false, false}); + Timestamp timestamp = r.getTimestamp("timestamp"); + long time; + if (timestamp == null) { + time = plot_id.hashCode(); + } + else { + time = timestamp.getTime(); + } + p = new Plot(plot_id, user, new HashSet(), new HashSet(), new HashSet(), "", null, null, worldname, new boolean[]{false, false, false, false}, time); plots.put(id, p); } if (Settings.CACHE_RATINGS) { diff --git a/src/main/java/com/intellectualcrafters/plot/object/Plot.java b/src/main/java/com/intellectualcrafters/plot/object/Plot.java index f26952922..2f5a71f5a 100644 --- a/src/main/java/com/intellectualcrafters/plot/object/Plot.java +++ b/src/main/java/com/intellectualcrafters/plot/object/Plot.java @@ -48,17 +48,30 @@ import com.intellectualcrafters.plot.util.TaskManager; public class Plot { /** * plot ID + * Direct access is Deprecated: use getId() */ + @Deprecated public final PlotId id; /** * plot world + * Direct access is Deprecated: use getWorld() */ + @Deprecated public final String world; /** * plot owner + * Direct access is Deprecated: use getOwners() */ + @Deprecated public UUID owner; + /** + * Plot creation timestamp (rough) + * Direct access is Deprecated: use getTimestamp() + */ + @Deprecated + public long timestamp; + /** * List of trusted (with plot permissions) * Direct access is Deprecated: use getTrusted() @@ -132,10 +145,11 @@ public class Plot { * @param denied * @param merged */ - public Plot(final PlotId id, final UUID owner, final HashSet trusted, final HashSet members, final HashSet denied, final String alias, final BlockLoc position, final Collection flags, final String world, final boolean[] merged) { + public Plot(final PlotId id, final UUID owner, final HashSet trusted, final HashSet members, final HashSet denied, final String alias, final BlockLoc position, final Collection flags, final String world, final boolean[] merged, final long timestamp) { this.id = id; - this.settings = new PlotSettings(this); + this.world = world; this.owner = owner; + this.settings = new PlotSettings(this); this.members = members; this.trusted = trusted; this.denied = denied; @@ -147,7 +161,7 @@ public class Plot { this.settings.flags.put(flag.getKey(), flag); } } - this.world = world; + this.timestamp = timestamp; this.temp = false; } @@ -201,7 +215,7 @@ public class Plot { public boolean isDenied(final UUID uuid) { return (this.getDenied() != null) && ((this.denied.contains(DBFunc.everyone) && !this.isAdded(uuid)) || (!this.isAdded(uuid) && this.denied.contains(uuid))); } - + /** * Get the plot ID */ @@ -209,6 +223,14 @@ public class Plot { return this.id; } + /** + * Get the world + * @return + */ + public String getWorld() { + return this.world; + } + /** * Get or create plot settings * @return PlotSettings @@ -227,6 +249,13 @@ public class Plot { return settings.getMerged(0) || settings.getMerged(2) || settings.getMerged(1) || settings.getMerged(3); } + public long getTimestamp() { + if (timestamp == 0) { + timestamp = System.currentTimeMillis(); + } + return timestamp; + } + /** * Get if the plot is merged in a direction * @param direction