From 6dcc33a65ff8b48c513d388729fdb74d59bfba60 Mon Sep 17 00:00:00 2001 From: CJ Burkey Date: Thu, 16 May 2024 13:54:02 -0400 Subject: [PATCH] Work on new data handler, switch player data to UUID instead of id --- .../data/newdata/BulkMySQLDataHandler.java | 2 + .../data/newdata/MySQLDataHandler.java | 43 +++++-- .../data/sqlite/SqLiteDataHandler.java | 8 +- .../sqlite/SqLiteTableMigrationManager.java | 13 +- .../claimchunk/data/sqlite/SqLiteWrapper.java | 116 +++++++++++++----- 5 files changed, 133 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/cjburkey/claimchunk/data/newdata/BulkMySQLDataHandler.java b/src/main/java/com/cjburkey/claimchunk/data/newdata/BulkMySQLDataHandler.java index b557d63..40d62ce 100644 --- a/src/main/java/com/cjburkey/claimchunk/data/newdata/BulkMySQLDataHandler.java +++ b/src/main/java/com/cjburkey/claimchunk/data/newdata/BulkMySQLDataHandler.java @@ -143,6 +143,7 @@ public void addClaimedChunks(DataChunk[] chunks) { @Override public void removeClaimedChunk(ChunkPos pos) { dataHandler.removeClaimedChunk(pos); + super.removeClaimedChunk(pos); } @Override @@ -214,6 +215,7 @@ public void givePlayerAccess( @Override public void takePlayerAccess(ChunkPos chunk, UUID accessor) { dataHandler.takePlayerAccess(chunk, accessor); + super.takePlayerAccess(chunk, accessor); } @Override diff --git a/src/main/java/com/cjburkey/claimchunk/data/newdata/MySQLDataHandler.java b/src/main/java/com/cjburkey/claimchunk/data/newdata/MySQLDataHandler.java index b1415bb..ded1b73 100644 --- a/src/main/java/com/cjburkey/claimchunk/data/newdata/MySQLDataHandler.java +++ b/src/main/java/com/cjburkey/claimchunk/data/newdata/MySQLDataHandler.java @@ -202,19 +202,46 @@ public void addClaimedChunks(DataChunk[] chunks) { } } + @SuppressWarnings("DuplicatedCode") @Override public void removeClaimedChunk(ChunkPos pos) { - String sql = - String.format( - "DELETE FROM `%s` WHERE `%s`=? AND `%s`=? AND `%s`=?", - CLAIMED_CHUNKS_TABLE_NAME, - CLAIMED_CHUNKS_WORLD, - CLAIMED_CHUNKS_X, - CLAIMED_CHUNKS_Z); - try (PreparedStatement statement = prep(claimChunk, connection, sql)) { + // Get the chunk ID + int chunkId; + try(PreparedStatement statement = prep(claimChunk, connection, String.format("SELECT `%s` FROM `%s` WHERE `%s`=? AND `%s`=? AND `%s`=?", CLAIMED_CHUNKS_ID, CLAIMED_CHUNKS_TABLE_NAME, + CLAIMED_CHUNKS_WORLD, + CLAIMED_CHUNKS_X, + CLAIMED_CHUNKS_Z))) { statement.setString(1, pos.world()); statement.setInt(2, pos.x()); statement.setInt(3, pos.z()); + + ResultSet resultSet = statement.executeQuery(); + if (!resultSet.next()) return; + chunkId = resultSet.getInt(1); + } catch (Exception e) { + Utils.err("Failed to get chunk id: %s", e.getMessage()); + //noinspection CallToPrintStackTrace + e.printStackTrace(); + return; + } + + // Remove chunk accesses + try (PreparedStatement statement = prep(claimChunk, connection, String.format( + "DELETE FROM `%s` WHERE `%s`=?", ACCESS_TABLE_NAME, ACCESS_CHUNK_ID))) { + statement.setInt(1, chunkId); + statement.execute(); + } catch (Exception e) { + Utils.err("Failed to unclaim chunk: %s", e.getMessage()); + //noinspection CallToPrintStackTrace + e.printStackTrace(); + } + + // Delete the chunk + try (PreparedStatement statement = prep(claimChunk, connection, String.format( + "DELETE FROM `%s` WHERE `%s`=?", + CLAIMED_CHUNKS_TABLE_NAME, + CLAIMED_CHUNKS_ID))) { + statement.setInt(1, chunkId); statement.execute(); } catch (Exception e) { Utils.err("Failed to unclaim chunk: %s", e.getMessage()); 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 22a44c8..2b91267 100644 --- a/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteDataHandler.java +++ b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteDataHandler.java @@ -32,6 +32,8 @@ * *

I hope this is better :) * + *

Mutations are written to disk immediately, but data is kept in memory + * * @since 0.0.25 */ public class SqLiteDataHandler implements IClaimChunkDataHandler { @@ -68,15 +70,13 @@ public void save() { // Don't do anything, we save as we go } - @SuppressWarnings("StatementWithEmptyBody") @Override public void load() throws Exception { for (FullPlayerData player : sqLiteWrapper.getAllPlayers()) { - // TODO: THIS + joinedPlayers.putIfAbsent(player.player, player); } - for (DataChunk chunk : sqLiteWrapper.getAllChunks()) { - // TODO: THIS + claimedChunks.putIfAbsent(chunk.chunk, chunk); } } 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 ae0c05c..e5f11e1 100644 --- a/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteTableMigrationManager.java +++ b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteTableMigrationManager.java @@ -50,8 +50,7 @@ private static void tryCreateTables(Connection connection) throws SQLException { .prepareStatement( """ CREATE TABLE IF NOT EXISTS player_data ( - player_id INTEGER PRIMARY KEY, - player_uuid TEXT UNIQUE NOT NULL, + player_uuid TEXT PRIMARY KEY NOT NULL, last_ign TEXT NOT NULL, chunk_name TEXT, last_online_time INTEGER NOT NULL, @@ -70,9 +69,9 @@ CREATE TABLE IF NOT EXISTS chunk_data ( chunk_world TEXT NOT NULL, chunk_x INTEGER NOT NULL, chunk_z INTEGER NOT NULL, - owner_id INTEGER NOT NULL, + owner_uuid TEXT NOT NULL, - FOREIGN KEY(owner_id) REFERENCES player_data(player_id) + FOREIGN KEY(owner_uuid) REFERENCES player_data(player_uuid) ) STRICT """) .execute(); @@ -83,11 +82,11 @@ FOREIGN KEY(owner_id) REFERENCES player_data(player_id) """ CREATE TABLE IF NOT EXISTS chunk_permissions ( chunk_id INTEGER NOT NULL, - other_player_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_id) REFERENCES player_data(player_id) + FOREIGN KEY(other_player_uuid) REFERENCES player_data(player_uuid) ) STRICT """) .execute(); @@ -106,7 +105,7 @@ SELECT COUNT(*) FROM pragma_table_info(?) WHERE name=? statement.setString(1, tableName); statement.setString(2, columnName); ResultSet resultSet = statement.executeQuery(); - int count = resultSet.getInt(1); + int count = resultSet.next() ? resultSet.getInt(1) : 0; return count > 0; } 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 88f79c9..627392d 100644 --- a/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteWrapper.java +++ b/src/main/java/com/cjburkey/claimchunk/data/sqlite/SqLiteWrapper.java @@ -1,6 +1,7 @@ package com.cjburkey.claimchunk.data.sqlite; import com.cjburkey.claimchunk.Utils; +import com.cjburkey.claimchunk.chunk.ChunkPlayerPermissions; import com.cjburkey.claimchunk.chunk.ChunkPos; import com.cjburkey.claimchunk.chunk.DataChunk; import com.cjburkey.claimchunk.player.FullPlayerData; @@ -12,7 +13,9 @@ import java.sql.*; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.UUID; +import java.util.stream.Collectors; public class SqLiteWrapper { @@ -52,11 +55,8 @@ INSERT OR IGNORE INTO chunk_data ( chunk_world, chunk_x, chunk_z, - owner_id - ) VALUES ( - ?, ?, ?, - (SELECT player_id FROM player_data WHERE player_uuid=?) - ) + owner_uuid + ) VALUES (?, ?, ?, ?) """)) { statement.setString(1, chunk.chunk.world()); statement.setInt(2, chunk.chunk.x()); @@ -228,7 +228,7 @@ public void addPlayerAccess(ChunkPos chunk, UUID accessor, int permissionFlags) """ INSERT OR IGNORE INTO chunk_permissions ( chunk_id, - other_player_id, + other_player_uuid, permission_bits ) VALUES ( ( @@ -236,12 +236,7 @@ INSERT OR IGNORE INTO chunk_permissions ( FROM chunk_data WHERE chunk_world=? AND chunk_x=? AND chunk_z=? ), - ( - SELECT player_id - FROM player_data - WHERE player_uuid=? - ), - ? + ?, ? ) """)) { statement.setString(1, chunk.world()); @@ -269,12 +264,7 @@ public void updatePlayerAccess(ChunkPos chunk, UUID accessor, int permissionFlag FROM chunk_data WHERE chunk_world=? AND chunk_x=? AND chunk_z=? ) - AND - other_player_id=( - SELECT player_id - FROM player_data - WHERE player_uuid=? - ) + AND other_player_uuid=? """)) { statement.setInt(1, permissionFlags); statement.setString(2, chunk.world()); @@ -300,12 +290,7 @@ public void removePlayerAccess(ChunkPos chunk, UUID accessor) { FROM chunk_data WHERE chunk_world=? AND chunk_x=? AND chunk_z=? ) - AND - other_player_id=( - SELECT player_id - FROM player_data - WHERE player_uuid=? - ) + AND other_player_uuid=? """)) { statement.setString(1, chunk.world()); statement.setInt(2, chunk.x()); @@ -322,10 +307,10 @@ public void removePlayerAccess(ChunkPos chunk, UUID accessor) { public Collection getAllPlayers() { ArrayList players = new ArrayList<>(); + try (Connection connection = connectionOrException()) { try (PreparedStatement statement = - connection.prepareStatement( - "SELECT * FROM player_data")) { + connection.prepareStatement("SELECT * FROM player_data")) { ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { UUID player = UUID.fromString(resultSet.getString("player_uuid")); @@ -334,18 +319,89 @@ public Collection getAllPlayers() { 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)); + + players.add( + new FullPlayerData( + player, + lastIgn, + chunkName, + lastOnlineTime, + alert, + extraMaxClaims)); } } } catch (SQLException e) { - throw new RuntimeException("Failed to remove player access!", e); + throw new RuntimeException("Failed to load all players from SQLite database!", e); } + return players; } public Collection getAllChunks() { - // TODO: THIS - return null; + 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); + } + } + + // 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); + } + + return owners.entrySet().stream() + .map( + entry -> + new DataChunk( + entry.getKey(), + entry.getValue(), + permissions.getOrDefault(entry.getKey(), new HashMap<>()), + false)) + .collect(Collectors.toList()); } // -- Connection stuff -- //