From b091558d896b31252652f70266853353e16740d8 Mon Sep 17 00:00:00 2001 From: CJ Burkey Date: Tue, 21 May 2024 01:29:52 -0400 Subject: [PATCH] Switch to library but now it doesn't work --- build.gradle.kts | 32 +- .../data/sqlite/SqLiteDataHandler.java | 15 +- .../sqlite/SqLiteTableMigrationManager.java | 116 ++-- .../claimchunk/data/sqlite/SqLiteWrapper.java | 553 +++++++----------- .../claimchunk/data/sqlite/SqlDataChunk.java | 36 ++ .../data/sqlite/SqlDataChunkPermission.java | 34 ++ .../claimchunk/data/sqlite/SqlDataPlayer.java | 42 ++ .../claimchunk/player/FullPlayerData.java | 12 + 8 files changed, 399 insertions(+), 441 deletions(-) create mode 100644 src/main/java/com/cjburkey/claimchunk/data/sqlite/SqlDataChunk.java create mode 100644 src/main/java/com/cjburkey/claimchunk/data/sqlite/SqlDataChunkPermission.java create mode 100644 src/main/java/com/cjburkey/claimchunk/data/sqlite/SqlDataPlayer.java diff --git a/build.gradle.kts b/build.gradle.kts index ec9999d..fc3b5e3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,4 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import com.vanniktech.maven.publish.SonatypeHost import org.apache.tools.ant.filters.ReplaceTokens import de.undercouch.gradle.tasks.download.Download @@ -37,7 +38,10 @@ object DepData { const val JETBRAINS_ANNOTATIONS_VERSION = "23.0.0" const val JUNIT_VERSION = "5.10.2" const val JUNIT_LAUNCHER_VERSION = "1.10.2" - const val SANS_ORM_VERSION = "3.7" + const val SQLITE_JDBC_VERSION = "3.42.0.1" + const val JAVAX_PERSISTENCE_VERSION = "2.1.0" + const val JAVAX_TRANSACTION_VERSION = "1.1" + const val SANS_ORM_VERSION = "3.17" // Directories const val TEST_SERVER_DIR = "run" @@ -75,6 +79,8 @@ java { tasks { compileJava { + mustRunAfter("googleFormat") + // Disable incremental compilation (module system bs and spigot no mesh // well) options.isIncremental = false @@ -96,15 +102,16 @@ tasks { archiveClassifier.set("plugin") archiveVersion.set(project.version.toString()) - relocate("com.zaxxer.sansorm", "claimchunk.dependency.com.zaxxer.sansorm") + dependencies { + exclude(dependency("org.slf4j:slf4j-api")) + exclude(dependency("org.xerial:sqlite-jdbc")) + } - // Move SmartCommandDispatcher to a unique package to avoid clashes with - // any other plugins that might include it in their jar files. - // relocate("de.goldmensch.commanddispatcher", - // "claimchunk.dependency.de.goldmensch.commanddispatcher"); - // Do the same with JALL - // relocate("io.github.goldmensch.jall", - // "claimchunk.dependency.io.github.goldmensch.jall"); + relocate("com.zaxxer", "claimchunk.dependency.com.zaxxer") + relocate("javax.persistence", "claimchunk.dependency.javax.persistence") + relocate("javax.transaction", "claimchunk.dependency.javax.transaction") + relocate("org.eclipse", "claimchunk.dependency.org.eclipse") + relocate("org.osgi", "claimchunk.dependency.org.osgi") } test { @@ -287,8 +294,11 @@ dependencies { compileOnly("com.sk89q.worldguard:worldguard-bukkit:${DepData.WORLD_GUARD_BUKKIT_VERSION}") compileOnly("me.clip:placeholderapi:${DepData.PLACEHOLDER_API_VERSION}") - // We need to shade this! - implementation("com.zaxxer:sansorm:${DepData.SANS_ORM_VERSION}") + // We need these during runtime! + implementation("org.xerial:sqlite-jdbc:${DepData.SQLITE_JDBC_VERSION}") + implementation("org.eclipse.persistence:javax.persistence:${DepData.JAVAX_PERSISTENCE_VERSION}") + implementation("javax.transaction:transaction-api:${DepData.JAVAX_TRANSACTION_VERSION}") + implementation("com.github.h-thurow:q2o:${DepData.SANS_ORM_VERSION}") testImplementation("org.junit.jupiter:junit-jupiter:${DepData.JUNIT_VERSION}") testRuntimeOnly("org.junit.platform:junit-platform-launcher:${DepData.JUNIT_LAUNCHER_VERSION}") diff --git a/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteDataHandler.java b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteDataHandler.java index 2b91267..5dcca7b 100644 --- a/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteDataHandler.java +++ b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteDataHandler.java @@ -63,7 +63,9 @@ public boolean getHasInit() { } @Override - public void exit() {} + public void exit() { + sqLiteWrapper.close(); + } @Override public void save() { @@ -234,15 +236,8 @@ public void givePlayerAccess( ChunkPos chunk, UUID accessor, ChunkPlayerPermissions permissions) { DataChunk chunkData = claimedChunks.get(chunk); if (chunkData != null) { - ChunkPlayerPermissions previousPerms = - chunkData.playerPermissions.put(accessor, permissions); - if (previousPerms == null) { - // Player doesn't already have any access - sqLiteWrapper.addPlayerAccess(chunk, accessor, permissions.permissionFlags); - } else { - // Player has access, we're changing it - sqLiteWrapper.updatePlayerAccess(chunk, accessor, permissions.permissionFlags); - } + chunkData.playerPermissions.put(accessor, permissions); + sqLiteWrapper.updateOrInsertPlayerAccess(chunk, accessor, permissions.permissionFlags); } } diff --git a/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteTableMigrationManager.java b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteTableMigrationManager.java index e5f11e1..a62e111 100644 --- a/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteTableMigrationManager.java +++ b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteTableMigrationManager.java @@ -1,95 +1,63 @@ package com.cjburkey.claimchunk.data.sqlite; -import org.jetbrains.annotations.NotNull; +import com.zaxxer.q2o.Q2Sql; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.function.Supplier; /** This class is responsible for creating, loading, and upgrading the database file. */ public class SqLiteTableMigrationManager { - public static void go(Supplier connectionSupplier) - throws RuntimeException, SQLException { - try (Connection connection = ensureConnection(connectionSupplier)) { - // Make tables if they don't exist - initializeTables(connection); + public static void go() { + // Make tables if they don't exist + tryCreateTables(); - // Call migration check methods here. - } + // Call migration check methods here. } - private static @NotNull Connection ensureConnection(Supplier connectionSupplier) - throws RuntimeException { - Connection connection = connectionSupplier.get(); - try { - if (connection != null && !connection.isClosed()) { - return connection; - } else { - throw new RuntimeException("Connection provided was not valid."); - } - } catch (SQLException e) { - throw new RuntimeException( - "Failed to create connection to ClaimChunk SQLite database file", e); - } - } - - private static void initializeTables(Connection connection) throws SQLException { - tryCreateTables(connection); - - // Call migration methods here. - // Add table column exist checks inside each method to make this method - // cleaner. - } - - private static void tryCreateTables(Connection connection) throws SQLException { - // Player data table - connection - .prepareStatement( - """ - CREATE TABLE IF NOT EXISTS player_data ( - player_uuid TEXT PRIMARY KEY NOT NULL, - last_ign TEXT NOT NULL, - chunk_name TEXT, - last_online_time INTEGER NOT NULL, - alerts_enabled INTEGER NOT NULL, - extra_max_claims INTEGER NOT NULL - ) STRICT - """) - .execute(); + private static void tryCreateTables() { + // Create player data table + Q2Sql.executeUpdate( + """ + CREATE TABLE IF NOT EXISTS player_data ( + player_uuid TEXT PRIMARY KEY NOT NULL, + last_ign TEXT NOT NULL, + chunk_name TEXT, + last_online_time INTEGER NOT NULL, + alerts_enabled INTEGER NOT NULL, + extra_max_claims INTEGER NOT NULL + ) STRICT + """); // Chunk data table - connection - .prepareStatement( - """ - CREATE TABLE IF NOT EXISTS chunk_data ( - chunk_id INTEGER PRIMARY KEY, - chunk_world TEXT NOT NULL, - chunk_x INTEGER NOT NULL, - chunk_z INTEGER NOT NULL, - owner_uuid TEXT NOT NULL, - - FOREIGN KEY(owner_uuid) REFERENCES player_data(player_uuid) - ) STRICT - """) - .execute(); + Q2Sql.executeUpdate( + """ + CREATE TABLE IF NOT EXISTS chunk_data ( + chunk_id INTEGER PRIMARY KEY, + chunk_world TEXT NOT NULL, + chunk_x INTEGER NOT NULL, + chunk_z INTEGER NOT NULL, + owner_uuid TEXT NOT NULL, + + FOREIGN KEY(owner_uuid) REFERENCES player_data(player_uuid) + ) STRICT + """); // Granular chunk player permission table - connection - .prepareStatement( - """ - CREATE TABLE IF NOT EXISTS chunk_permissions ( - chunk_id INTEGER NOT NULL, - other_player_uuid TEXT NOT NULL, - permission_bits INTEGER NOT NULL, - - FOREIGN KEY(chunk_id) REFERENCES chunk_data(chunk_id), - FOREIGN KEY(other_player_uuid) REFERENCES player_data(player_uuid) - ) STRICT - """) - .execute(); + Q2Sql.executeUpdate( + """ + CREATE TABLE IF NOT EXISTS chunk_permissions ( + perm_id INTEGER PRIMARY KEY, + chunk_id INTEGER NOT NULL, + other_player_uuid TEXT NOT NULL, + permission_bits INTEGER NOT NULL, + + FOREIGN KEY(chunk_id) REFERENCES chunk_data(chunk_id), + FOREIGN KEY(other_player_uuid) REFERENCES player_data(player_uuid) + ) STRICT + """); } // Use this method to determine if a column exists in a table to perform migrations diff --git a/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteWrapper.java b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteWrapper.java index 627392d..f8076aa 100644 --- a/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteWrapper.java +++ b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteWrapper.java @@ -5,392 +5,275 @@ import com.cjburkey.claimchunk.chunk.ChunkPos; import com.cjburkey.claimchunk.chunk.DataChunk; import com.cjburkey.claimchunk.player.FullPlayerData; +import com.zaxxer.q2o.*; import org.jetbrains.annotations.NotNull; +import org.sqlite.SQLiteDataSource; +import java.io.Closeable; import java.io.File; import java.io.IOException; import java.sql.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; -public class SqLiteWrapper { +public record SqLiteWrapper(File dbFile) implements Closeable { - public final File dbFile; - private Connection liveConnection; + private static final String SELECT_CHUNK_ID_SQL = + """ + ( + SELECT chunk_id + FROM chunk_data + WHERE chunk_world=? AND chunk_x=? AND chunk_z=? + ) + """; - public SqLiteWrapper(@NotNull File dbFile) throws RuntimeException { + public SqLiteWrapper(@NotNull File dbFile) { this.dbFile = dbFile; try { - // Make sure the SQLite driver exists and get it in the classpath - // for the DriverManager to search. - Class.forName("org.sqlite.JDBC"); - - // Initialize the tables and perform any changes to them - SqLiteTableMigrationManager.go(this::connectionOrException); - } catch (ClassNotFoundException e) { + if (!dbFile.exists() && dbFile.createNewFile()) { + Utils.warn("Created empty database file"); + } + } catch (IOException e) { throw new RuntimeException( - "Cannot find SQLite JDBC class? Not sure how this can happen. Please submit an" - + " issue on GitHub", - e); - } catch (SQLException e) { - throw new RuntimeException("Failed to initialize tables! This is fatal!", e); + "Failed to create new database file even though it didn't exist!", e); } + + // Make sure the SQLite driver exists and get it in the classpath + // for the DriverManager to search. + SQLiteDataSource dataSource = new SQLiteDataSource(); + dataSource.setUrl("jdbc:sqlite:" + dbFile); + //q2o.initializeTxSimple(dataSource); + q2o.initializeTxNone(dataSource); + + // Initialize the tables and perform any changes to them + SqLiteTableMigrationManager.go(); + + // TODO: WHY DOESN'T PARAMETER SUBSTITUTION WORK?!?!?! + // HELP ME PLEASE + Q2Sql.executeUpdate( + """ + INSERT INTO player_data ( + player_uuid, + last_ign, + last_online_time, + alerts_enabled, + extra_max_claims + ) VALUES ( + ?, + "CJBurkey", + 72468, + TRUE, + 0 + ) + """, + "8da30070-a1df-4e47-a913-f12424aabf6a"); + } + + @Override + public void close() { + q2o.deinitialize(); } // -- DATABASE INTEGRATIONS! -- // public void addClaimedChunk(DataChunk chunk) { - try (Connection connection = connectionOrException()) { - // Use the nested select query to get the user's row ID as the - // owner's id - try (PreparedStatement statement = - connection.prepareStatement( - """ - INSERT OR IGNORE INTO chunk_data ( - chunk_world, - chunk_x, - chunk_z, - owner_uuid - ) VALUES (?, ?, ?, ?) - """)) { - statement.setString(1, chunk.chunk.world()); - statement.setInt(2, chunk.chunk.x()); - statement.setInt(3, chunk.chunk.z()); - statement.setString(4, chunk.player.toString()); - statement.execute(); - } - } catch (SQLException e) { - throw new RuntimeException("Failed to add claimed chunk!", e); - } + Q2Obj.insert(new SqlDataChunk(chunk)); } public void removeClaimedChunk(ChunkPos chunk) { - try (Connection connection = connectionOrException()) { - // Get chunk ID - final int chunkId; - try (PreparedStatement statement = - connection.prepareStatement( - """ - SELECT chunk_id FROM chunk_data - WHERE chunk_world=? AND chunk_x=? AND chunk_y=? - """)) { - statement.setString(1, chunk.world()); - statement.setInt(2, chunk.x()); - statement.setInt(3, chunk.z()); - ResultSet results = statement.executeQuery(); - if (!results.next()) return; - chunkId = results.getInt(1); - } - - // Remove granted permissions - try (PreparedStatement statement = - connection.prepareStatement( - """ - DELETE FROM chunk_permissions - WHERE chunk_id=? - """)) { - statement.setInt(1, chunkId); - statement.execute(); - } - - // Remove the chunk - try (PreparedStatement statement = - connection.prepareStatement( - """ - DELETE FROM chunk_data - WHERE chunk_id=? - """)) { - statement.setInt(1, chunkId); - statement.execute(); - } - } catch (SQLException e) { - throw new RuntimeException("Failed to remove claimed chunk!", e); - } + int chunkId = + SqlClosure.sqlExecute( + connection -> { + // Get chunk ID + ResultSet resultSet = + Q2Sql.executeQuery( + connection, + """ + SELECT chunk_id FROM chunk_data + WHERE chunk_world=? AND chunk_x=? AND chunk_z=? + """, + chunk.world(), + chunk.x(), + chunk.z()); + return resultSet.next() ? resultSet.getInt(1) : -1; + }); + if (chunkId < 0) return; + + // Remove permissions + Q2Sql.executeUpdate( + """ + DELETE FROM chunk_permissions + WHERE chunk_id=? + """, + chunkId); + + // Remove chunks + Q2Sql.executeUpdate( + """ + DELETE FROM chunk_data + WHERE chunk_id=? + """, + chunkId); } - // TODO: TEST public void addPlayer(FullPlayerData playerData) { - try (Connection connection = connectionOrException()) { - try (PreparedStatement statement = - connection.prepareStatement( - """ - INSERT OR IGNORE INTO player_data ( - player_uuid, - last_ign, - chunk_name, - last_online_time, - alerts_enabled, - extra_max_claims - ) VALUES (?, ?, ?, ?, ?, ?) - """)) { - statement.setString(1, playerData.player.toString()); - statement.setString(2, playerData.lastIgn); - statement.setString(3, playerData.chunkName); - statement.setLong(4, playerData.lastOnlineTime); - statement.setBoolean(5, playerData.alert); - statement.setInt(6, playerData.extraMaxClaims); - statement.execute(); - } - } catch (SQLException e) { - throw new RuntimeException("Failed to add player to data handler!", e); - } + Q2Obj.insert(new SqlDataPlayer(playerData)); } public void setPlayerLastOnline(UUID player, long time) { - try (Connection connection = connectionOrException()) { - // Use the nested select query to get the user's row ID as the - // owner's id - try (PreparedStatement statement = - connection.prepareStatement( - """ - UPDATE player_data - SET last_online_time=? - WHERE player_uuid=? - """)) { - statement.setLong(1, time); - statement.setString(2, player.toString()); - statement.execute(); - } - } catch (SQLException e) { - throw new RuntimeException("Failed to set player last online time!", e); - } + Q2Sql.executeUpdate( + """ + UPDATE player_data + SET last_online_time=? + WHERE player_uuid=? + """, + time, + player.toString()); } public void setPlayerChunkName(UUID player, String chunkName) { - try (Connection connection = connectionOrException()) { - // Use the nested select query to get the user's row ID as the - // owner's id - try (PreparedStatement statement = - connection.prepareStatement( - """ - UPDATE player_data - SET chunk_name=? - WHERE player_uuid=? - """)) { - statement.setString(1, chunkName); - statement.setString(2, player.toString()); - statement.execute(); - } - } catch (SQLException e) { - throw new RuntimeException("Failed to set player chunk name!", e); - } + Q2Sql.executeUpdate( + """ + UPDATE player_data + SET chunk_name=? + WHERE player_uuid=? + """, + chunkName, + player.toString()); } public void setPlayerReceiveAlerts(UUID player, boolean receiveAlerts) { - try (Connection connection = connectionOrException()) { - // Use the nested select query to get the user's row ID as the - // owner's id - try (PreparedStatement statement = - connection.prepareStatement( - """ - UPDATE player_data - SET receiveAlerts=? - WHERE player_uuid=? - """)) { - statement.setBoolean(1, receiveAlerts); - statement.setString(2, player.toString()); - statement.execute(); - } - } catch (SQLException e) { - throw new RuntimeException("Failed to enable/disable player alerts!", e); - } + Q2Sql.executeUpdate( + """ + UPDATE player_data + SET receiveAlerts=? + WHERE player_uuid=? + """, + receiveAlerts, + player.toString()); } public void setPlayerExtraMaxClaims(UUID player, int extraMaxClaims) { - try (Connection connection = connectionOrException()) { - // Use the nested select query to get the user's row ID as the - // owner's id - try (PreparedStatement statement = - connection.prepareStatement( - """ - UPDATE player_data - SET extra_max_claims=? - WHERE player_uuid=? - """)) { - statement.setInt(1, extraMaxClaims); - statement.setString(2, player.toString()); - statement.execute(); - } - } catch (SQLException e) { - throw new RuntimeException("Failed to set player extra max claims!", e); - } + Q2Sql.executeUpdate( + """ + UPDATE player_data + SET extra_max_claims=? + WHERE player_uuid=? + """, + extraMaxClaims, + player.toString()); } - public void addPlayerAccess(ChunkPos chunk, UUID accessor, int permissionFlags) { - try (Connection connection = connectionOrException()) { - try (PreparedStatement statement = - connection.prepareStatement( + public void updateOrInsertPlayerAccess(ChunkPos chunk, UUID accessor, int permissionFlags) { + // Check if the access already exists + // If so, update the permission bits + if (Q2Obj.countFromClause( + SqlDataChunkPermission.class, + "other_player_uuid=? AND chunk_id=" + SELECT_CHUNK_ID_SQL, + accessor.toString(), + chunk.world(), + chunk.x(), + chunk.z()) + > 0) { + Q2Sql.executeUpdate( + String.format( + """ + UPDATE chunk_permissions + SET permission_bits=? + WHERE chunk_id=%s + AND other_player_uuid=? + """, + SELECT_CHUNK_ID_SQL), + permissionFlags, + chunk.world(), + chunk.x(), + chunk.z(), + accessor.toString()); + } else { + Q2Sql.executeUpdate( + String.format( """ - INSERT OR IGNORE INTO chunk_permissions ( + INSERT INTO chunk_permissions ( chunk_id, other_player_uuid, permission_bits ) VALUES ( - ( - SELECT chunk_id - FROM chunk_data - WHERE chunk_world=? AND chunk_x=? AND chunk_z=? - ), - ?, ? + %s, ?, ? ) - """)) { - statement.setString(1, chunk.world()); - statement.setInt(2, chunk.x()); - statement.setInt(3, chunk.z()); - statement.setString(4, accessor.toString()); - statement.setInt(5, permissionFlags); - statement.execute(); - } - } catch (SQLException e) { - throw new RuntimeException("Failed to add player access!", e); - } - } - - public void updatePlayerAccess(ChunkPos chunk, UUID accessor, int permissionFlags) { - try (Connection connection = connectionOrException()) { - try (PreparedStatement statement = - connection.prepareStatement( - """ - UPDATE chunk_permissions - SET permission_bits=? - WHERE - chunk_id=( - SELECT chunk_id - FROM chunk_data - WHERE chunk_world=? AND chunk_x=? AND chunk_z=? - ) - AND other_player_uuid=? - """)) { - statement.setInt(1, permissionFlags); - statement.setString(2, chunk.world()); - statement.setInt(3, chunk.x()); - statement.setInt(4, chunk.z()); - statement.setString(5, accessor.toString()); - statement.execute(); - } - } catch (SQLException e) { - throw new RuntimeException("Failed to update player access!", e); + """, + SELECT_CHUNK_ID_SQL), + chunk.world(), + chunk.x(), + chunk.z(), + accessor.toString(), + permissionFlags); } } public void removePlayerAccess(ChunkPos chunk, UUID accessor) { - try (Connection connection = connectionOrException()) { - try (PreparedStatement statement = - connection.prepareStatement( - """ - DELETE FROM chunk_permissions - WHERE - chunk_id=( - SELECT chunk_id - FROM chunk_data - WHERE chunk_world=? AND chunk_x=? AND chunk_z=? - ) - AND other_player_uuid=? - """)) { - statement.setString(1, chunk.world()); - statement.setInt(2, chunk.x()); - statement.setInt(3, chunk.z()); - statement.setString(4, accessor.toString()); - statement.execute(); - } - } catch (SQLException e) { - throw new RuntimeException("Failed to remove player access!", e); - } + Q2Sql.executeUpdate( + String.format( + """ + DELETE FROM chunk_permissions + WHERE chunk_id=%s, + AND other_player_uuid=? + """, + SELECT_CHUNK_ID_SQL), + chunk.world(), + chunk.x(), + chunk.z(), + accessor.toString()); } // -- Loading stuff -- // - public Collection getAllPlayers() { - ArrayList players = new ArrayList<>(); - - try (Connection connection = connectionOrException()) { - try (PreparedStatement statement = - connection.prepareStatement("SELECT * FROM player_data")) { - ResultSet resultSet = statement.executeQuery(); - while (resultSet.next()) { - UUID player = UUID.fromString(resultSet.getString("player_uuid")); - String lastIgn = resultSet.getString("last_ign"); - String chunkName = resultSet.getString("chunk_name"); - long lastOnlineTime = resultSet.getLong("last_online_time"); - boolean alert = resultSet.getBoolean("alerts_enabled"); - int extraMaxClaims = resultSet.getInt("extra_max_claims"); - - players.add( - new FullPlayerData( - player, - lastIgn, - chunkName, - lastOnlineTime, - alert, - extraMaxClaims)); - } - } - } catch (SQLException e) { - throw new RuntimeException("Failed to load all players from SQLite database!", e); - } - - return players; + public List getAllPlayers() { + return Q2ObjList.fromClause(SqlDataPlayer.class, null).stream() + .map(FullPlayerData::new) + .toList(); } public Collection getAllChunks() { HashMap> permissions = new HashMap<>(); HashMap owners = new HashMap<>(); - try (Connection connection = connectionOrException()) { - // Get the permissions first - try (PreparedStatement statement = - connection.prepareStatement( - """ - SELECT chunk_world, chunk_x, chunk_z, owner_uuid, - other_player_uuid, permission_bits - FROM chunk_permissions - RIGHT JOIN chunk_data - ON chunk_permissions.chunk_id=chunk_data.chunk_id - """)) { - ResultSet resultSet = statement.executeQuery(); - while (resultSet.next()) { - String world = resultSet.getString("chunk_world"); - int chunk_x = resultSet.getInt("chunk_x"); - int chunk_z = resultSet.getInt("chunk_z"); - ChunkPos pos = new ChunkPos(world, chunk_x, chunk_z); - UUID owner = UUID.fromString(resultSet.getString("owner_uuid")); - UUID otherPlayer = UUID.fromString(resultSet.getString("other_player_uuid")); - ChunkPlayerPermissions chunkPerms = - new ChunkPlayerPermissions(resultSet.getInt("permission_bits")); - - permissions - .computeIfAbsent(pos, ignoredPos -> new HashMap<>()) - .put(otherPlayer, chunkPerms); - - owners.putIfAbsent(pos, owner); - } + try (ResultSet resultSet = + SqlClosure.sqlExecute( + connection -> + Q2Sql.executeQuery( + connection, + """ + SELECT chunk_world, chunk_x, chunk_z, owner_uuid, + other_player_uuid, permission_bits + FROM chunk_permissions + RIGHT JOIN chunk_data + ON chunk_permissions.chunk_id=chunk_data.chunk_id + """))) { + while (resultSet.next()) { + String world = resultSet.getString("chunk_world"); + int chunk_x = resultSet.getInt("chunk_x"); + int chunk_z = resultSet.getInt("chunk_z"); + ChunkPos pos = new ChunkPos(world, chunk_x, chunk_z); + UUID owner = UUID.fromString(resultSet.getString("owner_uuid")); + UUID otherPlayer = UUID.fromString(resultSet.getString("other_player_uuid")); + ChunkPlayerPermissions chunkPerms = + new ChunkPlayerPermissions(resultSet.getInt("permission_bits")); + + permissions + .computeIfAbsent(pos, ignoredPos -> new HashMap<>()) + .put(otherPlayer, chunkPerms); + + owners.putIfAbsent(pos, owner); } + } catch (Exception e) { + throw new RuntimeException("Failed to load chunk data!", e); + } - // Then the chunks, for chunks with no permissions granted - try (PreparedStatement statement = - connection.prepareStatement( - """ - SELECT chunk_world, chunk_x, chunk_z, owner_uuid - FROM chunk_data - """)) { - ResultSet resultSet = statement.executeQuery(); - while (resultSet.next()) { - String world = resultSet.getString("chunk_world"); - int chunk_x = resultSet.getInt("chunk_x"); - int chunk_z = resultSet.getInt("chunk_z"); - ChunkPos pos = new ChunkPos(world, chunk_x, chunk_z); - UUID owner = UUID.fromString(resultSet.getString("owner_uuid")); - - owners.putIfAbsent(pos, owner); - } - } - } catch (SQLException e) { - throw new RuntimeException("Failed to load all players from SQLite database!", e); + for (SqlDataChunk chunk : Q2ObjList.fromClause(SqlDataChunk.class, null)) { + owners.putIfAbsent( + new ChunkPos(chunk.world, chunk.x, chunk.z), UUID.fromString(chunk.uuid)); } return owners.entrySet().stream() @@ -403,26 +286,4 @@ public Collection getAllChunks() { false)) .collect(Collectors.toList()); } - - // -- Connection stuff -- // - - public @NotNull Connection connection() throws SQLException, IOException { - if (liveConnection == null || liveConnection.isClosed()) { - if (!dbFile.exists() && dbFile.createNewFile()) { - Utils.warn("Created empty database file"); - } - liveConnection = DriverManager.getConnection("jdbc:sqlite:" + dbFile); - } - return liveConnection; - } - - public @NotNull Connection connectionOrException() throws RuntimeException { - try { - return connection(); - } catch (SQLException e) { - throw new RuntimeException("SQLException on connection creation", e); - } catch (IOException e) { - throw new RuntimeException("Failed to create new file " + dbFile, e); - } - } } diff --git a/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqlDataChunk.java b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqlDataChunk.java new file mode 100644 index 0000000..585d73d --- /dev/null +++ b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqlDataChunk.java @@ -0,0 +1,36 @@ +package com.cjburkey.claimchunk.data.sqlite; + +import com.cjburkey.claimchunk.chunk.DataChunk; + +import javax.persistence.*; + +@Table(name = "chunk_data") +public class SqlDataChunk { + + @Id + @Column(name = "chunk_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + public int chunkId; + + @Column(name = "chunk_world") + public String world; + + @Column(name = "chunk_x") + public int x; + + @Column(name = "chunk_z") + public int z; + + @Column(name = "owner_uuid") + public String uuid; + + @SuppressWarnings("unused") + public SqlDataChunk() {} + + public SqlDataChunk(DataChunk chunk) { + this.world = chunk.chunk.world(); + this.x = chunk.chunk.x(); + this.z = chunk.chunk.z(); + this.uuid = chunk.player.toString(); + } +} diff --git a/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqlDataChunkPermission.java b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqlDataChunkPermission.java new file mode 100644 index 0000000..a11aa49 --- /dev/null +++ b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqlDataChunkPermission.java @@ -0,0 +1,34 @@ +package com.cjburkey.claimchunk.data.sqlite; + +import com.cjburkey.claimchunk.chunk.ChunkPlayerPermissions; + +import java.util.UUID; + +import javax.persistence.*; + +@Table(name = "chunk_permissions") +public class SqlDataChunkPermission { + + @Id + @Column(name = "perm_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + public int permissionId; + + @Column(name = "chunk_id") + public int chunkId; + + @Column(name = "other_player_uuid") + public String otherPlayerUuid; + + @Column(name = "permission_bits") + public int permissionBits; + + @SuppressWarnings("unused") + public SqlDataChunkPermission() {} + + public SqlDataChunkPermission(UUID otherPlayer, ChunkPlayerPermissions permissions) { + this.chunkId = -1; + this.otherPlayerUuid = otherPlayer.toString(); + this.permissionBits = permissions.permissionFlags; + } +} diff --git a/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqlDataPlayer.java b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqlDataPlayer.java new file mode 100644 index 0000000..c8bd299 --- /dev/null +++ b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqlDataPlayer.java @@ -0,0 +1,42 @@ +package com.cjburkey.claimchunk.data.sqlite; + +import com.cjburkey.claimchunk.player.FullPlayerData; + +import javax.persistence.Column; +import javax.persistence.Id; +import javax.persistence.Table; + +@Table(name = "player_data") +public class SqlDataPlayer { + + @Id + @Column(name = "player_uuid") + public String uuid; + + @Column(name = "last_ign") + public String lastIgn; + + @Column(name = "chunk_name") + public String chunkName; + + @Column(name = "last_online_time") + public long lastOnlineTime; + + @Column(name = "alerts_enabled") + public boolean alert; + + @Column(name = "extra_max_claims") + public int extraMaxClaims; + + @SuppressWarnings("unused") + public SqlDataPlayer() {} + + public SqlDataPlayer(FullPlayerData player) { + this.uuid = player.player.toString(); + this.lastIgn = player.lastIgn; + this.chunkName = player.chunkName; + this.lastOnlineTime = player.lastOnlineTime; + this.alert = player.alert; + this.extraMaxClaims = player.extraMaxClaims; + } +} diff --git a/src/main/java/com/cjburkey/claimchunk/player/FullPlayerData.java b/src/main/java/com/cjburkey/claimchunk/player/FullPlayerData.java index 578d286..27ef038 100644 --- a/src/main/java/com/cjburkey/claimchunk/player/FullPlayerData.java +++ b/src/main/java/com/cjburkey/claimchunk/player/FullPlayerData.java @@ -1,5 +1,7 @@ package com.cjburkey.claimchunk.player; +import com.cjburkey.claimchunk.data.sqlite.SqlDataPlayer; + import java.util.UUID; public class FullPlayerData implements Cloneable { @@ -26,6 +28,16 @@ public FullPlayerData( this.extraMaxClaims = extraMaxClaims; } + public FullPlayerData(SqlDataPlayer player) { + this( + UUID.fromString(player.uuid), + player.lastIgn, + player.chunkName, + player.lastOnlineTime, + player.alert, + player.extraMaxClaims); + } + private FullPlayerData(FullPlayerData clone) { this( clone.player,