diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java index d60bbe3879..85517cad42 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java @@ -58,7 +58,6 @@ import com.plotsquared.bukkit.uuid.LuckPermsUUIDService; import com.plotsquared.bukkit.uuid.OfflinePlayerUUIDService; import com.plotsquared.bukkit.uuid.PaperUUIDService; -import com.plotsquared.bukkit.uuid.SQLiteUUIDService; import com.plotsquared.bukkit.uuid.SquirrelIdUUIDService; import com.plotsquared.core.PlotPlatform; import com.plotsquared.core.PlotSquared; @@ -71,7 +70,7 @@ import com.plotsquared.core.configuration.Storage; import com.plotsquared.core.configuration.caption.ChatFormatter; import com.plotsquared.core.configuration.file.YamlConfiguration; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.events.RemoveRoadEntityEvent; import com.plotsquared.core.events.Result; import com.plotsquared.core.generator.GeneratorWrapper; @@ -85,6 +84,7 @@ import com.plotsquared.core.inject.modules.PlotSquaredModule; import com.plotsquared.core.listener.PlotListener; import com.plotsquared.core.listener.WESubscriber; +import com.plotsquared.core.persistence.config.PersistenceModule; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; @@ -96,10 +96,10 @@ import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.plot.world.SinglePlotArea; import com.plotsquared.core.plot.world.SinglePlotAreaManager; +import com.plotsquared.core.services.config.ServiceModule; import com.plotsquared.core.setup.PlotAreaBuilder; import com.plotsquared.core.setup.SettingsNodesWrapper; import com.plotsquared.core.util.EventDispatcher; -import com.plotsquared.core.util.FileUtils; import com.plotsquared.core.util.PlatformWorldManager; import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.PremiumVerification; @@ -149,18 +149,10 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Queue; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; import static com.plotsquared.core.util.PremiumVerification.getDownloadID; import static com.plotsquared.core.util.PremiumVerification.getResourceID; @@ -298,7 +290,9 @@ public void onEnable() { new WorldManagerModule(), new PlotSquaredModule(), new BukkitModule(this), - new BackupModule() + new BackupModule(), + new PersistenceModule(), + new ServiceModule() ); this.injector.injectMembers(this); @@ -323,25 +317,6 @@ public void onEnable() { LOGGER.info("Couldn't verify purchase :("); } - // Database - if (Settings.Enabled_Components.DATABASE) { - plotSquared.setupDatabase(); - } - - // Check if we need to convert old flag values, etc - if (!plotSquared.getConfigurationVersion().equalsIgnoreCase("v5")) { - // Perform upgrade - if (DBFunc.dbManager.convertFlags()) { - LOGGER.info("Flags were converted successfully!"); - // Update the config version - try { - plotSquared.setConfigurationVersion("v5"); - } catch (final Exception e) { - e.printStackTrace(); - } - } - } - // Comments CommentManager.registerDefaultInboxes(); @@ -472,17 +447,6 @@ public void onEnable() { this.backgroundPipeline.registerService(offlinePlayerUUIDService); } - final SQLiteUUIDService sqLiteUUIDService = new SQLiteUUIDService("user_cache.db"); - - final SQLiteUUIDService legacyUUIDService; - if (Settings.UUID.LEGACY_DATABASE_SUPPORT && FileUtils - .getFile(PlotSquared.platform().getDirectory(), "usercache.db") - .exists()) { - legacyUUIDService = new SQLiteUUIDService("usercache.db"); - } else { - legacyUUIDService = null; - } - final LuckPermsUUIDService luckPermsUUIDService; if (Settings.UUID.SERVICE_LUCKPERMS && Bukkit.getPluginManager().getPlugin("LuckPerms") != null) { luckPermsUUIDService = new LuckPermsUUIDService(); @@ -508,16 +472,6 @@ public void onEnable() { LOGGER.info("(UUID) Using Paper as a complementary UUID service"); } - this.impromptuPipeline.registerService(sqLiteUUIDService); - this.backgroundPipeline.registerService(sqLiteUUIDService); - this.impromptuPipeline.registerConsumer(sqLiteUUIDService); - this.backgroundPipeline.registerConsumer(sqLiteUUIDService); - - if (legacyUUIDService != null) { - this.impromptuPipeline.registerService(legacyUUIDService); - this.backgroundPipeline.registerService(legacyUUIDService); - } - // Plugin providers if (luckPermsUUIDService != null) { this.impromptuPipeline.registerService(luckPermsUUIDService); @@ -534,23 +488,9 @@ public void onEnable() { } final SquirrelIdUUIDService backgroundMojangService = new SquirrelIdUUIDService(Settings.UUID.BACKGROUND_LIMIT); this.backgroundPipeline.registerService(backgroundMojangService); - } else { - this.impromptuPipeline.registerService(sqLiteUUIDService); - this.backgroundPipeline.registerService(sqLiteUUIDService); - this.impromptuPipeline.registerConsumer(sqLiteUUIDService); - this.backgroundPipeline.registerConsumer(sqLiteUUIDService); - - if (legacyUUIDService != null) { - this.impromptuPipeline.registerService(legacyUUIDService); - this.backgroundPipeline.registerService(legacyUUIDService); - } } - this.impromptuPipeline.storeImmediately("*", DBFunc.EVERYONE); - - if (Settings.UUID.BACKGROUND_CACHING_ENABLED) { - this.startUuidCaching(sqLiteUUIDService, cacheUUIDService); - } + this.impromptuPipeline.storeImmediately("*", StaticUUIDs.EVERYONE); if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { injector.getInstance(PAPIPlaceholders.class).register(); @@ -674,70 +614,6 @@ private void unload() { } } - private void startUuidCaching( - final @NonNull SQLiteUUIDService sqLiteUUIDService, - final @NonNull CacheUUIDService cacheUUIDService - ) { - // Record all unique UUID's and put them into a queue - final Set uuidSet = new HashSet<>(); - PlotSquared.get().forEachPlotRaw(plot -> { - uuidSet.add(plot.getOwnerAbs()); - uuidSet.addAll(plot.getMembers()); - uuidSet.addAll(plot.getTrusted()); - uuidSet.addAll(plot.getDenied()); - }); - final Queue uuidQueue = new LinkedBlockingQueue<>(uuidSet); - - LOGGER.info("(UUID) {} UUIDs will be cached", uuidQueue.size()); - - Executors.newSingleThreadScheduledExecutor().schedule(() -> { - // Begin by reading all the SQLite cache at once - cacheUUIDService.accept(sqLiteUUIDService.getAll()); - // Now fetch names for all known UUIDs - final int totalSize = uuidQueue.size(); - int read = 0; - LOGGER.info("(UUID) PlotSquared will fetch UUIDs in groups of {}", Settings.UUID.BACKGROUND_LIMIT); - final List uuidList = new ArrayList<>(Settings.UUID.BACKGROUND_LIMIT); - - // Used to indicate that the second retrieval has been attempted - boolean secondRun = false; - - while (!uuidQueue.isEmpty() || !uuidList.isEmpty()) { - if (!uuidList.isEmpty() && secondRun) { - LOGGER.warn("(UUID) Giving up on last batch. Fetching new batch instead"); - uuidList.clear(); - } - if (uuidList.isEmpty()) { - // Retrieve the secondRun variable to indicate that we're retrieving a - // fresh batch - secondRun = false; - // Populate the request list - for (int i = 0; i < Settings.UUID.BACKGROUND_LIMIT && !uuidQueue.isEmpty(); i++) { - uuidList.add(uuidQueue.poll()); - read++; - } - } else { - // If the list isn't empty then this is a second run for - // an old batch, so we re-use the patch - secondRun = true; - } - try { - PlotSquared.get().getBackgroundUUIDPipeline().getNames(uuidList).get(); - // Clear the list if we successfully index all the names - uuidList.clear(); - // Print progress - final double percentage = ((double) read / (double) totalSize) * 100.0D; - if (Settings.DEBUG) { - LOGGER.info("(UUID) PlotSquared has cached {} of UUIDs", String.format("%.1f%%", percentage)); - } - } catch (final InterruptedException | ExecutionException e) { - LOGGER.error("(UUID) Failed to retrieve last batch. Will try again", e); - } - } - LOGGER.info("(UUID) PlotSquared has cached all UUIDs"); - }, 10, TimeUnit.SECONDS); - } - @Override public void onDisable() { PlotSquared.get().disable(); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/HighFreqBlockEventListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/HighFreqBlockEventListener.java index 24a01eb996..80bd2550bf 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/HighFreqBlockEventListener.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/HighFreqBlockEventListener.java @@ -23,7 +23,7 @@ import com.plotsquared.bukkit.util.BukkitUtil; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.location.Location; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -112,7 +112,7 @@ public void onRedstoneEvent(BlockRedstoneEvent event) { } if (Settings.Redstone.DISABLE_OFFLINE) { boolean disable = false; - if (!DBFunc.SERVER.equals(plot.getOwner())) { + if (!StaticUUIDs.SERVER.equals(plot.getOwner())) { if (plot.isMerged()) { disable = true; for (UUID owner : plot.getOwners()) { diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java deleted file mode 100644 index 9193b4f0a0..0000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.bukkit.uuid; - -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.database.SQLite; -import com.plotsquared.core.util.FileUtils; -import com.plotsquared.core.uuid.UUIDMapping; -import com.plotsquared.core.uuid.UUIDService; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.UUID; -import java.util.function.Consumer; - -/** - * UUID service that uses the (legacy) SQL UUID cache - */ -public class SQLiteUUIDService implements UUIDService, Consumer> { - - private final SQLite sqlite; - - public SQLiteUUIDService(final String fileName) { - this.sqlite = - new SQLite(FileUtils.getFile(PlotSquared.platform().getDirectory(), fileName)); - try { - this.sqlite.openConnection(); - } catch (ClassNotFoundException | SQLException e) { - e.printStackTrace(); - } - - try (PreparedStatement stmt = getConnection().prepareStatement( - "CREATE TABLE IF NOT EXISTS `usercache` (uuid VARCHAR(32) NOT NULL, username VARCHAR(32) NOT NULL, PRIMARY KEY (uuid))")) { - stmt.execute(); - } catch (SQLException e) { - e.printStackTrace(); - } - } - - private Connection getConnection() { - synchronized (this.sqlite) { - return this.sqlite.getConnection(); - } - } - - @Override - public @NonNull List getNames(final @NonNull List uuids) { - final List mappings = new ArrayList<>(uuids.size()); - try (final PreparedStatement statement = getConnection() - .prepareStatement("SELECT `username` FROM `usercache` WHERE `uuid` = ?")) { - for (final UUID uuid : uuids) { - statement.setString(1, uuid.toString()); - try (final ResultSet resultSet = statement.executeQuery()) { - if (resultSet.next()) { - mappings.add(new UUIDMapping(uuid, resultSet.getString("username"))); - } - } - } - } catch (final Exception e) { - e.printStackTrace(); - } - return mappings; - } - - @Override - public @NonNull List getUUIDs(@NonNull List usernames) { - final List mappings = new ArrayList<>(usernames.size()); - try (final PreparedStatement statement = getConnection() - .prepareStatement("SELECT `uuid` FROM `usercache` WHERE `username` = ?")) { - for (final String username : usernames) { - statement.setString(1, username); - try (final ResultSet resultSet = statement.executeQuery()) { - if (resultSet.next()) { - mappings.add(new UUIDMapping( - UUID.fromString(resultSet.getString("uuid")), - username - )); - } - } - } - } catch (final Exception e) { - e.printStackTrace(); - } - return mappings; - } - - @Override - public void accept(final List uuidWrappers) { - try (final PreparedStatement statement = getConnection() - .prepareStatement("INSERT OR REPLACE INTO `usercache` (`uuid`, `username`) VALUES(?, ?)")) { - for (final UUIDMapping mapping : uuidWrappers) { - statement.setString(1, mapping.uuid().toString()); - statement.setString(2, mapping.username()); - statement.executeUpdate(); - } - } catch (SQLException e) { - e.printStackTrace(); - } - } - - /** - * Read the entire cache at once - * - * @return All read mappings - */ - public @NonNull List getAll() { - final List mappings = new LinkedList<>(); - try (final PreparedStatement statement = getConnection().prepareStatement("SELECT * FROM `usercache`")) { - try (final ResultSet resultSet = statement.executeQuery()) { - while (resultSet.next()) { - mappings.add(new UUIDMapping(UUID.fromString(resultSet.getString("uuid")), resultSet.getString("username"))); - } - } - } catch (final Exception e) { - e.printStackTrace(); - } - return mappings; - } - - -} diff --git a/Core/build.gradle.kts b/Core/build.gradle.kts index 5b7367be0a..3a7899e013 100644 --- a/Core/build.gradle.kts +++ b/Core/build.gradle.kts @@ -44,6 +44,19 @@ dependencies { api(libs.arkitektonika) api(libs.paster) api(libs.informativeAnnotations) + + // Database + api(libs.hibernateCore) + api(libs.hibernateHikariCp) + api(libs.hikari) + api(libs.hibernateCommunityDialects) + api(libs.jpaApi) + api(libs.liquibaseCore) + + runtimeOnly(libs.mariadbJavaClient) + runtimeOnly(libs.sqliteJdbc) + runtimeOnly(libs.h2) + runtimeOnly(libs.jaxbRuntime) } tasks.processResources { diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index af94ed1dde..9f2b6cbd68 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -30,11 +30,6 @@ import com.plotsquared.core.configuration.caption.load.DefaultCaptionProvider; import com.plotsquared.core.configuration.file.YamlConfiguration; import com.plotsquared.core.configuration.serialization.ConfigurationSerialization; -import com.plotsquared.core.database.DBFunc; -import com.plotsquared.core.database.Database; -import com.plotsquared.core.database.MySQL; -import com.plotsquared.core.database.SQLManager; -import com.plotsquared.core.database.SQLite; import com.plotsquared.core.generator.GeneratorWrapper; import com.plotsquared.core.generator.HybridPlotWorld; import com.plotsquared.core.generator.HybridUtils; @@ -55,8 +50,7 @@ import com.plotsquared.core.plot.expiration.ExpiryTask; import com.plotsquared.core.plot.flag.GlobalFlagContainer; import com.plotsquared.core.plot.world.PlotAreaManager; -import com.plotsquared.core.plot.world.SinglePlotArea; -import com.plotsquared.core.plot.world.SinglePlotAreaManager; +import com.plotsquared.core.services.api.ClusterService; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.FileUtils; import com.plotsquared.core.util.LegacyConverter; @@ -89,7 +83,6 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.StandardOpenOption; -import java.sql.SQLException; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; @@ -883,7 +876,8 @@ public void loadWorld( String name = cluster.getName(); // Cluster name String fullId = name + "-" + pos1 + "-" + pos2; worldSection.createSection("areas." + fullId); - DBFunc.replaceWorld(world, world + ";" + name, pos1, pos2); // NPE + PlotSquared.platform().injector().getInstance(ClusterService.class).replaceWorld(world, world + ";" + name, pos1, pos2); + // NPE LOGGER.info("- {}-{}-{}", name, pos1, pos2); GeneratorWrapper areaGen = this.platform.getGenerator(world, gen_string); if (areaGen == null) { @@ -1227,16 +1221,6 @@ public void disable() { try { eventDispatcher.unregisterAll(); checkRoadRegenPersistence(); - // Validate that all data in the db is correct - final HashSet plots = new HashSet<>(); - try { - forEachPlotRaw(plots::add); - } catch (final Exception ignored) { - } - DBFunc.validatePlots(plots); - - // Close the connection - DBFunc.close(); } catch (NullPointerException throwable) { LOGGER.error("Could not close database connection", throwable); throwable.printStackTrace(); @@ -1281,63 +1265,6 @@ private void checkRoadRegenPersistence() { } } - /** - * Set up the database connection. - */ - public void setupDatabase() { - try { - if (DBFunc.dbManager != null) { - DBFunc.dbManager.close(); - } - Database database; - if (Storage.MySQL.USE) { - database = new MySQL(Storage.MySQL.HOST, Storage.MySQL.PORT, Storage.MySQL.DATABASE, - Storage.MySQL.USER, Storage.MySQL.PASSWORD - ); - } else if (Storage.SQLite.USE) { - File file = FileUtils.getFile(platform.getDirectory(), Storage.SQLite.DB + ".db"); - database = new SQLite(file); - } else { - LOGGER.error("No storage type is set. Disabling PlotSquared"); - this.platform.shutdown(); //shutdown used instead of disable because no database is set - return; - } - DBFunc.dbManager = new SQLManager( - database, - Storage.PREFIX, - this.eventDispatcher, - this.plotListener, - this.worldConfiguration - ); - this.plots_tmp = DBFunc.getPlots(); - if (getPlotAreaManager() instanceof SinglePlotAreaManager) { - SinglePlotArea area = ((SinglePlotAreaManager) getPlotAreaManager()).getArea(); - addPlotArea(area); - ConfigurationSection section = worldConfiguration.getConfigurationSection("worlds.*"); - if (section == null) { - section = worldConfiguration.createSection("worlds.*"); - } - area.saveConfiguration(section); - area.loadDefaultConfiguration(section); - } - this.clustersTmp = DBFunc.getClusters(); - LOGGER.info("Connection to database established. Type: {}", Storage.MySQL.USE ? "MySQL" : "SQLite"); - } catch (ClassNotFoundException | SQLException e) { - LOGGER.error( - "Failed to open database connection ({}). Disabling PlotSquared", - Storage.MySQL.USE ? "MySQL" : "SQLite" - ); - LOGGER.error("==== Here is an ugly stacktrace, if you are interested in those things ==="); - e.printStackTrace(); - LOGGER.error("==== End of stacktrace ===="); - LOGGER.error( - "Please go to the {} 'storage.yml' and configure the database correctly", - platform.pluginName() - ); - this.platform.shutdown(); //shutdown used instead of disable because of database error - } - } - /** * Setup the default configuration. */ diff --git a/Core/src/main/java/com/plotsquared/core/command/Add.java b/Core/src/main/java/com/plotsquared/core/command/Add.java index 02a7124d24..715342f796 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Add.java +++ b/Core/src/main/java/com/plotsquared/core/command/Add.java @@ -22,7 +22,7 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -98,7 +98,7 @@ public CompletableFuture execute( int size = plot.getTrusted().size() + plot.getMembers().size(); while (iterator.hasNext()) { UUID uuid = iterator.next(); - if (uuid == DBFunc.EVERYONE && !(player.hasPermission(Permission.PERMISSION_TRUST_EVERYONE) || player.hasPermission( + if (uuid == StaticUUIDs.EVERYONE && !(player.hasPermission(Permission.PERMISSION_TRUST_EVERYONE) || player.hasPermission( Permission.PERMISSION_ADMIN_COMMAND_TRUST))) { player.sendMessage( TranslatableCaption.of("errors.invalid_player"), @@ -153,7 +153,7 @@ public CompletableFuture execute( // Success confirm.run(this, () -> { for (UUID uuid : uuids) { - if (uuid != DBFunc.EVERYONE) { + if (uuid != StaticUUIDs.EVERYONE) { if (!plot.removeTrusted(uuid)) { if (plot.getDenied().contains(uuid)) { plot.removeDenied(uuid); diff --git a/Core/src/main/java/com/plotsquared/core/command/Auto.java b/Core/src/main/java/com/plotsquared/core/command/Auto.java index 230ed9e3aa..8b05b131ef 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Auto.java +++ b/Core/src/main/java/com/plotsquared/core/command/Auto.java @@ -23,7 +23,6 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.PlayerAutoPlotEvent; import com.plotsquared.core.events.PlotAutoMergeEvent; import com.plotsquared.core.events.Result; @@ -35,6 +34,7 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.world.PlotAreaManager; +import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.services.plots.AutoQuery; import com.plotsquared.core.services.plots.AutoService; import com.plotsquared.core.util.EconHandler; @@ -158,7 +158,7 @@ private void claimSingle( } plot.setOwnerAbs(player.getUUID()); - final RunnableVal runnableVal = new RunnableVal<>() { + final RunnableVal successRunner = new RunnableVal<>() { { this.value = plot; } @@ -176,7 +176,8 @@ public void run(final Plot plot) { } }; - DBFunc.createPlotSafe(plot, runnableVal, () -> claimSingle(player, plot, plotArea, schematic)); + PlotService service = PlotSquared.platform().injector().getInstance(PlotService.class); + service.createPlotSafe(plot, successRunner, () -> {}); } diff --git a/Core/src/main/java/com/plotsquared/core/command/Claim.java b/Core/src/main/java/com/plotsquared/core/command/Claim.java index 422347449a..640f6c28bb 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Claim.java +++ b/Core/src/main/java/com/plotsquared/core/command/Claim.java @@ -19,9 +19,9 @@ package com.plotsquared.core.command; import com.google.inject.Inject; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.PlayerClaimPlotEvent; import com.plotsquared.core.events.PlotMergeEvent; import com.plotsquared.core.events.Result; @@ -32,6 +32,7 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.PlotExpression; @@ -199,7 +200,8 @@ public boolean onCommand(final PlotPlayer player, String[] args) { } plot.setOwnerAbs(player.getUUID()); final String finalSchematic = schematic; - DBFunc.createPlotSafe(plot, () -> { + PlotService service = PlotSquared.platform().injector().getInstance(PlotService.class); + service.createPlotSafe(plot, () -> { try { TaskManager.getPlatformImplementation().sync(() -> { if (!plot.claim(player, true, finalSchematic, false, false)) { diff --git a/Core/src/main/java/com/plotsquared/core/command/Cluster.java b/Core/src/main/java/com/plotsquared/core/command/Cluster.java index f52a56616b..ab2c5df23b 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Cluster.java +++ b/Core/src/main/java/com/plotsquared/core/command/Cluster.java @@ -22,7 +22,6 @@ import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.Caption; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.location.BlockLoc; import com.plotsquared.core.location.Location; @@ -32,6 +31,7 @@ import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotCluster; import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.services.api.ClusterService; import com.plotsquared.core.util.ComponentHelper; import com.plotsquared.core.util.TabCompletions; import com.plotsquared.core.util.query.PlotQuery; @@ -252,13 +252,13 @@ public boolean onCommand(PlotPlayer player, String[] args) { // create cluster cluster.settings.setAlias(name); area.addCluster(cluster); - DBFunc.createCluster(cluster); + PlotSquared.platform().injector().getInstance(ClusterService.class).createCluster(cluster); // Add any existing plots to the current cluster for (Plot plot : plots) { if (plot.hasOwner()) { if (!cluster.isAdded(plot.getOwner())) { cluster.invited.add(plot.getOwner()); - DBFunc.setInvited(cluster, plot.getOwner()); + PlotSquared.platform().injector().getInstance(ClusterService.class).setInvited(cluster, plot.getOwner()); } } } @@ -320,7 +320,7 @@ public boolean onCommand(PlotPlayer player, String[] args) { return false; } } - DBFunc.delete(cluster); + PlotSquared.platform().injector().getInstance(ClusterService.class).delete(cluster); player.sendMessage(TranslatableCaption.of("cluster.cluster_deleted"), TagResolver.resolver( "cluster", Tag.inserting(Component.text(cluster.toString())) @@ -444,7 +444,7 @@ public boolean onCommand(PlotPlayer player, String[] args) { return false; } // resize cluster - DBFunc.resizeCluster(cluster, pos1, pos2); + PlotSquared.platform().injector().getInstance(ClusterService.class).resizeCluster(cluster, pos1, pos2); player.sendMessage(TranslatableCaption.of("cluster.cluster_resized")); return true; } @@ -502,7 +502,7 @@ public boolean onCommand(PlotPlayer player, String[] args) { if (!cluster.isAdded(uuid)) { // add the user if not added cluster.invited.add(uuid); - DBFunc.setInvited(cluster, uuid); + PlotSquared.platform().injector().getInstance(ClusterService.class).setInvited(cluster, uuid); final PlotPlayer otherPlayer = PlotSquared.platform().playerManager().getPlayerIfExists(uuid); if (otherPlayer != null) { @@ -577,10 +577,10 @@ public boolean onCommand(PlotPlayer player, String[] args) { } else { if (cluster.helpers.contains(uuid)) { cluster.helpers.remove(uuid); - DBFunc.removeHelper(cluster, uuid); + PlotSquared.platform().injector().getInstance(ClusterService.class).removeHelper(cluster, uuid); } cluster.invited.remove(uuid); - DBFunc.removeInvited(cluster, uuid); + PlotSquared.platform().injector().getInstance(ClusterService.class).removeInvited(cluster, uuid); final PlotPlayer player2 = PlotSquared.platform().playerManager().getPlayerIfExists(uuid); @@ -647,10 +647,10 @@ public boolean onCommand(PlotPlayer player, String[] args) { } if (cluster.helpers.contains(uuid)) { cluster.helpers.remove(uuid); - DBFunc.removeHelper(cluster, uuid); + PlotSquared.platform().injector().getInstance(ClusterService.class).removeHelper(cluster, uuid); } cluster.invited.remove(uuid); - DBFunc.removeInvited(cluster, uuid); + PlotSquared.platform().injector().getInstance(ClusterService.class).removeInvited(cluster, uuid); player.sendMessage( TranslatableCaption.of("cluster.cluster_removed"), TagResolver.resolver("cluster", Tag.inserting(Component.text(cluster.getName()))) @@ -701,11 +701,11 @@ public boolean onCommand(PlotPlayer player, String[] args) { } else { if (args[1].equalsIgnoreCase("add")) { cluster.helpers.add(uuid); - DBFunc.setHelper(cluster, uuid); + PlotSquared.platform().injector().getInstance(ClusterService.class).setHelper(cluster, uuid); player.sendMessage(TranslatableCaption.of("cluster.cluster_added_helper")); } else if (args[1].equalsIgnoreCase("remove")) { cluster.helpers.remove(uuid); - DBFunc.removeHelper(cluster, uuid); + PlotSquared.platform().injector().getInstance(ClusterService.class).removeHelper(cluster, uuid); player.sendMessage(TranslatableCaption.of("cluster.cluster_removed_helper")); } else { player.sendMessage( @@ -872,7 +872,7 @@ public boolean onCommand(PlotPlayer player, String[] args) { Location relative = player.getLocation().subtract(base.getX(), 0, base.getZ()); BlockLoc blockloc = new BlockLoc(relative.getX(), relative.getY(), relative.getZ()); cluster.settings.setPosition(blockloc); - DBFunc.setPosition( + PlotSquared.platform().injector().getInstance(ClusterService.class).setPosition( cluster, relative.getX() + "," + relative.getY() + "," + relative.getZ() ); diff --git a/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java b/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java index 5d24194c0d..2ba5ccafc8 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java +++ b/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java @@ -19,257 +19,102 @@ package com.plotsquared.core.command; import com.google.inject.Inject; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.configuration.caption.StaticCaption; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.configuration.file.YamlConfiguration; -import com.plotsquared.core.database.DBFunc; -import com.plotsquared.core.database.Database; -import com.plotsquared.core.database.MySQL; -import com.plotsquared.core.database.SQLManager; -import com.plotsquared.core.database.SQLite; -import com.plotsquared.core.inject.annotations.WorldConfig; -import com.plotsquared.core.listener.PlotListener; +import com.plotsquared.core.persistence.config.LiquibaseCrossDatabaseMigrationService; import com.plotsquared.core.player.PlotPlayer; -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.PlotArea; -import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.world.PlotAreaManager; -import com.plotsquared.core.plot.world.SinglePlotArea; -import com.plotsquared.core.util.EventDispatcher; -import com.plotsquared.core.util.FileUtils; -import com.plotsquared.core.util.query.PlotQuery; -import com.plotsquared.core.util.task.TaskManager; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.tag.Tag; -import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; -import org.checkerframework.checker.nullness.qual.NonNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.io.File; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map.Entry; +import java.util.concurrent.CompletableFuture; -@CommandDeclaration(command = "database", - aliases = {"convert"}, +/** + * Command for migrating databases between SQLite and MySQL using Liquibase. + * All migrations now run completely through Liquibase without native SQL queries. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +@CommandDeclaration( + command = "database", + aliases = {"db", "migrate"}, category = CommandCategory.ADMINISTRATION, - permission = "plots.database", requiredType = RequiredType.CONSOLE, - usage = "/plot database [area] ") + permission = "plots.admin.database" +) public class DatabaseCommand extends SubCommand { - private final PlotAreaManager plotAreaManager; - private final EventDispatcher eventDispatcher; - private final PlotListener plotListener; - private final YamlConfiguration worldConfiguration; + private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseCommand.class); + + private final LiquibaseCrossDatabaseMigrationService liquibaseMigrationService; @Inject - public DatabaseCommand( - final @NonNull PlotAreaManager plotAreaManager, - final @NonNull EventDispatcher eventDispatcher, - final @NonNull PlotListener plotListener, - @WorldConfig final @NonNull YamlConfiguration worldConfiguration - ) { - this.plotAreaManager = plotAreaManager; - this.eventDispatcher = eventDispatcher; - this.plotListener = plotListener; - this.worldConfiguration = worldConfiguration; + public DatabaseCommand(LiquibaseCrossDatabaseMigrationService liquibaseMigrationService) { + this.liquibaseMigrationService = liquibaseMigrationService; } - public static void insertPlots( - final SQLManager manager, final List plots, - final PlotPlayer player - ) { - TaskManager.runTaskAsync(() -> { + @Override + public boolean onCommand(PlotPlayer player, String[] args) { + if (args.length == 0) { + player.sendMessage(TranslatableCaption.of("database.usage")); + return false; + } + + String subCommand = args[0].toLowerCase(); + + switch (subCommand) { + case "migrate-to-mysql": + migrateToMySQL(player); + break; + + case "migrate-to-h2": + migrateToH2(player); + break; + default: + player.sendMessage(TranslatableCaption.of("database.unknown_subcommand")); + player.sendMessage(TranslatableCaption.of("database.available_commands")); + return false; + } + + return true; + } + + private void migrateToMySQL(PlotPlayer player) { + player.sendMessage(TranslatableCaption.of("database.migration_mysql_started")); + + CompletableFuture.runAsync(() -> { try { - ArrayList ps = new ArrayList<>(plots); - player.sendMessage(TranslatableCaption.of("database.starting_conversion")); - manager.createPlotsAndData(ps, () -> { - player.sendMessage(TranslatableCaption.of("database.conversion_done")); - manager.close(); - }); + liquibaseMigrationService.migrateToMySQL(); + + player.sendMessage(TranslatableCaption.of("database.migration_completed")); + player.sendMessage(TranslatableCaption.of("database.update_config_reminder")); + + } catch (IllegalStateException e) { + player.sendMessage(TranslatableCaption.of("database.mysql_not_configured")); } catch (Exception e) { - player.sendMessage(TranslatableCaption.of("database.conversion_failed")); - e.printStackTrace(); + player.sendMessage(TranslatableCaption.of("database.migration_failed")); + LOGGER.error("Database migration to MySQL failed", e); } }); } - @Override - public boolean onCommand(final PlotPlayer player, String[] args) { - if (args.length < 1) { - player.sendMessage( - TranslatableCaption.of("commandconfig.command_syntax"), - TagResolver.resolver( - "value", - Tag.inserting(Component.text("/plot database [area] ")) - ) - ); - return false; - } - List plots; - PlotArea area = this.plotAreaManager.getPlotAreaByString(args[0]); - if (area != null) { - plots = PlotSquared.get().sortPlotsByTemp(area.getPlots()); - args = Arrays.copyOfRange(args, 1, args.length); - } else { - plots = PlotSquared.get().sortPlotsByTemp(PlotQuery.newQuery().allPlots().asList()); - } - if (args.length < 1) { - player.sendMessage( - TranslatableCaption.of("commandconfig.command_syntax"), - TagResolver.resolver("value", Tag.inserting(Component.text("/plot database [area] "))) - ); - player.sendMessage(TranslatableCaption.of("database.arg")); - return false; - } - try { - Database implementation; - String prefix = ""; - switch (args[0].toLowerCase()) { - case "import" -> { - if (args.length < 2) { - player.sendMessage( - TranslatableCaption.of("commandconfig.command_syntax"), - TagResolver.resolver( - "value", - Tag.inserting(Component.text("/plot database import [prefix]")) - ) - ); - return false; - } - File file = FileUtils.getFile( - PlotSquared.platform().getDirectory(), - args[1].endsWith(".db") ? args[1] : args[1] + ".db" - ); - if (!file.exists()) { - player.sendMessage( - TranslatableCaption.of("database.does_not_exist"), - TagResolver.resolver("value", Tag.inserting(Component.text(file.toString()))) - ); - return false; - } - player.sendMessage(TranslatableCaption.of("database.starting_conversion")); - implementation = new SQLite(file); - SQLManager manager = new SQLManager(implementation, args.length == 3 ? args[2] : "", - this.eventDispatcher, this.plotListener, this.worldConfiguration - ); - HashMap> map = manager.getPlots(); - plots = new ArrayList<>(); - for (Entry> entry : map.entrySet()) { - String areaName = entry.getKey(); - PlotArea pa = this.plotAreaManager.getPlotAreaByString(areaName); - if (pa != null) { - for (Entry entry2 : entry.getValue().entrySet()) { - Plot plot = entry2.getValue(); - if (pa.getOwnedPlotAbs(plot.getId()) != null) { - if (pa instanceof SinglePlotArea) { - Plot newPlot = pa.getNextFreePlot(null, plot.getId()); - if (newPlot != null) { - PlotId newId = newPlot.getId(); - PlotId id = plot.getId(); - File worldFile = - new File( - PlotSquared.platform().worldContainer(), - id.toCommaSeparatedString() - ); - if (worldFile.exists()) { - File newFile = - new File( - PlotSquared.platform().worldContainer(), - newId.toCommaSeparatedString() - ); - worldFile.renameTo(newFile); - } - plot.setId(newId); - plot.setArea(pa); - plots.add(plot); - continue; - } - } - player.sendMessage( - TranslatableCaption.of("database.skipping_duplicated_plot"), - TagResolver.builder() - .tag("plot", Tag.inserting(Component.text(plot.toString()))) - .tag("id", Tag.inserting(Component.text(plot.temp))) - .build() - ); - continue; - } - plot.setArea(pa); - plots.add(plot); - } - } else { - HashMap plotMap = PlotSquared.get().plots_tmp - .computeIfAbsent(areaName, k -> new HashMap<>()); - plotMap.putAll(entry.getValue()); - } - } - DBFunc.createPlotsAndData( - plots, - () -> player.sendMessage(TranslatableCaption.of("database.conversion_done")) - ); - return true; - } - case "mysql" -> { - if (args.length < 6) { - player.sendMessage(StaticCaption.of( - "/plot database mysql [host] [port] [username] [password] [database] {prefix}")); - return false; - } - String host = args[1]; - String port = args[2]; - String username = args[3]; - String password = args[4]; - String database = args[5]; - if (args.length > 6) { - prefix = args[6]; - } - implementation = new MySQL(host, port, database, username, password); - } - case "sqlite" -> { - if (args.length < 2) { - player.sendMessage(StaticCaption.of("/plot database sqlite [file]")); - return false; - } - File sqliteFile = - FileUtils.getFile(PlotSquared.platform().getDirectory(), args[1] + ".db"); - implementation = new SQLite(sqliteFile); - } - default -> { - player.sendMessage(StaticCaption.of("/plot database [sqlite/mysql]")); - return false; - } - } + private void migrateToH2(PlotPlayer player) { + player.sendMessage(TranslatableCaption.of("database.migration_sqlite_started")); + + CompletableFuture.runAsync(() -> { try { - SQLManager manager = new SQLManager( - implementation, - prefix, - this.eventDispatcher, - this.plotListener, - this.worldConfiguration - ); - DatabaseCommand.insertPlots(manager, plots, player); - return true; - } catch (ClassNotFoundException | SQLException e) { - player.sendMessage(TranslatableCaption.of("database.failed_to_save_plots")); - player.sendMessage(TranslatableCaption.of("errors.stacktrace_begin")); - e.printStackTrace(); - player.sendMessage(TranslatableCaption.of("errors.stacktrace_end")); - player.sendMessage(TranslatableCaption.of("database.invalid_args")); - return false; + liquibaseMigrationService.migrateToH2(); + + player.sendMessage(TranslatableCaption.of("database.migration_completed")); + player.sendMessage(TranslatableCaption.of("database.update_config_reminder")); + + } catch (IllegalStateException e) { + player.sendMessage(TranslatableCaption.of("database.sqlite_not_configured")); + } catch (Exception e) { + player.sendMessage(TranslatableCaption.of("database.migration_failed")); + LOGGER.error("Database migration to SQLite failed", e); } - } catch (ClassNotFoundException | SQLException e) { - player.sendMessage(TranslatableCaption.of("database.failed_to_open")); - player.sendMessage(TranslatableCaption.of("errors.stacktrace_begin")); - e.printStackTrace(); - player.sendMessage(TranslatableCaption.of("errors.stacktrace_end")); - player.sendMessage(TranslatableCaption.of("database.invalid_args")); - return false; - } + }); } - } diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugLoadTest.java b/Core/src/main/java/com/plotsquared/core/command/DebugLoadTest.java index 8416a00b55..3362058977 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugLoadTest.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugLoadTest.java @@ -19,8 +19,8 @@ package com.plotsquared.core.command; import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.services.api.PlotService; @CommandDeclaration(command = "debugloadtest", permission = "plots.debugloadtest", @@ -31,7 +31,8 @@ public class DebugLoadTest extends SubCommand { @Override public boolean onCommand(PlotPlayer player, String[] args) { - PlotSquared.get().plots_tmp = DBFunc.getPlots(); + PlotService plotService = PlotSquared.platform().injector().getInstance(PlotService.class); + PlotSquared.get().plots_tmp = plotService.getPlots(); return true; } diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java b/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java index 2e259b8f85..d5273dba36 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java @@ -18,10 +18,11 @@ */ package com.plotsquared.core.command; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.util.query.PlotQuery; import java.util.List; @@ -37,7 +38,8 @@ public class DebugSaveTest extends SubCommand { public boolean onCommand(final PlotPlayer player, String[] args) { final List plots = PlotQuery.newQuery().allPlots().asList(); player.sendMessage(TranslatableCaption.of("debugsavetest.starting")); - DBFunc.createPlotsAndData( + PlotService service = PlotSquared.platform().injector().getInstance(PlotService.class); + service.createPlotsAndData( plots, () -> player.sendMessage(TranslatableCaption.of("debugsavetest.done")) ); diff --git a/Core/src/main/java/com/plotsquared/core/command/Deny.java b/Core/src/main/java/com/plotsquared/core/command/Deny.java index 8d7365f6e0..290cae095a 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Deny.java +++ b/Core/src/main/java/com/plotsquared/core/command/Deny.java @@ -22,7 +22,7 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.location.Location; import com.plotsquared.core.permissions.Permission; @@ -104,7 +104,7 @@ public boolean onCommand(PlotPlayer player, String[] args) { ); } else { for (UUID uuid : uuids) { - if (uuid == DBFunc.EVERYONE && !( + if (uuid == StaticUUIDs.EVERYONE && !( player.hasPermission(Permission.PERMISSION_DENY_EVERYONE) || player.hasPermission(Permission.PERMISSION_ADMIN_COMMAND_DENY))) { player.sendMessage( TranslatableCaption.of("errors.invalid_player"), @@ -124,13 +124,13 @@ public boolean onCommand(PlotPlayer player, String[] args) { ); return; } else { - if (uuid != DBFunc.EVERYONE) { + if (uuid != StaticUUIDs.EVERYONE) { plot.removeMember(uuid); plot.removeTrusted(uuid); } plot.addDenied(uuid); this.eventDispatcher.callDenied(player, plot, uuid, true); - if (!uuid.equals(DBFunc.EVERYONE)) { + if (!uuid.equals(StaticUUIDs.EVERYONE)) { handleKick(PlotSquared.platform().playerManager().getPlayerIfExists(uuid), plot); } else { for (PlotPlayer plotPlayer : plot.getPlayersInPlot()) { diff --git a/Core/src/main/java/com/plotsquared/core/command/Grant.java b/Core/src/main/java/com/plotsquared/core/command/Grant.java index 18db0c77dc..4b94ddf73d 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Grant.java +++ b/Core/src/main/java/com/plotsquared/core/command/Grant.java @@ -21,14 +21,13 @@ import com.google.common.primitives.Ints; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.MetaDataAccess; import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.services.api.PlayerMetaService; import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.TabCompletions; -import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; import net.kyori.adventure.text.Component; @@ -43,6 +42,7 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; import java.util.stream.Collectors; @CommandDeclaration(command = "grant", @@ -108,39 +108,41 @@ public CompletableFuture execute( } } } else { - DBFunc.getPersistentMeta(uuid, new RunnableVal<>() { - @Override - public void run(Map value) { - final byte[] array = value.get("grantedPlots"); - if (arg0.equals("check")) { // check - int granted; - if (array == null) { - granted = 0; - } else { - granted = Ints.fromByteArray(array); - } - player.sendMessage( - TranslatableCaption.of("grants.granted_plots"), - TagResolver.resolver("amount", Tag.inserting(Component.text(granted))) - ); - } else { // add - int amount; - if (array == null) { - amount = 1; - } else { - amount = 1 + Ints.fromByteArray(array); - } - boolean replace = array != null; - String key = "grantedPlots"; - byte[] rawData = Ints.toByteArray(amount); - DBFunc.addPersistentMeta(uuid, key, rawData, replace); - player.sendMessage( - TranslatableCaption.of("grants.added"), - TagResolver.resolver("grants", Tag.inserting(Component.text(amount))) - ); + Consumer> resultConsumer = (value) -> { + final byte[] array = value.get("grantedPlots"); + if (arg0.equals("check")) { // check + int granted; + if (array == null) { + granted = 0; + } else { + granted = Ints.fromByteArray(array); } + player.sendMessage( + TranslatableCaption.of("grants.granted_plots"), + TagResolver.resolver("amount", Tag.inserting(Component.text(granted))) + ); + } else { // add + int amount; + if (array == null) { + amount = 1; + } else { + amount = 1 + Ints.fromByteArray(array); + } + boolean delete = array != null; + String key = "grantedPlots"; + byte[] rawData = Ints.toByteArray(amount); + PlayerMetaService service = + PlotSquared.platform().injector().getInstance(PlayerMetaService.class); + service.addPersistentMeta(uuid, key, rawData, delete); + player.sendMessage( + TranslatableCaption.of("grants.added"), + TagResolver.resolver("grants", Tag.inserting(Component.text(amount))) + ); } - }); + }; + PlayerMetaService service = + PlotSquared.platform().injector().getInstance(PlayerMetaService.class); + service.getPersistentMeta(uuid, resultConsumer); } } }); diff --git a/Core/src/main/java/com/plotsquared/core/command/Info.java b/Core/src/main/java/com/plotsquared/core/command/Info.java index 3efabe114d..b9f1998160 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Info.java +++ b/Core/src/main/java/com/plotsquared/core/command/Info.java @@ -21,7 +21,7 @@ import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.Caption; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -111,8 +111,8 @@ public boolean onCommand(final PlotPlayer player, String[] args) { boolean hasOwner = plot.hasOwner(); // Wildcard player {added} - boolean containsEveryone = plot.getTrusted().contains(DBFunc.EVERYONE); - boolean trustedEveryone = plot.getMembers().contains(DBFunc.EVERYONE); + boolean containsEveryone = plot.getTrusted().contains(StaticUUIDs.EVERYONE); + boolean trustedEveryone = plot.getMembers().contains(StaticUUIDs.EVERYONE); // Unclaimed? if (!hasOwner && !containsEveryone && !trustedEveryone) { player.sendMessage( diff --git a/Core/src/main/java/com/plotsquared/core/command/Kick.java b/Core/src/main/java/com/plotsquared/core/command/Kick.java index ced145fa58..16c32b6c8d 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Kick.java +++ b/Core/src/main/java/com/plotsquared/core/command/Kick.java @@ -21,7 +21,7 @@ import com.google.inject.Inject; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.location.Location; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.PlotPlayer; @@ -86,7 +86,7 @@ public boolean onCommand(PlotPlayer player, String[] args) { } else { Set> players = new HashSet<>(); for (UUID uuid : uuids) { - if (uuid == DBFunc.EVERYONE) { + if (uuid == StaticUUIDs.EVERYONE) { for (PlotPlayer pp : plot.getPlayersInPlot()) { if (pp == player || pp.hasPermission(Permission.PERMISSION_ADMIN_ENTRY_DENIED)) { continue; diff --git a/Core/src/main/java/com/plotsquared/core/command/Like.java b/Core/src/main/java/com/plotsquared/core/command/Like.java index 78a60327dc..1f4c0369d6 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Like.java +++ b/Core/src/main/java/com/plotsquared/core/command/Like.java @@ -19,9 +19,9 @@ package com.plotsquared.core.command; import com.google.inject.Inject; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.PlotRateEvent; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.permissions.Permission; @@ -29,6 +29,7 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.Rating; import com.plotsquared.core.plot.flag.implementations.DoneFlag; +import com.plotsquared.core.services.api.RatingService; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.TabCompletions; import com.plotsquared.core.util.query.PlotQuery; @@ -184,7 +185,7 @@ protected boolean handleLike( if (plot.getSettings().getRatings() == null) { if (!Settings.Enabled_Components.RATING_CACHE) { TaskManager.runTaskAsync(() -> { - plot.getSettings().setRatings(DBFunc.getRatings(plot)); + plot.getSettings().setRatings(PlotSquared.platform().injector().getInstance(RatingService.class).getRatings(plot)); run.run(); }); return true; diff --git a/Core/src/main/java/com/plotsquared/core/command/ListCmd.java b/Core/src/main/java/com/plotsquared/core/command/ListCmd.java index 2766721ffd..38e6b7cca7 100644 --- a/Core/src/main/java/com/plotsquared/core/command/ListCmd.java +++ b/Core/src/main/java/com/plotsquared/core/command/ListCmd.java @@ -24,7 +24,7 @@ import com.plotsquared.core.configuration.caption.Caption; import com.plotsquared.core.configuration.caption.CaptionHolder; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -419,7 +419,7 @@ public void run(Integer i, Plot plot, CaptionHolder caption) { Caption color; if (plot.getOwner() == null) { color = TranslatableCaption.of("info.plot_list_no_owner"); - } else if (plot.isOwner(player.getUUID()) || plot.getOwner().equals(DBFunc.EVERYONE)) { + } else if (plot.isOwner(player.getUUID()) || plot.getOwner().equals(StaticUUIDs.EVERYONE)) { color = TranslatableCaption.of("info.plot_list_owned_by"); } else if (plot.isAdded(player.getUUID())) { color = TranslatableCaption.of("info.plot_list_added_to"); @@ -487,7 +487,7 @@ public void run(Integer i, Plot plot, CaptionHolder caption) { Tag.inserting(TranslatableCaption.of("info.unknown").toComponent(player)) ); builder.append(MINI_MESSAGE.deserialize(unknown, unknownResolver)); - } else if (uuidMapping.uuid().equals(DBFunc.EVERYONE)) { + } else if (uuidMapping.uuid().equals(StaticUUIDs.EVERYONE)) { TagResolver everyoneResolver = TagResolver.resolver( "everyone", Tag.inserting(TranslatableCaption.of("info.everyone").toComponent(player)) diff --git a/Core/src/main/java/com/plotsquared/core/command/MainCommand.java b/Core/src/main/java/com/plotsquared/core/command/MainCommand.java index 5ceafa6011..fe6c5cf143 100644 --- a/Core/src/main/java/com/plotsquared/core/command/MainCommand.java +++ b/Core/src/main/java/com/plotsquared/core/command/MainCommand.java @@ -80,6 +80,7 @@ public static MainCommand getInstance() { if (Settings.Web.LEGACY_WEBINTERFACE) { LOGGER.warn("Legacy webinterface is used. Please note that it will be removed in future."); } + commands.add(DatabaseCommand.class); commands.add(Load.class); commands.add(Confirm.class); commands.add(Template.class); @@ -117,7 +118,6 @@ public static MainCommand getInstance() { commands.add(Kick.class); commands.add(Inbox.class); commands.add(Comment.class); - commands.add(DatabaseCommand.class); commands.add(Swap.class); commands.add(Music.class); commands.add(DebugRoadRegen.class); diff --git a/Core/src/main/java/com/plotsquared/core/command/Purge.java b/Core/src/main/java/com/plotsquared/core/command/Purge.java index 873c732b93..bc8bfa055e 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Purge.java +++ b/Core/src/main/java/com/plotsquared/core/command/Purge.java @@ -22,13 +22,13 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.listener.PlotListener; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.plot.world.PlotAreaManager; +import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.query.PlotQuery; import com.plotsquared.core.util.task.TaskManager; @@ -241,7 +241,7 @@ public void run() { TaskManager.runTaskAsync(this); } else { TaskManager.runTask(() -> { - DBFunc.purgeIds(ids); + PlotSquared.platform().injector().getInstance(PlotService.class).purgeIds(ids); player.sendMessage( TranslatableCaption.of("purge.purge_success"), TagResolver.resolver( diff --git a/Core/src/main/java/com/plotsquared/core/command/Rate.java b/Core/src/main/java/com/plotsquared/core/command/Rate.java index 6e1319cc84..a2425a9d5f 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Rate.java +++ b/Core/src/main/java/com/plotsquared/core/command/Rate.java @@ -19,9 +19,9 @@ package com.plotsquared.core.command; import com.google.inject.Inject; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.PlotRateEvent; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.permissions.Permission; @@ -31,6 +31,7 @@ import com.plotsquared.core.plot.PlotItemStack; import com.plotsquared.core.plot.Rating; import com.plotsquared.core.plot.flag.implementations.DoneFlag; +import com.plotsquared.core.services.api.RatingService; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.InventoryUtil; import com.plotsquared.core.util.MathMan; @@ -210,7 +211,7 @@ public boolean onClick(int i) { if (plot.getSettings().getRatings() == null) { if (!Settings.Enabled_Components.RATING_CACHE) { TaskManager.runTaskAsync(() -> { - plot.getSettings().setRatings(DBFunc.getRatings(plot)); + plot.getSettings().setRatings(PlotSquared.platform().injector().getInstance(RatingService.class).getRatings(plot)); run.run(); }); return true; @@ -258,7 +259,7 @@ public boolean onClick(int i) { if (plot.getSettings().getRatings() == null) { if (!Settings.Enabled_Components.RATING_CACHE) { TaskManager.runTaskAsync(() -> { - plot.getSettings().setRatings(DBFunc.getRatings(plot)); + plot.getSettings().setRatings(PlotSquared.platform().injector().getInstance(RatingService.class).getRatings(plot)); run.run(); }); return true; diff --git a/Core/src/main/java/com/plotsquared/core/command/Remove.java b/Core/src/main/java/com/plotsquared/core/command/Remove.java index e2fd2faca5..4846c4bd9e 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Remove.java +++ b/Core/src/main/java/com/plotsquared/core/command/Remove.java @@ -20,7 +20,7 @@ import com.google.inject.Inject; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -97,7 +97,7 @@ public boolean onCommand(PlotPlayer player, String[] args) { this.eventDispatcher.callDenied(player, plot, uuid, false); count++; } - } else if (uuid == DBFunc.EVERYONE) { + } else if (uuid == StaticUUIDs.EVERYONE) { count += plot.getTrusted().size(); if (plot.removeTrusted(uuid)) { this.eventDispatcher.callTrusted(player, plot, uuid, false); diff --git a/Core/src/main/java/com/plotsquared/core/command/Trust.java b/Core/src/main/java/com/plotsquared/core/command/Trust.java index 23d306ad39..5526fae074 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Trust.java +++ b/Core/src/main/java/com/plotsquared/core/command/Trust.java @@ -22,7 +22,7 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -100,7 +100,7 @@ public CompletableFuture execute( int size = currentPlot.getTrusted().size() + currentPlot.getMembers().size(); while (iterator.hasNext()) { UUID uuid = iterator.next(); - if (uuid == DBFunc.EVERYONE && !( + if (uuid == StaticUUIDs.EVERYONE && !( player.hasPermission(Permission.PERMISSION_TRUST_EVERYONE) || player.hasPermission(Permission.PERMISSION_ADMIN_COMMAND_TRUST))) { player.sendMessage( TranslatableCaption.of("errors.invalid_player"), @@ -152,7 +152,7 @@ public CompletableFuture execute( // Success confirm.run(this, () -> { for (UUID uuid : uuids) { - if (uuid != DBFunc.EVERYONE) { + if (uuid != StaticUUIDs.EVERYONE) { if (!currentPlot.removeMember(uuid)) { if (currentPlot.getDenied().contains(uuid)) { currentPlot.removeDenied(uuid); diff --git a/Core/src/main/java/com/plotsquared/core/configuration/Storage.java b/Core/src/main/java/com/plotsquared/core/configuration/Storage.java index db637ac70a..43698152e2 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Storage.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Storage.java @@ -57,10 +57,22 @@ public static final class MySQL { public static final class SQLite { @Comment("Should SQLite be used?") - public static boolean USE = true; + public static boolean USE = false; @Comment("The file to use") public static String DB = "storage"; } + @Comment("H2 section") + public static final class H2 { + @Comment("Should H2 be used?") + public static boolean USE = true; + @Comment("The file to use (without .mv.db ending)") + public static String DB = "storage"; + @Comment("The mode to use (MEMORY, FILE, SERVER)") + public static String MODE = "FILE"; + @Comment("Set additional properties: https://h2database.com/html/features.html#database_url") + public static List PROPERTIES = new ArrayList<>(Collections.singletonList("AUTO_SERVER=TRUE")); + } + } diff --git a/Core/src/main/java/com/plotsquared/core/database/AbstractDB.java b/Core/src/main/java/com/plotsquared/core/database/AbstractDB.java deleted file mode 100644 index 291772de90..0000000000 --- a/Core/src/main/java/com/plotsquared/core/database/AbstractDB.java +++ /dev/null @@ -1,380 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.PlotArea; -import com.plotsquared.core.plot.PlotCluster; -import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.comment.PlotComment; -import com.plotsquared.core.plot.flag.PlotFlag; -import com.plotsquared.core.util.task.RunnableVal; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -public interface AbstractDB { - - /** - * The UUID that will count as EVERYONE. - */ - UUID everyone = UUID.fromString("1-1-3-3-7"); - - /** - * Sets Plot owner. - * - * @param plot the plot - * @param uuid the uuid of the new owner - */ - void setOwner(Plot plot, UUID uuid); - - /** - * Creates all settings, and create default helpers, trusted + denied lists. - * - * @param plots Plots for which the default table entries should be created - * @param whenDone the task to run when the method is finished executing - */ - void createPlotsAndData(List plots, Runnable whenDone); - - /** - * Creates a plot. - * - * @param plot the plot to create - */ - void createPlotSafe(final Plot plot, final Runnable success, final Runnable failure); - - /** - * Create tables. - * - * @throws Exception If the database manager is unable to create the tables - */ - void createTables() throws Exception; - - /** - * Deletes a plot. - * - * @param plot the plot to delete - */ - void delete(Plot plot); - - void deleteSettings(Plot plot); - - void deleteHelpers(Plot plot); - - void deleteTrusted(Plot plot); - - /** - * Removes all denied players from the plot. - * - * @param plot the plot - */ - void deleteDenied(Plot plot); - - /** - * Deletes all comments from the plot. - * - * @param plot the plot - */ - void deleteComments(Plot plot); - - void deleteRatings(Plot plot); - - void delete(PlotCluster cluster); - - void addPersistentMeta(UUID uuid, String key, byte[] meta, boolean delete); - - void removePersistentMeta(UUID uuid, String key); - - void getPersistentMeta(UUID uuid, RunnableVal> result); - - /** - * Creates the plot settings. - * - * @param id the plot entry id - * @param plot the plot - */ - void createPlotSettings(int id, Plot plot); - - /** - * Gets the table entry ID. - * - * @param plot the plot - * @return {@link Integer} = Plot Entry Id - */ - int getId(Plot plot); - - /** - * Gets the id of a given plot cluster. - * - * @param cluster PlotCluster Object - * @return Integer = Cluster Entry Id - */ - int getClusterId(PlotCluster cluster); - - boolean convertFlags(); - - /** - * @return A linked HashMap containing all plots - */ - HashMap> getPlots(); - - /** - * @param toValidate - */ - void validateAllPlots(Set toValidate); - - /** - * @return A HashMap containing all plot clusters - */ - HashMap> getClusters(); - - /** - * Sets the merged status for a plot. - * - * @param plot The plot to set the merged status of - * @param merged boolean[] - */ - void setMerged(Plot plot, boolean[] merged); - - /** - * Swaps the settings, helpers etc. of two plots. - * - * @param plot1 Plot1 - * @param plot2 Plot2 - */ - CompletableFuture swapPlots(Plot plot1, Plot plot2); - - /** - * Sets plot flag. - * - * @param plot Plot Object - * @param flag Flag to set - */ - void setFlag(Plot plot, PlotFlag flag); - - /** - * Remove a plot flag. - * - * @param plot Plot Object - * @param flag Flag to remove - */ - void removeFlag(Plot plot, PlotFlag flag); - - /** - * Renames a cluster to the given name. - * - * @param cluster the cluster to rename - * @param name the new cluster name - */ - void setClusterName(PlotCluster cluster, String name); - - /** - * Sets the plot alias. - * - * @param plot Plot for which the alias should be set - * @param alias Plot Alias - */ - void setAlias(Plot plot, String alias); - - /** - * Purges a plot. - * - * @param uniqueIds list of plot id (db) to be purged - */ - void purgeIds(Set uniqueIds); - - /** - * Purges a whole world. - * - * @param area World in which the plots should be purged - * @param plotIds the {@link PlotId}s of {@link Plot}s to purge - */ - void purge(PlotArea area, Set plotIds); - - /** - * Sets the plot home position. - * - * @param plot the plot - * @param position the position of plot home - */ - void setPosition(Plot plot, String position); - - /** - * @param cluster - * @param position - */ - void setPosition(PlotCluster cluster, String position); - - /** - * Remove the specified player from the trust list of the specified plot. - * - * @param plot the plot - * @param uuid the uuid of the player to remove - */ - void removeTrusted(Plot plot, UUID uuid); - - /** - * @param cluster PlotCluster Object - * @param uuid Player that should be removed - */ - void removeHelper(PlotCluster cluster, UUID uuid); - - /** - * @param plot the plot - * @param uuid Player that should be removed - */ - void removeMember(Plot plot, UUID uuid); - - /** - * @param cluster - * @param uuid - */ - void removeInvited(PlotCluster cluster, UUID uuid); - - /** - * @param plot Plot Object - * @param uuid Player that should be removed - */ - void setTrusted(Plot plot, UUID uuid); - - /** - * @param cluster PlotCluster Object - * @param uuid Player that should be removed - */ - void setHelper(PlotCluster cluster, UUID uuid); - - /** - * @param plot Plot Object - * @param uuid Player that should be added - */ - void setMember(Plot plot, UUID uuid); - - /** - * @param cluster - * @param uuid - */ - void setInvited(PlotCluster cluster, UUID uuid); - - /** - * Removes the specified player from the denied list of the specified plot. - * - * @param plot the plot - * @param uuid the uuid of the player to remove - */ - void removeDenied(Plot plot, UUID uuid); - - /** - * Denies the specified player from the given plot. - * - * @param plot the plot - * @param uuid the uuid of the player to deny - */ - void setDenied(Plot plot, UUID uuid); - - /** - * Gets the ratings from the specified plot. - * - * @param plot the plot - * @return the plot ratings (pre-calculated) - */ - HashMap getRatings(Plot plot); - - /** - * Sets a rating for a plot. - * - * @param plot - * @param rater - * @param value - */ - void setRating(Plot plot, UUID rater, int value); - - /** - * Removes the specified comment from the given plot. - * - * @param plot the plot - * @param comment the comment to remove - */ - void removeComment(Plot plot, PlotComment comment); - - /** - * Clears the specified inbox on the given plot. - * - * @param plot the plot - * @param inbox the inbox to clear - */ - void clearInbox(Plot plot, String inbox); - - /** - * Adds the specified comment to the given plot. - * - * @param plot the plot - * @param comment the comment to add - */ - void setComment(Plot plot, PlotComment comment); - - /** - * Gets Plot comments. - * - * @param plot The Plot to get comments from - */ - void getComments(@NonNull Plot plot, String inbox, RunnableVal> whenDone); - - void createPlotAndSettings(Plot plot, Runnable whenDone); - - void createCluster(PlotCluster cluster); - - void resizeCluster(PlotCluster current, PlotId min, PlotId max); - - void movePlot(Plot originalPlot, Plot newPlot); - - /** - * Replaces a old uuid with a new one in the database. - * - *
    - *
  • Useful for replacing a few uuids (not the entire database).
  • - *
  • or entire conversion, the uuidconvert command scales better.
  • - *
- * - * @param old - * @param now - */ - void replaceUUID(UUID old, UUID now); - - /** - * Don't use this method unless you want to ruin someone's server. - * - * @return {@code true} if the tables were deleted, {@code false} when an error is encountered - */ - boolean deleteTables(); - - /** - * Closes the database. Generally not recommended to be used by add-ons. - */ - void close(); - - void replaceWorld(String oldWorld, String newWorld, PlotId min, PlotId max); - - void updateTables(int[] oldVersion); - -} diff --git a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java b/Core/src/main/java/com/plotsquared/core/database/DBFunc.java deleted file mode 100644 index 1b8ede36a3..0000000000 --- a/Core/src/main/java/com/plotsquared/core/database/DBFunc.java +++ /dev/null @@ -1,600 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.PlotArea; -import com.plotsquared.core.plot.PlotCluster; -import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.comment.PlotComment; -import com.plotsquared.core.plot.flag.PlotFlag; -import com.plotsquared.core.util.task.RunnableVal; - -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -/** - * Database Functions - * - These functions do not update the local plot objects and only make changes to the DB - */ -public class DBFunc { - - /** - * The "global" uuid. - */ - // TODO: Use this instead. public static final UUID EVERYONE = UUID.fromString("4aa2aaa4-c06b-485c-bc58-186aa1780d9b"); - public static final UUID EVERYONE = UUID.fromString("1-1-3-3-7"); - public static final UUID SERVER = UUID.fromString("00000000-0000-0000-0000-000000000000"); - - /** - * Abstract Database Manager - */ - public static AbstractDB dbManager; - - public static void updateTables(int[] oldVersion) { - if (dbManager != null) { - dbManager.updateTables(oldVersion); - } - } - - public static void addPersistentMeta(UUID uuid, String key, byte[] meta, boolean delete) { - if (dbManager != null) { - dbManager.addPersistentMeta(uuid, key, meta, delete); - } - } - - public static void getPersistentMeta(UUID uuid, RunnableVal> result) { - if (dbManager != null) { - dbManager.getPersistentMeta(uuid, result); - } - } - - public static void removePersistentMeta(UUID uuid, String key) { - if (dbManager != null) { - dbManager.removePersistentMeta(uuid, key); - } - } - - public static CompletableFuture swapPlots(Plot plot1, Plot plot2) { - if (dbManager != null) { - return dbManager.swapPlots(plot1, plot2); - } - return CompletableFuture.completedFuture(false); - } - - public static boolean deleteTables() { - return dbManager != null && dbManager.deleteTables(); - } - - public static void movePlot(Plot originalPlot, Plot newPlot) { - if (originalPlot.temp == -1 || newPlot.temp == -1) { - return; - } - DBFunc.dbManager.movePlot(originalPlot, newPlot); - } - - public static void validatePlots(Set plots) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.validateAllPlots(plots); - } - - - //TODO Consider Removal - - /** - * Check if a {@link ResultSet} contains a column. - * - * @param resultSet - * @param name - * @return - */ - @Deprecated - public static boolean hasColumn(ResultSet resultSet, String name) { - try { - ResultSetMetaData meta = resultSet.getMetaData(); - int count = meta.getColumnCount(); - for (int x = 1; x <= count; x++) { - if (name.equals(meta.getColumnName(x))) { - return true; - } - } - return false; - } catch (SQLException ignored) { - return false; - } - } - - /** - * Set the owner of a plot - * - * @param plot Plot Object - * @param uuid New Owner - */ - public static void setOwner(Plot plot, UUID uuid) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.setOwner(plot, uuid); - } - - /** - * Create all settings + (trusted, denied, members) - * - * @param plots List containing all plot objects - */ - public static void createPlotsAndData(List plots, Runnable whenDone) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.createPlotsAndData(plots, whenDone); - } - - public static void createPlotSafe( - final Plot plot, final Runnable success, - final Runnable failure - ) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.createPlotSafe(plot, success, failure); - } - - /** - * Create a plot. - * - * @param plot Plot to create - */ - public static void createPlotAndSettings(Plot plot, Runnable whenDone) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.createPlotAndSettings(plot, whenDone); - } - - /** - * Create tables. - * - * @throws Exception - */ - public static void createTables() throws Exception { - if (dbManager == null) { - return; - } - DBFunc.dbManager.createTables(); - } - - /** - * Delete a plot. - * - * @param plot Plot to delete - */ - public static void delete(Plot plot) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.delete(plot); - plot.temp = -1; - } - - /** - * Delete the ratings for a plot. - * - * @param plot - */ - public static void deleteRatings(Plot plot) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.deleteRatings(plot); - } - - /** - * Delete the trusted list for a plot. - * - * @param plot - */ - public static void deleteTrusted(Plot plot) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.deleteHelpers(plot); - } - - /** - * Delete the members list for a plot. - * - * @param plot - */ - public static void deleteMembers(Plot plot) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.deleteTrusted(plot); - } - - /** - * Delete the denied list for a plot. - * - * @param plot - */ - public static void deleteDenied(Plot plot) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.deleteDenied(plot); - } - - /** - * Delete the comments in a plot. - * - * @param plot - */ - public static void deleteComments(Plot plot) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.deleteComments(plot); - } - - /** - * Deleting settings will - * 1) Delete any settings (flags and such) associated with the plot - * 2) Prevent any local changes to the plot from saving properly to the db - *

- * This shouldn't ever be needed - * - * @param plot - */ - public static void deleteSettings(Plot plot) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.deleteSettings(plot); - } - - public static void delete(PlotCluster toDelete) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.delete(toDelete); - } - - /** - * Create plot settings. - * - * @param id Plot ID - * @param plot Plot Object - */ - public static void createPlotSettings(int id, Plot plot) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.createPlotSettings(id, plot); - } - - /** - * Get a plot id. - * - * @param plot Plot Object - * @return ID - */ - public static int getId(Plot plot) { - if (dbManager == null) { - return 0; - } - return DBFunc.dbManager.getId(plot); - } - - /** - * @return Plots - */ - public static HashMap> getPlots() { - if (dbManager == null) { - return new HashMap<>(); - } - return DBFunc.dbManager.getPlots(); - } - - public static void setMerged(Plot plot, boolean[] merged) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.setMerged(plot, merged); - } - - public static void setFlag(Plot plot, PlotFlag flag) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.setFlag(plot, flag); - } - - public static void removeFlag(Plot plot, PlotFlag flag) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.removeFlag(plot, flag); - } - - /** - * @param plot - * @param alias - */ - public static void setAlias(Plot plot, String alias) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.setAlias(plot, alias); - } - - public static void purgeIds(Set uniqueIds) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.purgeIds(uniqueIds); - } - - public static void purge(PlotArea area, Set plotIds) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.purge(area, plotIds); - } - - /** - * @param plot - * @param position - */ - public static void setPosition(Plot plot, String position) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.setPosition(plot, position); - } - - /** - * @param plot - * @param comment - */ - public static void removeComment(Plot plot, PlotComment comment) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.removeComment(plot, comment); - } - - public static void clearInbox(Plot plot, String inbox) { - if (plot != null && plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.clearInbox(plot, inbox); - } - - /** - * @param plot - * @param comment - */ - public static void setComment(Plot plot, PlotComment comment) { - if (plot != null && plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.setComment(plot, comment); - } - - /** - * @param plot - */ - public static void getComments( - Plot plot, String inbox, - RunnableVal> whenDone - ) { - if (plot != null && plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.getComments(plot, inbox, whenDone); - } - - /** - * @param plot - * @param uuid - */ - public static void removeTrusted(Plot plot, UUID uuid) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.removeTrusted(plot, uuid); - } - - /** - * @param cluster - * @param uuid - */ - public static void removeHelper(PlotCluster cluster, UUID uuid) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.removeHelper(cluster, uuid); - } - - /** - * @param cluster - */ - public static void createCluster(PlotCluster cluster) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.createCluster(cluster); - } - - /** - * @param current - * @param min - * @param max - */ - public static void resizeCluster(PlotCluster current, PlotId min, PlotId max) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.resizeCluster(current, min, max); - } - - /** - * @param plot - * @param uuid - */ - public static void removeMember(Plot plot, UUID uuid) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.removeMember(plot, uuid); - } - - /** - * @param cluster - * @param uuid - */ - public static void removeInvited(PlotCluster cluster, UUID uuid) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.removeInvited(cluster, uuid); - } - - /** - * @param plot - * @param uuid - */ - public static void setTrusted(Plot plot, UUID uuid) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.setTrusted(plot, uuid); - } - - public static void setHelper(PlotCluster cluster, UUID uuid) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.setHelper(cluster, uuid); - } - - /** - * @param plot - * @param uuid - */ - public static void setMember(Plot plot, UUID uuid) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.setMember(plot, uuid); - } - - public static void setInvited(PlotCluster cluster, UUID uuid) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.setInvited(cluster, uuid); - } - - /** - * @param plot - * @param uuid - */ - public static void removeDenied(Plot plot, UUID uuid) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.removeDenied(plot, uuid); - } - - /** - * @param plot - * @param uuid - */ - public static void setDenied(Plot plot, UUID uuid) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.setDenied(plot, uuid); - } - - public static HashMap getRatings(Plot plot) { - if (plot.temp == -1 || dbManager == null) { - return new HashMap<>(0); - } - return DBFunc.dbManager.getRatings(plot); - } - - public static void setRating(Plot plot, UUID rater, int value) { - if (plot.temp == -1 || dbManager == null) { - return; - } - DBFunc.dbManager.setRating(plot, rater, value); - } - - public static HashMap> getClusters() { - if (dbManager == null) { - return new HashMap<>(); - } - return DBFunc.dbManager.getClusters(); - } - - public static void setPosition(PlotCluster cluster, String position) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.setPosition(cluster, position); - } - - public static void replaceWorld(String oldWorld, String newWorld, PlotId min, PlotId max) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.replaceWorld(oldWorld, newWorld, min, max); - } - - /** - * Replace all occurrences of a uuid in the database with another one - * - * @param old - * @param now - */ - public static void replaceUUID(UUID old, UUID now) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.replaceUUID(old, now); - } - - public static void close() { - if (dbManager != null) { - DBFunc.dbManager.close(); - } - } - -} diff --git a/Core/src/main/java/com/plotsquared/core/database/Database.java b/Core/src/main/java/com/plotsquared/core/database/Database.java deleted file mode 100644 index 9f20ad7da6..0000000000 --- a/Core/src/main/java/com/plotsquared/core/database/Database.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -/** - * Abstract Database class, serves as a base for any connection method (MySQL, SQLite, etc.) - * - * @author -_Husky_- - * @author tips48 - */ -public abstract class Database { - - public abstract Connection forceConnection() throws SQLException, ClassNotFoundException; - - /** - * Opens a connection with the database. - * - * @return Opened connection - * @throws SQLException if the connection can not be opened - * @throws ClassNotFoundException if the driver cannot be found - */ - public abstract Connection openConnection() throws SQLException, ClassNotFoundException; - - /** - * Checks if a connection is open with the database. - * - * @return {@code true} if the connection is open - * @throws SQLException if the connection cannot be checked - */ - public abstract boolean checkConnection() throws SQLException; - - /** - * Gets the connection with the database. - * - * @return Connection with the database, null if none - */ - public abstract Connection getConnection(); - - /** - * Closes the connection with the database. - * - * @return {@code true} if successful - * @throws SQLException if the connection cannot be closed - */ - public abstract boolean closeConnection() throws SQLException; - - /** - * Executes a SQL Query. - * If the connection is closed, it will be opened. - * - * @param query Query to be run - * @return the results of the query - * @throws SQLException If the query cannot be executed - * @throws ClassNotFoundException If the driver cannot be found; see {@link #openConnection()} - */ - public abstract ResultSet querySQL(String query) throws SQLException, ClassNotFoundException; - - /** - * Executes an Update SQL Query. - * See {@link Statement#executeUpdate(String)}. - * If the connection is closed, it will be opened. - * - * @param query Query to be run - * @return Result Code, see {@link Statement#executeUpdate(String)} - * @throws SQLException If the query cannot be executed - * @throws ClassNotFoundException If the driver cannot be found; see {@link #openConnection()} - */ - public abstract int updateSQL(String query) throws SQLException, ClassNotFoundException; - -} diff --git a/Core/src/main/java/com/plotsquared/core/database/MySQL.java b/Core/src/main/java/com/plotsquared/core/database/MySQL.java deleted file mode 100644 index a8767b598c..0000000000 --- a/Core/src/main/java/com/plotsquared/core/database/MySQL.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import com.plotsquared.core.configuration.Storage; -import com.plotsquared.core.util.StringMan; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -/** - * Connects to and uses a MySQL database - * - * @author -_Husky_- - * @author tips48 - */ -public class MySQL extends Database { - - private final String user; - private final String database; - private final String password; - private final String port; - private final String hostname; - private Connection connection; - - /** - * Creates a new MySQL instance. - * - * @param hostname Name of the host - * @param port Port number - * @param database Database name - * @param username Username - * @param password Password - */ - public MySQL(String hostname, String port, String database, String username, String password) { - this.hostname = hostname; - this.port = port; - this.database = database; - this.user = username; - this.password = password; - this.connection = null; - } - - @Override - public Connection forceConnection() throws SQLException { - this.connection = DriverManager.getConnection( - "jdbc:mysql://" + this.hostname + ':' + this.port + '/' + this.database + "?" - + StringMan.join(Storage.MySQL.PROPERTIES, "&"), this.user, this.password); - return this.connection; - } - - @Override - public Connection openConnection() throws SQLException { - if (checkConnection()) { - return this.connection; - } - return forceConnection(); - } - - @Override - public boolean checkConnection() throws SQLException { - return (this.connection != null) && !this.connection.isClosed(); - } - - @Override - public Connection getConnection() { - return this.connection; - } - - @Override - public boolean closeConnection() throws SQLException { - if (this.connection == null) { - return false; - } - this.connection.close(); - this.connection = null; - return true; - } - - @Override - public ResultSet querySQL(String query) throws SQLException { - if (checkConnection()) { - openConnection(); - } - try (Statement statement = this.connection.createStatement()) { - return statement.executeQuery(query); - } - } - - @Override - public int updateSQL(String query) throws SQLException { - if (checkConnection()) { - openConnection(); - } - try (Statement statement = this.connection.createStatement()) { - return statement.executeUpdate(query); - } - } - -} diff --git a/Core/src/main/java/com/plotsquared/core/database/SQLManager.java b/Core/src/main/java/com/plotsquared/core/database/SQLManager.java deleted file mode 100644 index 63d1af450c..0000000000 --- a/Core/src/main/java/com/plotsquared/core/database/SQLManager.java +++ /dev/null @@ -1,3473 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import com.google.common.base.Charsets; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.configuration.ConfigurationSection; -import com.plotsquared.core.configuration.Settings; -import com.plotsquared.core.configuration.Storage; -import com.plotsquared.core.configuration.caption.CaptionUtility; -import com.plotsquared.core.configuration.file.YamlConfiguration; -import com.plotsquared.core.inject.annotations.WorldConfig; -import com.plotsquared.core.listener.PlotListener; -import com.plotsquared.core.location.BlockLoc; -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.PlotArea; -import com.plotsquared.core.plot.PlotCluster; -import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.PlotSettings; -import com.plotsquared.core.plot.comment.PlotComment; -import com.plotsquared.core.plot.flag.FlagContainer; -import com.plotsquared.core.plot.flag.FlagParseException; -import com.plotsquared.core.plot.flag.GlobalFlagContainer; -import com.plotsquared.core.plot.flag.PlotFlag; -import com.plotsquared.core.plot.flag.types.BlockTypeListFlag; -import com.plotsquared.core.util.EventDispatcher; -import com.plotsquared.core.util.HashUtil; -import com.plotsquared.core.util.StringMan; -import com.plotsquared.core.util.task.RunnableVal; -import com.plotsquared.core.util.task.TaskManager; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Timestamp; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Queue; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicInteger; - - -@SuppressWarnings("SqlDialectInspection") -public class SQLManager implements AbstractDB { - - private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + SQLManager.class.getSimpleName()); - - // Public final - public final String SET_OWNER; - public final String GET_ALL_PLOTS; - public final String CREATE_PLOTS; - public final String CREATE_SETTINGS; - public final String CREATE_TIERS; - public final String CREATE_PLOT; - public final String CREATE_PLOT_SAFE; - public final String CREATE_CLUSTER; - - // Private Final - private final String prefix; - private final Database database; - private final boolean mySQL; - @SuppressWarnings({"unused", "FieldCanBeLocal"}) - private final EventDispatcher eventDispatcher; - @SuppressWarnings({"unused", "FieldCanBeLocal"}) - private final PlotListener plotListener; - private final YamlConfiguration worldConfiguration; - /** - * important tasks - */ - public volatile Queue globalTasks; - /** - * Notify tasks - */ - public volatile Queue notifyTasks; - /** - * plot - * plot_denied - * plot_helpers - * plot_trusted - * plot_comments - * plot_settings - * plot_rating - */ - public volatile ConcurrentHashMap> plotTasks; - /** - * player_meta - */ - public volatile ConcurrentHashMap> playerTasks; - /** - * cluster - * cluster_helpers - * cluster_invited - * cluster_settings - */ - public volatile ConcurrentHashMap> clusterTasks; - // Private - private Connection connection; - private boolean supportsGetGeneratedKeys; - private boolean closed = false; - - /** - * Constructor - * - * @param database - * @param prefix prefix - * @throws SQLException - * @throws ClassNotFoundException - */ - public SQLManager( - final @NonNull Database database, - final @NonNull String prefix, - final @NonNull EventDispatcher eventDispatcher, - final @NonNull PlotListener plotListener, - @WorldConfig final @NonNull YamlConfiguration worldConfiguration - ) - throws SQLException, ClassNotFoundException { - // Private final - this.eventDispatcher = eventDispatcher; - this.plotListener = plotListener; - this.worldConfiguration = worldConfiguration; - this.database = database; - this.connection = database.openConnection(); - final DatabaseMetaData databaseMetaData = this.connection.getMetaData(); - this.supportsGetGeneratedKeys = databaseMetaData.supportsGetGeneratedKeys(); - this.mySQL = database instanceof MySQL; - this.globalTasks = new ConcurrentLinkedQueue<>(); - this.notifyTasks = new ConcurrentLinkedQueue<>(); - this.plotTasks = new ConcurrentHashMap<>(); - this.playerTasks = new ConcurrentHashMap<>(); - this.clusterTasks = new ConcurrentHashMap<>(); - this.prefix = prefix; - - if (mySQL && !supportsGetGeneratedKeys) { - String driver = databaseMetaData.getDriverName(); - String driverVersion = databaseMetaData.getDriverVersion(); - throw new SQLException("Database Driver for MySQL does not support Statement#getGeneratedKeys - which breaks " + - "PlotSquared functionality (Using " + driver + ":" + driverVersion + ")"); - } - - this.SET_OWNER = "UPDATE `" + this.prefix - + "plot` SET `owner` = ? WHERE `plot_id_x` = ? AND `plot_id_z` = ? AND `world` = ?"; - this.GET_ALL_PLOTS = - "SELECT `id`, `plot_id_x`, `plot_id_z`, `world` FROM `" + this.prefix + "plot`"; - this.CREATE_PLOTS = "INSERT INTO `" + this.prefix - + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) values "; - this.CREATE_SETTINGS = - "INSERT INTO `" + this.prefix + "plot_settings` (`plot_plot_id`) values "; - this.CREATE_TIERS = - "INSERT INTO `" + this.prefix + "plot_%tier%` (`plot_plot_id`, `user_uuid`) values "; - String tempCreatePlot = "INSERT INTO `" + this.prefix - + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) VALUES(?, ?, ?, ?, ?)"; - if (!supportsGetGeneratedKeys) { - tempCreatePlot += " RETURNING `id`"; - } - this.CREATE_PLOT = tempCreatePlot; - if (mySQL) { - this.CREATE_PLOT_SAFE = "INSERT IGNORE INTO `" + this.prefix - + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) SELECT ?, ?, ?, ?, ? FROM DUAL WHERE NOT EXISTS (SELECT null FROM `" - + this.prefix + "plot` WHERE `world` = ? AND `plot_id_x` = ? AND `plot_id_z` = ?)"; - } else { - String tempCreatePlotSafe = "INSERT INTO `" + this.prefix - + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) SELECT ?, ?, ?, ?, ? WHERE NOT EXISTS (SELECT null FROM `" - + this.prefix + "plot` WHERE `world` = ? AND `plot_id_x` = ? AND `plot_id_z` = ?)"; - if (!supportsGetGeneratedKeys) { - tempCreatePlotSafe += " RETURNING `id`"; - } - this.CREATE_PLOT_SAFE = tempCreatePlotSafe; - } - String tempCreateCluster = "INSERT INTO `" + this.prefix - + "cluster`(`pos1_x`, `pos1_z`, `pos2_x`, `pos2_z`, `owner`, `world`) VALUES(?, ?, ?, ?, ?, ?)"; - if (!supportsGetGeneratedKeys) { - tempCreateCluster += " RETURNING `id`"; - } - this.CREATE_CLUSTER = tempCreateCluster; - - try { - createTables(); - } catch (SQLException e) { - e.printStackTrace(); - } - TaskManager.runTaskAsync(() -> { - long last = System.currentTimeMillis(); - while (!SQLManager.this.closed) { - boolean hasTask = - !globalTasks.isEmpty() || !playerTasks.isEmpty() || !plotTasks.isEmpty() - || !clusterTasks.isEmpty(); - if (hasTask) { - if (SQLManager.this.mySQL && System.currentTimeMillis() - last > 550000 - || !isValid()) { - last = System.currentTimeMillis(); - reconnect(); - } - if (!sendBatch()) { - try { - if (!getNotifyTasks().isEmpty()) { - for (Runnable task : getNotifyTasks()) { - TaskManager.runTask(task); - } - getNotifyTasks().clear(); - } - Thread.sleep(50); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } else { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - }); - } - - public boolean isValid() { - try { - if (connection.isClosed()) { - return false; - } - } catch (SQLException e) { - return false; - } - try (PreparedStatement stmt = this.connection.prepareStatement("SELECT 1")) { - stmt.execute(); - return true; - } catch (Throwable e) { - return false; - } - } - - public void reconnect() { - try { - close(); - SQLManager.this.closed = false; - SQLManager.this.connection = database.forceConnection(); - } catch (SQLException | ClassNotFoundException e) { - e.printStackTrace(); - } - } - - public synchronized Queue getGlobalTasks() { - return this.globalTasks; - } - - public synchronized Queue getNotifyTasks() { - return this.notifyTasks; - } - - public synchronized void addPlotTask(@NonNull Plot plot, UniqueStatement task) { - Queue tasks = this.plotTasks.get(plot); - if (tasks == null) { - tasks = new ConcurrentLinkedQueue<>(); - this.plotTasks.put(plot, tasks); - } - if (task == null) { - task = new UniqueStatement(String.valueOf(plot.hashCode())) { - - @Override - public PreparedStatement get() { - return null; - } - - @Override - public void set(PreparedStatement statement) { - } - - @Override - public void addBatch(PreparedStatement statement) { - } - - @Override - public void execute(PreparedStatement statement) { - } - - }; - } - tasks.add(task); - } - - public synchronized void addPlayerTask(UUID uuid, UniqueStatement task) { - if (uuid == null) { - return; - } - Queue tasks = this.playerTasks.get(uuid); - if (tasks == null) { - tasks = new ConcurrentLinkedQueue<>(); - this.playerTasks.put(uuid, tasks); - } - if (task == null) { - task = new UniqueStatement(String.valueOf(uuid.hashCode())) { - - @Override - public PreparedStatement get() { - return null; - } - - @Override - public void set(PreparedStatement statement) { - } - - @Override - public void addBatch(PreparedStatement statement) { - } - - @Override - public void execute(PreparedStatement statement) { - } - - }; - } - tasks.add(task); - } - - public synchronized void addClusterTask(PlotCluster cluster, UniqueStatement task) { - Queue tasks = this.clusterTasks.get(cluster); - if (tasks == null) { - tasks = new ConcurrentLinkedQueue<>(); - this.clusterTasks.put(cluster, tasks); - } - if (task == null) { - task = new UniqueStatement(String.valueOf(cluster.hashCode())) { - - @Override - public PreparedStatement get() { - return null; - } - - @Override - public void set(PreparedStatement statement) { - } - - @Override - public void addBatch(PreparedStatement statement) { - } - - @Override - public void execute(PreparedStatement statement) { - } - - }; - } - tasks.add(task); - } - - public synchronized void addGlobalTask(Runnable task) { - getGlobalTasks().add(task); - } - - public synchronized void addNotifyTask(Runnable task) { - if (task != null) { - getNotifyTasks().add(task); - } - } - - public boolean sendBatch() { - try { - if (!getGlobalTasks().isEmpty()) { - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); - } - Runnable task = getGlobalTasks().remove(); - if (task != null) { - try { - task.run(); - } catch (Throwable e) { - LOGGER.error("============ DATABASE ERROR ============"); - LOGGER.error("============ DATABASE ERROR ============"); - LOGGER.error("There was an error updating the database."); - LOGGER.error(" - It will be corrected on shutdown"); - e.printStackTrace(); - LOGGER.error("========================================"); - } - } - commit(); - return true; - } - int count = -1; - if (!this.plotTasks.isEmpty()) { - count = Math.max(count, 0); - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); - } - String method = null; - PreparedStatement statement = null; - UniqueStatement task = null; - UniqueStatement lastTask = null; - Iterator>> iterator = - this.plotTasks.entrySet().iterator(); - while (iterator.hasNext()) { - try { - Entry> entry = iterator.next(); - Queue tasks = entry.getValue(); - if (tasks.isEmpty()) { - iterator.remove(); - continue; - } - task = tasks.remove(); - count++; - if (task != null) { - if (task.method == null || !task.method.equals(method) - || statement == null) { - if (statement != null) { - lastTask.execute(statement); - statement.close(); - } - method = task.method; - statement = task.get(); - } - task.set(statement); - task.addBatch(statement); - try { - if (statement.isClosed()) { - statement = null; - } - } catch (NullPointerException | AbstractMethodError ignore) { - } - } - lastTask = task; - } catch (Throwable e) { - LOGGER.error("============ DATABASE ERROR ============"); - LOGGER.error("There was an error updating the database."); - LOGGER.error(" - It will be corrected on shutdown"); - LOGGER.error("========================================"); - e.printStackTrace(); - LOGGER.error("========================================"); - } - } - if (statement != null && task != null) { - task.execute(statement); - statement.close(); - } - } - if (!this.playerTasks.isEmpty()) { - count = Math.max(count, 0); - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); - } - String method = null; - PreparedStatement statement = null; - UniqueStatement task = null; - UniqueStatement lastTask = null; - for (Entry> entry : this.playerTasks.entrySet()) { - try { - UUID uuid = entry.getKey(); - if (this.playerTasks.get(uuid).isEmpty()) { - this.playerTasks.remove(uuid); - continue; - } - task = this.playerTasks.get(uuid).remove(); - count++; - if (task != null) { - if (task.method == null || !task.method.equals(method)) { - if (statement != null) { - lastTask.execute(statement); - statement.close(); - } - method = task.method; - statement = task.get(); - } - task.set(statement); - task.addBatch(statement); - } - lastTask = task; - } catch (Throwable e) { - LOGGER.error("============ DATABASE ERROR ============"); - LOGGER.error("There was an error updating the database."); - LOGGER.error(" - It will be corrected on shutdown"); - LOGGER.error("========================================"); - e.printStackTrace(); - LOGGER.error("========================================"); - } - } - if (statement != null && task != null) { - task.execute(statement); - statement.close(); - } - } - if (!this.clusterTasks.isEmpty()) { - count = Math.max(count, 0); - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); - } - String method = null; - PreparedStatement statement = null; - UniqueStatement task = null; - UniqueStatement lastTask = null; - for (Entry> entry : this.clusterTasks - .entrySet()) { - try { - PlotCluster cluster = entry.getKey(); - if (this.clusterTasks.get(cluster).isEmpty()) { - this.clusterTasks.remove(cluster); - continue; - } - task = this.clusterTasks.get(cluster).remove(); - count++; - if (task != null) { - if (task.method == null || !task.method.equals(method)) { - if (statement != null) { - lastTask.execute(statement); - statement.close(); - } - method = task.method; - statement = task.get(); - } - task.set(statement); - task.addBatch(statement); - } - lastTask = task; - } catch (Throwable e) { - LOGGER.error("============ DATABASE ERROR ============"); - LOGGER.error("There was an error updating the database."); - LOGGER.error(" - It will be corrected on shutdown"); - LOGGER.error("========================================"); - e.printStackTrace(); - LOGGER.error("========================================"); - } - } - if (statement != null && task != null) { - task.execute(statement); - statement.close(); - } - } - if (count > 0) { - commit(); - return true; - } - if (count != -1) { - if (!this.connection.getAutoCommit()) { - this.connection.setAutoCommit(true); - } - } - if (!this.clusterTasks.isEmpty()) { - this.clusterTasks.clear(); - } - if (!this.plotTasks.isEmpty()) { - this.plotTasks.clear(); - } - } catch (Throwable e) { - LOGGER.error("============ DATABASE ERROR ============"); - LOGGER.error("There was an error updating the database."); - LOGGER.error(" - It will be corrected on shutdown"); - LOGGER.error("========================================"); - e.printStackTrace(); - LOGGER.error("========================================"); - } - return false; - } - - public Connection getConnection() { - return this.connection; - } - - /** - * Set Plot owner - * - * @param plot Plot Object - * @param uuid Owner UUID - */ - @Override - public void setOwner(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("setOwner") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, uuid.toString()); - statement.setInt(2, plot.getId().getX()); - statement.setInt(3, plot.getId().getY()); - statement.setString(4, plot.getArea().toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement(SQLManager.this.SET_OWNER); - } - }); - } - - @Override - public void createPlotsAndData(final List myList, final Runnable whenDone) { - addGlobalTask(() -> { - try { - // Create the plots - createPlots(myList, () -> { - final Map idMap = new HashMap<>(); - - try { - // Creating datastructures - HashMap plotMap = new HashMap<>(); - for (Plot plot : myList) { - plotMap.put(plot.getId(), plot); - } - ArrayList settings = new ArrayList<>(); - final ArrayList helpers = new ArrayList<>(); - final ArrayList trusted = new ArrayList<>(); - final ArrayList denied = new ArrayList<>(); - - // Populating structures - try (PreparedStatement stmt = SQLManager.this.connection - .prepareStatement(SQLManager.this.GET_ALL_PLOTS); - ResultSet result = stmt.executeQuery()) { - while (result.next()) { - int id = result.getInt("id"); - int x = result.getInt("plot_id_x"); - int y = result.getInt("plot_id_z"); - PlotId plotId = PlotId.of(x, y); - Plot plot = plotMap.get(plotId); - idMap.put(plotId, id); - if (plot != null) { - settings.add(new LegacySettings(id, plot.getSettings())); - for (UUID uuid : plot.getDenied()) { - denied.add(new UUIDPair(id, uuid)); - } - for (UUID uuid : plot.getMembers()) { - trusted.add(new UUIDPair(id, uuid)); - } - for (UUID uuid : plot.getTrusted()) { - helpers.add(new UUIDPair(id, uuid)); - } - } - } - } - - createFlags(idMap, myList, () -> createSettings( - settings, - () -> createTiers(helpers, "helpers", - () -> createTiers(trusted, "trusted", - () -> createTiers(denied, "denied", () -> { - try { - SQLManager.this.connection.commit(); - } catch (SQLException e) { - e.printStackTrace(); - } - if (whenDone != null) { - whenDone.run(); - } - }) - ) - ) - )); - } catch (SQLException e) { - LOGGER.warn("Failed to set all flags and member tiers for plots", e); - try { - SQLManager.this.connection.commit(); - } catch (SQLException e1) { - e1.printStackTrace(); - } - } - }); - } catch (Exception e) { - LOGGER.warn("Warning! Failed to set all helper for plots", e); - try { - SQLManager.this.connection.commit(); - } catch (SQLException e1) { - e1.printStackTrace(); - } - } - }); - } - - /** - * Create a plot - * - * @param myList list of plots to be created - */ - public void createTiers(ArrayList myList, final String tier, Runnable whenDone) { - StmtMod mod = new StmtMod<>() { - @Override - public String getCreateMySQL(int size) { - return getCreateMySQL(size, SQLManager.this.CREATE_TIERS.replaceAll("%tier%", tier), - 2 - ); - } - - @Override - public String getCreateSQLite(int size) { - return getCreateSQLite(size, - "INSERT INTO `" + SQLManager.this.prefix + "plot_" + tier - + "` SELECT ? AS `plot_plot_id`, ? AS `user_uuid`", 2 - ); - } - - @Override - public String getCreateSQL() { - return "INSERT INTO `" + SQLManager.this.prefix + "plot_" + tier - + "` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"; - } - - @Override - public void setMySQL(PreparedStatement stmt, int i, UUIDPair pair) - throws SQLException { - stmt.setInt(i * 2 + 1, pair.id); - stmt.setString(i * 2 + 2, pair.uuid.toString()); - } - - @Override - public void setSQLite(PreparedStatement stmt, int i, UUIDPair pair) - throws SQLException { - stmt.setInt(i * 2 + 1, pair.id); - stmt.setString(i * 2 + 2, pair.uuid.toString()); - } - - @Override - public void setSQL(PreparedStatement stmt, UUIDPair pair) - throws SQLException { - stmt.setInt(1, pair.id); - stmt.setString(2, pair.uuid.toString()); - } - }; - setBulk(myList, mod, whenDone); - } - - public void createFlags(Map ids, List plots, Runnable whenDone) { - try (final PreparedStatement preparedStatement = this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_flags`(`plot_id`, `flag`, `value`) VALUES(?, ?, ?)")) { - for (final Plot plot : plots) { - final FlagContainer flagContainer = plot.getFlagContainer(); - for (final PlotFlag flagEntry : flagContainer.getFlagMap().values()) { - preparedStatement.setInt(1, ids.get(plot.getId())); - preparedStatement.setString(2, flagEntry.getName()); - preparedStatement.setString(3, flagEntry.toString()); - preparedStatement.addBatch(); - } - try { - preparedStatement.executeBatch(); - } catch (final Exception e) { - LOGGER.error("Failed to store flag values for plot with entry ID: {}", plot); - e.printStackTrace(); - continue; - } - LOGGER.info( - "- Finished converting flag values for plot with entry ID: {}", - plot.getId() - ); - } - } catch (final Exception e) { - LOGGER.error("Failed to store flag values", e); - } - LOGGER.info("Finished converting flags ({} plots processed)", plots.size()); - whenDone.run(); - } - - /** - * Create a plot - * - * @param myList list of plots to be created - */ - public void createPlots(List myList, Runnable whenDone) { - StmtMod mod = new StmtMod<>() { - @Override - public String getCreateMySQL(int size) { - return getCreateMySQL(size, SQLManager.this.CREATE_PLOTS, 5); - } - - @Override - public String getCreateSQLite(int size) { - return getCreateSQLite(size, "INSERT INTO `" + SQLManager.this.prefix - + "plot` SELECT ? AS `id`, ? AS `plot_id_x`, ? AS `plot_id_z`, ? AS `owner`, ? AS `world`, ? AS `timestamp` ", - 6 - ); - } - - @Override - public String getCreateSQL() { - return SQLManager.this.CREATE_PLOT; - } - - @Override - public void setMySQL(PreparedStatement stmt, int i, Plot plot) - throws SQLException { - stmt.setInt(i * 5 + 1, plot.getId().getX()); - stmt.setInt(i * 5 + 2, plot.getId().getY()); - try { - stmt.setString(i * 5 + 3, plot.getOwnerAbs().toString()); - } catch (SQLException ignored) { - stmt.setString(i * 5 + 3, everyone.toString()); - } - stmt.setString(i * 5 + 4, plot.getArea().toString()); - stmt.setTimestamp(i * 5 + 5, new Timestamp(plot.getTimestamp())); - } - - @Override - public void setSQLite(PreparedStatement stmt, int i, Plot plot) - throws SQLException { - stmt.setNull(i * 6 + 1, 4); - stmt.setInt(i * 6 + 2, plot.getId().getX()); - stmt.setInt(i * 6 + 3, plot.getId().getY()); - try { - stmt.setString(i * 6 + 4, plot.getOwnerAbs().toString()); - } catch (SQLException ignored) { - stmt.setString(i * 6 + 4, everyone.toString()); - } - stmt.setString(i * 6 + 5, plot.getArea().toString()); - stmt.setTimestamp(i * 6 + 6, new Timestamp(plot.getTimestamp())); - } - - @Override - public void setSQL(PreparedStatement stmt, Plot plot) throws SQLException { - stmt.setInt(1, plot.getId().getX()); - stmt.setInt(2, plot.getId().getY()); - stmt.setString(3, plot.getOwnerAbs().toString()); - stmt.setString(4, plot.getArea().toString()); - stmt.setTimestamp(5, new Timestamp(plot.getTimestamp())); - - } - }; - setBulk(myList, mod, whenDone); - } - - public void setBulk(List objList, StmtMod mod, Runnable whenDone) { - int size = objList.size(); - if (size == 0) { - if (whenDone != null) { - whenDone.run(); - } - return; - } - int packet; - if (this.mySQL) { - packet = Math.min(size, 5000); - } else { - packet = Math.min(size, 50); - } - int amount = size / packet; - try { - int count = 0; - PreparedStatement preparedStmt = null; - int last = -1; - for (int j = 0; j <= amount; j++) { - List subList = objList.subList(j * packet, Math.min(size, (j + 1) * packet)); - if (subList.isEmpty()) { - break; - } - String statement; - if (last == -1) { - last = subList.size(); - statement = mod.getCreateMySQL(subList.size()); - preparedStmt = this.connection.prepareStatement(statement); - } - if (subList.size() != last || count % 5000 == 0 && count > 0) { - preparedStmt.executeBatch(); - preparedStmt.close(); - statement = mod.getCreateMySQL(subList.size()); - preparedStmt = this.connection.prepareStatement(statement); - } - for (int i = 0; i < subList.size(); i++) { - count++; - T obj = subList.get(i); - mod.setMySQL(preparedStmt, i, obj); - } - last = subList.size(); - preparedStmt.addBatch(); - } - preparedStmt.executeBatch(); - preparedStmt.clearParameters(); - preparedStmt.close(); - if (whenDone != null) { - whenDone.run(); - } - return; - } catch (SQLException e) { - if (this.mySQL) { - LOGGER.error("1: | {}", objList.get(0).getClass().getCanonicalName()); - e.printStackTrace(); - } - } - try { - int count = 0; - PreparedStatement preparedStmt = null; - int last = -1; - for (int j = 0; j <= amount; j++) { - List subList = objList.subList(j * packet, Math.min(size, (j + 1) * packet)); - if (subList.isEmpty()) { - break; - } - String statement; - if (last == -1) { - last = subList.size(); - statement = mod.getCreateSQLite(subList.size()); - preparedStmt = this.connection.prepareStatement(statement); - } - if (subList.size() != last || count % 5000 == 0 && count > 0) { - preparedStmt.executeBatch(); - preparedStmt.clearParameters(); - statement = mod.getCreateSQLite(subList.size()); - preparedStmt = this.connection.prepareStatement(statement); - } - for (int i = 0; i < subList.size(); i++) { - count++; - T obj = subList.get(i); - mod.setSQLite(preparedStmt, i, obj); - } - last = subList.size(); - preparedStmt.addBatch(); - } - preparedStmt.executeBatch(); - preparedStmt.clearParameters(); - preparedStmt.close(); - } catch (SQLException e) { - e.printStackTrace(); - LOGGER.error("2: | {}", objList.get(0).getClass().getCanonicalName()); - LOGGER.error("Could not bulk save!"); - try (PreparedStatement preparedStmt = this.connection - .prepareStatement(mod.getCreateSQL())) { - for (T obj : objList) { - mod.setSQL(preparedStmt, obj); - preparedStmt.addBatch(); - } - preparedStmt.executeBatch(); - } catch (SQLException e3) { - LOGGER.error("Failed to save all", e); - e3.printStackTrace(); - } - } - if (whenDone != null) { - whenDone.run(); - } - } - - public void createSettings(final ArrayList myList, final Runnable whenDone) { - try (final PreparedStatement preparedStatement = this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix + "plot_settings`" - + "(`plot_plot_id`,`biome`,`rain`,`custom_time`,`time`,`deny_entry`,`alias`,`merged`,`position`) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)")) { - - int packet; - if (this.mySQL) { - packet = Math.min(myList.size(), 5000); - } else { - packet = Math.min(myList.size(), 50); - } - - int totalUpdated = 0; - int updated = 0; - - for (final LegacySettings legacySettings : myList) { - preparedStatement.setInt(1, legacySettings.id); - preparedStatement.setNull(2, 4); - preparedStatement.setNull(3, 4); - preparedStatement.setNull(4, 4); - preparedStatement.setNull(5, 4); - preparedStatement.setNull(6, 4); - if (legacySettings.settings.getAlias().isEmpty()) { - preparedStatement.setNull(7, 4); - } else { - preparedStatement.setString(7, legacySettings.settings.getAlias()); - } - boolean[] merged = legacySettings.settings.getMerged(); - int hash = HashUtil.hash(merged); - preparedStatement.setInt(8, hash); - BlockLoc loc = legacySettings.settings.getPosition(); - String position; - if (loc.getY() == 0) { - position = "DEFAULT"; - } else { - position = loc.getX() + "," + loc.getY() + ',' + loc.getZ(); - } - preparedStatement.setString(9, position); - preparedStatement.addBatch(); - if (++updated >= packet) { - try { - preparedStatement.executeBatch(); - } catch (final Exception e) { - LOGGER.error("Failed to store settings for plot with entry ID: {}", legacySettings.id); - e.printStackTrace(); - continue; - } - } - totalUpdated += 1; - } - - if (totalUpdated < myList.size()) { - try { - preparedStatement.executeBatch(); - } catch (final Exception e) { - LOGGER.error("Failed to store settings", e); - } - } - } catch (final Exception e) { - LOGGER.error("Failed to store settings", e); - } - LOGGER.info("Finished converting settings ({} plots processed)", myList.size()); - whenDone.run(); - } - - public void createEmptySettings(final ArrayList myList, final Runnable whenDone) { - final StmtMod mod = new StmtMod<>() { - @Override - public String getCreateMySQL(int size) { - return getCreateMySQL(size, SQLManager.this.CREATE_SETTINGS, 1); - } - - @Override - public String getCreateSQLite(int size) { - return getCreateSQLite(size, "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings` SELECT ? AS `plot_plot_id`, ? AS `biome`, ? AS `rain`, ? AS `custom_time`, ? AS `time`, ? AS " - + "`deny_entry`, ? AS `alias`, ? AS `merged`, ? AS `position` ", 10); - } - - @Override - public String getCreateSQL() { - return "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings`(`plot_plot_id`) VALUES(?)"; - } - - @Override - public void setMySQL(PreparedStatement stmt, int i, Integer id) - throws SQLException { - stmt.setInt(i + 1, id); - } - - @Override - public void setSQLite(PreparedStatement stmt, int i, Integer id) - throws SQLException { - stmt.setInt(i * 10 + 1, id); - stmt.setNull(i * 10 + 2, 4); - stmt.setNull(i * 10 + 3, 4); - stmt.setNull(i * 10 + 4, 4); - stmt.setNull(i * 10 + 5, 4); - stmt.setNull(i * 10 + 6, 4); - stmt.setNull(i * 10 + 7, 4); - stmt.setNull(i * 10 + 8, 4); - stmt.setString(i * 10 + 9, "DEFAULT"); - } - - @Override - public void setSQL(PreparedStatement stmt, Integer id) throws SQLException { - stmt.setInt(1, id); - } - }; - addGlobalTask(() -> setBulk(myList, mod, whenDone)); - } - - public void createPlotSafe(final Plot plot, final Runnable success, final Runnable failure) { - addPlotTask(plot, new UniqueStatement("createPlotSafe_" + plot.hashCode()) { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, plot.getId().getX()); - statement.setInt(2, plot.getId().getY()); - statement.setString(3, plot.getOwnerAbs().toString()); - statement.setString(4, plot.getArea().toString()); - statement.setTimestamp(5, new Timestamp(plot.getTimestamp())); - statement.setString(6, plot.getArea().toString()); - statement.setInt(7, plot.getId().getX()); - statement.setInt(8, plot.getId().getY()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - SQLManager.this.CREATE_PLOT_SAFE, - Statement.RETURN_GENERATED_KEYS - ); - } - - @Override - public void execute(PreparedStatement statement) { - - } - - @Override - public void addBatch(PreparedStatement statement) throws SQLException { - if (statement.execute() || statement.getUpdateCount() > 0) { - try (ResultSet keys = supportsGetGeneratedKeys ? statement.getGeneratedKeys() : statement.getResultSet()) { - if (keys.next()) { - plot.temp = keys.getInt(1); - addPlotTask(plot, new UniqueStatement( - "createPlotAndSettings_settings_" + plot.hashCode()) { - @Override - public void set(PreparedStatement statement) - throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings`(`plot_plot_id`) VALUES(?)"); - } - }); - if (success != null) { - addNotifyTask(success); - } - return; - } - } - } - if (failure != null) { - failure.run(); - } - } - }); - } - - public void commit() { - if (this.closed) { - return; - } - try { - if (!this.connection.getAutoCommit()) { - this.connection.commit(); - this.connection.setAutoCommit(true); - } - } catch (SQLException e) { - e.printStackTrace(); - } - } - - @Override - public void createPlotAndSettings(final Plot plot, Runnable whenDone) { - addPlotTask(plot, new UniqueStatement("createPlotAndSettings_" + plot.hashCode()) { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, plot.getId().getX()); - statement.setInt(2, plot.getId().getY()); - statement.setString(3, plot.getOwnerAbs().toString()); - statement.setString(4, plot.getArea().toString()); - statement.setTimestamp(5, new Timestamp(plot.getTimestamp())); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection - .prepareStatement(SQLManager.this.CREATE_PLOT, Statement.RETURN_GENERATED_KEYS); - } - - @Override - public void execute(PreparedStatement statement) { - } - - @Override - public void addBatch(PreparedStatement statement) throws SQLException { - statement.execute(); - try (ResultSet keys = supportsGetGeneratedKeys ? statement.getGeneratedKeys() : statement.getResultSet()) { - if (keys.next()) { - plot.temp = keys.getInt(1); - } - } - } - }); - addPlotTask(plot, new UniqueStatement("createPlotAndSettings_settings_" + plot.hashCode()) { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings`(`plot_plot_id`) VALUES(?)"); - } - }); - addNotifyTask(whenDone); - } - - /** - * Create tables. - * - * @throws SQLException - */ - @Override - public void createTables() throws SQLException { - String[] tables = - new String[]{"plot", "plot_denied", "plot_helpers", "plot_comments", "plot_trusted", - "plot_rating", "plot_settings", "cluster", "player_meta", "plot_flags"}; - DatabaseMetaData meta = this.connection.getMetaData(); - int create = 0; - for (String s : tables) { - ResultSet set = meta.getTables(null, null, this.prefix + s, new String[]{"TABLE"}); - // ResultSet set = meta.getTables(null, null, prefix + s, null); - if (!set.next()) { - create++; - } - set.close(); - } - if (create == 0) { - return; - } - boolean addConstraint = create == tables.length; - try (Statement stmt = this.connection.createStatement()) { - if (this.mySQL) { - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot` (" - + "`id` INT(11) NOT NULL AUTO_INCREMENT," + "`plot_id_x` INT(11) NOT NULL," - + "`plot_id_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," - + "`world` VARCHAR(45) NOT NULL," - + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP," - + "PRIMARY KEY (`id`)" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=0"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_denied` (`plot_plot_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_helpers` (" - + "`plot_plot_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" - + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," - + "`comment` VARCHAR(40) NOT NULL," + "`inbox` VARCHAR(40) NOT NULL," - + "`timestamp` INT(11) NOT NULL," + "`sender` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_trusted` (" - + "`plot_plot_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_settings` (" - + " `plot_plot_id` INT(11) NOT NULL," - + " `biome` VARCHAR(45) DEFAULT 'FOREST'," + " `rain` INT(1) DEFAULT 0," - + " `custom_time` TINYINT(1) DEFAULT '0'," + " `time` INT(11) DEFAULT '8000'," - + " `deny_entry` TINYINT(1) DEFAULT '0'," - + " `alias` VARCHAR(50) DEFAULT NULL," + " `merged` INT(11) DEFAULT NULL," - + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," - + " PRIMARY KEY (`plot_plot_id`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_rating` ( `plot_plot_id` INT(11) NOT NULL, `rating` INT(2) NOT NULL, `player` VARCHAR(40) NOT NULL) ENGINE=InnoDB " - + "DEFAULT CHARSET=utf8"); - if (addConstraint) { - stmt.addBatch("ALTER TABLE `" + this.prefix + "plot_settings` ADD CONSTRAINT `" - + this.prefix - + "plot_settings_ibfk_1` FOREIGN KEY (`plot_plot_id`) REFERENCES `" - + this.prefix + "plot` (`id`) ON DELETE CASCADE"); - } - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster` (" - + "`id` INT(11) NOT NULL AUTO_INCREMENT," + "`pos1_x` INT(11) NOT NULL," - + "`pos1_z` INT(11) NOT NULL," + "`pos2_x` INT(11) NOT NULL," - + "`pos2_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," - + "`world` VARCHAR(45) NOT NULL," - + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP," - + "PRIMARY KEY (`id`)" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=0"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_helpers` (" - + "`cluster_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_invited` (" - + "`cluster_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_settings` (" - + " `cluster_id` INT(11) NOT NULL," + " `biome` VARCHAR(45) DEFAULT 'FOREST'," - + " `rain` INT(1) DEFAULT 0," + " `custom_time` TINYINT(1) DEFAULT '0'," - + " `time` INT(11) DEFAULT '8000'," + " `deny_entry` TINYINT(1) DEFAULT '0'," - + " `alias` VARCHAR(50) DEFAULT NULL," + " `merged` INT(11) DEFAULT NULL," - + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," - + " PRIMARY KEY (`cluster_id`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "player_meta` (" - + " `meta_id` INT(11) NOT NULL AUTO_INCREMENT," - + " `uuid` VARCHAR(40) NOT NULL," + " `key` VARCHAR(32) NOT NULL," - + " `value` blob NOT NULL," + " PRIMARY KEY (`meta_id`)" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_flags`(" - + "`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY," - + "`plot_id` INT(11) NOT NULL," + " `flag` VARCHAR(64)," - + " `value` VARCHAR(512)," + "FOREIGN KEY (plot_id) REFERENCES `" + this.prefix - + "plot` (id) ON DELETE CASCADE, " + "UNIQUE (plot_id, flag)" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - } else { - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot` (" - + "`id` INTEGER PRIMARY KEY AUTOINCREMENT," + "`plot_id_x` INT(11) NOT NULL," - + "`plot_id_z` INT(11) NOT NULL," + "`owner` VARCHAR(45) NOT NULL," - + "`world` VARCHAR(45) NOT NULL," - + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_denied` (`plot_plot_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_helpers` (`plot_plot_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_trusted` (`plot_plot_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" - + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," - + "`comment` VARCHAR(40) NOT NULL," - + "`inbox` VARCHAR(40) NOT NULL, `timestamp` INT(11) NOT NULL," - + "`sender` VARCHAR(40) NOT NULL" + ')'); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_settings` (" - + " `plot_plot_id` INT(11) NOT NULL," - + " `biome` VARCHAR(45) DEFAULT 'FOREST'," + " `rain` INT(1) DEFAULT 0," - + " `custom_time` TINYINT(1) DEFAULT '0'," + " `time` INT(11) DEFAULT '8000'," - + " `deny_entry` TINYINT(1) DEFAULT '0'," - + " `alias` VARCHAR(50) DEFAULT NULL," + " `merged` INT(11) DEFAULT NULL," - + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," - + " PRIMARY KEY (`plot_plot_id`)" + ')'); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_rating` (`plot_plot_id` INT(11) NOT NULL, `rating` INT(2) NOT NULL, `player` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster` (" - + "`id` INTEGER PRIMARY KEY AUTOINCREMENT," + "`pos1_x` INT(11) NOT NULL," - + "`pos1_z` INT(11) NOT NULL," + "`pos2_x` INT(11) NOT NULL," - + "`pos2_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," - + "`world` VARCHAR(45) NOT NULL," - + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP" + ')'); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "cluster_helpers` (`cluster_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "cluster_invited` (`cluster_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_settings` (" - + " `cluster_id` INT(11) NOT NULL," + " `biome` VARCHAR(45) DEFAULT 'FOREST'," - + " `rain` INT(1) DEFAULT 0," + " `custom_time` TINYINT(1) DEFAULT '0'," - + " `time` INT(11) DEFAULT '8000'," + " `deny_entry` TINYINT(1) DEFAULT '0'," - + " `alias` VARCHAR(50) DEFAULT NULL," + " `merged` INT(11) DEFAULT NULL," - + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," - + " PRIMARY KEY (`cluster_id`)" + ')'); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "player_meta` (" - + " `meta_id` INTEGER PRIMARY KEY AUTOINCREMENT," - + " `uuid` VARCHAR(40) NOT NULL," + " `key` VARCHAR(32) NOT NULL," - + " `value` blob NOT NULL" + ')'); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_flags`(" - + "`id` INTEGER PRIMARY KEY AUTOINCREMENT," + "`plot_id` INTEGER NOT NULL," - + " `flag` VARCHAR(64)," + " `value` VARCHAR(512)," - + "FOREIGN KEY (plot_id) REFERENCES `" + this.prefix - + "plot` (id) ON DELETE CASCADE, " + "UNIQUE (plot_id, flag))"); - } - stmt.executeBatch(); - stmt.clearBatch(); - } - } - - @Override - public void deleteSettings(final Plot plot) { - addPlotTask(plot, new UniqueStatement("delete_plot_settings") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_settings` WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override - public void deleteHelpers(final Plot plot) { - if (plot.getTrusted().isEmpty()) { - return; - } - addPlotTask(plot, new UniqueStatement("delete_plot_helpers") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_helpers` WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override - public void deleteTrusted(final Plot plot) { - if (plot.getMembers().isEmpty()) { - return; - } - addPlotTask(plot, new UniqueStatement("delete_plot_trusted") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_trusted` WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override - public void deleteDenied(final Plot plot) { - if (plot.getDenied().isEmpty()) { - return; - } - addPlotTask(plot, new UniqueStatement("delete_plot_denied") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_denied` WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override - public void deleteComments(final Plot plot) { - addPlotTask(plot, new UniqueStatement("delete_plot_comments") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, plot.getArea().toString()); - statement.setInt(2, plot.hashCode()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `world` = ? AND `hashcode` = ?"); - } - }); - } - - @Override - public void deleteRatings(final Plot plot) { - if (Settings.Enabled_Components.RATING_CACHE && plot.getSettings().getRatings().isEmpty()) { - return; - } - addPlotTask(plot, new UniqueStatement("delete_plot_ratings") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_rating` WHERE `plot_plot_id` = ?"); - } - }); - } - - /** - * Delete a plot. - * - * @param plot - */ - @Override - public void delete(final Plot plot) { - deleteSettings(plot); - deleteDenied(plot); - deleteHelpers(plot); - deleteTrusted(plot); - deleteComments(plot); - deleteRatings(plot); - addPlotTask(plot, new UniqueStatement("delete_plot") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix + "plot` WHERE `id` = ?"); - } - }); - } - - /** - * Creates plot settings - * - * @param id - * @param plot - */ - @Override - public void createPlotSettings(final int id, Plot plot) { - addPlotTask(plot, new UniqueStatement("createPlotSettings") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, id); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings`(`plot_plot_id`) VALUES(?)"); - } - }); - } - - @Override - public int getClusterId(PlotCluster cluster) { - if (cluster.temp > 0) { - return cluster.temp; - } - try { - commit(); - if (cluster.temp > 0) { - return cluster.temp; - } - int c_id; - try (PreparedStatement stmt = this.connection.prepareStatement( - "SELECT `id` FROM `" + this.prefix - + "cluster` WHERE `pos1_x` = ? AND `pos1_z` = ? AND `pos2_x` = ? AND `pos2_z` = ? AND `world` = ? ORDER BY `timestamp` ASC")) { - stmt.setInt(1, cluster.getP1().getX()); - stmt.setInt(2, cluster.getP1().getY()); - stmt.setInt(3, cluster.getP2().getX()); - stmt.setInt(4, cluster.getP2().getY()); - stmt.setString(5, cluster.area.toString()); - try (ResultSet resultSet = stmt.executeQuery()) { - c_id = Integer.MAX_VALUE; - while (resultSet.next()) { - c_id = resultSet.getInt("id"); - } - } - } - if (c_id == Integer.MAX_VALUE || c_id == 0) { - if (cluster.temp > 0) { - return cluster.temp; - } - throw new SQLException("Cluster does not exist in database"); - } - cluster.temp = c_id; - return c_id; - } catch (SQLException e) { - e.printStackTrace(); - } - return Integer.MAX_VALUE; - } - - @Override - public int getId(Plot plot) { - if (plot.temp > 0) { - return plot.temp; - } - try { - commit(); - if (plot.temp > 0) { - return plot.temp; - } - int id; - try (PreparedStatement statement = this.connection.prepareStatement( - "SELECT `id` FROM `" + this.prefix - + "plot` WHERE `plot_id_x` = ? AND `plot_id_z` = ? AND world = ? ORDER BY `timestamp` ASC")) { - statement.setInt(1, plot.getId().getX()); - statement.setInt(2, plot.getId().getY()); - statement.setString(3, plot.getArea().toString()); - try (ResultSet resultSet = statement.executeQuery()) { - id = Integer.MAX_VALUE; - while (resultSet.next()) { - id = resultSet.getInt("id"); - } - } - } - if (id == Integer.MAX_VALUE || id == 0) { - if (plot.temp > 0) { - return plot.temp; - } - throw new SQLException("Plot does not exist in database"); - } - plot.temp = id; - return id; - } catch (SQLException e) { - e.printStackTrace(); - } - return Integer.MAX_VALUE; - } - - @Override - public void updateTables(int[] oldVersion) { - try { - if (this.mySQL && !PlotSquared.get().checkVersion(oldVersion, 3, 3, 2)) { - try (Statement stmt = this.connection.createStatement()) { - stmt.executeUpdate( - "ALTER TABLE `" + this.prefix + "plots` DROP INDEX `unique_alias`"); - } catch (SQLException ignored) { - } - } - DatabaseMetaData data = this.connection.getMetaData(); - ResultSet rs = - data.getColumns(null, null, this.prefix + "plot_comments", "plot_plot_id"); - if (rs.next()) { - rs.close(); - rs = data.getColumns(null, null, this.prefix + "plot_comments", "hashcode"); - if (!rs.next()) { - rs.close(); - try (Statement statement = this.connection.createStatement()) { - statement.addBatch("DROP TABLE `" + this.prefix + "plot_comments`"); - if (Storage.MySQL.USE) { - statement.addBatch( - "CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" - + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," - + "`comment` VARCHAR(40) NOT NULL," - + "`inbox` VARCHAR(40) NOT NULL," - + "`timestamp` INT(11) NOT NULL," - + "`sender` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - } else { - statement.addBatch( - "CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" - + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," - + "`comment` VARCHAR(40) NOT NULL," - + "`inbox` VARCHAR(40) NOT NULL, `timestamp` INT(11) NOT NULL," - + "`sender` VARCHAR(40) NOT NULL" + ')'); - } - statement.executeBatch(); - } catch (SQLException ignored) { - try (Statement statement = this.connection.createStatement()) { - statement.addBatch("ALTER IGNORE TABLE `" + this.prefix - + "plot_comments` ADD `inbox` VARCHAR(11) DEFAULT `public`"); - statement.addBatch("ALTER IGNORE TABLE `" + this.prefix - + "plot_comments` ADD `timestamp` INT(11) DEFAULT 0"); - statement.addBatch("ALTER TABLE `" + this.prefix + "plot` DROP `tier`"); - statement.executeBatch(); - } - } - } - } - rs.close(); - rs = data.getColumns(null, null, this.prefix + "plot_denied", "plot_plot_id"); - if (rs.next()) { - try (Statement statement = this.connection.createStatement()) { - statement.executeUpdate("DELETE FROM `" + this.prefix - + "plot_denied` WHERE `plot_plot_id` NOT IN (SELECT `id` FROM `" - + this.prefix + "plot`)"); - } catch (SQLException e) { - e.printStackTrace(); - } - - rs.close(); - try (Statement statement = this.connection.createStatement()) { - for (String table : new String[]{"plot_denied", "plot_helpers", - "plot_trusted"}) { - ResultSet result = statement.executeQuery( - "SELECT plot_plot_id, user_uuid, COUNT(*) FROM " + this.prefix + table - + " GROUP BY plot_plot_id, user_uuid HAVING COUNT(*) > 1"); - if (result.next()) { - result.close(); - statement.executeUpdate( - "CREATE TABLE " + this.prefix + table + "_tmp AS SELECT * FROM " - + this.prefix + table + " GROUP BY plot_plot_id, user_uuid"); - statement.executeUpdate("DROP TABLE " + this.prefix + table); - statement.executeUpdate( - "CREATE TABLE " + this.prefix + table + " AS SELECT * FROM " - + this.prefix + table + "_tmp"); - statement.executeUpdate("DROP TABLE " + this.prefix + table + "_tmp"); - } - } - } catch (SQLException e2) { - e2.printStackTrace(); - } - } - } catch (SQLException e) { - e.printStackTrace(); - } - - } - - public void deleteRows(ArrayList rowIds, final String table, final String column) { - setBulk(rowIds, new StmtMod<>() { - - @Override - public String getCreateMySQL(int size) { - return getCreateMySQL(1, "DELETE FROM `" + table + "` WHERE `" + column + "` IN ", - size - ); - } - - @Override - public String getCreateSQLite(int size) { - return getCreateMySQL(1, "DELETE FROM `" + table + "` WHERE `" + column + "` IN ", - size - ); - } - - @Override - public String getCreateSQL() { - return "DELETE FROM `" + table + "` WHERE `" + column + "` = ?"; - } - - @Override - public void setMySQL(PreparedStatement stmt, int i, Integer obj) - throws SQLException { - stmt.setInt(i + 1, obj); - } - - @Override - public void setSQLite(PreparedStatement stmt, int i, Integer obj) - throws SQLException { - stmt.setInt(i + 1, obj); - } - - @Override - public void setSQL(PreparedStatement stmt, Integer obj) throws SQLException { - stmt.setInt(1, obj); - } - }, null); - } - - @Override - public boolean convertFlags() { - final Map> flagMap = new HashMap<>(); - try (Statement statement = this.connection.createStatement()) { - try (ResultSet resultSet = statement - .executeQuery("SELECT * FROM `" + this.prefix + "plot_settings`")) { - while (resultSet.next()) { - final int id = resultSet.getInt("plot_plot_id"); - final String plotFlags = resultSet.getString("flags"); - if (plotFlags == null || plotFlags.isEmpty()) { - continue; - } - flagMap.put(id, new HashMap<>()); - for (String element : plotFlags.split(",")) { - if (element.contains(":")) { - String[] split = element.split(":"); // splits flag:value - try { - String flag_str = - split[1].replaceAll("¯", ":").replaceAll("\u00B4", ","); - flagMap.get(id).put(split[0], flag_str); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - } - } catch (final Exception e) { - LOGGER.error("Failed to load old flag values", e); - return false; - } - LOGGER.info("Loaded {} plot flag collections...", flagMap.size()); - LOGGER.info("Attempting to store these flags in the new table..."); - try (final PreparedStatement preparedStatement = this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_flags`(`plot_id`, `flag`, `value`) VALUES(?, ?, ?)")) { - - long timeStarted = System.currentTimeMillis(); - int flagsProcessed = 0; - int plotsProcessed = 0; - - int totalFlags = 0; - for (final Map flags : flagMap.values()) { - totalFlags += flags.size(); - } - - for (final Map.Entry> plotFlagEntry : flagMap.entrySet()) { - for (final Map.Entry flagEntry : plotFlagEntry.getValue() - .entrySet()) { - preparedStatement.setInt(1, plotFlagEntry.getKey()); - preparedStatement.setString(2, flagEntry.getKey()); - preparedStatement.setString(3, flagEntry.getValue()); - preparedStatement.addBatch(); - flagsProcessed += 1; - } - plotsProcessed += 1; - - try { - preparedStatement.executeBatch(); - } catch (final Exception e) { - LOGGER.error("Failed to store flag values for plot with entry ID: {}", plotFlagEntry.getKey()); - e.printStackTrace(); - continue; - } - - if (System.currentTimeMillis() - timeStarted >= 1000L || plotsProcessed >= flagMap - .size()) { - timeStarted = System.currentTimeMillis(); - LOGGER.info( - "... Flag conversion in progress. {}% done", - String.format("%.1f", ((float) flagsProcessed / totalFlags) * 100) - ); - } - LOGGER.info( - "- Finished converting flags for plot with entry ID: {}", - plotFlagEntry.getKey() - ); - } - } catch (final Exception e) { - LOGGER.error("Failed to store flag values", e); - return false; - } - return true; - } - - /** - * Load all plots, helpers, denied, trusted, and every setting from DB into a {@link HashMap}. - */ - @Override - public HashMap> getPlots() { - HashMap> newPlots = new HashMap<>(); - HashMap plots = new HashMap<>(); - try { - HashSet areas = new HashSet<>(); - if (this.worldConfiguration.contains("worlds")) { - ConfigurationSection worldSection = this.worldConfiguration.getConfigurationSection("worlds"); - if (worldSection != null) { - for (String worldKey : worldSection.getKeys(false)) { - areas.add(worldKey); - ConfigurationSection areaSection = - worldSection.getConfigurationSection(worldKey + ".areas"); - if (areaSection != null) { - for (String areaKey : areaSection.getKeys(false)) { - String[] split = areaKey.split("(? uuids = new HashMap<>(); - HashMap noExist = new HashMap<>(); - - /* - * Getting plots - */ - try (Statement statement = this.connection.createStatement()) { - int id; - String o; - UUID user; - try (ResultSet resultSet = statement.executeQuery( - "SELECT `id`, `plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp` FROM `" - + this.prefix + "plot`")) { - ArrayList toDelete = new ArrayList<>(); - while (resultSet.next()) { - PlotId plot_id = PlotId.of( - resultSet.getInt("plot_id_x"), - resultSet.getInt("plot_id_z") - ); - id = resultSet.getInt("id"); - String areaID = resultSet.getString("world"); - if (!areas.contains(areaID)) { - if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - continue; - } else { - AtomicInteger value = noExist.get(areaID); - if (value != null) { - value.incrementAndGet(); - } else { - noExist.put(areaID, new AtomicInteger(1)); - } - } - } - o = resultSet.getString("owner"); - user = uuids.get(o); - if (user == null) { - try { - user = UUID.fromString(o); - } catch (IllegalArgumentException e) { - if (Settings.UUID.FORCE_LOWERCASE) { - user = UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + o.toLowerCase()) - .getBytes(Charsets.UTF_8)); - } else { - user = UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + o).getBytes(Charsets.UTF_8)); - } - } - uuids.put(o, user); - } - long time; - try { - Timestamp timestamp = resultSet.getTimestamp("timestamp"); - time = timestamp.getTime(); - } catch (SQLException exception) { - String parsable = resultSet.getString("timestamp"); - try { - time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(parsable) - .getTime(); - } catch (ParseException e) { - LOGGER.error("Could not parse date for plot: #{}({};{}) ({})", - id, areaID, plot_id, parsable - ); - time = System.currentTimeMillis() + id; - } - } - Plot p = new Plot(plot_id, user, new HashSet<>(), new HashSet<>(), - new HashSet<>(), "", null, null, null, - new boolean[]{false, false, false, false}, time, id - ); - HashMap map = newPlots.get(areaID); - if (map != null) { - Plot last = map.put(p.getId(), p); - if (last != null) { - if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(last.temp); - } else { - LOGGER.info( - "Plot #{}({}) in `{}plot` is a duplicate." - + " Delete this plot or set `database-purger: true` in the settings.yml", - id, - last, - this.prefix - ); - } - } - } else { - map = new HashMap<>(); - newPlots.put(areaID, map); - map.put(p.getId(), p); - } - plots.put(id, p); - } - deleteRows(toDelete, this.prefix + "plot", "id"); - } - if (Settings.Enabled_Components.RATING_CACHE) { - try (ResultSet r = statement.executeQuery( - "SELECT `plot_plot_id`, `player`, `rating` FROM `" + this.prefix - + "plot_rating`")) { - ArrayList toDelete = new ArrayList<>(); - while (r.next()) { - id = r.getInt("plot_plot_id"); - o = r.getString("player"); - user = uuids.get(o); - if (user == null) { - user = UUID.fromString(o); - uuids.put(o, user); - } - Plot plot = plots.get(id); - if (plot != null) { - plot.getSettings().getRatings().put(user, r.getInt("rating")); - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - LOGGER.warn("Entry #{}({}) in `plot_rating` does not exist." - + " Create this plot or set `database-purger: true` in settings.yml", id, plot); - } - } - deleteRows(toDelete, this.prefix + "plot_rating", "plot_plot_id"); - } - } - - /* - * Getting helpers - */ - try (ResultSet r = statement.executeQuery( - "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_helpers`")) { - ArrayList toDelete = new ArrayList<>(); - while (r.next()) { - id = r.getInt("plot_plot_id"); - o = r.getString("user_uuid"); - user = uuids.get(o); - if (user == null) { - user = UUID.fromString(o); - uuids.put(o, user); - } - Plot plot = plots.get(id); - if (plot != null) { - plot.getTrusted().add(user); - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - LOGGER.warn("Entry #{}({}) in `plot_helpers` does not exist." - + " Create this plot or set `database-purger: true` in settings.yml", id, plot); - } - } - deleteRows(toDelete, this.prefix + "plot_helpers", "plot_plot_id"); - } - - /* - * Getting trusted - */ - try (ResultSet r = statement.executeQuery( - "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_trusted`")) { - ArrayList toDelete = new ArrayList<>(); - while (r.next()) { - id = r.getInt("plot_plot_id"); - o = r.getString("user_uuid"); - user = uuids.get(o); - if (user == null) { - user = UUID.fromString(o); - uuids.put(o, user); - } - Plot plot = plots.get(id); - if (plot != null) { - plot.getMembers().add(user); - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - LOGGER.warn("Entry #{}({}) in `plot_trusted` does not exist." - + " Create this plot or set `database-purger: true` in settings.yml", id, plot); - } - } - deleteRows(toDelete, this.prefix + "plot_trusted", "plot_plot_id"); - } - - /* - * Getting denied - */ - try (ResultSet r = statement.executeQuery( - "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_denied`")) { - ArrayList toDelete = new ArrayList<>(); - while (r.next()) { - id = r.getInt("plot_plot_id"); - o = r.getString("user_uuid"); - user = uuids.get(o); - if (user == null) { - user = UUID.fromString(o); - uuids.put(o, user); - } - Plot plot = plots.get(id); - if (plot != null) { - plot.getDenied().add(user); - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - LOGGER.warn("Entry #{}({}) in `plot_denied` does not exist." - + " Create this plot or set `database-purger: true` in settings.yml", id, plot); - } - } - deleteRows(toDelete, this.prefix + "plot_denied", "plot_plot_id"); - } - - try (final ResultSet resultSet = statement - .executeQuery("SELECT * FROM `" + this.prefix + "plot_flags`")) { - BlockTypeListFlag.skipCategoryVerification = - true; // allow invalid tags, as initialized lazily - final ArrayList toDelete = new ArrayList<>(); - final Map>> invalidFlags = new HashMap<>(); - while (resultSet.next()) { - id = resultSet.getInt("plot_id"); - final String flag = resultSet.getString("flag"); - String value = resultSet.getString("value"); - final Plot plot = plots.get(id); - if (plot != null) { - final PlotFlag plotFlag = - GlobalFlagContainer.getInstance().getFlagFromString(flag); - if (plotFlag == null) { - plot.getFlagContainer().addUnknownFlag(flag, value); - } else { - value = CaptionUtility.stripClickEvents(plotFlag, value); - try { - plot.getFlagContainer().addFlag(plotFlag.parse(value)); - } catch (final FlagParseException e) { - e.printStackTrace(); - LOGGER.error("Plot with ID {} has an invalid value:", id); - LOGGER.error("Failed to parse flag '{}', value '{}': {}", - plotFlag.getName(), e.getValue(), e.getErrorMessage() - ); - if (!invalidFlags.containsKey(plot)) { - invalidFlags.put(plot, new ArrayList<>()); - } - invalidFlags.get(plot).add(plotFlag); - } - } - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - LOGGER.warn("Entry #{}({}) in `plot_flags` does not exist." - + " Create this plot or set `database-purger: true` in settings.yml", id, plot); - } - } - BlockTypeListFlag.skipCategoryVerification = - false; // don't allow invalid tags anymore - if (Settings.Enabled_Components.DATABASE_PURGER) { - for (final Map.Entry>> plotFlagEntry : invalidFlags - .entrySet()) { - for (final PlotFlag flag : plotFlagEntry.getValue()) { - LOGGER.info( - "Plot {} has an invalid flag ({}). A fix has been attempted", - plotFlagEntry.getKey(), flag.getName() - ); - removeFlag(plotFlagEntry.getKey(), flag); - } - } - } - deleteRows(toDelete, this.prefix + "plot_flags", "plot_id"); - } - - try (ResultSet resultSet = statement - .executeQuery("SELECT * FROM `" + this.prefix + "plot_settings`")) { - ArrayList toDelete = new ArrayList<>(); - while (resultSet.next()) { - id = resultSet.getInt("plot_plot_id"); - Plot plot = plots.get(id); - if (plot != null) { - plots.remove(id); - String alias = resultSet.getString("alias"); - if (alias != null) { - plot.getSettings().setAlias(alias); - } - String pos = resultSet.getString("position"); - switch (pos.toLowerCase()) { - case "": - case "default": - case "0,0,0": - case "center": - case "centre": - break; - default: - try { - plot.getSettings().setPosition(BlockLoc.fromString(pos)); - } catch (Exception ignored) { - } - } - int m = resultSet.getInt("merged"); - boolean[] merged = new boolean[4]; - for (int i = 0; i < 4; i++) { - merged[3 - i] = (m & 1 << i) != 0; - } - plot.getSettings().setMerged(merged); - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - LOGGER.warn("Entry #{}({}) in `plot_settings` does not exist." - + " Create this plot or set `database-purger: true` in settings.yml", id, plot); - } - } - deleteRows(toDelete, this.prefix + "plot_settings", "plot_plot_id"); - } - } - if (!plots.entrySet().isEmpty()) { - createEmptySettings(new ArrayList<>(plots.keySet()), null); - for (Entry entry : plots.entrySet()) { - entry.getValue().getSettings(); - } - } - boolean invalidPlot = false; - for (Entry entry : noExist.entrySet()) { - String worldName = entry.getKey(); - invalidPlot = true; - if (Settings.DEBUG) { - LOGGER.info("Warning! Found {} plots in DB for non existent world: '{}'", - entry.getValue().intValue(), worldName - ); - } - } - if (invalidPlot && Settings.DEBUG) { - LOGGER.info("Warning! Please create the world(s) or remove the plots using the purge command"); - } - } catch (SQLException e) { - LOGGER.error("Failed to load plots", e); - } - return newPlots; - } - - @Override - public void setMerged(final Plot plot, final boolean[] merged) { - plot.getSettings().setMerged(merged); - addPlotTask(plot, new UniqueStatement("setMerged") { - @Override - public void set(PreparedStatement statement) throws SQLException { - int hash = HashUtil.hash(merged); - statement.setInt(1, hash); - statement.setInt(2, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot_settings` SET `merged` = ? WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override - public CompletableFuture swapPlots(Plot plot1, Plot plot2) { - final CompletableFuture future = new CompletableFuture<>(); - TaskManager.runTaskAsync(() -> { - final int id1 = getId(plot1); - final int id2 = getId(plot2); - final PlotId pos1 = plot1.getId(); - final PlotId pos2 = plot2.getId(); - try (final PreparedStatement preparedStatement = this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot` SET `plot_id_x` = ?, `plot_id_z` = ? WHERE `id` = ?")) { - preparedStatement.setInt(1, pos1.getX()); - preparedStatement.setInt(2, pos1.getY()); - preparedStatement.setInt(3, id1); - preparedStatement.execute(); - preparedStatement.setInt(1, pos2.getX()); - preparedStatement.setInt(2, pos2.getY()); - preparedStatement.setInt(3, id2); - preparedStatement.execute(); - } catch (final Exception e) { - LOGGER.error("Failed to persist wap of {} and {}", plot1, plot2); - e.printStackTrace(); - future.complete(false); - return; - } - future.complete(true); - }); - return future; - } - - @Override - public void movePlot(final Plot original, final Plot newPlot) { - addPlotTask(original, new UniqueStatement("movePlot") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, newPlot.getId().getX()); - statement.setInt(2, newPlot.getId().getY()); - statement.setString(3, newPlot.getArea().toString()); - statement.setInt(4, getId(original)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot` SET `plot_id_x` = ?, `plot_id_z` = ?, `world` = ? WHERE `id` = ?"); - } - }); - addPlotTask(newPlot, null); - } - - @Override - public void setFlag(final Plot plot, final PlotFlag flag) { - addPlotTask(plot, new UniqueStatement("setFlag") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, flag.getName()); - statement.setString(3, flag.toString()); - statement.setString(4, flag.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - final String statement; - if (SQLManager.this.mySQL) { - statement = "INSERT INTO `" + SQLManager.this.prefix - + "plot_flags`(`plot_id`, `flag`, `value`) VALUES(?, ?, ?) " - + "ON DUPLICATE KEY UPDATE `value` = ?"; - } else { - statement = "INSERT INTO `" + SQLManager.this.prefix - + "plot_flags`(`plot_id`, `flag`, `value`) VALUES(?, ?, ?) " - + "ON CONFLICT(`plot_id`,`flag`) DO UPDATE SET `value` = ?"; - } - return SQLManager.this.connection.prepareStatement(statement); - } - }); - } - - @Override - public void removeFlag(final Plot plot, final PlotFlag flag) { - addPlotTask(plot, new UniqueStatement("removeFlag") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, flag.getName()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_flags` WHERE `plot_id` = ? AND `flag` = ?"); - } - }); - } - - @Override - public void setAlias(final Plot plot, final String alias) { - addPlotTask(plot, new UniqueStatement("setAlias") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, alias); - statement.setInt(2, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot_settings` SET `alias` = ? WHERE `plot_plot_id` = ?"); - } - }); - } - - /** - * Purge all plots with the following database IDs - */ - @Override - public void purgeIds(final Set uniqueIds) { - addGlobalTask(() -> { - if (!uniqueIds.isEmpty()) { - try { - ArrayList uniqueIdsList = new ArrayList<>(uniqueIds); - int size = uniqueIdsList.size(); - int packet = 990; - int amount = size / packet; - for (int j = 0; j <= amount; j++) { - List subList = - uniqueIdsList.subList(j * packet, Math.min(size, (j + 1) * packet)); - if (subList.isEmpty()) { - break; - } - StringBuilder idstr2 = new StringBuilder(); - String stmt_prefix = ""; - for (Integer id : subList) { - idstr2.append(stmt_prefix).append(id); - stmt_prefix = " OR `id` = "; - } - stmt_prefix = ""; - StringBuilder idstr = new StringBuilder(); - for (Integer id : subList) { - idstr.append(stmt_prefix).append(id); - stmt_prefix = " OR `plot_plot_id` = "; - } - PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_helpers` WHERE `plot_plot_id` = " + idstr); - stmt.executeUpdate(); - stmt.close(); - stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_denied` WHERE `plot_plot_id` = " + idstr); - stmt.executeUpdate(); - stmt.close(); - stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_settings` WHERE `plot_plot_id` = " + idstr); - stmt.executeUpdate(); - stmt.close(); - stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_trusted` WHERE `plot_plot_id` = " + idstr); - stmt.executeUpdate(); - stmt.close(); - stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix + "plot` WHERE `id` = " - + idstr2); - stmt.executeUpdate(); - stmt.close(); - commit(); - } - } catch (SQLException e) { - LOGGER.error("Failed to purge plots", e); - return; - } - } - LOGGER.info("Successfully purged {} plots", uniqueIds.size()); - }); - } - - @Override - public void purge(final PlotArea area, final Set plots) { - addGlobalTask(() -> { - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "SELECT `id`, `plot_id_x`, `plot_id_z` FROM `" + SQLManager.this.prefix - + "plot` WHERE `world` = ?")) { - stmt.setString(1, area.toString()); - Set ids; - try (ResultSet r = stmt.executeQuery()) { - ids = new HashSet<>(); - while (r.next()) { - PlotId plot_id = PlotId.of(r.getInt("plot_id_x"), r.getInt("plot_id_z")); - if (plots.contains(plot_id)) { - ids.add(r.getInt("id")); - } - } - } - purgeIds(ids); - } catch (SQLException e) { - LOGGER.error("Failed to purge area '{}'", area); - e.printStackTrace(); - } - for (Iterator iterator = plots.iterator(); iterator.hasNext(); ) { - PlotId plotId = iterator.next(); - iterator.remove(); - PlotId id = PlotId.of(plotId.getX(), plotId.getY()); - area.removePlot(id); - } - }); - } - - @Override - public void setPosition(final Plot plot, final String position) { - addPlotTask(plot, new UniqueStatement("setPosition") { - @Override - public void set(PreparedStatement statement) throws SQLException { - // Please see the table creation statement. There is the default value of "default" - statement.setString(1, position == null ? "DEFAULT" : position); - statement.setInt(2, getId(plot)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot_settings` SET `position` = ? WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override - public void removeComment(final Plot plot, final PlotComment comment) { - addPlotTask(plot, new UniqueStatement("removeComment") { - @Override - public void set(PreparedStatement statement) throws SQLException { - if (plot != null) { - statement.setString(1, plot.getArea().toString()); - statement.setInt(2, plot.getId().hashCode()); - statement.setString(3, comment.comment()); - statement.setString(4, comment.inbox()); - statement.setString(5, comment.senderName()); - } else { - statement.setString(1, comment.comment()); - statement.setString(2, comment.inbox()); - statement.setString(3, comment.senderName()); - } - } - - @Override - public PreparedStatement get() throws SQLException { - if (plot != null) { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `comment` = ? AND `inbox` = ? AND `sender` = ?"); - } - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `comment` = ? AND `inbox` = ? AND `sender` = ?"); - } - }); - } - - @Override - public void clearInbox(final Plot plot, final String inbox) { - addPlotTask(plot, new UniqueStatement("clearInbox") { - @Override - public void set(PreparedStatement statement) throws SQLException { - if (plot != null) { - statement.setString(1, plot.getArea().toString()); - statement.setInt(2, plot.getId().hashCode()); - statement.setString(3, inbox); - } else { - statement.setString(1, inbox); - } - } - - @Override - public PreparedStatement get() throws SQLException { - if (plot != null) { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `inbox` = ?"); - } - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix + "plot_comments` `inbox` = ?"); - } - }); - } - - @Override - public void getComments( - @NonNull Plot plot, final String inbox, - final RunnableVal> whenDone - ) { - addPlotTask(plot, new UniqueStatement("getComments_" + plot) { - @Override - public void set(PreparedStatement statement) throws SQLException { - if (plot != null) { - statement.setString(1, plot.getArea().toString()); - statement.setInt(2, plot.getId().hashCode()); - statement.setString(3, inbox); - } else { - statement.setString(1, inbox); - } - } - - @Override - public PreparedStatement get() throws SQLException { - if (plot != null) { - return SQLManager.this.connection.prepareStatement( - "SELECT * FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `inbox` = ?"); - } - return SQLManager.this.connection.prepareStatement( - "SELECT * FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `inbox` = ?"); - } - - @Override - public void execute(PreparedStatement statement) { - } - - @Override - public void addBatch(PreparedStatement statement) throws SQLException { - ArrayList comments = new ArrayList<>(); - try (ResultSet set = statement.executeQuery()) { - while (set.next()) { - String sender = set.getString("sender"); - String world = set.getString("world"); - int hash = set.getInt("hashcode"); - PlotId id; - if (hash != 0) { - id = PlotId.unpair(hash); - } else { - id = null; - } - String msg = set.getString("comment"); - long timestamp = set.getInt("timestamp") * 1000; - PlotComment comment = - new PlotComment(world, id, msg, sender, inbox, timestamp); - comments.add(comment); - } - whenDone.value = comments; - } - TaskManager.runTask(whenDone); - } - }); - } - - @Override - public void setComment(final Plot plot, final PlotComment comment) { - addPlotTask(plot, new UniqueStatement("setComment") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, plot.getArea().toString()); - statement.setInt(2, plot.getId().hashCode()); - statement.setString(3, comment.comment()); - statement.setString(4, comment.inbox()); - statement.setInt(5, (int) (comment.timestamp() / 1000)); - statement.setString(6, comment.senderName()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_comments` (`world`, `hashcode`, `comment`, `inbox`, `timestamp`, `sender`) VALUES(?,?,?,?,?,?)"); - } - }); - } - - @Override - public void removeTrusted(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("removeTrusted") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_helpers` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override - public void removeMember(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("removeMember") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_trusted` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override - public void setTrusted(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("setTrusted") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_helpers` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override - public void setMember(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("setMember") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_trusted` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override - public void removeDenied(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("removeDenied") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_denied` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override - public void setDenied(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("setDenied") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_denied` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override - public HashMap getRatings(Plot plot) { - HashMap map = new HashMap<>(); - try (PreparedStatement statement = this.connection.prepareStatement( - "SELECT `rating`, `player` FROM `" + this.prefix - + "plot_rating` WHERE `plot_plot_id` = ? ")) { - statement.setInt(1, getId(plot)); - try (ResultSet resultSet = statement.executeQuery()) { - while (resultSet.next()) { - UUID uuid = UUID.fromString(resultSet.getString("player")); - int rating = resultSet.getInt("rating"); - map.put(uuid, rating); - } - } - } catch (SQLException e) { - LOGGER.error("Failed to fetch rating for plot {}", plot.getId().toString()); - e.printStackTrace(); - } - return map; - } - - @Override - public void setRating(final Plot plot, final UUID rater, final int value) { - addPlotTask(plot, new UniqueStatement("setRating") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setInt(2, value); - statement.setString(3, rater.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_rating` (`plot_plot_id`, `rating`, `player`) VALUES(?,?,?)"); - } - }); - } - - @Override - public void delete(PlotCluster cluster) { - final int id = getClusterId(cluster); - addClusterTask(cluster, new UniqueStatement("delete_cluster_settings") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, id); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_settings` WHERE `cluster_id` = ?"); - } - }); - addClusterTask(cluster, new UniqueStatement("delete_cluster_helpers") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, id); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_helpers` WHERE `cluster_id` = ?"); - } - }); - addClusterTask(cluster, new UniqueStatement("delete_cluster_invited") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, id); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_invited` WHERE `cluster_id` = ?"); - } - }); - addClusterTask(cluster, new UniqueStatement("delete_cluster") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, id); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix + "cluster` WHERE `id` = ?"); - } - }); - } - - @Override - public void addPersistentMeta( - final UUID uuid, final String key, final byte[] meta, - final boolean replace - ) { - addPlayerTask(uuid, new UniqueStatement("addPersistentMeta") { - @Override - public void set(PreparedStatement statement) throws SQLException { - if (replace) { - statement.setBytes(1, meta); - statement.setString(2, uuid.toString()); - statement.setString(3, key); - } else { - statement.setString(1, uuid.toString()); - statement.setString(2, key); - statement.setBytes(3, meta); - } - } - - @Override - public PreparedStatement get() throws SQLException { - if (replace) { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "player_meta` SET `value` = ? WHERE `uuid` = ? AND `key` = ?"); - } else { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "player_meta`(`uuid`, `key`, `value`) VALUES(?, ? ,?)"); - } - } - }); - } - - @Override - public void removePersistentMeta(final UUID uuid, final String key) { - addPlayerTask(uuid, new UniqueStatement("removePersistentMeta") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, uuid.toString()); - statement.setString(2, key); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "player_meta` WHERE `uuid` = ? AND `key` = ?"); - } - }); - } - - @Override - public void getPersistentMeta(final UUID uuid, final RunnableVal> result) { - addPlayerTask(uuid, new UniqueStatement("getPersistentMeta") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "SELECT * FROM `" + SQLManager.this.prefix - + "player_meta` WHERE `uuid` = ? ORDER BY `meta_id` ASC"); - } - - @Override - public void execute(PreparedStatement statement) { - } - - @Override - public void addBatch(PreparedStatement statement) throws SQLException { - ResultSet resultSet = statement.executeQuery(); - - final Map metaMap = new HashMap<>(); - - while (resultSet.next()) { - String key = resultSet.getString("key"); - byte[] bytes = resultSet.getBytes("value"); - metaMap.put(key, bytes); - } - - resultSet.close(); - TaskManager.runTaskAsync(() -> result.run(metaMap)); - } - - }); - } - - @Override - public HashMap> getClusters() { - LinkedHashMap> newClusters = new LinkedHashMap<>(); - HashMap clusters = new HashMap<>(); - try { - HashSet areas = new HashSet<>(); - if (this.worldConfiguration.contains("worlds")) { - ConfigurationSection worldSection = this.worldConfiguration.getConfigurationSection("worlds"); - if (worldSection != null) { - for (String worldKey : worldSection.getKeys(false)) { - areas.add(worldKey); - ConfigurationSection areaSection = - worldSection.getConfigurationSection(worldKey + ".areas"); - if (areaSection != null) { - for (String areaKey : areaSection.getKeys(false)) { - String[] split = areaKey.split("(? uuids = new HashMap<>(); - HashMap noExist = new HashMap<>(); - /* - * Getting clusters - */ - try (Statement stmt = this.connection.createStatement()) { - ResultSet resultSet = - stmt.executeQuery("SELECT * FROM `" + this.prefix + "cluster`"); - PlotCluster cluster; - String owner; - UUID user; - int id; - while (resultSet.next()) { - PlotId pos1 = - PlotId.of(resultSet.getInt("pos1_x"), resultSet.getInt("pos1_z")); - PlotId pos2 = - PlotId.of(resultSet.getInt("pos2_x"), resultSet.getInt("pos2_z")); - id = resultSet.getInt("id"); - String areaid = resultSet.getString("world"); - if (!areas.contains(areaid)) { - noExist.merge(areaid, 1, Integer::sum); - } - owner = resultSet.getString("owner"); - user = uuids.get(owner); - if (user == null) { - user = UUID.fromString(owner); - uuids.put(owner, user); - } - cluster = new PlotCluster(null, pos1, pos2, user, id); - clusters.put(id, cluster); - Set set = - newClusters.computeIfAbsent(areaid, k -> new HashSet<>()); - set.add(cluster); - } - //Getting helpers - resultSet = stmt.executeQuery( - "SELECT `user_uuid`, `cluster_id` FROM `" + this.prefix + "cluster_helpers`"); - while (resultSet.next()) { - id = resultSet.getInt("cluster_id"); - owner = resultSet.getString("user_uuid"); - user = uuids.get(owner); - if (user == null) { - user = UUID.fromString(owner); - uuids.put(owner, user); - } - cluster = clusters.get(id); - if (cluster != null) { - cluster.helpers.add(user); - } else { - LOGGER.warn("Cluster #{}({}) in cluster_helpers does not exist." - + " Please create the cluster or remove this entry", id, cluster); - } - } - // Getting invited - resultSet = stmt.executeQuery( - "SELECT `user_uuid`, `cluster_id` FROM `" + this.prefix + "cluster_invited`"); - while (resultSet.next()) { - id = resultSet.getInt("cluster_id"); - owner = resultSet.getString("user_uuid"); - user = uuids.get(owner); - if (user == null) { - user = UUID.fromString(owner); - uuids.put(owner, user); - } - cluster = clusters.get(id); - if (cluster != null) { - cluster.invited.add(user); - } else { - LOGGER.warn("Cluster #{}({}) in cluster_helpers does not exist." - + " Please create the cluster or remove this entry", id, cluster); - } - } - resultSet = - stmt.executeQuery("SELECT * FROM `" + this.prefix + "cluster_settings`"); - while (resultSet.next()) { - id = resultSet.getInt("cluster_id"); - cluster = clusters.get(id); - if (cluster != null) { - String alias = resultSet.getString("alias"); - if (alias != null) { - cluster.settings.setAlias(alias); - } - String pos = resultSet.getString("position"); - switch (pos.toLowerCase()) { - case "": - case "default": - case "0,0,0": - case "center": - case "centre": - break; - default: - try { - BlockLoc loc = BlockLoc.fromString(pos); - cluster.settings.setPosition(loc); - } catch (Exception ignored) { - } - } - int m = resultSet.getInt("merged"); - boolean[] merged = new boolean[4]; - for (int i = 0; i < 4; i++) { - merged[3 - i] = (m & 1 << i) != 0; - } - cluster.settings.setMerged(merged); - } else { - LOGGER.warn("Cluster #{}({}) in cluster_helpers does not exist." - + " Please create the cluster or remove this entry", id, cluster); - } - } - resultSet.close(); - } - boolean invalidPlot = false; - for (Entry entry : noExist.entrySet()) { - String a = entry.getKey(); - invalidPlot = true; - LOGGER.warn("Warning! Found {} clusters in DB for non existent area; '{}'", noExist.get(a), a); - } - if (invalidPlot) { - LOGGER.warn("Warning! Please create the world(s) or remove the clusters using the purge command"); - } - } catch (SQLException e) { - LOGGER.error("Failed to load clusters", e); - } - return newClusters; - } - - @Override - public void setClusterName(final PlotCluster cluster, final String name) { - addClusterTask(cluster, new UniqueStatement("setClusterName") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, name); - statement.setInt(2, getClusterId(cluster)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster_settings` SET `alias` = ? WHERE `cluster_id` = ?"); - } - }); - cluster.settings.setAlias(name); - } - - @Override - public void removeHelper(final PlotCluster cluster, final UUID uuid) { - addClusterTask(cluster, new UniqueStatement("removeHelper") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getClusterId(cluster)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_helpers` WHERE `cluster_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override - public void setHelper(final PlotCluster cluster, final UUID uuid) { - addClusterTask(cluster, new UniqueStatement("setHelper") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getClusterId(cluster)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "cluster_helpers` (`cluster_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override - public void createCluster(final PlotCluster cluster) { - addClusterTask(cluster, new UniqueStatement("createCluster_" + cluster.hashCode()) { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, cluster.getP1().getX()); - statement.setInt(2, cluster.getP1().getY()); - statement.setInt(3, cluster.getP2().getX()); - statement.setInt(4, cluster.getP2().getY()); - statement.setString(5, cluster.owner.toString()); - statement.setString(6, cluster.area.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - SQLManager.this.CREATE_CLUSTER, - Statement.RETURN_GENERATED_KEYS - ); - } - - @Override - public void execute(PreparedStatement statement) { - } - - @Override - public void addBatch(PreparedStatement statement) throws SQLException { - statement.execute(); - try (ResultSet keys = supportsGetGeneratedKeys ? statement.getGeneratedKeys() : statement.getResultSet()) { - if (keys.next()) { - cluster.temp = keys.getInt(1); - } - } - } - }); - addClusterTask( - cluster, - new UniqueStatement("createCluster_settings_" + cluster.hashCode()) { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getClusterId(cluster)); - statement.setString(2, cluster.settings.getAlias()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "cluster_settings`(`cluster_id`, `alias`) VALUES(?, ?)"); - } - } - ); - } - - @Override - public void resizeCluster(final PlotCluster current, PlotId min, PlotId max) { - final PlotId pos1 = PlotId.of(current.getP1().getX(), current.getP1().getY()); - final PlotId pos2 = PlotId.of(current.getP2().getX(), current.getP2().getY()); - current.setP1(min); - current.setP2(max); - - addClusterTask(current, new UniqueStatement("resizeCluster") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, pos1.getX()); - statement.setInt(2, pos1.getY()); - statement.setInt(3, pos2.getX()); - statement.setInt(4, pos2.getY()); - statement.setInt(5, getClusterId(current)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster` SET `pos1_x` = ?, `pos1_z` = ?, `pos2_x` = ?, `pos2_z` = ? WHERE `id` = ?"); - } - }); - } - - @Override - public void setPosition(final PlotCluster cluster, final String position) { - addClusterTask(cluster, new UniqueStatement("setPosition") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, position); - statement.setInt(2, getClusterId(cluster)); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster_settings` SET `position` = ? WHERE `cluster_id` = ?"); - } - }); - } - - @Override - public void removeInvited(final PlotCluster cluster, final UUID uuid) { - addClusterTask(cluster, new UniqueStatement("removeInvited") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getClusterId(cluster)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_invited` WHERE `cluster_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override - public void setInvited(final PlotCluster cluster, final UUID uuid) { - addClusterTask(cluster, new UniqueStatement("setInvited") { - @Override - public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getClusterId(cluster)); - statement.setString(2, uuid.toString()); - } - - @Override - public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "cluster_invited` (`cluster_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override - public boolean deleteTables() { - try (Statement stmt = this.connection.createStatement(); - PreparedStatement statement = this.connection - .prepareStatement("DROP TABLE `" + this.prefix + "plot`")) { - close(); - this.closed = false; - SQLManager.this.connection = this.database.forceConnection(); - stmt.addBatch("DROP TABLE `" + this.prefix + "cluster_invited`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "cluster_helpers`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "cluster`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_rating`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_settings`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_comments`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_trusted`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_helpers`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_denied`"); - stmt.executeBatch(); - stmt.clearBatch(); - statement.executeUpdate(); - } catch (ClassNotFoundException | SQLException e) { - e.printStackTrace(); - - } - return true; - } - - @SuppressWarnings({"unchecked", "unused"}) - @Override - public void validateAllPlots(Set toValidate) { - if (!isValid()) { - reconnect(); - } - LOGGER.info( - "All DB transactions during this session are being validated (This may take a while if corrections need to be made)"); - commit(); - while (true) { - if (!sendBatch()) { - break; - } - } - try { - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); - } - } catch (SQLException e) { - e.printStackTrace(); - } - HashMap> database = getPlots(); - ArrayList toCreate = new ArrayList<>(); - for (Plot plot : toValidate) { - if (plot.temp == -1) { - continue; - } - if (plot.getArea() == null) { - LOGGER.error("CRITICAL ERROR IN VALIDATION TASK: {}", plot); - LOGGER.error("PLOT AREA CANNOT BE NULL! SKIPPING PLOT!"); - LOGGER.info("Delete this entry from your database or set `database-purger: true` in the settings.yml"); - continue; - } - if (database == null) { - LOGGER.error("CRITICAL ERROR IN VALIDATION TASK!"); - LOGGER.error("DATABASE VARIABLE CANNOT BE NULL! NOW ENDING VALIDATION!"); - break; - } - HashMap worldPlots = database.get(plot.getArea().toString()); - if (worldPlots == null) { - toCreate.add(plot); - continue; - } - Plot dataPlot = worldPlots.remove(plot.getId()); - if (dataPlot == null) { - toCreate.add(plot); - continue; - } - // owner - if (!plot.getOwnerAbs().equals(dataPlot.getOwnerAbs())) { - setOwner(plot, plot.getOwnerAbs()); - } - // trusted - if (!plot.getTrusted().equals(dataPlot.getTrusted())) { - HashSet toAdd = (HashSet) plot.getTrusted().clone(); - HashSet toRemove = (HashSet) dataPlot.getTrusted().clone(); - toRemove.removeAll(plot.getTrusted()); - toAdd.removeAll(dataPlot.getTrusted()); - if (!toRemove.isEmpty()) { - for (UUID uuid : toRemove) { - removeTrusted(plot, uuid); - } - } - if (!toAdd.isEmpty()) { - for (UUID uuid : toAdd) { - setTrusted(plot, uuid); - } - } - } - if (!plot.getMembers().equals(dataPlot.getMembers())) { - HashSet toAdd = (HashSet) plot.getMembers().clone(); - HashSet toRemove = (HashSet) dataPlot.getMembers().clone(); - toRemove.removeAll(plot.getMembers()); - toAdd.removeAll(dataPlot.getMembers()); - if (!toRemove.isEmpty()) { - for (UUID uuid : toRemove) { - removeMember(plot, uuid); - } - } - if (!toAdd.isEmpty()) { - for (UUID uuid : toAdd) { - setMember(plot, uuid); - } - } - } - if (!plot.getDenied().equals(dataPlot.getDenied())) { - HashSet toAdd = (HashSet) plot.getDenied().clone(); - HashSet toRemove = (HashSet) dataPlot.getDenied().clone(); - toRemove.removeAll(plot.getDenied()); - toAdd.removeAll(dataPlot.getDenied()); - if (!toRemove.isEmpty()) { - for (UUID uuid : toRemove) { - removeDenied(plot, uuid); - } - } - if (!toAdd.isEmpty()) { - for (UUID uuid : toAdd) { - setDenied(plot, uuid); - } - } - } - boolean[] pm = plot.getMerged(); - boolean[] dm = dataPlot.getMerged(); - if (pm[0] != dm[0] || pm[1] != dm[1]) { - setMerged(dataPlot, plot.getMerged()); - } - Set> pf = plot.getFlags(); - Set> df = dataPlot.getFlags(); - if (!pf.isEmpty() && !df.isEmpty()) { - if (pf.size() != df.size() || !StringMan - .isEqual(StringMan.joinOrdered(pf, ","), StringMan.joinOrdered(df, ","))) { - // setFlags(plot, pf); - // TODO: Re-implement - } - } - } - - for (Entry> entry : database.entrySet()) { - HashMap map = entry.getValue(); - if (!map.isEmpty()) { - for (Entry entry2 : map.entrySet()) { - // TODO implement this when sure safe" - } - } - } - commit(); - } - - @Override - public void replaceWorld( - final String oldWorld, final String newWorld, final PlotId min, - final PlotId max - ) { - addGlobalTask(() -> { - if (min == null) { - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot` SET `world` = ? WHERE `world` = ?")) { - stmt.setString(1, newWorld); - stmt.setString(2, oldWorld); - stmt.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - } - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster` SET `world` = ? WHERE `world` = ?")) { - stmt.setString(1, newWorld); - stmt.setString(2, oldWorld); - stmt.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - } - } else { - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot` SET `world` = ? WHERE `world` = ? AND `plot_id_x` BETWEEN ? AND ? AND `plot_id_z` BETWEEN ? AND ?")) { - stmt.setString(1, newWorld); - stmt.setString(2, oldWorld); - stmt.setInt(3, min.getX()); - stmt.setInt(4, max.getX()); - stmt.setInt(5, min.getY()); - stmt.setInt(6, max.getY()); - stmt.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - } - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster` SET `world` = ? WHERE `world` = ? AND `pos1_x` <= ? AND `pos1_z` <= ? AND `pos2_x` >= ? AND `pos2_z` >= ?")) { - stmt.setString(1, newWorld); - stmt.setString(2, oldWorld); - stmt.setInt(3, max.getX()); - stmt.setInt(4, max.getY()); - stmt.setInt(5, min.getX()); - stmt.setInt(6, min.getY()); - stmt.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - } - } - }); - } - - @Override - public void replaceUUID(final UUID old, final UUID now) { - addGlobalTask(() -> { - try (Statement stmt = SQLManager.this.connection.createStatement()) { - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "cluster` SET `owner` = '" + now - .toString() + "' WHERE `owner` = '" + old.toString() + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "cluster_helpers` SET `user_uuid` = '" - + now + "' WHERE `user_uuid` = '" + old + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "cluster_invited` SET `user_uuid` = '" - + now + "' WHERE `user_uuid` = '" + old + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "plot` SET `owner` = '" + now - + "' WHERE `owner` = '" + old + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "plot_denied` SET `user_uuid` = '" + now + "' WHERE `user_uuid` = '" + old + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "plot_helpers` SET `user_uuid` = '" + now + "' WHERE `user_uuid` = '" + old + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "plot_trusted` SET `user_uuid` = '" + now + "' WHERE `user_uuid` = '" + old + '\''); - } catch (SQLException e) { - e.printStackTrace(); - } - }); - } - - @Override - public void close() { - try { - this.closed = true; - this.connection.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - } - - private record LegacySettings( - int id, - PlotSettings settings - ) { - - } - - public abstract static class UniqueStatement { - - public final String method; - - public UniqueStatement(String method) { - this.method = method; - } - - public void addBatch(PreparedStatement statement) throws SQLException { - statement.addBatch(); - } - - public void execute(PreparedStatement statement) throws SQLException { - statement.executeBatch(); - } - - public abstract PreparedStatement get() throws SQLException; - - public abstract void set(PreparedStatement statement) throws SQLException; - - } - - private record UUIDPair(int id, UUID uuid) { - - } - -} diff --git a/Core/src/main/java/com/plotsquared/core/database/SQLite.java b/Core/src/main/java/com/plotsquared/core/database/SQLite.java deleted file mode 100644 index c34be4c59d..0000000000 --- a/Core/src/main/java/com/plotsquared/core/database/SQLite.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import com.plotsquared.core.PlotSquared; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.io.File; -import java.io.IOException; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -/** - * Connects to and uses a SQLite database. - */ -public class SQLite extends Database { - - private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + SQLite.class.getSimpleName()); - - private final String dbLocation; - private Connection connection; - - /** - * Creates a new SQLite instance - * - * @param dbLocation Location of the Database (Must end in .db) - */ - public SQLite(File dbLocation) { - this.dbLocation = dbLocation.getAbsolutePath(); - } - - @Override - public Connection openConnection() throws SQLException, ClassNotFoundException { - if (checkConnection()) { - return this.connection; - } - if (!PlotSquared.platform().getDirectory().exists()) { - PlotSquared.platform().getDirectory().mkdirs(); - } - File file = new File(this.dbLocation); - if (!file.exists()) { - try { - file.createNewFile(); - } catch (IOException ignored) { - LOGGER.error("Unable to create database"); - } - } - Class.forName("org.sqlite.JDBC"); - this.connection = DriverManager.getConnection("jdbc:sqlite:" + this.dbLocation); - return this.connection; - } - - @Override - public boolean checkConnection() throws SQLException { - return (this.connection != null) && !this.connection.isClosed(); - } - - @Override - public Connection getConnection() { - return this.connection; - } - - @Override - public boolean closeConnection() throws SQLException { - if (this.connection == null) { - return false; - } - this.connection.close(); - this.connection = null; - return true; - } - - @Override - public ResultSet querySQL(String query) throws SQLException, ClassNotFoundException { - if (checkConnection()) { - openConnection(); - } - try (Statement statement = this.connection.createStatement()) { - return statement.executeQuery(query); - } - } - - @Override - public int updateSQL(String query) throws SQLException, ClassNotFoundException { - if (checkConnection()) { - openConnection(); - } - try (Statement statement = this.connection.createStatement()) { - return statement.executeUpdate(query); - } - } - - @Override - public Connection forceConnection() throws SQLException, ClassNotFoundException { - Class.forName("org.sqlite.JDBC"); - this.connection = DriverManager.getConnection("jdbc:sqlite:" + this.dbLocation); - return this.connection; - } - -} diff --git a/Core/src/main/java/com/plotsquared/core/database/StmtMod.java b/Core/src/main/java/com/plotsquared/core/database/StmtMod.java deleted file mode 100644 index 2b31e4b3df..0000000000 --- a/Core/src/main/java/com/plotsquared/core/database/StmtMod.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import com.plotsquared.core.util.StringMan; - -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -public abstract class StmtMod { - - public abstract String getCreateMySQL(int size); - - public String getCreateMySQL(int size, String query, int params) { - StringBuilder statement = new StringBuilder(query); - for (int i = 0; i < size - 1; i++) { - statement.append('(').append(StringMan.repeat(",?", params).substring(1)).append("),"); - } - statement.append('(').append(StringMan.repeat(",?", params).substring(1)).append(')'); - return statement.toString(); - } - - public String getCreateSQLite(int size, String query, int params) { - String modParams = StringMan.repeat(",?", params).substring(1); - return IntStream.range(0, size - 1).mapToObj(i -> "UNION SELECT " + modParams + ' ') - .collect(Collectors.joining("", query, "")); - } - - public abstract String getCreateSQLite(int size); - - public abstract String getCreateSQL(); - - public abstract void setMySQL(PreparedStatement stmt, int i, T obj) throws SQLException; - - public abstract void setSQLite(PreparedStatement stmt, int i, T obj) throws SQLException; - - public abstract void setSQL(PreparedStatement stmt, T obj) throws SQLException; - -} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java b/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java new file mode 100644 index 0000000000..568fc33c0f --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/DataSourceProvider.java @@ -0,0 +1,90 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.config; + +import com.google.inject.Singleton; +import com.plotsquared.core.configuration.Storage; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; + +import javax.sql.DataSource; + +/** + * Provides configured DataSource instances for database connections. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +@Singleton +public final class DataSourceProvider { + + /** + * Creates a DataSource based on current storage configuration. + */ + public DataSource createDataSource() { + HikariConfig config = new HikariConfig(); + + if (Storage.MySQL.USE) { + String url = "jdbc:mysql://" + Storage.MySQL.HOST + ":" + Storage.MySQL.PORT + "/" + Storage.MySQL.DATABASE + + "?" + String.join("&", Storage.MySQL.PROPERTIES); + config.setJdbcUrl(url); + config.setUsername(Storage.MySQL.USER); + config.setPassword(Storage.MySQL.PASSWORD); + config.setDriverClassName("com.mysql.cj.jdbc.Driver"); + } else if (Storage.H2.USE) { + String url = switch (Storage.H2.MODE.toUpperCase()) { + case "MEMORY" -> "jdbc:h2:mem:" + Storage.H2.DB; + case "SERVER" -> "jdbc:h2:tcp://localhost/" + Storage.H2.DB; + default -> "jdbc:h2:file:./" + Storage.H2.DB; + }; + if (!Storage.H2.PROPERTIES.isEmpty()) { + url += ";" + String.join(";", Storage.H2.PROPERTIES); + } + config.setJdbcUrl(url); + config.setDriverClassName("org.h2.Driver"); + } + + config.setMaximumPoolSize(10); + config.setMinimumIdle(2); + config.setConnectionTimeout(30000); + config.setIdleTimeout(600000); + config.setLeakDetectionThreshold(60000); + + return new HikariDataSource(config); + } + + /** + * Creates a DataSource for a specific database configuration (used for migration between databases). + */ + public DataSource createDataSource(String jdbcUrl, String username, String password, String driverClass) { + HikariConfig config = new HikariConfig(); + config.setJdbcUrl(jdbcUrl); + if (username != null) config.setUsername(username); + if (password != null) config.setPassword(password); + config.setDriverClassName(driverClass); + + config.setMaximumPoolSize(5); + config.setMinimumIdle(1); + config.setConnectionTimeout(30000); + + return new HikariDataSource(config); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/InstallationState.java b/Core/src/main/java/com/plotsquared/core/persistence/config/InstallationState.java new file mode 100644 index 0000000000..7db02a3592 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/InstallationState.java @@ -0,0 +1,36 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.config; + +enum InstallationState { + FRESH_INSTALLATION("Fresh installation with no prior data"), + UPGRADE_FROM_V7("Upgrade from version 7.x"), + UPGRADE_FROM_V8("Upgrade from version 8.x"), + NO_MIGRATION_NEEDED("No migration needed, already on latest version"); + + private final String description; + + InstallationState(final String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java new file mode 100644 index 0000000000..793bb64dae --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/JpaPropertiesProvider.java @@ -0,0 +1,76 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.config; + +import com.google.inject.Singleton; +import com.plotsquared.core.configuration.Storage; + +import java.util.HashMap; +import java.util.Map; + +/** + * Builds JPA/Hibernate properties based on Storage configuration. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +@Singleton +public final class JpaPropertiesProvider { + + /** + * Create a map of JPA properties suitable for EntityManagerFactory creation. + */ + public Map getProperties() { + Map props = new HashMap<>(); + + if (Storage.MySQL.USE) { + String url = "jdbc:mysql://" + Storage.MySQL.HOST + ":" + Storage.MySQL.PORT + "/" + Storage.MySQL.DATABASE + + "?" + String.join("&", Storage.MySQL.PROPERTIES); + props.put("jakarta.persistence.jdbc.url", url); + props.put("jakarta.persistence.jdbc.user", Storage.MySQL.USER); + props.put("jakarta.persistence.jdbc.password", Storage.MySQL.PASSWORD); + props.put("jakarta.persistence.jdbc.driver", "com.mysql.cj.jdbc.Driver"); + props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); + } else if (Storage.H2.USE) { + String url = switch (Storage.H2.MODE.toUpperCase()) { + case "MEMORY" -> "jdbc:h2:mem:" + Storage.H2.DB; + case "SERVER" -> "jdbc:h2:tcp://localhost/" + Storage.H2.DB; + default -> "jdbc:h2:file:./" + Storage.H2.DB; + }; + if (!Storage.H2.PROPERTIES.isEmpty()) { + url += ";" + String.join(";", Storage.H2.PROPERTIES); + } + props.put("jakarta.persistence.jdbc.url", url); + props.put("jakarta.persistence.jdbc.driver", "org.h2.Driver"); + props.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); + } + + // Schema is managed by Liquibase; only validate with Hibernate + props.put("hibernate.hbm2ddl.auto", "validate"); + props.put("hibernate.show_sql", false); + props.put("hibernate.format_sql", false); + + // Apply dynamic table prefixing + props.put("hibernate.physical_naming_strategy", new PrefixedNamingStrategy(Storage.PREFIX)); + + return props; + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java new file mode 100644 index 0000000000..f63fa342a7 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseBootstrap.java @@ -0,0 +1,81 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.config; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.plotsquared.core.configuration.Storage; +import liquibase.Contexts; +import liquibase.LabelExpression; +import liquibase.Liquibase; +import liquibase.database.Database; +import liquibase.database.DatabaseFactory; +import liquibase.database.jvm.JdbcConnection; +import liquibase.resource.ClassLoaderResourceAccessor; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.util.logging.Logger; + +/** + * Eager bootstrap that executes Liquibase migrations during application startup. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +@Singleton +public final class LiquibaseBootstrap { + private static final Logger LOGGER = Logger.getLogger(LiquibaseBootstrap.class.getName()); + + @Inject + public LiquibaseBootstrap(DataSource dataSource) { + syncThreadForServiceLoader(() -> { + try (Connection connection = dataSource.getConnection()) { + Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection)); + + // Run Liquibase migrations - this will handle both v7->v8 migration and new v8 installations + Liquibase liquibase = new Liquibase("db/changelog/db.changelog-master.xml", + new ClassLoaderResourceAccessor(), database); + + liquibase.setChangeLogParameter("PREFIX", Storage.PREFIX == null ? "" : Storage.PREFIX); + liquibase.setChangeLogParameter("prefix", Storage.PREFIX == null ? "" : Storage.PREFIX); + + liquibase.update(new Contexts(), new LabelExpression()); + LOGGER.info("Liquibase migration completed successfully."); + + } catch (Exception e) { + LOGGER.severe("Liquibase migration failed: " + e.getMessage()); + } + }); + } + + void syncThreadForServiceLoader(Runnable runnable) { + Thread currentThread = Thread.currentThread(); + ClassLoader originalClassLoader = currentThread.getContextClassLoader(); + ClassLoader pluginClassLoader = this.getClass().getClassLoader(); + try { + currentThread.setContextClassLoader(pluginClassLoader); + runnable.run(); + } finally { + currentThread.setContextClassLoader(originalClassLoader); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java new file mode 100644 index 0000000000..b5f1c32860 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/LiquibaseCrossDatabaseMigrationService.java @@ -0,0 +1,207 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.config; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.plotsquared.core.configuration.Storage; +import liquibase.Contexts; +import liquibase.LabelExpression; +import liquibase.Liquibase; +import liquibase.database.Database; +import liquibase.database.DatabaseFactory; +import liquibase.database.jvm.JdbcConnection; +import liquibase.diff.DiffGeneratorFactory; +import liquibase.diff.DiffResult; +import liquibase.diff.compare.CompareControl; +import liquibase.diff.output.DiffOutputControl; +import liquibase.diff.output.changelog.DiffToChangeLog; +import liquibase.resource.ClassLoaderResourceAccessor; +import liquibase.snapshot.DatabaseSnapshot; + +import javax.sql.DataSource; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.Connection; +import java.util.logging.Logger; + +/** + * Service for handling cross-database migrations using pure Liquibase functionality. + * Uses Liquibase's native generateChangeLog and diffChangeLog capabilities. + * + * @since 8.0.0 + * @version 2.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +@Singleton +public final class LiquibaseCrossDatabaseMigrationService { + private static final Logger LOGGER = Logger.getLogger(LiquibaseCrossDatabaseMigrationService.class.getName()); + + private final DataSourceProvider dataSourceProvider; + + @Inject + public LiquibaseCrossDatabaseMigrationService(DataSourceProvider dataSourceProvider) { + this.dataSourceProvider = dataSourceProvider; + } + + /** + * Migrates from current database to MySQL using Liquibase's native capabilities. + */ + public void migrateToMySQL() { + LOGGER.info("Starting pure Liquibase migration to MySQL..."); + + if (!Storage.MySQL.USE) { + throw new IllegalStateException("MySQL is not configured. Please configure MySQL settings in the config file first."); + } + + try { + // Create MySQL datasource using config settings + String mysqlUrl = "jdbc:mysql://" + Storage.MySQL.HOST + ":" + Storage.MySQL.PORT + "/" + Storage.MySQL.DATABASE + + "?" + String.join("&", Storage.MySQL.PROPERTIES) + "&createDatabaseIfNotExist=true"; + DataSource targetDataSource = dataSourceProvider.createDataSource(mysqlUrl, Storage.MySQL.USER, Storage.MySQL.PASSWORD, "com.mysql.cj.jdbc.Driver"); + + // Get current datasource + DataSource sourceDataSource = dataSourceProvider.createDataSource(); + + // Perform migration using pure Liquibase + migrateUsingLiquibaseNative(sourceDataSource, targetDataSource); + + LOGGER.info("Migration to MySQL completed successfully."); + + } catch (Exception e) { + LOGGER.severe("Migration to MySQL failed: " + e.getMessage()); + e.printStackTrace(); + throw new RuntimeException("Migration to MySQL failed", e); + } + } + + /** + * Migrates from current database to H2 using Liquibase's native capabilities. + */ + public void migrateToH2() { + LOGGER.info("Starting pure Liquibase migration to H2..."); + + if (!Storage.H2.USE) { + throw new IllegalStateException("H2 is not configured. Please configure H2 settings in the config file first."); + } + + try { + // Create H2 datasource using config settings + String h2Url = "jdbc:h2:file:./" + Storage.H2.DB; + if (!Storage.H2.PROPERTIES.isEmpty()) { + h2Url += ";" + String.join(";", Storage.H2.PROPERTIES); + } + DataSource targetDataSource = dataSourceProvider.createDataSource(h2Url, null, null, "org.h2.Driver"); + + // Get current datasource + DataSource sourceDataSource = dataSourceProvider.createDataSource(); + + // Perform migration using pure Liquibase + migrateUsingLiquibaseNative(sourceDataSource, targetDataSource); + + LOGGER.info("Migration to H2 completed successfully."); + + } catch (Exception e) { + LOGGER.severe("Migration to H2 failed: " + e.getMessage()); + e.printStackTrace(); + throw new RuntimeException("Migration to H2 failed", e); + } + } + + /** + * Performs the actual migration using Liquibase's native generateChangeLog functionality. + * This approach eliminates the need for CSV export/import and uses pure Liquibase operations. + */ + private void migrateUsingLiquibaseNative(DataSource sourceDataSource, DataSource targetDataSource) throws Exception { + // Create temporary file for the generated changelog + Path tempChangelog = Files.createTempFile(Path.of(""),"plotsquared-migration-", ".xml"); + + try (Connection sourceConnection = sourceDataSource.getConnection(); + Connection targetConnection = targetDataSource.getConnection()) { + + Database sourceDatabase = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(sourceConnection)); + Database targetDatabase = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(targetConnection)); + + // Step 1: Create the target schema structure first + LOGGER.info("Creating target database schema..."); + Liquibase schemaLiquibase = new Liquibase("db/changelog/db.changelog-master.xml", + new ClassLoaderResourceAccessor(), targetDatabase); + schemaLiquibase.update(new Contexts(), new LabelExpression()); + + // Step 2: Generate changelog with data from source database + LOGGER.info("Generating changelog with data from source database..."); + generateDataChangeLog(sourceDatabase, tempChangelog); + + // Step 3: Apply the data changelog to target database + LOGGER.info("Applying data to target database..."); + Liquibase dataLiquibase = new Liquibase(tempChangelog.toString(), + new ClassLoaderResourceAccessor(), targetDatabase); + dataLiquibase.setChangeLogParameter("PREFIX", Storage.PREFIX == null ? "" : Storage.PREFIX); + dataLiquibase.setChangeLogParameter("prefix", Storage.PREFIX == null ? "" : Storage.PREFIX); + + dataLiquibase.update(new Contexts(), new LabelExpression()); + + LOGGER.info("Pure Liquibase migration completed successfully."); + + } finally { + // Cleanup temporary file + try { + Files.deleteIfExists(tempChangelog); + } catch (Exception e) { + LOGGER.warning("Could not delete temporary changelog file: " + e.getMessage()); + } + } + } + + /** + * Generates a Liquibase changelog with data using Liquibase's native capabilities. + */ + private void generateDataChangeLog(Database sourceDatabase, Path outputFile) throws Exception { + // This uses Liquibase's built-in generateChangeLog with data option + generateChangeLogUsingDiff(sourceDatabase, sourceDatabase, outputFile); + } + + /** + * Alternative approach using Liquibase's diff functionality for more control. + */ + private void generateChangeLogUsingDiff(Database sourceDatabase, Database targetDatabase, Path outputFile) throws Exception { + try (PrintStream output = new PrintStream(Files.newOutputStream(outputFile))) { + + // Create database snapshots + DatabaseSnapshot sourceSnapshot = liquibase.snapshot.SnapshotGeneratorFactory.getInstance() + .createSnapshot(sourceDatabase.getDefaultSchema(), sourceDatabase, new liquibase.snapshot.SnapshotControl(sourceDatabase)); + + DatabaseSnapshot targetSnapshot = liquibase.snapshot.SnapshotGeneratorFactory.getInstance() + .createSnapshot(targetDatabase.getDefaultSchema(), targetDatabase, new liquibase.snapshot.SnapshotControl(targetDatabase)); + + // Compare databases + DiffResult diffResult = DiffGeneratorFactory.getInstance().compare(sourceSnapshot, targetSnapshot, new CompareControl()); + + // Generate changelog from diff + DiffToChangeLog changeLogWriter = new DiffToChangeLog(diffResult, new DiffOutputControl(true, true, true, null)); + changeLogWriter.print(output); + + } catch (Exception e) { + LOGGER.severe("Failed to generate changelog using diff: " + e.getMessage()); + throw e; + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java new file mode 100644 index 0000000000..ed124dca2c --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PersistenceModule.java @@ -0,0 +1,125 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.config; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.plotsquared.core.persistence.repository.api.ClusterHelperRepository; +import com.plotsquared.core.persistence.repository.api.ClusterInvitedRepository; +import com.plotsquared.core.persistence.repository.api.ClusterRepository; +import com.plotsquared.core.persistence.repository.api.ClusterSettingsRepository; +import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; +import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; +import com.plotsquared.core.persistence.repository.api.PlotDeniedRepository; +import com.plotsquared.core.persistence.repository.api.PlotFlagRepository; +import com.plotsquared.core.persistence.repository.api.PlotMembershipRepository; +import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.persistence.repository.api.PlotSettingsRepository; +import com.plotsquared.core.persistence.repository.api.PlotTrustedRepository; +import com.plotsquared.core.persistence.repository.api.PlotRatingRepository; +import com.plotsquared.core.persistence.repository.jpa.ClusterHelperRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.ClusterInvitedRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.ClusterRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.ClusterSettingsRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlayerMetaRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotCommentRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotDeniedRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotFlagRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotMembershipRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotSettingsRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotTrustedRepositoryJpa; +import com.plotsquared.core.persistence.repository.jpa.PlotRatingRepositoryJpa; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import org.hibernate.jpa.HibernatePersistenceProvider; + +import javax.sql.DataSource; +import java.util.Map; +import java.util.function.Supplier; + +/** + * Guice module for configuring persistence-related bindings and providers. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public final class PersistenceModule extends AbstractModule { + + @Override + protected void configure() { + // Bind repository interfaces to JPA implementations + bind(PlotRepository.class).to(PlotRepositoryJpa.class); + bind(PlotFlagRepository.class).to(PlotFlagRepositoryJpa.class); + bind(PlotCommentRepository.class).to(PlotCommentRepositoryJpa.class); + bind(PlotRatingRepository.class).to(PlotRatingRepositoryJpa.class); + bind(PlayerMetaRepository.class).to(PlayerMetaRepositoryJpa.class); + bind(PlotSettingsRepository.class).to(PlotSettingsRepositoryJpa.class); + bind(PlotMembershipRepository.class).to(PlotMembershipRepositoryJpa.class); + bind(PlotTrustedRepository.class).to(PlotTrustedRepositoryJpa.class); + bind(PlotDeniedRepository.class).to(PlotDeniedRepositoryJpa.class); + bind(ClusterRepository.class).to(ClusterRepositoryJpa.class); + bind(ClusterHelperRepository.class).to(ClusterHelperRepositoryJpa.class); + bind(ClusterInvitedRepository.class).to(ClusterInvitedRepositoryJpa.class); + bind(ClusterSettingsRepository.class).to(ClusterSettingsRepositoryJpa.class); + + // Bind configuration and migration services + bind(JpaPropertiesProvider.class).asEagerSingleton(); + bind(DataSourceProvider.class).asEagerSingleton(); + bind(LiquibaseCrossDatabaseMigrationService.class).asEagerSingleton(); + + // Eagerly run Liquibase migrations on startup + bind(LiquibaseBootstrap.class).asEagerSingleton(); + } + + @Provides + @Singleton + DataSource provideDataSource(DataSourceProvider dataSourceProvider) { + return dataSourceProvider.createDataSource(); + } + + @Provides + @Singleton + EntityManagerFactory provideEmf(JpaPropertiesProvider jpaPropertiesProvider, DataSource ds, LiquibaseBootstrap liquibaseBootstrap) { + Map props = jpaPropertiesProvider.getProperties(); + props.put("jakarta.persistence.nonJtaDataSource", ds); + return syncThreadForServiceLoader(() -> new HibernatePersistenceProvider().createEntityManagerFactory("plotsquaredPU", + props)); + } + + @Provides + EntityManager provideEm(EntityManagerFactory emf) { + return emf.createEntityManager(); + } + + private T syncThreadForServiceLoader(Supplier supplier) { + Thread currentThread = Thread.currentThread(); + ClassLoader originalClassLoader = currentThread.getContextClassLoader(); + ClassLoader pluginClassLoader = this.getClass().getClassLoader(); + try { + currentThread.setContextClassLoader(pluginClassLoader); + return supplier.get(); + } finally { + currentThread.setContextClassLoader(originalClassLoader); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java b/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java new file mode 100644 index 0000000000..ebfed8e74d --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/config/PrefixedNamingStrategy.java @@ -0,0 +1,83 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.config; + +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.naming.PhysicalNamingStrategy; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.jetbrains.annotations.NotNull; + +/** + * A PhysicalNamingStrategy that adds a specified prefix to all table names. + * This is useful for avoiding naming conflicts in shared databases. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public final class PrefixedNamingStrategy implements PhysicalNamingStrategy { + + private final String prefix; + + public PrefixedNamingStrategy(@NotNull String prefix) { + this.prefix = prefix; + } + + @Override + public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment env) { + if (name == null) { + return null; + } + return Identifier.toIdentifier((prefix + name.getText()).toUpperCase(), name.isQuoted()); + } + + @Override + public Identifier toPhysicalCatalogName(Identifier n, JdbcEnvironment e) { + if (n == null) { + return null; + } + return Identifier.toIdentifier(n.getText().toUpperCase()); + } + + @Override + public Identifier toPhysicalSchemaName(Identifier n, JdbcEnvironment e) { + if (n == null) { + return null; + } + return Identifier.toIdentifier(n.getText().toUpperCase()); + } + + @Override + public Identifier toPhysicalSequenceName(Identifier n, JdbcEnvironment e) { + if (n == null) { + return null; + } + return Identifier.toIdentifier(n.getText().toUpperCase()); + } + + @Override + public Identifier toPhysicalColumnName(Identifier n, JdbcEnvironment e) { + if (n == null) { + return null; + } + return Identifier.toIdentifier(n.getText().toUpperCase()); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java new file mode 100644 index 0000000000..bc5337753e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterEntity.java @@ -0,0 +1,73 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +import java.sql.Timestamp; + +@Entity +@Table(name = "cluster") +@NamedQueries({ + @NamedQuery(name = "Cluster.findByWorldAndBounds", query = "SELECT c FROM ClusterEntity c WHERE c.world = :world AND c" + + ".pos1X <= :x AND c.pos2X >= :x AND c.pos1Z <= :z AND c.pos2Z >= :z"), + @NamedQuery(name = "Cluster.findByWorld", query = "SELECT c FROM ClusterEntity c WHERE c.world = :world"), + @NamedQuery(name = "Cluster.finaAll", query = "SELECT c FROM ClusterEntity c"), + @NamedQuery(name = "Cluster.updateWorld", query = "UPDATE ClusterEntity c SET c.world = :newWorld WHERE c.world = :oldWorld"), + @NamedQuery(name = "Cluster.updateWorldInBounds", query = "UPDATE ClusterEntity c SET c.world = :newWorld WHERE c.world = :oldWorld AND c.pos1X <= :maxX AND c.pos1Z <= :maxZ AND c.pos2X >= :minX AND c.pos2Z >= :minZ") +}) +public class ClusterEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "pos1_x") private int pos1X; + @Column(name = "pos1_z") private int pos1Z; + @Column(name = "pos2_x") private int pos2X; + @Column(name = "pos2_z") private int pos2Z; + @Column(length = 40) private String owner; + @Column(length = 45) private String world; + @Column(name = "timestamp", insertable = false, updatable = false) + private Timestamp timestamp; + + public ClusterEntity() {} + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + public int getPos1X() { return pos1X; } + public void setPos1X(int pos1X) { this.pos1X = pos1X; } + public int getPos1Z() { return pos1Z; } + public void setPos1Z(int pos1Z) { this.pos1Z = pos1Z; } + public int getPos2X() { return pos2X; } + public void setPos2X(int pos2X) { this.pos2X = pos2X; } + public int getPos2Z() { return pos2Z; } + public void setPos2Z(int pos2Z) { this.pos2Z = pos2Z; } + public String getOwner() { return owner; } + public void setOwner(String owner) { this.owner = owner; } + public String getWorld() { return world; } + public void setWorld(String world) { this.world = world; } + public java.sql.Timestamp getTimestamp() { return timestamp; } + public void setTimestamp(Timestamp timestamp) { this.timestamp = timestamp; } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterHelperEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterHelperEntity.java new file mode 100644 index 0000000000..80b58decba --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterHelperEntity.java @@ -0,0 +1,50 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "cluster_helpers") +@IdClass(ClusterUserId.class) +@NamedQueries({ + @NamedQuery(name = "ClusterHelper.delete", query = "DELETE FROM ClusterHelperEntity e WHERE e.clusterId = :clusterId AND e.userUuid = :uuid"), + @NamedQuery(name = "ClusterHelper.findUsers", query = "SELECT e.userUuid FROM ClusterHelperEntity e WHERE e.clusterId = :clusterId") +}) +public class ClusterHelperEntity { + @Id + @Column(name = "cluster_id") + private Long clusterId; + @Id + @Column(name = "user_uuid", length = 40) + private String userUuid; + + public ClusterHelperEntity() {} + + public Long getClusterId() { return clusterId; } + public void setClusterId(Long clusterId) { this.clusterId = clusterId; } + public String getUserUuid() { return userUuid; } + public void setUserUuid(String userUuid) { this.userUuid = userUuid; } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterInvitedEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterInvitedEntity.java new file mode 100644 index 0000000000..dfd6f902ca --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterInvitedEntity.java @@ -0,0 +1,50 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "cluster_invited") +@IdClass(ClusterUserId.class) +@NamedQueries({ + @NamedQuery(name = "ClusterInvited.delete", query = "DELETE FROM ClusterInvitedEntity e WHERE e.clusterId = :clusterId AND e.userUuid = :uuid"), + @NamedQuery(name = "ClusterInvited.findUsers", query = "SELECT e.userUuid FROM ClusterInvitedEntity e WHERE e.clusterId = :clusterId") +}) +public class ClusterInvitedEntity { + @Id + @Column(name = "cluster_id") + private Long clusterId; + @Id + @Column(name = "user_uuid", length = 40) + private String userUuid; + + public ClusterInvitedEntity() {} + + public Long getClusterId() { return clusterId; } + public void setClusterId(Long clusterId) { this.clusterId = clusterId; } + public String getUserUuid() { return userUuid; } + public void setUserUuid(String userUuid) { this.userUuid = userUuid; } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java new file mode 100644 index 0000000000..b08c3f24bd --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterSettingsEntity.java @@ -0,0 +1,143 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.MapsId; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; + +@Entity +@Table(name = "cluster_settings") +@jakarta.persistence.NamedQueries({ + @jakarta.persistence.NamedQuery(name = "ClusterSettings.updatePosition", query = "UPDATE ClusterSettingsEntity s SET s.position = :pos WHERE s.id = :clusterId") +}) +public class ClusterSettingsEntity { + @Id + @Column(name = "cluster_id") + private Long id; + + @OneToOne + @MapsId + @JoinColumn(name = "cluster_id") + private ClusterEntity cluster; + + @Column(length = 45) + private String biome; + @Column(name = "rain") + private Integer rain; + @Column(name = "custom_time") + private Boolean customTime; + @Column(name = "time") + private Integer time; + @Column(name = "deny_entry") + private Boolean denyEntry; + @Column(length = 50) + private String alias; + @Column(name = "merged") + private Integer merged; + @Column(length = 50) + private String position; + + public ClusterSettingsEntity() { + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public ClusterEntity getCluster() { + return cluster; + } + + public void setCluster(ClusterEntity cluster) { + this.cluster = cluster; + } + + public String getBiome() { + return biome; + } + + public void setBiome(String biome) { + this.biome = biome; + } + + public Integer getRain() { + return rain; + } + + public void setRain(Integer rain) { + this.rain = rain; + } + + public Boolean getCustomTime() { + return customTime; + } + + public void setCustomTime(Boolean customTime) { + this.customTime = customTime; + } + + public Integer getTime() { + return time; + } + + public void setTime(Integer time) { + this.time = time; + } + + public Boolean getDenyEntry() { + return denyEntry; + } + + public void setDenyEntry(Boolean denyEntry) { + this.denyEntry = denyEntry; + } + + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public Integer getMerged() { + return merged; + } + + public void setMerged(Integer merged) { + this.merged = merged; + } + + public String getPosition() { + return position; + } + + public void setPosition(String position) { + this.position = position; + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterUserId.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterUserId.java new file mode 100644 index 0000000000..7527cbaf4c --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/ClusterUserId.java @@ -0,0 +1,52 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import java.io.Serializable; +import java.util.Objects; + +public class ClusterUserId implements Serializable { + private Long clusterId; + private String userUuid; + + public ClusterUserId() {} + + public ClusterUserId(Long clusterId, String userUuid) { + this.clusterId = clusterId; + this.userUuid = userUuid; + } + + public Long getClusterId() { return clusterId; } + public void setClusterId(Long clusterId) { this.clusterId = clusterId; } + public String getUserUuid() { return userUuid; } + public void setUserUuid(String userUuid) { this.userUuid = userUuid; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ClusterUserId that = (ClusterUserId) o; + return Objects.equals(clusterId, that.clusterId) && Objects.equals(userUuid, that.userUuid); + } + + @Override + public int hashCode() { + return Objects.hash(clusterId, userUuid); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java new file mode 100644 index 0000000000..9c6e7b7ace --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlayerMetaEntity.java @@ -0,0 +1,60 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "player_meta") +@NamedQueries({ + @NamedQuery(name = "PlayerMeta.findByUuid", query = "SELECT m FROM PlayerMetaEntity m WHERE m.uuid = :uuid"), + @NamedQuery(name = "PlayerMeta.deleteByUuidAndKey", query = "DELETE FROM PlayerMetaEntity m WHERE m.uuid = :uuid AND m.key = :key") +}) +public class PlayerMetaEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "meta_id") + private Long id; + @Column(length = 40, nullable = false) + private String uuid; + @Column(name = "playerMetaKey", length = 32, nullable = false) + private String key; + @Lob + @Column(name = "playerMetaValue", nullable = false) + private byte[] playerMetaValue; + + public PlayerMetaEntity() {} + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + public String getUuid() { return uuid; } + public void setUuid(String uuid) { this.uuid = uuid; } + public String getKey() { return key; } + public void setKey(String key) { this.key = key; } + public byte[] getPlayerMetaValue() { return playerMetaValue; } + public void setPlayerMetaValue(byte[] value) { this.playerMetaValue = value; } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java new file mode 100644 index 0000000000..aeb3ab3a0d --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentEntity.java @@ -0,0 +1,70 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "plot_comments") +@IdClass(PlotCommentId.class) +@NamedQueries({ + @NamedQuery(name = "PlotComment.findByWorldAndInbox", query = "SELECT c FROM PlotCommentEntity c WHERE c.world = :world AND c.inbox = :inbox ORDER BY c.timestamp DESC"), + @NamedQuery(name = "PlotComment.findByWorldHashAndInbox", query = "SELECT c FROM PlotCommentEntity c WHERE c.world = :world AND c.hashcode = :hash AND c.inbox = :inbox ORDER BY c.timestamp DESC"), + @NamedQuery(name = "PlotComment.deleteOne", query = "DELETE FROM PlotCommentEntity c WHERE c.world = :world AND c.hashcode = :hash AND c.inbox = :inbox AND c.sender = :sender AND c.comment = :comment"), + @NamedQuery(name = "PlotComment.clearInbox", query = "DELETE FROM PlotCommentEntity c WHERE c.world = :world AND c.inbox = :inbox"), + @NamedQuery(name = "PlotComment.clearInboxByWorldHash", query = "DELETE FROM PlotCommentEntity c WHERE c.world = :world AND c.hashcode = :hash AND c.inbox = :inbox"), + @NamedQuery(name = "PlotComment.deleteByWorldAndHash", query = "DELETE FROM PlotCommentEntity c WHERE c.world = :world AND c.hashcode = :hash") +}) +public class PlotCommentEntity { + @Id + @Column(length = 40) + private String world; + @Id @Column(name = "hashcode") + private Integer hashcode; + @Id @Column(length = 40) + private String inbox; + + @Column(length = 40, nullable = false) + private String comment; + @Column(name = "timestamp", nullable = false) + private Integer timestamp; + @Column(length = 40, nullable = false) + private String sender; + + public PlotCommentEntity() {} + + public String getWorld() { return world; } + public void setWorld(String world) { this.world = world; } + public Integer getHashcode() { return hashcode; } + public void setHashcode(Integer hashcode) { this.hashcode = hashcode; } + public String getInbox() { return inbox; } + public void setInbox(String inbox) { this.inbox = inbox; } + public String getComment() { return comment; } + public void setComment(String comment) { this.comment = comment; } + public Integer getTimestamp() { return timestamp; } + public void setTimestamp(Integer timestamp) { this.timestamp = timestamp; } + public String getSender() { return sender; } + public void setSender(String sender) { this.sender = sender; } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentId.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentId.java new file mode 100644 index 0000000000..175baf32d2 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotCommentId.java @@ -0,0 +1,56 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import java.io.Serializable; +import java.util.Objects; + +public class PlotCommentId implements Serializable { + private String world; + private Integer hashcode; + private String inbox; + + public PlotCommentId() {} + + public PlotCommentId(String world, Integer hashcode, String inbox) { + this.world = world; + this.hashcode = hashcode; + this.inbox = inbox; + } + + public String getWorld() { return world; } + public void setWorld(String world) { this.world = world; } + public Integer getHashcode() { return hashcode; } + public void setHashcode(Integer hashcode) { this.hashcode = hashcode; } + public String getInbox() { return inbox; } + public void setInbox(String inbox) { this.inbox = inbox; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PlotCommentId that = (PlotCommentId) o; + return Objects.equals(world, that.world) && Objects.equals(hashcode, that.hashcode) && Objects.equals(inbox, that.inbox); + } + + @Override + public int hashCode() { + return Objects.hash(world, hashcode, inbox); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java new file mode 100644 index 0000000000..bba252957a --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotDeniedEntity.java @@ -0,0 +1,53 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "plot_denied") +@IdClass(PlotUserId.class) +@NamedQueries({ + @NamedQuery(name = "PlotDenied.delete", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId AND e.userUuid = :uuid"), + @NamedQuery(name = "PlotDenied.findUsers", query = "SELECT e.userUuid FROM PlotDeniedEntity e WHERE e.plotId = :plotId"), + @NamedQuery(name = "PlotDenied.deleteAll", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId"), + @NamedQuery(name = "PlotDenied.deleteByPlotId", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId = :plotId"), + @NamedQuery(name = "PlotDenied.findAll", query = "SELECT e FROM PlotDeniedEntity e"), + @NamedQuery(name = "PlotDenied.deleteAllInPlotIds", query = "DELETE FROM PlotDeniedEntity e WHERE e.plotId IN :plotIds") +}) +public class PlotDeniedEntity { + @Id + @Column(name = "plot_plot_id") + private Long plotId; + @Id @Column(name = "user_uuid", length = 40) + private String userUuid; + + public PlotDeniedEntity() {} + + public Long getPlotId() { return plotId; } + public void setPlotId(Long plotId) { this.plotId = plotId; } + public String getUserUuid() { return userUuid; } + public void setUserUuid(String userUuid) { this.userUuid = userUuid; } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java new file mode 100644 index 0000000000..e6d17e93bc --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotEntity.java @@ -0,0 +1,133 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; + +@Entity +@Table(name = "plot") +@NamedQueries({ + @NamedQuery(name = "Plot.findAll", query = "SELECT p FROM PlotEntity p"), + @NamedQuery(name = "Plot.findByWorldAndId", query = "SELECT p FROM PlotEntity p WHERE p.world = :world AND p.plotIdX = :x AND p.plotIdZ = :z"), + @NamedQuery(name = "Plot.findByOwner", query = "SELECT p FROM PlotEntity p WHERE p.owner = :owner"), + @NamedQuery(name = "Plot.findByWorld", query = "SELECT p FROM PlotEntity p WHERE p.world = :world"), + @NamedQuery( + name = "Plot.updateXANDZ", + query = "UPDATE PlotEntity p SET p.plotIdX = :x, p.plotIdZ = :z WHERE p.id = :id" + ), + @NamedQuery(name = "Plot.findByXAndZAndWorld", query = "SELECT p FROM PlotEntity p WHERE p.plotIdX = :x AND p.plotIdZ = :z AND " + + "world = :world order by timestamp asc "), + @NamedQuery( + name = "Plot.movePlot", + query = "UPDATE PlotEntity p SET p.plotIdX = :plotIdX, p.plotIdZ = :plotIdZ, p.world = :world WHERE p.id = :id" + ), + @NamedQuery(name = "Plot.setOwner", query = "UPDATE PlotEntity p SET p.owner = :owner WHERE p.world = :world AND p.plotIdX = :x AND p.plotIdZ = :z"), + @NamedQuery(name = "Plot.replaceWorldInBounds", query = "UPDATE PlotEntity p SET p.world = :newWorld WHERE p.world = " + + ":oldWorld AND p.plotIdX BETWEEN :minX AND :maxX AND p.plotIdZ BETWEEN :minZ AND :maxZ"), + @NamedQuery(name = "Plot.replaceWorldAll", query = "UPDATE PlotEntity p SET p.world = :newWorld WHERE p.world = " + + ":oldWorld"), + @NamedQuery(name = "Plot.deleteAllInIds", query = "DELETE FROM PlotEntity p WHERE p.id IN :ids"), +}) +public class PlotEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "plot_id_x", nullable = false) + private int plotIdX; + @Column(name = "plot_id_z", nullable = false) + private int plotIdZ; + @Column(length = 40, nullable = false) + private String owner; + @Column(length = 45, nullable = false) + private String world; + @Column(name = "timestamp", insertable = false, updatable = false) + private java.sql.Timestamp timestamp; + + @OneToOne(mappedBy = "plot", cascade = CascadeType.ALL, optional = true, fetch = FetchType.LAZY) + private PlotSettingsEntity settings; + + public PlotEntity() { + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public int getPlotIdX() { + return plotIdX; + } + + public void setPlotIdX(int plotIdX) { + this.plotIdX = plotIdX; + } + + public int getPlotIdZ() { + return plotIdZ; + } + + public void setPlotIdZ(int plotIdZ) { + this.plotIdZ = plotIdZ; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public String getWorld() { + return world; + } + + public void setWorld(String world) { + this.world = world; + } + + public java.sql.Timestamp getTimestamp() { + return timestamp; + } + + public void setTimestamp(java.sql.Timestamp timestamp) { + this.timestamp = timestamp; + } + + public PlotSettingsEntity getSettings() { + return settings; + } + + public void setSettings(PlotSettingsEntity settings) { + this.settings = settings; + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java new file mode 100644 index 0000000000..373195b1e4 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotFlagEntity.java @@ -0,0 +1,70 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; + +@Entity +@Table(name = "plot_flags", uniqueConstraints = @UniqueConstraint(columnNames = {"plot_id","flag"})) +@NamedQueries({ + @NamedQuery(name = "PlotFlag.findByPlot", query = "SELECT f FROM PlotFlagEntity f join fetch f.plot p WHERE p.id =" + + " " + + ":plotId"), + @NamedQuery(name = "PlotFlag.findAllInPlotIds", query = "SELECT f FROM PlotFlagEntity f join fetch f.plot p WHERE p.id IN :plotIds"), + @NamedQuery(name = "PlotFlag.findByPlotAndName", query = "SELECT f FROM PlotFlagEntity f join fetch f.plot p WHERE p.id" + + " = :plotId AND f.flag = :flag"), + @NamedQuery(name = "PlotFlag.findAll", query = "SELECT f FROM PlotFlagEntity f"), +}) +public class PlotFlagEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "plot_id", nullable = false) + private PlotEntity plot; + @Column(length = 64) + private String flag; + @Column(length = 512) + private String flagValue; + + public PlotFlagEntity() {} + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + + public PlotEntity getPlot() { return plot; } + public void setPlot(PlotEntity plot) { this.plot = plot; } + + public String getFlag() { return flag; } + public void setFlag(String flag) { this.flag = flag; } + + public String getFlagValue() { return flagValue; } + public void setFlagValue(String value) { this.flagValue = value; } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java new file mode 100644 index 0000000000..6ef457da44 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotMembershipEntity.java @@ -0,0 +1,53 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "plot_helpers") +@IdClass(PlotUserId.class) +@NamedQueries({ + @NamedQuery(name = "PlotHelper.delete", query = "DELETE FROM PlotMembershipEntity e WHERE e.plotId = :plotId AND e.userUuid = :uuid"), + @NamedQuery(name = "PlotHelper.findUsers", query = "SELECT e.userUuid FROM PlotMembershipEntity e WHERE e.plotId = " + + ":plotId"), + @NamedQuery(name = "PlotHelper.deleteByPlotId", query = "DELETE FROM PlotMembershipEntity e WHERE e.plotId = :plotId"), + @NamedQuery(name = "PlotHelper.findAll", query = "SELECT e FROM PlotMembershipEntity e"), + @NamedQuery(name = "PlotHelper.deleteAllInPlotIds", query = "DELETE FROM PlotMembershipEntity e WHERE e.plotId IN :plotIds") +}) +public class PlotMembershipEntity { + @Id + @Column(name = "plot_plot_id") + private Long plotId; + @Id @Column(name = "user_uuid", length = 40) + private String userUuid; + + public PlotMembershipEntity() {} + + public Long getPlotId() { return plotId; } + public void setPlotId(Long plotId) { this.plotId = plotId; } + public String getUserUuid() { return userUuid; } + public void setUserUuid(String userUuid) { this.userUuid = userUuid; } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java new file mode 100644 index 0000000000..7dca44c2aa --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingEntity.java @@ -0,0 +1,58 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "plot_rating") +@IdClass(PlotRatingId.class) +@NamedQueries({ + @NamedQuery(name = "PlotRating.findByPlot", query = "SELECT r FROM PlotRatingEntity r WHERE r.plotId = :plotId"), + @NamedQuery(name = "PlotRating.upsert", query = "UPDATE PlotRatingEntity r SET r.rating = :rating WHERE r.plotId = :plotId AND r.player = :player"), + @NamedQuery(name = "PlotRating.updateValue", query = "UPDATE PlotRatingEntity r SET r.rating = :rating WHERE r.plotId =" + + " :plotId AND r.player = :player"), + @NamedQuery(name = "PlotRating.deleteByPlot", query = "DELETE FROM PlotRatingEntity r WHERE r.plotId = :plotId"), + @NamedQuery(name = "PlotRating.findAll", query = "SELECT r FROM PlotRatingEntity r"), + @NamedQuery(name = "PlotRating.deleteAllInPlotIds", query = "DELETE FROM PlotRatingEntity r WHERE r.plotId IN :plotIds") +}) +public class PlotRatingEntity { + @Id @Column(name = "plot_plot_id") + private Long plotId; + @Id + @Column(length = 40) + private String player; + @Column(nullable = false) + private Integer rating; + + public PlotRatingEntity() {} + + public Long getPlotId() { return plotId; } + public void setPlotId(Long plotId) { this.plotId = plotId; } + public String getPlayer() { return player; } + public void setPlayer(String player) { this.player = player; } + public Integer getRating() { return rating; } + public void setRating(Integer rating) { this.rating = rating; } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingId.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingId.java new file mode 100644 index 0000000000..528bd6acb8 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotRatingId.java @@ -0,0 +1,52 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import java.io.Serializable; +import java.util.Objects; + +public class PlotRatingId implements Serializable { + private Long plotId; + private String player; + + public PlotRatingId() {} + + public PlotRatingId(Long plotId, String player) { + this.plotId = plotId; + this.player = player; + } + + public Long getPlotId() { return plotId; } + public void setPlotId(Long plotId) { this.plotId = plotId; } + public String getPlayer() { return player; } + public void setPlayer(String player) { this.player = player; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PlotRatingId that = (PlotRatingId) o; + return Objects.equals(plotId, that.plotId) && Objects.equals(player, that.player); + } + + @Override + public int hashCode() { + return Objects.hash(plotId, player); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java new file mode 100644 index 0000000000..e109f2478e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotSettingsEntity.java @@ -0,0 +1,100 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.MapsId; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; + +@Entity +@Table(name = "plot_settings") +@NamedQueries({ + @NamedQuery(name = "PlotSettings.updateAlias", query = "UPDATE PlotSettingsEntity s SET s.alias = :alias WHERE s.id = :plotId"), + @NamedQuery(name = "PlotSettings.updatePosition", query = "UPDATE PlotSettingsEntity s SET s.position = :pos WHERE s.id = :plotId"), + @NamedQuery(name = "PlotSettings.updateMerged", query = "UPDATE PlotSettingsEntity s SET s.merged =" + + " :merged WHERE s.id = :plotId"), + @NamedQuery(name = "PlotSettings.deleteByPlot", query = "DELETE FROM PlotSettingsEntity s WHERE s.id = :plotId"), + @NamedQuery(name = "PlotSettings.findAll", query = "SELECT s FROM PlotSettingsEntity s"), + @NamedQuery(name = "PlotSettings.deleteAllInPlotIds", query = "DELETE FROM PlotSettingsEntity s WHERE s.id IN :plotIds") +}) +public class PlotSettingsEntity { + @Id + @Column(name = "plot_plot_id") + private Long id; + + @OneToOne + @MapsId + @JoinColumn(name = "plot_plot_id") + private PlotEntity plot; + + @Column(length = 45) + private String biome; + @Column(name = "rain") + private Integer rain; + @Column(name = "custom_time") + private Boolean customTime; + @Column(name = "time") + private Integer time; + @Column(name = "deny_entry") + private Boolean denyEntry; + @Column(length = 50) + private String alias; + @Column(name = "merged") + private Integer merged; + @Column(length = 50) + private String position; + + public PlotSettingsEntity() {} + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + + public PlotEntity getPlot() { return plot; } + public void setPlot(PlotEntity plot) { this.plot = plot; } + + public String getBiome() { return biome; } + public void setBiome(String biome) { this.biome = biome; } + + public Integer getRain() { return rain; } + public void setRain(Integer rain) { this.rain = rain; } + + public Boolean getCustomTime() { return customTime; } + public void setCustomTime(Boolean customTime) { this.customTime = customTime; } + + public Integer getTime() { return time; } + public void setTime(Integer time) { this.time = time; } + + public Boolean getDenyEntry() { return denyEntry; } + public void setDenyEntry(Boolean denyEntry) { this.denyEntry = denyEntry; } + + public String getAlias() { return alias; } + public void setAlias(String alias) { this.alias = alias; } + + public Integer getMerged() { return merged; } + public void setMerged(Integer merged) { this.merged = merged; } + + public String getPosition() { return position; } + public void setPosition(String position) { this.position = position; } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java new file mode 100644 index 0000000000..0320b9348e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotTrustedEntity.java @@ -0,0 +1,53 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "plot_trusted") +@IdClass(PlotUserId.class) +@NamedQueries({ + @NamedQuery(name = "PlotTrusted.deleteByPlotIdAndUserUUID", query = "DELETE FROM PlotTrustedEntity e WHERE e.plotId = :plotId AND e.userUuid = :uuid"), + @NamedQuery(name = "PlotTrusted.findUsers", query = "SELECT e.userUuid FROM PlotTrustedEntity e WHERE e.plotId = " + + ":plotId"), + @NamedQuery(name = "PlotTrusted.deleteByPlotId", query = "DELETE FROM PlotTrustedEntity e WHERE e.plotId = :plotId"), + @NamedQuery(name = "PlotTrusted.findAll", query = "SELECT e FROM PlotTrustedEntity e"), + @NamedQuery(name = "PlotTrusted.deleteAllInPlotIds", query = "DELETE FROM PlotTrustedEntity e WHERE e.plotId IN :plotIds") +}) +public class PlotTrustedEntity { + @Id + @Column(name = "plot_plot_id") + private Long plotId; + @Id @Column(name = "user_uuid", length = 40) + private String userUuid; + + public PlotTrustedEntity() {} + + public Long getPlotId() { return plotId; } + public void setPlotId(Long plotId) { this.plotId = plotId; } + public String getUserUuid() { return userUuid; } + public void setUserUuid(String userUuid) { this.userUuid = userUuid; } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotUserId.java b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotUserId.java new file mode 100644 index 0000000000..86d9b6632b --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/entity/PlotUserId.java @@ -0,0 +1,52 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.entity; + +import java.io.Serializable; +import java.util.Objects; + +public class PlotUserId implements Serializable { + private Long plotId; + private String userUuid; + + public PlotUserId() {} + + public PlotUserId(Long plotId, String userUuid) { + this.plotId = plotId; + this.userUuid = userUuid; + } + + public Long getPlotId() { return plotId; } + public void setPlotId(Long plotId) { this.plotId = plotId; } + public String getUserUuid() { return userUuid; } + public void setUserUuid(String userUuid) { this.userUuid = userUuid; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PlotUserId that = (PlotUserId) o; + return Objects.equals(plotId, that.plotId) && Objects.equals(userUuid, that.userUuid); + } + + @Override + public int hashCode() { + return Objects.hash(plotId, userUuid); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java new file mode 100644 index 0000000000..27731ae78b --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterHelperRepository.java @@ -0,0 +1,59 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.api; + +import java.util.List; + +/** + * Repository abstraction for managing helper users associated with a cluster. + * Implementations are responsible for persisting and retrieving associations + * between a cluster and player UUIDs who act as helpers. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface ClusterHelperRepository { + /** + * Retrieves all helper user UUIDs associated with the given cluster. + * + * @param clusterId the unique identifier of the cluster + * @return list of helper user UUIDs (as String), never null; may be empty + */ + List findUsers(long clusterId); + + /** + * Adds the given user as a helper to the specified cluster. + * Implementations should be idempotent: adding an existing association + * should not create duplicates nor fail. + * + * @param clusterId the unique identifier of the cluster + * @param userUuid the helper user's UUID (String representation) + */ + void add(long clusterId, String userUuid); + + /** + * Removes the given user from the helpers of the specified cluster. + * + * @param clusterId the unique identifier of the cluster + * @param userUuid the helper user's UUID (String representation) + */ + void remove(long clusterId, String userUuid); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java new file mode 100644 index 0000000000..f47c12ae2f --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterInvitedRepository.java @@ -0,0 +1,58 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.api; + +import java.util.List; + +/** + * Repository abstraction for managing invited users for a cluster. + * Implementations persist associations between clusters and player UUIDs + * that have been invited to the cluster but may not yet be members/helpers. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface ClusterInvitedRepository { + /** + * Retrieves all invited user UUIDs for the given cluster. + * + * @param clusterId the unique identifier of the cluster + * @return list of invited user UUIDs (as String), never null; may be empty + */ + List findUsers(long clusterId); + + /** + * Records an invitation of the given user to the specified cluster. + * Implementations should treat duplicate invitations idempotently. + * + * @param clusterId the unique identifier of the cluster + * @param userUuid the invited user's UUID (String representation) + */ + void add(long clusterId, String userUuid); + + /** + * Revokes an invitation for the given user from the specified cluster. + * + * @param clusterId the unique identifier of the cluster + * @param userUuid the invited user's UUID (String representation) + */ + void remove(long clusterId, String userUuid); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java new file mode 100644 index 0000000000..6c2aec5234 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterRepository.java @@ -0,0 +1,102 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.ClusterEntity; +import com.plotsquared.core.plot.PlotId; + +import java.util.List; +import java.util.Optional; + +/** + * Repository for managing ClusterEntity persistence and lookups. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface ClusterRepository { + /** + * Finds a cluster by its primary identifier. + * + * @param id the cluster id + * @return an Optional containing the ClusterEntity if found, otherwise empty + */ + Optional findById(long id); + + /** + * Finds the cluster by world and a coordinate that lies within the cluster bounds. + * Exact semantics depend on implementation; typically returns the cluster that contains + * the given x/z coordinate in the specified world. + * + * @param world the world name + * @param x x-coordinate (plot coordinate or block coordinate as defined by implementation) + * @param z z-coordinate (plot coordinate or block coordinate as defined by implementation) + * @return an Optional containing the ClusterEntity if a match is found; otherwise empty + */ + Optional findByWorldAndBounds(String world, int x, int z); + + /** + * Returns all clusters in a given world. + * + * @param world the world name + * @return list of clusters, never null; may be empty + */ + List findByWorld(String world); + + /** + * Returns all clusters across all worlds. + */ + List findAll(); + + /** + * Persists the given cluster. Implementations may insert or update as needed. + * + * @param cluster the cluster entity to save + */ + void save(ClusterEntity cluster); + + /** + * Deletes the cluster with the specified id. No-op if it does not exist. + * + * @param id the cluster id + */ + void deleteById(long id); + + /** + * Update world for all clusters from oldWorld to newWorld. + */ + void updateWorldAll(String oldWorld, String newWorld); + + /** + * Update world for clusters overlapping the given bounds in oldWorld. + */ + void updateWorldInBounds(String oldWorld, String newWorld, int minX, int minZ, int maxX, int maxZ); + + /** + * Update world for all clusters from oldWorld to newWorld. + */ + void replaceWorld(String oldWorld, String newWorld); + + /** + * Update world for clusters overlapping the given bounds in oldWorld. + */ + void replaceWorldInBounds(String oldWorld, String newWorld, PlotId min, PlotId max); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java new file mode 100644 index 0000000000..53eb44b2e9 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/ClusterSettingsRepository.java @@ -0,0 +1,49 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.ClusterSettingsEntity; + +import java.util.Optional; + +/** + * Repository abstraction for managing cluster settings operations. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface ClusterSettingsRepository { + /** + * Find settings for a given cluster id. + * + * @param clusterId the cluster id + * @return optional settings entity + */ + Optional findById(long clusterId); + + /** + * Update the "position" setting for a cluster. + * + * @param clusterId the cluster id + * @param position the new position string + */ + void updatePosition(long clusterId, String position); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java new file mode 100644 index 0000000000..99e13c190c --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlayerMetaRepository.java @@ -0,0 +1,59 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.PlayerMetaEntity; + +import java.util.List; + +/** + * Repository for storing and retrieving arbitrary metadata entries for players. + * Keys are namespaced per player UUID and map to binary values. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface PlayerMetaRepository { + /** + * Returns all metadata entries for the player with the given UUID. + * + * @param uuid the player's UUID (String representation) + * @return list of metadata entries, never null; may be empty + */ + List findByUuid(String uuid); + + /** + * Inserts or updates a metadata value for the given player and key. + * + * @param uuid the player's UUID (String representation) + * @param key the metadata key + * @param value the value as a byte array; implementations may store as-is + */ + void put(String uuid, String key, byte[] value); + + /** + * Deletes a metadata entry for the given player and key. No-op if absent. + * + * @param uuid the player's UUID (String representation) + * @param key the metadata key + */ + void delete(String uuid, String key); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java new file mode 100644 index 0000000000..2b117fa815 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotCommentRepository.java @@ -0,0 +1,98 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.PlotCommentEntity; + +import java.util.List; + +/** + * Repository for managing plot comments, typically grouped by "inbox" names + * (e.g., inbox types). Methods support querying by world, by plot hash, and + * by inbox, as well as adding and removing comments. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface PlotCommentRepository { + /** + * Returns all comments for a given world and inbox across all plots. + * + * @param world the world name + * @param inbox the inbox identifier/category + * @return list of comments, never null; may be empty + */ + List findByWorldAndInbox(String world, String inbox); + + /** + * Returns all comments for a specific plot (identified by hash) in a world and inbox. + * + * @param world the world name + * @param hashcode the plot hash identifier + * @param inbox the inbox identifier/category + * @return list of comments, never null; may be empty + */ + List findByWorldHashAndInbox(String world, int hashcode, String inbox); + + /** + * Persists a comment entity (insert). + * + * @param entity the comment entity to save + */ + void save(PlotCommentEntity entity); + + /** + * Deletes a single comment by its identifying fields. + * + * @param world the world name + * @param hashcode the plot hash identifier + * @param inbox the inbox identifier/category + * @param sender the comment sender (UUID or name as stored) + * @param comment the exact comment text + */ + void deleteOne(String world, int hashcode, String inbox, String sender, String comment); + + /** + * Clears all comments in the given world for the specified inbox across all plots. + * + * @param world the world name + * @param inbox the inbox identifier/category + */ + void clearInbox(String world, String inbox); + + /** + * Clears all comments for a specific plot (by hash) in the given world and inbox. + * + * @param world the world name + * @param hashcode the plot hash identifier + * @param inbox the inbox identifier/category + */ + void clearInbox(String world, int hashcode, String inbox); + + /** + * Deletes all comments associated with a specific plot (by hash) in a world, + * regardless of inbox. + * + * @param world the world name + * @param hashcode the plot hash identifier + */ + void deleteByWorldAndHash(String world, int hashcode); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java new file mode 100644 index 0000000000..e3f3eb9773 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotDeniedRepository.java @@ -0,0 +1,66 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.api; + +import java.util.List; + +/** + * Repository for managing denied users for a plot. + * Denied users are explicitly prevented from interacting with or entering the plot + * depending on gameplay rules. This repository stores associations between plot ids + * and player UUIDs. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface PlotDeniedRepository { + /** + * Retrieves all denied user UUIDs for the given plot. + * + * @param plotId the unique identifier of the plot + * @return list of denied user UUIDs (as String), never null; may be empty + */ + List findUsers(long plotId); + + /** + * Adds the given user to the denied list of the specified plot. + * Implementations should be idempotent and avoid duplicates. + * + * @param plotId the unique identifier of the plot + * @param userUuid the user's UUID (String representation) + */ + void add(long plotId, String userUuid); + + /** + * Removes the given user from the denied list of the specified plot. + * + * @param plotId the unique identifier of the plot + * @param userUuid the user's UUID (String representation) + */ + void remove(long plotId, String userUuid); + + /** + * Removes all denied users for the specified plot. + * + * @param plotId the unique identifier of the plot + */ + void deleteByPlotId(long plotId); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java new file mode 100644 index 0000000000..cb9431c57e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotFlagRepository.java @@ -0,0 +1,67 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.PlotFlagEntity; + +import java.util.List; +import java.util.Optional; + +/** + * Repository for managing flags associated with a plot. + * A flag is a named configuration entry applied to an individual plot. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface PlotFlagRepository { + /** + * Retrieves all flags for a given plot. + * + * @param plotId the plot identifier + * @return list of plot flags, never null; may be empty + */ + List findByPlotId(long plotId); + + /** + * Retrieves a specific flag by name for the given plot. + * + * @param plotId the plot identifier + * @param flagName the flag name + * @return Optional with the flag if present; otherwise empty + */ + Optional findByPlotAndName(long plotId, String flagName); + + /** + * Persists the flag entity. Implementations may insert or update as needed. + * + * @param entity the flag entity to save + */ + void save(PlotFlagEntity entity); + + /** + * Deletes the flag with the given name from the specified plot. + * + * @param plotId the plot identifier + * @param flagName the flag name + */ + void deleteByPlotAndName(long plotId, String flagName); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java new file mode 100644 index 0000000000..2066eac740 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotMembershipRepository.java @@ -0,0 +1,64 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.api; + +import java.util.List; + +/** + * Repository for managing plot member associations. + * Members typically have elevated permissions on the plot compared to visitors. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface PlotMembershipRepository { + /** + * Retrieves all member user UUIDs for the given plot. + * + * @param plotId the unique identifier of the plot + * @return list of member user UUIDs (as String), never null; may be empty + */ + List findUsers(long plotId); + + /** + * Adds the given user as a member of the specified plot. + * Implementations should be idempotent and avoid duplicates. + * + * @param plotId the unique identifier of the plot + * @param userUuid the user's UUID (String representation) + */ + void add(long plotId, String userUuid); + + /** + * Removes the given user from the members of the specified plot. + * + * @param plotId the unique identifier of the plot + * @param userUuid the user's UUID (String representation) + */ + void remove(long plotId, String userUuid); + + /** + * Removes all members for the specified plot. + * + * @param plotId the unique identifier of the plot + */ + void deleteByPlotId(long plotId); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java new file mode 100644 index 0000000000..cabb98356f --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRatingRepository.java @@ -0,0 +1,51 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.PlotRatingEntity; + +import java.util.List; + +/** + * Repository for managing player ratings of plots. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface PlotRatingRepository { + /** + * Retrieves all rating entries for the given plot. + * + * @param plotId the plot identifier + * @return list of plot ratings, never null; may be empty + */ + List findByPlotId(long plotId); + + /** + * Inserts a new rating or updates the existing rating for the given player on the plot. + * The rating scale is defined by the caller/implementation. + * + * @param plotId the plot identifier + * @param playerUuid the player's UUID (String representation) + * @param rating the rating value to set + */ + void upsert(long plotId, String playerUuid, int rating); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java new file mode 100644 index 0000000000..56a1a95aa2 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotRepository.java @@ -0,0 +1,213 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.plot.Plot; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +/** + * Repository abstraction for reading and writing plot data and related + * lookups by id, world, owner, and coordinates. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface PlotRepository { + /** + * Swaps the persisted state of two plots. + * Implementations should ensure the swap occurs atomically/consistently + * if the underlying storage supports transactions. + * + * @param plot1 the first plot + * @param plot2 the second plot + * @return true if the swap succeeded; false otherwise + */ + boolean swapPlots(Plot plot1, Plot plot2); + + /** + * Updates the world name for all stored plots. + * + * @param oldWorld The previous world name + * @param newWorld The new world name + */ + void replaceWorldAll(String oldWorld, String newWorld); + + /** + * Moves all data from one plot to another. + * + * @param originPlot The source plot + * @param newPlot The target plot + */ + void movePlots(Plot originPlot, Plot newPlot); + + /** + * Sets a new owner for a plot. + * + * @param plot The plot whose owner should be changed + * @param newOwner The UUID of the new owner + */ + void setOwner(Plot plot, UUID newOwner); + + /** + * Bulk update world name for plots within the given rectangular plot-id range. + * + * @param oldWorld the source world name + * @param newWorld the destination world name + * @param minX minimum plot x-id (inclusive) + * @param minZ minimum plot z-id (inclusive) + * @param maxX maximum plot x-id (inclusive) + * @param maxZ maximum plot z-id (inclusive) + */ + void replaceWorldInRange(String oldWorld, String newWorld, int minX, int minZ, int maxX, int maxZ); + + /** + * Bulk update world name for all plots in a given world. + */ + void replaceWorld(String oldWorld, String newWorld); + + /** + * Bulk update world name for plots within the given rectangular plot-id bounds. + */ + void replaceWorldInBounds(String oldWorld, String newWorld, com.plotsquared.core.plot.PlotId min, com.plotsquared.core.plot.PlotId max); + + /** + * Bulk-creates plots and associated data (settings, flags, memberships) + * in a single transactional operation. + * + * @param plots list of plots to persist + */ + void createPlotsAndData(List plots); + + /** + * Creates a plot if it does not already exist for the given world/x/z. + * Also creates an empty settings row. Mirrors legacy createPlotSafe behavior. + * Sets plot.temp to the generated id if created. + * + * @param plot plot to create + * @return true if a new plot was created; false if it already existed + */ + boolean createPlotSafe(Plot plot); + + /** + * Creates a plot and an empty settings row. Mirrors legacy createPlotAndSettings. + * Sets plot.temp to the generated id. + * + * @param plot plot to create + */ + void createPlotAndSettings(Plot plot); + + /** + * Load all plots (with settings, flags and tiers) grouped by world and PlotId. + * Mirrors the legacy SQLManager#getPlots structure. + * + * @return world -> (PlotId -> Plot) + */ + java.util.HashMap> getPlots(); + + /** + * Finds a plot by its primary identifier. + * + * @param id the plot id + * @return an Optional with the plot entity if found; otherwise empty + */ + Optional findById(long id); + + /** + * Finds a plot by its x and z coordinates. + * The exact semantics are implementation-defined; despite the name, some + * implementations may also use the provided world hint. + * + * @param x plot x-id (not block coordinate) + * @param z plot z-id (not block coordinate) + * @param world an optional world hint depending on implementation + * @return an Optional with the plot entity if found; otherwise empty + */ + Optional findByXAndZAnyWorld(int x, int z, String world); + + /** + * Finds a plot by world and plot coordinates. + * + * @param world the world name + * @param x plot x-id (not block coordinate) + * @param z plot z-id (not block coordinate) + * @return an Optional with the plot entity if found; otherwise empty + */ + Optional findByWorldAndId(String world, int x, int z); + + /** + * Finds all plots owned by the given player. + * + * @param ownerUuid the owner's UUID (String representation) + * @return list of plots, never null; may be empty + */ + List findByOwner(String ownerUuid); + + /** + * Finds all plots in the specified world. + * + * @param world the world name + * @return list of plots, never null; may be empty + */ + List findByWorld(String world); + + /** + * Persists the given plot entity (insert or update). + * + * @param plot the plot entity to save + */ + void save(PlotEntity plot); + + /** + * Deletes the plot with the specified id. No-op if it does not exist. + * + * @param id the plot id + */ + void deleteById(long id); + + /** + * Deletes all ratings for the given plot. + * + * @param plot the plot whose ratings should be removed + */ + void deleteRatings(Plot plot); + + /** + * Deletes the plot and all related data (flags, helpers, trusted, denied, ratings, and settings via cascade). + * No-op if the plot does not exist. + * + * @param plot the plot to delete + */ + void delete(Plot plot); + + /** + * Purge plots and all related data by internal database ids. + */ + void purgeIds(java.util.Set ids); + + /** + * Purge plots by world and plot-id coordinates. + */ + void purgeByWorldAndPlotIds(String world, java.util.Set plotIds); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java new file mode 100644 index 0000000000..34f51e011a --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotSettingsRepository.java @@ -0,0 +1,75 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.api; + +import com.plotsquared.core.persistence.entity.PlotSettingsEntity; + +import java.util.Optional; + +/** + * Repository for persisting and retrieving per-plot settings. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface PlotSettingsRepository { + /** + * Retrieves the settings for the given plot if available. + * + * @param plotId the plot identifier + * @return Optional with the settings if present; otherwise empty + */ + Optional findByPlotId(long plotId); + + /** + * Persists the provided settings entity (insert or update). + * + * @param settings the settings entity to save + */ + void save(PlotSettingsEntity settings); + + /** + * Deletes the settings associated with the specified plot id. No-op if absent. + * + * @param plotId the plot identifier + */ + void deleteByPlotId(long plotId); + + /** + * Updates the alias for the plot settings row of the given plot id. + */ + void updateAlias(long plotId, String alias); + + /** + * Updates the home position string for the plot settings row of the given plot id. + */ + void updatePosition(long plotId, String position); + + /** + * Updates the merged bitmask for the plot settings row of the given plot id. + */ + void updateMerged(long plotId, int mergedBitmask); + + /** + * Creates a default settings row for the plot if it does not exist. + */ + void createDefaultIfAbsent(long plotId, String defaultPosition); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java new file mode 100644 index 0000000000..79c48217b2 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/PlotTrustedRepository.java @@ -0,0 +1,65 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.api; + +import java.util.List; + +/** + * Repository for managing trusted users for a plot. + * Trusted users typically have broader permissions than helpers but may be + * distinct from owners and members depending on server policy. + * + * @since 8.0.0 + * @version 1.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface PlotTrustedRepository { + /** + * Retrieves all trusted user UUIDs for the given plot. + * + * @param plotId the unique identifier of the plot + * @return list of trusted user UUIDs (as String), never null; may be empty + */ + List findUsers(long plotId); + + /** + * Adds the given user to the trusted list of the specified plot. + * Implementations should be idempotent and avoid duplicates. + * + * @param plotId the unique identifier of the plot + * @param userUuid the user's UUID (String representation) + */ + void add(long plotId, String userUuid); + + /** + * Removes the given user from the trusted list of the specified plot. + * + * @param plotId the unique identifier of the plot + * @param userUuid the user's UUID (String representation) + */ + void remove(long plotId, String userUuid); + + /** + * Removes all trusted users for the specified plot. + * + * @param plotId the unique identifier of the plot + */ + void deleteByPlotId(long plotId); +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/api/package-info.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/package-info.java new file mode 100644 index 0000000000..c18d74e7b8 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/api/package-info.java @@ -0,0 +1,12 @@ +/** + * This package contains interfaces for repositories that handle data persistence for various entities in the PlotSquared system. + * + * @version 1.0.0 + * @since 8.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +@NotNullByDefault +package com.plotsquared.core.persistence.repository.api; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java new file mode 100644 index 0000000000..6ad94553a6 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterHelperRepositoryJpa.java @@ -0,0 +1,85 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.ClusterHelperEntity; +import com.plotsquared.core.persistence.repository.api.ClusterHelperRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +public class ClusterHelperRepositoryJpa implements ClusterHelperRepository { + + private static final Logger LOGGER = LogManager.getLogger(ClusterHelperRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public ClusterHelperRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public List findUsers(long clusterId) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("ClusterHelper.findUsers", String.class) + .setParameter("clusterId", clusterId) + .getResultList(); + } + } + + @Override + public void add(long clusterId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + ClusterHelperEntity e = new ClusterHelperEntity(); + e.setClusterId(clusterId); + e.setUserUuid(userUuid); + em.persist(e); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to add cluster helper (clusterId={}, userUuid={})", clusterId, userUuid, ex); + } + } + + @Override + public void remove(long clusterId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("ClusterHelper.delete") + .setParameter("clusterId", clusterId) + .setParameter("uuid", userUuid) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to remove cluster helper (clusterId={}, userUuid={})", clusterId, userUuid, ex); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java new file mode 100644 index 0000000000..849ef36ab3 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterInvitedRepositoryJpa.java @@ -0,0 +1,85 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.ClusterInvitedEntity; +import com.plotsquared.core.persistence.repository.api.ClusterInvitedRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +public class ClusterInvitedRepositoryJpa implements ClusterInvitedRepository { + + private static final Logger LOGGER = LogManager.getLogger(ClusterInvitedRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public ClusterInvitedRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public List findUsers(long clusterId) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("ClusterInvited.findUsers", String.class) + .setParameter("clusterId", clusterId) + .getResultList(); + } + } + + @Override + public void add(long clusterId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + ClusterInvitedEntity e = new ClusterInvitedEntity(); + e.setClusterId(clusterId); + e.setUserUuid(userUuid); + em.persist(e); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to add cluster invited (clusterId={}, userUuid={})", clusterId, userUuid, ex); + } + } + + @Override + public void remove(long clusterId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("ClusterInvited.delete") + .setParameter("clusterId", clusterId) + .setParameter("uuid", userUuid) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to remove cluster invited (clusterId={}, userUuid={})", clusterId, userUuid, ex); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java new file mode 100644 index 0000000000..37a3d1d4ee --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterRepositoryJpa.java @@ -0,0 +1,172 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.ClusterEntity; +import com.plotsquared.core.persistence.repository.api.ClusterRepository; +import com.plotsquared.core.plot.PlotId; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Optional; + +public class ClusterRepositoryJpa implements ClusterRepository { + + private static final Logger LOGGER = LogManager.getLogger(ClusterRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public ClusterRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public @NotNull Optional findById(long id) { + try (EntityManager em = emf.createEntityManager()) { + return Optional.ofNullable(em.find(ClusterEntity.class, id)); + } + } + + @Override + public @NotNull Optional findByWorldAndBounds(@NotNull String world, int x, int z) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("Cluster.findByWorldAndBounds", ClusterEntity.class) + .setParameter("world", world) + .setParameter("x", x) + .setParameter("z", z) + .getResultStream().findFirst(); + } + } + + @Override + public @NotNull List findByWorld(@NotNull String world) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("Cluster.findByWorld", ClusterEntity.class) + .setParameter("world", world) + .getResultList(); + } + } + + @Override + public @NotNull List findAll() { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("Cluster.finaAll", ClusterEntity.class) + .getResultList(); + } + } + + @Override + public void save(@NotNull ClusterEntity cluster) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + if (cluster.getId() == null) { + em.persist(cluster); + } else { + em.merge(cluster); + } + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to save cluster (id={}, world={})", cluster.getId(), cluster.getWorld(), ex); + } + } + + @Override + public void deleteById(long id) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + ClusterEntity e = em.find(ClusterEntity.class, id); + if (e != null) { + em.remove(e); + } + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete cluster by id (id={})", id, ex); + } + } + + @Override + public void updateWorldAll(@NotNull String oldWorld, @NotNull String newWorld) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("Cluster.updateWorld") + .setParameter("newWorld", newWorld) + .setParameter("oldWorld", oldWorld) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to update cluster world (all) oldWorld={}, newWorld={}", oldWorld, newWorld, ex); + } + } + + @Override + public void updateWorldInBounds(@NotNull String oldWorld, @NotNull String newWorld, int minX, int minZ, int maxX, int maxZ) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("Cluster.updateWorldInBounds") + .setParameter("newWorld", newWorld) + .setParameter("oldWorld", oldWorld) + .setParameter("minX", minX) + .setParameter("minZ", minZ) + .setParameter("maxX", maxX) + .setParameter("maxZ", maxZ) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error( + "Failed to update cluster world in bounds oldWorld={}, newWorld={}, bounds=[{}..{}]x[{}..{}]", + oldWorld, + newWorld, + minX, + maxX, + minZ, + maxZ, + ex + ); + } + } + + @Override + public void replaceWorld(String oldWorld, String newWorld) { + updateWorldAll(oldWorld, newWorld); + } + + @Override + public void replaceWorldInBounds(String oldWorld, String newWorld, PlotId min, PlotId max) { + updateWorldInBounds(oldWorld, newWorld, min.getX(), min.getY(), max.getX(), max.getY()); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java new file mode 100644 index 0000000000..818d5df593 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/ClusterSettingsRepositoryJpa.java @@ -0,0 +1,67 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.ClusterSettingsEntity; +import com.plotsquared.core.persistence.repository.api.ClusterSettingsRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +public class ClusterSettingsRepositoryJpa implements ClusterSettingsRepository { + + private static final Logger LOGGER = LogManager.getLogger(ClusterSettingsRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public ClusterSettingsRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public Optional findById(long clusterId) { + try (EntityManager em = emf.createEntityManager()) { + return Optional.ofNullable(em.find(ClusterSettingsEntity.class, clusterId)); + } + } + + @Override + public void updatePosition(long clusterId, @NotNull String position) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("ClusterSettings.updatePosition") + .setParameter("clusterId", clusterId) + .setParameter("pos", position) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to update cluster position (clusterId={}, position={})", clusterId, position, ex); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java new file mode 100644 index 0000000000..a89804fa23 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlayerMetaRepositoryJpa.java @@ -0,0 +1,98 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlayerMetaEntity; +import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class PlayerMetaRepositoryJpa implements PlayerMetaRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlayerMetaRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlayerMetaRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public @NotNull List findByUuid(@NotNull String uuid) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("PlayerMeta.findByUuid", PlayerMetaEntity.class) + .setParameter("uuid", uuid) + .getResultList(); + } + } + + @Override + public void put(@NotNull String uuid, @NotNull String key, byte @NotNull [] value) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + // Delete existing row for same (uuid,key) then insert new + em.createNamedQuery("PlayerMeta.deleteByUuidAndKey") + .setParameter("uuid", uuid) + .setParameter("key", key) + .executeUpdate(); + PlayerMetaEntity e = new PlayerMetaEntity(); + e.setUuid(uuid); + e.setKey(key); + e.setPlayerMetaValue(value); + em.persist(e); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error( + "Failed to put player meta (uuid={}, key={}, value.length={})", + uuid, + key, + value.length, + ex + ); + } + } + + @Override + public void delete(@NotNull String uuid, @NotNull String key) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("PlayerMeta.deleteByUuidAndKey") + .setParameter("uuid", uuid) + .setParameter("key", key) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete player meta (uuid={}, key={})", uuid, key, ex); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java new file mode 100644 index 0000000000..dce6da2ca0 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotCommentRepositoryJpa.java @@ -0,0 +1,167 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotCommentEntity; +import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class PlotCommentRepositoryJpa implements PlotCommentRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotCommentRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotCommentRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public List findByWorldAndInbox(@NotNull String world, @NotNull String inbox) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("PlotComment.findByWorldAndInbox", PlotCommentEntity.class) + .setParameter("world", world) + .setParameter("inbox", inbox) + .getResultList(); + } + } + + @Override + public List findByWorldHashAndInbox(@NotNull String world, int hashcode, @NotNull String inbox) { + EntityManager em = emf.createEntityManager(); + try { + return em.createNamedQuery("PlotComment.findByWorldHashAndInbox", PlotCommentEntity.class) + .setParameter("world", world) + .setParameter("hash", hashcode) + .setParameter("inbox", inbox) + .getResultList(); + } finally { + em.close(); + } + } + + @Override + public void save(@NotNull PlotCommentEntity entity) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.persist(entity); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error( + "Failed to save plot comment (world={}, inbox={}, hashcode={})", + entity.getWorld(), + entity.getInbox(), + entity.getHashcode(), + e + ); + } + } + + @Override + public void deleteOne(@NotNull String world, int hashcode, @NotNull String inbox, @NotNull String sender, @NotNull String comment) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("PlotComment.deleteOne") + .setParameter("world", world) + .setParameter("hash", hashcode) + .setParameter("inbox", inbox) + .setParameter("sender", sender) + .setParameter("comment", comment) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error( + "Failed to delete one plot comment (world={}, inbox={}, hashcode={}, sender={}, comment={})", + world, + inbox, + hashcode, + sender, + comment, + e + ); + } + } + + @Override + public void clearInbox(@NotNull String world, @NotNull String inbox) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("PlotComment.clearInbox") + .setParameter("world", world) + .setParameter("inbox", inbox) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to clear inbox (world={}, inbox={})", world, inbox, e); + } + } + + @Override + public void clearInbox(@NotNull String world, int hashcode, @NotNull String inbox) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("PlotComment.clearInboxByWorldHash") + .setParameter("world", world) + .setParameter("hash", hashcode) + .setParameter("inbox", inbox) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to clear inbox by world+hash (world={}, hashcode={}, inbox={})", world, hashcode, inbox, e); + } + } + + @Override + public void deleteByWorldAndHash(@NotNull String world, int hashcode) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("PlotComment.deleteByWorldAndHash") + .setParameter("world", world) + .setParameter("hash", hashcode) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete comments by world and hash (world={}, hashcode={})", world, hashcode, e); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java new file mode 100644 index 0000000000..50e3f7b0bc --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotDeniedRepositoryJpa.java @@ -0,0 +1,102 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotDeniedEntity; +import com.plotsquared.core.persistence.repository.api.PlotDeniedRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class PlotDeniedRepositoryJpa implements PlotDeniedRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotDeniedRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotDeniedRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public @NotNull List findUsers(long plotId) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("PlotDenied.findUsers", String.class) + .setParameter("plotId", plotId) + .getResultList(); + } + } + + @Override + public void add(long plotId, @NotNull String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + PlotDeniedEntity e = new PlotDeniedEntity(); + e.setPlotId(plotId); + e.setUserUuid(userUuid); + em.persist(e); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to add plot denied (plotId={}, userUuid={})", plotId, userUuid, ex); + } + } + + @Override + public void remove(long plotId, @NotNull String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("PlotDenied.delete") + .setParameter("plotId", plotId) + .setParameter("uuid", userUuid) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to remove plot denied (plotId={}, userUuid={})", plotId, userUuid, ex); + } + } + + @Override + public void deleteByPlotId(long plotId) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("PlotDenied.deleteByPlotId") + .setParameter("plotId", plotId) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete all plot denied users (plotId={})", plotId, ex); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java new file mode 100644 index 0000000000..d2de387eef --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotFlagRepositoryJpa.java @@ -0,0 +1,113 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.persistence.entity.PlotFlagEntity; +import com.plotsquared.core.persistence.repository.api.PlotFlagRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Optional; + +public class PlotFlagRepositoryJpa implements PlotFlagRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotFlagRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotFlagRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public @NotNull List findByPlotId(long plotId) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("PlotFlag.findByPlot", PlotFlagEntity.class) + .setParameter("plotId", plotId) + .getResultList(); + } + } + + @Override + public @NotNull Optional findByPlotAndName(long plotId, @NotNull String flagName) { + try (EntityManager em = emf.createEntityManager()) { + return Optional.ofNullable(em.createNamedQuery("PlotFlag.findByPlotAndName", PlotFlagEntity.class) + .setParameter("plotId", plotId) + .setParameter("flag", flagName) + .getSingleResultOrNull()); + } + } + + @Override + public void save(@NotNull PlotFlagEntity entity) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + if (entity.getId() == null) { + // ensure Plot reference is managed if set by id only + PlotEntity plot = entity.getPlot(); + if (plot != null && plot.getId() != null && !em.contains(plot)) { + plot = em.getReference(PlotEntity.class, plot.getId()); + entity.setPlot(plot); + } + em.persist(entity); + } else { + em.merge(entity); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error( + "Failed to save plot flag (plotId={}, flag={})", + entity.getPlot() != null ? entity.getPlot().getId() : null, + entity.getFlag(), + e + ); + } + } + + @Override + public void deleteByPlotAndName(long plotId, @NotNull String flagName) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + var plot = em.createNamedQuery("PlotFlag.findByPlotAndName", PlotFlagEntity.class) + .setParameter("plotId", plotId) + .setParameter("flag", flagName) + .getSingleResultOrNull(); + if (plot != null) { + em.remove(plot); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete plot flag (plotId={}, flag={})", plotId, flagName, e); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java new file mode 100644 index 0000000000..9c490e5a28 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotMembershipRepositoryJpa.java @@ -0,0 +1,102 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotMembershipEntity; +import com.plotsquared.core.persistence.repository.api.PlotMembershipRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class PlotMembershipRepositoryJpa implements PlotMembershipRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotMembershipRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotMembershipRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public @NotNull List findUsers(long plotId) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("PlotHelper.findUsers", String.class) + .setParameter("plotId", plotId) + .getResultList(); + } + } + + @Override + public void add(long plotId, @NotNull String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + PlotMembershipEntity e = new PlotMembershipEntity(); + e.setPlotId(plotId); + e.setUserUuid(userUuid); + em.persist(e); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to add plot member (plotId={}, userUuid={})", plotId, userUuid, ex); + } + } + + @Override + public void remove(long plotId, @NotNull String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("PlotHelper.delete") + .setParameter("plotId", plotId) + .setParameter("uuid", userUuid) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to remove plot member (plotId={}, userUuid={})", plotId, userUuid, ex); + } + } + + @Override + public void deleteByPlotId(long plotId) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("PlotHelper.deleteByPlotId") + .setParameter("plotId", plotId) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete all plot members (plotId={})", plotId, ex); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java new file mode 100644 index 0000000000..b052d9b957 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRatingRepositoryJpa.java @@ -0,0 +1,77 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotRatingEntity; +import com.plotsquared.core.persistence.repository.api.PlotRatingRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class PlotRatingRepositoryJpa implements PlotRatingRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotRatingRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotRatingRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public @NotNull List findByPlotId(long plotId) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("PlotRating.findByPlot", PlotRatingEntity.class) + .setParameter("plotId", plotId) + .getResultList(); + } + } + + @Override + public void upsert(long plotId, @NotNull String playerUuid, int rating) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + int updated = em.createNamedQuery("PlotRating.updateValue") + .setParameter("rating", rating) + .setParameter("plotId", plotId) + .setParameter("player", playerUuid) + .executeUpdate(); + if (updated == 0) { + PlotRatingEntity entity = new PlotRatingEntity(); + entity.setPlotId(plotId); + entity.setPlayer(playerUuid); + entity.setRating(rating); + em.persist(entity); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to upsert plot rating (plotId={}, playerUuid={}, rating={})", plotId, playerUuid, rating, e); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java new file mode 100644 index 0000000000..dd7c76de4e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotRepositoryJpa.java @@ -0,0 +1,803 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.location.BlockLoc; +import com.plotsquared.core.persistence.entity.PlotDeniedEntity; +import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.persistence.entity.PlotFlagEntity; +import com.plotsquared.core.persistence.entity.PlotMembershipEntity; +import com.plotsquared.core.persistence.entity.PlotRatingEntity; +import com.plotsquared.core.persistence.entity.PlotSettingsEntity; +import com.plotsquared.core.persistence.entity.PlotTrustedEntity; +import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.plot.flag.FlagParseException; +import com.plotsquared.core.plot.flag.types.BlockTypeListFlag; +import com.plotsquared.core.util.HashUtil; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; + +public class PlotRepositoryJpa implements PlotRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotRepositoryJpa.class); + private static final UUID EVERYONE = UUID.fromString("1-1-3-3-7"); + + private final EntityManagerFactory emf; + + @Inject + public PlotRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public boolean createPlotSafe(final Plot plot) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + String world = Optional.of(plot).map(Plot::getWorldName).orElse(Optional.of(plot).map(Plot::getArea).map(Object::toString).orElse(null)); + Optional existing = findByWorldAndId(world, plot.getId().getX(), plot.getId().getY()); + if (existing.isPresent()) { + tx.commit(); + return false; + } + PlotEntity pe = new PlotEntity(); + pe.setPlotIdX(plot.getId().getX()); + pe.setPlotIdZ(plot.getId().getY()); + UUID ownerUuid = plot.getOwnerAbs(); + pe.setOwner(Optional.ofNullable(ownerUuid).map(UUID::toString).orElse(EVERYONE.toString())); + pe.setWorld(world); + em.persist(pe); + em.flush(); + PlotSettingsEntity se = new PlotSettingsEntity(); + se.setPlot(pe); + se.setPosition("DEFAULT"); + em.persist(se); + tx.commit(); + return true; + } catch (RuntimeException e) { + if (tx.isActive()) { + tx.rollback(); + } + LOGGER.error("Failed to create plot safely (plot={})", plot, e); + } + return false; + } + + @Override + public void createPlotAndSettings(final Plot plot) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + String world = Optional.of(plot).map(Plot::getWorldName).orElse(Optional.of(plot).map(Plot::getArea).map(Object::toString).orElse(null)); + PlotEntity pe = new PlotEntity(); + pe.setPlotIdX(plot.getId().getX()); + pe.setPlotIdZ(plot.getId().getY()); + UUID ownerUuid = plot.getOwnerAbs(); + pe.setOwner(Optional.ofNullable(ownerUuid).map(UUID::toString).orElse(EVERYONE.toString())); + pe.setWorld(world); + em.persist(pe); + em.flush(); + PlotSettingsEntity se = new PlotSettingsEntity(); + se.setPlot(pe); + se.setPosition("DEFAULT"); + em.persist(se); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) { + tx.rollback(); + } + LOGGER.error("Failed to create plot and settings (plot={})", plot, e); + throw e; + } + } + + @Override + public void createPlotsAndData(final List plots) { + if (plots.isEmpty()) { + return; + } + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + for (final Plot plot : plots) { + // Persist plot row + PlotEntity pe = new PlotEntity(); + pe.setPlotIdX(plot.getId().getX()); + pe.setPlotIdZ(plot.getId().getY()); + UUID ownerUuid = plot.getOwnerAbs(); + pe.setOwner(Optional.ofNullable(ownerUuid).map(UUID::toString).orElse(EVERYONE.toString())); + // Prefer world name for consistency with other queries + String world = Optional.of(plot).map(Plot::getWorldName).orElse(Optional.of(plot).map(Plot::getArea).map(Object::toString).orElse(null)); + pe.setWorld(world); + em.persist(pe); + em.flush(); // ensure ID is generated + + long plotId = pe.getId(); + + // Persist settings (alias, merged, position) similar to legacy behavior + try { + var ps = plot.getSettings(); + PlotSettingsEntity se = new PlotSettingsEntity(); + se.setPlot(pe); + String alias = ps.getAlias(); + if (alias != null && !alias.isEmpty()) { + se.setAlias(alias); + } + boolean[] merged = ps.getMerged(); + if (merged != null) { + int hash = HashUtil.hash(merged); + se.setMerged(hash); + } + var loc = ps.getPosition(); + String position = "DEFAULT"; + if (loc != null) { + if (loc.getY() == 0) { + position = "DEFAULT"; + } else { + position = loc.getX() + "," + loc.getY() + "," + loc.getZ(); + } + } + se.setPosition(position); + em.persist(se); + } catch (Throwable t) { + // log and continue + LOGGER.warn( + "Failed to persist settings for plot (x={}, z={}, world={})", + plot.getId().getX(), + plot.getId().getY(), + world, + t + ); + } + + // Persist flags + try { + var flagContainer = plot.getFlagContainer(); + if (flagContainer.getFlagMap() != null) { + for (var flagEntry : flagContainer.getFlagMap().values()) { + PlotFlagEntity fe = new PlotFlagEntity(); + fe.setPlot(pe); + fe.setFlag(flagEntry.getName()); + fe.setFlagValue(flagEntry.toString()); + em.persist(fe); + } + } + } catch (Throwable t) { + LOGGER.warn( + "Failed to persist flags for plot (x={}, z={}, world={})", + plot.getId().getX(), + plot.getId().getY(), + world, + t + ); + } + + // Persist tiers: NOTE legacy mapping members->trusted, trusted->helpers + try { + // helpers table from plot.getTrusted() + for (UUID uuid : plot.getTrusted()) { + PlotMembershipEntity e = new PlotMembershipEntity(); + e.setPlotId(plotId); + e.setUserUuid(uuid.toString()); + em.persist(e); + } + // trusted table from plot.getMembers() + for (UUID uuid : plot.getMembers()) { + PlotTrustedEntity e = new PlotTrustedEntity(); + e.setPlotId(plotId); + e.setUserUuid(uuid.toString()); + em.persist(e); + } + // denied table from plot.getDenied() + for (UUID uuid : plot.getDenied()) { + PlotDeniedEntity e = new PlotDeniedEntity(); + e.setPlotId(plotId); + e.setUserUuid(uuid.toString()); + em.persist(e); + } + } catch (Exception exception) { + LOGGER.warn( + "Failed to persist tiers for plot (x={}, z={}, world={})", + plot.getId().getX(), + plot.getId().getY(), + world, + exception + ); + } + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) { + tx.rollback(); + } + LOGGER.error("Failed bulk create plots and data", e); + } + } + + @Override + public boolean swapPlots(final @NotNull Plot plot1, final @NotNull Plot plot2) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + var plot1Id = findByXAndZAnyWorld(plot1.getId().getX(), plot1.getId().getY(), plot1.getWorldName()) + .orElseThrow() + .getId(); + var plot2Id = findByXAndZAnyWorld(plot2.getId().getX(), plot2.getId().getY(), plot2.getWorldName()) + .orElseThrow() + .getId(); + em.createNamedQuery("Plot.updateXANDZ") + .setParameter("id", plot1Id) + .setParameter("x", plot1.getId().getX()) + .setParameter("z", plot1.getId().getY()); + em.createNamedQuery("Plot.updateXANDZ") + .setParameter("id", plot2Id) + .setParameter("x", plot2.getId().getX()) + .setParameter("z", plot2.getId().getY()); + tx.commit(); + return true; + } catch (RuntimeException e) { + if (tx.isActive()) { + tx.rollback(); + } + } + return false; + } + + @Override + public void replaceWorldInRange(@NotNull String oldWorld, @NotNull String newWorld, int minX, int minZ, int maxX, int maxZ) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("Plot.replaceWorldInBounds") + .setParameter("newWorld", newWorld) + .setParameter("oldWorld", oldWorld) + .setParameter("minX", minX) + .setParameter("maxX", maxX) + .setParameter("minZ", minZ) + .setParameter("maxZ", maxZ) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error( + "Failed to replace world in range (oldWorld={}, newWorld={}, range=[{}..{}]x[{}..{}])", + oldWorld, + newWorld, + minX, + maxX, + minZ, + maxZ, + e + ); + } + } + + @Override + public void replaceWorldAll(@NotNull String oldWorld, @NotNull String newWorld) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("Plot.replaceWorldAll") + .setParameter("newWorld", newWorld) + .setParameter("oldWorld", oldWorld) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to replace world (all plots) oldWorld={}, newWorld={}", oldWorld, newWorld, e); + } + } + + @Override + public void movePlots(final @NotNull Plot originPlot, final @NotNull Plot newPlot) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + var originPlotId = findByXAndZAnyWorld( + originPlot.getId().getX(), + originPlot.getId().getY(), + originPlot.getWorldName() + ).orElseThrow().getId(); + em.createNamedQuery("Plot.movePlot") + .setParameter("id", originPlotId) + .setParameter("plotIdX", newPlot.getId().getX()) + .setParameter("plotIdZ", newPlot.getId().getY()) + .setParameter("world", newPlot.getWorldName()); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) { + tx.rollback(); + } + LOGGER.error("Failed to move plots (plot1={}, plot2={})", originPlot, newPlot, e); + } + } + + @Override + public void setOwner(final @NotNull Plot plot, final @NotNull UUID newOwner) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("Plot.setOwner") + .setParameter("world", plot.getWorldName()) + .setParameter("x", plot.getId().getX()) + .setParameter("z", plot.getId().getY()) + .setParameter("owner", newOwner.toString()); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) { + tx.rollback(); + } + LOGGER.error("Failed to set plot owner (plot={}, newOwner={})", plot, newOwner, e); + } + } + + @Override + public @NotNull Optional findById(long id) { + try (EntityManager em = emf.createEntityManager()) { + return Optional.ofNullable(em.find(PlotEntity.class, id)); + } + } + + @Override + public @NotNull Optional findByXAndZAnyWorld(final int x, final int z, final @NotNull String world) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("Plot.findByXAndZAndWorld", PlotEntity.class) + .setParameter("x", x) + .setParameter("z", z) + .setParameter("world", world) + .getResultStream().findFirst(); + } + } + + @Override + public @NotNull Optional findByWorldAndId(@NotNull String world, int x, int z) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("Plot.findByWorldAndId", PlotEntity.class) + .setParameter("world", world) + .setParameter("x", x) + .setParameter("z", z) + .getResultStream().findFirst(); + } + } + + @Override + public @NotNull List findByOwner(@NotNull String ownerUuid) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("Plot.findByOwner", PlotEntity.class) + .setParameter("owner", ownerUuid) + .getResultList(); + } + } + + @Override + public @NotNull List findByWorld(@NotNull String world) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("Plot.findByWorld", PlotEntity.class) + .setParameter("world", world) + .getResultList(); + } + } + + @Override + public void save(@NotNull PlotEntity plot) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + if (plot.getId() == null) { + em.persist(plot); + } else { + em.merge(plot); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) { + tx.rollback(); + } + LOGGER.error( + "Failed to save plot (id={}, world={}, x={}, z={})", + plot.getId(), + plot.getWorld(), + plot.getPlotIdX(), + plot.getPlotIdZ(), + e + ); + } + } + + @Override + public void deleteById(long id) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + PlotEntity ref = em.find(PlotEntity.class, id); + if (ref != null) { + em.remove(ref); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) { + tx.rollback(); + } + LOGGER.error("Failed to delete plot by id (id={})", id, e); + } + } + + @Override + public void deleteRatings(final Plot plot) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + String world = null; + try { + world = plot.getWorldName(); + } catch (Throwable ignored) { + } + if (world == null) { + world = plot.getArea().toString(); + } + PlotEntity pe = em.createNamedQuery("Plot.findByWorldAndId", PlotEntity.class) + .setParameter("world", world) + .setParameter("x", plot.getId().getX()) + .setParameter("z", plot.getId().getY()) + .getResultStream().findFirst().orElse(null); + if (pe != null && pe.getId() != null) { + em.createQuery("DELETE FROM PlotRatingEntity r WHERE r.plotId = :plotId") + .setParameter("plotId", pe.getId()) + .executeUpdate(); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) { + tx.rollback(); + } + LOGGER.error("Failed to delete ratings for plot (plot={})", plot, e); + throw e; + } finally { + em.close(); + } + } + + @Override + public void delete(final Plot plot) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + String world = Optional.of(plot).map(Plot::getWorldName).orElse(Optional + .of(plot) + .map(Plot::getArea) + .map(Object::toString) + .orElse(null)); + PlotEntity pe = em.createNamedQuery("Plot.findByWorldAndId", PlotEntity.class) + .setParameter("world", world) + .setParameter("x", plot.getId().getX()) + .setParameter("z", plot.getId().getY()) + .getResultStream().findFirst().orElse(null); + if (pe != null && pe.getId() != null) { + Long plotId = pe.getId(); + // Delete children first to satisfy FK constraints + em.createNamedQuery("PlotFlag.findByPlot") + .setParameter("plotId", plotId) + .getResultList().forEach(em::remove); + em.createNamedQuery("PlotHelper.deleteByPlotId") + .setParameter("plotId", plotId) + .executeUpdate(); + em.createNamedQuery("PlotTrusted.deleteByPlotId") + .setParameter("plotId", plotId) + .executeUpdate(); + em.createNamedQuery("PlotDenied.deleteByPlotId") + .setParameter("plotId", plotId) + .executeUpdate(); + em.createNamedQuery("PlotRating.deleteByPlot") + .setParameter("plotId", plotId) + .executeUpdate(); + // Remove settings explicitly to mirror legacy behavior and avoid orphan rows + em.createNamedQuery("PlotSettings.deleteByPlot") + .setParameter("plotId", plotId) + .executeUpdate(); + // Remove plot + PlotEntity managed = em.contains(pe) ? pe : em.merge(pe); + em.remove(managed); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) { + tx.rollback(); + } + LOGGER.error("Failed to delete plot (plot={})", plot, e); + } + } + + @Override + public HashMap> getPlots() { + HashMap> worldMap = new HashMap<>(); + Map byId = new HashMap<>(); + Map uuidCache = new HashMap<>(); + try (EntityManager em = emf.createEntityManager()) { + // Load plots + List plots = em.createNamedQuery("Plot.findAll", PlotEntity.class).getResultList(); + for (PlotEntity p : plots) { + String ownerStr = p.getOwner(); + UUID owner; + if (ownerStr == null) { + owner = EVERYONE; + } else { + owner = uuidCache.get(ownerStr); + if (owner == null) { + try { + owner = UUID.fromString(ownerStr); + } catch (IllegalArgumentException ex) { + String base = Settings.UUID.FORCE_LOWERCASE + ? ("OfflinePlayer:" + ownerStr.toLowerCase()) + : ("OfflinePlayer:" + ownerStr); + owner = UUID.nameUUIDFromBytes(base.getBytes(StandardCharsets.UTF_8)); + } + uuidCache.put(ownerStr, owner); + } + } + long time = p.getTimestamp() != null ? p.getTimestamp().getTime() : System.currentTimeMillis(); + PlotId pid = PlotId.of(p.getPlotIdX(), p.getPlotIdZ()); + Plot plot = new Plot( + pid, + owner, + new java.util.HashSet<>(), + new java.util.HashSet<>(), + new java.util.HashSet<>(), + "", + null, + null, + null, + new boolean[]{false, false, false, false}, + time, + p.getId() != null ? p.getId().intValue() : -1 + ); + worldMap.computeIfAbsent(p.getWorld(), k -> new HashMap<>()).put(pid, plot); + if (p.getId() != null) { + byId.put(p.getId(), plot); + } + } + + // Ratings (optional) + if (Settings.Enabled_Components.RATING_CACHE) { + var ratings = em.createNamedQuery("PlotRating.findAll", PlotRatingEntity.class).getResultList(); + for (var r : ratings) { + var plot = byId.get(r.getPlotId()); + if (plot != null) { + plot.getSettings().getRatings().put(UUID.fromString(r.getPlayer()), r.getRating()); + } + } + } + + // Helpers -> trusted + var helpers = em.createNamedQuery("PlotHelper.findAll", PlotMembershipEntity.class).getResultList(); + for (var e : helpers) { + var plot = byId.get(e.getPlotId()); + if (plot != null) { + plot.getTrusted().add(UUID.fromString(e.getUserUuid())); + } + } + + // Trusted -> members + var trusted = em.createNamedQuery("PlotTrusted.findAll", PlotTrustedEntity.class).getResultList(); + for (var e : trusted) { + var plot = byId.get(e.getPlotId()); + if (plot != null) { + plot.getMembers().add(UUID.fromString(e.getUserUuid())); + } + } + + // Denied + var denied = em.createNamedQuery("PlotDenied.findAll", PlotDeniedEntity.class).getResultList(); + for (var e : denied) { + var plot = byId.get(e.getPlotId()); + if (plot != null) { + plot.getDenied().add(UUID.fromString(e.getUserUuid())); + } + } + + // Flags + BlockTypeListFlag.skipCategoryVerification = true; + var flags = em.createNamedQuery("PlotFlag.findAll", PlotFlagEntity.class).getResultList(); + for (var f : flags) { + var plot = byId.get(f.getPlot().getId()); + if (plot != null) { + String flag = f.getFlag(); + String value = f.getFlagValue(); + var registry = com.plotsquared.core.plot.flag.GlobalFlagContainer.getInstance(); + var plotFlag = registry.getFlagFromString(flag); + if (plotFlag == null) { + plot.getFlagContainer().addUnknownFlag(flag, value); + } else { + plot.getFlagContainer().addFlag(plotFlag.parse(value)); + } + } + } + BlockTypeListFlag.skipCategoryVerification = false; + + // Settings + var settings = em.createNamedQuery("PlotSettings.findAll", PlotSettingsEntity.class).getResultList(); + for (var s : settings) { + var plot = byId.get(s.getId()); + if (plot != null) { + if (s.getAlias() != null) { + plot.getSettings().setAlias(s.getAlias()); + } + String pos = s.getPosition(); + if (pos != null) { + String lower = pos.toLowerCase(); + if (!lower.isEmpty() && !"default".equals(lower) && !"0,0,0".equals(lower) && !"center".equals(lower) && !"centre".equals( + lower)) { + plot.getSettings().setPosition(BlockLoc.fromString(pos)); + } + } + Integer m = s.getMerged(); + if (m != null) { + boolean[] merged = new boolean[4]; + for (int i = 0; i < 4; i++) { + merged[3 - i] = ((m & (1 << i)) != 0); + } + plot.getSettings().setMerged(merged); + } + } + } + + return worldMap; + } catch (FlagParseException e) { + LOGGER.error("Failed to load plots due to flag parse error", e); + return worldMap; + } + } + + @Override + public void purgeIds(@NotNull Set ids) { + if (ids.isEmpty()) return; + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + // Convert Integer to Long (plot ids are Long) + Set longIds = new HashSet<>(); + for (Integer i : ids) { + if (i != null) longIds.add(i.longValue()); + } + if (longIds.isEmpty()) { + tx.commit(); + return; + } + // Delete child tables first + em.createNamedQuery("PlotFlag.findAllInPlotIds") + .setParameter("plotIds", longIds) + .getResultList().forEach(em::remove); + em.createNamedQuery("PlotTrusted.deleteAllInPlotIds") + .setParameter("plotIds", longIds) + .executeUpdate(); + em.createNamedQuery("PlotHelper.deleteAllInPlotIds") + .setParameter("plotIds", longIds) + .executeUpdate(); + em.createNamedQuery("PlotDenied.deleteAllInPlotIds") + .setParameter("plotIds", longIds) + .executeUpdate(); + em.createNamedQuery("PlotRating.deleteAllInPlotIds") + .setParameter("plotIds", longIds) + .executeUpdate(); + em.createNamedQuery("PlotSettings.deleteAllInPlotIds") + .setParameter("plotIds", longIds) + .executeUpdate(); + // Finally delete plots + em.createNamedQuery("Plot.deleteAllInIds") + .setParameter("ids", longIds) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to purge plots by ids (ids={})", ids, e); + } + } + + @Override + public void purgeByWorldAndPlotIds(String world, Set plotIds) { + if (world.isEmpty() || plotIds.isEmpty()) return; + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + // Resolve plot ids by fetching candidates in the world and filtering in-memory + List ids = new ArrayList<>(); + List candidates = em.createNamedQuery("Plot.findByWorld", PlotEntity.class) + .setParameter("world", world) + .getResultList(); + HashSet lookup = new HashSet<>(plotIds); + for (PlotEntity p : candidates) { + if (lookup.contains(PlotId.of(p.getPlotIdX(), p.getPlotIdZ())) && p.getId() != null) { + ids.add(p.getId()); + } + } + if (ids.isEmpty()) { + tx.commit(); + return; + } + Set longIds = new HashSet<>(ids); + // Delete child tables first + em.createNamedQuery("PlotFlag.deleteAllInPlotIds") + .setParameter("plotIds", longIds) + .executeUpdate(); + em.createNamedQuery("PlotTrusted.deleteAllInPlotIds") + .setParameter("plotIds", longIds) + .executeUpdate(); + em.createNamedQuery("PlotHelper.deleteAllInPlotIds") + .setParameter("plotIds", longIds) + .executeUpdate(); + em.createNamedQuery("PlotDenied.deleteAllInPlotIds") + .setParameter("plotIds", longIds) + .executeUpdate(); + em.createNamedQuery("PlotRating.deleteAllInPlotIds") + .setParameter("plotIds", longIds) + .executeUpdate(); + em.createNamedQuery("PlotSettings.deleteAllInPlotIds") + .setParameter("plotIds", longIds) + .executeUpdate(); + em.createNamedQuery("Plot.deleteAllInIds") + .setParameter("ids", longIds) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to purge plots by world/id (world={}, plotIds={})", world, plotIds, e); + } + } + + @Override + public void replaceWorld(@NotNull String oldWorld, @NotNull String newWorld) { + replaceWorldAll(oldWorld, newWorld); + } + + @Override + public void replaceWorldInBounds(@NotNull String oldWorld, @NotNull String newWorld, PlotId min, PlotId max) { + replaceWorldInRange(oldWorld, newWorld, min.getX(), min.getY(), max.getX(), max.getY()); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java new file mode 100644 index 0000000000..b94f6272f8 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotSettingsRepositoryJpa.java @@ -0,0 +1,162 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotSettingsEntity; +import com.plotsquared.core.persistence.repository.api.PlotSettingsRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +public class PlotSettingsRepositoryJpa implements PlotSettingsRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotSettingsRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotSettingsRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public @NotNull Optional findByPlotId(long plotId) { + try (EntityManager em = emf.createEntityManager()) { + return Optional.ofNullable(em.find(PlotSettingsEntity.class, plotId)); + } + } + + @Override + public void save(@NotNull PlotSettingsEntity settings) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + if (settings.getId() == null) { + em.persist(settings); + } else { + em.merge(settings); + } + tx.commit(); + } catch (RuntimeException e) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to save plot settings (plotId={})", settings.getId(), e); + } + } + + @Override + public void deleteByPlotId(long plotId) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + PlotSettingsEntity e = em.find(PlotSettingsEntity.class, plotId); + if (e != null) { + em.remove(e); + } + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete plot settings (plotId={})", plotId, ex); + } + } + + @Override + public void updateAlias(long plotId, @NotNull String alias) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("PlotSettings.updateAlias") + .setParameter("plotId", plotId) + .setParameter("alias", alias) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to update alias (plotId={})", plotId, ex); + } + } + + @Override + public void updatePosition(long plotId, @NotNull String position) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("PlotSettings.updatePosition") + .setParameter("plotId", plotId) + .setParameter("pos", position) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to update position (plotId={})", plotId, ex); + } + } + + @Override + public void updateMerged(long plotId, int mergedBitmask) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("PlotSettings.updateMerged") + .setParameter("plotId", plotId) + .setParameter("merged", mergedBitmask) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to update merged (plotId={})", plotId, ex); + } + } + + @Override + public void createDefaultIfAbsent(long plotId, @NotNull String defaultPosition) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + PlotSettingsEntity existing = em.find(PlotSettingsEntity.class, plotId); + if (existing == null) { + PlotSettingsEntity se = new PlotSettingsEntity(); + se.setId(plotId); + // attach plot reference to satisfy FK if needed + com.plotsquared.core.persistence.entity.PlotEntity pe = em.getReference( + com.plotsquared.core.persistence.entity.PlotEntity.class, + plotId + ); + se.setPlot(pe); + se.setPosition(defaultPosition); + em.persist(se); + } + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to create default settings if absent (plotId={})", plotId, ex); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java new file mode 100644 index 0000000000..9dee7b0c2f --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/persistence/repository/jpa/PlotTrustedRepositoryJpa.java @@ -0,0 +1,102 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.persistence.repository.jpa; + +import com.google.inject.Inject; +import com.plotsquared.core.persistence.entity.PlotTrustedEntity; +import com.plotsquared.core.persistence.repository.api.PlotTrustedRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class PlotTrustedRepositoryJpa implements PlotTrustedRepository { + + private static final Logger LOGGER = LogManager.getLogger(PlotTrustedRepositoryJpa.class); + + private final EntityManagerFactory emf; + + @Inject + public PlotTrustedRepositoryJpa(EntityManagerFactory emf) { + this.emf = emf; + } + + @Override + public List findUsers(long plotId) { + try (EntityManager em = emf.createEntityManager()) { + return em.createNamedQuery("PlotTrusted.findUsers", String.class) + .setParameter("plotId", plotId) + .getResultList(); + } + } + + @Override + public void add(long plotId, @NotNull String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + PlotTrustedEntity e = new PlotTrustedEntity(); + e.setPlotId(plotId); + e.setUserUuid(userUuid); + em.persist(e); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to add plot trusted (plotId={}, userUuid={})", plotId, userUuid, ex); + } + } + + @Override + public void remove(long plotId, String userUuid) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("PlotTrusted.deleteByPlotIdAndUserUUID") + .setParameter("plotId", plotId) + .setParameter("uuid", userUuid) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to remove plot trusted (plotId={}, userUuid={})", plotId, userUuid, ex); + } + } + + @Override + public void deleteByPlotId(long plotId) { + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + try (em) { + tx.begin(); + em.createNamedQuery("PlotTrusted.deleteByPlotId") + .setParameter("plotId", plotId) + .executeUpdate(); + tx.commit(); + } catch (RuntimeException ex) { + if (tx.isActive()) tx.rollback(); + LOGGER.error("Failed to delete all plot trusted users (plotId={})", plotId, ex); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java b/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java index 87d3ff5798..931e7eb007 100644 --- a/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java +++ b/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java @@ -24,7 +24,7 @@ import com.plotsquared.core.configuration.caption.Caption; import com.plotsquared.core.configuration.caption.CaptionUtility; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.inject.annotations.ConsoleActor; import com.plotsquared.core.location.Location; @@ -128,7 +128,7 @@ public Location getLocationFull() { @NonNull @Override public UUID getUUID() { - return DBFunc.EVERYONE; + return StaticUUIDs.EVERYONE; } @Override diff --git a/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java b/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java index b0692aa2f1..9b2f6ec19f 100644 --- a/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java +++ b/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java @@ -31,7 +31,6 @@ import com.plotsquared.core.configuration.caption.CaptionUtility; import com.plotsquared.core.configuration.caption.LocaleHolder; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.location.Location; import com.plotsquared.core.permissions.NullPermissionProfile; @@ -46,10 +45,10 @@ import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.plot.world.SinglePlotArea; import com.plotsquared.core.plot.world.SinglePlotAreaManager; +import com.plotsquared.core.services.api.PlayerMetaService; import com.plotsquared.core.synchronization.LockRepository; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.query.PlotQuery; -import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.world.gamemode.GameMode; @@ -83,6 +82,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; /** * The abstract class supporting {@code BukkitPlayer} and {@code SpongePlayer}. @@ -683,88 +683,87 @@ public Set getPlots(String world) { public void populatePersistentMetaMap() { if (Settings.Enabled_Components.PERSISTENT_META) { - DBFunc.getPersistentMeta(getUUID(), new RunnableVal<>() { - @Override - public void run(Map value) { - try { - PlotPlayer.this.metaMap = value; - if (value.isEmpty()) { - return; - } + PlayerMetaService service = + PlotSquared.platform().injector().getInstance(PlayerMetaService.class); + Consumer> resultConsumer = value -> { + try { + PlotPlayer.this.metaMap = value; + if (value.isEmpty()) { + return; + } - if (PlotPlayer.this.getAttribute("debug")) { - debugModeEnabled.add(PlotPlayer.this); - } + if (PlotPlayer.this.getAttribute("debug")) { + debugModeEnabled.add(PlotPlayer.this); + } - if (!Settings.Teleport.ON_LOGIN) { - return; - } - PlotAreaManager manager = PlotPlayer.this.plotAreaManager; + if (!Settings.Teleport.ON_LOGIN) { + return; + } + PlotAreaManager manager = PlotPlayer.this.plotAreaManager; - if (!(manager instanceof SinglePlotAreaManager)) { - return; - } - PlotArea area = ((SinglePlotAreaManager) manager).getArea(); - boolean V2 = false; - byte[] arr = PlotPlayer.this.getPersistentMeta("quitLoc"); + if (!(manager instanceof SinglePlotAreaManager)) { + return; + } + PlotArea area = ((SinglePlotAreaManager) manager).getArea(); + boolean V2 = false; + byte[] arr = PlotPlayer.this.getPersistentMeta("quitLoc"); + if (arr == null) { + arr = PlotPlayer.this.getPersistentMeta("quitLocV2"); if (arr == null) { - arr = PlotPlayer.this.getPersistentMeta("quitLocV2"); - if (arr == null) { - return; - } - V2 = true; - removePersistentMeta("quitLocV2"); - } else { - removePersistentMeta("quitLoc"); - } - - if (!getMeta("teleportOnLogin", true)) { - return; - } - ByteBuffer quitWorld = ByteBuffer.wrap(arr); - final int plotX = quitWorld.getShort(); - final int plotZ = quitWorld.getShort(); - PlotId id = PlotId.of(plotX, plotZ); - int x = quitWorld.getInt(); - int y = V2 ? quitWorld.getShort() : (quitWorld.get() & 0xFF); - int z = quitWorld.getInt(); - Plot plot = area.getOwnedPlot(id); - - if (plot == null) { return; } + V2 = true; + removePersistentMeta("quitLocV2"); + } else { + removePersistentMeta("quitLoc"); + } - final Location location = Location.at(plot.getWorldName(), x, y, z); - if (plot.isLoaded()) { - TaskManager.runTask(() -> { - if (getMeta("teleportOnLogin", true)) { - teleport(location, TeleportCause.LOGIN); - sendMessage( - TranslatableCaption.of("teleport.teleported_to_plot")); - } - }); - } else if (!PlotSquared.get().isMainThread(Thread.currentThread())) { + if (!getMeta("teleportOnLogin", true)) { + return; + } + ByteBuffer quitWorld = ByteBuffer.wrap(arr); + final int plotX = quitWorld.getShort(); + final int plotZ = quitWorld.getShort(); + PlotId id = PlotId.of(plotX, plotZ); + int x = quitWorld.getInt(); + int y = V2 ? quitWorld.getShort() : (quitWorld.get() & 0xFF); + int z = quitWorld.getInt(); + Plot plot = area.getOwnedPlot(id); + + if (plot == null) { + return; + } + + final Location location = Location.at(plot.getWorldName(), x, y, z); + if (plot.isLoaded()) { + TaskManager.runTask(() -> { if (getMeta("teleportOnLogin", true)) { - plot.teleportPlayer( - PlotPlayer.this, - result -> TaskManager.runTask(() -> { - if (getMeta("teleportOnLogin", true)) { - if (plot.isLoaded()) { - teleport(location, TeleportCause.LOGIN); - sendMessage(TranslatableCaption - .of("teleport.teleported_to_plot")); - } - } - }) - ); + teleport(location, TeleportCause.LOGIN); + sendMessage( + TranslatableCaption.of("teleport.teleported_to_plot")); } + }); + } else if (!PlotSquared.get().isMainThread(Thread.currentThread())) { + if (getMeta("teleportOnLogin", true)) { + plot.teleportPlayer( + PlotPlayer.this, + result -> TaskManager.runTask(() -> { + if (getMeta("teleportOnLogin", true)) { + if (plot.isLoaded()) { + teleport(location, TeleportCause.LOGIN); + sendMessage(TranslatableCaption + .of("teleport.teleported_to_plot")); + } + } + }) + ); } - } catch (Throwable e) { - LOGGER.error("Error populating persistent meta for player {}", PlotPlayer.this.getName(), e); } + } catch (Throwable e) { + LOGGER.error("Error populating persistent meta for player {}", PlotPlayer.this.getName(), e); } - } - ); + }; + service.getPersistentMeta(getUUID(), resultConsumer); } } @@ -775,7 +774,9 @@ byte[] getPersistentMeta(String key) { Object removePersistentMeta(String key) { final Object old = this.metaMap.remove(key); if (Settings.Enabled_Components.PERSISTENT_META) { - DBFunc.removePersistentMeta(getUUID(), key); + PlayerMetaService service = + PlotSquared.platform().injector().getInstance(PlayerMetaService.class); + service.removePersistentMeta(getUUID(), key); } return old; } @@ -852,7 +853,9 @@ void setPersistentMeta(String key, byte[] value) { boolean delete = hasPersistentMeta(key); this.metaMap.put(key, value); if (Settings.Enabled_Components.PERSISTENT_META) { - DBFunc.addPersistentMeta(getUUID(), key, value, delete); + PlayerMetaService service = + PlotSquared.platform().injector().getInstance(PlayerMetaService.class); + service.addPersistentMeta(getUUID(), key, value, delete); } } diff --git a/Core/src/main/java/com/plotsquared/core/plot/Plot.java b/Core/src/main/java/com/plotsquared/core/plot/Plot.java index 655dc6d3f5..170f53c01a 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -28,7 +28,7 @@ import com.plotsquared.core.configuration.caption.CaptionUtility; import com.plotsquared.core.configuration.caption.StaticCaption; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.events.PlayerTeleportToPlotEvent; import com.plotsquared.core.events.Result; import com.plotsquared.core.events.TeleportCause; @@ -53,6 +53,10 @@ import com.plotsquared.core.plot.schematic.Schematic; import com.plotsquared.core.plot.world.SinglePlotArea; import com.plotsquared.core.queue.QueueCoordinator; +import com.plotsquared.core.services.api.FlagService; +import com.plotsquared.core.services.api.MemberService; +import com.plotsquared.core.services.api.PlotService; +import com.plotsquared.core.services.api.RatingService; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.PlayerManager; @@ -676,7 +680,7 @@ public boolean isOwnerAbs(final @Nullable UUID uuid) { */ public @Nullable UUID getOwner() { if (this.getFlag(ServerPlotFlag.class)) { - return DBFunc.SERVER; + return StaticUUIDs.SERVER; } return this.getOwnerAbs(); } @@ -692,17 +696,18 @@ public void setOwner(final @NonNull UUID owner) { this.getPlotModificationManager().create(); return; } + PlotService service = PlotSquared.platform().injector().getInstance(PlotService.class); if (!isMerged()) { if (!owner.equals(this.getOwnerAbs())) { this.setOwnerAbs(owner); - DBFunc.setOwner(this, owner); + service.setOwner(this, owner); } return; } for (final Plot current : getConnectedPlots()) { if (!owner.equals(current.getOwnerAbs())) { current.setOwnerAbs(owner); - DBFunc.setOwner(current, owner); + service.setOwner(current, owner); } } } @@ -742,10 +747,10 @@ public boolean isAdded(final @NonNull UUID uuid) { if (getMembers().contains(uuid)) { return isOnline(); } - if (getTrusted().contains(uuid) || getTrusted().contains(DBFunc.EVERYONE)) { + if (getTrusted().contains(uuid) || getTrusted().contains(StaticUUIDs.EVERYONE)) { return true; } - if (getMembers().contains(DBFunc.EVERYONE)) { + if (getMembers().contains(StaticUUIDs.EVERYONE)) { return isOnline(); } return false; @@ -758,7 +763,7 @@ public boolean isAdded(final @NonNull UUID uuid) { * @return {@code false} if the player is allowed to enter the plot, else {@code true} */ public boolean isDenied(final @NonNull UUID uuid) { - return this.denied != null && (this.denied.contains(DBFunc.EVERYONE) && !this.isAdded(uuid) || !this.isAdded(uuid) && this.denied + return this.denied != null && (this.denied.contains(StaticUUIDs.EVERYONE) && !this.isAdded(uuid) || !this.isAdded(uuid) && this.denied .contains(uuid)); } @@ -1071,7 +1076,7 @@ public void setMembers(final @NonNull Set uuids) { public void addDenied(final @NonNull UUID uuid) { for (final Plot current : getConnectedPlots()) { if (current.getDenied().add(uuid)) { - DBFunc.setDenied(current, uuid); + PlotSquared.platform().injector().getInstance(MemberService.class).setDenied(current, uuid); } } } @@ -1084,7 +1089,7 @@ public void addDenied(final @NonNull UUID uuid) { public void addTrusted(final @NonNull UUID uuid) { for (final Plot current : getConnectedPlots()) { if (current.getTrusted().add(uuid)) { - DBFunc.setTrusted(current, uuid); + PlotSquared.platform().injector().getInstance(MemberService.class).setTrusted(current, uuid); } } } @@ -1097,7 +1102,7 @@ public void addTrusted(final @NonNull UUID uuid) { public void addMember(final @NonNull UUID uuid) { for (final Plot current : getConnectedPlots()) { if (current.getMembers().add(uuid)) { - DBFunc.setMember(current, uuid); + PlotSquared.platform().injector().getInstance(MemberService.class).setMember(current, uuid); } } } @@ -1115,17 +1120,18 @@ public boolean setOwner(UUID owner, PlotPlayer initiator) { this.getPlotModificationManager().create(); return true; } + PlotService service = PlotSquared.platform().injector().getInstance(PlotService.class); if (!isMerged()) { if (!owner.equals(this.getOwnerAbs())) { this.setOwnerAbs(owner); - DBFunc.setOwner(this, owner); + service.setOwner(this, owner); } return true; } for (final Plot current : getConnectedPlots()) { if (!owner.equals(current.getOwnerAbs())) { current.setOwnerAbs(owner); - DBFunc.setOwner(current, owner); + service.setOwner(current, owner); } } return true; @@ -1168,7 +1174,7 @@ public boolean setFlag(final @NonNull PlotFlag flag) { for (final Plot plot : this.getConnectedPlots()) { plot.getFlagContainer().addFlag(flag); plot.reEnter(); - DBFunc.setFlag(plot, flag); + PlotSquared.platform().injector().getInstance(FlagService.class).setFlag(plot, flag); } return true; } @@ -1258,7 +1264,7 @@ public boolean removeFlag(final @NonNull PlotFlag flag) { continue; } plot.reEnter(); - DBFunc.removeFlag(plot, flag); + PlotSquared.platform().injector().getInstance(FlagService.class).removeFlag(plot, flag); removed = true; } return removed; @@ -1349,7 +1355,7 @@ public boolean unclaim() { } getArea().removePlot(getId()); - DBFunc.delete(current); + PlotSquared.platform().injector().getInstance(PlotService.class).delete(current); current.setOwnerAbs(null); current.settings = null; current.clearCache(); @@ -1549,10 +1555,11 @@ public void setHome(BlockLoc location) { } plot.getSettings().setPosition(location); if (location != null) { - DBFunc.setPosition(plot, plot.getSettings().getPosition().toString()); + PlotSquared.platform().injector().getInstance(PlotService.class).setPosition(plot, + plot.getSettings().getPosition().toString()); return; } - DBFunc.setPosition(plot, null); + PlotSquared.platform().injector().getInstance(PlotService.class).setPosition(plot, null); } /** @@ -1707,7 +1714,7 @@ public boolean addRating(UUID uuid, Rating rating) { } int aggregate = rating.getAggregate(); baseSettings.getRatings().put(uuid, aggregate); - DBFunc.setRating(base, uuid, aggregate); + PlotSquared.platform().injector().getInstance(RatingService.class).setRating(base, uuid, aggregate); return true; } @@ -1718,7 +1725,8 @@ public void clearRatings() { Plot base = this.getBasePlot(false); PlotSettings baseSettings = base.getSettings(); if (baseSettings.getRatings() != null && !baseSettings.getRatings().isEmpty()) { - DBFunc.deleteRatings(base); + PlotService plotService = PlotSquared.platform().injector().getInstance(PlotService.class); + plotService.deleteRatings(base); baseSettings.setRatings(null); } } @@ -1901,7 +1909,9 @@ public CompletableFuture swapData(Plot plot) { this.area.addPlotAbs(this); plot.area.addPlotAbs(plot); // Swap database - return DBFunc.swapPlots(plot, this); + PlotService service = + PlotSquared.platform().injector().getInstance(PlotService.class); + return service.swapPlots(plot, this); } /** @@ -1924,7 +1934,8 @@ public boolean moveData(Plot plot, Runnable whenDone) { this.id = plot.getId(); this.area.addPlotAbs(this); clearCache(); - DBFunc.movePlot(this, plot); + PlotService service = PlotSquared.platform().injector().getInstance(PlotService.class); + service.movePlot(this, plot); TaskManager.runTaskLater(whenDone, TaskTime.ticks(1L)); return true; } @@ -2026,7 +2037,7 @@ public String toString() { * @return success or not */ public boolean removeDenied(UUID uuid) { - if (uuid == DBFunc.EVERYONE && !denied.contains(uuid)) { + if (uuid == StaticUUIDs.EVERYONE && !denied.contains(uuid)) { boolean result = false; for (UUID other : new HashSet<>(getDenied())) { result = rmvDenied(other) || result; @@ -2039,7 +2050,7 @@ public boolean removeDenied(UUID uuid) { private boolean rmvDenied(UUID uuid) { for (Plot current : this.getConnectedPlots()) { if (current.getDenied().remove(uuid)) { - DBFunc.removeDenied(current, uuid); + PlotSquared.platform().injector().getInstance(MemberService.class).removeDenied(current, uuid); } else { return false; } @@ -2055,7 +2066,7 @@ private boolean rmvDenied(UUID uuid) { * @return success or not */ public boolean removeTrusted(UUID uuid) { - if (uuid == DBFunc.EVERYONE && !trusted.contains(uuid)) { + if (uuid == StaticUUIDs.EVERYONE && !trusted.contains(uuid)) { boolean result = false; for (UUID other : new HashSet<>(getTrusted())) { result = rmvTrusted(other) || result; @@ -2068,7 +2079,7 @@ public boolean removeTrusted(UUID uuid) { private boolean rmvTrusted(UUID uuid) { for (Plot plot : this.getConnectedPlots()) { if (plot.getTrusted().remove(uuid)) { - DBFunc.removeTrusted(plot, uuid); + PlotSquared.platform().injector().getInstance(MemberService.class).removeTrusted(plot, uuid); } else { return false; } @@ -2087,7 +2098,7 @@ public boolean removeMember(UUID uuid) { if (this.members == null) { return false; } - if (uuid == DBFunc.EVERYONE && !members.contains(uuid)) { + if (uuid == StaticUUIDs.EVERYONE && !members.contains(uuid)) { boolean result = false; for (UUID other : new HashSet<>(this.members)) { result = rmvMember(other) || result; @@ -2100,7 +2111,7 @@ public boolean removeMember(UUID uuid) { private boolean rmvMember(UUID uuid) { for (Plot current : this.getConnectedPlots()) { if (current.getMembers().remove(uuid)) { - DBFunc.removeMember(current, uuid); + PlotSquared.platform().injector().getInstance(MemberService.class).removeMember(current, uuid); } else { return false; } @@ -2164,7 +2175,7 @@ public void setAlias(String alias) { return; } current.getSettings().setAlias(alias); - DBFunc.setAlias(current, alias); + PlotSquared.platform().injector().getInstance(PlotService.class).setAlias(current, alias); } } @@ -2197,7 +2208,7 @@ public void setMerged(Direction direction, boolean value) { } this.connectedCache = null; } - DBFunc.setMerged(this, this.getSettings().getMerged()); + PlotSquared.platform().injector().getInstance(PlotService.class).setMerged(this, this.getSettings().getMerged()); } } @@ -2227,7 +2238,7 @@ public boolean[] getMerged() { */ public void setMerged(boolean[] merged) { this.getSettings().setMerged(merged); - DBFunc.setMerged(this, merged); + PlotSquared.platform().injector().getInstance(PlotService.class).setMerged(this, merged); clearCache(); } @@ -2406,10 +2417,10 @@ private void computeDirectMerged(Set queueCache, Deque frontier, Dir // invalid merge if (tmp.isOwnerAbs(this.getOwnerAbs())) { tmp.getSettings().setMerged(direction.opposite(), true); - DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); + PlotSquared.platform().injector().getInstance(PlotService.class).setMerged(tmp, tmp.getSettings().getMerged()); } else { this.getSettings().setMerged(direction, false); - DBFunc.setMerged(this, this.getSettings().getMerged()); + PlotSquared.platform().injector().getInstance(PlotService.class).setMerged(this, this.getSettings().getMerged()); } } queueCache.add(tmp); @@ -2919,7 +2930,7 @@ public CompletableFuture format(final Caption iInfo, PlotPlayer play Component owner; if (this.getOwner() == null) { owner = Component.text("unowned"); - } else if (this.getOwner().equals(DBFunc.SERVER)) { + } else if (this.getOwner().equals(StaticUUIDs.SERVER)) { owner = Component.text(MINI_MESSAGE.stripTags(TranslatableCaption .of("info.server") .getComponent(player))); @@ -3036,7 +3047,7 @@ public CompletableFuture format(final Caption iInfo, PlotPlayer play } else if (Settings.Enabled_Components.RATING_CACHE) { rating = new HashMap<>(); } else { - rating = DBFunc.getRatings(this); + rating = PlotSquared.platform().injector().getInstance(RatingService.class).getRatings(this); } int size = 1; if (!Settings.Ratings.CATEGORIES.isEmpty()) { diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotCluster.java b/Core/src/main/java/com/plotsquared/core/plot/PlotCluster.java index 3bb87fc3b6..221d15e26d 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotCluster.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotCluster.java @@ -19,7 +19,7 @@ package com.plotsquared.core.plot; import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.location.BlockLoc; import com.plotsquared.core.location.Location; import com.plotsquared.core.util.RegionUtil; @@ -103,13 +103,13 @@ public boolean isOwner(UUID uuid) { public boolean isAdded(UUID uuid) { return this.owner.equals(uuid) || this.invited.contains(uuid) || this.invited - .contains(DBFunc.EVERYONE) || this.helpers.contains(uuid) || this.helpers - .contains(DBFunc.EVERYONE); + .contains(StaticUUIDs.EVERYONE) || this.helpers.contains(uuid) || this.helpers + .contains(StaticUUIDs.EVERYONE); } public boolean hasHelperRights(UUID uuid) { return this.owner.equals(uuid) || this.helpers.contains(uuid) || this.helpers - .contains(DBFunc.EVERYONE); + .contains(StaticUUIDs.EVERYONE); } public String getName() { diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java b/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java index cc2f1f0709..f917cb66f7 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotModificationManager.java @@ -25,7 +25,6 @@ import com.plotsquared.core.configuration.caption.Caption; import com.plotsquared.core.configuration.caption.LocaleHolder; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.PlotComponentSetEvent; import com.plotsquared.core.events.PlotMergeEvent; import com.plotsquared.core.events.PlotUnlinkEvent; @@ -38,6 +37,9 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.flag.PlotFlag; import com.plotsquared.core.queue.QueueCoordinator; +import com.plotsquared.core.services.api.FlagService; +import com.plotsquared.core.services.api.MemberService; +import com.plotsquared.core.services.api.PlotService; import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskTime; import com.sk89q.worldedit.function.pattern.Pattern; @@ -124,9 +126,9 @@ public CompletableFuture copy(final @NonNull Plot destination, @Nullabl for (final PlotFlag flag : existingFlags) { final PlotFlag newFlag = other.getFlagContainer().queryLocal(flag.getClass()); if (other.getFlagContainer().queryLocal(flag.getClass()) == null) { - DBFunc.removeFlag(other, flag); + PlotSquared.platform().injector().getInstance(FlagService.class).removeFlag(other, flag); } else { - DBFunc.setFlag(other, newFlag); + PlotSquared.platform().injector().getInstance(FlagService.class).setFlag(other, newFlag); } } } @@ -136,19 +138,19 @@ public CompletableFuture copy(final @NonNull Plot destination, @Nullabl if (plot.members != null && !plot.members.isEmpty()) { other.members = plot.members; for (UUID member : plot.members) { - DBFunc.setMember(other, member); + PlotSquared.platform().injector().getInstance(MemberService.class).setMember(other, member); } } if (plot.trusted != null && !plot.trusted.isEmpty()) { other.trusted = plot.trusted; for (UUID trusted : plot.trusted) { - DBFunc.setTrusted(other, trusted); + PlotSquared.platform().injector().getInstance(MemberService.class).setTrusted(other, trusted); } } if (plot.denied != null && !plot.denied.isEmpty()) { other.denied = plot.denied; for (UUID denied : plot.denied) { - DBFunc.setDenied(other, denied); + PlotSquared.platform().injector().getInstance(MemberService.class).setDenied(other, denied); } } } @@ -516,7 +518,8 @@ public boolean create(final @NonNull UUID uuid, final boolean notify) { this.plot.getDenied().clear(); this.plot.settings = new PlotSettings(); if (this.plot.getArea().addPlot(this.plot)) { - DBFunc.createPlotAndSettings(this.plot, () -> { + final PlotService service = PlotSquared.platform().injector().getInstance(PlotService.class); + service.createPlotAndSettings(this.plot, () -> { PlotArea plotworld = plot.getArea(); if (notify && plotworld.isAutoMerge()) { final PlotPlayer player = PlotSquared.platform().playerManager().getPlayerIfExists(uuid); diff --git a/Core/src/main/java/com/plotsquared/core/plot/comment/CommentInbox.java b/Core/src/main/java/com/plotsquared/core/plot/comment/CommentInbox.java index 1e0894538f..c10a47f79f 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/comment/CommentInbox.java +++ b/Core/src/main/java/com/plotsquared/core/plot/comment/CommentInbox.java @@ -18,9 +18,10 @@ */ package com.plotsquared.core.plot.comment; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.services.api.CommentService; import com.plotsquared.core.util.task.RunnableVal; import java.util.List; @@ -91,14 +92,14 @@ public boolean canModify(Plot plot, PlotPlayer player) { * @param comment the comment to remove */ public void removeComment(Plot plot, PlotComment comment) { - DBFunc.removeComment(plot, comment); + PlotSquared.platform().injector().getInstance(CommentService.class).removeComment(plot, comment); } /** * @param plot plot */ public void clearInbox(Plot plot) { - DBFunc.clearInbox(plot, toString()); + PlotSquared.platform().injector().getInstance(CommentService.class).clearInbox(plot, toString()); } } diff --git a/Core/src/main/java/com/plotsquared/core/plot/comment/InboxOwner.java b/Core/src/main/java/com/plotsquared/core/plot/comment/InboxOwner.java index f872d32f4a..08bce323e6 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/comment/InboxOwner.java +++ b/Core/src/main/java/com/plotsquared/core/plot/comment/InboxOwner.java @@ -18,12 +18,12 @@ */ package com.plotsquared.core.plot.comment; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.services.api.CommentService; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; -import java.util.ArrayList; import java.util.List; public class InboxOwner extends CommentInbox { @@ -36,19 +36,12 @@ public boolean getComments(final Plot plot, final RunnableVal> TaskManager.runTask(whenDone); return true; } - DBFunc.getComments(plot, toString(), new RunnableVal<>() { - @Override - public void run(List value) { - whenDone.value = value; - if (value != null) { - for (PlotComment comment : value) { - plot.getPlotCommentContainer().addComment(comment); - } - } else { - plot.getPlotCommentContainer().setComments(new ArrayList<>()); - } - TaskManager.runTask(whenDone); + PlotSquared.platform().injector().getInstance(CommentService.class).getComments(plot, toString(), value -> { + whenDone.value = value; + for (PlotComment comment : value) { + plot.getPlotCommentContainer().addComment(comment); } + TaskManager.runTask(whenDone); }); return true; } @@ -59,7 +52,7 @@ public boolean addComment(Plot plot, PlotComment comment) { return false; } plot.getPlotCommentContainer().addComment(comment); - DBFunc.setComment(plot, comment); + PlotSquared.platform().injector().getInstance(CommentService.class).setComment(plot, comment); return true; } diff --git a/Core/src/main/java/com/plotsquared/core/plot/comment/InboxPublic.java b/Core/src/main/java/com/plotsquared/core/plot/comment/InboxPublic.java index 53484e9cab..22323c18d0 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/comment/InboxPublic.java +++ b/Core/src/main/java/com/plotsquared/core/plot/comment/InboxPublic.java @@ -18,8 +18,9 @@ */ package com.plotsquared.core.plot.comment; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.services.api.CommentService; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; @@ -35,17 +36,12 @@ public boolean getComments(final Plot plot, final RunnableVal> TaskManager.runTask(whenDone); return true; } - DBFunc.getComments(plot, toString(), new RunnableVal<>() { - @Override - public void run(List value) { - whenDone.value = value; - if (value != null) { - for (PlotComment comment : value) { - plot.getPlotCommentContainer().addComment(comment); - } - } - TaskManager.runTask(whenDone); + PlotSquared.platform().injector().getInstance(CommentService.class).getComments(plot, toString(), value -> { + whenDone.value = value; + for (PlotComment comment : value) { + plot.getPlotCommentContainer().addComment(comment); } + TaskManager.runTask(whenDone); }); return true; } @@ -53,7 +49,7 @@ public void run(List value) { @Override public boolean addComment(Plot plot, PlotComment comment) { plot.getPlotCommentContainer().addComment(comment); - DBFunc.setComment(plot, comment); + PlotSquared.platform().injector().getInstance(CommentService.class).setComment(plot, comment); return true; } diff --git a/Core/src/main/java/com/plotsquared/core/plot/comment/InboxReport.java b/Core/src/main/java/com/plotsquared/core/plot/comment/InboxReport.java index c8c5cc07fb..81007f1c4b 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/comment/InboxReport.java +++ b/Core/src/main/java/com/plotsquared/core/plot/comment/InboxReport.java @@ -18,8 +18,9 @@ */ package com.plotsquared.core.plot.comment; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.services.api.CommentService; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; @@ -29,12 +30,9 @@ public class InboxReport extends CommentInbox { @Override public boolean getComments(Plot plot, final RunnableVal> whenDone) { - DBFunc.getComments(plot, toString(), new RunnableVal<>() { - @Override - public void run(List value) { - whenDone.value = value; - TaskManager.runTask(whenDone); - } + PlotSquared.platform().injector().getInstance(CommentService.class).getComments(plot, toString(), value -> { + whenDone.value = value; + TaskManager.runTask(whenDone); }); return true; } @@ -44,7 +42,7 @@ public boolean addComment(Plot plot, PlotComment comment) { if (plot.getOwner() == null) { return false; } - DBFunc.setComment(plot, comment); + PlotSquared.platform().injector().getInstance(CommentService.class).setComment(plot, comment); return true; } diff --git a/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java b/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java index 81b0555e1b..9605f992a3 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java @@ -22,7 +22,7 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.caption.Caption; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.util.StaticUUIDs; import com.plotsquared.core.events.PlotFlagAddEvent; import com.plotsquared.core.events.PlotUnlinkEvent; import com.plotsquared.core.events.Result; @@ -467,7 +467,7 @@ public long getAge(UUID uuid, final boolean shouldDeleteUnknownOwner) { } public long getAge(Plot plot, final boolean shouldDeleteUnknownOwner) { - if (!plot.hasOwner() || Objects.equals(DBFunc.EVERYONE, plot.getOwner()) + if (!plot.hasOwner() || Objects.equals(StaticUUIDs.EVERYONE, plot.getOwner()) || PlotSquared.platform().playerManager().getPlayerIfExists(plot.getOwner()) != null || plot.getRunning() > 0) { return 0; } diff --git a/Core/src/main/java/com/plotsquared/core/services/api/ClusterService.java b/Core/src/main/java/com/plotsquared/core/services/api/ClusterService.java new file mode 100644 index 0000000000..647e901550 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/ClusterService.java @@ -0,0 +1,50 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.api; + +import com.plotsquared.core.plot.PlotCluster; +import com.plotsquared.core.plot.PlotId; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Set; +import java.util.UUID; + +public interface ClusterService { + + void createCluster(PlotCluster cluster); + + void resizeCluster(PlotCluster cluster, PlotId min, PlotId max); + + void removeHelper(PlotCluster cluster, UUID uuid); + + void delete(PlotCluster cluster); + + HashMap> getClusters(); + + void setPosition(PlotCluster cluster, String position); + + void setInvited(PlotCluster cluster, UUID uuid); + + void removeInvited(PlotCluster cluster, UUID uuid); + + void setHelper(PlotCluster cluster, UUID uuid); + + void replaceWorld(String oldWorld, String newWorld, @Nullable PlotId min, PlotId max); +} diff --git a/Core/src/main/java/com/plotsquared/core/services/api/CommentService.java b/Core/src/main/java/com/plotsquared/core/services/api/CommentService.java new file mode 100644 index 0000000000..6232bf390e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/CommentService.java @@ -0,0 +1,36 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.api; + +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.comment.PlotComment; + +import java.util.List; +import java.util.function.Consumer; + +public interface CommentService { + + void removeComment(Plot plot, PlotComment comment); + + void setComment(Plot plot, PlotComment comment); + + void clearInbox(Plot plot, String inbox); + + void getComments(Plot plot, String inbox, Consumer> whenDone); +} diff --git a/Core/src/main/java/com/plotsquared/core/services/api/FlagService.java b/Core/src/main/java/com/plotsquared/core/services/api/FlagService.java new file mode 100644 index 0000000000..dbb566057f --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/FlagService.java @@ -0,0 +1,29 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.api; + +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.flag.PlotFlag; + +public interface FlagService { + + void setFlag(Plot plot, PlotFlag flag); + + void removeFlag(Plot plot, PlotFlag flag); +} diff --git a/Core/src/main/java/com/plotsquared/core/services/api/MemberService.java b/Core/src/main/java/com/plotsquared/core/services/api/MemberService.java new file mode 100644 index 0000000000..1ac0a1f582 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/MemberService.java @@ -0,0 +1,38 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.api; + +import com.plotsquared.core.plot.Plot; + +import java.util.UUID; + +public interface MemberService { + + void removeTrusted(Plot plot, UUID uuid); + + void removeMember(Plot plot, UUID uuid); + + void setTrusted(Plot plot, UUID uuid); + + void setMember(Plot plot, UUID uuid); + + void removeDenied(Plot plot, UUID uuid); + + void setDenied(Plot plot, UUID uuid); +} diff --git a/Core/src/main/java/com/plotsquared/core/services/api/PlayerMetaService.java b/Core/src/main/java/com/plotsquared/core/services/api/PlayerMetaService.java new file mode 100644 index 0000000000..69fd86a0c1 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/PlayerMetaService.java @@ -0,0 +1,41 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.api; + +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +/** + * Manages player metadata + * + * @version 1.0.0 + * @since 8.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +public interface PlayerMetaService { + + void addPersistentMeta(UUID uuid, String key, byte[] meta, boolean delete); + + void getPersistentMeta(UUID uuid, Consumer> result); + + void removePersistentMeta(UUID uuid, String key); + +} diff --git a/Core/src/main/java/com/plotsquared/core/services/api/PlotService.java b/Core/src/main/java/com/plotsquared/core/services/api/PlotService.java new file mode 100644 index 0000000000..227810dbc3 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/PlotService.java @@ -0,0 +1,65 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.api; + +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotId; + +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +public interface PlotService { + + CompletableFuture swapPlots(Plot plot1, Plot plot2); + + void movePlot(Plot originalPlot, Plot newPlot); + + void setOwner(Plot plot, UUID uuid); + + void createPlotsAndData(List plots, Runnable whenDone); + + void createPlotSafe( + final Plot plot, final Runnable success, + final Runnable failure + ); + + void createPlotAndSettings(Plot plot, Runnable whenDone); + + void delete(Plot plot); + + @Deprecated(forRemoval = true, since = "8.0.0") + void deleteRatings(Plot plot); + + HashMap> getPlots(); + + void setMerged(Plot plot, boolean[] merged); + + void setAlias(Plot plot, String alias); + + void setPosition(Plot plot, String position); + + void purgeIds(Set uniqueIds); + + void purge(PlotArea area, Set plotIds); + +} diff --git a/Core/src/main/java/com/plotsquared/core/services/api/RatingService.java b/Core/src/main/java/com/plotsquared/core/services/api/RatingService.java new file mode 100644 index 0000000000..b15674bee7 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/RatingService.java @@ -0,0 +1,31 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.api; + +import com.plotsquared.core.plot.Plot; + +import java.util.HashMap; +import java.util.UUID; + +public interface RatingService { + + HashMap getRatings(Plot plot); + + void setRating(Plot plot, UUID rater, int value); +} diff --git a/Core/src/main/java/com/plotsquared/core/services/api/package-info.java b/Core/src/main/java/com/plotsquared/core/services/api/package-info.java new file mode 100644 index 0000000000..7821dbd4bf --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/api/package-info.java @@ -0,0 +1,12 @@ +/** + * This package contains interfaces for various services provided by PlotSquared. + * + * @version 1.0.0 + * @since 8.0.0 + * @author TheMeinerLP + * @author IntellectualSites + */ +@NotNullByDefault +package com.plotsquared.core.services.api; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java new file mode 100644 index 0000000000..18937ebfa0 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/config/ServiceModule.java @@ -0,0 +1,50 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.config; + +import com.google.inject.AbstractModule; +import com.plotsquared.core.services.api.ClusterService; +import com.plotsquared.core.services.api.CommentService; +import com.plotsquared.core.services.api.FlagService; +import com.plotsquared.core.services.api.MemberService; +import com.plotsquared.core.services.api.PlayerMetaService; +import com.plotsquared.core.services.api.PlotService; +import com.plotsquared.core.services.api.RatingService; +import com.plotsquared.core.services.impl.ClusterDefaultService; +import com.plotsquared.core.services.impl.CommentDefaultService; +import com.plotsquared.core.services.impl.FlagDefaultService; +import com.plotsquared.core.services.impl.MemberDefaultService; +import com.plotsquared.core.services.impl.PlayerMetaDefaultService; +import com.plotsquared.core.services.impl.PlotDefaultService; +import com.plotsquared.core.services.impl.RatingDefaultService; + +public class ServiceModule extends AbstractModule { + + @Override + protected void configure() { + bind(PlayerMetaService.class).to(PlayerMetaDefaultService.class); + bind(PlotService.class).to(PlotDefaultService.class); + bind(ClusterService.class).to(ClusterDefaultService.class); + bind(FlagService.class).to(FlagDefaultService.class); + bind(CommentService.class).to(CommentDefaultService.class); + bind(MemberService.class).to(MemberDefaultService.class); + bind(RatingService.class).to(RatingDefaultService.class); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/ClusterDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/ClusterDefaultService.java new file mode 100644 index 0000000000..0cda624458 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/impl/ClusterDefaultService.java @@ -0,0 +1,211 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.impl; + +import com.plotsquared.core.persistence.entity.ClusterEntity; +import com.plotsquared.core.persistence.repository.api.ClusterHelperRepository; +import com.plotsquared.core.persistence.repository.api.ClusterInvitedRepository; +import com.plotsquared.core.persistence.repository.api.ClusterRepository; +import com.plotsquared.core.persistence.repository.api.ClusterSettingsRepository; +import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.plot.PlotCluster; +import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.services.api.ClusterService; +import jakarta.inject.Inject; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; + +public class ClusterDefaultService implements ClusterService { + + private final ClusterRepository repository; + private final ClusterHelperRepository helperRepository; + private final ClusterInvitedRepository invitedRepo; + private final ClusterSettingsRepository settingsRepo; + private final PlotRepository plotRepository; + + @Inject + public ClusterDefaultService(final ClusterRepository repository, final ClusterHelperRepository helperRepository, + final ClusterInvitedRepository repo, final ClusterSettingsRepository settingsRepo, + final PlotRepository plotRepository + ) { + this.repository = repository; + this.helperRepository = helperRepository; + this.invitedRepo = repo; + this.settingsRepo = settingsRepo; + this.plotRepository = plotRepository; + } + + @Override + public void createCluster(final PlotCluster cluster) { + ClusterEntity e = new ClusterEntity(); + e.setWorld(cluster.area != null ? cluster.area.toString() : null); + e.setOwner(cluster.owner != null ? cluster.owner.toString() : null); + if (cluster.getP1() != null) { + e.setPos1X(cluster.getP1().getX()); + e.setPos1Z(cluster.getP1().getY()); + } + if (cluster.getP2() != null) { + e.setPos2X(cluster.getP2().getX()); + e.setPos2Z(cluster.getP2().getY()); + } + this.repository.save(e); + } + + @Override + public void resizeCluster(final PlotCluster cluster, final PlotId min, final PlotId max) { + String world = cluster.area != null ? cluster.area.toString() : null; + PlotId center = cluster.getCenterPlotId(); + if (world != null) { + Optional ent = this.repository.findByWorldAndBounds(world, center.getX(), center.getY()); + if (ent.isPresent()) { + ClusterEntity e = ent.get(); + e.setPos1X(min.getX()); + e.setPos1Z(min.getY()); + e.setPos2X(max.getX()); + e.setPos2Z(max.getY()); + this.repository.save(e); + } + } + } + + @Override + public void removeHelper(final PlotCluster cluster, final @NotNull UUID uuid) { + String world = cluster.area != null ? cluster.area.toString() : null; + PlotId center = cluster.getCenterPlotId(); + if (world != null) { + Optional ent = this.repository.findByWorldAndBounds(world, center.getX(), center.getY()); + if (ent.isPresent() && ent.get().getId() != null) { + this.helperRepository.remove(ent.get().getId(), uuid.toString()); + } + } + } + + @Override + public void delete(final PlotCluster cluster) { + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { + return; + } + PlotId center = cluster.getCenterPlotId(); + Optional ce = this.repository.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> this.repository.deleteById(entity.getId())); + } + + @Override + public HashMap> getClusters() { + HashMap> result = new HashMap<>(); + List clusters = this.repository.findAll(); + Map built = new HashMap<>(); + for (ClusterEntity ce : clusters) { + UUID owner = Optional.ofNullable(ce.getOwner()).map(UUID::fromString).orElse(null); + PlotCluster cluster = new PlotCluster(null, PlotId.of(ce.getPos1X(), ce.getPos1Z()), PlotId.of(ce.getPos2X(), ce.getPos2Z()), owner); + built.put(ce.getId(), cluster); + result.computeIfAbsent(ce.getWorld(), k -> new HashSet<>()).add(cluster); + } + // Populate helpers and invited + for (Map.Entry e : built.entrySet()) { + long id = e.getKey(); + PlotCluster cluster = e.getValue(); + for (String u : this.helperRepository.findUsers(id)) { + cluster.helpers.add(UUID.fromString(u)); + } + for (String u : this.invitedRepo.findUsers(id)) { + cluster.invited.add(UUID.fromString(u)); + } + // Apply settings (alias, merged). Avoid setting temp variable. + this.settingsRepo.findById(id).ifPresent(se -> { + if (se.getAlias() != null) { + cluster.settings.setAlias(se.getAlias()); + } + Integer m = se.getMerged(); + if (m != null) { + boolean[] merged = new boolean[4]; + for (int i = 0; i < 4; i++) { + merged[3 - i] = (m & 1 << i) != 0; + } + cluster.settings.setMerged(merged); + } + }); + } + return result; + } + + @Override + public void setPosition(final PlotCluster cluster, final String position) { + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { + return; + } + PlotId center = cluster.getCenterPlotId(); + Optional ce = this.repository.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> this.settingsRepo.updatePosition(entity.getId(), position)); + } + + @Override + public void setInvited(final PlotCluster cluster, final UUID uuid) { + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { + return; + } + PlotId center = cluster.getCenterPlotId(); + Optional ce = this.repository.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> this.invitedRepo.add(entity.getId(), uuid.toString())); + } + + @Override + public void removeInvited(final PlotCluster cluster, final UUID uuid) { + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { + return; + } + PlotId center = cluster.getCenterPlotId(); + Optional ce = this.repository.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> this.invitedRepo.remove(entity.getId(), uuid.toString())); + } + + @Override + public void setHelper(final PlotCluster cluster, final UUID uuid) { + String world = cluster.area != null ? cluster.area.getWorldName() : null; + if (world == null) { + return; + } + PlotId center = cluster.getCenterPlotId(); + Optional ce = this.repository.findByWorldAndBounds(world, center.getX(), center.getY()); + ce.ifPresent(entity -> this.helperRepository.add(entity.getId(), uuid.toString())); + } + + @Override + public void replaceWorld(final @NotNull String oldWorld, final @NotNull String newWorld, final PlotId min, final PlotId max) { + if (min == null) { + this.plotRepository.replaceWorld(oldWorld, newWorld); + this.repository.replaceWorld(oldWorld, newWorld); + } else { + this.plotRepository.replaceWorldInBounds(oldWorld, newWorld, min, max); + this.repository.replaceWorldInBounds(oldWorld, newWorld, min, max); + } + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/CommentDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/CommentDefaultService.java new file mode 100644 index 0000000000..7d359fb84f --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/impl/CommentDefaultService.java @@ -0,0 +1,88 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.impl; + +import com.plotsquared.core.persistence.entity.PlotCommentEntity; +import com.plotsquared.core.persistence.repository.api.PlotCommentRepository; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.plot.comment.PlotComment; +import com.plotsquared.core.services.api.CommentService; +import jakarta.inject.Inject; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class CommentDefaultService implements CommentService { + + private final PlotCommentRepository repository; + + @Inject + public CommentDefaultService(final PlotCommentRepository repository) { + this.repository = repository; + } + + @Override + public void removeComment(final Plot plot, final PlotComment comment) { + String world = plot.getWorldName(); + if (world == null) { + return; + } + int hash = plot.getId().hashCode(); + this.repository.deleteOne(world, hash, comment.inbox(), comment.senderName(), comment.comment()); + } + + @Override + public void setComment(final Plot plot, final PlotComment comment) { + PlotCommentEntity entity = new PlotCommentEntity(); + entity.setWorld(plot.getWorldName()); + entity.setHashcode(plot.getId().hashCode()); + entity.setComment(comment.comment()); + entity.setInbox(comment.inbox()); + entity.setTimestamp((int) (comment.timestamp() / 1000)); + entity.setSender(comment.senderName()); + this.repository.save(entity); + } + + @Override + public void clearInbox(final Plot plot, final String inbox) { + String world = plot.getWorldName(); + if (world == null) { + return; + } + int hash = plot.getId().hashCode(); + this.repository.clearInbox(world, hash, inbox); + } + + @Override + public void getComments(final Plot plot, final @NotNull String inbox, final @NotNull Consumer> whenDone) { + List out = new ArrayList<>(); + String world = plot.getWorldName(); + int hash = plot.getId().hashCode(); + for (PlotCommentEntity e : this.repository.findByWorldHashAndInbox(world, hash, inbox)) { + PlotId id = (e.getHashcode() != null && e.getHashcode() != 0) ? PlotId.unpair(e.getHashcode()) : null; + long tsMillis = e.getTimestamp() != null ? e.getTimestamp().longValue() * 1000L : 0L; + out.add(new PlotComment(e.getWorld(), id, e.getComment(), e.getSender(), e.getInbox(), tsMillis)); + } + whenDone.accept(out); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/FlagDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/FlagDefaultService.java new file mode 100644 index 0000000000..a4f325334b --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/impl/FlagDefaultService.java @@ -0,0 +1,74 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.impl; + +import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.persistence.entity.PlotFlagEntity; +import com.plotsquared.core.persistence.repository.api.PlotFlagRepository; +import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.flag.PlotFlag; +import com.plotsquared.core.services.api.FlagService; +import jakarta.inject.Inject; + +import java.util.Optional; + +public class FlagDefaultService implements FlagService { + + private final PlotRepository plotRepository; + private final PlotFlagRepository flagRepository; + + @Inject + public FlagDefaultService(final PlotRepository repository, final PlotFlagRepository flagRepository) { + this.plotRepository = repository; + this.flagRepository = flagRepository; + } + + @Override + public void setFlag(final Plot plot, final PlotFlag flag) { + Optional pe = this.plotRepository.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> { + long plotId = entity.getId(); + String name = flag.getName(); + String value = flag.toString(); + var existing = this.flagRepository.findByPlotAndName(plotId, name); + if (existing.isPresent()) { + var e = existing.get(); + e.setFlagValue(value); + this.flagRepository.save(e); + } else { + PlotFlagEntity e = new PlotFlagEntity(); + PlotEntity pref = new PlotEntity(); + pref.setId(entity.getId()); + e.setPlot(pref); + e.setFlag(name); + e.setFlagValue(value); + this.flagRepository.save(e); + } + }); + } + + @Override + public void removeFlag(final Plot plot, final PlotFlag flag) { + Optional pe = this.plotRepository.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), + plot.getId().getY()); + pe.ifPresent(entity -> this.flagRepository.deleteByPlotAndName(entity.getId(), flag.getName())); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/MemberDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/MemberDefaultService.java new file mode 100644 index 0000000000..1086db74f3 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/impl/MemberDefaultService.java @@ -0,0 +1,138 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.impl; + +import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.persistence.repository.api.PlotDeniedRepository; +import com.plotsquared.core.persistence.repository.api.PlotMembershipRepository; +import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.persistence.repository.api.PlotTrustedRepository; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.services.api.MemberService; +import jakarta.inject.Inject; + +import java.util.Optional; +import java.util.UUID; + +public class MemberDefaultService implements MemberService { + + private final PlotRepository plotRepository; + private final PlotTrustedRepository trustedRepository; + private final PlotMembershipRepository membershipRepository; + private final PlotDeniedRepository deniedRepository; + + @Inject + public MemberDefaultService(final PlotRepository repository, final PlotTrustedRepository trustedRepository, + final PlotMembershipRepository repo, final PlotDeniedRepository deniedRepository + ) { + this.plotRepository = repository; + this.trustedRepository = trustedRepository; + this.membershipRepository = repo; + this.deniedRepository = deniedRepository; + } + + @Override + public void removeTrusted(final Plot plot, final UUID uuid) { + String world = null; + if (plot.getArea() != null) { + world = plot.getArea().toString(); + } + if (world == null) { + return; + } + int x = plot.getId().getX(); + int z = plot.getId().getY(); + Optional ent = this.plotRepository.findByWorldAndId(world, x, z); + if (ent.isPresent() && ent.get().getId() != null) { + this.trustedRepository.remove(ent.get().getId(), uuid.toString()); + } + } + + @Override + public void removeMember(final Plot plot, final UUID uuid) { + String world = null; + if (plot.getArea() != null) { + world = plot.getArea().toString(); + } + if (world == null) { + return; + } + PlotId pid = plot.getId(); + Optional pe = this.plotRepository.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> this.membershipRepository.remove(entity.getId(), uuid.toString())); + } + + @Override + public void setTrusted(final Plot plot, final UUID uuid) { + String world = null; + if (plot.getArea() != null) { + world = plot.getArea().toString(); + } + if (world == null) { + return; + } + PlotId pid = plot.getId(); + Optional pe = this.plotRepository.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> this.trustedRepository.add(entity.getId(), uuid.toString())); + } + + @Override + public void setMember(final Plot plot, final UUID uuid) { + String world = null; + if (plot.getArea() != null) { + world = plot.getArea().toString(); + } + if (world == null) { + return; + } + PlotId pid = plot.getId(); + Optional pe = this.plotRepository.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> membershipRepository.add(entity.getId(), uuid.toString())); + } + + @Override + public void removeDenied(final Plot plot, final UUID uuid) { + String world = null; + if (plot.getArea() != null) { + world = plot.getArea().toString(); + } + if (world == null) { + return; + } + PlotId pid = plot.getId(); + Optional pe = this.plotRepository.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> this.deniedRepository.remove(entity.getId(), uuid.toString())); + } + + @Override + public void setDenied(final Plot plot, final UUID uuid) { + String world = null; + if (plot.getArea() != null) { + world = plot.getArea().toString(); + } + if (world == null) { + return; + } + PlotId pid = plot.getId(); + Optional pe = this.plotRepository.findByWorldAndId(world, pid.getX(), pid.getY()); + pe.ifPresent(entity -> this.deniedRepository.add(entity.getId(), uuid.toString())); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/PlayerMetaDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/PlayerMetaDefaultService.java new file mode 100644 index 0000000000..b77cdf29b3 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/impl/PlayerMetaDefaultService.java @@ -0,0 +1,64 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.impl; + +import com.plotsquared.core.persistence.entity.PlayerMetaEntity; +import com.plotsquared.core.persistence.repository.api.PlayerMetaRepository; +import com.plotsquared.core.services.api.PlayerMetaService; +import jakarta.inject.Inject; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +public class PlayerMetaDefaultService implements PlayerMetaService { + + private final PlayerMetaRepository repository; + + @Inject + public PlayerMetaDefaultService(final PlayerMetaRepository repository) { + this.repository = repository; + } + + @Override + public void addPersistentMeta(final @NotNull UUID uuid, final @NotNull String key, final byte @NotNull [] meta, final boolean delete) { + if (delete) { + this.repository.delete(uuid.toString(), key); + } else { + this.repository.put(uuid.toString(), key, meta); + } + } + + @Override + public void getPersistentMeta(final @NotNull UUID uuid, final @NotNull Consumer> result) { + Map map = new HashMap<>(); + for (PlayerMetaEntity e : this.repository.findByUuid(uuid.toString())) { + map.put(e.getKey(), e.getPlayerMetaValue()); + } + result.accept(map); + } + + @Override + public void removePersistentMeta(final UUID uuid, final @NotNull String key) { + this.repository.delete(uuid.toString(), key); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java new file mode 100644 index 0000000000..7b62ae7934 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/impl/PlotDefaultService.java @@ -0,0 +1,135 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.impl; + +import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.persistence.repository.api.PlotSettingsRepository; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.services.api.PlotService; +import jakarta.inject.Inject; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +public class PlotDefaultService implements PlotService { + + private final PlotRepository repository; + private final PlotSettingsRepository settingsRepository; + + @Inject + public PlotDefaultService(final PlotRepository repository, final PlotSettingsRepository settingsRepository) { + this.repository = repository; + this.settingsRepository = settingsRepository; + } + + @Override + public @NotNull CompletableFuture swapPlots(final @NotNull Plot plot1, final @NotNull Plot plot2) { + return CompletableFuture.completedFuture(this.repository.swapPlots(plot1, plot2)); + } + + @Override + public void movePlot(final @NotNull Plot originalPlot, final @NotNull Plot newPlot) { + this.repository.movePlots(originalPlot, newPlot); + } + + @Override + public void setOwner(final @NotNull Plot plot, final @NotNull UUID uuid) { + this.repository.setOwner(plot, uuid); + } + + @Override + public void createPlotsAndData(final @NotNull List plots, final Runnable whenDone) { + this.repository.createPlotsAndData(plots); + whenDone.run(); + } + + @Override + public void createPlotSafe(final @NotNull Plot plot, final @NotNull Runnable success, final Runnable failure) { + boolean created = this.repository.createPlotSafe(plot); + if (created) { + success.run(); + } else { + failure.run(); + } + } + + @Override + public void createPlotAndSettings(final @NotNull Plot plot, final Runnable whenDone) { + this.repository.createPlotAndSettings(plot); + whenDone.run(); + } + + @Override + public void delete(final @NotNull Plot plot) { + this.repository.delete(plot); + } + + @Override + public void deleteRatings(final Plot plot) { + this.repository.deleteRatings(plot); + } + + @Override + public HashMap> getPlots() { + return this.repository.getPlots(); + } + + @Override + public void setMerged(final Plot plot, final boolean[] merged) { + String world = plot.getWorldName(); + int x = plot.getId().getX(); + int z = plot.getId().getY(); + Optional pe = this.repository.findByWorldAndId(world, x, z); + pe.ifPresent(entity -> { + int mask = com.plotsquared.core.util.HashUtil.hash(merged); + this.settingsRepository.updateMerged(entity.getId(), mask); + }); + } + + @Override + public void setAlias(final Plot plot, final String alias) { + Optional pe = this.repository.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> this.settingsRepository.updateAlias(entity.getId(), alias)); + } + + @Override + public void setPosition(final Plot plot, final String position) { + Optional pe = this.repository.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> this.settingsRepository.updatePosition(entity.getId(), position)); + } + + @Override + public void purgeIds(final Set uniqueIds) { + this.repository.purgeIds(uniqueIds); + } + + @Override + public void purge(final PlotArea area, final Set plotIds) { + this.repository.purgeByWorldAndPlotIds(area.getWorldName(), plotIds); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/services/impl/RatingDefaultService.java b/Core/src/main/java/com/plotsquared/core/services/impl/RatingDefaultService.java new file mode 100644 index 0000000000..5c1e8446e2 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/services/impl/RatingDefaultService.java @@ -0,0 +1,68 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.services.impl; + +import com.plotsquared.core.persistence.entity.PlotEntity; +import com.plotsquared.core.persistence.entity.PlotRatingEntity; +import com.plotsquared.core.persistence.repository.api.PlotRatingRepository; +import com.plotsquared.core.persistence.repository.api.PlotRepository; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.services.api.RatingService; +import jakarta.inject.Inject; + +import java.util.HashMap; +import java.util.Optional; +import java.util.UUID; + +public class RatingDefaultService implements RatingService { + + private final PlotRepository plotRepository; + private final PlotRatingRepository ratingRepository; + + @Inject + public RatingDefaultService(final PlotRepository repository, final PlotRatingRepository ratingRepository) { + this.plotRepository = repository; + this.ratingRepository = ratingRepository; + } + + @Override + public HashMap getRatings(final Plot plot) { + if (plot.getWorldName() == null) { + return new HashMap<>(0); + } + Optional pe = this.plotRepository.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + HashMap out = new HashMap<>(); + pe.ifPresent(entity -> { + for (PlotRatingEntity e : this.ratingRepository.findByPlotId(entity.getId())) { + out.put(UUID.fromString(e.getPlayer()), e.getRating()); + } + }); + return out; + } + + @Override + public void setRating(final Plot plot, final UUID rater, final int value) { + if (plot.getWorldName() == null) { + return; + } + Optional pe = this.plotRepository.findByWorldAndId(plot.getWorldName(), plot.getId().getX(), plot.getId().getY()); + pe.ifPresent(entity -> this.ratingRepository.upsert(entity.getId(), rater.toString(), value)); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java index 0d5f66e229..f2bfd41558 100644 --- a/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java @@ -24,7 +24,6 @@ import com.plotsquared.core.configuration.caption.LocaleHolder; import com.plotsquared.core.configuration.caption.StaticCaption; import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.player.ConsolePlayer; import com.plotsquared.core.player.OfflinePlotPlayer; import com.plotsquared.core.player.PlotPlayer; @@ -78,7 +77,7 @@ public static void getUUIDsFromString( consumer.accept(Collections.emptySet(), null); return; } else if ("*".equals(name)) { - result.add(DBFunc.EVERYONE); + result.add(StaticUUIDs.EVERYONE); } else if (name.length() > 16) { try { result.add(UUID.fromString(name)); @@ -127,9 +126,9 @@ public static void getUUIDsFromString( for (final UUID uuid : uuids) { if (uuid == null) { users.add(TranslatableCaption.of("info.none").toComponent(localeHolder)); - } else if (DBFunc.EVERYONE.equals(uuid)) { + } else if (StaticUUIDs.EVERYONE.equals(uuid)) { users.add(TranslatableCaption.of("info.everyone").toComponent(localeHolder)); - } else if (DBFunc.SERVER.equals(uuid)) { + } else if (StaticUUIDs.SERVER.equals(uuid)) { users.add(TranslatableCaption.of("info.console").toComponent(localeHolder)); } else { players.add(uuid); @@ -193,10 +192,10 @@ public static void getUUIDsFromString( if (owner == null) { return TranslatableCaption.of("info.none"); } - if (owner.equals(DBFunc.EVERYONE)) { + if (owner.equals(StaticUUIDs.EVERYONE)) { return TranslatableCaption.of("info.everyone"); } - if (owner.equals(DBFunc.SERVER)) { + if (owner.equals(StaticUUIDs.SERVER)) { return TranslatableCaption.of("info.server"); } final String name; @@ -226,8 +225,8 @@ public static void getUUIDsFromString( * Special Cases: *

    *
  • {@code null}: Resolves to a {@link TranslatableCaption} with the key {@code info.none}
  • - *
  • {@link DBFunc#EVERYONE}: Resolves to a {@link TranslatableCaption} with the key {@code info.everyone}
  • - *
  • {@link DBFunc#SERVER}: Resolves to a {@link TranslatableCaption} with the key {@code info.server}
  • + *
  • {@link StaticUUIDs#EVERYONE}: Resolves to a {@link TranslatableCaption} with the key {@code info.everyone}
  • + *
  • {@link StaticUUIDs#SERVER}: Resolves to a {@link TranslatableCaption} with the key {@code info.server}
  • *
*
* Otherwise, if the UUID is a valid UUID and not reserved by PlotSquared itself, this method first attempts to query the @@ -244,10 +243,10 @@ public static void getUUIDsFromString( if (uuid == null) { return CompletableFuture.completedFuture(TranslatableCaption.of("info.none")); } - if (uuid.equals(DBFunc.EVERYONE)) { + if (uuid.equals(StaticUUIDs.EVERYONE)) { return CompletableFuture.completedFuture(TranslatableCaption.of("info.everyone")); } - if (uuid.equals(DBFunc.SERVER)) { + if (uuid.equals(StaticUUIDs.SERVER)) { return CompletableFuture.completedFuture(TranslatableCaption.of("info.server")); } P player = getPlayerIfExists(uuid); diff --git a/Core/src/main/java/com/plotsquared/core/util/StaticUUIDs.java b/Core/src/main/java/com/plotsquared/core/util/StaticUUIDs.java new file mode 100644 index 0000000000..f8154e2940 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/StaticUUIDs.java @@ -0,0 +1,33 @@ +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util; + + +import java.util.UUID; + +public class StaticUUIDs { + + /** + * The "global" uuid. + */ + // TODO: Use this instead. public static final UUID EVERYONE = UUID.fromString("4aa2aaa4-c06b-485c-bc58-186aa1780d9b"); + public static final UUID EVERYONE = UUID.fromString("1-1-3-3-7"); + public static final UUID SERVER = UUID.fromString("00000000-0000-0000-0000-000000000000"); + +} diff --git a/Core/src/main/resources/META-INF/persistence.xml b/Core/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000000..47ef663f04 --- /dev/null +++ b/Core/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,30 @@ + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.plotsquared.core.persistence.entity.PlotEntity + com.plotsquared.core.persistence.entity.ClusterEntity + com.plotsquared.core.persistence.entity.ClusterHelperEntity + com.plotsquared.core.persistence.entity.ClusterInvitedEntity + com.plotsquared.core.persistence.entity.ClusterSettingsEntity + com.plotsquared.core.persistence.entity.ClusterUserId + com.plotsquared.core.persistence.entity.PlayerMetaEntity + com.plotsquared.core.persistence.entity.PlotCommentEntity + com.plotsquared.core.persistence.entity.PlotCommentId + com.plotsquared.core.persistence.entity.PlotDeniedEntity + com.plotsquared.core.persistence.entity.PlotEntity + com.plotsquared.core.persistence.entity.PlotFlagEntity + com.plotsquared.core.persistence.entity.PlotMembershipEntity + com.plotsquared.core.persistence.entity.PlotRatingEntity + com.plotsquared.core.persistence.entity.PlotRatingId + com.plotsquared.core.persistence.entity.PlotSettingsEntity + com.plotsquared.core.persistence.entity.PlotTrustedEntity + com.plotsquared.core.persistence.entity.PlotUserId + + + + + diff --git a/Core/src/main/resources/db/changelog/db.changelog-master.xml b/Core/src/main/resources/db/changelog/db.changelog-master.xml new file mode 100644 index 0000000000..3fdc17ff98 --- /dev/null +++ b/Core/src/main/resources/db/changelog/db.changelog-master.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml b/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml new file mode 100644 index 0000000000..4be5c36a44 --- /dev/null +++ b/Core/src/main/resources/db/changelog/v7-to-v8-migration.xml @@ -0,0 +1,293 @@ + + + + + + + + + + + + Add auto-increment ID column to existing v7 plot table + + + + + + + + + + + + + + + + + + + + Create plot_settings table for v8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Update plot_trusted foreign key to use new plot.id + + + + + + + + + + + + + + Update plot_helpers foreign key to use new plot.id + + + + + + + + + + + + + + Update plot_denied foreign key to use new plot.id + + + + + + + + + + + + + + Update plot_rating foreign key to use new plot.id + + + + + + + + + + + + + + + + + Add auto-increment ID column to existing v7 cluster table + + + + + + + + + + + + + + + + + + + Update cluster_helpers foreign key to use new cluster.id + + + + + + + + + + + + + + Update cluster_invited foreign key to use new cluster.id + + + + + + + + + + + + + + Update cluster_settings foreign key to use new cluster.id + + + + + + + + + + + + + + + Add auto-increment meta_id column to existing v7 player_meta table + + + + + + + + + + + + + + + + + + Create plot_flags table if missing + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml b/Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml new file mode 100644 index 0000000000..61767cb2f9 --- /dev/null +++ b/Core/src/main/resources/db/changelog/v8.0.0/db.changelog-v8.0.0.xml @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/test/java/com/plotsquared/core/database/AbstractDBTest.java b/Core/src/test/java/com/plotsquared/core/database/AbstractDBTest.java deleted file mode 100644 index 18e0a5f413..0000000000 --- a/Core/src/test/java/com/plotsquared/core/database/AbstractDBTest.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.database; - -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.PlotArea; -import com.plotsquared.core.plot.PlotCluster; -import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.comment.PlotComment; -import com.plotsquared.core.plot.flag.PlotFlag; -import com.plotsquared.core.util.task.RunnableVal; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -public class AbstractDBTest implements AbstractDB { - - @Override - public void setOwner(Plot plot, UUID uuid) { - } - - @Override - public void createPlotsAndData(List plots, Runnable whenDone) { - } - - @Override - public void createPlotSafe(Plot plot, Runnable success, Runnable failure) { - } - - @Override - public void createTables() { - } - - @Override - public void delete(Plot plot) { - } - - @Override - public void deleteSettings(Plot plot) { - } - - @Override - public void deleteHelpers(Plot plot) { - } - - @Override - public void deleteTrusted(Plot plot) { - } - - @Override - public void deleteDenied(Plot plot) { - } - - @Override - public void deleteComments(Plot plot) { - } - - @Override - public void deleteRatings(Plot plot) { - } - - @Override - public void delete(PlotCluster cluster) { - } - - @Override - public void addPersistentMeta(UUID uuid, String key, byte[] meta, boolean delete) { - } - - @Override - public void removePersistentMeta(UUID uuid, String key) { - } - - @Override - public void getPersistentMeta(UUID uuid, RunnableVal> result) { - } - - @Override - public void createPlotSettings(int id, Plot plot) { - } - - @Override - public int getId(Plot plot) { - return 0; - } - - @Override - public int getClusterId(PlotCluster cluster) { - return 0; - } - - @Override - public boolean convertFlags() { - return true; - } - - @Override - public HashMap> getPlots() { - return null; - } - - @Override - public void validateAllPlots(Set toValidate) { - } - - @Override - public HashMap> getClusters() { - return null; - } - - @Override - public void setMerged(Plot plot, boolean[] merged) { - } - - @Override - public CompletableFuture swapPlots(Plot plot1, Plot plot2) { - return CompletableFuture.completedFuture(true); - } - - @Override - public void setFlag(Plot plot, PlotFlag flag) { - } - - @Override - public void removeFlag(Plot plot, PlotFlag flag) { - } - - @Override - public void setClusterName(PlotCluster cluster, String name) { - } - - @Override - public void setAlias(Plot plot, String alias) { - } - - @Override - public void purgeIds(Set uniqueIds) { - } - - @Override - public void purge(PlotArea area, Set plotIds) { - } - - @Override - public void setPosition(Plot plot, String position) { - } - - @Override - public void setPosition(PlotCluster cluster, String position) { - } - - @Override - public void removeTrusted(Plot plot, UUID uuid) { - } - - @Override - public void removeHelper(PlotCluster cluster, UUID uuid) { - } - - @Override - public void removeMember(Plot plot, UUID uuid) { - } - - @Override - public void removeInvited(PlotCluster cluster, UUID uuid) { - } - - @Override - public void setTrusted(Plot plot, UUID uuid) { - } - - @Override - public void setHelper(PlotCluster cluster, UUID uuid) { - } - - @Override - public void setMember(Plot plot, UUID uuid) { - } - - @Override - public void setInvited(PlotCluster cluster, UUID uuid) { - } - - @Override - public void removeDenied(Plot plot, UUID uuid) { - } - - @Override - public void setDenied(Plot plot, UUID uuid) { - } - - @Override - public HashMap getRatings(Plot plot) { - return null; - } - - @Override - public void setRating(Plot plot, UUID rater, int value) { - } - - @Override - public void removeComment(Plot plot, PlotComment comment) { - } - - @Override - public void clearInbox(Plot plot, String inbox) { - } - - @Override - public void setComment(Plot plot, PlotComment comment) { - } - - @Override - public void getComments( - @NonNull Plot plot, String inbox, - RunnableVal> whenDone - ) { - } - - @Override - public void createPlotAndSettings(Plot plot, Runnable whenDone) { - } - - @Override - public void createCluster(PlotCluster cluster) { - } - - @Override - public void resizeCluster(PlotCluster current, PlotId min, PlotId max) { - } - - @Override - public void movePlot(Plot originalPlot, Plot newPlot) { - } - - @Override - public void replaceUUID(UUID old, UUID now) { - } - - @Override - public boolean deleteTables() { - return false; - } - - @Override - public void close() { - } - - @Override - public void replaceWorld(String oldWorld, String newWorld, PlotId min, PlotId max) { - } - - @Override - public void updateTables(int[] oldVersion) { - } - -} diff --git a/Core/src/test/java/com/plotsquared/core/plot/FlagTest.java b/Core/src/test/java/com/plotsquared/core/plot/FlagTest.java deleted file mode 100644 index c3063b37d5..0000000000 --- a/Core/src/test/java/com/plotsquared/core/plot/FlagTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.plot; - -import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.AbstractDBTest; -import com.plotsquared.core.database.DBFunc; -import com.plotsquared.core.plot.flag.FlagParseException; -import com.plotsquared.core.plot.flag.PlotFlag; -import com.plotsquared.core.plot.flag.implementations.PlotTitleFlag; -import com.plotsquared.core.plot.flag.implementations.UseFlag; -import com.sk89q.worldedit.world.item.ItemType; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class FlagTest { - - private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + FlagTest.class.getSimpleName()); - - private ItemType testBlock; - - @BeforeEach - public void setUp() throws Exception { - //EventUtil.manager = new EventUtilTest(); - DBFunc.dbManager = new AbstractDBTest(); - } - -// @Test public void flagTest() throws Exception { -// Plot plot = new Plot(null, PlotId.of(0, 0)); -// plot.owner = UUID.fromString("84499644-ad72-454b-a19d-f28c28df382b"); -// //plot.setFlag(use, use.parseValue("33,33:1,6:4")); //TODO fix this so FlagTest will run during compile -// Optional flag = plot.getFlag(use); -// if (flag.isPresent()) { -// LOGGER.info(Flags.USE.valueToString(flag.get())); -// testBlock = ItemTypes.BONE_BLOCK; -// flag.get().add(testBlock); -// } -// flag.ifPresent(collection -> LOGGER.info(Flags.USE.valueToString(collection))); -// Optional> flag2 = plot.getFlag(Flags.USE); -// if (flag2.isPresent()) { -// // assertThat(flag2.get(), (Matcher>) IsCollectionContaining.hasItem(testBlock)); -// } -// if (flag.isPresent() && flag2.isPresent()) { -// assertEquals(flag.get(), flag2.get()); -// } -// } - - @Test - public void testFlagName() { - String flagName = PlotFlag.getFlagName(UseFlag.class); - Assertions.assertEquals("use", flagName); - } - - @Test - public void shouldSuccessfullyParseTitleFlagWithTitleSingularAndSubTitleEmpty() { - Assertions.assertDoesNotThrow(() -> { - var title = PlotTitleFlag.TITLE_FLAG_DEFAULT.parse("\"test\" \"\"").getValue(); - Assertions.assertEquals("test", title.title()); - Assertions.assertEquals("", title.subtitle()); - }, "Should not throw a FlagParseException"); - } - - @Test - public void shouldSuccessfullyParseTitleFlagWithTitleMultipleWordsAndSubTitleEmpty() { - Assertions.assertDoesNotThrow(() -> { - var title = PlotTitleFlag.TITLE_FLAG_DEFAULT.parse("\"test hello test\" \"\"").getValue(); - Assertions.assertEquals("test hello test", title.title()); - Assertions.assertEquals("", title.subtitle()); - }, "Should not throw a FlagParseException"); - } - - @Test - public void shouldSuccessfullyParseTitleFlagWithTitleMultipleWordsAndSubTitleMultipleWords() { - Assertions.assertDoesNotThrow(() -> { - var title = PlotTitleFlag.TITLE_FLAG_DEFAULT.parse("\"test hello test\" \"a very long subtitle\"").getValue(); - Assertions.assertEquals("test hello test", title.title()); - Assertions.assertEquals("a very long subtitle", title.subtitle()); - }, "Should not throw a FlagParseException"); - } - - @Test - public void shouldSuccessfullyParseTitleFlagWithTitleEmptyAndSubTitleSingleWord() { - Assertions.assertDoesNotThrow(() -> { - var title = PlotTitleFlag.TITLE_FLAG_DEFAULT.parse("\"\" \"single\"").getValue(); - Assertions.assertEquals("", title.title()); - Assertions.assertEquals("single", title.subtitle()); - }, "Should not throw a FlagParseException"); - } - - @Test - public void shouldExtractTitleWhenASingleDoubleQuoteAtEndOfTitle() { - Assertions.assertDoesNotThrow(() -> { - var plotTitle = PlotTitleFlag.TITLE_FLAG_DEFAULT.parse("title\"").getValue(); - Assertions.assertEquals("title", plotTitle.title()); - Assertions.assertEquals("", plotTitle.subtitle()); - }, "Should not throw a FlagParseException"); - } - - @Test - public void shouldThrowFlagParseExceptionWithQuotesGreater4() { - var exception = Assertions.assertThrows( - FlagParseException.class, - () -> PlotTitleFlag.TITLE_FLAG_DEFAULT.parse("\"title\" \"subtitle\" \"more\""), - "Needs to throw a FlagParseException" - ); - Assertions.assertTrue(exception.getErrorMessage() instanceof TranslatableCaption); - Assertions.assertEquals( - "flags.flag_error_title", - ((TranslatableCaption) exception.getErrorMessage()).getKey() - ); - } - -} diff --git a/build.gradle.kts b/build.gradle.kts index ef652ad7d2..153a49443c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,7 +20,7 @@ plugins { } group = "com.intellectualsites.plotsquared" -version = "7.5.7-SNAPSHOT" +version = "8.0.0-SNAPSHOT" if (!File("$rootDir/.git").exists()) { logger.lifecycle(""" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a720710ace..7d43f65ee7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,6 +32,17 @@ informative-annotations = "1.6" vault = "1.7.1" serverlib = "2.3.7" +# Database +jpa-api = "3.2.0" +hibernate-core = "7.1.0.Final" +liquibase-core = "4.33.0" +hikari = "7.0.2" +jaxbRuntime = "4.0.5" +# JDBC Drivers +mariadb-java-client = "3.5.5" +sqlite-jdbc = "3.50.3.0" +h2 = "2.3.232" + # Gradle plugins shadow = "8.3.9" grgit = "4.1.1" @@ -77,6 +88,19 @@ paperlib = { group = "io.papermc", name = "paperlib", version.ref = "paperlib" } vault = { group = "com.github.MilkBowl", name = "VaultAPI", version.ref = "vault" } serverlib = { group = "dev.notmyfault.serverlib", name = "ServerLib", version.ref = "serverlib" } +# Database +jpaApi = { group = "jakarta.persistence", name = "jakarta.persistence-api", version.ref = "jpa-api" } +hibernateCore = { group = "org.hibernate.orm", name = "hibernate-core", version.ref = "hibernate-core" } +hikari = { group = "com.zaxxer", name = "HikariCP", version.ref = "hikari" } +hibernateHikariCp = { group = "org.hibernate.orm", name = "hibernate-hikaricp", version.ref = "hibernate-core" } +hibernateCommunityDialects = { group = "org.hibernate.orm", name = "hibernate-community-dialects", version.ref = "hibernate-core" } +liquibaseCore = { group = "org.liquibase", name = "liquibase-core", version.ref = "liquibase-core" } +jaxbRuntime = { group = "org.glassfish.jaxb", name = "jaxb-runtime", version.ref = "jaxbRuntime" } +# JDBC Drivers +mariadbJavaClient = { group = "org.mariadb.jdbc", name = "mariadb-java-client", version.ref = "mariadb-java-client" } +sqliteJdbc = { group = "org.xerial", name = "sqlite-jdbc", version.ref = "sqlite-jdbc" } +h2 = { group = "com.h2database", name = "h2", version.ref = "h2" } + [plugins] shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } grgit = { id = "org.ajoberstar.grgit", version.ref = "grgit" }