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;
import com.intellectualcrafters.plot.config.Storage;
import com.intellectualcrafters.plot.flag.Flag;
import com.intellectualcrafters.plot.flag.FlagManager;
import com.intellectualcrafters.plot.flag.StringFlag;
import com.intellectualcrafters.plot.object.BlockLoc;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotArea;
import com.intellectualcrafters.plot.object.PlotCluster;
import com.intellectualcrafters.plot.object.PlotId;
import com.intellectualcrafters.plot.object.PlotSettings;
import com.intellectualcrafters.plot.object.RunnableVal;
import com.intellectualcrafters.plot.object.comment.PlotComment;
import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.StringMan;
import com.intellectualcrafters.plot.util.TaskManager;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
@SuppressWarnings("SqlDialectInspection")
public class SQLManager implements AbstractDB {
// Public final
public final String SET_OWNER;
public final String GET_ALL_PLOTS;
public final String CREATE_PLOTS;
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
private final Database database;
private final boolean mySQL;
/**
* important tasks
*/
public volatile Queue<Runnable> globalTasks;
/**
* Notify tasks
*/
public volatile Queue<Runnable> notifyTasks;
/**
* plot
* plot_denied
* plot_helpers
* plot_trusted
* plot_comments
* plot_settings
* plot_rating
*/
public volatile ConcurrentHashMap<Plot, Queue<UniqueStatement>> plotTasks;
/**
* player_meta
*/
public volatile ConcurrentHashMap<UUID, Queue<UniqueStatement>> playerTasks;
/**
* cluster
* cluster_helpers
* cluster_invited
* cluster_settings
*/
public volatile ConcurrentHashMap<PlotCluster, Queue<UniqueStatement>> clusterTasks;
// Private
private Connection connection;
private boolean closed = false;
/**
* Constructor
*
* @param database
* @param p prefix
* @throws SQLException
* @throws ClassNotFoundException
*/
public SQLManager(final Database database, String p, boolean debug) throws SQLException, ClassNotFoundException {
// Private final
this.database = database;
this.connection = database.openConnection();
this.mySQL = database instanceof MySQL;
this.globalTasks = new ConcurrentLinkedQueue<>();
this.notifyTasks = new ConcurrentLinkedQueue<>();
this.plotTasks = new ConcurrentHashMap<>();
this.playerTasks = new ConcurrentHashMap<>();
this.clusterTasks = new ConcurrentHashMap<>();
this.prefix = p;
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`, `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`, `timestamp`) VALUES(?, ?, ?, ?, ?)";
if (mySQL) {
this.CREATE_PLOT_SAFE = "INSERT 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 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 {
createTables();
} catch (SQLException e) {
e.printStackTrace();
}
TaskManager.runTaskAsync(new Runnable() {
@Override
public void run() {
long last = System.currentTimeMillis();
while (true) {
if (SQLManager.this.closed) {
break;
}
boolean hasTask = !globalTasks.isEmpty() || !playerTasks.isEmpty() || !plotTasks.isEmpty() || !clusterTasks.isEmpty();
if (hasTask) {
if (SQLManager.this.mySQL && System.currentTimeMillis() - last > 550000 || !isValid()) {
last = System.currentTimeMillis();
reconnect();
}
if (!sendBatch()) {
try {
if (!getNotifyTasks().isEmpty()) {
for (Runnable task : getNotifyTasks()) {
TaskManager.runTask(task);
}
getNotifyTasks().clear();
}
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
}
public boolean isValid() {
try {
if (connection.isClosed()) {
return false;
}
} catch (SQLException e) {
return false;
}
try (PreparedStatement stmt = this.connection.prepareStatement("SELECT 1")) {
stmt.executeQuery();
return true;
} catch (Throwable e) {
return false;
}
}
public void reconnect() {
try {
close();
SQLManager.this.closed = false;
SQLManager.this.connection = database.forceConnection();
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public synchronized Queue<Runnable> getGlobalTasks() {
return this.globalTasks;
}
public synchronized Queue<Runnable> getNotifyTasks() {
return this.notifyTasks;
}
public synchronized void addPlotTask(Plot plot, UniqueStatement task) {
if (plot == null) {
plot = new Plot(null, new PlotId(Integer.MAX_VALUE, Integer.MAX_VALUE));
}
Queue<UniqueStatement> tasks = this.plotTasks.get(plot);
if (tasks == null) {
tasks = new ConcurrentLinkedQueue<>();
this.plotTasks.put(plot, tasks);
}
if (task == null) {
task = new UniqueStatement(String.valueOf(plot.hashCode())) {
@Override
public PreparedStatement get() {
return null;
}
@Override
public void set(PreparedStatement stmt) {}
@Override
public void addBatch(PreparedStatement statement) {}
@Override
public void execute(PreparedStatement statement) {}
};
}
tasks.add(task);
}
public synchronized void addPlayerTask(UUID uuid, UniqueStatement task) {
if (uuid == null) {
return;
}
Queue<UniqueStatement> tasks = this.playerTasks.get(uuid);
if (tasks == null) {
tasks = new ConcurrentLinkedQueue<>();
this.playerTasks.put(uuid, tasks);
}
if (task == null) {
task = new UniqueStatement(String.valueOf(uuid.hashCode())) {
@Override
public PreparedStatement get() {
return null;
}
@Override
public void set(PreparedStatement stmt) {}
@Override
public void addBatch(PreparedStatement statement) {}
@Override
public void execute(PreparedStatement statement) {}
};
}
tasks.add(task);
}
public synchronized void addClusterTask(PlotCluster cluster, UniqueStatement task) {
Queue<UniqueStatement> tasks = this.clusterTasks.get(cluster);
if (tasks == null) {
tasks = new ConcurrentLinkedQueue<>();
this.clusterTasks.put(cluster, tasks);
}
if (task == null) {
task = new UniqueStatement(String.valueOf(cluster.hashCode())) {
@Override
public PreparedStatement get() {
return null;
}
@Override
public void set(PreparedStatement stmt) {}
@Override
public void addBatch(PreparedStatement statement) {}
@Override
public void execute(PreparedStatement statement) {}
};
}
tasks.add(task);
}
public synchronized void addGlobalTask(Runnable task) {
getGlobalTasks().add(task);
}
public synchronized void addNotifyTask(Runnable task) {
if (task != null) {
getNotifyTasks().add(task);
}
}
public boolean sendBatch() {
try {
if (!getGlobalTasks().isEmpty()) {
if (this.connection.getAutoCommit()) {
this.connection.setAutoCommit(false);
}
Runnable task = getGlobalTasks().remove();
if (task != null) {
try {
task.run();
} catch (Throwable e) {
PS.debug("============ DATABASE ERROR ============");
PS.debug("There was an error updating the database.");
PS.debug(" - It will be correct on shutdown");
PS.debug("========================================");
e.printStackTrace();
PS.debug("========================================");
}
}
commit();
return true;
}
int count = -1;
if (!this.plotTasks.isEmpty()) {
count = 0;
if (this.connection.getAutoCommit()) {
this.connection.setAutoCommit(false);
}
String method = null;
PreparedStatement statement = null;
UniqueStatement task = null;
UniqueStatement lastTask = null;
Iterator<Entry<Plot, Queue<UniqueStatement>>> iter = this.plotTasks.entrySet().iterator();
while (iter.hasNext()) {
try {
Entry<Plot, Queue<UniqueStatement>> entry = iter.next();
Plot plot = entry.getKey();
Queue<UniqueStatement> tasks = entry.getValue();
if (tasks.isEmpty()) {
iter.remove();
continue;
}
task = tasks.remove();
count++;
if (task != null) {
if (task.method == null || !task.method.equals(method)) {
if (statement != null) {
lastTask.execute(statement);
statement.close();
}
method = task.method;
statement = task.get();
}
task.set(statement);
task.addBatch(statement);
}
lastTask = task;
} catch (Throwable e) {
PS.debug("============ DATABASE ERROR ============");
PS.debug("There was an error updating the database.");
PS.debug(" - It will be correct on shutdown");
PS.debug("========================================");
e.printStackTrace();
PS.debug("========================================");
}
}
if (statement != null && task != null) {
task.execute(statement);
statement.close();
}
}
if (!this.playerTasks.isEmpty()) {
count = 0;
if (this.connection.getAutoCommit()) {
this.connection.setAutoCommit(false);
}
String method = null;
PreparedStatement statement = null;
UniqueStatement task = null;
UniqueStatement lastTask = null;
for (Entry<UUID, Queue<UniqueStatement>> entry : this.playerTasks.entrySet()) {
try {
UUID uuid = entry.getKey();
if (this.playerTasks.get(uuid).isEmpty()) {
this.playerTasks.remove(uuid);
continue;
}
task = this.playerTasks.get(uuid).remove();
count++;
if (task != null) {
if (task.method == null || !task.method.equals(method)) {
if (statement != null) {
lastTask.execute(statement);
statement.close();
}
method = task.method;
statement = task.get();
}
task.set(statement);
task.addBatch(statement);
}
lastTask = task;
} catch (Throwable e) {
PS.debug("============ DATABASE ERROR ============");
PS.debug("There was an error updating the database.");
PS.debug(" - It will be correct on shutdown");
PS.debug("========================================");
e.printStackTrace();
PS.debug("========================================");
}
}
if (statement != null && task != null) {
task.execute(statement);
statement.close();
}
}
if (!this.clusterTasks.isEmpty()) {
count = 0;
if (this.connection.getAutoCommit()) {
this.connection.setAutoCommit(false);
}
String method = null;
PreparedStatement statement = null;
UniqueStatement task = null;
UniqueStatement lastTask = null;
for (Entry<PlotCluster, Queue<UniqueStatement>> entry : this.clusterTasks.entrySet()) {
try {
PlotCluster cluster = entry.getKey();
if (this.clusterTasks.get(cluster).isEmpty()) {
this.clusterTasks.remove(cluster);
continue;
}
task = this.clusterTasks.get(cluster).remove();
count++;
if (task != null) {
if (task.method == null || !task.method.equals(method)) {
if (statement != null) {
lastTask.execute(statement);
statement.close();
}
method = task.method;
statement = task.get();
}
task.set(statement);
task.addBatch(statement);
}
lastTask = task;
} catch (Throwable e) {
PS.debug("============ DATABASE ERROR ============");
PS.debug("There was an error updating the database.");
PS.debug(" - It will be correct on shutdown");
PS.debug("========================================");
e.printStackTrace();
PS.debug("========================================");
}
}
if (statement != null && task != null) {
task.execute(statement);
statement.close();
}
}
if (count > 0) {
commit();
return true;
}
if (count != -1) {
if (!this.connection.getAutoCommit()) {
this.connection.setAutoCommit(true);
}
}
if (!this.clusterTasks.isEmpty()) {
this.clusterTasks.clear();
}
if (!this.plotTasks.isEmpty()) {
this.plotTasks.clear();
}
} catch (Throwable e) {
PS.debug("============ DATABASE ERROR ============");
PS.debug("There was an error updating the database.");
PS.debug(" - It will be correct on shutdown");
PS.debug("========================================");
e.printStackTrace();
PS.debug("========================================");
}
return false;
}
public Connection getConnection() {
return this.connection;
}
/**
* Set Plot owner
*
* @param plot Plot Object
* @param uuid Owner UUID
*/
@Override
public void setOwner(final Plot plot, final UUID uuid) {
addPlotTask(plot, new UniqueStatement("setOwner") {
@Override
public void set(PreparedStatement statement) throws SQLException {
statement.setString(1, uuid.toString());
statement.setInt(2, plot.getId().x);
statement.setInt(3, plot.getId().y);
statement.setString(4, plot.getArea().toString());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection.prepareStatement(SQLManager.this.SET_OWNER);
}
});
}
@Override
public void createPlotsAndData(final List<Plot> myList, final Runnable whenDone) {
addGlobalTask(new Runnable() {
@Override
public void run() {
try {
// Create the plots
createPlots(myList, new Runnable() {
@Override
public void run() {
try {
// Creating datastructures
HashMap<PlotId, Plot> plotMap = new HashMap<>();
for (Plot plot : myList) {
plotMap.put(plot.getId(), plot);
}
ArrayList<SettingsPair> settings = new ArrayList<>();
final ArrayList<UUIDPair> helpers = new ArrayList<>();
final ArrayList<UUIDPair> trusted = new ArrayList<>();
final ArrayList<UUIDPair> denied = new ArrayList<>();
// Populating structures
try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement(SQLManager.this.GET_ALL_PLOTS);
ResultSet result = stmt.executeQuery()) {
while (result.next()) {
int id = result.getInt("id");
int x = result.getInt("plot_id_x");
int y = result.getInt("plot_id_z");
PlotId plotId = new PlotId(x, y);
Plot plot = plotMap.get(plotId);
if (plot != null) {
settings.add(new SettingsPair(id, plot.getSettings()));
for (UUID uuid : plot.getDenied()) {
denied.add(new UUIDPair(id, uuid));
}
for (UUID uuid : plot.getMembers()) {
trusted.add(new UUIDPair(id, uuid));
}
for (UUID uuid : plot.getTrusted()) {
helpers.add(new UUIDPair(id, uuid));
}
}
}
}
createSettings(settings, new Runnable() {
@Override
public void run() {
createTiers(helpers, "helpers", new Runnable() {
@Override
public void run() {
createTiers(trusted, "trusted", new Runnable() {
@Override
public void run() {
createTiers(denied, "denied", new Runnable() {
@Override
public void run() {
try {
SQLManager.this.connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}
if (whenDone != null) {
whenDone.run();
}
}
});
}
});
}
});
}
});
} catch (SQLException e) {
e.printStackTrace();
PS.debug("&7[WARN] Failed to set all helpers for plots");
try {
SQLManager.this.connection.commit();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
}
});
} catch (Exception e) {
e.printStackTrace();
PS.debug("&7[WARN] Failed to set all helpers for plots");
try {
SQLManager.this.connection.commit();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
}
});
}
/**
* Create a plot
*
* @param myList list of plots to be created
*/
public void createTiers(ArrayList<UUIDPair> myList, final String tier, Runnable whenDone) {
StmtMod<UUIDPair> mod = new StmtMod<UUIDPair>() {
@Override
public String getCreateMySQL(int size) {
return getCreateMySQL(size, SQLManager.this.CREATE_TIERS.replaceAll("%tier%", tier), 2);
}
@Override
public String getCreateSQLite(int size) {
return getCreateSQLite(size,
"INSERT INTO `" + SQLManager.this.prefix + "plot_" + tier + "` SELECT ? AS `plot_plot_id`, ? AS `user_uuid`", 2);
}
@Override
public String getCreateSQL() {
return "INSERT INTO `" + SQLManager.this.prefix + "plot_" + tier + "` (`plot_plot_id`, `user_uuid`) VALUES(?,?)";
}
@Override
public void setMySQL(PreparedStatement stmt, int i, UUIDPair pair) throws SQLException {
stmt.setInt(i * 2 + 1, pair.id);
stmt.setString(i * 2 + 2, pair.uuid.toString());
}
@Override
public void setSQLite(PreparedStatement stmt, int i, UUIDPair pair) throws SQLException {
stmt.setInt(i * 2 + 1, pair.id);
stmt.setString(i * 2 + 2, pair.uuid.toString());
}
@Override
public void setSQL(PreparedStatement stmt, UUIDPair pair) throws SQLException {
stmt.setInt(1, pair.id);
stmt.setString(2, pair.uuid.toString());
}
};
setBulk(myList, mod, whenDone);
}
/**
* Create a plot
*
* @param myList list of plots to be created
*/
public void createPlots(List<Plot> myList, Runnable whenDone) {
StmtMod<Plot> mod = new StmtMod<Plot>() {
@Override
public String getCreateMySQL(int size) {
return getCreateMySQL(size, SQLManager.this.CREATE_PLOTS, 5);
}
@Override
public String getCreateSQLite(int size) {
return getCreateSQLite(size, "INSERT INTO `" + SQLManager.this.prefix
+ "plot` SELECT ? AS `id`, ? AS `plot_id_x`, ? AS `plot_id_z`, ? AS `owner`, ? AS `world`, ? AS `timestamp` ", 6);
}
@Override
public String getCreateSQL() {
return SQLManager.this.CREATE_PLOT;
}
@Override
public void setMySQL(PreparedStatement stmt, int i, Plot plot) throws SQLException {
stmt.setInt(i * 5 + 1, plot.getId().x);
stmt.setInt(i * 5 + 2, plot.getId().y);
try {
stmt.setString(i * 5 + 3, plot.owner.toString());
} catch (SQLException ignored) {
stmt.setString(i * 5 + 3, AbstractDB.everyone.toString());
}
stmt.setString(i * 5 + 4, plot.getArea().toString());
stmt.setTimestamp(i * 5 + 5, new Timestamp(plot.getTimestamp()));
}
@Override
public void setSQLite(PreparedStatement stmt, int i, Plot plot) throws SQLException {
stmt.setNull(i * 6 + 1, 4);
stmt.setInt(i * 6 + 2, plot.getId().x);
stmt.setInt(i * 6 + 3, plot.getId().y);
try {
stmt.setString(i * 6 + 4, plot.owner.toString());
} catch (SQLException ignored) {
stmt.setString(i * 6 + 4, AbstractDB.everyone.toString());
}
stmt.setString(i * 6 + 5, plot.getArea().toString());
stmt.setTimestamp(i * 6 + 6, new Timestamp(plot.getTimestamp()));
}
@Override
public void setSQL(PreparedStatement stmt, Plot plot) throws SQLException {
stmt.setInt(1, plot.getId().x);
stmt.setInt(2, plot.getId().y);
stmt.setString(3, plot.owner.toString());
stmt.setString(4, plot.getArea().toString());
stmt.setTimestamp(5, new Timestamp(plot.getTimestamp()));
}
};
setBulk(myList, mod, whenDone);
}
public <T> void setBulk(List<T> objList, StmtMod<T> mod, Runnable whenDone) {
int size = objList.size();
if (size == 0) {
if (whenDone != null) {
whenDone.run();
}
return;
}
int packet;
if (this.mySQL) {
packet = Math.min(size, 5000);
} else {
packet = Math.min(size, 50);
}
int amount = size / packet;
try {
int count = 0;
PreparedStatement preparedStmt = null;
int last = -1;
for (int j = 0; j <= amount; j++) {
List<T> subList = objList.subList(j * packet, Math.min(size, (j + 1) * packet));
if (subList.isEmpty()) {
break;
}
String statement;
if (last == -1) {
last = subList.size();
statement = mod.getCreateMySQL(subList.size());
preparedStmt = this.connection.prepareStatement(statement);
}
if (subList.size() != last || count % 5000 == 0 && count > 0) {
preparedStmt.executeBatch();
preparedStmt.close();
statement = mod.getCreateMySQL(subList.size());
preparedStmt = this.connection.prepareStatement(statement);
}
for (int i = 0; i < subList.size(); i++) {
count++;
T obj = subList.get(i);
mod.setMySQL(preparedStmt, i, obj);
}
last = subList.size();
preparedStmt.addBatch();
}
PS.debug("&aBatch 1: " + count + " | " + objList.get(0).getClass().getCanonicalName());
preparedStmt.executeBatch();
preparedStmt.clearParameters();
preparedStmt.close();
if (whenDone != null) {
whenDone.run();
}
return;
} catch (SQLException e) {
if (this.mySQL) {
e.printStackTrace();
PS.debug("&cERROR 1: | " + objList.get(0).getClass().getCanonicalName());
}
}
try {
int count = 0;
PreparedStatement preparedStmt = null;
int last = -1;
for (int j = 0; j <= amount; j++) {
List<T> subList = objList.subList(j * packet, Math.min(size, (j + 1) * packet));
if (subList.isEmpty()) {
break;
}
String statement;
if (last == -1) {
last = subList.size();
statement = mod.getCreateSQLite(subList.size());
preparedStmt = this.connection.prepareStatement(statement);
}
if (subList.size() != last || count % 5000 == 0 && count > 0) {
preparedStmt.executeBatch();
preparedStmt.clearParameters();
statement = mod.getCreateSQLite(subList.size());
preparedStmt = this.connection.prepareStatement(statement);
}
for (int i = 0; i < subList.size(); i++) {
count++;
T obj = subList.get(i);
mod.setSQLite(preparedStmt, i, obj);
}
last = subList.size();
preparedStmt.addBatch();
}
PS.debug("&aBatch 2: " + count + " | " + objList.get(0).getClass().getCanonicalName());
preparedStmt.executeBatch();
preparedStmt.clearParameters();
preparedStmt.close();
} catch (SQLException e) {
e.printStackTrace();
PS.debug("&cERROR 2: | " + objList.get(0).getClass().getCanonicalName());
PS.debug("&6[WARN] Could not bulk save!");
try (PreparedStatement preparedStmt = this.connection.prepareStatement(mod.getCreateSQL())) {
for (T obj : objList) {
mod.setSQL(preparedStmt, obj);
preparedStmt.addBatch();
}
PS.debug("&aBatch 3");
preparedStmt.executeBatch();
} catch (SQLException e3) {
e3.printStackTrace();
PS.debug("&c[ERROR] Failed to save all!");
}
}
if (whenDone != null) {
whenDone.run();
}
}
public void createSettings(final ArrayList<SettingsPair> myList, final Runnable whenDone) {
final StmtMod<SettingsPair> mod = new StmtMod<SettingsPair>() {
@Override
public String getCreateMySQL(int size) {
return getCreateMySQL(size, "INSERT INTO `" + SQLManager.this.prefix
+ "plot_settings`(`plot_plot_id`,`biome`,`rain`,`custom_time`,`time`,`deny_entry`,`alias`,`flags`,`merged`,"
+ "`position`) VALUES ",
10);
}
@Override
public String getCreateSQLite(int size) {
return getCreateSQLite(
size,
"INSERT INTO `"
+ SQLManager.this.prefix
+ "plot_settings` SELECT ? AS `plot_plot_id`, ? AS `biome`, ? AS `rain`, ? AS `custom_time`, ? AS `time`, ? AS "
+ "`deny_entry`, ? AS `alias`, ? AS `flags`, ? AS `merged`, ? AS `position`",
10);
}
@Override
public String getCreateSQL() {
return "INSERT INTO `" + SQLManager.this.prefix + "plot_settings`(`plot_plot_id`) VALUES(?)";
}
@Override
public void setMySQL(PreparedStatement statement, int i, SettingsPair pair) throws SQLException {
statement.setInt(i * 10 + 1, pair.id); // id
statement.setNull(i * 10 + 2, 4); // biome
statement.setNull(i * 10 + 3, 4); // rain
statement.setNull(i * 10 + 4, 4); // custom_time
statement.setNull(i * 10 + 5, 4); // time
statement.setNull(i * 10 + 6, 4); // deny_entry
if (pair.settings.getAlias().isEmpty()) {
statement.setNull(i * 10 + 7, 4);
} else {
statement.setString(i * 10 + 7, pair.settings.getAlias());
}
StringBuilder flag_string = new StringBuilder();
int k = 0;
for (Entry<Flag<?>, ?> flag : pair.settings.flags.entrySet()) {
if (k != 0) {
flag_string.append(',');
}
flag_string.append(flag.getKey().getName()).append(':').append(flag.getKey().valueToString(flag.getValue()).replaceAll(":", "¯")
.replaceAll(",", "´"));
k++;
}
statement.setString(i * 10 + 8, flag_string.toString());
boolean[] merged = pair.settings.getMerged();
int hash = MainUtil.hash(merged);
statement.setInt(i * 10 + 9, hash);
BlockLoc loc = pair.settings.getPosition();
String position;
if (loc.y == 0) {
position = "DEFAULT";
} else {
position = loc.x + "," + loc.y + ',' + loc.z;
}
statement.setString(i * 10 + 10, position);
}
@Override
public void setSQLite(PreparedStatement stmt, int i, SettingsPair pair) throws SQLException {
stmt.setInt(i * 10 + 1, pair.id); // id
stmt.setNull(i * 10 + 2, 4); // biome
stmt.setNull(i * 10 + 3, 4); // rain
stmt.setNull(i * 10 + 4, 4); // custom_time
stmt.setNull(i * 10 + 5, 4); // time
stmt.setNull(i * 10 + 6, 4); // deny_entry
if (pair.settings.getAlias().isEmpty()) {
stmt.setNull(i * 10 + 7, 4);
} else {
stmt.setString(i * 10 + 7, pair.settings.getAlias());
}
StringBuilder flag_string = new StringBuilder();
int k = 0;
for (Entry<Flag<?>, ?> flag : pair.settings.flags.entrySet()) {
if (k != 0) {
flag_string.append(',');
}
flag_string.append(flag.getKey().getName()).append(':').append(flag.getKey().valueToString(flag.getValue()).replaceAll(":", "¯")
.replaceAll(",", "´"));
k++;
}
stmt.setString(i * 10 + 8, flag_string.toString());
boolean[] merged = pair.settings.getMerged();
int n = 0;
for (int j = 0; j < 4; ++j) {
n = (n << 1) + (merged[j] ? 1 : 0);
}
stmt.setInt(i * 10 + 9, n);
BlockLoc loc = pair.settings.getPosition();
String position;
if (loc.y == 0) {
position = "DEFAULT";
} else {
position = loc.x + "," + loc.y + ',' + loc.z;
}
stmt.setString(i * 10 + 10, position);
}
@Override
public void setSQL(PreparedStatement stmt, SettingsPair pair) throws SQLException {
stmt.setInt(1, pair.id);
}
};
addGlobalTask(new Runnable() {
@Override
public void run() {
setBulk(myList, mod, whenDone);
}
});
}
public void createEmptySettings(final ArrayList<Integer> myList, final Runnable whenDone) {
final StmtMod<Integer> mod = new StmtMod<Integer>() {
@Override
public String getCreateMySQL(int size) {
return getCreateMySQL(size, SQLManager.this.CREATE_SETTINGS, 1);
}
@Override
public String getCreateSQLite(int size) {
return getCreateSQLite(
size,
"INSERT INTO `"
+ SQLManager.this.prefix
+ "plot_settings` SELECT ? AS `plot_plot_id`, ? AS `biome`, ? AS `rain`, ? AS `custom_time`, ? AS `time`, ? AS "
+ "`deny_entry`, ? AS `alias`, ? AS `flags`, ? AS `merged`, ? AS `position` ",
10);
}
@Override
public String getCreateSQL() {
return "INSERT INTO `" + SQLManager.this.prefix + "plot_settings`(`plot_plot_id`) VALUES(?)";
}
@Override
public void setMySQL(PreparedStatement stmt, int i, Integer id) throws SQLException {
stmt.setInt(i + 1, id);
}
@Override
public void setSQLite(PreparedStatement stmt, int i, Integer id) throws SQLException {
stmt.setInt(i * 10 + 1, id);
stmt.setNull(i * 10 + 2, 4);
stmt.setNull(i * 10 + 3, 4);
stmt.setNull(i * 10 + 4, 4);
stmt.setNull(i * 10 + 5, 4);
stmt.setNull(i * 10 + 6, 4);
stmt.setNull(i * 10 + 7, 4);
stmt.setNull(i * 10 + 8, 4);
stmt.setNull(i * 10 + 9, 4);
stmt.setString(i * 10 + 10, "DEFAULT");
}
@Override
public void setSQL(PreparedStatement stmt, Integer id) throws SQLException {
stmt.setInt(1, id);
}
};
addGlobalTask(new Runnable() {
@Override
public void run() {
setBulk(myList, mod, whenDone);
}
});
}
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);
stmt.setInt(2, plot.getId().y);
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_SAFE, Statement.RETURN_GENERATED_KEYS );
}
@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();
}
});
}
public void commit() {
if (this.closed) {
return;
}
try {
if (!this.connection.getAutoCommit()) {
this.connection.commit();
this.connection.setAutoCommit(true);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void createPlotAndSettings(final Plot plot, Runnable whenDone) {
addPlotTask(plot, new UniqueStatement("createPlotAndSettings_" + plot.hashCode()) {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, plot.getId().x);
stmt.setInt(2, plot.getId().y);
stmt.setString(3, plot.owner.toString());
stmt.setString(4, plot.getArea().toString());
stmt.setTimestamp(5, new Timestamp(plot.getTimestamp()));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection.prepareStatement(SQLManager.this.CREATE_PLOT, Statement.RETURN_GENERATED_KEYS);
}
@Override
public void execute(PreparedStatement statement) {}
@Override
public void addBatch(PreparedStatement statement) throws SQLException {
statement.executeUpdate();
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(?)");
}
});
addNotifyTask(whenDone);
}
/**
* Create tables.
*
* @throws SQLException
*/
@Override
public void createTables() throws SQLException {
String[] tables =
new String[]{"plot", "plot_denied", "plot_helpers", "plot_comments", "plot_trusted", "plot_rating", "plot_settings", "cluster",
"player_meta"};
DatabaseMetaData meta = this.connection.getMetaData();
int create = 0;
for (String s : tables) {
ResultSet set = meta.getTables(null, null, this.prefix + s, new String[]{"TABLE"});
// ResultSet set = meta.getTables(null, null, prefix + s, null);
if (!set.next()) {
create++;
}
set.close();
}
if (create == 0) {
return;
}
boolean addConstraint = create == tables.length;
PS.debug("Creating tables");
try (Statement stmt = this.connection.createStatement()) {
if (this.mySQL) {
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "plot` ("
+ "`id` INT(11) NOT NULL AUTO_INCREMENT,"
+ "`plot_id_x` INT(11) NOT NULL,"
+ "`plot_id_z` INT(11) NOT NULL,"
+ "`owner` VARCHAR(40) NOT NULL,"
+ "`world` VARCHAR(45) NOT NULL,"
+ "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,"
+ "PRIMARY KEY (`id`)"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=0");
stmt
.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_denied` (`plot_plot_id` INT(11) NOT NULL,"
+ "`user_uuid` VARCHAR(40) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "plot_helpers` ("
+ "`plot_plot_id` INT(11) NOT NULL,"
+ "`user_uuid` VARCHAR(40) NOT NULL"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "plot_comments` ("
+ "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL,"
+ "`comment` VARCHAR(40) NOT NULL,"
+ "`inbox` VARCHAR(40) NOT NULL,"
+ "`timestamp` INT(11) NOT NULL,"
+ "`sender` VARCHAR(40) NOT NULL"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "plot_trusted` ("
+ "`plot_plot_id` INT(11) NOT NULL,"
+ "`user_uuid` VARCHAR(40) NOT NULL"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "plot_settings` ("
+ " `plot_plot_id` INT(11) NOT NULL,"
+ " `biome` VARCHAR(45) DEFAULT 'FOREST',"
+ " `rain` INT(1) DEFAULT 0,"
+ " `custom_time` TINYINT(1) DEFAULT '0',"
+ " `time` INT(11) DEFAULT '8000',"
+ " `deny_entry` TINYINT(1) DEFAULT '0',"
+ " `alias` VARCHAR(50) DEFAULT NULL,"
+ " `flags` VARCHAR(512) DEFAULT NULL,"
+ " `merged` INT(11) DEFAULT NULL,"
+ " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT',"
+ " PRIMARY KEY (`plot_plot_id`)"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "plot_rating` ( `plot_plot_id` INT(11) NOT NULL, `rating` INT(2) NOT NULL, `player` VARCHAR(40) NOT NULL) ENGINE=InnoDB "
+ "DEFAULT CHARSET=utf8");
if (addConstraint) {
stmt.addBatch("ALTER TABLE `"
+ this.prefix
+ "plot_settings` ADD CONSTRAINT `"
+ this.prefix
+ "plot_settings_ibfk_1` FOREIGN KEY (`plot_plot_id`) REFERENCES `"
+ this.prefix
+ "plot` (`id`) ON DELETE CASCADE");
}
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "cluster` ("
+ "`id` INT(11) NOT NULL AUTO_INCREMENT,"
+ "`pos1_x` INT(11) NOT NULL,"
+ "`pos1_z` INT(11) NOT NULL,"
+ "`pos2_x` INT(11) NOT NULL,"
+ "`pos2_z` INT(11) NOT NULL,"
+ "`owner` VARCHAR(40) NOT NULL,"
+ "`world` VARCHAR(45) NOT NULL,"
+ "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,"
+ "PRIMARY KEY (`id`)"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=0");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "cluster_helpers` ("
+ "`cluster_id` INT(11) NOT NULL,"
+ "`user_uuid` VARCHAR(40) NOT NULL"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "cluster_invited` ("
+ "`cluster_id` INT(11) NOT NULL,"
+ "`user_uuid` VARCHAR(40) NOT NULL"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "cluster_settings` ("
+ " `cluster_id` INT(11) NOT NULL,"
+ " `biome` VARCHAR(45) DEFAULT 'FOREST',"
+ " `rain` INT(1) DEFAULT 0,"
+ " `custom_time` TINYINT(1) DEFAULT '0',"
+ " `time` INT(11) DEFAULT '8000',"
+ " `deny_entry` TINYINT(1) DEFAULT '0',"
+ " `alias` VARCHAR(50) DEFAULT NULL,"
+ " `flags` VARCHAR(512) DEFAULT NULL,"
+ " `merged` INT(11) DEFAULT NULL,"
+ " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT',"
+ " PRIMARY KEY (`cluster_id`)"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "player_meta` ("
+ " `meta_id` INT(11) NOT NULL AUTO_INCREMENT,"
+ " `uuid` VARCHAR(40) NOT NULL,"
+ " `key` VARCHAR(32) NOT NULL,"
+ " `value` blob NOT NULL,"
+ " PRIMARY KEY (`meta_id`)"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8");
} else {
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "plot` ("
+ "`id` INTEGER PRIMARY KEY AUTOINCREMENT,"
+ "`plot_id_x` INT(11) NOT NULL,"
+ "`plot_id_z` INT(11) NOT NULL,"
+ "`owner` VARCHAR(45) NOT NULL,"
+ "`world` VARCHAR(45) NOT NULL,"
+ "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP)");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_denied` (`plot_plot_id` INT(11) NOT NULL,"
+ "`user_uuid` VARCHAR(40) NOT NULL)");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_helpers` (`plot_plot_id` INT(11) NOT NULL,"
+ "`user_uuid` VARCHAR(40) NOT NULL)");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_trusted` (`plot_plot_id` INT(11) NOT NULL,"
+ "`user_uuid` VARCHAR(40) NOT NULL)");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "plot_comments` ("
+ "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL,"
+ "`comment` VARCHAR(40) NOT NULL,"
+ "`inbox` VARCHAR(40) NOT NULL, `timestamp` INT(11) NOT NULL,"
+ "`sender` VARCHAR(40) NOT NULL"
+ ')');
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "plot_settings` ("
+ " `plot_plot_id` INT(11) NOT NULL,"
+ " `biome` VARCHAR(45) DEFAULT 'FOREST',"
+ " `rain` INT(1) DEFAULT 0,"
+ " `custom_time` TINYINT(1) DEFAULT '0',"
+ " `time` INT(11) DEFAULT '8000',"
+ " `deny_entry` TINYINT(1) DEFAULT '0',"
+ " `alias` VARCHAR(50) DEFAULT NULL,"
+ " `flags` VARCHAR(512) DEFAULT NULL,"
+ " `merged` INT(11) DEFAULT NULL,"
+ " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT',"
+ " PRIMARY KEY (`plot_plot_id`)"
+ ')');
stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix
+ "plot_rating` (`plot_plot_id` INT(11) NOT NULL, `rating` INT(2) NOT NULL, `player` VARCHAR(40) NOT NULL)");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "cluster` ("
+ "`id` INTEGER PRIMARY KEY AUTOINCREMENT,"
+ "`pos1_x` INT(11) NOT NULL,"
+ "`pos1_z` INT(11) NOT NULL,"
+ "`pos2_x` INT(11) NOT NULL,"
+ "`pos2_z` INT(11) NOT NULL,"
+ "`owner` VARCHAR(40) NOT NULL,"
+ "`world` VARCHAR(45) NOT NULL,"
+ "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP"
+ ')');
stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_helpers` (`cluster_id` INT(11) NOT NULL,"
+ "`user_uuid` VARCHAR(40) NOT NULL)");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_invited` (`cluster_id` INT(11) NOT NULL,"
+ "`user_uuid` VARCHAR(40) NOT NULL)");
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "cluster_settings` ("
+ " `cluster_id` INT(11) NOT NULL,"
+ " `biome` VARCHAR(45) DEFAULT 'FOREST',"
+ " `rain` INT(1) DEFAULT 0,"
+ " `custom_time` TINYINT(1) DEFAULT '0',"
+ " `time` INT(11) DEFAULT '8000',"
+ " `deny_entry` TINYINT(1) DEFAULT '0',"
+ " `alias` VARCHAR(50) DEFAULT NULL,"
+ " `flags` VARCHAR(512) DEFAULT NULL,"
+ " `merged` INT(11) DEFAULT NULL,"
+ " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT',"
+ " PRIMARY KEY (`cluster_id`)"
+ ')');
stmt.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "player_meta` ("
+ " `meta_id` INTEGER PRIMARY KEY AUTOINCREMENT,"
+ " `uuid` VARCHAR(40) NOT NULL,"
+ " `key` VARCHAR(32) NOT NULL,"
+ " `value` blob NOT NULL"
+ ')');
}
stmt.executeBatch();
stmt.clearBatch();
}
}
@Override
public void deleteSettings(final Plot plot) {
addPlotTask(plot, new UniqueStatement("delete_plot_settings") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, getId(plot));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot_settings` WHERE `plot_plot_id` = ?");
}
});
}
@Override
public void deleteHelpers(final Plot plot) {
if (plot.getTrusted().isEmpty()) {
return;
}
addPlotTask(plot, new UniqueStatement("delete_plot_helpers") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, getId(plot));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot_helpers` WHERE `plot_plot_id` = ?");
}
});
}
@Override
public void deleteTrusted(final Plot plot) {
if (plot.getMembers().isEmpty()) {
return;
}
addPlotTask(plot, new UniqueStatement("delete_plot_trusted") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, getId(plot));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot_trusted` WHERE `plot_plot_id` = ?");
}
});
}
@Override
public void deleteDenied(final Plot plot) {
if (plot.getDenied().isEmpty()) {
return;
}
addPlotTask(plot, new UniqueStatement("delete_plot_denied") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, getId(plot));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot_denied` WHERE `plot_plot_id` = ?");
}
});
}
@Override
public void deleteComments(final Plot plot) {
addPlotTask(plot, new UniqueStatement("delete_plot_comments") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setString(1, plot.getArea().toString());
stmt.setInt(2, plot.hashCode());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot_comments` WHERE `world` = ? AND `hashcode` = ?");
}
});
}
@Override
public void deleteRatings(final Plot plot) {
if (Settings.Enabled_Components.RATING_CACHE && plot.getSettings().getRatings().isEmpty()) {
return;
}
addPlotTask(plot, new UniqueStatement("delete_plot_ratings") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, getId(plot));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot_rating` WHERE `plot_plot_id` = ?");
}
});
}
/**
* Delete a plot.
*
* @param plot
*/
@Override
public void delete(final Plot plot) {
PS.debug("Deleting plot... Id: " + plot.getId() + " World: " + plot.getWorldName() + " Owner: " + plot.owner + " Index: " + plot.temp);
deleteSettings(plot);
deleteDenied(plot);
deleteHelpers(plot);
deleteTrusted(plot);
deleteComments(plot);
deleteRatings(plot);
addPlotTask(plot, new UniqueStatement("delete_plot") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, getId(plot));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot` WHERE `id` = ?");
}
});
}
/**
* Create plot settings
*
* @param id
* @param plot
*/
@Override
public void createPlotSettings(final int id, Plot plot) {
PS.debug("Creating plot... Id: " + plot.getId() + " World: " + plot.getWorldName() + " Owner: " + plot.owner + " Index: " + id);
addPlotTask(plot, new UniqueStatement("createPlotSettings") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, id);
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("INSERT INTO `" + SQLManager.this.prefix + "plot_settings`(`plot_plot_id`) VALUES(?)");
}
});
}
@Override
public int getClusterId(PlotCluster cluster) {
if (cluster.temp > 0) {
return cluster.temp;
}
try {
commit();
if (cluster.temp > 0) {
return cluster.temp;
}
int c_id;
try (PreparedStatement stmt = this.connection.prepareStatement("SELECT `id` FROM `"
+ this.prefix
+ "cluster` WHERE `pos1_x` = ? AND `pos1_z` = ? AND `pos2_x` = ? AND `pos2_z` = ? AND `world` = ? ORDER BY `timestamp` ASC")) {
stmt.setInt(1, cluster.getP1().x);
stmt.setInt(2, cluster.getP1().y);
stmt.setInt(3, cluster.getP2().x);
stmt.setInt(4, cluster.getP2().y);
stmt.setString(5, cluster.area.toString());
try (ResultSet resultSet = stmt.executeQuery()) {
c_id = Integer.MAX_VALUE;
while (resultSet.next()) {
c_id = resultSet.getInt("id");
}
}
}
if (c_id == Integer.MAX_VALUE || c_id == 0) {
if (cluster.temp > 0) {
return cluster.temp;
}
throw new SQLException("Cluster does not exist in database");
}
cluster.temp = c_id;
return c_id;
} catch (SQLException e) {
e.printStackTrace();
}
return Integer.MAX_VALUE;
}
@Override
public int getId(Plot plot) {
if (plot.temp > 0) {
return plot.temp;
}
try {
commit();
if (plot.temp > 0) {
return plot.temp;
}
int id;
try (PreparedStatement statement = this.connection.prepareStatement(
"SELECT `id` FROM `" + this.prefix + "plot` WHERE `plot_id_x` = ? AND `plot_id_z` = ? AND world = ? ORDER BY `timestamp` ASC")) {
statement.setInt(1, plot.getId().x);
statement.setInt(2, plot.getId().y);
statement.setString(3, plot.getArea().toString());
try (ResultSet resultSet = statement.executeQuery()) {
id = Integer.MAX_VALUE;
while (resultSet.next()) {
id = resultSet.getInt("id");
}
}
}
if (id == Integer.MAX_VALUE || id == 0) {
if (plot.temp > 0) {
return plot.temp;
}
throw new SQLException("Plot does not exist in database");
}
plot.temp = id;
return id;
} catch (SQLException e) {
e.printStackTrace();
}
return Integer.MAX_VALUE;
}
@Override public void updateTables(int[] oldVersion) {
try {
if (this.mySQL && !PS.get().checkVersion(oldVersion, 3, 3, 2)) {
try (Statement stmt = this.connection.createStatement()) {
stmt.executeUpdate("ALTER TABLE `" + this.prefix + "plots` DROP INDEX `unique_alias`");
} catch (SQLException ignored) {}
}
DatabaseMetaData data = this.connection.getMetaData();
ResultSet rs = data.getColumns(null, null, this.prefix + "plot_comments", "plot_plot_id");
if (rs.next()) {
rs.close();
rs = data.getColumns(null, null, this.prefix + "plot_comments", "hashcode");
if (!rs.next()) {
rs.close();
try (Statement statement = this.connection.createStatement()) {
statement.addBatch("DROP TABLE `" + this.prefix + "plot_comments`");
if (Storage.MySQL.USE) {
statement.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "plot_comments` ("
+ "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL,"
+ "`comment` VARCHAR(40) NOT NULL,"
+ "`inbox` VARCHAR(40) NOT NULL,"
+ "`timestamp` INT(11) NOT NULL,"
+ "`sender` VARCHAR(40) NOT NULL"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8");
} else {
statement.addBatch("CREATE TABLE IF NOT EXISTS `"
+ this.prefix
+ "plot_comments` ("
+ "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL,"
+ "`comment` VARCHAR(40) NOT NULL,"
+ "`inbox` VARCHAR(40) NOT NULL, `timestamp` INT(11) NOT NULL,"
+ "`sender` VARCHAR(40) NOT NULL"
+ ')');
}
statement.executeBatch();
} catch (SQLException ignored) {
try (Statement statement = this.connection.createStatement()) {
statement.addBatch("ALTER IGNORE TABLE `" + this.prefix + "plot_comments` ADD `inbox` VARCHAR(11) DEFAULT `public`");
statement.addBatch("ALTER IGNORE TABLE `" + this.prefix + "plot_comments` ADD `timestamp` INT(11) DEFAULT 0");
statement.addBatch("ALTER TABLE `" + this.prefix + "plot` DROP `tier`");
statement.executeBatch();
}
}
}
}
rs.close();
rs = data.getColumns(null, null, this.prefix + "plot_denied", "plot_plot_id");
if (rs.next()) {
try (Statement statement = this.connection.createStatement()) {
statement.executeUpdate(
"DELETE FROM `" + this.prefix + "plot_denied` WHERE `plot_plot_id` NOT IN (SELECT `id` FROM `" + this.prefix + "plot`)");
} catch (SQLException e) {
e.printStackTrace();
}
rs.close();
try (Statement statement = this.connection.createStatement()) {
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: " + this.prefix + table);
result.close();
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 " + this.prefix + table + "_tmp");
statement.executeUpdate("DROP TABLE " + this.prefix + table + "_tmp");
PS.debug("RESTORING: " + this.prefix + table);
}
}
} catch (SQLException e2) {
e2.printStackTrace();
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public void deleteRows(ArrayList<Integer> rowIds, final String table, final String column) {
setBulk(rowIds, new StmtMod<Integer>() {
@Override
public String getCreateMySQL(int size) {
return getCreateMySQL(1, "DELETE FROM `" + table + "` WHERE `" + column + "` IN ", size);
}
@Override
public String getCreateSQLite(int size) {
return getCreateMySQL(1, "DELETE FROM `" + table + "` WHERE `" + column + "` IN ", size);
}
@Override
public String getCreateSQL() {
return "DELETE FROM `" + table + "` WHERE `" + column + "` = ?";
}
@Override
public void setMySQL(PreparedStatement stmt, int i, Integer obj) throws SQLException {
stmt.setInt(i + 1, obj);
}
@Override
public void setSQLite(PreparedStatement stmt, int i, Integer obj) throws SQLException {
stmt.setInt(i + 1, obj);
}
@Override
public void setSQL(PreparedStatement stmt, Integer obj) throws SQLException {
stmt.setInt(1, obj);
}
}, null);
}
/**
* Load all plots, helpers, denied, trusted, and every setting from DB into a {@link HashMap}.
*/
@Override
public HashMap<String, HashMap<PlotId, Plot>> getPlots() {
HashMap<String, HashMap<PlotId, Plot>> newPlots = new HashMap<>();
HashMap<Integer, Plot> plots = new HashMap<>();
try {
HashSet<String> areas = new HashSet<>();
if (PS.get().worlds.contains("worlds")) {
ConfigurationSection worldSection = PS.get().worlds.getConfigurationSection("worlds");
if (worldSection != null) {
for (String worldKey : worldSection.getKeys(false)) {
areas.add(worldKey);
ConfigurationSection areaSection = worldSection.getConfigurationSection(worldKey + ".areas");
if (areaSection != null) {
for (String areaKey : areaSection.getKeys(false)) {
String[] split = areaKey.split("(?<![;])-");
if (split.length == 3) {
areas.add(worldKey + ';' + split[0]);
}
}
}
}
}
}
HashMap<String, UUID> uuids = new HashMap<>();
HashMap<String, AtomicInteger> noExist = new HashMap<>();
/*
* Getting plots
*/
try (Statement statement = this.connection.createStatement()) {
int id;
String o;
UUID user;
try (ResultSet resultSet = statement
.executeQuery("SELECT `id`, `plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp` FROM `" + this.prefix + "plot`")) {
ArrayList<Integer> toDelete = new ArrayList<>();
while (resultSet.next()) {
PlotId plot_id = new PlotId(resultSet.getInt("plot_id_x"), resultSet.getInt("plot_id_z"));
id = resultSet.getInt("id");
String areaid = resultSet.getString("world");
if (!areas.contains(areaid)) {
if (Settings.Enabled_Components.DATABASE_PURGER) {
toDelete.add(id);
continue;
} else {
AtomicInteger value = noExist.get(areaid);
if (value != null) {
value.incrementAndGet();
} else {
noExist.put(areaid, new AtomicInteger(1));
}
}
}
o = resultSet.getString("owner");
user = uuids.get(o);
if (user == null) {
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;
try {
Timestamp timestamp = resultSet.getTimestamp("timestamp");
time = timestamp.getTime();
} catch (SQLException exception) {
String parsable = resultSet.getString("timestamp");
try {
time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(parsable).getTime();
} catch (ParseException e) {
PS.debug("Could not parse date for plot: #" + id + "(" + areaid + ";" + plot_id + ") (" + parsable + ")");
time = System.currentTimeMillis() + id;
}
}
Plot p = new Plot(plot_id, user, new HashSet<UUID>(), new HashSet<UUID>(), new HashSet<UUID>(), "", null, null, null, new boolean[]{false, false, false, false}, time, id);
HashMap<PlotId, Plot> map = newPlots.get(areaid);
if (map != null) {
Plot last = map.put(p.getId(), p);
if (last != null) {
if (Settings.Enabled_Components.DATABASE_PURGER) {
toDelete.add(last.temp);
} else {
PS.debug("&cPLOT #" + id + "(" + last + ") in `" + this.prefix
+ "plot` is a duplicate. Delete this plot or set `database-purger: true` in the settings.yml.");
}
}
} else {
map = new HashMap<>();
newPlots.put(areaid, map);
map.put(p.getId(), p);
}
plots.put(id, p);
}
deleteRows(toDelete, this.prefix + "plot", "id");
}
if (Settings.Enabled_Components.RATING_CACHE) {
try (ResultSet r = statement.executeQuery("SELECT `plot_plot_id`, `player`, `rating` FROM `" + this.prefix + "plot_rating`")) {
ArrayList<Integer> toDelete = new ArrayList<>();
while (r.next()) {
id = r.getInt("plot_plot_id");
o = r.getString("player");
user = uuids.get(o);
if (user == null) {
user = UUID.fromString(o);
uuids.put(o, user);
}
Plot plot = plots.get(id);
if (plot != null) {
plot.getSettings().getRatings().put(user, r.getInt("rating"));
} else if (Settings.Enabled_Components.DATABASE_PURGER) {
toDelete.add(id);
} else {
PS.debug("&cENTRY #" + id + "(" + plot + ") in `plot_rating` does not exist. Create this plot or set `database-purger: true` in the "
+ "settings.yml.");
}
}
deleteRows(toDelete, this.prefix + "plot_rating", "plot_plot_id");
}
}
/*
* Getting helpers
*/
try (ResultSet r = statement.executeQuery("SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_helpers`")) {
ArrayList<Integer> toDelete = new ArrayList<>();
while (r.next()) {
id = r.getInt("plot_plot_id");
o = r.getString("user_uuid");
user = uuids.get(o);
if (user == null) {
user = UUID.fromString(o);
uuids.put(o, user);
}
Plot plot = plots.get(id);
if (plot != null) {
plot.getTrusted().add(user);
} else if (Settings.Enabled_Components.DATABASE_PURGER) {
toDelete.add(id);
} else {
PS.debug("&cENTRY #" + id + "(" + plot + ") in `plot_helpers` does not exist. Create this plot or set `database-purger: true` in the settings"
+ ".yml.");
}
}
deleteRows(toDelete, this.prefix + "plot_helpers", "plot_plot_id");
}
/*
* Getting trusted
*/
try (ResultSet r = statement.executeQuery("SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_trusted`")) {
ArrayList<Integer> toDelete = new ArrayList<>();
while (r.next()) {
id = r.getInt("plot_plot_id");
o = r.getString("user_uuid");
user = uuids.get(o);
if (user == null) {
user = UUID.fromString(o);
uuids.put(o, user);
}
Plot plot = plots.get(id);
if (plot != null) {
plot.getMembers().add(user);
} else if (Settings.Enabled_Components.DATABASE_PURGER) {
toDelete.add(id);
} else {
PS.debug("&cENTRY #" + id + "(" + plot + ") in `plot_trusted` does not exist. Create this plot or set `database-purger: true` in the settings"
+ ".yml.");
}
}
deleteRows(toDelete, this.prefix + "plot_trusted", "plot_plot_id");
}
/*
* Getting denied
*/
try (ResultSet r = statement.executeQuery("SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_denied`")) {
ArrayList<Integer> toDelete = new ArrayList<>();
while (r.next()) {
id = r.getInt("plot_plot_id");
o = r.getString("user_uuid");
user = uuids.get(o);
if (user == null) {
user = UUID.fromString(o);
uuids.put(o, user);
}
Plot plot = plots.get(id);
if (plot != null) {
plot.getDenied().add(user);
} else if (Settings.Enabled_Components.DATABASE_PURGER) {
toDelete.add(id);
} else {
PS.debug("&cENTRY " + id
+ " in `plot_denied` does not exist. Create this plot or set `database-purger: true` in the settings.yml.");
}
}
deleteRows(toDelete, this.prefix + "plot_denied", "plot_plot_id");
}
try (ResultSet resultSet = statement.executeQuery("SELECT * FROM `" + this.prefix + "plot_settings`")) {
ArrayList<Integer> toDelete = new ArrayList<>();
while (resultSet.next()) {
id = resultSet.getInt("plot_plot_id");
Plot plot = plots.get(id);
if (plot != null) {
plots.remove(id);
String alias = resultSet.getString("alias");
if (alias != null) {
plot.getSettings().setAlias(alias);
}
String pos = resultSet.getString("position");
switch (pos.toLowerCase()) {
case "":
case "default":
case "0,0,0":
case "center":
break;
default:
try {
plot.getSettings().setPosition(BlockLoc.fromString(pos));
} catch (Exception ignored) {}
}
Integer m = resultSet.getInt("merged");
boolean[] merged = new boolean[4];
for (int i = 0; i < 4; i++) {
merged[3 - i] = (m & 1 << i) != 0;
}
plot.getSettings().setMerged(merged);
String[] flags_string;
String myflags = resultSet.getString("flags");
if (myflags == null || myflags.isEmpty()) {
flags_string = new String[]{};
} else {
flags_string = myflags.split(",");
}
HashMap<Flag<?>, Object> flags = new HashMap<>();
boolean exception = false;
for (String element : flags_string) {
if (element.contains(":")) {
String[] split = element.split(":");
try {
String flag_str = split[1].replaceAll("¯", ":").replaceAll("\u00B4", ",");
Flag<?> flag = FlagManager.getOrCreateFlag(split[0]);
flags.put(flag, flag.parseValue(flag_str));
} catch (Exception e) {
e.printStackTrace();
exception = true;
}
} else {
element = element.replaceAll("\u00AF", ":").replaceAll("\u00B4", ",");
if (StringMan.isAlpha(element.replaceAll("_", "").replaceAll("-", ""))) {
Flag flag = FlagManager.getOrCreateFlag(element);
if (flag == null) {
flag = new StringFlag(element) {
@Override public String getValueDescription() {
return "Generic Filler Flag";
}
};
}
flags.put(flag, flag.parseValue(""));
} else {
PS.debug("INVALID FLAG: " + element);
}
}
}
if (exception) {
PS.debug("&cPlot #" + id + "(" + plot + ") | " + plot + " had an invalid flag. A fix has been attempted.");
PS.debug("&c" + myflags);
this.setFlags(plot, flags);
}
plot.getSettings().flags = flags;
} else if (Settings.Enabled_Components.DATABASE_PURGER) {
toDelete.add(id);
} else {
PS.debug(
"&cENTRY #" + id + "(" + plot + ") in `plot_settings` does not exist. Create this plot or set `database-purger: true` in the settings"
+ ".yml.");
}
}
deleteRows(toDelete, this.prefix + "plot_settings", "plot_plot_id");
}
}
if (!plots.entrySet().isEmpty()) {
createEmptySettings(new ArrayList<>(plots.keySet()), null);
for (Entry<Integer, Plot> entry : plots.entrySet()) {
entry.getValue().getSettings();
}
}
boolean invalidPlot = false;
for (Entry<String, AtomicInteger> entry : noExist.entrySet()) {
String worldName = entry.getKey();
invalidPlot = true;
PS.debug("&c[WARNING] Found " + entry.getValue().intValue() + " plots in DB for non existent world; '" + worldName + "'.");
}
if (invalidPlot) {
PS.debug("&c[WARNING] - Please create the world/s or remove the plots using the purge command");
}
} catch (SQLException e) {
PS.debug("&7[WARN] Failed to load plots.");
e.printStackTrace();
}
return newPlots;
}
@Override
public void setMerged(final Plot plot, final boolean[] merged) {
plot.getSettings().setMerged(merged);
addPlotTask(plot, new UniqueStatement("setMerged") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
int hash = MainUtil.hash(merged);
stmt.setInt(1, hash);
stmt.setInt(2, getId(plot));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("UPDATE `" + SQLManager.this.prefix + "plot_settings` SET `merged` = ? WHERE `plot_plot_id` = ?");
}
});
}
@Override
public void swapPlots(Plot plot1, Plot plot2) {
final int id1 = getId(plot1);
final int id2 = getId(plot2);
final PlotId pos1 = plot1.getId();
final PlotId pos2 = plot2.getId();
addPlotTask(plot1, new UniqueStatement("swapPlots") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, pos2.x);
stmt.setInt(2, pos2.y);
stmt.setInt(3, id1);
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("UPDATE `" + SQLManager.this.prefix + "plot` SET `plot_id_x` = ?, `plot_id_z` = ? WHERE `id` = ?");
}
});
addPlotTask(plot2, new UniqueStatement("swapPlots") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, pos1.x);
stmt.setInt(2, pos1.y);
stmt.setInt(3, id2);
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("UPDATE `" + SQLManager.this.prefix + "plot` SET `plot_id_x` = ?, `plot_id_z` = ? WHERE `id` = ?");
}
});
}
@Override
public void movePlot(final Plot original, final Plot newPlot) {
addPlotTask(original, new UniqueStatement("movePlot") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, newPlot.getId().x);
stmt.setInt(2, newPlot.getId().y);
stmt.setString(3, newPlot.getArea().toString());
stmt.setInt(4, getId(original));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection.prepareStatement(
"UPDATE `" + SQLManager.this.prefix + "plot` SET `plot_id_x` = ?, `plot_id_z` = ?, `world` = ? WHERE `id` = ?");
}
});
addPlotTask(newPlot, null);
}
@Override
public void setFlags(final Plot plot, HashMap<Flag<?>, Object> flags) {
final String flag_string = FlagManager.toString(flags);
addPlotTask(plot, new UniqueStatement("setFlags") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setString(1, flag_string);
stmt.setInt(2, getId(plot));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("UPDATE `" + SQLManager.this.prefix + "plot_settings` SET `flags` = ? WHERE `plot_plot_id` = ?");
}
});
}
@Override
public void setAlias(final Plot plot, final String alias) {
addPlotTask(plot, new UniqueStatement("setAlias") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setString(1, alias);
stmt.setInt(2, getId(plot));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("UPDATE `" + SQLManager.this.prefix + "plot_settings` SET `alias` = ? WHERE `plot_plot_id` = ?");
}
});
}
/**
* Purge all plots with the following database IDs
*/
@Override
public void purgeIds(final Set<Integer> uniqueIds) {
addGlobalTask(new Runnable() {
@Override
public void run() {
if (!uniqueIds.isEmpty()) {
try {
ArrayList<Integer> uniqueIdsList = new ArrayList<Integer>(uniqueIds);
String stmt_prefix = "";
int size = uniqueIdsList.size();
int packet = 990;
int amount = size / packet;
int count = 0;
int last = -1;
for (int j = 0; j <= amount; j++) {
PS.debug("Purging " + (j * packet) + " / " + size);
List<Integer> subList = uniqueIdsList.subList(j * packet, Math.min(size, (j + 1) * packet));
if (subList.isEmpty()) {
break;
}
StringBuilder idstr2 = new StringBuilder("");
stmt_prefix = "";
for (Integer id : subList) {
idstr2.append(stmt_prefix).append(id);
stmt_prefix = " OR `id` = ";
}
stmt_prefix = "";
StringBuilder idstr = new StringBuilder();
for (Integer id : subList) {
idstr.append(stmt_prefix).append(id);
stmt_prefix = " OR `plot_plot_id` = ";
}
PreparedStatement stmt = SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot_helpers` WHERE `plot_plot_id` = " + idstr);
stmt.executeUpdate();
stmt.close();
stmt = SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot_denied` WHERE `plot_plot_id` = " + idstr);
stmt.executeUpdate();
stmt.close();
stmt = SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot_settings` WHERE `plot_plot_id` = " + idstr);
stmt.executeUpdate();
stmt.close();
stmt = SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot_trusted` WHERE `plot_plot_id` = " + idstr);
stmt.executeUpdate();
stmt.close();
stmt = SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot` WHERE `id` = " + idstr2);
stmt.executeUpdate();
stmt.close();
commit();
}
} catch (SQLException e) {
e.printStackTrace();
PS.debug("&c[ERROR] FAILED TO PURGE PLOTS!");
return;
}
}
PS.debug("&6[INFO] SUCCESSFULLY PURGED " + uniqueIds.size() + " PLOTS!");
}
});
}
@Override
public void purge(final PlotArea area, final Set<PlotId> plots) {
addGlobalTask(new Runnable() {
@Override
public void run() {
try (PreparedStatement stmt = SQLManager.this.connection
.prepareStatement("SELECT `id`, `plot_id_x`, `plot_id_z` FROM `" + SQLManager.this.prefix + "plot` WHERE `world` = ?")) {
stmt.setString(1, area.toString());
Set<Integer> ids;
try (ResultSet r = stmt.executeQuery()) {
ids = new HashSet<>();
while (r.next()) {
PlotId plot_id = new PlotId(r.getInt("plot_id_x"), r.getInt("plot_id_z"));
if (plots.contains(plot_id)) {
ids.add(r.getInt("id"));
}
}
}
purgeIds(ids);
} catch (SQLException e) {
e.printStackTrace();
PS.debug("&c[ERROR] FAILED TO PURGE AREA '" + area + "'!");
}
for (Iterator<PlotId> iterator = plots.iterator(); iterator.hasNext(); ) {
PlotId plotId = iterator.next();
iterator.remove();
PlotId id = new PlotId(plotId.x, plotId.y);
area.removePlot(id);
}
}
});
}
@Override
public void setPosition(final Plot plot, final String position) {
addPlotTask(plot, new UniqueStatement("setPosition") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setString(1, position == null ? "" : position);
stmt.setInt(2, getId(plot));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("UPDATE `" + SQLManager.this.prefix + "plot_settings` SET `position` = ? WHERE `plot_plot_id` = ?");
}
});
}
@Override
public void removeComment(final Plot plot, final PlotComment comment) {
addPlotTask(plot, new UniqueStatement("removeComment") {
@Override
public void set(PreparedStatement statement) throws SQLException {
if (plot != null) {
statement.setString(1, plot.getArea().toString());
statement.setInt(2, plot.getId().hashCode());
statement.setString(3, comment.comment);
statement.setString(4, comment.inbox);
statement.setString(5, comment.senderName);
} else {
statement.setString(1, comment.comment);
statement.setString(2, comment.inbox);
statement.setString(3, comment.senderName);
}
}
@Override
public PreparedStatement get() throws SQLException {
if (plot != null) {
return SQLManager.this.connection.prepareStatement("DELETE FROM `" + SQLManager.this.prefix
+ "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `comment` = ? AND `inbox` = ? AND `sender` = ?");
}
return SQLManager.this.connection.prepareStatement(
"DELETE FROM `" + SQLManager.this.prefix + "plot_comments` WHERE `comment` = ? AND `inbox` = ? AND `sender` = ?");
}
});
}
@Override
public void clearInbox(final Plot plot, final String inbox) {
addPlotTask(plot, new UniqueStatement("clearInbox") {
@Override
public void set(PreparedStatement statement) throws SQLException {
if (plot != null) {
statement.setString(1, plot.getArea().toString());
statement.setInt(2, plot.getId().hashCode());
statement.setString(3, inbox);
} else {
statement.setString(1, inbox);
}
}
@Override
public PreparedStatement get() throws SQLException {
if (plot != null) {
return SQLManager.this.connection.prepareStatement(
"DELETE FROM `" + SQLManager.this.prefix + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `inbox` = ?");
}
return SQLManager.this.connection.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot_comments` `inbox` = ?");
}
});
}
@Override
public void getComments(final Plot plot, final String inbox, final RunnableVal<List<PlotComment>> whenDone) {
addPlotTask(plot, new UniqueStatement("getComments_" + plot) {
@Override
public void set(PreparedStatement statement) throws SQLException {
if (plot != null) {
statement.setString(1, plot.getArea().toString());
statement.setInt(2, plot.getId().hashCode());
statement.setString(3, inbox);
} else {
statement.setString(1, inbox);
}
}
@Override
public PreparedStatement get() throws SQLException {
if (plot != null) {
return SQLManager.this.connection.prepareStatement(
"SELECT * FROM `" + SQLManager.this.prefix + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `inbox` = ?");
}
return SQLManager.this.connection.prepareStatement("SELECT * FROM `" + SQLManager.this.prefix + "plot_comments` WHERE `inbox` = ?");
}
@Override
public void execute(PreparedStatement statement) {}
@Override
public void addBatch(PreparedStatement statement) throws SQLException {
ArrayList<PlotComment> comments = new ArrayList<>();
try (ResultSet set = statement.executeQuery()) {
while (set.next()) {
String sender = set.getString("sender");
String world = set.getString("world");
int hash = set.getInt("hashcode");
PlotId id;
if (hash != 0) {
id = PlotId.unpair(hash);
} else {
id = null;
}
String msg = set.getString("comment");
long timestamp = set.getInt("timestamp") * 1000;
PlotComment comment = new PlotComment(world, id, msg, sender, inbox, timestamp);
comments.add(comment);
whenDone.value = comments;
}
}
TaskManager.runTask(whenDone);
}
});
}
@Override
public void setComment(final Plot plot, final PlotComment comment) {
addPlotTask(plot, new UniqueStatement("setComment") {
@Override
public void set(PreparedStatement statement) throws SQLException {
statement.setString(1, plot.getArea().toString());
statement.setInt(2, plot.getId().hashCode());
statement.setString(3, comment.comment);
statement.setString(4, comment.inbox);
statement.setInt(5, (int) (comment.timestamp / 1000));
statement.setString(6, comment.senderName);
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection.prepareStatement("INSERT INTO `" + SQLManager.this.prefix
+ "plot_comments` (`world`, `hashcode`, `comment`, `inbox`, `timestamp`, `sender`) VALUES(?,?,?,?,?,?)");
}
});
}
@Override
public void removeTrusted(final Plot plot, final UUID uuid) {
addPlotTask(plot, new UniqueStatement("removeTrusted") {
@Override
public void set(PreparedStatement statement) throws SQLException {
statement.setInt(1, getId(plot));
statement.setString(2, uuid.toString());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot_helpers` WHERE `plot_plot_id` = ? AND `user_uuid` = ?");
}
});
}
@Override
public void removeMember(final Plot plot, final UUID uuid) {
addPlotTask(plot, new UniqueStatement("removeMember") {
@Override
public void set(PreparedStatement statement) throws SQLException {
statement.setInt(1, getId(plot));
statement.setString(2, uuid.toString());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot_trusted` WHERE `plot_plot_id` = ? AND `user_uuid` = ?");
}
});
}
@Override
public void setTrusted(final Plot plot, final UUID uuid) {
addPlotTask(plot, new UniqueStatement("setTrusted") {
@Override
public void set(PreparedStatement statement) throws SQLException {
statement.setInt(1, getId(plot));
statement.setString(2, uuid.toString());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("INSERT INTO `" + SQLManager.this.prefix + "plot_helpers` (`plot_plot_id`, `user_uuid`) VALUES(?,?)");
}
});
}
@Override
public void setMember(final Plot plot, final UUID uuid) {
addPlotTask(plot, new UniqueStatement("setMember") {
@Override
public void set(PreparedStatement statement) throws SQLException {
statement.setInt(1, getId(plot));
statement.setString(2, uuid.toString());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("INSERT INTO `" + SQLManager.this.prefix + "plot_trusted` (`plot_plot_id`, `user_uuid`) VALUES(?,?)");
}
});
}
@Override
public void removeDenied(final Plot plot, final UUID uuid) {
addPlotTask(plot, new UniqueStatement("removeDenied") {
@Override
public void set(PreparedStatement statement) throws SQLException {
statement.setInt(1, getId(plot));
statement.setString(2, uuid.toString());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "plot_denied` WHERE `plot_plot_id` = ? AND `user_uuid` = ?");
}
});
}
@Override
public void setDenied(final Plot plot, final UUID uuid) {
addPlotTask(plot, new UniqueStatement("setDenied") {
@Override
public void set(PreparedStatement statement) throws SQLException {
statement.setInt(1, getId(plot));
statement.setString(2, uuid.toString());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("INSERT INTO `" + SQLManager.this.prefix + "plot_denied` (`plot_plot_id`, `user_uuid`) VALUES(?,?)");
}
});
}
@Override
public HashMap<UUID, Integer> getRatings(Plot plot) {
HashMap<UUID, Integer> map = new HashMap<>();
try (PreparedStatement statement = this.connection
.prepareStatement("SELECT `rating`, `player` FROM `" + this.prefix + "plot_rating` WHERE `plot_plot_id` = ? ")) {
statement.setInt(1, getId(plot));
try (ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
UUID uuid = UUID.fromString(resultSet.getString("player"));
int rating = resultSet.getInt("rating");
map.put(uuid, rating);
}
}
} catch (SQLException e) {
PS.debug("&7[WARN] Failed to fetch rating for plot " + plot.getId().toString());
e.printStackTrace();
}
return map;
}
@Override
public void setRating(final Plot plot, final UUID rater, final int value) {
addPlotTask(plot, new UniqueStatement("setRating") {
@Override
public void set(PreparedStatement statement) throws SQLException {
statement.setInt(1, getId(plot));
statement.setInt(2, value);
statement.setString(3, rater.toString());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection.prepareStatement(
"INSERT INTO `" + SQLManager.this.prefix + "plot_rating` (`plot_plot_id`, `rating`, `player`) VALUES(?,?,?)");
}
});
}
@Override
public void delete(PlotCluster cluster) {
final int id = getClusterId(cluster);
addClusterTask(cluster, new UniqueStatement("delete_cluster_settings") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, id);
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "cluster_settings` WHERE `cluster_id` = ?");
}
});
addClusterTask(cluster, new UniqueStatement("delete_cluster_helpers") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, id);
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "cluster_helpers` WHERE `cluster_id` = ?");
}
});
addClusterTask(cluster, new UniqueStatement("delete_cluster_invited") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, id);
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "cluster_invited` WHERE `cluster_id` = ?");
}
});
addClusterTask(cluster, new UniqueStatement("delete_cluster") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, id);
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "cluster` WHERE `id` = ?");
}
});
}
@Override
public void addPersistentMeta(final UUID uuid, final String key, final byte[] meta, final boolean replace) {
addPlayerTask(uuid, new UniqueStatement("addPersistentMeta") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
if (replace) {
stmt.setBytes(1, meta);
stmt.setString(2, uuid.toString());
stmt.setString(3, key);
} else {
stmt.setString(1, uuid.toString());
stmt.setString(2, key);
stmt.setBytes(3, meta);
}
}
@Override
public PreparedStatement get() throws SQLException {
if (replace) {
return SQLManager.this.connection
.prepareStatement("UPDATE `" + SQLManager.this.prefix + "player_meta` SET `value` = ? WHERE `uuid` = ? AND `key` = ?");
} else {
return SQLManager.this.connection
.prepareStatement("INSERT INTO `" + SQLManager.this.prefix + "player_meta`(`uuid`, `key`, `value`) VALUES(?, ? ,?)");
}
}
});
}
@Override
public void removePersistentMeta(final UUID uuid, final String key) {
addPlayerTask(uuid, new UniqueStatement("removePersistentMeta") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setString(1, uuid.toString());
stmt.setString(2, key);
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "player_meta` WHERE `uuid` = ? AND `key` = ?");
}
});
}
@Override
public void getPersistentMeta(final UUID uuid, final RunnableVal<Map<String, byte[]>> result) {
addPlayerTask(uuid, new UniqueStatement("getPersistentMeta") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setString(1, uuid.toString());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection.prepareStatement("SELECT * FROM `" + SQLManager.this.prefix + "player_meta` WHERE `uuid` = ?");
}
@Override
public void execute(PreparedStatement statement) {}
@Override
public void addBatch(PreparedStatement statement) throws SQLException {
ResultSet resultSet = statement.executeQuery();
Map<String, byte[]> metaMap = new HashMap<>();
while (resultSet.next()) {
String key = resultSet.getString("key");
byte[] bytes = resultSet.getBytes("value");
metaMap.put(key, bytes);
}
resultSet.close();
result.run(metaMap);
}
});
}
@Override
public HashMap<String, Set<PlotCluster>> getClusters() {
LinkedHashMap<String, Set<PlotCluster>> newClusters = new LinkedHashMap<>();
HashMap<Integer, PlotCluster> clusters = new HashMap<>();
try {
HashSet<String> areas = new HashSet<>();
if (PS.get().worlds.contains("worlds")) {
ConfigurationSection worldSection = PS.get().worlds.getConfigurationSection("worlds");
if (worldSection != null) {
for (String worldKey : worldSection.getKeys(false)) {
areas.add(worldKey);
ConfigurationSection areaSection = worldSection.getConfigurationSection(worldKey + ".areas");
if (areaSection != null) {
for (String areaKey : areaSection.getKeys(false)) {
String[] split = areaKey.split("(?<![;])-");
if (split.length == 3) {
areas.add(worldKey + ';' + split[0]);
}
}
}
}
}
}
HashMap<String, UUID> uuids = new HashMap<>();
HashMap<String, Integer> noExist = new HashMap<>();
/*
* Getting clusters
*/
try (Statement stmt = this.connection.createStatement()) {
ResultSet resultSet = stmt.executeQuery("SELECT * FROM `" + this.prefix + "cluster`");
PlotCluster cluster;
String owner;
UUID user;
int id;
while (resultSet.next()) {
PlotId pos1 = new PlotId(resultSet.getInt("pos1_x"), resultSet.getInt("pos1_z"));
PlotId pos2 = new PlotId(resultSet.getInt("pos2_x"), resultSet.getInt("pos2_z"));
id = resultSet.getInt("id");
String areaid = resultSet.getString("world");
if (!areas.contains(areaid)) {
if (noExist.containsKey(areaid)) {
noExist.put(areaid, noExist.get(areaid) + 1);
} else {
noExist.put(areaid, 1);
}
}
owner = resultSet.getString("owner");
user = uuids.get(owner);
if (user == null) {
user = UUID.fromString(owner);
uuids.put(owner, user);
}
cluster = new PlotCluster(null, pos1, pos2, user, id);
clusters.put(id, cluster);
Set<PlotCluster> set = newClusters.get(areaid);
if (set == null) {
set = new HashSet<>();
newClusters.put(areaid, set);
}
set.add(cluster);
}
//Getting helpers
resultSet = stmt.executeQuery("SELECT `user_uuid`, `cluster_id` FROM `" + this.prefix + "cluster_helpers`");
while (resultSet.next()) {
id = resultSet.getInt("cluster_id");
owner = resultSet.getString("user_uuid");
user = uuids.get(owner);
if (user == null) {
user = UUID.fromString(owner);
uuids.put(owner, user);
}
cluster = clusters.get(id);
if (cluster != null) {
cluster.helpers.add(user);
} else {
PS.debug("&cCluster #" + id + "(" + cluster + ") in cluster_helpers does not exist. Please create the cluster or remove this entry.");
}
}
// Getting invited
resultSet = stmt.executeQuery("SELECT `user_uuid`, `cluster_id` FROM `" + this.prefix + "cluster_invited`");
while (resultSet.next()) {
id = resultSet.getInt("cluster_id");
owner = resultSet.getString("user_uuid");
user = uuids.get(owner);
if (user == null) {
user = UUID.fromString(owner);
uuids.put(owner, user);
}
cluster = clusters.get(id);
if (cluster != null) {
cluster.invited.add(user);
} else {
PS.debug("&cCluster #" + id + "(" + cluster + ") in cluster_invited does not exist. Please create the cluster or remove this entry.");
}
}
resultSet = stmt.executeQuery("SELECT * FROM `" + this.prefix + "cluster_settings`");
while (resultSet.next()) {
id = resultSet.getInt("cluster_id");
cluster = clusters.get(id);
if (cluster != null) {
String alias = resultSet.getString("alias");
if (alias != null) {
cluster.settings.setAlias(alias);
}
String pos = resultSet.getString("position");
switch (pos.toLowerCase()) {
case "":
case "default":
case "0,0,0":
case "center":
break;
default:
try {
BlockLoc loc = BlockLoc.fromString(pos);
cluster.settings.setPosition(loc);
} catch (Exception ignored) {}
}
Integer m = resultSet.getInt("merged");
boolean[] merged = new boolean[4];
for (int i = 0; i < 4; i++) {
merged[3 - i] = (m & 1 << i) != 0;
}
cluster.settings.setMerged(merged);
String[] flags_string;
String myflags = resultSet.getString("flags");
if (myflags == null || myflags.isEmpty()) {
flags_string = new String[]{};
} else {
flags_string = myflags.split(",");
}
HashMap<Flag<?>, Object> flags = new HashMap<>();
for (String element : flags_string) {
if (element.contains(":")) {
String[] split = element.split(":");
String flag_str = split[1].replaceAll("\u00AF", ":").replaceAll("´", ",");
Flag flag = FlagManager.getOrCreateFlag(split[0]);
if (flag == null) {
flag = new StringFlag(split[0]) {
@Override public String getValueDescription() {
return "Generic Filler Flag";
}
};
}
flags.put(flag, flag.parseValue(flag_str));
} else {
Flag flag = FlagManager.getOrCreateFlag(element);
if (flag == null) {
flag = new StringFlag(element) {
@Override public String getValueDescription() {
return "Generic Filler Flag";
}
};
}
flags.put(flag, flag.parseValue(""));
}
}
cluster.settings.flags = flags;
} else {
PS.debug("&cCluster #" + id + "(" + cluster + ") in cluster_settings does not exist. Please create the cluster or remove this entry.");
}
}
resultSet.close();
}
boolean invalidPlot = false;
for (Entry<String, Integer> entry : noExist.entrySet()) {
String a = entry.getKey();
invalidPlot = true;
PS.debug("&c[WARNING] Found " + noExist.get(a) + " clusters in DB for non existent area; '" + a + "'.");
}
if (invalidPlot) {
PS.debug("&c[WARNING] - Please create the world/s or remove the clusters using the purge command");
}
} catch (SQLException e) {
PS.debug("&7[WARN] Failed to load clusters.");
e.printStackTrace();
}
return newClusters;
}
@Override
public void setFlags(final PlotCluster cluster, HashMap<Flag<?>, Object> flags) {
final StringBuilder flag_string = new StringBuilder();
int i = 0;
for (Entry<Flag<?>, Object> flag : flags.entrySet()) {
if (i != 0) {
flag_string.append(',');
}
flag_string.append(flag.getKey().getName()).append(':')
.append(flag.getKey().valueToString(flag.getValue()).replaceAll(":", "\u00AF").replaceAll(",", "´"));
i++;
}
addClusterTask(cluster, new UniqueStatement("setFlags") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setString(1, flag_string.toString());
stmt.setInt(2, getClusterId(cluster));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("UPDATE `" + SQLManager.this.prefix + "cluster_settings` SET `flags` = ? WHERE `cluster_id` = ?");
}
});
}
@Override
public void setClusterName(final PlotCluster cluster, final String name) {
addClusterTask(cluster, new UniqueStatement("setClusterName") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setString(1, name);
stmt.setInt(2, getClusterId(cluster));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("UPDATE `" + SQLManager.this.prefix + "cluster_settings` SET `alias` = ? WHERE `cluster_id` = ?");
}
});
cluster.settings.setAlias(name);
}
@Override
public void removeHelper(final PlotCluster cluster, final UUID uuid) {
addClusterTask(cluster, new UniqueStatement("removeHelper") {
@Override
public void set(PreparedStatement statement) throws SQLException {
statement.setInt(1, getClusterId(cluster));
statement.setString(2, uuid.toString());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "cluster_helpers` WHERE `cluster_id` = ? AND `user_uuid` = ?");
}
});
}
@Override
public void setHelper(final PlotCluster cluster, final UUID uuid) {
addClusterTask(cluster, new UniqueStatement("setHelper") {
@Override
public void set(PreparedStatement statement) throws SQLException {
statement.setInt(1, getClusterId(cluster));
statement.setString(2, uuid.toString());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("INSERT INTO `" + SQLManager.this.prefix + "cluster_helpers` (`cluster_id`, `user_uuid`) VALUES(?,?)");
}
});
}
@Override
public void createCluster(final PlotCluster cluster) {
addClusterTask(cluster, new UniqueStatement("createCluster_" + cluster.hashCode()) {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, cluster.getP1().x);
stmt.setInt(2, cluster.getP1().y);
stmt.setInt(3, cluster.getP2().x);
stmt.setInt(4, cluster.getP2().y);
stmt.setString(5, cluster.owner.toString());
stmt.setString(6, cluster.area.toString());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection.prepareStatement(SQLManager.this.CREATE_CLUSTER, Statement.RETURN_GENERATED_KEYS);
}
@Override
public void execute(PreparedStatement statement) {}
@Override
public void addBatch(PreparedStatement statement) throws SQLException {
statement.executeUpdate();
try (ResultSet keys = statement.getGeneratedKeys()) {
if (keys.next()) {
cluster.temp = keys.getInt(1);
}
}
}
});
addClusterTask(cluster, new UniqueStatement("createCluster_settings_" + cluster.hashCode()) {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, getClusterId(cluster));
stmt.setString(2, cluster.settings.getAlias());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("INSERT INTO `" + SQLManager.this.prefix + "cluster_settings`(`cluster_id`, `alias`) VALUES(?, ?)");
}
});
}
@Override
public void resizeCluster(final PlotCluster current, PlotId min, PlotId max) {
final PlotId pos1 = new PlotId(current.getP1().x, current.getP1().y);
final PlotId pos2 = new PlotId(current.getP2().x, current.getP2().y);
current.setP1(min);
current.setP2(max);
addClusterTask(current, new UniqueStatement("resizeCluster") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setInt(1, pos1.x);
stmt.setInt(2, pos1.y);
stmt.setInt(3, pos2.x);
stmt.setInt(4, pos2.y);
stmt.setInt(5, getClusterId(current));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection.prepareStatement(
"UPDATE `" + SQLManager.this.prefix + "cluster` SET `pos1_x` = ?, `pos1_z` = ?, `pos2_x` = ?, `pos2_z` = ? WHERE `id` = ?");
}
});
}
@Override
public void setPosition(final PlotCluster cluster, final String position) {
addClusterTask(cluster, new UniqueStatement("setPosition") {
@Override
public void set(PreparedStatement stmt) throws SQLException {
stmt.setString(1, position);
stmt.setInt(2, getClusterId(cluster));
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("UPDATE `" + SQLManager.this.prefix + "cluster_settings` SET `position` = ? WHERE `cluster_id` = ?");
}
});
}
@Override
public void removeInvited(final PlotCluster cluster, final UUID uuid) {
addClusterTask(cluster, new UniqueStatement("removeInvited") {
@Override
public void set(PreparedStatement statement) throws SQLException {
statement.setInt(1, getClusterId(cluster));
statement.setString(2, uuid.toString());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("DELETE FROM `" + SQLManager.this.prefix + "cluster_invited` WHERE `cluster_id` = ? AND `user_uuid` = ?");
}
});
}
@Override
public void setInvited(final PlotCluster cluster, final UUID uuid) {
addClusterTask(cluster, new UniqueStatement("setInvited") {
@Override
public void set(PreparedStatement statement) throws SQLException {
statement.setInt(1, getClusterId(cluster));
statement.setString(2, uuid.toString());
}
@Override
public PreparedStatement get() throws SQLException {
return SQLManager.this.connection
.prepareStatement("INSERT INTO `" + SQLManager.this.prefix + "cluster_invited` (`cluster_id`, `user_uuid`) VALUES(?,?)");
}
});
}
@Override
public boolean deleteTables() {
try (Statement stmt = this.connection.createStatement();
PreparedStatement statement = this.connection.prepareStatement("DROP TABLE `" + this.prefix + "plot`")) {
close();
this.closed = false;
SQLManager.this.connection = this.database.forceConnection();
stmt.addBatch("DROP TABLE `" + this.prefix + "cluster_invited`");
stmt.addBatch("DROP TABLE `" + this.prefix + "cluster_helpers`");
stmt.addBatch("DROP TABLE `" + this.prefix + "cluster`");
stmt.addBatch("DROP TABLE `" + this.prefix + "plot_rating`");
stmt.addBatch("DROP TABLE `" + this.prefix + "plot_settings`");
stmt.addBatch("DROP TABLE `" + this.prefix + "plot_comments`");
stmt.addBatch("DROP TABLE `" + this.prefix + "plot_trusted`");
stmt.addBatch("DROP TABLE `" + this.prefix + "plot_helpers`");
stmt.addBatch("DROP TABLE `" + this.prefix + "plot_denied`");
stmt.executeBatch();
stmt.clearBatch();
statement.executeUpdate();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return true;
}
@Override
public void validateAllPlots(Set<Plot> toValidate) {
if (!isValid()) {
reconnect();
}
PS.debug("$1All DB transactions during this session are being validated (This may take a while if corrections need to be made)");
commit();
while (true) {
if (!sendBatch()) {
break;
}
}
try {
if (this.connection.getAutoCommit()) {
this.connection.setAutoCommit(false);
}
} catch (SQLException e) {
e.printStackTrace();
}
HashMap<String, HashMap<PlotId, Plot>> database = getPlots();
ArrayList<Plot> toCreate = new ArrayList<>();
for (Plot plot : toValidate) {
if (plot.temp == -1) {
continue;
}
HashMap<PlotId, Plot> worldPlots = database.get(plot.getArea().toString());
if (worldPlots == null) {
PS.debug("&8 - &7Creating plot (1): " + plot);
toCreate.add(plot);
continue;
}
Plot dataPlot = worldPlots.remove(plot.getId());
if (dataPlot == null) {
PS.debug("&8 - &7Creating plot (2): " + plot);
toCreate.add(plot);
continue;
}
// owner
if (!plot.owner.equals(dataPlot.owner)) {
PS.debug("&8 - &7Setting owner: " + plot + " -> " + MainUtil.getName(plot.owner));
setOwner(plot, plot.owner);
}
// trusted
if (!plot.getTrusted().equals(dataPlot.getTrusted())) {
HashSet<UUID> toAdd = (HashSet<UUID>) plot.getTrusted().clone();
HashSet<UUID> toRemove = (HashSet<UUID>) dataPlot.getTrusted().clone();
toRemove.removeAll(plot.getTrusted());
toAdd.removeAll(dataPlot.getTrusted());
PS.debug("&8 - &7Correcting " + (toAdd.size() + toRemove.size()) + " trusted for: " + plot);
if (!toRemove.isEmpty()) {
for (UUID uuid : toRemove) {
removeTrusted(plot, uuid);
}
}
if (!toAdd.isEmpty()) {
for (UUID uuid : toAdd) {
setTrusted(plot, uuid);
}
}
}
if (!plot.getMembers().equals(dataPlot.getMembers())) {
HashSet<UUID> toAdd = (HashSet<UUID>) plot.getMembers().clone();
HashSet<UUID> toRemove = (HashSet<UUID>) dataPlot.getMembers().clone();
toRemove.removeAll(plot.getMembers());
toAdd.removeAll(dataPlot.getMembers());
PS.debug("&8 - &7Correcting " + (toAdd.size() + toRemove.size()) + " members for: " + plot);
if (!toRemove.isEmpty()) {
for (UUID uuid : toRemove) {
removeMember(plot, uuid);
}
}
if (!toAdd.isEmpty()) {
for (UUID uuid : toAdd) {
setMember(plot, uuid);
}
}
}
if (!plot.getDenied().equals(dataPlot.getDenied())) {
HashSet<UUID> toAdd = (HashSet<UUID>) plot.getDenied().clone();
HashSet<UUID> toRemove = (HashSet<UUID>) dataPlot.getDenied().clone();
toRemove.removeAll(plot.getDenied());
toAdd.removeAll(dataPlot.getDenied());
PS.debug("&8 - &7Correcting " + (toAdd.size() + toRemove.size()) + " denied for: " + plot);
if (!toRemove.isEmpty()) {
for (UUID uuid : toRemove) {
removeDenied(plot, uuid);
}
}
if (!toAdd.isEmpty()) {
for (UUID uuid : toAdd) {
setDenied(plot, uuid);
}
}
}
boolean[] pm = plot.getMerged();
boolean[] dm = dataPlot.getMerged();
if (pm[0] != dm[0] || pm[1] != dm[1]) {
PS.debug("&8 - &7Correcting merge for: " + plot);
setMerged(dataPlot, plot.getMerged());
}
HashMap<Flag<?>, Object> pf = plot.getFlags();
HashMap<Flag<?>, Object> df = dataPlot.getFlags();
if (!pf.isEmpty() && !df.isEmpty()) {
if (pf.size() != df.size() || !StringMan.isEqual(StringMan.joinOrdered(pf.values(), ","), StringMan.joinOrdered(df.values(), ","))) {
PS.debug("&8 - &7Correcting flags for: " + plot);
setFlags(plot, pf);
}
}
}
for (Entry<String, HashMap<PlotId, Plot>> entry : database.entrySet()) {
HashMap<PlotId, Plot> map = entry.getValue();
if (!map.isEmpty()) {
for (Entry<PlotId, Plot> entry2 : map.entrySet()) {
PS.debug("$1Plot was deleted: " + entry2.getValue().toString() + "// TODO implement this when sure safe");
}
}
}
commit();
}
@Override
public void replaceWorld(final String oldWorld, final String newWorld, final PlotId min, final PlotId max) {
addGlobalTask(new Runnable() {
@Override
public void run() {
if (min == null) {
try (PreparedStatement stmt = SQLManager.this.connection
.prepareStatement("UPDATE `" + SQLManager.this.prefix + "plot` SET `world` = ? WHERE `world` = ?")) {
stmt.setString(1, newWorld);
stmt.setString(2, oldWorld);
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
try (PreparedStatement stmt = SQLManager.this.connection
.prepareStatement("UPDATE `" + SQLManager.this.prefix + "cluster` SET `world` = ? WHERE `world` = ?")) {
stmt.setString(1, newWorld);
stmt.setString(2, oldWorld);
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
} else {
try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement("UPDATE `"
+ SQLManager.this.prefix
+ "plot` SET `world` = ? WHERE `world` = ? AND `plot_id_x` BETWEEN ? AND ? AND `plot_id_z` BETWEEN ? AND ?")) {
stmt.setString(1, newWorld);
stmt.setString(2, oldWorld);
stmt.setInt(3, min.x);
stmt.setInt(4, max.x);
stmt.setInt(5, min.y);
stmt.setInt(6, max.y);
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement("UPDATE `"
+ SQLManager.this.prefix
+ "cluster` SET `world` = ? WHERE `world` = ? AND `pos1_x` <= ? AND `pos1_z` <= ? AND `pos2_x` >= ? AND `pos2_z` >= ?")) {
stmt.setString(1, newWorld);
stmt.setString(2, oldWorld);
stmt.setInt(3, max.x);
stmt.setInt(4, max.y);
stmt.setInt(5, min.x);
stmt.setInt(6, min.y);
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
});
}
@Override
public void replaceUUID(final UUID old, final UUID now) {
addGlobalTask(new Runnable() {
@Override
public void run() {
try (Statement stmt = SQLManager.this.connection.createStatement()) {
stmt.executeUpdate(
"UPDATE `" + SQLManager.this.prefix + "cluster` SET `owner` = '" + now.toString() + "' WHERE `owner` = '" + old.toString()
+ '\'');
stmt.executeUpdate(
"UPDATE `" + SQLManager.this.prefix + "cluster_helpers` SET `user_uuid` = '" + now.toString() + "' WHERE `user_uuid` = '"
+ old.toString()
+ '\'');
stmt.executeUpdate(
"UPDATE `" + SQLManager.this.prefix + "cluster_invited` SET `user_uuid` = '" + now.toString() + "' WHERE `user_uuid` = '"
+ old.toString()
+ '\'');
stmt.executeUpdate(
"UPDATE `" + SQLManager.this.prefix + "plot` SET `owner` = '" + now.toString() + "' WHERE `owner` = '" + old.toString()
+ '\'');
stmt.executeUpdate(
"UPDATE `" + SQLManager.this.prefix + "plot_denied` SET `user_uuid` = '" + now.toString() + "' WHERE `user_uuid` = '"
+ old.toString()
+ '\'');
stmt.executeUpdate(
"UPDATE `" + SQLManager.this.prefix + "plot_helpers` SET `user_uuid` = '" + now.toString() + "' WHERE `user_uuid` = '"
+ old.toString()
+ '\'');
stmt.executeUpdate(
"UPDATE `" + SQLManager.this.prefix + "plot_trusted` SET `user_uuid` = '" + now.toString() + "' WHERE `user_uuid` = '"
+ old.toString()
+ '\'');
} catch (SQLException e) {
e.printStackTrace();
}
}
});
}
@Override
public void close() {
try {
this.closed = true;
this.connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public abstract class UniqueStatement {
public final String method;
public UniqueStatement(String method) {
this.method = method;
}
public void addBatch(PreparedStatement statement) throws SQLException {
statement.addBatch();
}
public void execute(PreparedStatement statement) throws SQLException {
statement.executeBatch();
}
public abstract PreparedStatement get() throws SQLException;
public abstract void set(PreparedStatement stmt) throws SQLException;
}
private class UUIDPair {
public final int id;
public final UUID uuid;
public UUIDPair(int id, UUID uuid) {
this.id = id;
this.uuid = uuid;
}
}
private class SettingsPair {
public final int id;
public final PlotSettings settings;
public SettingsPair(int id, PlotSettings settings) {
this.id = id;
this.settings = settings;
}
}
}