From 37977f1da453f6860d491608e76b772562ffdce7 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sat, 15 Apr 2017 12:40:23 +1000 Subject: [PATCH] Check database before claiming plot --- .../plot/commands/Auto.java | 114 ++++++++++++------ .../plot/commands/Claim.java | 27 ++++- .../plot/database/AbstractDB.java | 2 +- .../plot/database/DBFunc.java | 11 +- .../plot/database/SQLManager.java | 81 ++++++++++--- .../plot/object/Plot.java | 12 +- .../plot/object/PlotArea.java | 9 ++ .../plot/util/expiry/ExpireManager.java | 20 +-- 8 files changed, 197 insertions(+), 79 deletions(-) diff --git a/Core/src/main/java/com/intellectualcrafters/plot/commands/Auto.java b/Core/src/main/java/com/intellectualcrafters/plot/commands/Auto.java index 27f950b09..d54241dee 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/commands/Auto.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/commands/Auto.java @@ -3,15 +3,16 @@ package com.intellectualcrafters.plot.commands; import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.config.C; import com.intellectualcrafters.plot.config.Settings; +import com.intellectualcrafters.plot.database.DBFunc; import com.intellectualcrafters.plot.object.Expression; import com.intellectualcrafters.plot.object.Plot; import com.intellectualcrafters.plot.object.PlotArea; import com.intellectualcrafters.plot.object.PlotId; import com.intellectualcrafters.plot.object.PlotPlayer; +import com.intellectualcrafters.plot.object.RunnableVal; import com.intellectualcrafters.plot.util.ByteArrayUtilities; import com.intellectualcrafters.plot.util.EconHandler; import com.intellectualcrafters.plot.util.MainUtil; -import com.intellectualcrafters.plot.util.MathMan; import com.intellectualcrafters.plot.util.Permissions; import com.plotsquared.general.commands.CommandDeclaration; @@ -54,7 +55,7 @@ public class Auto extends SubCommand { } @Override - public boolean onCommand(PlotPlayer player, String[] args) { + public boolean onCommand(final PlotPlayer player, String[] args) { PlotArea plotarea = player.getApplicablePlotArea(); if (plotarea == null) { if (EconHandler.manager != null) { @@ -155,48 +156,85 @@ public class Auto extends SubCommand { } } // TODO handle type 2 the same as normal worlds! - if (plotarea.TYPE == 2) { - PlotId bot = plotarea.getMin(); - PlotId top = plotarea.getMax(); - PlotId origin = new PlotId(MathMan.average(bot.x, top.x), MathMan.average(bot.y, top.y)); - PlotId id = new PlotId(0, 0); - int width = Math.max(top.x - bot.x + 1, top.y - bot.y + 1); - int max = width * width; - // - for (int i = 0; i <= max; i++) { - PlotId currentId = new PlotId(origin.x + id.x, origin.y + id.y); - Plot current = plotarea.getPlotAbs(currentId); - if (current.canClaim(player)) { - current.claim(player, true, null); - return true; - } - id = getNextPlotId(id, 1); - } - // no free plots - MainUtil.sendMessage(player, C.NO_FREE_PLOTS); - return false; - } - while (true) { - PlotId start = getNextPlotId(getLastPlotId(plotarea), 1); - PlotId end = new PlotId(start.x + size_x - 1, start.y + size_z - 1); - plotarea.setMeta("lastPlot", start); - if (plotarea.canClaim(player, start, end)) { - for (int i = start.x; i <= end.x; i++) { - for (int j = start.y; j <= end.y; j++) { - Plot plot = plotarea.getPlotAbs(new PlotId(i, j)); - boolean teleport = i == end.x && j == end.y; - plot.claim(player, teleport, null); + if (size_x == 1 && size_z == 1) { + final String finalSchematic = schematic; + autoClaimSafe(player, plotarea, null, new RunnableVal() { + @Override + public void run(Plot value) { + if (value == null) { + MainUtil.sendMessage(player, C.NO_FREE_PLOTS); + } else { + value.claim(player, true, finalSchematic, false); } } - if (size_x != 1 || size_z != 1) { - if (!plotarea.mergePlots(MainUtil.getPlotSelectionIds(start, end), true, true)) { - return false; + }); + return true; + } else { + if (plotarea.TYPE == 2) { + // TODO + MainUtil.sendMessage(player, C.NO_FREE_PLOTS); + return false; + } + while (true) { + PlotId start = getNextPlotId(getLastPlotId(plotarea), 1); + PlotId end = new PlotId(start.x + size_x - 1, start.y + size_z - 1); + plotarea.setMeta("lastPlot", start); + if (plotarea.canClaim(player, start, end)) { + for (int i = start.x; i <= end.x; i++) { + for (int j = start.y; j <= end.y; j++) { + Plot plot = plotarea.getPlotAbs(new PlotId(i, j)); + boolean teleport = i == end.x && j == end.y; + plot.claim(player, teleport, null); + } + } + if (size_x != 1 || size_z != 1) { + if (!plotarea.mergePlots(MainUtil.getPlotSelectionIds(start, end), true, true)) { + return false; + } + } + break; + } + } + return true; + } + } + + public void autoClaimSafe(final PlotPlayer player, final PlotArea area, PlotId start, final RunnableVal whenDone) { + if (area.TYPE == 2) { + PlotId min = area.getMin(); + PlotId max = area.getMax(); + if (start == null) start = new PlotId(min.x, min.y); + while (!area.canClaim(player, start, start)) { + if (++start.x > max.x) { + start.x = min.x; + if (++start.y > max.y) { + whenDone.run(null); + return; } } - break; + start.recalculateHash(); + } + } else { + if (start == null) start = getLastPlotId(area); + while (!area.canClaim(player, start, start)) { + start = getNextPlotId(start, 1); } } - return true; + Plot plot = area.getPlotAbs(start); + if (plot.canClaim(player)) { + plot.owner = player.getUUID(); + final PlotId finalStart = getNextPlotId(start, 1); + area.setMeta("lastPlot", finalStart); + whenDone.value = plot; + DBFunc.createPlotSafe(plot, whenDone, new Runnable() { + @Override + public void run() { + autoClaimSafe(player, area, finalStart, whenDone); + } + }); + return; + } + autoClaimSafe(player, area, start, whenDone); } public PlotId getLastPlotId(PlotArea area) { diff --git a/Core/src/main/java/com/intellectualcrafters/plot/commands/Claim.java b/Core/src/main/java/com/intellectualcrafters/plot/commands/Claim.java index ea6f39a02..15674e16b 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/commands/Claim.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/commands/Claim.java @@ -2,6 +2,7 @@ package com.intellectualcrafters.plot.commands; import com.intellectualcrafters.plot.config.C; import com.intellectualcrafters.plot.config.Settings; +import com.intellectualcrafters.plot.database.DBFunc; import com.intellectualcrafters.plot.object.Expression; import com.intellectualcrafters.plot.object.Location; import com.intellectualcrafters.plot.object.Plot; @@ -21,13 +22,13 @@ import com.plotsquared.general.commands.CommandDeclaration; public class Claim extends SubCommand { @Override - public boolean onCommand(PlotPlayer player, String[] args) { + public boolean onCommand(final PlotPlayer player, String[] args) { String schematic = ""; if (args.length >= 1) { schematic = args[0]; } Location loc = player.getLocation(); - Plot plot = loc.getPlotAbs(); + final Plot plot = loc.getPlotAbs(); if (plot == null) { return sendMessage(player, C.NOT_IN_PLOT); } @@ -47,7 +48,7 @@ public class Claim extends SubCommand { if (!plot.canClaim(player)) { return sendMessage(player, C.PLOT_IS_CLAIMED); } - PlotArea area = plot.getArea(); + final PlotArea area = plot.getArea(); if (!schematic.isEmpty()) { if (area.SCHEMATIC_CLAIM_SPECIFY) { if (!area.SCHEMATICS.contains(schematic.toLowerCase())) { @@ -81,6 +82,24 @@ public class Claim extends SubCommand { } sendMessage(player, C.REMOVED_GRANTED_PLOT, "1", "" + (grants - 1)); } - return plot.claim(player, false, schematic) || sendMessage(player, C.PLOT_NOT_CLAIMED); + plot.owner = player.getUUID(); + if (plot.canClaim(player)) { + final String finalSchematic = schematic; + DBFunc.createPlotSafe(plot, new Runnable() { + @Override + public void run() { + plot.claim(player, true, finalSchematic, false); + } + }, new Runnable() { + @Override + public void run() { + sendMessage(player, C.PLOT_NOT_CLAIMED); + } + }); + return true; + } else { + sendMessage(player, C.PLOT_NOT_CLAIMED); + } + return false; } } diff --git a/Core/src/main/java/com/intellectualcrafters/plot/database/AbstractDB.java b/Core/src/main/java/com/intellectualcrafters/plot/database/AbstractDB.java index 15a291053..99128d1c7 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/database/AbstractDB.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/database/AbstractDB.java @@ -42,7 +42,7 @@ public interface AbstractDB { * * @param plot the plot to create */ - void createPlot(Plot plot); + void createPlotSafe(final Plot plot, final Runnable success, final Runnable failure); /** * Create tables. diff --git a/Core/src/main/java/com/intellectualcrafters/plot/database/DBFunc.java b/Core/src/main/java/com/intellectualcrafters/plot/database/DBFunc.java index 157758d41..6c3673d13 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/database/DBFunc.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/database/DBFunc.java @@ -125,16 +125,11 @@ public class DBFunc { DBFunc.dbManager.createPlotsAndData(plots, whenDone); } - /** - * Create a plot - * - * @param plot Plot to create - */ - public static void createPlot(Plot plot) { - if (plot.temp == -1 || dbManager == null) { + public static void createPlotSafe(final Plot plot, final Runnable success, final Runnable failure) { + if (dbManager == null) { return; } - DBFunc.dbManager.createPlot(plot); + DBFunc.dbManager.createPlotSafe(plot, success, failure); } /** diff --git a/Core/src/main/java/com/intellectualcrafters/plot/database/SQLManager.java b/Core/src/main/java/com/intellectualcrafters/plot/database/SQLManager.java index bfc42f390..93c84c467 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/database/SQLManager.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/database/SQLManager.java @@ -1,5 +1,6 @@ package com.intellectualcrafters.plot.database; +import com.google.common.base.Charsets; import com.intellectualcrafters.configuration.ConfigurationSection; import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.config.Settings; @@ -53,6 +54,7 @@ public class SQLManager implements AbstractDB { public final String CREATE_SETTINGS; public final String CREATE_TIERS; public final String CREATE_PLOT; + public final String CREATE_PLOT_SAFE; public final String CREATE_CLUSTER; private final String prefix; // Private Final @@ -116,6 +118,12 @@ public class SQLManager implements AbstractDB { 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`, `timestamp`) VALUES(?, ?, ?, ?, ?)"; + + if (mySQL) { + this.CREATE_PLOT_SAFE = "INSERT OR IGNORE INTO `" + this.prefix + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) SELECT ?, ?, ?, ?, ? FROM DUAL WHERE NOT EXISTS (SELECT null FROM `" + this.prefix + "plot` WHERE `world` = ? AND `plot_id_x` = ? AND `plot_id_z` = ?)"; + } else { + this.CREATE_PLOT_SAFE = "INSERT OR IGNORE INTO `" + this.prefix + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) SELECT ?, ?, ?, ?, ? WHERE NOT EXISTS (SELECT null FROM `" + this.prefix + "plot` WHERE `world` = ? AND `plot_id_x` = ? AND `plot_id_z` = ?)"; + } this.CREATE_CLUSTER = "INSERT INTO `" + this.prefix + "cluster`(`pos1_x`, `pos1_z`, `pos2_x`, `pos2_z`, `owner`, `world`) VALUES(?, ?, ?, ?, ?, ?)"; try { @@ -994,14 +1002,9 @@ public class SQLManager implements AbstractDB { }); } - /** - * Create a plot. - * - * @param plot - */ - @Override - public void createPlot(final Plot plot) { - addPlotTask(plot, new UniqueStatement("createPlot") { + public void createPlotSafe(final Plot plot, final Runnable success, final Runnable failure) { + final long timestamp = plot.getTimestamp(); + addPlotTask(plot, new UniqueStatement("createPlotSafe_" + plot.hashCode()) { @Override public void set(PreparedStatement stmt) throws SQLException { stmt.setInt(1, plot.getId().x); @@ -1009,11 +1012,45 @@ public class SQLManager implements AbstractDB { stmt.setString(3, plot.owner.toString()); stmt.setString(4, plot.getArea().toString()); stmt.setTimestamp(5, new Timestamp(plot.getTimestamp())); + stmt.setString(6, plot.getArea().toString()); + stmt.setInt(7, plot.getId().x); + stmt.setInt(8, plot.getId().y); } @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement(SQLManager.this.CREATE_PLOT); + return SQLManager.this.connection.prepareStatement(SQLManager.this.CREATE_PLOT_SAFE, Statement.KEEP_CURRENT_RESULT ); + } + + @Override + public void execute(PreparedStatement statement) { + + } + + @Override + public void addBatch(PreparedStatement statement) throws SQLException { + int inserted = statement.executeUpdate(); + if (inserted > 0) { + try (ResultSet keys = statement.getGeneratedKeys()) { + if (keys.next()) { + plot.temp = keys.getInt(1); + addPlotTask(plot, new UniqueStatement("createPlotAndSettings_settings_" + plot.hashCode()) { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, getId(plot)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement("INSERT INTO `" + SQLManager.this.prefix + "plot_settings`(`plot_plot_id`) VALUES(?)"); + } + }); + if (success != null) addNotifyTask(success); + return; + } + } + } + if (failure != null) failure.run(); } }); } @@ -1040,7 +1077,7 @@ public class SQLManager implements AbstractDB { stmt.setInt(1, plot.getId().x); stmt.setInt(2, plot.getId().y); stmt.setString(3, plot.owner.toString()); - stmt.setString(4, plot.getArea().worldname); + stmt.setString(4, plot.getArea().toString()); stmt.setTimestamp(5, new Timestamp(plot.getTimestamp())); } @@ -1055,9 +1092,10 @@ public class SQLManager implements AbstractDB { @Override public void addBatch(PreparedStatement statement) throws SQLException { statement.executeUpdate(); - ResultSet keys = statement.getGeneratedKeys(); - if (keys.next()) { - plot.temp = keys.getInt(1); + try (ResultSet keys = statement.getGeneratedKeys()) { + if (keys.next()) { + plot.temp = keys.getInt(1); + } } } }); @@ -1069,8 +1107,7 @@ public class SQLManager implements AbstractDB { @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection - .prepareStatement("INSERT INTO `" + SQLManager.this.prefix + "plot_settings`(`plot_plot_id`) VALUES(?)"); + return SQLManager.this.connection.prepareStatement("INSERT INTO `" + SQLManager.this.prefix + "plot_settings`(`plot_plot_id`) VALUES(?)"); } }); addNotifyTask(whenDone); @@ -1714,7 +1751,15 @@ public class SQLManager implements AbstractDB { o = resultSet.getString("owner"); user = uuids.get(o); if (user == null) { - user = UUID.fromString(o); + try { + user = UUID.fromString(o); + } catch (IllegalArgumentException e) { + if (Settings.UUID.FORCE_LOWERCASE) { + user = UUID.nameUUIDFromBytes(("OfflinePlayer:" + o.toLowerCase()).getBytes(Charsets.UTF_8)); + } else { + user = UUID.nameUUIDFromBytes(("OfflinePlayer:" + o).getBytes(Charsets.UTF_8)); + } + } uuids.put(o, user); } long time; @@ -2722,7 +2767,7 @@ public class SQLManager implements AbstractDB { for (String element : flags_string) { if (element.contains(":")) { String[] split = element.split(":"); - String flag_str = split[1].replaceAll("\u00AF", ":").replaceAll("�", ","); + String flag_str = split[1].replaceAll("\u00AF", ":").replaceAll("´", ","); Flag flag = FlagManager.getOrCreateFlag(split[0]); if (flag == null) { flag = new StringFlag(split[0]) { @@ -2776,7 +2821,7 @@ public class SQLManager implements AbstractDB { flag_string.append(','); } flag_string.append(flag.getKey().getName()).append(':') - .append(flag.getKey().valueToString(flag.getValue()).replaceAll(":", "¯").replaceAll(",", "´")); + .append(flag.getKey().valueToString(flag.getValue()).replaceAll(":", "\u00AF").replaceAll(",", "´")); i++; } addClusterTask(cluster, new UniqueStatement("setFlags") { diff --git a/Core/src/main/java/com/intellectualcrafters/plot/object/Plot.java b/Core/src/main/java/com/intellectualcrafters/plot/object/Plot.java index b8dc06e18..cc2ad11e8 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/object/Plot.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/object/Plot.java @@ -1330,9 +1330,17 @@ public class Plot { if (!canClaim(player)) { return false; } + return claim(player, teleport, schematic, true); + } + + public boolean claim(final PlotPlayer player, boolean teleport, String schematic, boolean updateDB) { boolean result = EventUtil.manager.callClaim(player, this, false); - if (!result || !create(player.getUUID(), true)) { - return false; + if (updateDB) { + if (!result || (!create(player.getUUID(), true))) { + return false; + } + } else { + area.addPlot(this); } setSign(player.getName()); MainUtil.sendMessage(player, C.CLAIMED); diff --git a/Core/src/main/java/com/intellectualcrafters/plot/object/PlotArea.java b/Core/src/main/java/com/intellectualcrafters/plot/object/PlotArea.java index 2cc5beb2b..5e4b649dd 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/object/PlotArea.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/object/PlotArea.java @@ -744,10 +744,19 @@ public abstract class PlotArea { } public boolean canClaim(PlotPlayer player, PlotId pos1, PlotId pos2) { + if (pos1.x == pos2.x && pos1.y == pos2.y) { + if (getOwnedPlot(pos1) != null) { + return false; + } + Plot plot = getPlotAbs(pos1); + if (plot == null) return false; + return plot.canClaim(player); + } for (int x = pos1.x; x <= pos2.x; x++) { for (int y = pos1.y; y <= pos2.y; y++) { PlotId id = new PlotId(x, y); Plot plot = getPlotAbs(id); + if (plot == null) return false; if (!plot.canClaim(player)) { return false; } diff --git a/Core/src/main/java/com/intellectualcrafters/plot/util/expiry/ExpireManager.java b/Core/src/main/java/com/intellectualcrafters/plot/util/expiry/ExpireManager.java index e03e59935..25acd389e 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/util/expiry/ExpireManager.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/util/expiry/ExpireManager.java @@ -16,6 +16,7 @@ import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.object.RunnableVal; import com.intellectualcrafters.plot.object.RunnableVal3; import com.intellectualcrafters.plot.util.MainUtil; +import com.intellectualcrafters.plot.util.StringMan; import com.intellectualcrafters.plot.util.TaskManager; import com.intellectualcrafters.plot.util.UUIDHandler; import java.util.ArrayDeque; @@ -25,6 +26,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Objects; +import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedDeque; @@ -244,16 +246,17 @@ public class ExpireManager { ExpireManager.this.running = 0; return; } - final Plot plot = plots.poll(); + Plot plot = plots.poll(); PlotArea area = plot.getArea(); + final Plot newPlot = area.getPlot(plot.getId()); final ArrayDeque applicable = new ArrayDeque<>(tasks); - final Collection expired = isExpired(applicable, plot); + final Collection expired = isExpired(applicable, newPlot); if (expired.isEmpty()) { continue; } for (ExpiryTask expiryTask : expired) { if (!expiryTask.needsAnalysis()) { - expiredTask.run(plot, new Runnable() { + expiredTask.run(newPlot, new Runnable() { @Override public void run() { TaskManager.IMP.taskLaterAsync(task, 1); @@ -268,7 +271,7 @@ public class ExpireManager { passesComplexity(changed, expired, new RunnableVal() { @Override public void run(Boolean confirmation) { - expiredTask.run(plot, new Runnable() { + expiredTask.run(newPlot, new Runnable() { @Override public void run() { TaskManager.IMP.taskLaterAsync(task, 1); @@ -278,7 +281,7 @@ public class ExpireManager { }, new Runnable() { @Override public void run() { - FlagManager.addPlotFlag(plot, Flags.ANALYSIS, changed.asList()); + FlagManager.addPlotFlag(newPlot, Flags.ANALYSIS, changed.asList()); TaskManager.runTaskLaterAsync(task, 20); } }); @@ -287,11 +290,11 @@ public class ExpireManager { final Runnable doAnalysis = new Runnable() { @Override public void run() { - HybridUtils.manager.analyzePlot(plot, handleAnalysis); + HybridUtils.manager.analyzePlot(newPlot, handleAnalysis); } }; - PlotAnalysis analysis = plot.getComplexity(null); + PlotAnalysis analysis = newPlot.getComplexity(null); if (analysis != null) { passesComplexity(analysis, expired, new RunnableVal() { @Override @@ -352,11 +355,12 @@ public class ExpireManager { MainUtil.sendMessage(player, C.PLOT_REMOVED_USER, plot.toString()); } } + Set plots = plot.getConnectedPlots(); plot.deletePlot(whenDone); PlotAnalysis changed = plot.getComplexity(null); int changes = changed == null ? 0 : changed.changes_sd; int modified = changed == null ? 0 : changed.changes; - PS.debug("$2[&5Expire&dManager$2] &cDeleted expired plot: " + plot + " User:" + plot.owner + " Delta:" + changes + "/" + modified); + PS.debug("$2[&5Expire&dManager$2] &cDeleted expired plot: " + plot + " User:" + plot.owner + " Delta:" + changes + "/" + modified + " Connected: " + StringMan.getString(plots)); PS.debug("$4 - Area: " + plot.getArea()); if (plot.hasOwner()) { PS.debug("$4 - Owner: " + UUIDHandler.getName(plot.owner));