diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/blockstate/BlockStateCommand.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/blockstate/BlockStateCommand.java index c1c593f..b754a2e 100644 --- a/src/main/java/de/jaschastarke/minecraft/limitedcreative/blockstate/BlockStateCommand.java +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/blockstate/BlockStateCommand.java @@ -187,10 +187,12 @@ public class BlockStateCommand extends BukkitCommand implements IHelpDescribed { * Imports BlockState Data from a given Database to the current active Database. * A Server-Restart is needed after migration! * Parameters: - * -u --update Don't delete existing records / only overwrite if newer + * -u --update Don't delete existing records / only overwrite if newer + * --import= Import from other Plugins. Supported Types: + * cc CreativeControl */ @IsCommand("migrate") - @Usages("-u [username] [password]") + @Usages("-u --import=cc [username] [password]") public boolean migrateDatabase(final CommandContext context, String... args) throws CommandException, MissingPermissionCommandException { DefinedParameterParser params = new DefinedParameterParser(args, new String[]{"debug", "d", "update", "u", "confirm"}); if (params.getArgumentCount() < 1) {// doesn't count parameters @@ -219,19 +221,31 @@ public class BlockStateCommand extends BukkitCommand implements IHelpDescribed { return true; } - if (!params.getFlags().contains("confirm")) { - context.responseFormatted(ChatFormattings.INFO, L("command.blockstate.migrate_confirm", "--confirm")); - return true; + DatabaseMigrationThread thread; + if (params.getParameter("import") != null) { + if (params.getParameter("import").equals("cc")) { + thread = new CreativeControlImportThread(mod, context, source, target); + } else { + context.responseFormatted(ChatFormattings.ERROR, L("command.blockstate.migrate_importtype_error", params.getParameter("import"))); + return false; + } + } else { + thread = new DatabaseMigrationThread(mod, context, source, target); } - - mod.getModuleEntry().disable(); - DatabaseMigrationThread thread = new DatabaseMigrationThread(mod, context, source, target); if (params.getFlags().contains("update") || params.getFlags().contains("u")) { thread.setMode(DatabaseMigrationThread.Mode.UPDATE); } if (params.getFlags().contains("debug") || params.getFlags().contains("d")) { thread.setDebug(true); } + + if (!params.getFlags().contains("confirm")) { + context.responseFormatted(ChatFormattings.INFO, L("command.blockstate.migrate_confirm", "--confirm")); + return true; + } + + mod.getModuleEntry().disable(); + thread.start(); context.response(L("command.blockstate.migrate_started", source.getType(), target.getType())); return true; diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/blockstate/CreativeControlImportThread.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/blockstate/CreativeControlImportThread.java new file mode 100644 index 0000000..ff9bd6d --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/blockstate/CreativeControlImportThread.java @@ -0,0 +1,139 @@ +package de.jaschastarke.minecraft.limitedcreative.blockstate; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.World; + +import de.jaschastarke.bukkit.lib.chat.ChatFormattings; +import de.jaschastarke.bukkit.lib.commands.CommandContext; +import de.jaschastarke.bukkit.lib.database.ResultIterator; +import de.jaschastarke.database.db.Database; +import de.jaschastarke.minecraft.limitedcreative.ModBlockStates; +import de.jaschastarke.minecraft.limitedcreative.blockstate.BlockState.Source; +import de.jaschastarke.minecraft.limitedcreative.blockstate.DBModel.Cuboid; + +public class CreativeControlImportThread extends DatabaseMigrationThread { + public CreativeControlImportThread(ModBlockStates mod, CommandContext context, Database source, Database target) { + super(mod, context, source, target); + } + + @Override + public void run() { + try { + if (!target.isInTransaction()) + target.startTransaction(); + + int rowCount = 0; + Connection sourceConnection = source.getConnection(); + Connection targetConnection = target.getConnection(); + + if (mode == Mode.REPLACE) { + targetConnection.createStatement().execute("DELETE FROM lc_block_state"); + } + + DBQueries targetDB = new DBQueries(this, target); + + List worldBounds = new ArrayList(); + for (World w : mod.getPlugin().getServer().getWorlds()) { + try { + ResultSet fetchBounds = sourceConnection.createStatement().executeQuery("SELECT MIN(x), MIN(z), MAX(x), MAX(z) FROM crcr_blocks_" + w.getName()); + while (fetchBounds.next()) { + worldBounds.add(new WorldSize(w, + fetchBounds.getInt(1), + fetchBounds.getInt(2), + fetchBounds.getInt(3), + fetchBounds.getInt(4))); + } + fetchBounds.close(); + } catch (SQLException e) { + if (isDebug()) + mod.getLog().debug("crcr_blocks_" + w.getName() + " not found: " + e.getMessage()); + mod.getLog().info("CreativeControl has BlockData for World " + w.getName()); + } + } + + for (WorldSize bounds : worldBounds) { + World world = mod.getPlugin().getServer().getWorld(bounds.getWorld()); + if (world != null) { + long time = System.currentTimeMillis(); + int itCount = 0; + if (mod.isDebug()) + mod.getLog().debug("Processing world " + world.getName() + " with bounds: " + bounds); + + for (int x = bounds.getMinX(); x <= bounds.getMaxX(); x += CHUNK_SIZE + 1) { + for (int z = bounds.getMinZ(); z <= bounds.getMaxZ(); z += CHUNK_SIZE + 1) { + Cuboid c = new Cuboid(); + c.add(new Location(world, x, 0, z)); + c.add(new Location(world, x + CHUNK_SIZE, world.getMaxHeight(), z + CHUNK_SIZE)); + System.out.println("Fetching Cuboid: " + c.toString()); + + for (BlockState bs : iterateAllIn(c)) { + if (mode == Mode.UPDATE) { + BlockState xs = targetDB.find(bs.getLocation()); + if (xs == null) { + targetDB.insert(bs); + } else if (xs.getDate().before(bs.getDate())) { + targetDB.update(bs); + } + } else { + targetDB.insert(bs); + } + rowCount++; + itCount++; + } + + Thread.yield(); + } + } + String region = "Region{world = " + world.getName() + ", x = [" + bounds.getMinX() + "; " + (bounds.getMinX() + CHUNK_SIZE) + "], z = [" + bounds.getMinZ() + "; " + (bounds.getMinZ() + CHUNK_SIZE) + "]}"; + mod.getLog().info("Migration processed " + itCount + " BlockStates in " + region + " within " + ((System.currentTimeMillis() - time) / 1000.0) + " seconds"); + } + } + + target.endTransaction(); + context.responseFormatted(ChatFormattings.SUCCESS, L("command.blockstate.migration_finished", rowCount) + " " + + context.getFormatter().formatString(ChatFormattings.ERROR, L("command.blockstate.migration_finished_restart"))); + } catch (SQLException e) { + try { + target.revertTransaction(); + } catch (SQLException e1) {} + context.responseFormatted(ChatFormattings.ERROR, L("command.blockstate.migration_error", e.getMessage())); + } + } + + private PreparedStatement findall = null; + private Iterable iterateAllIn(final DBModel.Cuboid c) throws SQLException { + if (isDebug()) + getLog().debug("DBQuery: iterateAllIn: " + c.toString()); + if (findall == null) { + findall = source.prepare("SELECT * FROM crcr_blocks_" + c.getWorld().getName() + " LEFT JOIN crcr_players ON owner = id WHERE x >= ? AND x <= ? AND y >= ? AND y <= ? AND z >= ? AND z <= ?"); + } + findall.setInt(1, c.getMinX()); + findall.setInt(2, c.getMaxX()); + findall.setInt(3, c.getMinY()); + findall.setInt(4, c.getMaxY()); + findall.setInt(5, c.getMinZ()); + findall.setInt(6, c.getMaxZ()); + ResultSet rs = findall.executeQuery(); + return new ResultIterator(rs) { + @Override + protected BlockState fetch(ResultSet rs) throws SQLException { + BlockState bs = new BlockState(); + bs.setLocation(new Location(c.getWorld(), rs.getInt("x"), rs.getInt("y"), rs.getInt("z"))); + bs.setDate(new Date(rs.getLong("time"))); + bs.setGameMode(GameMode.CREATIVE); + bs.setPlayerName(rs.getString("player")); + bs.setSource(Source.PLAYER); + return bs; + } + }; + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/blockstate/DatabaseMigrationThread.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/blockstate/DatabaseMigrationThread.java index d45a9b1..58a813e 100644 --- a/src/main/java/de/jaschastarke/minecraft/limitedcreative/blockstate/DatabaseMigrationThread.java +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/blockstate/DatabaseMigrationThread.java @@ -20,12 +20,12 @@ import de.jaschastarke.utils.IDebugLogHolder; import de.jaschastarke.utils.ISimpleLogger; public class DatabaseMigrationThread extends Thread implements IDebugLogHolder { - private static final int CHUNK_SIZE = 512; - private ModBlockStates mod; - private CommandContext context; - private Database source; - private Database target; - private Mode mode = Mode.REPLACE; + protected static final int CHUNK_SIZE = 512; + protected ModBlockStates mod; + protected CommandContext context; + protected Database source; + protected Database target; + protected Mode mode = Mode.REPLACE; private boolean debug = false; public static enum Mode { @@ -139,11 +139,11 @@ public class DatabaseMigrationThread extends Thread implements IDebugLogHolder { } } - private String L(String msg, Object... args) { + protected String L(String msg, Object... args) { return mod.getPlugin().getLocale().trans(msg, args); } - private static class WorldSize { + protected static class WorldSize { UUID w; int minX, minZ, maxX, maxZ; @@ -154,6 +154,13 @@ public class DatabaseMigrationThread extends Thread implements IDebugLogHolder { this.maxX = maxX; this.maxZ = maxZ; } + public WorldSize(World w, int minX, int minZ, int maxX, int maxZ) { + this.w = w.getUID(); + this.minX = minX; + this.minZ = minZ; + this.maxX = maxX; + this.maxZ = maxZ; + } public String toString() { World world = Bukkit.getServer().getWorld(w); String wn = world == null ? w.toString() : world.getName(); diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/LimitConfig.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/LimitConfig.java index 5357081..f846811 100644 --- a/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/LimitConfig.java +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/LimitConfig.java @@ -174,11 +174,8 @@ public class LimitConfig extends Configuration implements IConfigurationSubGroup * values aren't supported yet. If you don't add a data-value, all blocks of this material are blocked. * * default: - * - SIGN + * - WALL_SIGN * - SIGN_POST - * - LEVER - * - STONE_BUTTON - * - WOOD_BUTTON * - JUKEBOX */ @IsConfigurationNode(name = "interact", order = 600) @@ -188,9 +185,6 @@ public class LimitConfig extends Configuration implements IConfigurationSubGroup if (!config.contains("interact")) { interactList.add(new BlackList.Blacklisted(Material.WALL_SIGN)); interactList.add(new BlackList.Blacklisted(Material.SIGN_POST)); - interactList.add(new BlackList.Blacklisted(Material.LEVER)); - interactList.add(new BlackList.Blacklisted(Material.STONE_BUTTON)); - interactList.add(new BlackList.Blacklisted(Material.WOOD_BUTTON)); interactList.add(new BlackList.Blacklisted(Material.JUKEBOX)); } } diff --git a/src/main/resources/lang/messages.properties b/src/main/resources/lang/messages.properties index 2b8d7d9..bc54e5c 100644 --- a/src/main/resources/lang/messages.properties +++ b/src/main/resources/lang/messages.properties @@ -32,6 +32,7 @@ command.blockstate.command_updated: Successfully updated {0} blocks. command.blockstate.command_failed: Failed to update blocks. See server.log for details. command.blockstate.migrate_started: Database migration from {0} to {1} started... command.blockstate.migrate_connect_error: Connection to database failed with error: {0} +command.blockstate.migrate_importtype_error: Unknown --import-type: {0} command.blockstate.migration_finished: Database migration of {0} records successful. command.blockstate.migration_finished_restart: A Server-Restart is required! command.blockstate.migration_error: Migration failed with error: {0} diff --git a/src/main/resources/lang/messages_de.properties b/src/main/resources/lang/messages_de.properties index 1cc0b41..0db65d8 100644 --- a/src/main/resources/lang/messages_de.properties +++ b/src/main/resources/lang/messages_de.properties @@ -32,6 +32,7 @@ command.blockstate.command_updated: Erfolgreich {0} Bl command.blockstate.command_failed: Fehler beim aktualisieren der Blöcke. Siehe server.log für Details command.blockstate.migrate_started: Datenbank-Migration von {0} nach {1} gestartet... command.blockstate.migrate_connect_error: Verbindung zur Datenbank mit folgendem Fehler fehlgeschlafen: {0} +command.blockstate.migrate_importtype_error: Unbekannter --import-Typ: {0} command.blockstate.migration_finished: Datenbank-Migration von {0} Datensätzen erfolgreich command.blockstate.migration_finished_restart: Server-Neustart notwendig! command.blockstate.migration_error: Migration mit folgendem Fehler fehlgeschlagen: {0}