diff --git a/gradle.properties b/gradle.properties index 754a4a2..3015eaf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -53,7 +53,7 @@ mod_name=Zontreck's Library Mod # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=GPLv3 # The mod version. See https://semver.org/ -mod_version=1201.13.042324.1837 +mod_version=1201.13.042324.2018 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/dev/zontreck/libzontreck/memory/world/BlockRestore.java b/src/main/java/dev/zontreck/libzontreck/memory/world/BlockRestore.java index a3d4d20..4e85f16 100644 --- a/src/main/java/dev/zontreck/libzontreck/memory/world/BlockRestore.java +++ b/src/main/java/dev/zontreck/libzontreck/memory/world/BlockRestore.java @@ -11,4 +11,9 @@ public class BlockRestore extends BlockRestoreQueue public void notifyDirtyQueue(boolean blockAdded) { return; // We dont care. This is a basic queue } + + @Override + public boolean sorted() { + return false; + } } diff --git a/src/main/java/dev/zontreck/libzontreck/memory/world/BlockRestoreQueue.java b/src/main/java/dev/zontreck/libzontreck/memory/world/BlockRestoreQueue.java index a98a854..44ab47d 100644 --- a/src/main/java/dev/zontreck/libzontreck/memory/world/BlockRestoreQueue.java +++ b/src/main/java/dev/zontreck/libzontreck/memory/world/BlockRestoreQueue.java @@ -1,19 +1,14 @@ package dev.zontreck.libzontreck.memory.world; -import dev.zontreck.libzontreck.vectors.WorldPosition; -import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.NbtUtils; import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.block.Block; -import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; import java.io.*; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; @@ -70,6 +65,7 @@ public abstract class BlockRestoreQueue if(usesDatabase()) { databaseUpdate(block); + notifyDirtyQueue(true); return; } BLOCK_QUEUE.add(block); @@ -86,28 +82,17 @@ public abstract class BlockRestoreQueue PreparedStatement pstmt = null; try { - pstmt = DatabaseWrapper.get().prepareStatement("REPLACE INTO `blocks` (queueName, posX, posY, posZ, state, entity, dimension, snapshotID) VALUES (?, ?, ?, ?, ?, ?, ?, ?);"); + pstmt = DatabaseWrapper.get().prepareStatement("INSERT INTO `blocks` (queueName, posX, posY, posZ, snapshotID, block) VALUES (?, ?, ?, ?, ?, ?);"); pstmt.setString(0, getRestoreQueueName()); pstmt.setInt(1, block.position.getX()); pstmt.setInt(2, block.position.getY()); pstmt.setInt(3, block.position.getZ()); + pstmt.setInt(4, 0); ByteArrayOutputStream blockState = new ByteArrayOutputStream(); DataOutputStream dos0 = new DataOutputStream(blockState); - NbtIo.write(NbtUtils.writeBlockState(block.blockState), dos0); - pstmt.setBytes(4, blockState.toByteArray()); - ByteArrayOutputStream blockEntity = new ByteArrayOutputStream(); + NbtIo.write(block.serialize(), dos0); + pstmt.setBytes(5, blockState.toByteArray()); - if(block.blockEntity == null) - { - pstmt.setObject(5, null); - } else { - dos0 = new DataOutputStream(blockEntity); - NbtIo.write(block.blockEntity, dos0); - pstmt.setBytes(5, blockEntity.toByteArray()); - } - - pstmt.setString(6, WorldPosition.getDim(block.level)); - pstmt.setInt(7, 0); DatabaseWrapper.get().executePreparedStatement(pstmt); @@ -130,12 +115,62 @@ public abstract class BlockRestoreQueue */ public PrimitiveBlock getNextBlock() { + if (usesDatabase()) { + // Send a query to the database to retrieve the block, and reconstruct here + try { + PreparedStatement sel; + if (sorted()) { + sel = DatabaseWrapper.get().prepareStatement("SELECT * FROM `blocks` WHERE queueName=? ORDER BY posY ASC LIMIT 1;"); + } else + sel = DatabaseWrapper.get().prepareStatement("SELECT * FROM `blocks` WHERE queueName=? LIMIT 1;"); + + sel.setString(0, getRestoreQueueName()); + ResultSet res = DatabaseWrapper.get().executePreparedStatementQuery(sel); + // Now retrieve the block from the database + if (res.next()) { + byte[] data = res.getBytes("block"); + ByteArrayInputStream bais = new ByteArrayInputStream(data); + DataInputStream dis = new DataInputStream(bais); + + PrimitiveBlock block = PrimitiveBlock.deserialize(NbtIo.read(dis)); + + try { + res.deleteRow(); + if (!res.rowDeleted()) { + + } + } catch (SQLException e001) { + PreparedStatement pstat = DatabaseWrapper.get().prepareStatement("DELETE FROM `blocks` WHERE queueName=? AND posX=? AND posY=? AND posZ=?;"); + pstat.setString(0, getRestoreQueueName()); + pstat.setInt(1, block.position.getX()); + pstat.setInt(2, block.position.getY()); + pstat.setInt(3, block.position.getZ()); + DatabaseWrapper.get().executePreparedStatement(pstat); + } + + + return block; + } else return null; + + } catch (SQLException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } PrimitiveBlock blk = BLOCK_QUEUE.get(0); BLOCK_QUEUE.remove(0); notifyDirtyQueue(false); return blk; } + /** + * Override to indicate if the list should be sorted by lowest Y value + * + * @return + */ + public abstract boolean sorted(); + /** * Clears the entire queue, discarding the saved blocks permanently. */ diff --git a/src/main/java/dev/zontreck/libzontreck/memory/world/DatabaseMigrations.java b/src/main/java/dev/zontreck/libzontreck/memory/world/DatabaseMigrations.java index a0175ae..5626fbd 100644 --- a/src/main/java/dev/zontreck/libzontreck/memory/world/DatabaseMigrations.java +++ b/src/main/java/dev/zontreck/libzontreck/memory/world/DatabaseMigrations.java @@ -108,15 +108,13 @@ public class DatabaseMigrations " `posX` int(11) NOT NULL," + " `posY` int(11) NOT NULL," + " `posZ` int(11) NOT NULL," + - " `state` blob NOT NULL," + - " `entity` blob," + - " `dimension` varchar(255) NOT NULL," + " `snapshotID` int(11) NOT NULL DEFAULT 0 COMMENT 'Enables multiple blocks existing at the same position'," + + " `block` blob NOT NULL COMMENT 'NBT Data representing a SavedBlock'," + " PRIMARY KEY (`time`)," + " UNIQUE KEY `posX` (`posX`)," + " UNIQUE KEY `posY` (`posY`)," + " UNIQUE KEY `posZ` (`posZ`)" + - "); "); + ") ;"); migrations.add(blocksTable.withMigrationAction(makeBlocksTable)); diff --git a/src/main/java/dev/zontreck/libzontreck/memory/world/DatabaseWrapper.java b/src/main/java/dev/zontreck/libzontreck/memory/world/DatabaseWrapper.java index dc7b3ca..8902578 100644 --- a/src/main/java/dev/zontreck/libzontreck/memory/world/DatabaseWrapper.java +++ b/src/main/java/dev/zontreck/libzontreck/memory/world/DatabaseWrapper.java @@ -10,26 +10,24 @@ public class DatabaseWrapper { private Connection connection; private static DatabaseWrapper instance; - private static boolean hasDatabase=false; + private static boolean hasDatabase = false; - private static void setHasDatabase(boolean value) - { + private static void setHasDatabase(boolean value) { hasDatabase = value; } - public static DatabaseWrapper get() - { - if(instance==null) + public static DatabaseWrapper get() { + if (instance == null) start(); return instance; } /** * This function will return true if the database drivers are available. + * * @return */ - public static boolean databaseIsAvailable() - { + public static boolean databaseIsAvailable() { return hasDatabase; } @@ -37,8 +35,7 @@ public class DatabaseWrapper { connection = null; } - public static void start() - { + public static void start() { instance = new DatabaseWrapper(); try { instance.connect(ServerConfig.database.host, ServerConfig.database.user, ServerConfig.database.password); @@ -66,10 +63,9 @@ public class DatabaseWrapper { Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection("jdbc:mysql://" + url, username, password); - }catch (ClassNotFoundException | SQLException ex1) - { + } catch (ClassNotFoundException | SQLException ex1) { - LibZontreck.LOGGER.warn("Failed to connect via MySQL: " + e.getMessage() + "; " + ex1.getMessage()+ "; Attempting to fall back to sqlite"); + LibZontreck.LOGGER.warn("Failed to connect via MySQL: " + e.getMessage() + "; " + ex1.getMessage() + "; Attempting to fall back to sqlite"); try { Class.forName("org.sqlite.JDBC"); @@ -111,6 +107,13 @@ public class DatabaseWrapper { return preparedStatement.executeUpdate(); } + public ResultSet executePreparedStatementQuery(PreparedStatement query) throws SQLException { + if (connection == null) { + throw new SQLException("Connection not established."); + } + return query.executeQuery(); + } + public PreparedStatement prepareStatement(String query) throws SQLException { if (connection == null) { throw new SQLException("Connection not established."); diff --git a/src/main/java/dev/zontreck/libzontreck/memory/world/SortedBlockQueue.java b/src/main/java/dev/zontreck/libzontreck/memory/world/SortedBlockQueue.java index 8cced50..a098a21 100644 --- a/src/main/java/dev/zontreck/libzontreck/memory/world/SortedBlockQueue.java +++ b/src/main/java/dev/zontreck/libzontreck/memory/world/SortedBlockQueue.java @@ -33,4 +33,9 @@ public class SortedBlockQueue extends BlockRestoreQueue } } + @Override + public boolean sorted() { + return true; + } + }