001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.core.database; 020 021import com.google.common.base.Charsets; 022import com.plotsquared.core.PlotSquared; 023import com.plotsquared.core.configuration.ConfigurationSection; 024import com.plotsquared.core.configuration.Settings; 025import com.plotsquared.core.configuration.Storage; 026import com.plotsquared.core.configuration.caption.CaptionUtility; 027import com.plotsquared.core.configuration.file.YamlConfiguration; 028import com.plotsquared.core.inject.annotations.WorldConfig; 029import com.plotsquared.core.listener.PlotListener; 030import com.plotsquared.core.location.BlockLoc; 031import com.plotsquared.core.plot.Plot; 032import com.plotsquared.core.plot.PlotArea; 033import com.plotsquared.core.plot.PlotCluster; 034import com.plotsquared.core.plot.PlotId; 035import com.plotsquared.core.plot.PlotSettings; 036import com.plotsquared.core.plot.comment.PlotComment; 037import com.plotsquared.core.plot.flag.FlagContainer; 038import com.plotsquared.core.plot.flag.FlagParseException; 039import com.plotsquared.core.plot.flag.GlobalFlagContainer; 040import com.plotsquared.core.plot.flag.PlotFlag; 041import com.plotsquared.core.plot.flag.types.BlockTypeListFlag; 042import com.plotsquared.core.util.EventDispatcher; 043import com.plotsquared.core.util.HashUtil; 044import com.plotsquared.core.util.StringMan; 045import com.plotsquared.core.util.task.RunnableVal; 046import com.plotsquared.core.util.task.TaskManager; 047import org.apache.logging.log4j.LogManager; 048import org.apache.logging.log4j.Logger; 049import org.checkerframework.checker.nullness.qual.NonNull; 050 051import java.sql.Connection; 052import java.sql.DatabaseMetaData; 053import java.sql.PreparedStatement; 054import java.sql.ResultSet; 055import java.sql.SQLException; 056import java.sql.Statement; 057import java.sql.Timestamp; 058import java.text.ParseException; 059import java.text.SimpleDateFormat; 060import java.util.ArrayList; 061import java.util.Collection; 062import java.util.HashMap; 063import java.util.HashSet; 064import java.util.Iterator; 065import java.util.LinkedHashMap; 066import java.util.List; 067import java.util.Map; 068import java.util.Map.Entry; 069import java.util.Queue; 070import java.util.Set; 071import java.util.UUID; 072import java.util.concurrent.CompletableFuture; 073import java.util.concurrent.ConcurrentHashMap; 074import java.util.concurrent.ConcurrentLinkedQueue; 075import java.util.concurrent.atomic.AtomicInteger; 076 077 078@SuppressWarnings("SqlDialectInspection") 079public class SQLManager implements AbstractDB { 080 081 private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + SQLManager.class.getSimpleName()); 082 083 // Public final 084 public final String SET_OWNER; 085 public final String GET_ALL_PLOTS; 086 public final String CREATE_PLOTS; 087 public final String CREATE_SETTINGS; 088 public final String CREATE_TIERS; 089 public final String CREATE_PLOT; 090 public final String CREATE_PLOT_SAFE; 091 public final String CREATE_CLUSTER; 092 093 // Private Final 094 private final String prefix; 095 private final Database database; 096 private final boolean mySQL; 097 @SuppressWarnings({"unused", "FieldCanBeLocal"}) 098 private final EventDispatcher eventDispatcher; 099 @SuppressWarnings({"unused", "FieldCanBeLocal"}) 100 private final PlotListener plotListener; 101 private final YamlConfiguration worldConfiguration; 102 /** 103 * important tasks 104 */ 105 public volatile Queue<Runnable> globalTasks; 106 /** 107 * Notify tasks 108 */ 109 public volatile Queue<Runnable> notifyTasks; 110 /** 111 * plot 112 * plot_denied 113 * plot_helpers 114 * plot_trusted 115 * plot_comments 116 * plot_settings 117 * plot_rating 118 */ 119 public volatile ConcurrentHashMap<Plot, Queue<UniqueStatement>> plotTasks; 120 /** 121 * player_meta 122 */ 123 public volatile ConcurrentHashMap<UUID, Queue<UniqueStatement>> playerTasks; 124 /** 125 * cluster 126 * cluster_helpers 127 * cluster_invited 128 * cluster_settings 129 */ 130 public volatile ConcurrentHashMap<PlotCluster, Queue<UniqueStatement>> clusterTasks; 131 // Private 132 private Connection connection; 133 private boolean closed = false; 134 135 /** 136 * Constructor 137 * 138 * @param database 139 * @param prefix prefix 140 * @throws SQLException 141 * @throws ClassNotFoundException 142 */ 143 public SQLManager( 144 final @NonNull Database database, 145 final @NonNull String prefix, 146 final @NonNull EventDispatcher eventDispatcher, 147 final @NonNull PlotListener plotListener, 148 @WorldConfig final @NonNull YamlConfiguration worldConfiguration 149 ) 150 throws SQLException, ClassNotFoundException { 151 // Private final 152 this.eventDispatcher = eventDispatcher; 153 this.plotListener = plotListener; 154 this.worldConfiguration = worldConfiguration; 155 this.database = database; 156 this.connection = database.openConnection(); 157 this.mySQL = database instanceof MySQL; 158 this.globalTasks = new ConcurrentLinkedQueue<>(); 159 this.notifyTasks = new ConcurrentLinkedQueue<>(); 160 this.plotTasks = new ConcurrentHashMap<>(); 161 this.playerTasks = new ConcurrentHashMap<>(); 162 this.clusterTasks = new ConcurrentHashMap<>(); 163 this.prefix = prefix; 164 this.SET_OWNER = "UPDATE `" + this.prefix 165 + "plot` SET `owner` = ? WHERE `plot_id_x` = ? AND `plot_id_z` = ? AND `world` = ?"; 166 this.GET_ALL_PLOTS = 167 "SELECT `id`, `plot_id_x`, `plot_id_z`, `world` FROM `" + this.prefix + "plot`"; 168 this.CREATE_PLOTS = "INSERT INTO `" + this.prefix 169 + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) values "; 170 this.CREATE_SETTINGS = 171 "INSERT INTO `" + this.prefix + "plot_settings` (`plot_plot_id`) values "; 172 this.CREATE_TIERS = 173 "INSERT INTO `" + this.prefix + "plot_%tier%` (`plot_plot_id`, `user_uuid`) values "; 174 this.CREATE_PLOT = "INSERT INTO `" + this.prefix 175 + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) VALUES(?, ?, ?, ?, ?)"; 176 177 if (mySQL) { 178 this.CREATE_PLOT_SAFE = "INSERT IGNORE INTO `" + this.prefix 179 + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) SELECT ?, ?, ?, ?, ? FROM DUAL WHERE NOT EXISTS (SELECT null FROM `" 180 + this.prefix + "plot` WHERE `world` = ? AND `plot_id_x` = ? AND `plot_id_z` = ?)"; 181 } else { 182 this.CREATE_PLOT_SAFE = "INSERT INTO `" + this.prefix 183 + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) SELECT ?, ?, ?, ?, ? WHERE NOT EXISTS (SELECT null FROM `" 184 + this.prefix + "plot` WHERE `world` = ? AND `plot_id_x` = ? AND `plot_id_z` = ?)"; 185 } 186 this.CREATE_CLUSTER = "INSERT INTO `" + this.prefix 187 + "cluster`(`pos1_x`, `pos1_z`, `pos2_x`, `pos2_z`, `owner`, `world`) VALUES(?, ?, ?, ?, ?, ?)"; 188 try { 189 createTables(); 190 } catch (SQLException e) { 191 e.printStackTrace(); 192 } 193 TaskManager.runTaskAsync(() -> { 194 long last = System.currentTimeMillis(); 195 while (!SQLManager.this.closed) { 196 boolean hasTask = 197 !globalTasks.isEmpty() || !playerTasks.isEmpty() || !plotTasks.isEmpty() 198 || !clusterTasks.isEmpty(); 199 if (hasTask) { 200 if (SQLManager.this.mySQL && System.currentTimeMillis() - last > 550000 201 || !isValid()) { 202 last = System.currentTimeMillis(); 203 reconnect(); 204 } 205 if (!sendBatch()) { 206 try { 207 if (!getNotifyTasks().isEmpty()) { 208 for (Runnable task : getNotifyTasks()) { 209 TaskManager.runTask(task); 210 } 211 getNotifyTasks().clear(); 212 } 213 Thread.sleep(50); 214 } catch (InterruptedException e) { 215 e.printStackTrace(); 216 } 217 } 218 } else { 219 try { 220 Thread.sleep(1000); 221 } catch (InterruptedException e) { 222 e.printStackTrace(); 223 } 224 } 225 } 226 }); 227 } 228 229 public boolean isValid() { 230 try { 231 if (connection.isClosed()) { 232 return false; 233 } 234 } catch (SQLException e) { 235 return false; 236 } 237 try (PreparedStatement stmt = this.connection.prepareStatement("SELECT 1")) { 238 stmt.execute(); 239 return true; 240 } catch (Throwable e) { 241 return false; 242 } 243 } 244 245 public void reconnect() { 246 try { 247 close(); 248 SQLManager.this.closed = false; 249 SQLManager.this.connection = database.forceConnection(); 250 } catch (SQLException | ClassNotFoundException e) { 251 e.printStackTrace(); 252 } 253 } 254 255 public synchronized Queue<Runnable> getGlobalTasks() { 256 return this.globalTasks; 257 } 258 259 public synchronized Queue<Runnable> getNotifyTasks() { 260 return this.notifyTasks; 261 } 262 263 public synchronized void addPlotTask(@NonNull Plot plot, UniqueStatement task) { 264 Queue<UniqueStatement> tasks = this.plotTasks.get(plot); 265 if (tasks == null) { 266 tasks = new ConcurrentLinkedQueue<>(); 267 this.plotTasks.put(plot, tasks); 268 } 269 if (task == null) { 270 task = new UniqueStatement(String.valueOf(plot.hashCode())) { 271 272 @Override 273 public PreparedStatement get() { 274 return null; 275 } 276 277 @Override 278 public void set(PreparedStatement statement) { 279 } 280 281 @Override 282 public void addBatch(PreparedStatement statement) { 283 } 284 285 @Override 286 public void execute(PreparedStatement statement) { 287 } 288 289 }; 290 } 291 tasks.add(task); 292 } 293 294 public synchronized void addPlayerTask(UUID uuid, UniqueStatement task) { 295 if (uuid == null) { 296 return; 297 } 298 Queue<UniqueStatement> tasks = this.playerTasks.get(uuid); 299 if (tasks == null) { 300 tasks = new ConcurrentLinkedQueue<>(); 301 this.playerTasks.put(uuid, tasks); 302 } 303 if (task == null) { 304 task = new UniqueStatement(String.valueOf(uuid.hashCode())) { 305 306 @Override 307 public PreparedStatement get() { 308 return null; 309 } 310 311 @Override 312 public void set(PreparedStatement statement) { 313 } 314 315 @Override 316 public void addBatch(PreparedStatement statement) { 317 } 318 319 @Override 320 public void execute(PreparedStatement statement) { 321 } 322 323 }; 324 } 325 tasks.add(task); 326 } 327 328 public synchronized void addClusterTask(PlotCluster cluster, UniqueStatement task) { 329 Queue<UniqueStatement> tasks = this.clusterTasks.get(cluster); 330 if (tasks == null) { 331 tasks = new ConcurrentLinkedQueue<>(); 332 this.clusterTasks.put(cluster, tasks); 333 } 334 if (task == null) { 335 task = new UniqueStatement(String.valueOf(cluster.hashCode())) { 336 337 @Override 338 public PreparedStatement get() { 339 return null; 340 } 341 342 @Override 343 public void set(PreparedStatement statement) { 344 } 345 346 @Override 347 public void addBatch(PreparedStatement statement) { 348 } 349 350 @Override 351 public void execute(PreparedStatement statement) { 352 } 353 354 }; 355 } 356 tasks.add(task); 357 } 358 359 public synchronized void addGlobalTask(Runnable task) { 360 getGlobalTasks().add(task); 361 } 362 363 public synchronized void addNotifyTask(Runnable task) { 364 if (task != null) { 365 getNotifyTasks().add(task); 366 } 367 } 368 369 public boolean sendBatch() { 370 try { 371 if (!getGlobalTasks().isEmpty()) { 372 if (this.connection.getAutoCommit()) { 373 this.connection.setAutoCommit(false); 374 } 375 Runnable task = getGlobalTasks().remove(); 376 if (task != null) { 377 try { 378 task.run(); 379 } catch (Throwable e) { 380 LOGGER.error("============ DATABASE ERROR ============"); 381 LOGGER.error("============ DATABASE ERROR ============"); 382 LOGGER.error("There was an error updating the database."); 383 LOGGER.error(" - It will be corrected on shutdown"); 384 e.printStackTrace(); 385 LOGGER.error("========================================"); 386 } 387 } 388 commit(); 389 return true; 390 } 391 int count = -1; 392 if (!this.plotTasks.isEmpty()) { 393 count = Math.max(count, 0); 394 if (this.connection.getAutoCommit()) { 395 this.connection.setAutoCommit(false); 396 } 397 String method = null; 398 PreparedStatement statement = null; 399 UniqueStatement task = null; 400 UniqueStatement lastTask = null; 401 Iterator<Entry<Plot, Queue<UniqueStatement>>> iterator = 402 this.plotTasks.entrySet().iterator(); 403 while (iterator.hasNext()) { 404 try { 405 Entry<Plot, Queue<UniqueStatement>> entry = iterator.next(); 406 Queue<UniqueStatement> tasks = entry.getValue(); 407 if (tasks.isEmpty()) { 408 iterator.remove(); 409 continue; 410 } 411 task = tasks.remove(); 412 count++; 413 if (task != null) { 414 if (task.method == null || !task.method.equals(method) 415 || statement == null) { 416 if (statement != null) { 417 lastTask.execute(statement); 418 statement.close(); 419 } 420 method = task.method; 421 statement = task.get(); 422 } 423 task.set(statement); 424 task.addBatch(statement); 425 try { 426 if (statement.isClosed()) { 427 statement = null; 428 } 429 } catch (NullPointerException | AbstractMethodError ignore) { 430 } 431 } 432 lastTask = task; 433 } catch (Throwable e) { 434 LOGGER.error("============ DATABASE ERROR ============"); 435 LOGGER.error("There was an error updating the database."); 436 LOGGER.error(" - It will be corrected on shutdown"); 437 LOGGER.error("========================================"); 438 e.printStackTrace(); 439 LOGGER.error("========================================"); 440 } 441 } 442 if (statement != null && task != null) { 443 task.execute(statement); 444 statement.close(); 445 } 446 } 447 if (!this.playerTasks.isEmpty()) { 448 count = Math.max(count, 0); 449 if (this.connection.getAutoCommit()) { 450 this.connection.setAutoCommit(false); 451 } 452 String method = null; 453 PreparedStatement statement = null; 454 UniqueStatement task = null; 455 UniqueStatement lastTask = null; 456 for (Entry<UUID, Queue<UniqueStatement>> entry : this.playerTasks.entrySet()) { 457 try { 458 UUID uuid = entry.getKey(); 459 if (this.playerTasks.get(uuid).isEmpty()) { 460 this.playerTasks.remove(uuid); 461 continue; 462 } 463 task = this.playerTasks.get(uuid).remove(); 464 count++; 465 if (task != null) { 466 if (task.method == null || !task.method.equals(method)) { 467 if (statement != null) { 468 lastTask.execute(statement); 469 statement.close(); 470 } 471 method = task.method; 472 statement = task.get(); 473 } 474 task.set(statement); 475 task.addBatch(statement); 476 } 477 lastTask = task; 478 } catch (Throwable e) { 479 LOGGER.error("============ DATABASE ERROR ============"); 480 LOGGER.error("There was an error updating the database."); 481 LOGGER.error(" - It will be corrected on shutdown"); 482 LOGGER.error("========================================"); 483 e.printStackTrace(); 484 LOGGER.error("========================================"); 485 } 486 } 487 if (statement != null && task != null) { 488 task.execute(statement); 489 statement.close(); 490 } 491 } 492 if (!this.clusterTasks.isEmpty()) { 493 count = Math.max(count, 0); 494 if (this.connection.getAutoCommit()) { 495 this.connection.setAutoCommit(false); 496 } 497 String method = null; 498 PreparedStatement statement = null; 499 UniqueStatement task = null; 500 UniqueStatement lastTask = null; 501 for (Entry<PlotCluster, Queue<UniqueStatement>> entry : this.clusterTasks 502 .entrySet()) { 503 try { 504 PlotCluster cluster = entry.getKey(); 505 if (this.clusterTasks.get(cluster).isEmpty()) { 506 this.clusterTasks.remove(cluster); 507 continue; 508 } 509 task = this.clusterTasks.get(cluster).remove(); 510 count++; 511 if (task != null) { 512 if (task.method == null || !task.method.equals(method)) { 513 if (statement != null) { 514 lastTask.execute(statement); 515 statement.close(); 516 } 517 method = task.method; 518 statement = task.get(); 519 } 520 task.set(statement); 521 task.addBatch(statement); 522 } 523 lastTask = task; 524 } catch (Throwable e) { 525 LOGGER.error("============ DATABASE ERROR ============"); 526 LOGGER.error("There was an error updating the database."); 527 LOGGER.error(" - It will be corrected on shutdown"); 528 LOGGER.error("========================================"); 529 e.printStackTrace(); 530 LOGGER.error("========================================"); 531 } 532 } 533 if (statement != null && task != null) { 534 task.execute(statement); 535 statement.close(); 536 } 537 } 538 if (count > 0) { 539 commit(); 540 return true; 541 } 542 if (count != -1) { 543 if (!this.connection.getAutoCommit()) { 544 this.connection.setAutoCommit(true); 545 } 546 } 547 if (!this.clusterTasks.isEmpty()) { 548 this.clusterTasks.clear(); 549 } 550 if (!this.plotTasks.isEmpty()) { 551 this.plotTasks.clear(); 552 } 553 } catch (Throwable e) { 554 LOGGER.error("============ DATABASE ERROR ============"); 555 LOGGER.error("There was an error updating the database."); 556 LOGGER.error(" - It will be corrected on shutdown"); 557 LOGGER.error("========================================"); 558 e.printStackTrace(); 559 LOGGER.error("========================================"); 560 } 561 return false; 562 } 563 564 public Connection getConnection() { 565 return this.connection; 566 } 567 568 /** 569 * Set Plot owner 570 * 571 * @param plot Plot Object 572 * @param uuid Owner UUID 573 */ 574 @Override 575 public void setOwner(final Plot plot, final UUID uuid) { 576 addPlotTask(plot, new UniqueStatement("setOwner") { 577 @Override 578 public void set(PreparedStatement statement) throws SQLException { 579 statement.setString(1, uuid.toString()); 580 statement.setInt(2, plot.getId().getX()); 581 statement.setInt(3, plot.getId().getY()); 582 statement.setString(4, plot.getArea().toString()); 583 } 584 585 @Override 586 public PreparedStatement get() throws SQLException { 587 return SQLManager.this.connection.prepareStatement(SQLManager.this.SET_OWNER); 588 } 589 }); 590 } 591 592 @Override 593 public void createPlotsAndData(final List<Plot> myList, final Runnable whenDone) { 594 addGlobalTask(() -> { 595 try { 596 // Create the plots 597 createPlots(myList, () -> { 598 final Map<PlotId, Integer> idMap = new HashMap<>(); 599 600 try { 601 // Creating datastructures 602 HashMap<PlotId, Plot> plotMap = new HashMap<>(); 603 for (Plot plot : myList) { 604 plotMap.put(plot.getId(), plot); 605 } 606 ArrayList<LegacySettings> settings = new ArrayList<>(); 607 final ArrayList<UUIDPair> helpers = new ArrayList<>(); 608 final ArrayList<UUIDPair> trusted = new ArrayList<>(); 609 final ArrayList<UUIDPair> denied = new ArrayList<>(); 610 611 // Populating structures 612 try (PreparedStatement stmt = SQLManager.this.connection 613 .prepareStatement(SQLManager.this.GET_ALL_PLOTS); 614 ResultSet result = stmt.executeQuery()) { 615 while (result.next()) { 616 int id = result.getInt("id"); 617 int x = result.getInt("plot_id_x"); 618 int y = result.getInt("plot_id_z"); 619 PlotId plotId = PlotId.of(x, y); 620 Plot plot = plotMap.get(plotId); 621 idMap.put(plotId, id); 622 if (plot != null) { 623 settings.add(new LegacySettings(id, plot.getSettings())); 624 for (UUID uuid : plot.getDenied()) { 625 denied.add(new UUIDPair(id, uuid)); 626 } 627 for (UUID uuid : plot.getMembers()) { 628 trusted.add(new UUIDPair(id, uuid)); 629 } 630 for (UUID uuid : plot.getTrusted()) { 631 helpers.add(new UUIDPair(id, uuid)); 632 } 633 } 634 } 635 } 636 637 createFlags(idMap, myList, () -> createSettings( 638 settings, 639 () -> createTiers(helpers, "helpers", 640 () -> createTiers(trusted, "trusted", 641 () -> createTiers(denied, "denied", () -> { 642 try { 643 SQLManager.this.connection.commit(); 644 } catch (SQLException e) { 645 e.printStackTrace(); 646 } 647 if (whenDone != null) { 648 whenDone.run(); 649 } 650 }) 651 ) 652 ) 653 )); 654 } catch (SQLException e) { 655 LOGGER.warn("Failed to set all flags and member tiers for plots", e); 656 try { 657 SQLManager.this.connection.commit(); 658 } catch (SQLException e1) { 659 e1.printStackTrace(); 660 } 661 } 662 }); 663 } catch (Exception e) { 664 LOGGER.warn("Warning! Failed to set all helper for plots", e); 665 try { 666 SQLManager.this.connection.commit(); 667 } catch (SQLException e1) { 668 e1.printStackTrace(); 669 } 670 } 671 }); 672 } 673 674 /** 675 * Create a plot 676 * 677 * @param myList list of plots to be created 678 */ 679 public void createTiers(ArrayList<UUIDPair> myList, final String tier, Runnable whenDone) { 680 StmtMod<UUIDPair> mod = new StmtMod<>() { 681 @Override 682 public String getCreateMySQL(int size) { 683 return getCreateMySQL(size, SQLManager.this.CREATE_TIERS.replaceAll("%tier%", tier), 684 2 685 ); 686 } 687 688 @Override 689 public String getCreateSQLite(int size) { 690 return getCreateSQLite(size, 691 "INSERT INTO `" + SQLManager.this.prefix + "plot_" + tier 692 + "` SELECT ? AS `plot_plot_id`, ? AS `user_uuid`", 2 693 ); 694 } 695 696 @Override 697 public String getCreateSQL() { 698 return "INSERT INTO `" + SQLManager.this.prefix + "plot_" + tier 699 + "` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"; 700 } 701 702 @Override 703 public void setMySQL(PreparedStatement stmt, int i, UUIDPair pair) 704 throws SQLException { 705 stmt.setInt(i * 2 + 1, pair.id); 706 stmt.setString(i * 2 + 2, pair.uuid.toString()); 707 } 708 709 @Override 710 public void setSQLite(PreparedStatement stmt, int i, UUIDPair pair) 711 throws SQLException { 712 stmt.setInt(i * 2 + 1, pair.id); 713 stmt.setString(i * 2 + 2, pair.uuid.toString()); 714 } 715 716 @Override 717 public void setSQL(PreparedStatement stmt, UUIDPair pair) 718 throws SQLException { 719 stmt.setInt(1, pair.id); 720 stmt.setString(2, pair.uuid.toString()); 721 } 722 }; 723 setBulk(myList, mod, whenDone); 724 } 725 726 public void createFlags(Map<PlotId, Integer> ids, List<Plot> plots, Runnable whenDone) { 727 try (final PreparedStatement preparedStatement = this.connection.prepareStatement( 728 "INSERT INTO `" + SQLManager.this.prefix 729 + "plot_flags`(`plot_id`, `flag`, `value`) VALUES(?, ?, ?)")) { 730 for (final Plot plot : plots) { 731 final FlagContainer flagContainer = plot.getFlagContainer(); 732 for (final PlotFlag<?, ?> flagEntry : flagContainer.getFlagMap().values()) { 733 preparedStatement.setInt(1, ids.get(plot.getId())); 734 preparedStatement.setString(2, flagEntry.getName()); 735 preparedStatement.setString(3, flagEntry.toString()); 736 preparedStatement.addBatch(); 737 } 738 try { 739 preparedStatement.executeBatch(); 740 } catch (final Exception e) { 741 LOGGER.error("Failed to store flag values for plot with entry ID: {}", plot); 742 e.printStackTrace(); 743 continue; 744 } 745 LOGGER.info( 746 "- Finished converting flag values for plot with entry ID: {}", 747 plot.getId() 748 ); 749 } 750 } catch (final Exception e) { 751 LOGGER.error("Failed to store flag values", e); 752 } 753 LOGGER.info("Finished converting flags ({} plots processed)", plots.size()); 754 whenDone.run(); 755 } 756 757 /** 758 * Create a plot 759 * 760 * @param myList list of plots to be created 761 */ 762 public void createPlots(List<Plot> myList, Runnable whenDone) { 763 StmtMod<Plot> mod = new StmtMod<>() { 764 @Override 765 public String getCreateMySQL(int size) { 766 return getCreateMySQL(size, SQLManager.this.CREATE_PLOTS, 5); 767 } 768 769 @Override 770 public String getCreateSQLite(int size) { 771 return getCreateSQLite(size, "INSERT INTO `" + SQLManager.this.prefix 772 + "plot` SELECT ? AS `id`, ? AS `plot_id_x`, ? AS `plot_id_z`, ? AS `owner`, ? AS `world`, ? AS `timestamp` ", 773 6 774 ); 775 } 776 777 @Override 778 public String getCreateSQL() { 779 return SQLManager.this.CREATE_PLOT; 780 } 781 782 @Override 783 public void setMySQL(PreparedStatement stmt, int i, Plot plot) 784 throws SQLException { 785 stmt.setInt(i * 5 + 1, plot.getId().getX()); 786 stmt.setInt(i * 5 + 2, plot.getId().getY()); 787 try { 788 stmt.setString(i * 5 + 3, plot.getOwnerAbs().toString()); 789 } catch (SQLException ignored) { 790 stmt.setString(i * 5 + 3, everyone.toString()); 791 } 792 stmt.setString(i * 5 + 4, plot.getArea().toString()); 793 stmt.setTimestamp(i * 5 + 5, new Timestamp(plot.getTimestamp())); 794 } 795 796 @Override 797 public void setSQLite(PreparedStatement stmt, int i, Plot plot) 798 throws SQLException { 799 stmt.setNull(i * 6 + 1, 4); 800 stmt.setInt(i * 6 + 2, plot.getId().getX()); 801 stmt.setInt(i * 6 + 3, plot.getId().getY()); 802 try { 803 stmt.setString(i * 6 + 4, plot.getOwnerAbs().toString()); 804 } catch (SQLException ignored) { 805 stmt.setString(i * 6 + 4, everyone.toString()); 806 } 807 stmt.setString(i * 6 + 5, plot.getArea().toString()); 808 stmt.setTimestamp(i * 6 + 6, new Timestamp(plot.getTimestamp())); 809 } 810 811 @Override 812 public void setSQL(PreparedStatement stmt, Plot plot) throws SQLException { 813 stmt.setInt(1, plot.getId().getX()); 814 stmt.setInt(2, plot.getId().getY()); 815 stmt.setString(3, plot.getOwnerAbs().toString()); 816 stmt.setString(4, plot.getArea().toString()); 817 stmt.setTimestamp(5, new Timestamp(plot.getTimestamp())); 818 819 } 820 }; 821 setBulk(myList, mod, whenDone); 822 } 823 824 public <T> void setBulk(List<T> objList, StmtMod<T> mod, Runnable whenDone) { 825 int size = objList.size(); 826 if (size == 0) { 827 if (whenDone != null) { 828 whenDone.run(); 829 } 830 return; 831 } 832 int packet; 833 if (this.mySQL) { 834 packet = Math.min(size, 5000); 835 } else { 836 packet = Math.min(size, 50); 837 } 838 int amount = size / packet; 839 try { 840 int count = 0; 841 PreparedStatement preparedStmt = null; 842 int last = -1; 843 for (int j = 0; j <= amount; j++) { 844 List<T> subList = objList.subList(j * packet, Math.min(size, (j + 1) * packet)); 845 if (subList.isEmpty()) { 846 break; 847 } 848 String statement; 849 if (last == -1) { 850 last = subList.size(); 851 statement = mod.getCreateMySQL(subList.size()); 852 preparedStmt = this.connection.prepareStatement(statement); 853 } 854 if (subList.size() != last || count % 5000 == 0 && count > 0) { 855 preparedStmt.executeBatch(); 856 preparedStmt.close(); 857 statement = mod.getCreateMySQL(subList.size()); 858 preparedStmt = this.connection.prepareStatement(statement); 859 } 860 for (int i = 0; i < subList.size(); i++) { 861 count++; 862 T obj = subList.get(i); 863 mod.setMySQL(preparedStmt, i, obj); 864 } 865 last = subList.size(); 866 preparedStmt.addBatch(); 867 } 868 preparedStmt.executeBatch(); 869 preparedStmt.clearParameters(); 870 preparedStmt.close(); 871 if (whenDone != null) { 872 whenDone.run(); 873 } 874 return; 875 } catch (SQLException e) { 876 if (this.mySQL) { 877 LOGGER.error("1: | {}", objList.get(0).getClass().getCanonicalName()); 878 e.printStackTrace(); 879 } 880 } 881 try { 882 int count = 0; 883 PreparedStatement preparedStmt = null; 884 int last = -1; 885 for (int j = 0; j <= amount; j++) { 886 List<T> subList = objList.subList(j * packet, Math.min(size, (j + 1) * packet)); 887 if (subList.isEmpty()) { 888 break; 889 } 890 String statement; 891 if (last == -1) { 892 last = subList.size(); 893 statement = mod.getCreateSQLite(subList.size()); 894 preparedStmt = this.connection.prepareStatement(statement); 895 } 896 if (subList.size() != last || count % 5000 == 0 && count > 0) { 897 preparedStmt.executeBatch(); 898 preparedStmt.clearParameters(); 899 statement = mod.getCreateSQLite(subList.size()); 900 preparedStmt = this.connection.prepareStatement(statement); 901 } 902 for (int i = 0; i < subList.size(); i++) { 903 count++; 904 T obj = subList.get(i); 905 mod.setSQLite(preparedStmt, i, obj); 906 } 907 last = subList.size(); 908 preparedStmt.addBatch(); 909 } 910 preparedStmt.executeBatch(); 911 preparedStmt.clearParameters(); 912 preparedStmt.close(); 913 } catch (SQLException e) { 914 e.printStackTrace(); 915 LOGGER.error("2: | {}", objList.get(0).getClass().getCanonicalName()); 916 LOGGER.error("Could not bulk save!"); 917 try (PreparedStatement preparedStmt = this.connection 918 .prepareStatement(mod.getCreateSQL())) { 919 for (T obj : objList) { 920 mod.setSQL(preparedStmt, obj); 921 preparedStmt.addBatch(); 922 } 923 preparedStmt.executeBatch(); 924 } catch (SQLException e3) { 925 LOGGER.error("Failed to save all", e); 926 e3.printStackTrace(); 927 } 928 } 929 if (whenDone != null) { 930 whenDone.run(); 931 } 932 } 933 934 public void createSettings(final ArrayList<LegacySettings> myList, final Runnable whenDone) { 935 try (final PreparedStatement preparedStatement = this.connection.prepareStatement( 936 "INSERT INTO `" + SQLManager.this.prefix + "plot_settings`" 937 + "(`plot_plot_id`,`biome`,`rain`,`custom_time`,`time`,`deny_entry`,`alias`,`merged`,`position`) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)")) { 938 939 int packet; 940 if (this.mySQL) { 941 packet = Math.min(myList.size(), 5000); 942 } else { 943 packet = Math.min(myList.size(), 50); 944 } 945 946 int totalUpdated = 0; 947 int updated = 0; 948 949 for (final LegacySettings legacySettings : myList) { 950 preparedStatement.setInt(1, legacySettings.id); 951 preparedStatement.setNull(2, 4); 952 preparedStatement.setNull(3, 4); 953 preparedStatement.setNull(4, 4); 954 preparedStatement.setNull(5, 4); 955 preparedStatement.setNull(6, 4); 956 if (legacySettings.settings.getAlias().isEmpty()) { 957 preparedStatement.setNull(7, 4); 958 } else { 959 preparedStatement.setString(7, legacySettings.settings.getAlias()); 960 } 961 boolean[] merged = legacySettings.settings.getMerged(); 962 int hash = HashUtil.hash(merged); 963 preparedStatement.setInt(8, hash); 964 BlockLoc loc = legacySettings.settings.getPosition(); 965 String position; 966 if (loc.getY() == 0) { 967 position = "DEFAULT"; 968 } else { 969 position = loc.getX() + "," + loc.getY() + ',' + loc.getZ(); 970 } 971 preparedStatement.setString(9, position); 972 preparedStatement.addBatch(); 973 if (++updated >= packet) { 974 try { 975 preparedStatement.executeBatch(); 976 } catch (final Exception e) { 977 LOGGER.error("Failed to store settings for plot with entry ID: {}", legacySettings.id); 978 e.printStackTrace(); 979 continue; 980 } 981 } 982 totalUpdated += 1; 983 } 984 985 if (totalUpdated < myList.size()) { 986 try { 987 preparedStatement.executeBatch(); 988 } catch (final Exception e) { 989 LOGGER.error("Failed to store settings", e); 990 } 991 } 992 } catch (final Exception e) { 993 LOGGER.error("Failed to store settings", e); 994 } 995 LOGGER.info("Finished converting settings ({} plots processed)", myList.size()); 996 whenDone.run(); 997 } 998 999 public void createEmptySettings(final ArrayList<Integer> myList, final Runnable whenDone) { 1000 final StmtMod<Integer> mod = new StmtMod<>() { 1001 @Override 1002 public String getCreateMySQL(int size) { 1003 return getCreateMySQL(size, SQLManager.this.CREATE_SETTINGS, 1); 1004 } 1005 1006 @Override 1007 public String getCreateSQLite(int size) { 1008 return getCreateSQLite(size, "INSERT INTO `" + SQLManager.this.prefix 1009 + "plot_settings` SELECT ? AS `plot_plot_id`, ? AS `biome`, ? AS `rain`, ? AS `custom_time`, ? AS `time`, ? AS " 1010 + "`deny_entry`, ? AS `alias`, ? AS `merged`, ? AS `position` ", 10); 1011 } 1012 1013 @Override 1014 public String getCreateSQL() { 1015 return "INSERT INTO `" + SQLManager.this.prefix 1016 + "plot_settings`(`plot_plot_id`) VALUES(?)"; 1017 } 1018 1019 @Override 1020 public void setMySQL(PreparedStatement stmt, int i, Integer id) 1021 throws SQLException { 1022 stmt.setInt(i + 1, id); 1023 } 1024 1025 @Override 1026 public void setSQLite(PreparedStatement stmt, int i, Integer id) 1027 throws SQLException { 1028 stmt.setInt(i * 10 + 1, id); 1029 stmt.setNull(i * 10 + 2, 4); 1030 stmt.setNull(i * 10 + 3, 4); 1031 stmt.setNull(i * 10 + 4, 4); 1032 stmt.setNull(i * 10 + 5, 4); 1033 stmt.setNull(i * 10 + 6, 4); 1034 stmt.setNull(i * 10 + 7, 4); 1035 stmt.setNull(i * 10 + 8, 4); 1036 stmt.setString(i * 10 + 9, "DEFAULT"); 1037 } 1038 1039 @Override 1040 public void setSQL(PreparedStatement stmt, Integer id) throws SQLException { 1041 stmt.setInt(1, id); 1042 } 1043 }; 1044 addGlobalTask(() -> setBulk(myList, mod, whenDone)); 1045 } 1046 1047 public void createPlotSafe(final Plot plot, final Runnable success, final Runnable failure) { 1048 addPlotTask(plot, new UniqueStatement("createPlotSafe_" + plot.hashCode()) { 1049 @Override 1050 public void set(PreparedStatement statement) throws SQLException { 1051 statement.setInt(1, plot.getId().getX()); 1052 statement.setInt(2, plot.getId().getY()); 1053 statement.setString(3, plot.getOwnerAbs().toString()); 1054 statement.setString(4, plot.getArea().toString()); 1055 statement.setTimestamp(5, new Timestamp(plot.getTimestamp())); 1056 statement.setString(6, plot.getArea().toString()); 1057 statement.setInt(7, plot.getId().getX()); 1058 statement.setInt(8, plot.getId().getY()); 1059 } 1060 1061 @Override 1062 public PreparedStatement get() throws SQLException { 1063 return SQLManager.this.connection.prepareStatement( 1064 SQLManager.this.CREATE_PLOT_SAFE, 1065 Statement.RETURN_GENERATED_KEYS 1066 ); 1067 } 1068 1069 @Override 1070 public void execute(PreparedStatement statement) { 1071 1072 } 1073 1074 @Override 1075 public void addBatch(PreparedStatement statement) throws SQLException { 1076 int inserted = statement.executeUpdate(); 1077 if (inserted > 0) { 1078 try (ResultSet keys = statement.getGeneratedKeys()) { 1079 if (keys.next()) { 1080 plot.temp = keys.getInt(1); 1081 addPlotTask(plot, new UniqueStatement( 1082 "createPlotAndSettings_settings_" + plot.hashCode()) { 1083 @Override 1084 public void set(PreparedStatement statement) 1085 throws SQLException { 1086 statement.setInt(1, getId(plot)); 1087 } 1088 1089 @Override 1090 public PreparedStatement get() throws SQLException { 1091 return SQLManager.this.connection.prepareStatement( 1092 "INSERT INTO `" + SQLManager.this.prefix 1093 + "plot_settings`(`plot_plot_id`) VALUES(?)"); 1094 } 1095 }); 1096 if (success != null) { 1097 addNotifyTask(success); 1098 } 1099 return; 1100 } 1101 } 1102 } 1103 if (failure != null) { 1104 failure.run(); 1105 } 1106 } 1107 }); 1108 } 1109 1110 public void commit() { 1111 if (this.closed) { 1112 return; 1113 } 1114 try { 1115 if (!this.connection.getAutoCommit()) { 1116 this.connection.commit(); 1117 this.connection.setAutoCommit(true); 1118 } 1119 } catch (SQLException e) { 1120 e.printStackTrace(); 1121 } 1122 } 1123 1124 @Override 1125 public void createPlotAndSettings(final Plot plot, Runnable whenDone) { 1126 addPlotTask(plot, new UniqueStatement("createPlotAndSettings_" + plot.hashCode()) { 1127 @Override 1128 public void set(PreparedStatement statement) throws SQLException { 1129 statement.setInt(1, plot.getId().getX()); 1130 statement.setInt(2, plot.getId().getY()); 1131 statement.setString(3, plot.getOwnerAbs().toString()); 1132 statement.setString(4, plot.getArea().toString()); 1133 statement.setTimestamp(5, new Timestamp(plot.getTimestamp())); 1134 } 1135 1136 @Override 1137 public PreparedStatement get() throws SQLException { 1138 return SQLManager.this.connection 1139 .prepareStatement(SQLManager.this.CREATE_PLOT, Statement.RETURN_GENERATED_KEYS); 1140 } 1141 1142 @Override 1143 public void execute(PreparedStatement statement) { 1144 } 1145 1146 @Override 1147 public void addBatch(PreparedStatement statement) throws SQLException { 1148 statement.executeUpdate(); 1149 try (ResultSet keys = statement.getGeneratedKeys()) { 1150 if (keys.next()) { 1151 plot.temp = keys.getInt(1); 1152 } 1153 } 1154 } 1155 }); 1156 addPlotTask(plot, new UniqueStatement("createPlotAndSettings_settings_" + plot.hashCode()) { 1157 @Override 1158 public void set(PreparedStatement statement) throws SQLException { 1159 statement.setInt(1, getId(plot)); 1160 } 1161 1162 @Override 1163 public PreparedStatement get() throws SQLException { 1164 return SQLManager.this.connection.prepareStatement( 1165 "INSERT INTO `" + SQLManager.this.prefix 1166 + "plot_settings`(`plot_plot_id`) VALUES(?)"); 1167 } 1168 }); 1169 addNotifyTask(whenDone); 1170 } 1171 1172 /** 1173 * Create tables. 1174 * 1175 * @throws SQLException 1176 */ 1177 @Override 1178 public void createTables() throws SQLException { 1179 String[] tables = 1180 new String[]{"plot", "plot_denied", "plot_helpers", "plot_comments", "plot_trusted", 1181 "plot_rating", "plot_settings", "cluster", "player_meta", "plot_flags"}; 1182 DatabaseMetaData meta = this.connection.getMetaData(); 1183 int create = 0; 1184 for (String s : tables) { 1185 ResultSet set = meta.getTables(null, null, this.prefix + s, new String[]{"TABLE"}); 1186 // ResultSet set = meta.getTables(null, null, prefix + s, null); 1187 if (!set.next()) { 1188 create++; 1189 } 1190 set.close(); 1191 } 1192 if (create == 0) { 1193 return; 1194 } 1195 boolean addConstraint = create == tables.length; 1196 try (Statement stmt = this.connection.createStatement()) { 1197 if (this.mySQL) { 1198 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot` (" 1199 + "`id` INT(11) NOT NULL AUTO_INCREMENT," + "`plot_id_x` INT(11) NOT NULL," 1200 + "`plot_id_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," 1201 + "`world` VARCHAR(45) NOT NULL," 1202 + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP," 1203 + "PRIMARY KEY (`id`)" 1204 + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=0"); 1205 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix 1206 + "plot_denied` (`plot_plot_id` INT(11) NOT NULL," 1207 + "`user_uuid` VARCHAR(40) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8"); 1208 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_helpers` (" 1209 + "`plot_plot_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" 1210 + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); 1211 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" 1212 + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," 1213 + "`comment` VARCHAR(40) NOT NULL," + "`inbox` VARCHAR(40) NOT NULL," 1214 + "`timestamp` INT(11) NOT NULL," + "`sender` VARCHAR(40) NOT NULL" 1215 + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); 1216 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_trusted` (" 1217 + "`plot_plot_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" 1218 + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); 1219 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_settings` (" 1220 + " `plot_plot_id` INT(11) NOT NULL," 1221 + " `biome` VARCHAR(45) DEFAULT 'FOREST'," + " `rain` INT(1) DEFAULT 0," 1222 + " `custom_time` TINYINT(1) DEFAULT '0'," + " `time` INT(11) DEFAULT '8000'," 1223 + " `deny_entry` TINYINT(1) DEFAULT '0'," 1224 + " `alias` VARCHAR(50) DEFAULT NULL," + " `merged` INT(11) DEFAULT NULL," 1225 + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," 1226 + " PRIMARY KEY (`plot_plot_id`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); 1227 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix 1228 + "plot_rating` ( `plot_plot_id` INT(11) NOT NULL, `rating` INT(2) NOT NULL, `player` VARCHAR(40) NOT NULL) ENGINE=InnoDB " 1229 + "DEFAULT CHARSET=utf8"); 1230 if (addConstraint) { 1231 stmt.addBatch("ALTER TABLE `" + this.prefix + "plot_settings` ADD CONSTRAINT `" 1232 + this.prefix 1233 + "plot_settings_ibfk_1` FOREIGN KEY (`plot_plot_id`) REFERENCES `" 1234 + this.prefix + "plot` (`id`) ON DELETE CASCADE"); 1235 } 1236 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster` (" 1237 + "`id` INT(11) NOT NULL AUTO_INCREMENT," + "`pos1_x` INT(11) NOT NULL," 1238 + "`pos1_z` INT(11) NOT NULL," + "`pos2_x` INT(11) NOT NULL," 1239 + "`pos2_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," 1240 + "`world` VARCHAR(45) NOT NULL," 1241 + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP," 1242 + "PRIMARY KEY (`id`)" 1243 + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=0"); 1244 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_helpers` (" 1245 + "`cluster_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" 1246 + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); 1247 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_invited` (" 1248 + "`cluster_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" 1249 + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); 1250 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_settings` (" 1251 + " `cluster_id` INT(11) NOT NULL," + " `biome` VARCHAR(45) DEFAULT 'FOREST'," 1252 + " `rain` INT(1) DEFAULT 0," + " `custom_time` TINYINT(1) DEFAULT '0'," 1253 + " `time` INT(11) DEFAULT '8000'," + " `deny_entry` TINYINT(1) DEFAULT '0'," 1254 + " `alias` VARCHAR(50) DEFAULT NULL," + " `merged` INT(11) DEFAULT NULL," 1255 + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," 1256 + " PRIMARY KEY (`cluster_id`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); 1257 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "player_meta` (" 1258 + " `meta_id` INT(11) NOT NULL AUTO_INCREMENT," 1259 + " `uuid` VARCHAR(40) NOT NULL," + " `key` VARCHAR(32) NOT NULL," 1260 + " `value` blob NOT NULL," + " PRIMARY KEY (`meta_id`)" 1261 + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); 1262 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_flags`(" 1263 + "`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY," 1264 + "`plot_id` INT(11) NOT NULL," + " `flag` VARCHAR(64)," 1265 + " `value` VARCHAR(512)," + "FOREIGN KEY (plot_id) REFERENCES `" + this.prefix 1266 + "plot` (id) ON DELETE CASCADE, " + "UNIQUE (plot_id, flag)" 1267 + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); 1268 } else { 1269 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot` (" 1270 + "`id` INTEGER PRIMARY KEY AUTOINCREMENT," + "`plot_id_x` INT(11) NOT NULL," 1271 + "`plot_id_z` INT(11) NOT NULL," + "`owner` VARCHAR(45) NOT NULL," 1272 + "`world` VARCHAR(45) NOT NULL," 1273 + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP)"); 1274 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix 1275 + "plot_denied` (`plot_plot_id` INT(11) NOT NULL," 1276 + "`user_uuid` VARCHAR(40) NOT NULL)"); 1277 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix 1278 + "plot_helpers` (`plot_plot_id` INT(11) NOT NULL," 1279 + "`user_uuid` VARCHAR(40) NOT NULL)"); 1280 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix 1281 + "plot_trusted` (`plot_plot_id` INT(11) NOT NULL," 1282 + "`user_uuid` VARCHAR(40) NOT NULL)"); 1283 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" 1284 + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," 1285 + "`comment` VARCHAR(40) NOT NULL," 1286 + "`inbox` VARCHAR(40) NOT NULL, `timestamp` INT(11) NOT NULL," 1287 + "`sender` VARCHAR(40) NOT NULL" + ')'); 1288 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_settings` (" 1289 + " `plot_plot_id` INT(11) NOT NULL," 1290 + " `biome` VARCHAR(45) DEFAULT 'FOREST'," + " `rain` INT(1) DEFAULT 0," 1291 + " `custom_time` TINYINT(1) DEFAULT '0'," + " `time` INT(11) DEFAULT '8000'," 1292 + " `deny_entry` TINYINT(1) DEFAULT '0'," 1293 + " `alias` VARCHAR(50) DEFAULT NULL," + " `merged` INT(11) DEFAULT NULL," 1294 + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," 1295 + " PRIMARY KEY (`plot_plot_id`)" + ')'); 1296 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix 1297 + "plot_rating` (`plot_plot_id` INT(11) NOT NULL, `rating` INT(2) NOT NULL, `player` VARCHAR(40) NOT NULL)"); 1298 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster` (" 1299 + "`id` INTEGER PRIMARY KEY AUTOINCREMENT," + "`pos1_x` INT(11) NOT NULL," 1300 + "`pos1_z` INT(11) NOT NULL," + "`pos2_x` INT(11) NOT NULL," 1301 + "`pos2_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," 1302 + "`world` VARCHAR(45) NOT NULL," 1303 + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP" + ')'); 1304 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix 1305 + "cluster_helpers` (`cluster_id` INT(11) NOT NULL," 1306 + "`user_uuid` VARCHAR(40) NOT NULL)"); 1307 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix 1308 + "cluster_invited` (`cluster_id` INT(11) NOT NULL," 1309 + "`user_uuid` VARCHAR(40) NOT NULL)"); 1310 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_settings` (" 1311 + " `cluster_id` INT(11) NOT NULL," + " `biome` VARCHAR(45) DEFAULT 'FOREST'," 1312 + " `rain` INT(1) DEFAULT 0," + " `custom_time` TINYINT(1) DEFAULT '0'," 1313 + " `time` INT(11) DEFAULT '8000'," + " `deny_entry` TINYINT(1) DEFAULT '0'," 1314 + " `alias` VARCHAR(50) DEFAULT NULL," + " `merged` INT(11) DEFAULT NULL," 1315 + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," 1316 + " PRIMARY KEY (`cluster_id`)" + ')'); 1317 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "player_meta` (" 1318 + " `meta_id` INTEGER PRIMARY KEY AUTOINCREMENT," 1319 + " `uuid` VARCHAR(40) NOT NULL," + " `key` VARCHAR(32) NOT NULL," 1320 + " `value` blob NOT NULL" + ')'); 1321 stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_flags`(" 1322 + "`id` INTEGER PRIMARY KEY AUTOINCREMENT," + "`plot_id` INTEGER NOT NULL," 1323 + " `flag` VARCHAR(64)," + " `value` VARCHAR(512)," 1324 + "FOREIGN KEY (plot_id) REFERENCES `" + this.prefix 1325 + "plot` (id) ON DELETE CASCADE, " + "UNIQUE (plot_id, flag))"); 1326 } 1327 stmt.executeBatch(); 1328 stmt.clearBatch(); 1329 } 1330 } 1331 1332 @Override 1333 public void deleteSettings(final Plot plot) { 1334 addPlotTask(plot, new UniqueStatement("delete_plot_settings") { 1335 @Override 1336 public void set(PreparedStatement statement) throws SQLException { 1337 statement.setInt(1, getId(plot)); 1338 } 1339 1340 @Override 1341 public PreparedStatement get() throws SQLException { 1342 return SQLManager.this.connection.prepareStatement( 1343 "DELETE FROM `" + SQLManager.this.prefix 1344 + "plot_settings` WHERE `plot_plot_id` = ?"); 1345 } 1346 }); 1347 } 1348 1349 @Override 1350 public void deleteHelpers(final Plot plot) { 1351 if (plot.getTrusted().isEmpty()) { 1352 return; 1353 } 1354 addPlotTask(plot, new UniqueStatement("delete_plot_helpers") { 1355 @Override 1356 public void set(PreparedStatement statement) throws SQLException { 1357 statement.setInt(1, getId(plot)); 1358 } 1359 1360 @Override 1361 public PreparedStatement get() throws SQLException { 1362 return SQLManager.this.connection.prepareStatement( 1363 "DELETE FROM `" + SQLManager.this.prefix 1364 + "plot_helpers` WHERE `plot_plot_id` = ?"); 1365 } 1366 }); 1367 } 1368 1369 @Override 1370 public void deleteTrusted(final Plot plot) { 1371 if (plot.getMembers().isEmpty()) { 1372 return; 1373 } 1374 addPlotTask(plot, new UniqueStatement("delete_plot_trusted") { 1375 @Override 1376 public void set(PreparedStatement statement) throws SQLException { 1377 statement.setInt(1, getId(plot)); 1378 } 1379 1380 @Override 1381 public PreparedStatement get() throws SQLException { 1382 return SQLManager.this.connection.prepareStatement( 1383 "DELETE FROM `" + SQLManager.this.prefix 1384 + "plot_trusted` WHERE `plot_plot_id` = ?"); 1385 } 1386 }); 1387 } 1388 1389 @Override 1390 public void deleteDenied(final Plot plot) { 1391 if (plot.getDenied().isEmpty()) { 1392 return; 1393 } 1394 addPlotTask(plot, new UniqueStatement("delete_plot_denied") { 1395 @Override 1396 public void set(PreparedStatement statement) throws SQLException { 1397 statement.setInt(1, getId(plot)); 1398 } 1399 1400 @Override 1401 public PreparedStatement get() throws SQLException { 1402 return SQLManager.this.connection.prepareStatement( 1403 "DELETE FROM `" + SQLManager.this.prefix 1404 + "plot_denied` WHERE `plot_plot_id` = ?"); 1405 } 1406 }); 1407 } 1408 1409 @Override 1410 public void deleteComments(final Plot plot) { 1411 addPlotTask(plot, new UniqueStatement("delete_plot_comments") { 1412 @Override 1413 public void set(PreparedStatement statement) throws SQLException { 1414 statement.setString(1, plot.getArea().toString()); 1415 statement.setInt(2, plot.hashCode()); 1416 } 1417 1418 @Override 1419 public PreparedStatement get() throws SQLException { 1420 return SQLManager.this.connection.prepareStatement( 1421 "DELETE FROM `" + SQLManager.this.prefix 1422 + "plot_comments` WHERE `world` = ? AND `hashcode` = ?"); 1423 } 1424 }); 1425 } 1426 1427 @Override 1428 public void deleteRatings(final Plot plot) { 1429 if (Settings.Enabled_Components.RATING_CACHE && plot.getSettings().getRatings().isEmpty()) { 1430 return; 1431 } 1432 addPlotTask(plot, new UniqueStatement("delete_plot_ratings") { 1433 @Override 1434 public void set(PreparedStatement statement) throws SQLException { 1435 statement.setInt(1, getId(plot)); 1436 } 1437 1438 @Override 1439 public PreparedStatement get() throws SQLException { 1440 return SQLManager.this.connection.prepareStatement( 1441 "DELETE FROM `" + SQLManager.this.prefix 1442 + "plot_rating` WHERE `plot_plot_id` = ?"); 1443 } 1444 }); 1445 } 1446 1447 /** 1448 * Delete a plot. 1449 * 1450 * @param plot 1451 */ 1452 @Override 1453 public void delete(final Plot plot) { 1454 deleteSettings(plot); 1455 deleteDenied(plot); 1456 deleteHelpers(plot); 1457 deleteTrusted(plot); 1458 deleteComments(plot); 1459 deleteRatings(plot); 1460 addPlotTask(plot, new UniqueStatement("delete_plot") { 1461 @Override 1462 public void set(PreparedStatement statement) throws SQLException { 1463 statement.setInt(1, getId(plot)); 1464 } 1465 1466 @Override 1467 public PreparedStatement get() throws SQLException { 1468 return SQLManager.this.connection.prepareStatement( 1469 "DELETE FROM `" + SQLManager.this.prefix + "plot` WHERE `id` = ?"); 1470 } 1471 }); 1472 } 1473 1474 /** 1475 * Creates plot settings 1476 * 1477 * @param id 1478 * @param plot 1479 */ 1480 @Override 1481 public void createPlotSettings(final int id, Plot plot) { 1482 addPlotTask(plot, new UniqueStatement("createPlotSettings") { 1483 @Override 1484 public void set(PreparedStatement statement) throws SQLException { 1485 statement.setInt(1, id); 1486 } 1487 1488 @Override 1489 public PreparedStatement get() throws SQLException { 1490 return SQLManager.this.connection.prepareStatement( 1491 "INSERT INTO `" + SQLManager.this.prefix 1492 + "plot_settings`(`plot_plot_id`) VALUES(?)"); 1493 } 1494 }); 1495 } 1496 1497 @Override 1498 public int getClusterId(PlotCluster cluster) { 1499 if (cluster.temp > 0) { 1500 return cluster.temp; 1501 } 1502 try { 1503 commit(); 1504 if (cluster.temp > 0) { 1505 return cluster.temp; 1506 } 1507 int c_id; 1508 try (PreparedStatement stmt = this.connection.prepareStatement( 1509 "SELECT `id` FROM `" + this.prefix 1510 + "cluster` WHERE `pos1_x` = ? AND `pos1_z` = ? AND `pos2_x` = ? AND `pos2_z` = ? AND `world` = ? ORDER BY `timestamp` ASC")) { 1511 stmt.setInt(1, cluster.getP1().getX()); 1512 stmt.setInt(2, cluster.getP1().getY()); 1513 stmt.setInt(3, cluster.getP2().getX()); 1514 stmt.setInt(4, cluster.getP2().getY()); 1515 stmt.setString(5, cluster.area.toString()); 1516 try (ResultSet resultSet = stmt.executeQuery()) { 1517 c_id = Integer.MAX_VALUE; 1518 while (resultSet.next()) { 1519 c_id = resultSet.getInt("id"); 1520 } 1521 } 1522 } 1523 if (c_id == Integer.MAX_VALUE || c_id == 0) { 1524 if (cluster.temp > 0) { 1525 return cluster.temp; 1526 } 1527 throw new SQLException("Cluster does not exist in database"); 1528 } 1529 cluster.temp = c_id; 1530 return c_id; 1531 } catch (SQLException e) { 1532 e.printStackTrace(); 1533 } 1534 return Integer.MAX_VALUE; 1535 } 1536 1537 @Override 1538 public int getId(Plot plot) { 1539 if (plot.temp > 0) { 1540 return plot.temp; 1541 } 1542 try { 1543 commit(); 1544 if (plot.temp > 0) { 1545 return plot.temp; 1546 } 1547 int id; 1548 try (PreparedStatement statement = this.connection.prepareStatement( 1549 "SELECT `id` FROM `" + this.prefix 1550 + "plot` WHERE `plot_id_x` = ? AND `plot_id_z` = ? AND world = ? ORDER BY `timestamp` ASC")) { 1551 statement.setInt(1, plot.getId().getX()); 1552 statement.setInt(2, plot.getId().getY()); 1553 statement.setString(3, plot.getArea().toString()); 1554 try (ResultSet resultSet = statement.executeQuery()) { 1555 id = Integer.MAX_VALUE; 1556 while (resultSet.next()) { 1557 id = resultSet.getInt("id"); 1558 } 1559 } 1560 } 1561 if (id == Integer.MAX_VALUE || id == 0) { 1562 if (plot.temp > 0) { 1563 return plot.temp; 1564 } 1565 throw new SQLException("Plot does not exist in database"); 1566 } 1567 plot.temp = id; 1568 return id; 1569 } catch (SQLException e) { 1570 e.printStackTrace(); 1571 } 1572 return Integer.MAX_VALUE; 1573 } 1574 1575 @Override 1576 public void updateTables(int[] oldVersion) { 1577 try { 1578 if (this.mySQL && !PlotSquared.get().checkVersion(oldVersion, 3, 3, 2)) { 1579 try (Statement stmt = this.connection.createStatement()) { 1580 stmt.executeUpdate( 1581 "ALTER TABLE `" + this.prefix + "plots` DROP INDEX `unique_alias`"); 1582 } catch (SQLException ignored) { 1583 } 1584 } 1585 DatabaseMetaData data = this.connection.getMetaData(); 1586 ResultSet rs = 1587 data.getColumns(null, null, this.prefix + "plot_comments", "plot_plot_id"); 1588 if (rs.next()) { 1589 rs.close(); 1590 rs = data.getColumns(null, null, this.prefix + "plot_comments", "hashcode"); 1591 if (!rs.next()) { 1592 rs.close(); 1593 try (Statement statement = this.connection.createStatement()) { 1594 statement.addBatch("DROP TABLE `" + this.prefix + "plot_comments`"); 1595 if (Storage.MySQL.USE) { 1596 statement.addBatch( 1597 "CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" 1598 + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," 1599 + "`comment` VARCHAR(40) NOT NULL," 1600 + "`inbox` VARCHAR(40) NOT NULL," 1601 + "`timestamp` INT(11) NOT NULL," 1602 + "`sender` VARCHAR(40) NOT NULL" 1603 + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); 1604 } else { 1605 statement.addBatch( 1606 "CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" 1607 + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," 1608 + "`comment` VARCHAR(40) NOT NULL," 1609 + "`inbox` VARCHAR(40) NOT NULL, `timestamp` INT(11) NOT NULL," 1610 + "`sender` VARCHAR(40) NOT NULL" + ')'); 1611 } 1612 statement.executeBatch(); 1613 } catch (SQLException ignored) { 1614 try (Statement statement = this.connection.createStatement()) { 1615 statement.addBatch("ALTER IGNORE TABLE `" + this.prefix 1616 + "plot_comments` ADD `inbox` VARCHAR(11) DEFAULT `public`"); 1617 statement.addBatch("ALTER IGNORE TABLE `" + this.prefix 1618 + "plot_comments` ADD `timestamp` INT(11) DEFAULT 0"); 1619 statement.addBatch("ALTER TABLE `" + this.prefix + "plot` DROP `tier`"); 1620 statement.executeBatch(); 1621 } 1622 } 1623 } 1624 } 1625 rs.close(); 1626 rs = data.getColumns(null, null, this.prefix + "plot_denied", "plot_plot_id"); 1627 if (rs.next()) { 1628 try (Statement statement = this.connection.createStatement()) { 1629 statement.executeUpdate("DELETE FROM `" + this.prefix 1630 + "plot_denied` WHERE `plot_plot_id` NOT IN (SELECT `id` FROM `" 1631 + this.prefix + "plot`)"); 1632 } catch (SQLException e) { 1633 e.printStackTrace(); 1634 } 1635 1636 rs.close(); 1637 try (Statement statement = this.connection.createStatement()) { 1638 for (String table : new String[]{"plot_denied", "plot_helpers", 1639 "plot_trusted"}) { 1640 ResultSet result = statement.executeQuery( 1641 "SELECT plot_plot_id, user_uuid, COUNT(*) FROM " + this.prefix + table 1642 + " GROUP BY plot_plot_id, user_uuid HAVING COUNT(*) > 1"); 1643 if (result.next()) { 1644 result.close(); 1645 statement.executeUpdate( 1646 "CREATE TABLE " + this.prefix + table + "_tmp AS SELECT * FROM " 1647 + this.prefix + table + " GROUP BY plot_plot_id, user_uuid"); 1648 statement.executeUpdate("DROP TABLE " + this.prefix + table); 1649 statement.executeUpdate( 1650 "CREATE TABLE " + this.prefix + table + " AS SELECT * FROM " 1651 + this.prefix + table + "_tmp"); 1652 statement.executeUpdate("DROP TABLE " + this.prefix + table + "_tmp"); 1653 } 1654 } 1655 } catch (SQLException e2) { 1656 e2.printStackTrace(); 1657 } 1658 } 1659 } catch (SQLException e) { 1660 e.printStackTrace(); 1661 } 1662 1663 } 1664 1665 public void deleteRows(ArrayList<Integer> rowIds, final String table, final String column) { 1666 setBulk(rowIds, new StmtMod<>() { 1667 1668 @Override 1669 public String getCreateMySQL(int size) { 1670 return getCreateMySQL(1, "DELETE FROM `" + table + "` WHERE `" + column + "` IN ", 1671 size 1672 ); 1673 } 1674 1675 @Override 1676 public String getCreateSQLite(int size) { 1677 return getCreateMySQL(1, "DELETE FROM `" + table + "` WHERE `" + column + "` IN ", 1678 size 1679 ); 1680 } 1681 1682 @Override 1683 public String getCreateSQL() { 1684 return "DELETE FROM `" + table + "` WHERE `" + column + "` = ?"; 1685 } 1686 1687 @Override 1688 public void setMySQL(PreparedStatement stmt, int i, Integer obj) 1689 throws SQLException { 1690 stmt.setInt(i + 1, obj); 1691 } 1692 1693 @Override 1694 public void setSQLite(PreparedStatement stmt, int i, Integer obj) 1695 throws SQLException { 1696 stmt.setInt(i + 1, obj); 1697 } 1698 1699 @Override 1700 public void setSQL(PreparedStatement stmt, Integer obj) throws SQLException { 1701 stmt.setInt(1, obj); 1702 } 1703 }, null); 1704 } 1705 1706 @Override 1707 public boolean convertFlags() { 1708 final Map<Integer, Map<String, String>> flagMap = new HashMap<>(); 1709 try (Statement statement = this.connection.createStatement()) { 1710 try (ResultSet resultSet = statement 1711 .executeQuery("SELECT * FROM `" + this.prefix + "plot_settings`")) { 1712 while (resultSet.next()) { 1713 final int id = resultSet.getInt("plot_plot_id"); 1714 final String plotFlags = resultSet.getString("flags"); 1715 if (plotFlags == null || plotFlags.isEmpty()) { 1716 continue; 1717 } 1718 flagMap.put(id, new HashMap<>()); 1719 for (String element : plotFlags.split(",")) { 1720 if (element.contains(":")) { 1721 String[] split = element.split(":"); // splits flag:value 1722 try { 1723 String flag_str = 1724 split[1].replaceAll("¯", ":").replaceAll("\u00B4", ","); 1725 flagMap.get(id).put(split[0], flag_str); 1726 } catch (Exception e) { 1727 e.printStackTrace(); 1728 } 1729 } 1730 } 1731 } 1732 } 1733 } catch (final Exception e) { 1734 LOGGER.error("Failed to load old flag values", e); 1735 return false; 1736 } 1737 LOGGER.info("Loaded {} plot flag collections...", flagMap.size()); 1738 LOGGER.info("Attempting to store these flags in the new table..."); 1739 try (final PreparedStatement preparedStatement = this.connection.prepareStatement( 1740 "INSERT INTO `" + SQLManager.this.prefix 1741 + "plot_flags`(`plot_id`, `flag`, `value`) VALUES(?, ?, ?)")) { 1742 1743 long timeStarted = System.currentTimeMillis(); 1744 int flagsProcessed = 0; 1745 int plotsProcessed = 0; 1746 1747 int totalFlags = 0; 1748 for (final Map<String, String> flags : flagMap.values()) { 1749 totalFlags += flags.size(); 1750 } 1751 1752 for (final Map.Entry<Integer, Map<String, String>> plotFlagEntry : flagMap.entrySet()) { 1753 for (final Map.Entry<String, String> flagEntry : plotFlagEntry.getValue() 1754 .entrySet()) { 1755 preparedStatement.setInt(1, plotFlagEntry.getKey()); 1756 preparedStatement.setString(2, flagEntry.getKey()); 1757 preparedStatement.setString(3, flagEntry.getValue()); 1758 preparedStatement.addBatch(); 1759 flagsProcessed += 1; 1760 } 1761 plotsProcessed += 1; 1762 1763 try { 1764 preparedStatement.executeBatch(); 1765 } catch (final Exception e) { 1766 LOGGER.error("Failed to store flag values for plot with entry ID: {}", plotFlagEntry.getKey()); 1767 e.printStackTrace(); 1768 continue; 1769 } 1770 1771 if (System.currentTimeMillis() - timeStarted >= 1000L || plotsProcessed >= flagMap 1772 .size()) { 1773 timeStarted = System.currentTimeMillis(); 1774 LOGGER.info( 1775 "... Flag conversion in progress. {}% done", 1776 String.format("%.1f", ((float) flagsProcessed / totalFlags) * 100) 1777 ); 1778 } 1779 LOGGER.info( 1780 "- Finished converting flags for plot with entry ID: {}", 1781 plotFlagEntry.getKey() 1782 ); 1783 } 1784 } catch (final Exception e) { 1785 LOGGER.error("Failed to store flag values", e); 1786 return false; 1787 } 1788 return true; 1789 } 1790 1791 /** 1792 * Load all plots, helpers, denied, trusted, and every setting from DB into a {@link HashMap}. 1793 */ 1794 @Override 1795 public HashMap<String, HashMap<PlotId, Plot>> getPlots() { 1796 HashMap<String, HashMap<PlotId, Plot>> newPlots = new HashMap<>(); 1797 HashMap<Integer, Plot> plots = new HashMap<>(); 1798 try { 1799 HashSet<String> areas = new HashSet<>(); 1800 if (this.worldConfiguration.contains("worlds")) { 1801 ConfigurationSection worldSection = this.worldConfiguration.getConfigurationSection("worlds"); 1802 if (worldSection != null) { 1803 for (String worldKey : worldSection.getKeys(false)) { 1804 areas.add(worldKey); 1805 ConfigurationSection areaSection = 1806 worldSection.getConfigurationSection(worldKey + ".areas"); 1807 if (areaSection != null) { 1808 for (String areaKey : areaSection.getKeys(false)) { 1809 String[] split = areaKey.split("(?<![;])-"); 1810 if (split.length == 3) { 1811 areas.add(worldKey + ';' + split[0]); 1812 } 1813 } 1814 } 1815 } 1816 } 1817 } 1818 HashMap<String, UUID> uuids = new HashMap<>(); 1819 HashMap<String, AtomicInteger> noExist = new HashMap<>(); 1820 1821 /* 1822 * Getting plots 1823 */ 1824 try (Statement statement = this.connection.createStatement()) { 1825 int id; 1826 String o; 1827 UUID user; 1828 try (ResultSet resultSet = statement.executeQuery( 1829 "SELECT `id`, `plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp` FROM `" 1830 + this.prefix + "plot`")) { 1831 ArrayList<Integer> toDelete = new ArrayList<>(); 1832 while (resultSet.next()) { 1833 PlotId plot_id = PlotId.of( 1834 resultSet.getInt("plot_id_x"), 1835 resultSet.getInt("plot_id_z") 1836 ); 1837 id = resultSet.getInt("id"); 1838 String areaID = resultSet.getString("world"); 1839 if (!areas.contains(areaID)) { 1840 if (Settings.Enabled_Components.DATABASE_PURGER) { 1841 toDelete.add(id); 1842 continue; 1843 } else { 1844 AtomicInteger value = noExist.get(areaID); 1845 if (value != null) { 1846 value.incrementAndGet(); 1847 } else { 1848 noExist.put(areaID, new AtomicInteger(1)); 1849 } 1850 } 1851 } 1852 o = resultSet.getString("owner"); 1853 user = uuids.get(o); 1854 if (user == null) { 1855 try { 1856 user = UUID.fromString(o); 1857 } catch (IllegalArgumentException e) { 1858 if (Settings.UUID.FORCE_LOWERCASE) { 1859 user = UUID.nameUUIDFromBytes( 1860 ("OfflinePlayer:" + o.toLowerCase()) 1861 .getBytes(Charsets.UTF_8)); 1862 } else { 1863 user = UUID.nameUUIDFromBytes( 1864 ("OfflinePlayer:" + o).getBytes(Charsets.UTF_8)); 1865 } 1866 } 1867 uuids.put(o, user); 1868 } 1869 long time; 1870 try { 1871 Timestamp timestamp = resultSet.getTimestamp("timestamp"); 1872 time = timestamp.getTime(); 1873 } catch (SQLException exception) { 1874 String parsable = resultSet.getString("timestamp"); 1875 try { 1876 time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(parsable) 1877 .getTime(); 1878 } catch (ParseException e) { 1879 LOGGER.error("Could not parse date for plot: #{}({};{}) ({})", 1880 id, areaID, plot_id, parsable 1881 ); 1882 time = System.currentTimeMillis() + id; 1883 } 1884 } 1885 Plot p = new Plot(plot_id, user, new HashSet<>(), new HashSet<>(), 1886 new HashSet<>(), "", null, null, null, 1887 new boolean[]{false, false, false, false}, time, id 1888 ); 1889 HashMap<PlotId, Plot> map = newPlots.get(areaID); 1890 if (map != null) { 1891 Plot last = map.put(p.getId(), p); 1892 if (last != null) { 1893 if (Settings.Enabled_Components.DATABASE_PURGER) { 1894 toDelete.add(last.temp); 1895 } else { 1896 LOGGER.info( 1897 "Plot #{}({}) in `{}plot` is a duplicate." 1898 + " Delete this plot or set `database-purger: true` in the settings.yml", 1899 id, 1900 last, 1901 this.prefix 1902 ); 1903 } 1904 } 1905 } else { 1906 map = new HashMap<>(); 1907 newPlots.put(areaID, map); 1908 map.put(p.getId(), p); 1909 } 1910 plots.put(id, p); 1911 } 1912 deleteRows(toDelete, this.prefix + "plot", "id"); 1913 } 1914 if (Settings.Enabled_Components.RATING_CACHE) { 1915 try (ResultSet r = statement.executeQuery( 1916 "SELECT `plot_plot_id`, `player`, `rating` FROM `" + this.prefix 1917 + "plot_rating`")) { 1918 ArrayList<Integer> toDelete = new ArrayList<>(); 1919 while (r.next()) { 1920 id = r.getInt("plot_plot_id"); 1921 o = r.getString("player"); 1922 user = uuids.get(o); 1923 if (user == null) { 1924 user = UUID.fromString(o); 1925 uuids.put(o, user); 1926 } 1927 Plot plot = plots.get(id); 1928 if (plot != null) { 1929 plot.getSettings().getRatings().put(user, r.getInt("rating")); 1930 } else if (Settings.Enabled_Components.DATABASE_PURGER) { 1931 toDelete.add(id); 1932 } else { 1933 LOGGER.warn("Entry #{}({}) in `plot_rating` does not exist." 1934 + " Create this plot or set `database-purger: true` in settings.yml", id, plot); 1935 } 1936 } 1937 deleteRows(toDelete, this.prefix + "plot_rating", "plot_plot_id"); 1938 } 1939 } 1940 1941 /* 1942 * Getting helpers 1943 */ 1944 try (ResultSet r = statement.executeQuery( 1945 "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_helpers`")) { 1946 ArrayList<Integer> toDelete = new ArrayList<>(); 1947 while (r.next()) { 1948 id = r.getInt("plot_plot_id"); 1949 o = r.getString("user_uuid"); 1950 user = uuids.get(o); 1951 if (user == null) { 1952 user = UUID.fromString(o); 1953 uuids.put(o, user); 1954 } 1955 Plot plot = plots.get(id); 1956 if (plot != null) { 1957 plot.getTrusted().add(user); 1958 } else if (Settings.Enabled_Components.DATABASE_PURGER) { 1959 toDelete.add(id); 1960 } else { 1961 LOGGER.warn("Entry #{}({}) in `plot_helpers` does not exist." 1962 + " Create this plot or set `database-purger: true` in settings.yml", id, plot); 1963 } 1964 } 1965 deleteRows(toDelete, this.prefix + "plot_helpers", "plot_plot_id"); 1966 } 1967 1968 /* 1969 * Getting trusted 1970 */ 1971 try (ResultSet r = statement.executeQuery( 1972 "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_trusted`")) { 1973 ArrayList<Integer> toDelete = new ArrayList<>(); 1974 while (r.next()) { 1975 id = r.getInt("plot_plot_id"); 1976 o = r.getString("user_uuid"); 1977 user = uuids.get(o); 1978 if (user == null) { 1979 user = UUID.fromString(o); 1980 uuids.put(o, user); 1981 } 1982 Plot plot = plots.get(id); 1983 if (plot != null) { 1984 plot.getMembers().add(user); 1985 } else if (Settings.Enabled_Components.DATABASE_PURGER) { 1986 toDelete.add(id); 1987 } else { 1988 LOGGER.warn("Entry #{}({}) in `plot_trusted` does not exist." 1989 + " Create this plot or set `database-purger: true` in settings.yml", id, plot); 1990 } 1991 } 1992 deleteRows(toDelete, this.prefix + "plot_trusted", "plot_plot_id"); 1993 } 1994 1995 /* 1996 * Getting denied 1997 */ 1998 try (ResultSet r = statement.executeQuery( 1999 "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_denied`")) { 2000 ArrayList<Integer> toDelete = new ArrayList<>(); 2001 while (r.next()) { 2002 id = r.getInt("plot_plot_id"); 2003 o = r.getString("user_uuid"); 2004 user = uuids.get(o); 2005 if (user == null) { 2006 user = UUID.fromString(o); 2007 uuids.put(o, user); 2008 } 2009 Plot plot = plots.get(id); 2010 if (plot != null) { 2011 plot.getDenied().add(user); 2012 } else if (Settings.Enabled_Components.DATABASE_PURGER) { 2013 toDelete.add(id); 2014 } else { 2015 LOGGER.warn("Entry #{}({}) in `plot_denied` does not exist." 2016 + " Create this plot or set `database-purger: true` in settings.yml", id, plot); 2017 } 2018 } 2019 deleteRows(toDelete, this.prefix + "plot_denied", "plot_plot_id"); 2020 } 2021 2022 try (final ResultSet resultSet = statement 2023 .executeQuery("SELECT * FROM `" + this.prefix + "plot_flags`")) { 2024 BlockTypeListFlag.skipCategoryVerification = 2025 true; // allow invalid tags, as initialized lazily 2026 final ArrayList<Integer> toDelete = new ArrayList<>(); 2027 final Map<Plot, Collection<PlotFlag<?, ?>>> invalidFlags = new HashMap<>(); 2028 while (resultSet.next()) { 2029 id = resultSet.getInt("plot_id"); 2030 final String flag = resultSet.getString("flag"); 2031 String value = resultSet.getString("value"); 2032 final Plot plot = plots.get(id); 2033 if (plot != null) { 2034 final PlotFlag<?, ?> plotFlag = 2035 GlobalFlagContainer.getInstance().getFlagFromString(flag); 2036 if (plotFlag == null) { 2037 plot.getFlagContainer().addUnknownFlag(flag, value); 2038 } else { 2039 value = CaptionUtility.stripClickEvents(plotFlag, value); 2040 try { 2041 plot.getFlagContainer().addFlag(plotFlag.parse(value)); 2042 } catch (final FlagParseException e) { 2043 e.printStackTrace(); 2044 LOGGER.error("Plot with ID {} has an invalid value:", id); 2045 LOGGER.error("Failed to parse flag '{}', value '{}': {}", 2046 plotFlag.getName(), e.getValue(), e.getErrorMessage() 2047 ); 2048 if (!invalidFlags.containsKey(plot)) { 2049 invalidFlags.put(plot, new ArrayList<>()); 2050 } 2051 invalidFlags.get(plot).add(plotFlag); 2052 } 2053 } 2054 } else if (Settings.Enabled_Components.DATABASE_PURGER) { 2055 toDelete.add(id); 2056 } else { 2057 LOGGER.warn("Entry #{}({}) in `plot_flags` does not exist." 2058 + " Create this plot or set `database-purger: true` in settings.yml", id, plot); 2059 } 2060 } 2061 BlockTypeListFlag.skipCategoryVerification = 2062 false; // don't allow invalid tags anymore 2063 if (Settings.Enabled_Components.DATABASE_PURGER) { 2064 for (final Map.Entry<Plot, Collection<PlotFlag<?, ?>>> plotFlagEntry : invalidFlags 2065 .entrySet()) { 2066 for (final PlotFlag<?, ?> flag : plotFlagEntry.getValue()) { 2067 LOGGER.info( 2068 "Plot {} has an invalid flag ({}). A fix has been attempted", 2069 plotFlagEntry.getKey(), flag.getName() 2070 ); 2071 removeFlag(plotFlagEntry.getKey(), flag); 2072 } 2073 } 2074 } 2075 deleteRows(toDelete, this.prefix + "plot_flags", "plot_id"); 2076 } 2077 2078 try (ResultSet resultSet = statement 2079 .executeQuery("SELECT * FROM `" + this.prefix + "plot_settings`")) { 2080 ArrayList<Integer> toDelete = new ArrayList<>(); 2081 while (resultSet.next()) { 2082 id = resultSet.getInt("plot_plot_id"); 2083 Plot plot = plots.get(id); 2084 if (plot != null) { 2085 plots.remove(id); 2086 String alias = resultSet.getString("alias"); 2087 if (alias != null) { 2088 plot.getSettings().setAlias(alias); 2089 } 2090 String pos = resultSet.getString("position"); 2091 switch (pos.toLowerCase()) { 2092 case "": 2093 case "default": 2094 case "0,0,0": 2095 case "center": 2096 case "centre": 2097 break; 2098 default: 2099 try { 2100 plot.getSettings().setPosition(BlockLoc.fromString(pos)); 2101 } catch (Exception ignored) { 2102 } 2103 } 2104 int m = resultSet.getInt("merged"); 2105 boolean[] merged = new boolean[4]; 2106 for (int i = 0; i < 4; i++) { 2107 merged[3 - i] = (m & 1 << i) != 0; 2108 } 2109 plot.getSettings().setMerged(merged); 2110 } else if (Settings.Enabled_Components.DATABASE_PURGER) { 2111 toDelete.add(id); 2112 } else { 2113 LOGGER.warn("Entry #{}({}) in `plot_settings` does not exist." 2114 + " Create this plot or set `database-purger: true` in settings.yml", id, plot); 2115 } 2116 } 2117 deleteRows(toDelete, this.prefix + "plot_settings", "plot_plot_id"); 2118 } 2119 } 2120 if (!plots.entrySet().isEmpty()) { 2121 createEmptySettings(new ArrayList<>(plots.keySet()), null); 2122 for (Entry<Integer, Plot> entry : plots.entrySet()) { 2123 entry.getValue().getSettings(); 2124 } 2125 } 2126 boolean invalidPlot = false; 2127 for (Entry<String, AtomicInteger> entry : noExist.entrySet()) { 2128 String worldName = entry.getKey(); 2129 invalidPlot = true; 2130 if (Settings.DEBUG) { 2131 LOGGER.info("Warning! Found {} plots in DB for non existent world: '{}'", 2132 entry.getValue().intValue(), worldName 2133 ); 2134 } 2135 } 2136 if (invalidPlot && Settings.DEBUG) { 2137 LOGGER.info("Warning! Please create the world(s) or remove the plots using the purge command"); 2138 } 2139 } catch (SQLException e) { 2140 LOGGER.error("Failed to load plots", e); 2141 } 2142 return newPlots; 2143 } 2144 2145 @Override 2146 public void setMerged(final Plot plot, final boolean[] merged) { 2147 plot.getSettings().setMerged(merged); 2148 addPlotTask(plot, new UniqueStatement("setMerged") { 2149 @Override 2150 public void set(PreparedStatement statement) throws SQLException { 2151 int hash = HashUtil.hash(merged); 2152 statement.setInt(1, hash); 2153 statement.setInt(2, getId(plot)); 2154 } 2155 2156 @Override 2157 public PreparedStatement get() throws SQLException { 2158 return SQLManager.this.connection.prepareStatement( 2159 "UPDATE `" + SQLManager.this.prefix 2160 + "plot_settings` SET `merged` = ? WHERE `plot_plot_id` = ?"); 2161 } 2162 }); 2163 } 2164 2165 @Override 2166 public CompletableFuture<Boolean> swapPlots(Plot plot1, Plot plot2) { 2167 final CompletableFuture<Boolean> future = new CompletableFuture<>(); 2168 TaskManager.runTaskAsync(() -> { 2169 final int id1 = getId(plot1); 2170 final int id2 = getId(plot2); 2171 final PlotId pos1 = plot1.getId(); 2172 final PlotId pos2 = plot2.getId(); 2173 try (final PreparedStatement preparedStatement = this.connection.prepareStatement( 2174 "UPDATE `" + SQLManager.this.prefix 2175 + "plot` SET `plot_id_x` = ?, `plot_id_z` = ? WHERE `id` = ?")) { 2176 preparedStatement.setInt(1, pos1.getX()); 2177 preparedStatement.setInt(2, pos1.getY()); 2178 preparedStatement.setInt(3, id1); 2179 preparedStatement.execute(); 2180 preparedStatement.setInt(1, pos2.getX()); 2181 preparedStatement.setInt(2, pos2.getY()); 2182 preparedStatement.setInt(3, id2); 2183 preparedStatement.execute(); 2184 } catch (final Exception e) { 2185 LOGGER.error("Failed to persist wap of {} and {}", plot1, plot2); 2186 e.printStackTrace(); 2187 future.complete(false); 2188 return; 2189 } 2190 future.complete(true); 2191 }); 2192 return future; 2193 } 2194 2195 @Override 2196 public void movePlot(final Plot original, final Plot newPlot) { 2197 addPlotTask(original, new UniqueStatement("movePlot") { 2198 @Override 2199 public void set(PreparedStatement statement) throws SQLException { 2200 statement.setInt(1, newPlot.getId().getX()); 2201 statement.setInt(2, newPlot.getId().getY()); 2202 statement.setString(3, newPlot.getArea().toString()); 2203 statement.setInt(4, getId(original)); 2204 } 2205 2206 @Override 2207 public PreparedStatement get() throws SQLException { 2208 return SQLManager.this.connection.prepareStatement( 2209 "UPDATE `" + SQLManager.this.prefix 2210 + "plot` SET `plot_id_x` = ?, `plot_id_z` = ?, `world` = ? WHERE `id` = ?"); 2211 } 2212 }); 2213 addPlotTask(newPlot, null); 2214 } 2215 2216 @Override 2217 public void setFlag(final Plot plot, final PlotFlag<?, ?> flag) { 2218 addPlotTask(plot, new UniqueStatement("setFlag") { 2219 @Override 2220 public void set(PreparedStatement statement) throws SQLException { 2221 statement.setInt(1, getId(plot)); 2222 statement.setString(2, flag.getName()); 2223 statement.setString(3, flag.toString()); 2224 statement.setString(4, flag.toString()); 2225 } 2226 2227 @Override 2228 public PreparedStatement get() throws SQLException { 2229 final String statement; 2230 if (SQLManager.this.mySQL) { 2231 statement = "INSERT INTO `" + SQLManager.this.prefix 2232 + "plot_flags`(`plot_id`, `flag`, `value`) VALUES(?, ?, ?) " 2233 + "ON DUPLICATE KEY UPDATE `value` = ?"; 2234 } else { 2235 statement = "INSERT INTO `" + SQLManager.this.prefix 2236 + "plot_flags`(`plot_id`, `flag`, `value`) VALUES(?, ?, ?) " 2237 + "ON CONFLICT(`plot_id`,`flag`) DO UPDATE SET `value` = ?"; 2238 } 2239 return SQLManager.this.connection.prepareStatement(statement); 2240 } 2241 }); 2242 } 2243 2244 @Override 2245 public void removeFlag(final Plot plot, final PlotFlag<?, ?> flag) { 2246 addPlotTask(plot, new UniqueStatement("removeFlag") { 2247 @Override 2248 public void set(PreparedStatement statement) throws SQLException { 2249 statement.setInt(1, getId(plot)); 2250 statement.setString(2, flag.getName()); 2251 } 2252 2253 @Override 2254 public PreparedStatement get() throws SQLException { 2255 return SQLManager.this.connection.prepareStatement( 2256 "DELETE FROM `" + SQLManager.this.prefix 2257 + "plot_flags` WHERE `plot_id` = ? AND `flag` = ?"); 2258 } 2259 }); 2260 } 2261 2262 @Override 2263 public void setAlias(final Plot plot, final String alias) { 2264 addPlotTask(plot, new UniqueStatement("setAlias") { 2265 @Override 2266 public void set(PreparedStatement statement) throws SQLException { 2267 statement.setString(1, alias); 2268 statement.setInt(2, getId(plot)); 2269 } 2270 2271 @Override 2272 public PreparedStatement get() throws SQLException { 2273 return SQLManager.this.connection.prepareStatement( 2274 "UPDATE `" + SQLManager.this.prefix 2275 + "plot_settings` SET `alias` = ? WHERE `plot_plot_id` = ?"); 2276 } 2277 }); 2278 } 2279 2280 /** 2281 * Purge all plots with the following database IDs 2282 */ 2283 @Override 2284 public void purgeIds(final Set<Integer> uniqueIds) { 2285 addGlobalTask(() -> { 2286 if (!uniqueIds.isEmpty()) { 2287 try { 2288 ArrayList<Integer> uniqueIdsList = new ArrayList<>(uniqueIds); 2289 int size = uniqueIdsList.size(); 2290 int packet = 990; 2291 int amount = size / packet; 2292 for (int j = 0; j <= amount; j++) { 2293 List<Integer> subList = 2294 uniqueIdsList.subList(j * packet, Math.min(size, (j + 1) * packet)); 2295 if (subList.isEmpty()) { 2296 break; 2297 } 2298 StringBuilder idstr2 = new StringBuilder(); 2299 String stmt_prefix = ""; 2300 for (Integer id : subList) { 2301 idstr2.append(stmt_prefix).append(id); 2302 stmt_prefix = " OR `id` = "; 2303 } 2304 stmt_prefix = ""; 2305 StringBuilder idstr = new StringBuilder(); 2306 for (Integer id : subList) { 2307 idstr.append(stmt_prefix).append(id); 2308 stmt_prefix = " OR `plot_plot_id` = "; 2309 } 2310 PreparedStatement stmt = SQLManager.this.connection.prepareStatement( 2311 "DELETE FROM `" + SQLManager.this.prefix 2312 + "plot_helpers` WHERE `plot_plot_id` = " + idstr); 2313 stmt.executeUpdate(); 2314 stmt.close(); 2315 stmt = SQLManager.this.connection.prepareStatement( 2316 "DELETE FROM `" + SQLManager.this.prefix 2317 + "plot_denied` WHERE `plot_plot_id` = " + idstr); 2318 stmt.executeUpdate(); 2319 stmt.close(); 2320 stmt = SQLManager.this.connection.prepareStatement( 2321 "DELETE FROM `" + SQLManager.this.prefix 2322 + "plot_settings` WHERE `plot_plot_id` = " + idstr); 2323 stmt.executeUpdate(); 2324 stmt.close(); 2325 stmt = SQLManager.this.connection.prepareStatement( 2326 "DELETE FROM `" + SQLManager.this.prefix 2327 + "plot_trusted` WHERE `plot_plot_id` = " + idstr); 2328 stmt.executeUpdate(); 2329 stmt.close(); 2330 stmt = SQLManager.this.connection.prepareStatement( 2331 "DELETE FROM `" + SQLManager.this.prefix + "plot` WHERE `id` = " 2332 + idstr2); 2333 stmt.executeUpdate(); 2334 stmt.close(); 2335 commit(); 2336 } 2337 } catch (SQLException e) { 2338 LOGGER.error("Failed to purge plots", e); 2339 return; 2340 } 2341 } 2342 LOGGER.info("Successfully purged {} plots", uniqueIds.size()); 2343 }); 2344 } 2345 2346 @Override 2347 public void purge(final PlotArea area, final Set<PlotId> plots) { 2348 addGlobalTask(() -> { 2349 try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( 2350 "SELECT `id`, `plot_id_x`, `plot_id_z` FROM `" + SQLManager.this.prefix 2351 + "plot` WHERE `world` = ?")) { 2352 stmt.setString(1, area.toString()); 2353 Set<Integer> ids; 2354 try (ResultSet r = stmt.executeQuery()) { 2355 ids = new HashSet<>(); 2356 while (r.next()) { 2357 PlotId plot_id = PlotId.of(r.getInt("plot_id_x"), r.getInt("plot_id_z")); 2358 if (plots.contains(plot_id)) { 2359 ids.add(r.getInt("id")); 2360 } 2361 } 2362 } 2363 purgeIds(ids); 2364 } catch (SQLException e) { 2365 LOGGER.error("Failed to purge area '{}'", area); 2366 e.printStackTrace(); 2367 } 2368 for (Iterator<PlotId> iterator = plots.iterator(); iterator.hasNext(); ) { 2369 PlotId plotId = iterator.next(); 2370 iterator.remove(); 2371 PlotId id = PlotId.of(plotId.getX(), plotId.getY()); 2372 area.removePlot(id); 2373 } 2374 }); 2375 } 2376 2377 @Override 2378 public void setPosition(final Plot plot, final String position) { 2379 addPlotTask(plot, new UniqueStatement("setPosition") { 2380 @Override 2381 public void set(PreparedStatement statement) throws SQLException { 2382 statement.setString(1, position == null ? "" : position); 2383 statement.setInt(2, getId(plot)); 2384 } 2385 2386 @Override 2387 public PreparedStatement get() throws SQLException { 2388 return SQLManager.this.connection.prepareStatement( 2389 "UPDATE `" + SQLManager.this.prefix 2390 + "plot_settings` SET `position` = ? WHERE `plot_plot_id` = ?"); 2391 } 2392 }); 2393 } 2394 2395 @Override 2396 public void removeComment(final Plot plot, final PlotComment comment) { 2397 addPlotTask(plot, new UniqueStatement("removeComment") { 2398 @Override 2399 public void set(PreparedStatement statement) throws SQLException { 2400 if (plot != null) { 2401 statement.setString(1, plot.getArea().toString()); 2402 statement.setInt(2, plot.getId().hashCode()); 2403 statement.setString(3, comment.comment()); 2404 statement.setString(4, comment.inbox()); 2405 statement.setString(5, comment.senderName()); 2406 } else { 2407 statement.setString(1, comment.comment()); 2408 statement.setString(2, comment.inbox()); 2409 statement.setString(3, comment.senderName()); 2410 } 2411 } 2412 2413 @Override 2414 public PreparedStatement get() throws SQLException { 2415 if (plot != null) { 2416 return SQLManager.this.connection.prepareStatement( 2417 "DELETE FROM `" + SQLManager.this.prefix 2418 + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `comment` = ? AND `inbox` = ? AND `sender` = ?"); 2419 } 2420 return SQLManager.this.connection.prepareStatement( 2421 "DELETE FROM `" + SQLManager.this.prefix 2422 + "plot_comments` WHERE `comment` = ? AND `inbox` = ? AND `sender` = ?"); 2423 } 2424 }); 2425 } 2426 2427 @Override 2428 public void clearInbox(final Plot plot, final String inbox) { 2429 addPlotTask(plot, new UniqueStatement("clearInbox") { 2430 @Override 2431 public void set(PreparedStatement statement) throws SQLException { 2432 if (plot != null) { 2433 statement.setString(1, plot.getArea().toString()); 2434 statement.setInt(2, plot.getId().hashCode()); 2435 statement.setString(3, inbox); 2436 } else { 2437 statement.setString(1, inbox); 2438 } 2439 } 2440 2441 @Override 2442 public PreparedStatement get() throws SQLException { 2443 if (plot != null) { 2444 return SQLManager.this.connection.prepareStatement( 2445 "DELETE FROM `" + SQLManager.this.prefix 2446 + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `inbox` = ?"); 2447 } 2448 return SQLManager.this.connection.prepareStatement( 2449 "DELETE FROM `" + SQLManager.this.prefix + "plot_comments` `inbox` = ?"); 2450 } 2451 }); 2452 } 2453 2454 @Override 2455 public void getComments( 2456 @NonNull Plot plot, final String inbox, 2457 final RunnableVal<List<PlotComment>> whenDone 2458 ) { 2459 addPlotTask(plot, new UniqueStatement("getComments_" + plot) { 2460 @Override 2461 public void set(PreparedStatement statement) throws SQLException { 2462 if (plot != null) { 2463 statement.setString(1, plot.getArea().toString()); 2464 statement.setInt(2, plot.getId().hashCode()); 2465 statement.setString(3, inbox); 2466 } else { 2467 statement.setString(1, inbox); 2468 } 2469 } 2470 2471 @Override 2472 public PreparedStatement get() throws SQLException { 2473 if (plot != null) { 2474 return SQLManager.this.connection.prepareStatement( 2475 "SELECT * FROM `" + SQLManager.this.prefix 2476 + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `inbox` = ?"); 2477 } 2478 return SQLManager.this.connection.prepareStatement( 2479 "SELECT * FROM `" + SQLManager.this.prefix 2480 + "plot_comments` WHERE `inbox` = ?"); 2481 } 2482 2483 @Override 2484 public void execute(PreparedStatement statement) { 2485 } 2486 2487 @Override 2488 public void addBatch(PreparedStatement statement) throws SQLException { 2489 ArrayList<PlotComment> comments = new ArrayList<>(); 2490 try (ResultSet set = statement.executeQuery()) { 2491 while (set.next()) { 2492 String sender = set.getString("sender"); 2493 String world = set.getString("world"); 2494 int hash = set.getInt("hashcode"); 2495 PlotId id; 2496 if (hash != 0) { 2497 id = PlotId.unpair(hash); 2498 } else { 2499 id = null; 2500 } 2501 String msg = set.getString("comment"); 2502 long timestamp = set.getInt("timestamp") * 1000; 2503 PlotComment comment = 2504 new PlotComment(world, id, msg, sender, inbox, timestamp); 2505 comments.add(comment); 2506 } 2507 whenDone.value = comments; 2508 } 2509 TaskManager.runTask(whenDone); 2510 } 2511 }); 2512 } 2513 2514 @Override 2515 public void setComment(final Plot plot, final PlotComment comment) { 2516 addPlotTask(plot, new UniqueStatement("setComment") { 2517 @Override 2518 public void set(PreparedStatement statement) throws SQLException { 2519 statement.setString(1, plot.getArea().toString()); 2520 statement.setInt(2, plot.getId().hashCode()); 2521 statement.setString(3, comment.comment()); 2522 statement.setString(4, comment.inbox()); 2523 statement.setInt(5, (int) (comment.timestamp() / 1000)); 2524 statement.setString(6, comment.senderName()); 2525 } 2526 2527 @Override 2528 public PreparedStatement get() throws SQLException { 2529 return SQLManager.this.connection.prepareStatement( 2530 "INSERT INTO `" + SQLManager.this.prefix 2531 + "plot_comments` (`world`, `hashcode`, `comment`, `inbox`, `timestamp`, `sender`) VALUES(?,?,?,?,?,?)"); 2532 } 2533 }); 2534 } 2535 2536 @Override 2537 public void removeTrusted(final Plot plot, final UUID uuid) { 2538 addPlotTask(plot, new UniqueStatement("removeTrusted") { 2539 @Override 2540 public void set(PreparedStatement statement) throws SQLException { 2541 statement.setInt(1, getId(plot)); 2542 statement.setString(2, uuid.toString()); 2543 } 2544 2545 @Override 2546 public PreparedStatement get() throws SQLException { 2547 return SQLManager.this.connection.prepareStatement( 2548 "DELETE FROM `" + SQLManager.this.prefix 2549 + "plot_helpers` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); 2550 } 2551 }); 2552 } 2553 2554 @Override 2555 public void removeMember(final Plot plot, final UUID uuid) { 2556 addPlotTask(plot, new UniqueStatement("removeMember") { 2557 @Override 2558 public void set(PreparedStatement statement) throws SQLException { 2559 statement.setInt(1, getId(plot)); 2560 statement.setString(2, uuid.toString()); 2561 } 2562 2563 @Override 2564 public PreparedStatement get() throws SQLException { 2565 return SQLManager.this.connection.prepareStatement( 2566 "DELETE FROM `" + SQLManager.this.prefix 2567 + "plot_trusted` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); 2568 } 2569 }); 2570 } 2571 2572 @Override 2573 public void setTrusted(final Plot plot, final UUID uuid) { 2574 addPlotTask(plot, new UniqueStatement("setTrusted") { 2575 @Override 2576 public void set(PreparedStatement statement) throws SQLException { 2577 statement.setInt(1, getId(plot)); 2578 statement.setString(2, uuid.toString()); 2579 } 2580 2581 @Override 2582 public PreparedStatement get() throws SQLException { 2583 return SQLManager.this.connection.prepareStatement( 2584 "INSERT INTO `" + SQLManager.this.prefix 2585 + "plot_helpers` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); 2586 } 2587 }); 2588 } 2589 2590 @Override 2591 public void setMember(final Plot plot, final UUID uuid) { 2592 addPlotTask(plot, new UniqueStatement("setMember") { 2593 @Override 2594 public void set(PreparedStatement statement) throws SQLException { 2595 statement.setInt(1, getId(plot)); 2596 statement.setString(2, uuid.toString()); 2597 } 2598 2599 @Override 2600 public PreparedStatement get() throws SQLException { 2601 return SQLManager.this.connection.prepareStatement( 2602 "INSERT INTO `" + SQLManager.this.prefix 2603 + "plot_trusted` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); 2604 } 2605 }); 2606 } 2607 2608 @Override 2609 public void removeDenied(final Plot plot, final UUID uuid) { 2610 addPlotTask(plot, new UniqueStatement("removeDenied") { 2611 @Override 2612 public void set(PreparedStatement statement) throws SQLException { 2613 statement.setInt(1, getId(plot)); 2614 statement.setString(2, uuid.toString()); 2615 } 2616 2617 @Override 2618 public PreparedStatement get() throws SQLException { 2619 return SQLManager.this.connection.prepareStatement( 2620 "DELETE FROM `" + SQLManager.this.prefix 2621 + "plot_denied` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); 2622 } 2623 }); 2624 } 2625 2626 @Override 2627 public void setDenied(final Plot plot, final UUID uuid) { 2628 addPlotTask(plot, new UniqueStatement("setDenied") { 2629 @Override 2630 public void set(PreparedStatement statement) throws SQLException { 2631 statement.setInt(1, getId(plot)); 2632 statement.setString(2, uuid.toString()); 2633 } 2634 2635 @Override 2636 public PreparedStatement get() throws SQLException { 2637 return SQLManager.this.connection.prepareStatement( 2638 "INSERT INTO `" + SQLManager.this.prefix 2639 + "plot_denied` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); 2640 } 2641 }); 2642 } 2643 2644 @Override 2645 public HashMap<UUID, Integer> getRatings(Plot plot) { 2646 HashMap<UUID, Integer> map = new HashMap<>(); 2647 try (PreparedStatement statement = this.connection.prepareStatement( 2648 "SELECT `rating`, `player` FROM `" + this.prefix 2649 + "plot_rating` WHERE `plot_plot_id` = ? ")) { 2650 statement.setInt(1, getId(plot)); 2651 try (ResultSet resultSet = statement.executeQuery()) { 2652 while (resultSet.next()) { 2653 UUID uuid = UUID.fromString(resultSet.getString("player")); 2654 int rating = resultSet.getInt("rating"); 2655 map.put(uuid, rating); 2656 } 2657 } 2658 } catch (SQLException e) { 2659 LOGGER.error("Failed to fetch rating for plot {}", plot.getId().toString()); 2660 e.printStackTrace(); 2661 } 2662 return map; 2663 } 2664 2665 @Override 2666 public void setRating(final Plot plot, final UUID rater, final int value) { 2667 addPlotTask(plot, new UniqueStatement("setRating") { 2668 @Override 2669 public void set(PreparedStatement statement) throws SQLException { 2670 statement.setInt(1, getId(plot)); 2671 statement.setInt(2, value); 2672 statement.setString(3, rater.toString()); 2673 } 2674 2675 @Override 2676 public PreparedStatement get() throws SQLException { 2677 return SQLManager.this.connection.prepareStatement( 2678 "INSERT INTO `" + SQLManager.this.prefix 2679 + "plot_rating` (`plot_plot_id`, `rating`, `player`) VALUES(?,?,?)"); 2680 } 2681 }); 2682 } 2683 2684 @Override 2685 public void delete(PlotCluster cluster) { 2686 final int id = getClusterId(cluster); 2687 addClusterTask(cluster, new UniqueStatement("delete_cluster_settings") { 2688 @Override 2689 public void set(PreparedStatement statement) throws SQLException { 2690 statement.setInt(1, id); 2691 } 2692 2693 @Override 2694 public PreparedStatement get() throws SQLException { 2695 return SQLManager.this.connection.prepareStatement( 2696 "DELETE FROM `" + SQLManager.this.prefix 2697 + "cluster_settings` WHERE `cluster_id` = ?"); 2698 } 2699 }); 2700 addClusterTask(cluster, new UniqueStatement("delete_cluster_helpers") { 2701 @Override 2702 public void set(PreparedStatement statement) throws SQLException { 2703 statement.setInt(1, id); 2704 } 2705 2706 @Override 2707 public PreparedStatement get() throws SQLException { 2708 return SQLManager.this.connection.prepareStatement( 2709 "DELETE FROM `" + SQLManager.this.prefix 2710 + "cluster_helpers` WHERE `cluster_id` = ?"); 2711 } 2712 }); 2713 addClusterTask(cluster, new UniqueStatement("delete_cluster_invited") { 2714 @Override 2715 public void set(PreparedStatement statement) throws SQLException { 2716 statement.setInt(1, id); 2717 } 2718 2719 @Override 2720 public PreparedStatement get() throws SQLException { 2721 return SQLManager.this.connection.prepareStatement( 2722 "DELETE FROM `" + SQLManager.this.prefix 2723 + "cluster_invited` WHERE `cluster_id` = ?"); 2724 } 2725 }); 2726 addClusterTask(cluster, new UniqueStatement("delete_cluster") { 2727 @Override 2728 public void set(PreparedStatement statement) throws SQLException { 2729 statement.setInt(1, id); 2730 } 2731 2732 @Override 2733 public PreparedStatement get() throws SQLException { 2734 return SQLManager.this.connection.prepareStatement( 2735 "DELETE FROM `" + SQLManager.this.prefix + "cluster` WHERE `id` = ?"); 2736 } 2737 }); 2738 } 2739 2740 @Override 2741 public void addPersistentMeta( 2742 final UUID uuid, final String key, final byte[] meta, 2743 final boolean replace 2744 ) { 2745 addPlayerTask(uuid, new UniqueStatement("addPersistentMeta") { 2746 @Override 2747 public void set(PreparedStatement statement) throws SQLException { 2748 if (replace) { 2749 statement.setBytes(1, meta); 2750 statement.setString(2, uuid.toString()); 2751 statement.setString(3, key); 2752 } else { 2753 statement.setString(1, uuid.toString()); 2754 statement.setString(2, key); 2755 statement.setBytes(3, meta); 2756 } 2757 } 2758 2759 @Override 2760 public PreparedStatement get() throws SQLException { 2761 if (replace) { 2762 return SQLManager.this.connection.prepareStatement( 2763 "UPDATE `" + SQLManager.this.prefix 2764 + "player_meta` SET `value` = ? WHERE `uuid` = ? AND `key` = ?"); 2765 } else { 2766 return SQLManager.this.connection.prepareStatement( 2767 "INSERT INTO `" + SQLManager.this.prefix 2768 + "player_meta`(`uuid`, `key`, `value`) VALUES(?, ? ,?)"); 2769 } 2770 } 2771 }); 2772 } 2773 2774 @Override 2775 public void removePersistentMeta(final UUID uuid, final String key) { 2776 addPlayerTask(uuid, new UniqueStatement("removePersistentMeta") { 2777 @Override 2778 public void set(PreparedStatement statement) throws SQLException { 2779 statement.setString(1, uuid.toString()); 2780 statement.setString(2, key); 2781 } 2782 2783 @Override 2784 public PreparedStatement get() throws SQLException { 2785 return SQLManager.this.connection.prepareStatement( 2786 "DELETE FROM `" + SQLManager.this.prefix 2787 + "player_meta` WHERE `uuid` = ? AND `key` = ?"); 2788 } 2789 }); 2790 } 2791 2792 @Override 2793 public void getPersistentMeta(final UUID uuid, final RunnableVal<Map<String, byte[]>> result) { 2794 addPlayerTask(uuid, new UniqueStatement("getPersistentMeta") { 2795 @Override 2796 public void set(PreparedStatement statement) throws SQLException { 2797 statement.setString(1, uuid.toString()); 2798 } 2799 2800 @Override 2801 public PreparedStatement get() throws SQLException { 2802 return SQLManager.this.connection.prepareStatement( 2803 "SELECT * FROM `" + SQLManager.this.prefix 2804 + "player_meta` WHERE `uuid` = ? ORDER BY `meta_id` ASC"); 2805 } 2806 2807 @Override 2808 public void execute(PreparedStatement statement) { 2809 } 2810 2811 @Override 2812 public void addBatch(PreparedStatement statement) throws SQLException { 2813 ResultSet resultSet = statement.executeQuery(); 2814 2815 final Map<String, byte[]> metaMap = new HashMap<>(); 2816 2817 while (resultSet.next()) { 2818 String key = resultSet.getString("key"); 2819 byte[] bytes = resultSet.getBytes("value"); 2820 metaMap.put(key, bytes); 2821 } 2822 2823 resultSet.close(); 2824 TaskManager.runTaskAsync(() -> result.run(metaMap)); 2825 } 2826 2827 }); 2828 } 2829 2830 @Override 2831 public HashMap<String, Set<PlotCluster>> getClusters() { 2832 LinkedHashMap<String, Set<PlotCluster>> newClusters = new LinkedHashMap<>(); 2833 HashMap<Integer, PlotCluster> clusters = new HashMap<>(); 2834 try { 2835 HashSet<String> areas = new HashSet<>(); 2836 if (this.worldConfiguration.contains("worlds")) { 2837 ConfigurationSection worldSection = this.worldConfiguration.getConfigurationSection("worlds"); 2838 if (worldSection != null) { 2839 for (String worldKey : worldSection.getKeys(false)) { 2840 areas.add(worldKey); 2841 ConfigurationSection areaSection = 2842 worldSection.getConfigurationSection(worldKey + ".areas"); 2843 if (areaSection != null) { 2844 for (String areaKey : areaSection.getKeys(false)) { 2845 String[] split = areaKey.split("(?<![;])-"); 2846 if (split.length == 3) { 2847 areas.add(worldKey + ';' + split[0]); 2848 } 2849 } 2850 } 2851 } 2852 } 2853 } 2854 HashMap<String, UUID> uuids = new HashMap<>(); 2855 HashMap<String, Integer> noExist = new HashMap<>(); 2856 /* 2857 * Getting clusters 2858 */ 2859 try (Statement stmt = this.connection.createStatement()) { 2860 ResultSet resultSet = 2861 stmt.executeQuery("SELECT * FROM `" + this.prefix + "cluster`"); 2862 PlotCluster cluster; 2863 String owner; 2864 UUID user; 2865 int id; 2866 while (resultSet.next()) { 2867 PlotId pos1 = 2868 PlotId.of(resultSet.getInt("pos1_x"), resultSet.getInt("pos1_z")); 2869 PlotId pos2 = 2870 PlotId.of(resultSet.getInt("pos2_x"), resultSet.getInt("pos2_z")); 2871 id = resultSet.getInt("id"); 2872 String areaid = resultSet.getString("world"); 2873 if (!areas.contains(areaid)) { 2874 noExist.merge(areaid, 1, Integer::sum); 2875 } 2876 owner = resultSet.getString("owner"); 2877 user = uuids.get(owner); 2878 if (user == null) { 2879 user = UUID.fromString(owner); 2880 uuids.put(owner, user); 2881 } 2882 cluster = new PlotCluster(null, pos1, pos2, user, id); 2883 clusters.put(id, cluster); 2884 Set<PlotCluster> set = 2885 newClusters.computeIfAbsent(areaid, k -> new HashSet<>()); 2886 set.add(cluster); 2887 } 2888 //Getting helpers 2889 resultSet = stmt.executeQuery( 2890 "SELECT `user_uuid`, `cluster_id` FROM `" + this.prefix + "cluster_helpers`"); 2891 while (resultSet.next()) { 2892 id = resultSet.getInt("cluster_id"); 2893 owner = resultSet.getString("user_uuid"); 2894 user = uuids.get(owner); 2895 if (user == null) { 2896 user = UUID.fromString(owner); 2897 uuids.put(owner, user); 2898 } 2899 cluster = clusters.get(id); 2900 if (cluster != null) { 2901 cluster.helpers.add(user); 2902 } else { 2903 LOGGER.warn("Cluster #{}({}) in cluster_helpers does not exist." 2904 + " Please create the cluster or remove this entry", id, cluster); 2905 } 2906 } 2907 // Getting invited 2908 resultSet = stmt.executeQuery( 2909 "SELECT `user_uuid`, `cluster_id` FROM `" + this.prefix + "cluster_invited`"); 2910 while (resultSet.next()) { 2911 id = resultSet.getInt("cluster_id"); 2912 owner = resultSet.getString("user_uuid"); 2913 user = uuids.get(owner); 2914 if (user == null) { 2915 user = UUID.fromString(owner); 2916 uuids.put(owner, user); 2917 } 2918 cluster = clusters.get(id); 2919 if (cluster != null) { 2920 cluster.invited.add(user); 2921 } else { 2922 LOGGER.warn("Cluster #{}({}) in cluster_helpers does not exist." 2923 + " Please create the cluster or remove this entry", id, cluster); 2924 } 2925 } 2926 resultSet = 2927 stmt.executeQuery("SELECT * FROM `" + this.prefix + "cluster_settings`"); 2928 while (resultSet.next()) { 2929 id = resultSet.getInt("cluster_id"); 2930 cluster = clusters.get(id); 2931 if (cluster != null) { 2932 String alias = resultSet.getString("alias"); 2933 if (alias != null) { 2934 cluster.settings.setAlias(alias); 2935 } 2936 String pos = resultSet.getString("position"); 2937 switch (pos.toLowerCase()) { 2938 case "": 2939 case "default": 2940 case "0,0,0": 2941 case "center": 2942 case "centre": 2943 break; 2944 default: 2945 try { 2946 BlockLoc loc = BlockLoc.fromString(pos); 2947 cluster.settings.setPosition(loc); 2948 } catch (Exception ignored) { 2949 } 2950 } 2951 int m = resultSet.getInt("merged"); 2952 boolean[] merged = new boolean[4]; 2953 for (int i = 0; i < 4; i++) { 2954 merged[3 - i] = (m & 1 << i) != 0; 2955 } 2956 cluster.settings.setMerged(merged); 2957 } else { 2958 LOGGER.warn("Cluster #{}({}) in cluster_helpers does not exist." 2959 + " Please create the cluster or remove this entry", id, cluster); 2960 } 2961 } 2962 resultSet.close(); 2963 } 2964 boolean invalidPlot = false; 2965 for (Entry<String, Integer> entry : noExist.entrySet()) { 2966 String a = entry.getKey(); 2967 invalidPlot = true; 2968 LOGGER.warn("Warning! Found {} clusters in DB for non existent area; '{}'", noExist.get(a), a); 2969 } 2970 if (invalidPlot) { 2971 LOGGER.warn("Warning! Please create the world(s) or remove the clusters using the purge command"); 2972 } 2973 } catch (SQLException e) { 2974 LOGGER.error("Failed to load clusters", e); 2975 } 2976 return newClusters; 2977 } 2978 2979 @Override 2980 public void setClusterName(final PlotCluster cluster, final String name) { 2981 addClusterTask(cluster, new UniqueStatement("setClusterName") { 2982 @Override 2983 public void set(PreparedStatement statement) throws SQLException { 2984 statement.setString(1, name); 2985 statement.setInt(2, getClusterId(cluster)); 2986 } 2987 2988 @Override 2989 public PreparedStatement get() throws SQLException { 2990 return SQLManager.this.connection.prepareStatement( 2991 "UPDATE `" + SQLManager.this.prefix 2992 + "cluster_settings` SET `alias` = ? WHERE `cluster_id` = ?"); 2993 } 2994 }); 2995 cluster.settings.setAlias(name); 2996 } 2997 2998 @Override 2999 public void removeHelper(final PlotCluster cluster, final UUID uuid) { 3000 addClusterTask(cluster, new UniqueStatement("removeHelper") { 3001 @Override 3002 public void set(PreparedStatement statement) throws SQLException { 3003 statement.setInt(1, getClusterId(cluster)); 3004 statement.setString(2, uuid.toString()); 3005 } 3006 3007 @Override 3008 public PreparedStatement get() throws SQLException { 3009 return SQLManager.this.connection.prepareStatement( 3010 "DELETE FROM `" + SQLManager.this.prefix 3011 + "cluster_helpers` WHERE `cluster_id` = ? AND `user_uuid` = ?"); 3012 } 3013 }); 3014 } 3015 3016 @Override 3017 public void setHelper(final PlotCluster cluster, final UUID uuid) { 3018 addClusterTask(cluster, new UniqueStatement("setHelper") { 3019 @Override 3020 public void set(PreparedStatement statement) throws SQLException { 3021 statement.setInt(1, getClusterId(cluster)); 3022 statement.setString(2, uuid.toString()); 3023 } 3024 3025 @Override 3026 public PreparedStatement get() throws SQLException { 3027 return SQLManager.this.connection.prepareStatement( 3028 "INSERT INTO `" + SQLManager.this.prefix 3029 + "cluster_helpers` (`cluster_id`, `user_uuid`) VALUES(?,?)"); 3030 } 3031 }); 3032 } 3033 3034 @Override 3035 public void createCluster(final PlotCluster cluster) { 3036 addClusterTask(cluster, new UniqueStatement("createCluster_" + cluster.hashCode()) { 3037 @Override 3038 public void set(PreparedStatement statement) throws SQLException { 3039 statement.setInt(1, cluster.getP1().getX()); 3040 statement.setInt(2, cluster.getP1().getY()); 3041 statement.setInt(3, cluster.getP2().getX()); 3042 statement.setInt(4, cluster.getP2().getY()); 3043 statement.setString(5, cluster.owner.toString()); 3044 statement.setString(6, cluster.area.toString()); 3045 } 3046 3047 @Override 3048 public PreparedStatement get() throws SQLException { 3049 return SQLManager.this.connection.prepareStatement( 3050 SQLManager.this.CREATE_CLUSTER, 3051 Statement.RETURN_GENERATED_KEYS 3052 ); 3053 } 3054 3055 @Override 3056 public void execute(PreparedStatement statement) { 3057 } 3058 3059 @Override 3060 public void addBatch(PreparedStatement statement) throws SQLException { 3061 statement.executeUpdate(); 3062 try (ResultSet keys = statement.getGeneratedKeys()) { 3063 if (keys.next()) { 3064 cluster.temp = keys.getInt(1); 3065 } 3066 } 3067 } 3068 }); 3069 addClusterTask( 3070 cluster, 3071 new UniqueStatement("createCluster_settings_" + cluster.hashCode()) { 3072 @Override 3073 public void set(PreparedStatement statement) throws SQLException { 3074 statement.setInt(1, getClusterId(cluster)); 3075 statement.setString(2, cluster.settings.getAlias()); 3076 } 3077 3078 @Override 3079 public PreparedStatement get() throws SQLException { 3080 return SQLManager.this.connection.prepareStatement( 3081 "INSERT INTO `" + SQLManager.this.prefix 3082 + "cluster_settings`(`cluster_id`, `alias`) VALUES(?, ?)"); 3083 } 3084 } 3085 ); 3086 } 3087 3088 @Override 3089 public void resizeCluster(final PlotCluster current, PlotId min, PlotId max) { 3090 final PlotId pos1 = PlotId.of(current.getP1().getX(), current.getP1().getY()); 3091 final PlotId pos2 = PlotId.of(current.getP2().getX(), current.getP2().getY()); 3092 current.setP1(min); 3093 current.setP2(max); 3094 3095 addClusterTask(current, new UniqueStatement("resizeCluster") { 3096 @Override 3097 public void set(PreparedStatement statement) throws SQLException { 3098 statement.setInt(1, pos1.getX()); 3099 statement.setInt(2, pos1.getY()); 3100 statement.setInt(3, pos2.getX()); 3101 statement.setInt(4, pos2.getY()); 3102 statement.setInt(5, getClusterId(current)); 3103 } 3104 3105 @Override 3106 public PreparedStatement get() throws SQLException { 3107 return SQLManager.this.connection.prepareStatement( 3108 "UPDATE `" + SQLManager.this.prefix 3109 + "cluster` SET `pos1_x` = ?, `pos1_z` = ?, `pos2_x` = ?, `pos2_z` = ? WHERE `id` = ?"); 3110 } 3111 }); 3112 } 3113 3114 @Override 3115 public void setPosition(final PlotCluster cluster, final String position) { 3116 addClusterTask(cluster, new UniqueStatement("setPosition") { 3117 @Override 3118 public void set(PreparedStatement statement) throws SQLException { 3119 statement.setString(1, position); 3120 statement.setInt(2, getClusterId(cluster)); 3121 } 3122 3123 @Override 3124 public PreparedStatement get() throws SQLException { 3125 return SQLManager.this.connection.prepareStatement( 3126 "UPDATE `" + SQLManager.this.prefix 3127 + "cluster_settings` SET `position` = ? WHERE `cluster_id` = ?"); 3128 } 3129 }); 3130 } 3131 3132 @Override 3133 public void removeInvited(final PlotCluster cluster, final UUID uuid) { 3134 addClusterTask(cluster, new UniqueStatement("removeInvited") { 3135 @Override 3136 public void set(PreparedStatement statement) throws SQLException { 3137 statement.setInt(1, getClusterId(cluster)); 3138 statement.setString(2, uuid.toString()); 3139 } 3140 3141 @Override 3142 public PreparedStatement get() throws SQLException { 3143 return SQLManager.this.connection.prepareStatement( 3144 "DELETE FROM `" + SQLManager.this.prefix 3145 + "cluster_invited` WHERE `cluster_id` = ? AND `user_uuid` = ?"); 3146 } 3147 }); 3148 } 3149 3150 @Override 3151 public void setInvited(final PlotCluster cluster, final UUID uuid) { 3152 addClusterTask(cluster, new UniqueStatement("setInvited") { 3153 @Override 3154 public void set(PreparedStatement statement) throws SQLException { 3155 statement.setInt(1, getClusterId(cluster)); 3156 statement.setString(2, uuid.toString()); 3157 } 3158 3159 @Override 3160 public PreparedStatement get() throws SQLException { 3161 return SQLManager.this.connection.prepareStatement( 3162 "INSERT INTO `" + SQLManager.this.prefix 3163 + "cluster_invited` (`cluster_id`, `user_uuid`) VALUES(?,?)"); 3164 } 3165 }); 3166 } 3167 3168 @Override 3169 public boolean deleteTables() { 3170 try (Statement stmt = this.connection.createStatement(); 3171 PreparedStatement statement = this.connection 3172 .prepareStatement("DROP TABLE `" + this.prefix + "plot`")) { 3173 close(); 3174 this.closed = false; 3175 SQLManager.this.connection = this.database.forceConnection(); 3176 stmt.addBatch("DROP TABLE `" + this.prefix + "cluster_invited`"); 3177 stmt.addBatch("DROP TABLE `" + this.prefix + "cluster_helpers`"); 3178 stmt.addBatch("DROP TABLE `" + this.prefix + "cluster`"); 3179 stmt.addBatch("DROP TABLE `" + this.prefix + "plot_rating`"); 3180 stmt.addBatch("DROP TABLE `" + this.prefix + "plot_settings`"); 3181 stmt.addBatch("DROP TABLE `" + this.prefix + "plot_comments`"); 3182 stmt.addBatch("DROP TABLE `" + this.prefix + "plot_trusted`"); 3183 stmt.addBatch("DROP TABLE `" + this.prefix + "plot_helpers`"); 3184 stmt.addBatch("DROP TABLE `" + this.prefix + "plot_denied`"); 3185 stmt.executeBatch(); 3186 stmt.clearBatch(); 3187 statement.executeUpdate(); 3188 } catch (ClassNotFoundException | SQLException e) { 3189 e.printStackTrace(); 3190 3191 } 3192 return true; 3193 } 3194 3195 @SuppressWarnings({"unchecked", "unused"}) 3196 @Override 3197 public void validateAllPlots(Set<Plot> toValidate) { 3198 if (!isValid()) { 3199 reconnect(); 3200 } 3201 LOGGER.info( 3202 "All DB transactions during this session are being validated (This may take a while if corrections need to be made)"); 3203 commit(); 3204 while (true) { 3205 if (!sendBatch()) { 3206 break; 3207 } 3208 } 3209 try { 3210 if (this.connection.getAutoCommit()) { 3211 this.connection.setAutoCommit(false); 3212 } 3213 } catch (SQLException e) { 3214 e.printStackTrace(); 3215 } 3216 HashMap<String, HashMap<PlotId, Plot>> database = getPlots(); 3217 ArrayList<Plot> toCreate = new ArrayList<>(); 3218 for (Plot plot : toValidate) { 3219 if (plot.temp == -1) { 3220 continue; 3221 } 3222 if (plot.getArea() == null) { 3223 LOGGER.error("CRITICAL ERROR IN VALIDATION TASK: {}", plot); 3224 LOGGER.error("PLOT AREA CANNOT BE NULL! SKIPPING PLOT!"); 3225 LOGGER.info("Delete this entry from your database or set `database-purger: true` in the settings.yml"); 3226 continue; 3227 } 3228 if (database == null) { 3229 LOGGER.error("CRITICAL ERROR IN VALIDATION TASK!"); 3230 LOGGER.error("DATABASE VARIABLE CANNOT BE NULL! NOW ENDING VALIDATION!"); 3231 break; 3232 } 3233 HashMap<PlotId, Plot> worldPlots = database.get(plot.getArea().toString()); 3234 if (worldPlots == null) { 3235 toCreate.add(plot); 3236 continue; 3237 } 3238 Plot dataPlot = worldPlots.remove(plot.getId()); 3239 if (dataPlot == null) { 3240 toCreate.add(plot); 3241 continue; 3242 } 3243 // owner 3244 if (!plot.getOwnerAbs().equals(dataPlot.getOwnerAbs())) { 3245 setOwner(plot, plot.getOwnerAbs()); 3246 } 3247 // trusted 3248 if (!plot.getTrusted().equals(dataPlot.getTrusted())) { 3249 HashSet<UUID> toAdd = (HashSet<UUID>) plot.getTrusted().clone(); 3250 HashSet<UUID> toRemove = (HashSet<UUID>) dataPlot.getTrusted().clone(); 3251 toRemove.removeAll(plot.getTrusted()); 3252 toAdd.removeAll(dataPlot.getTrusted()); 3253 if (!toRemove.isEmpty()) { 3254 for (UUID uuid : toRemove) { 3255 removeTrusted(plot, uuid); 3256 } 3257 } 3258 if (!toAdd.isEmpty()) { 3259 for (UUID uuid : toAdd) { 3260 setTrusted(plot, uuid); 3261 } 3262 } 3263 } 3264 if (!plot.getMembers().equals(dataPlot.getMembers())) { 3265 HashSet<UUID> toAdd = (HashSet<UUID>) plot.getMembers().clone(); 3266 HashSet<UUID> toRemove = (HashSet<UUID>) dataPlot.getMembers().clone(); 3267 toRemove.removeAll(plot.getMembers()); 3268 toAdd.removeAll(dataPlot.getMembers()); 3269 if (!toRemove.isEmpty()) { 3270 for (UUID uuid : toRemove) { 3271 removeMember(plot, uuid); 3272 } 3273 } 3274 if (!toAdd.isEmpty()) { 3275 for (UUID uuid : toAdd) { 3276 setMember(plot, uuid); 3277 } 3278 } 3279 } 3280 if (!plot.getDenied().equals(dataPlot.getDenied())) { 3281 HashSet<UUID> toAdd = (HashSet<UUID>) plot.getDenied().clone(); 3282 HashSet<UUID> toRemove = (HashSet<UUID>) dataPlot.getDenied().clone(); 3283 toRemove.removeAll(plot.getDenied()); 3284 toAdd.removeAll(dataPlot.getDenied()); 3285 if (!toRemove.isEmpty()) { 3286 for (UUID uuid : toRemove) { 3287 removeDenied(plot, uuid); 3288 } 3289 } 3290 if (!toAdd.isEmpty()) { 3291 for (UUID uuid : toAdd) { 3292 setDenied(plot, uuid); 3293 } 3294 } 3295 } 3296 boolean[] pm = plot.getMerged(); 3297 boolean[] dm = dataPlot.getMerged(); 3298 if (pm[0] != dm[0] || pm[1] != dm[1]) { 3299 setMerged(dataPlot, plot.getMerged()); 3300 } 3301 Set<PlotFlag<?, ?>> pf = plot.getFlags(); 3302 Set<PlotFlag<?, ?>> df = dataPlot.getFlags(); 3303 if (!pf.isEmpty() && !df.isEmpty()) { 3304 if (pf.size() != df.size() || !StringMan 3305 .isEqual(StringMan.joinOrdered(pf, ","), StringMan.joinOrdered(df, ","))) { 3306 // setFlags(plot, pf); 3307 // TODO: Re-implement 3308 } 3309 } 3310 } 3311 3312 for (Entry<String, HashMap<PlotId, Plot>> entry : database.entrySet()) { 3313 HashMap<PlotId, Plot> map = entry.getValue(); 3314 if (!map.isEmpty()) { 3315 for (Entry<PlotId, Plot> entry2 : map.entrySet()) { 3316 // TODO implement this when sure safe" 3317 } 3318 } 3319 } 3320 commit(); 3321 } 3322 3323 @Override 3324 public void replaceWorld( 3325 final String oldWorld, final String newWorld, final PlotId min, 3326 final PlotId max 3327 ) { 3328 addGlobalTask(() -> { 3329 if (min == null) { 3330 try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( 3331 "UPDATE `" + SQLManager.this.prefix 3332 + "plot` SET `world` = ? WHERE `world` = ?")) { 3333 stmt.setString(1, newWorld); 3334 stmt.setString(2, oldWorld); 3335 stmt.executeUpdate(); 3336 } catch (SQLException e) { 3337 e.printStackTrace(); 3338 } 3339 try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( 3340 "UPDATE `" + SQLManager.this.prefix 3341 + "cluster` SET `world` = ? WHERE `world` = ?")) { 3342 stmt.setString(1, newWorld); 3343 stmt.setString(2, oldWorld); 3344 stmt.executeUpdate(); 3345 } catch (SQLException e) { 3346 e.printStackTrace(); 3347 } 3348 } else { 3349 try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( 3350 "UPDATE `" + SQLManager.this.prefix 3351 + "plot` SET `world` = ? WHERE `world` = ? AND `plot_id_x` BETWEEN ? AND ? AND `plot_id_z` BETWEEN ? AND ?")) { 3352 stmt.setString(1, newWorld); 3353 stmt.setString(2, oldWorld); 3354 stmt.setInt(3, min.getX()); 3355 stmt.setInt(4, max.getX()); 3356 stmt.setInt(5, min.getY()); 3357 stmt.setInt(6, max.getY()); 3358 stmt.executeUpdate(); 3359 } catch (SQLException e) { 3360 e.printStackTrace(); 3361 } 3362 try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( 3363 "UPDATE `" + SQLManager.this.prefix 3364 + "cluster` SET `world` = ? WHERE `world` = ? AND `pos1_x` <= ? AND `pos1_z` <= ? AND `pos2_x` >= ? AND `pos2_z` >= ?")) { 3365 stmt.setString(1, newWorld); 3366 stmt.setString(2, oldWorld); 3367 stmt.setInt(3, max.getX()); 3368 stmt.setInt(4, max.getY()); 3369 stmt.setInt(5, min.getX()); 3370 stmt.setInt(6, min.getY()); 3371 stmt.executeUpdate(); 3372 } catch (SQLException e) { 3373 e.printStackTrace(); 3374 } 3375 } 3376 }); 3377 } 3378 3379 @Override 3380 public void replaceUUID(final UUID old, final UUID now) { 3381 addGlobalTask(() -> { 3382 try (Statement stmt = SQLManager.this.connection.createStatement()) { 3383 stmt.executeUpdate( 3384 "UPDATE `" + SQLManager.this.prefix + "cluster` SET `owner` = '" + now 3385 .toString() + "' WHERE `owner` = '" + old.toString() + '\''); 3386 stmt.executeUpdate( 3387 "UPDATE `" + SQLManager.this.prefix + "cluster_helpers` SET `user_uuid` = '" 3388 + now + "' WHERE `user_uuid` = '" + old + '\''); 3389 stmt.executeUpdate( 3390 "UPDATE `" + SQLManager.this.prefix + "cluster_invited` SET `user_uuid` = '" 3391 + now + "' WHERE `user_uuid` = '" + old + '\''); 3392 stmt.executeUpdate( 3393 "UPDATE `" + SQLManager.this.prefix + "plot` SET `owner` = '" + now 3394 + "' WHERE `owner` = '" + old + '\''); 3395 stmt.executeUpdate( 3396 "UPDATE `" + SQLManager.this.prefix + "plot_denied` SET `user_uuid` = '" + now + "' WHERE `user_uuid` = '" + old + '\''); 3397 stmt.executeUpdate( 3398 "UPDATE `" + SQLManager.this.prefix + "plot_helpers` SET `user_uuid` = '" + now + "' WHERE `user_uuid` = '" + old + '\''); 3399 stmt.executeUpdate( 3400 "UPDATE `" + SQLManager.this.prefix + "plot_trusted` SET `user_uuid` = '" + now + "' WHERE `user_uuid` = '" + old + '\''); 3401 } catch (SQLException e) { 3402 e.printStackTrace(); 3403 } 3404 }); 3405 } 3406 3407 @Override 3408 public void close() { 3409 try { 3410 this.closed = true; 3411 this.connection.close(); 3412 } catch (SQLException e) { 3413 e.printStackTrace(); 3414 } 3415 } 3416 3417 private record LegacySettings( 3418 int id, 3419 PlotSettings settings 3420 ) { 3421 3422 } 3423 3424 public abstract static class UniqueStatement { 3425 3426 public final String method; 3427 3428 public UniqueStatement(String method) { 3429 this.method = method; 3430 } 3431 3432 public void addBatch(PreparedStatement statement) throws SQLException { 3433 statement.addBatch(); 3434 } 3435 3436 public void execute(PreparedStatement statement) throws SQLException { 3437 statement.executeBatch(); 3438 } 3439 3440 public abstract PreparedStatement get() throws SQLException; 3441 3442 public abstract void set(PreparedStatement statement) throws SQLException; 3443 3444 } 3445 3446 private record UUIDPair(int id, UUID uuid) { 3447 3448 } 3449 3450}