diff --git a/war/src/main/java/com/tommytony/war/War.java b/war/src/main/java/com/tommytony/war/War.java index c3e26bd..a9faa51 100644 --- a/war/src/main/java/com/tommytony/war/War.java +++ b/war/src/main/java/com/tommytony/war/War.java @@ -151,6 +151,13 @@ public class War extends JavaPlugin { } catch (ClassNotFoundException e) { isSpoutServer = false; } + try { + Class.forName("org.sqlite.JDBC").newInstance(); + } catch (Exception e) { + this.log("SQLite3 driver not found!", Level.SEVERE); + this.getServer().getPluginManager().disablePlugin(this); + return; + } // Register events PluginManager pm = this.getServer().getPluginManager(); diff --git a/war/src/main/java/com/tommytony/war/command/RenameZoneCommand.java b/war/src/main/java/com/tommytony/war/command/RenameZoneCommand.java index 6c62bdc..c7b33e2 100644 --- a/war/src/main/java/com/tommytony/war/command/RenameZoneCommand.java +++ b/war/src/main/java/com/tommytony/war/command/RenameZoneCommand.java @@ -1,6 +1,7 @@ package com.tommytony.war.command; import java.io.File; +import java.sql.SQLException; import java.util.logging.Level; import org.bukkit.command.CommandSender; @@ -79,9 +80,18 @@ public class RenameZoneCommand extends AbstractZoneMakerCommand { War.war.log("Loading zone " + newName + "...", Level.INFO); Warzone newZone = WarzoneYmlMapper.load(newName, false); War.war.getWarzones().add(newZone); - newZone.getVolume().loadCorners(); - - zone.getVolume().loadCorners(); + try { + newZone.getVolume().loadCorners(); + } catch (SQLException ex) { + War.war.log("Failed to load warzone " + newZone.getName() + ": " + ex.getMessage(), Level.WARNING); + throw new RuntimeException(ex); + } + try { + zone.getVolume().loadCorners(); + } catch (SQLException ex) { + War.war.log("Failed to load warzone " + zone.getName() + ": " + ex.getMessage(), Level.WARNING); + throw new RuntimeException(ex); + } if (zone.getLobby() != null) { zone.getLobby().getVolume().resetBlocks(); } diff --git a/war/src/main/java/com/tommytony/war/job/RestoreWarhubJob.java b/war/src/main/java/com/tommytony/war/job/RestoreWarhubJob.java index bc1f1d8..f61b880 100644 --- a/war/src/main/java/com/tommytony/war/job/RestoreWarhubJob.java +++ b/war/src/main/java/com/tommytony/war/job/RestoreWarhubJob.java @@ -1,5 +1,6 @@ package com.tommytony.war.job; +import java.sql.SQLException; import java.util.logging.Level; import org.bukkit.Location; @@ -43,7 +44,12 @@ public class RestoreWarhubJob implements Runnable { Location hubLocation = new Location(world, hubX, hubY, hubZ); WarHub hub = new WarHub(hubLocation, hubOrientation); War.war.setWarHub(hub); - Volume vol = VolumeMapper.loadVolume("warhub", "", world); + Volume vol; + try { + vol = VolumeMapper.loadVolume("warhub", "", world); + } catch (SQLException e) { + throw new RuntimeException(e); + } hub.setVolume(vol); hub.getVolume().resetBlocks(); hub.initialize(); diff --git a/war/src/main/java/com/tommytony/war/job/RestoreWarzonesJob.java b/war/src/main/java/com/tommytony/war/job/RestoreWarzonesJob.java index e173633..a901b23 100644 --- a/war/src/main/java/com/tommytony/war/job/RestoreWarzonesJob.java +++ b/war/src/main/java/com/tommytony/war/job/RestoreWarzonesJob.java @@ -1,8 +1,8 @@ package com.tommytony.war.job; +import java.sql.SQLException; import java.util.logging.Level; - import com.tommytony.war.War; import com.tommytony.war.Warzone; import com.tommytony.war.config.WarzoneConfig; @@ -32,7 +32,12 @@ public class RestoreWarzonesJob implements Runnable { Warzone zone = WarzoneTxtMapper.load(warzoneName, !this.newWarInstall); if (zone != null) { // could have failed, would've been logged already War.war.getWarzones().add(zone); - zone.getVolume().loadCorners(); + try { + zone.getVolume().loadCorners(); + } catch (SQLException ex) { + War.war.log("Failed to load warzone " + warzoneName + ": " + ex.getMessage(), Level.WARNING); + throw new RuntimeException(ex); + } if (zone.getLobby() != null) { zone.getLobby().getVolume().resetBlocks(); diff --git a/war/src/main/java/com/tommytony/war/job/RestoreYmlWarhubJob.java b/war/src/main/java/com/tommytony/war/job/RestoreYmlWarhubJob.java index acf38f3..bce46e8 100644 --- a/war/src/main/java/com/tommytony/war/job/RestoreYmlWarhubJob.java +++ b/war/src/main/java/com/tommytony/war/job/RestoreYmlWarhubJob.java @@ -1,5 +1,6 @@ package com.tommytony.war.job; +import java.sql.SQLException; import java.util.logging.Level; import org.bukkit.Location; @@ -84,7 +85,12 @@ public class RestoreYmlWarhubJob implements Runnable { Location hubLocation = new Location(world, hubX, hubY, hubZ); WarHub hub = new WarHub(hubLocation, hubOrientation); War.war.setWarHub(hub); - Volume vol = VolumeMapper.loadVolume("warhub", "", world); + Volume vol; + try { + vol = VolumeMapper.loadVolume("warhub", "", world); + } catch (SQLException e) { + throw new RuntimeException(e); + } hub.setVolume(vol); hub.getVolume().resetBlocks(); hub.initialize(); diff --git a/war/src/main/java/com/tommytony/war/job/RestoreYmlWarzonesJob.java b/war/src/main/java/com/tommytony/war/job/RestoreYmlWarzonesJob.java index 51d132c..a68d193 100644 --- a/war/src/main/java/com/tommytony/war/job/RestoreYmlWarzonesJob.java +++ b/war/src/main/java/com/tommytony/war/job/RestoreYmlWarzonesJob.java @@ -1,9 +1,9 @@ package com.tommytony.war.job; +import java.sql.SQLException; import java.util.List; import java.util.logging.Level; - import com.tommytony.war.War; import com.tommytony.war.Warzone; import com.tommytony.war.config.WarzoneConfig; @@ -28,8 +28,12 @@ public class RestoreYmlWarzonesJob implements Runnable { Warzone zone = WarzoneYmlMapper.load(warzoneName, !this.newWarInstall); if (zone != null) { // could have failed, would've been logged already War.war.getWarzones().add(zone); - - zone.getVolume().loadCorners(); + try { + zone.getVolume().loadCorners(); + } catch (SQLException ex) { + War.war.log("Failed to load warzone " + warzoneName + ": " + ex.getMessage(), Level.WARNING); + throw new RuntimeException(ex); + } if (zone.getLobby() != null) { zone.getLobby().getVolume().resetBlocks(); } diff --git a/war/src/main/java/com/tommytony/war/job/ZoneVolumeSaveJob.java b/war/src/main/java/com/tommytony/war/job/ZoneVolumeSaveJob.java index ca0c307..cc6ac67 100644 --- a/war/src/main/java/com/tommytony/war/job/ZoneVolumeSaveJob.java +++ b/war/src/main/java/com/tommytony/war/job/ZoneVolumeSaveJob.java @@ -1,9 +1,15 @@ package com.tommytony.war.job; +import com.tommytony.war.War; import com.tommytony.war.mapper.ZoneVolumeMapper; import com.tommytony.war.volume.Volume; -public class ZoneVolumeSaveJob extends Thread { +import java.sql.SQLException; +import java.util.logging.Level; + +import org.bukkit.scheduler.BukkitRunnable; + +public class ZoneVolumeSaveJob extends BukkitRunnable { private final Volume volume; private final String zoneName; @@ -14,6 +20,10 @@ public class ZoneVolumeSaveJob extends Thread { @Override public void run() { - ZoneVolumeMapper.save(this.volume, this.zoneName); + try { + ZoneVolumeMapper.save(this.volume, this.zoneName); + } catch (SQLException ex) { + War.war.log(ex.getMessage(), Level.SEVERE); + } } } diff --git a/war/src/main/java/com/tommytony/war/mapper/PreDeGaulleZoneVolumeMapper.java b/war/src/main/java/com/tommytony/war/mapper/PreDeGaulleZoneVolumeMapper.java index 1ef431a..d229424 100644 --- a/war/src/main/java/com/tommytony/war/mapper/PreDeGaulleZoneVolumeMapper.java +++ b/war/src/main/java/com/tommytony/war/mapper/PreDeGaulleZoneVolumeMapper.java @@ -1,10 +1,8 @@ package com.tommytony.war.mapper; import java.io.BufferedReader; -import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; -import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -17,15 +15,12 @@ import org.bukkit.block.BlockState; import org.bukkit.block.Chest; import org.bukkit.block.Dispenser; import org.bukkit.block.Sign; -import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.material.MaterialData; - import com.tommytony.war.War; import com.tommytony.war.job.DeferredBlockResetsJob; import com.tommytony.war.utility.DeferredBlockReset; -import com.tommytony.war.volume.Volume; import com.tommytony.war.volume.ZoneVolume; /** @@ -34,6 +29,7 @@ import com.tommytony.war.volume.ZoneVolume; * @author tommytony * */ +@SuppressWarnings("deprecation") public class PreDeGaulleZoneVolumeMapper { private static List readInventoryString(String invString) { @@ -283,151 +279,4 @@ public class PreDeGaulleZoneVolumeMapper { } return noOfResetBlocks; } - - public static int save(Volume volume, String zoneName, War war) { - int noOfSavedBlocks = 0; - if (volume.hasTwoCorners()) { - BufferedWriter out = null; - try { - (new File(war.getDataFolder().getPath() + "/dat/warzone-" + zoneName)).mkdir(); - if (zoneName.equals("")) { - out = new BufferedWriter(new FileWriter(new File(war.getDataFolder().getPath() + "/dat/volume-" + volume.getName() + ".dat"))); - } else { - out = new BufferedWriter(new FileWriter(new File(war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".dat"))); - } - - out.write("corner1"); - out.newLine(); - out.write(Integer.toString(volume.getCornerOne().getBlockX())); - out.newLine(); - out.write(Integer.toString(volume.getCornerOne().getBlockY())); - out.newLine(); - out.write(Integer.toString(volume.getCornerOne().getBlockZ())); - out.newLine(); - out.write("corner2"); - out.newLine(); - out.write(Integer.toString(volume.getCornerTwo().getBlockX())); - out.newLine(); - out.write(Integer.toString(volume.getCornerTwo().getBlockY())); - out.newLine(); - out.write(Integer.toString(volume.getCornerTwo().getBlockZ())); - out.newLine(); - - int x = 0; - int y = 0; - int z = 0; - Block block; - int typeId; - byte data; - BlockState state; - - x = volume.getMinX(); - for (int i = 0; i < volume.getSizeX(); i++) { - y = volume.getMinY(); - for (int j = 0; j < volume.getSizeY(); j++) { - z = volume.getMinZ(); - for (int k = 0; k < volume.getSizeZ(); k++) { - try { - block = volume.getWorld().getBlockAt(x, y, z); - typeId = block.getTypeId(); - data = block.getData(); - state = block.getState(); - - out.write(typeId + "," + data + ","); - - if (state instanceof Sign) { - // Signs - String extra = ""; - Sign sign = (Sign) state; - if (sign.getLines() != null) { - for (String line : sign.getLines()) { - extra += line + ";;"; - } - out.write(extra); - } - - } else if (state instanceof Chest) { - // Chests - Chest chest = (Chest) state; - Inventory inv = chest.getInventory(); - int size = inv.getSize(); - List items = new ArrayList(); - for (int invIndex = 0; invIndex < size; invIndex++) { - ItemStack item = inv.getItem(invIndex); - if (item != null && item.getType().getId() != Material.AIR.getId()) { - items.add(item); - } - } - String extra = ""; - if (items != null) { - for (ItemStack item : items) { - if (item != null) { - extra += item.getTypeId() + ";" + item.getAmount() + ";" + item.getDurability(); - if (item.getData() != null) { - extra += ";" + item.getData().getData(); - } - extra += ";;"; - } - } - out.write(extra); - } - } else if (state instanceof Dispenser) { - // Dispensers - Dispenser dispenser = (Dispenser) state; - Inventory inv = dispenser.getInventory(); - int size = inv.getSize(); - List items = new ArrayList(); - for (int invIndex = 0; invIndex < size; invIndex++) { - ItemStack item = inv.getItem(invIndex); - if (item != null && item.getType().getId() != Material.AIR.getId()) { - items.add(item); - } - } - String extra = ""; - if (items != null) { - for (ItemStack item : items) { - if (item != null) { - extra += item.getTypeId() + ";" + item.getAmount() + ";" + item.getDurability(); - if (item.getData() != null) { - extra += ";" + item.getData().getData(); - } - extra += ";;"; - } - } - out.write(extra); - } - } - noOfSavedBlocks++; - out.newLine(); - } catch (Exception e) { - war.log("Unexpected error while saving a block to " + " file for zone " + zoneName + ". Blocks saved so far: " + noOfSavedBlocks + "Position: x:" + x + " y:" + y + " z:" + z + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); - } finally { - z++; - } - } - y++; - } - x++; - } - } catch (IOException e) { - war.log("Failed to write volume file " + zoneName + " for warzone " + volume.getName() + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); - } catch (Exception e) { - war.log("Unexpected error caused failure to write volume file " + zoneName + " for warzone " + volume.getName() + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - war.log("Failed to close file writer for volume " + volume.getName() + " for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); - } - } - } - } - return noOfSavedBlocks; - } - } diff --git a/war/src/main/java/com/tommytony/war/mapper/PreNimitzZoneVolumeMapper.java b/war/src/main/java/com/tommytony/war/mapper/PreNimitzZoneVolumeMapper.java new file mode 100644 index 0000000..707380a --- /dev/null +++ b/war/src/main/java/com/tommytony/war/mapper/PreNimitzZoneVolumeMapper.java @@ -0,0 +1,459 @@ +package com.tommytony.war.mapper; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; +import java.util.logging.Level; + +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.Chest; +import org.bukkit.block.Dispenser; +import org.bukkit.block.Sign; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + + +import com.tommytony.war.War; +import com.tommytony.war.job.DeferredBlockResetsJob; +import com.tommytony.war.job.ZoneVolumeSaveJob; +import com.tommytony.war.utility.DeferredBlockReset; +import com.tommytony.war.volume.Volume; +import com.tommytony.war.volume.ZoneVolume; + +/** + * The ZoneVolumeMapper take the blocks from disk and sets them in the worlds, since the ZoneVolume doesn't hold its blocks in memory like regular Volumes. + * + * @author tommytony, Tim Düsterhus + * @package com.tommytony.war.mappers + */ +@SuppressWarnings("deprecation") +public class PreNimitzZoneVolumeMapper { + + /** + * Loads the given volume + * + * @param ZoneVolume + * volume Volume to load + * @param String + * zoneName Zone to load the volume from + * @param World + * world The world the zone is located + * @param boolean onlyLoadCorners Should only the corners be loaded + * @return integer Changed blocks + */ + public static int load(ZoneVolume volume, String zoneName, World world, boolean onlyLoadCorners) { + File cornersFile = new File(War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".corners"); + File blocksFile = new File(War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".blocks"); + File signsFile = new File(War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".signs"); + File invsFile = new File(War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".invs"); + int noOfResetBlocks = 0; + boolean failed = false; + if (!blocksFile.exists()) { + // The post 1.6 formatted files haven't been created yet so + // we need to use the old load. + noOfResetBlocks = PreDeGaulleZoneVolumeMapper.load(volume, zoneName, world, onlyLoadCorners); + + // The new 1.6 files aren't created yet. We just reset the zone (except deferred blocks which will soon execute on main thread ), + // so let's save to the new format as soon as the zone is fully reset. + PreNimitzZoneVolumeMapper.saveAsJob(volume, zoneName, 2); + War.war.log("Warzone " + zoneName + " file converted!", Level.INFO); + + return noOfResetBlocks; + } else { + // 1.6 file exist, so go ahead with reset + BufferedReader cornersReader = null; + FileInputStream blocksStream = null; + BufferedReader signsReader = null; + BufferedReader invsReader = null; + try { + cornersReader = new BufferedReader(new FileReader(cornersFile)); + blocksStream = new FileInputStream(blocksFile); + signsReader = new BufferedReader(new FileReader(signsFile)); + invsReader = new BufferedReader(new FileReader(invsFile)); + + // Get the corners + cornersReader.readLine(); + int x1 = Integer.parseInt(cornersReader.readLine()); + int y1 = Integer.parseInt(cornersReader.readLine()); + int z1 = Integer.parseInt(cornersReader.readLine()); + cornersReader.readLine(); + int x2 = Integer.parseInt(cornersReader.readLine()); + int y2 = Integer.parseInt(cornersReader.readLine()); + int z2 = Integer.parseInt(cornersReader.readLine()); + + volume.setCornerOne(world.getBlockAt(x1, y1, z1)); + volume.setCornerTwo(world.getBlockAt(x2, y2, z2)); + + // Allocate block byte arrays + int noOfBlocks = volume.getSizeX() * volume.getSizeY() * volume.getSizeZ(); + byte[] blockBytes = new byte[noOfBlocks * 2]; // one byte for type, one for data + + blocksStream.read(blockBytes); // read it all + + // Now use the block bytes to reset the world blocks + if (!onlyLoadCorners) { + DeferredBlockResetsJob deferred = new DeferredBlockResetsJob(world); + int blockReads = 0, visitedBlocks = 0, x = 0, y = 0, z = 0, i = 0, j = 0, k = 0; + int diskBlockType; + byte diskBlockData; + Block worldBlock; + int worldBlockId; + volume.clearBlocksThatDontFloat(); + x = volume.getMinX(); + for (i = 0; i < volume.getSizeX(); i++) { + y = volume.getMinY(); + for (j = 0; j < volume.getSizeY(); j++) { + z = volume.getMinZ(); + for (k = 0; k < volume.getSizeZ(); k++) { + try { + diskBlockType = blockBytes[visitedBlocks * 2]; + diskBlockData = blockBytes[visitedBlocks * 2 + 1]; + + worldBlock = volume.getWorld().getBlockAt(x, y, z); + worldBlockId = worldBlock.getTypeId(); + if (worldBlockId != diskBlockType || (worldBlockId == diskBlockType && worldBlock.getData() != diskBlockData) || (worldBlockId == diskBlockType && worldBlock.getData() == diskBlockData && (diskBlockType == Material.WALL_SIGN.getId() || diskBlockType == Material.SIGN_POST.getId() || diskBlockType == Material.CHEST.getId() || diskBlockType == Material.DISPENSER.getId()))) { + if (diskBlockType == Material.WALL_SIGN.getId() || diskBlockType == Material.SIGN_POST.getId()) { + // Signs read + String linesStr = signsReader.readLine(); + String[] lines = linesStr.split(";;"); + + // Signs set + if (diskBlockType == Material.WALL_SIGN.getId() && ((diskBlockData & 0x04) == 0x04) && i + 1 != volume.getSizeX()) { + // A sign post hanging on a wall south of here needs that block to be set first + deferred.add(new DeferredBlockReset(x, y, z, diskBlockType, diskBlockData, lines)); + } else { + worldBlock.setType(Material.getMaterial(diskBlockType)); + BlockState state = worldBlock.getState(); + state.setData(new org.bukkit.material.Sign(diskBlockType, diskBlockData)); + if (state instanceof Sign) { + Sign sign = (Sign) state; + if (lines != null && sign.getLines() != null) { + if (lines.length > 0) { + sign.setLine(0, lines[0]); + } + if (lines.length > 1) { + sign.setLine(1, lines[1]); + } + if (lines.length > 2) { + sign.setLine(2, lines[2]); + } + if (lines.length > 3) { + sign.setLine(3, lines[3]); + } + sign.update(true); + } + } + } + } else if (diskBlockType == Material.CHEST.getId()) { + // Chests read + List items = VolumeMapper.readInventoryString(invsReader.readLine()); + + // Chests set + worldBlock.setType(Material.getMaterial(diskBlockType)); + worldBlock.setData(diskBlockData); + BlockState state = worldBlock.getState(); + if (state instanceof Chest) { + Chest chest = (Chest) state; + if (items != null) { + int ii = 0; + chest.getInventory().clear(); + for (ItemStack item : items) { + if (item != null) { + chest.getInventory().setItem(ii, item); + ii++; + } + } + chest.update(true); + } + } + } else if (diskBlockType == Material.DISPENSER.getId()) { + // Dispensers read + List items = VolumeMapper.readInventoryString(invsReader.readLine()); + + // Dispensers set + worldBlock.setType(Material.getMaterial(diskBlockType)); + worldBlock.setData(diskBlockData); + BlockState state = worldBlock.getState(); + if (state instanceof Dispenser) { + Dispenser dispenser = (Dispenser) state; + if (items != null) { + int ii = 0; + dispenser.getInventory().clear(); + for (ItemStack item : items) { + if (item != null) { + dispenser.getInventory().setItem(ii, item); + ii++; + } + } + dispenser.update(true); + } + } + } else if (diskBlockType == Material.WOODEN_DOOR.getId() || diskBlockType == Material.IRON_DOOR_BLOCK.getId()) { + // Door blocks + deferred.add(new DeferredBlockReset(x, y, z, diskBlockType, diskBlockData)); + } else if (((diskBlockType == Material.TORCH.getId() && ((diskBlockData & 0x02) == 0x02)) || (diskBlockType == Material.REDSTONE_TORCH_OFF.getId() && ((diskBlockData & 0x02) == 0x02)) || (diskBlockType == Material.REDSTONE_TORCH_ON.getId() && ((diskBlockData & 0x02) == 0x02)) || (diskBlockType == Material.LEVER.getId() && ((diskBlockData & 0x02) == 0x02)) || (diskBlockType == Material.STONE_BUTTON.getId() && ((diskBlockData & 0x02) == 0x02)) || (diskBlockType == Material.LADDER.getId() && ((diskBlockData & 0x04) == 0x04)) || (diskBlockType == Material.RAILS.getId() && ((diskBlockData & 0x02) == 0x02))) && i + 1 != volume.getSizeX()) { + // Blocks that hang on a block south of themselves need to make sure that block is there before placing themselves... lol + // Change the block itself later on: + deferred.add(new DeferredBlockReset(x, y, z, diskBlockType, diskBlockData)); + } else { + // regular block + if (diskBlockType >= 0) { + worldBlock.setType(Material.getMaterial(diskBlockType)); + worldBlock.setData(diskBlockData); + } else { + // The larger than 127 block types were stored as bytes, + // but now -128 to -1 are the result of the bad cast from byte + // to int array above. To make matters worse let's make this + // quick a dirty patch. Anyway everything will break horribly + // once block ids get higher than 255. + worldBlock.setType(Material.getMaterial(256 + diskBlockType)); + worldBlock.setData(diskBlockData); + } + } + noOfResetBlocks++; + } + visitedBlocks++; + + blockReads++; + + } catch (Exception e) { + if (!failed) { + // Don't spam the console + War.war.getLogger().warning("Failed to reset block in zone volume " + volume.getName() + ". " + "Blocks read: " + blockReads + ". Visited blocks so far:" + visitedBlocks + ". Blocks reset: " + noOfResetBlocks + ". Error at x:" + x + " y:" + y + " z:" + z + ". Exception:" + e.getClass().toString() + " " + e.getMessage()); + e.printStackTrace(); + failed = true; + } + } finally { + z++; + } + } + y++; + } + x++; + } + if (!deferred.isEmpty()) { + War.war.getServer().getScheduler().scheduleSyncDelayedTask(War.war, deferred, 2); + } + } + } catch (FileNotFoundException e) { + War.war.log("Failed to find volume file " + volume.getName() + " for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); + e.printStackTrace(); + } catch (IOException e) { + War.war.log("Failed to read volume file " + volume.getName() + " for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); + e.printStackTrace(); + } finally { + try { + if (cornersReader != null) { + cornersReader.close(); + } + if (blocksStream != null) { + blocksStream.close(); + } + if (signsReader != null) { + signsReader.close(); + } + if (invsReader != null) { + invsReader.close(); + } + } catch (IOException e) { + War.war.log("Failed to close volume file " + volume.getName() + " for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); + e.printStackTrace(); + } + } + return noOfResetBlocks; + } + } + + /** + * Saves the given volume + * + * @param Volume + * volume Volume to save + * @param String + * zoneName The warzone the volume is located + * @return integer Number of written blocks + */ + public static int save(Volume volume, String zoneName) { + int noOfSavedBlocks = 0; + if (volume.hasTwoCorners()) { + BufferedWriter cornersWriter = null; + FileOutputStream blocksOutput = null; + BufferedWriter signsWriter = null; + BufferedWriter invsWriter = null; + try { + (new File(War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName)).mkdir(); + String path = War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName(); + cornersWriter = new BufferedWriter(new FileWriter(new File(path + ".corners"))); + blocksOutput = new FileOutputStream(new File(path + ".blocks")); + signsWriter = new BufferedWriter(new FileWriter(new File(path + ".signs"))); + invsWriter = new BufferedWriter(new FileWriter(new File(path + ".invs"))); + + cornersWriter.write("corner1"); + cornersWriter.newLine(); + cornersWriter.write(Integer.toString(volume.getCornerOne().getBlockX())); + cornersWriter.newLine(); + cornersWriter.write(Integer.toString(volume.getCornerOne().getBlockY())); + cornersWriter.newLine(); + cornersWriter.write(Integer.toString(volume.getCornerOne().getBlockZ())); + cornersWriter.newLine(); + cornersWriter.write("corner2"); + cornersWriter.newLine(); + cornersWriter.write(Integer.toString(volume.getCornerTwo().getBlockX())); + cornersWriter.newLine(); + cornersWriter.write(Integer.toString(volume.getCornerTwo().getBlockY())); + cornersWriter.newLine(); + cornersWriter.write(Integer.toString(volume.getCornerTwo().getBlockZ())); + cornersWriter.newLine(); + + int x = 0; + int y = 0; + int z = 0; + Block block; + int typeId; + byte data; + BlockState state; + + x = volume.getMinX(); + for (int i = 0; i < volume.getSizeX(); i++) { + y = volume.getMinY(); + for (int j = 0; j < volume.getSizeY(); j++) { + z = volume.getMinZ(); + for (int k = 0; k < volume.getSizeZ(); k++) { + try { + block = volume.getWorld().getBlockAt(x, y, z); + typeId = block.getTypeId(); + data = block.getData(); + state = block.getState(); + + blocksOutput.write((byte) typeId); + blocksOutput.write(data); + + if (state instanceof Sign) { + // Signs + String extra = ""; + Sign sign = (Sign) state; + if (sign.getLines() != null) { + for (String line : sign.getLines()) { + extra += line + ";;"; + } + signsWriter.write(extra); + signsWriter.newLine(); + } + } else if (state instanceof Chest) { + // Chests + Chest chest = (Chest) state; + Inventory inv = chest.getInventory(); + List items = VolumeMapper.getItemListFromInv(inv); + invsWriter.write(VolumeMapper.buildInventoryStringFromItemList(items)); + invsWriter.newLine(); + } else if (state instanceof Dispenser) { + // Dispensers + Dispenser dispenser = (Dispenser) state; + Inventory inv = dispenser.getInventory(); + List items = VolumeMapper.getItemListFromInv(inv); + invsWriter.write(VolumeMapper.buildInventoryStringFromItemList(items)); + invsWriter.newLine(); + } + noOfSavedBlocks++; + } catch (Exception e) { + War.war.log("Unexpected error while saving a block to " + " file for zone " + zoneName + ". Blocks saved so far: " + noOfSavedBlocks + "Position: x:" + x + " y:" + y + " z:" + z + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); + e.printStackTrace(); + } finally { + z++; + } + } + y++; + } + x++; + } + } catch (IOException e) { + War.war.log("Failed to write volume file " + zoneName + " for warzone " + volume.getName() + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); + e.printStackTrace(); + } catch (Exception e) { + War.war.log("Unexpected error caused failure to write volume file " + zoneName + " for warzone " + volume.getName() + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); + e.printStackTrace(); + } finally { + try { + if (cornersWriter != null) { + cornersWriter.close(); + } + if (blocksOutput != null) { + blocksOutput.close(); + } + if (signsWriter != null) { + signsWriter.close(); + } + if (invsWriter != null) { + invsWriter.close(); + } + } catch (IOException e) { + War.war.log("Failed to close volume file " + volume.getName() + " for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); + e.printStackTrace(); + } + } + } + return noOfSavedBlocks; + } + + + + /** + * Saves the Volume as a background-job + * + * @param ZoneVolme + * volume volume to save + * @param String + * zoneName The zone the volume is located + * @param War + * war Instance of war + * @param long tickDelay delay before beginning the task + */ + private static void saveAsJob(ZoneVolume volume, String zoneName, long tickDelay) { + ZoneVolumeSaveJob job = new ZoneVolumeSaveJob(volume, zoneName); + War.war.getServer().getScheduler().scheduleSyncDelayedTask(War.war, job, tickDelay); + } + + /** + * Deletes the given volume + * + * @param Volume + * volume volume to delete + * @param War + * war Instance of war + */ + public static void delete(Volume volume) { + PreNimitzZoneVolumeMapper.deleteFile(War.war.getDataFolder().getPath() + "/dat/volume-" + volume.getName() + ".dat"); + PreNimitzZoneVolumeMapper.deleteFile(War.war.getDataFolder().getPath() + "/dat/volume-" + volume.getName() + ".corners"); + PreNimitzZoneVolumeMapper.deleteFile(War.war.getDataFolder().getPath() + "/dat/volume-" + volume.getName() + ".blocks"); + PreNimitzZoneVolumeMapper.deleteFile(War.war.getDataFolder().getPath() + "/dat/volume-" + volume.getName() + ".signs"); + PreNimitzZoneVolumeMapper.deleteFile(War.war.getDataFolder().getPath() + "/dat/volume-" + volume.getName() + ".invs"); + } + + /** + * Deletes a volume file + * + * @param String + * path path of file + * @param War + * war Instance of war + */ + private static void deleteFile(String path) { + File volFile = new File(path); + if (volFile.exists()) { + boolean deletedData = volFile.delete(); + if (!deletedData) { + War.war.log("Failed to delete file " + volFile.getName(), Level.WARNING); + } + } + } +} diff --git a/war/src/main/java/com/tommytony/war/mapper/VolumeMapper.java b/war/src/main/java/com/tommytony/war/mapper/VolumeMapper.java index 99cc40b..214cc6a 100644 --- a/war/src/main/java/com/tommytony/war/mapper/VolumeMapper.java +++ b/war/src/main/java/com/tommytony/war/mapper/VolumeMapper.java @@ -1,23 +1,31 @@ package com.tommytony.war.mapper; import java.io.BufferedReader; -import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; -import java.io.FileWriter; import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.material.MaterialData; - import com.tommytony.war.War; import com.tommytony.war.volume.Volume; @@ -28,13 +36,72 @@ import com.tommytony.war.volume.Volume; */ public class VolumeMapper { - public static Volume loadVolume(String volumeName, String zoneName, World world) { + public static Volume loadVolume(String volumeName, String zoneName, World world) throws SQLException { Volume volume = new Volume(volumeName, world); VolumeMapper.load(volume, zoneName, world); return volume; } - public static void load(Volume volume, String zoneName, World world) { + public static void load(Volume volume, String zoneName, World world) throws SQLException { + File databaseFile = new File(War.war.getDataFolder(), String.format( + "/dat/volume-%s.sl3", volume.getName())); + if (!zoneName.isEmpty()) { + databaseFile = new File(War.war.getDataFolder(), + String.format("/dat/warzone-%s/volume-%s.sl3", zoneName, + volume.getName())); + } + if (!databaseFile.exists()) { + legacyLoad(volume, zoneName, world); + save(volume, zoneName); + War.war.getLogger().info("Volume " + volume.getName() + " for warzone " + zoneName + " converted to nimitz format!"); + return; + } + Connection databaseConnection = DriverManager.getConnection("jdbc:sqlite:" + databaseFile.getPath()); + Statement stmt = databaseConnection.createStatement(); + ResultSet versionQuery = stmt.executeQuery("PRAGMA user_version"); + int version = versionQuery.getInt("user_version"); + versionQuery.close(); + if (version > DATABASE_VERSION) { + try { + throw new IllegalStateException("Unsupported zone format " + version); + } finally { + stmt.close(); + databaseConnection.close(); + } + } else if (version < DATABASE_VERSION) { + switch (version) { + // Run some update SQL for each old version + } + } + ResultSet cornerQuery = stmt.executeQuery("SELECT * FROM corners"); + cornerQuery.next(); + final Block corner1 = world.getBlockAt(cornerQuery.getInt("x"), cornerQuery.getInt("y"), cornerQuery.getInt("z")); + cornerQuery.next(); + final Block corner2 = world.getBlockAt(cornerQuery.getInt("x"), cornerQuery.getInt("y"), cornerQuery.getInt("z")); + cornerQuery.close(); + volume.setCornerOne(corner1); + volume.setCornerTwo(corner2); + ResultSet query = stmt.executeQuery("SELECT * FROM blocks"); + while (query.next()) { + int x = query.getInt("x"), y = query.getInt("y"), z = query.getInt("z"); + BlockState modify = corner1.getRelative(x, y, z).getState(); + modify.setType(Material.valueOf(query.getString("type"))); + YamlConfiguration data = new YamlConfiguration(); + try { + data.loadFromString(query.getString("data")); + modify.setData(data.getItemStack("data").getData()); + } catch (InvalidConfigurationException e) { + War.war.getLogger().log(Level.WARNING, "Exception loading some material data", e); + } + volume.getBlocks().add(modify); + } + query.close(); + stmt.close(); + databaseConnection.close(); + } + + @SuppressWarnings("deprecation") + public static void legacyLoad(Volume volume, String zoneName, World world) { BufferedReader in = null; try { if (zoneName.equals("")) { @@ -64,8 +131,6 @@ public class VolumeMapper { volume.setCornerOne(world.getBlockAt(x1, y1, z1)); volume.setCornerTwo(world.getBlockAt(x2, y2, z2)); - volume.setBlockTypes(new int[volume.getSizeX()][volume.getSizeY()][volume.getSizeZ()]); - volume.setBlockDatas(new byte[volume.getSizeX()][volume.getSizeY()][volume.getSizeZ()]); int blockReads = 0; for (int i = 0; i < volume.getSizeX(); i++) { for (int j = 0; j < volume.getSizeY(); j++) { @@ -78,34 +143,10 @@ public class VolumeMapper { int typeID = Integer.parseInt(blockSplit[0]); byte data = Byte.parseByte(blockSplit[1]); - volume.getBlockTypes()[i][j][k] = typeID; - volume.getBlockDatas()[i][j][k] = data; - - if (typeID == Material.WALL_SIGN.getId() || typeID == Material.SIGN_POST.getId()) { - // Signs - String linesStr = ""; - if (blockSplit.length > 2) { - for (int o = 2; o < blockSplit.length; o++) { - linesStr += blockSplit[o]; - } - String[] lines = linesStr.split(";;"); - volume.getSignLines().put("sign-" + i + "-" + j + "-" + k, lines); - } - } else if (typeID == Material.CHEST.getId()) { - // Chests - List items = new ArrayList(); - if (blockSplit.length > 2) { - items = readInventoryString(blockSplit[2]); - } - volume.getInvBlockContents().put("chest-" + i + "-" + j + "-" + k, items); - } else if (typeID == Material.DISPENSER.getId()) { - // Dispensers - List items = new ArrayList(); - if (blockSplit.length > 2) { - items = readInventoryString(blockSplit[2]); - } - volume.getInvBlockContents().put("dispenser-" + i + "-" + j + "-" + k, items); - } + BlockState dummy = volume.getWorld().getBlockAt(x1 + i, y1 + j, z1 + k).getState(); + dummy.setTypeId(typeID); + dummy.setRawData(data); + volume.getBlocks().add(dummy); } blockReads++; } @@ -140,90 +181,58 @@ public class VolumeMapper { } } - public static void save(Volume volume, String zoneName) { - if (volume.hasTwoCorners()) { - BufferedWriter out = null; - try { - if (zoneName.equals("")) { - out = new BufferedWriter(new FileWriter(new File(War.war.getDataFolder().getPath() + "/dat/volume-" + volume.getName() + ".dat"))); - } else { - out = new BufferedWriter(new FileWriter(new File(War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".dat"))); - } - - out.write("corner1"); - out.newLine(); - out.write(Integer.toString(volume.getCornerOne().getBlockX())); - out.newLine(); - out.write(Integer.toString(volume.getCornerOne().getBlockY())); - out.newLine(); - out.write(Integer.toString(volume.getCornerOne().getBlockZ())); - out.newLine(); - out.write("corner2"); - out.newLine(); - out.write(Integer.toString(volume.getCornerTwo().getBlockX())); - out.newLine(); - out.write(Integer.toString(volume.getCornerTwo().getBlockY())); - out.newLine(); - out.write(Integer.toString(volume.getCornerTwo().getBlockZ())); - out.newLine(); - int blockWrites = 0; - for (int i = 0; i < volume.getSizeX(); i++) { - for (int j = 0; j < volume.getSizeY(); j++) { - for (int k = 0; k < volume.getSizeZ(); k++) { - try { - int typeId = volume.getBlockTypes()[i][j][k]; - byte data = volume.getBlockDatas()[i][j][k]; - out.write(typeId + "," + data + ","); - if (typeId == Material.WALL_SIGN.getId() || typeId == Material.SIGN_POST.getId()) { - // Signs - String extra = ""; - String[] lines = volume.getSignLines().get("sign-" + i + "-" + j + "-" + k); - if (lines != null) { - for (String line : lines) { - extra += line + ";;"; - } - out.write(extra); - } - } else if (typeId == Material.CHEST.getId()) { - // Chests - String extra = ""; - List contents = volume.getInvBlockContents().get("chest-" + i + "-" + j + "-" + k); - if (contents != null) { - out.write(buildInventoryStringFromItemList(contents)); - out.write(extra); - } - } else if (typeId == Material.DISPENSER.getId()) { - // Dispensers - List contents = volume.getInvBlockContents().get("dispenser-" + i + "-" + j + "-" + k); - if (contents != null) { - out.write(buildInventoryStringFromItemList(contents)); - } - } - out.newLine(); - } catch (Exception e) { - War.war.log("Unexpected error while writing block into volume " + volume.getName() + " file for zone " + zoneName + ". Blocks written so far: " + blockWrites + "Position: x:" + i + " y:" + j + " z:" + k + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); - } - } - } - } - } catch (IOException e) { - War.war.log("Failed to write volume file " + zoneName + " for warzone " + volume.getName() + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); - } catch (Exception e) { - War.war.log("Unexpected error caused failure to write volume file " + zoneName + " for warzone " + volume.getName() + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - War.war.log("Failed to close file writer for volume " + volume.getName() + " for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); - } - } + public static final int DATABASE_VERSION = 1; + public static void save(Volume volume, String zoneName) throws SQLException { + File databaseFile = new File(War.war.getDataFolder(), String.format( + "/dat/volume-%s.sl3", volume.getName())); + if (!zoneName.isEmpty()) { + databaseFile = new File(War.war.getDataFolder(), + String.format("/dat/warzone-%s/volume-%s.sl3", zoneName, + volume.getName())); + } + Connection databaseConnection = DriverManager + .getConnection("jdbc:sqlite:" + databaseFile.getPath()); + Statement stmt = databaseConnection.createStatement(); + stmt.executeUpdate("PRAGMA user_version = " + DATABASE_VERSION); + stmt.executeUpdate("CREATE TABLE IF NOT EXISTS blocks (x BIGINT, y BIGINT, z BIGINT, type TEXT, data BLOB)"); + stmt.executeUpdate("CREATE TABLE IF NOT EXISTS corners (pos INTEGER PRIMARY KEY NOT NULL UNIQUE, x INTEGER NOT NULL, y INTEGER NOT NULL, z INTEGER NOT NULL)"); + stmt.executeUpdate("DELETE FROM blocks"); + stmt.executeUpdate("DELETE FROM corners"); + stmt.close(); + PreparedStatement cornerStmt = databaseConnection + .prepareStatement("INSERT INTO corners SELECT 1 AS pos, ? AS x, ? AS y, ? AS z UNION SELECT 2, ?, ?, ?"); + cornerStmt.setInt(1, volume.getCornerOne().getBlockX()); + cornerStmt.setInt(2, volume.getCornerOne().getBlockY()); + cornerStmt.setInt(3, volume.getCornerOne().getBlockZ()); + cornerStmt.setInt(4, volume.getCornerTwo().getBlockX()); + cornerStmt.setInt(5, volume.getCornerTwo().getBlockY()); + cornerStmt.setInt(6, volume.getCornerTwo().getBlockZ()); + cornerStmt.executeUpdate(); + cornerStmt.close(); + PreparedStatement dataStmt = databaseConnection + .prepareStatement("INSERT INTO blocks VALUES (?, ?, ?, ?, ?)"); + databaseConnection.setAutoCommit(false); + final int batchSize = 1000; + int changed = 0; + for (BlockState block : volume.getBlocks()) { + final Location relLoc = ZoneVolumeMapper.rebase( + volume.getCornerOne(), block.getLocation()); + dataStmt.setInt(1, relLoc.getBlockX()); + dataStmt.setInt(2, relLoc.getBlockY()); + dataStmt.setInt(3, relLoc.getBlockZ()); + dataStmt.setString(4, block.getType().toString()); + YamlConfiguration data = new YamlConfiguration(); + data.set("data", block.getData().toItemStack()); + dataStmt.setString(5, data.saveToString()); + dataStmt.addBatch(); + if (++changed % batchSize == 0) { + dataStmt.executeBatch(); } } + dataStmt.executeBatch(); // insert remaining records + databaseConnection.commit(); + dataStmt.close(); + databaseConnection.close(); } /** @@ -233,6 +242,7 @@ public class VolumeMapper { * invString string to parse * @return List Parsed items */ + @Deprecated public static List readInventoryString(String invString) { List items = new ArrayList(); if (invString != null && !invString.equals("")) { @@ -282,6 +292,7 @@ public class VolumeMapper { * @param items The list of items * @return The list as a string */ + @Deprecated public static String buildInventoryStringFromItemList(List items) { String extra = ""; for (ItemStack item : items) { @@ -310,6 +321,7 @@ public class VolumeMapper { * @param inv The inventory * @return The inventory as a list */ + @Deprecated public static List getItemListFromInv(Inventory inv) { int size = inv.getSize(); List items = new ArrayList(); diff --git a/war/src/main/java/com/tommytony/war/mapper/WarYmlMapper.java b/war/src/main/java/com/tommytony/war/mapper/WarYmlMapper.java index f0f4430..c4cda7c 100644 --- a/war/src/main/java/com/tommytony/war/mapper/WarYmlMapper.java +++ b/war/src/main/java/com/tommytony/war/mapper/WarYmlMapper.java @@ -2,6 +2,7 @@ package com.tommytony.war.mapper; import java.io.File; import java.io.IOException; +import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -189,7 +190,12 @@ public class WarYmlMapper { hubConfigSection.set("materials.gate", War.war.getWarhubMaterials().getGateBlock()); hubConfigSection.set("materials.light", War.war.getWarhubMaterials().getLightBlock()); - VolumeMapper.save(hub.getVolume(), ""); + try { + VolumeMapper.save(hub.getVolume(), ""); + } catch (SQLException e) { + // who really even cares + War.war.getLogger().log(Level.WARNING, "Failed to save warhub volume blocks", e); + } } ConfigurationSection killstreakSection = warRootSection.createSection("war.killstreak"); diff --git a/war/src/main/java/com/tommytony/war/mapper/WarzoneTxtMapper.java b/war/src/main/java/com/tommytony/war/mapper/WarzoneTxtMapper.java index bf38d1d..9115940 100644 --- a/war/src/main/java/com/tommytony/war/mapper/WarzoneTxtMapper.java +++ b/war/src/main/java/com/tommytony/war/mapper/WarzoneTxtMapper.java @@ -2,6 +2,7 @@ package com.tommytony.war.mapper; import java.io.File; import java.io.IOException; +import java.sql.SQLException; import java.util.HashMap; import java.util.logging.Level; @@ -344,16 +345,28 @@ public class WarzoneTxtMapper { // monument blocks for (Monument monument : warzone.getMonuments()) { - monument.setVolume(VolumeMapper.loadVolume(monument.getName(), warzone.getName(), world)); + try { + monument.setVolume(VolumeMapper.loadVolume(monument.getName(), warzone.getName(), world)); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to load some ambiguous old volume", e); + } } // team spawn blocks for (Team team : warzone.getTeams()) { for (Location spawnLocation : team.getTeamSpawns()) { - team.setSpawnVolume(spawnLocation, VolumeMapper.loadVolume(team.getName(), warzone.getName(), world)); + try { + team.setSpawnVolume(spawnLocation, VolumeMapper.loadVolume(team.getName(), warzone.getName(), world)); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to load some ambiguous old volume", e); + } } if (team.getTeamFlag() != null) { - team.setFlagVolume(VolumeMapper.loadVolume(team.getName() + "flag", warzone.getName(), world)); + try { + team.setFlagVolume(VolumeMapper.loadVolume(team.getName() + "flag", warzone.getName(), world)); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to load some ambiguous old volume", e); + } } } @@ -383,7 +396,13 @@ public class WarzoneTxtMapper { } // create the lobby - Volume lobbyVolume = VolumeMapper.loadVolume("lobby", warzone.getName(), lobbyWorld); + Volume lobbyVolume = null; + try { + lobbyVolume = VolumeMapper.loadVolume("lobby", warzone.getName(), lobbyWorld); + } catch (SQLException e) { + // if the zone is this old is there any reason the lobby should be nimitz format + War.war.getLogger().log(Level.WARNING, "Failed to load lobby for a really old warzone", e); + } ZoneLobby lobby = new ZoneLobby(warzone, lobbyFace, lobbyVolume); warzone.setLobby(lobby); } diff --git a/war/src/main/java/com/tommytony/war/mapper/WarzoneYmlMapper.java b/war/src/main/java/com/tommytony/war/mapper/WarzoneYmlMapper.java index d0f1d52..ac494d9 100644 --- a/war/src/main/java/com/tommytony/war/mapper/WarzoneYmlMapper.java +++ b/war/src/main/java/com/tommytony/war/mapper/WarzoneYmlMapper.java @@ -2,6 +2,7 @@ package com.tommytony.war.mapper; import java.io.File; import java.io.IOException; +import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -282,26 +283,46 @@ public class WarzoneYmlMapper { // monument blocks for (Monument monument : warzone.getMonuments()) { - monument.setVolume(VolumeMapper.loadVolume(monument.getName(), warzone.getName(), world)); + try { + monument.setVolume(VolumeMapper.loadVolume(monument.getName(), warzone.getName(), world)); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e); + } } // bomb blocks for (Bomb bomb : warzone.getBombs()) { - bomb.setVolume(VolumeMapper.loadVolume("bomb-" + bomb.getName(), warzone.getName(), world)); + try { + bomb.setVolume(VolumeMapper.loadVolume("bomb-" + bomb.getName(), warzone.getName(), world)); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e); + } } // cake blocks for (Cake cake : warzone.getCakes()) { - cake.setVolume(VolumeMapper.loadVolume("cake-" + cake.getName(), warzone.getName(), world)); + try { + cake.setVolume(VolumeMapper.loadVolume("cake-" + cake.getName(), warzone.getName(), world)); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e); + } } // team spawn blocks for (Team team : warzone.getTeams()) { for (Location teamSpawn : team.getTeamSpawns()) { - team.setSpawnVolume(teamSpawn, VolumeMapper.loadVolume(team.getName() + team.getTeamSpawns().indexOf(teamSpawn), warzone.getName(), world)); + try { + team.setSpawnVolume(teamSpawn, VolumeMapper.loadVolume(team.getName() + team.getTeamSpawns().indexOf(teamSpawn), warzone.getName(), world)); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e); + } } if (team.getTeamFlag() != null) { - team.setFlagVolume(VolumeMapper.loadVolume(team.getName() + "flag", warzone.getName(), world)); + try { + team.setFlagVolume(VolumeMapper.loadVolume(team.getName() + "flag", warzone.getName(), world)); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e); + } } } @@ -376,7 +397,12 @@ public class WarzoneYmlMapper { World lobbyWorld = War.war.getServer().getWorld(lobbyWorldName); // create the lobby - Volume lobbyVolume = VolumeMapper.loadVolume("lobby", warzone.getName(), lobbyWorld); + Volume lobbyVolume = null; + try { + lobbyVolume = VolumeMapper.loadVolume("lobby", warzone.getName(), lobbyWorld); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to load warzone lobby", e); + } ZoneLobby lobby = new ZoneLobby(warzone, lobbyFace, lobbyVolume); warzone.setLobby(lobby); @@ -626,31 +652,55 @@ public class WarzoneYmlMapper { // monument blocks for (Monument monument : warzone.getMonuments()) { - VolumeMapper.save(monument.getVolume(), warzone.getName()); + try { + VolumeMapper.save(monument.getVolume(), warzone.getName()); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e); + } } // bomb blocks for (Bomb bomb : warzone.getBombs()) { - VolumeMapper.save(bomb.getVolume(), warzone.getName()); + try { + VolumeMapper.save(bomb.getVolume(), warzone.getName()); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e); + } } // cake blocks for (Cake cake : warzone.getCakes()) { - VolumeMapper.save(cake.getVolume(), warzone.getName()); + try { + VolumeMapper.save(cake.getVolume(), warzone.getName()); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e); + } } // team spawn & flag blocks for (Team team : teams) { for (Volume volume : team.getSpawnVolumes().values()) { - VolumeMapper.save(volume, warzone.getName()); + try { + VolumeMapper.save(volume, warzone.getName()); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e); + } } if (team.getFlagVolume() != null) { - VolumeMapper.save(team.getFlagVolume(), warzone.getName()); + try { + VolumeMapper.save(team.getFlagVolume(), warzone.getName()); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e); + } } } if (warzone.getLobby() != null) { - VolumeMapper.save(warzone.getLobby().getVolume(), warzone.getName()); + try { + VolumeMapper.save(warzone.getLobby().getVolume(), warzone.getName()); + } catch (SQLException e) { + War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e); + } } // Save to disk diff --git a/war/src/main/java/com/tommytony/war/mapper/ZoneVolumeMapper.java b/war/src/main/java/com/tommytony/war/mapper/ZoneVolumeMapper.java index e9aac31..1ffb901 100644 --- a/war/src/main/java/com/tommytony/war/mapper/ZoneVolumeMapper.java +++ b/war/src/main/java/com/tommytony/war/mapper/ZoneVolumeMapper.java @@ -1,458 +1,279 @@ package com.tommytony.war.mapper; -import java.io.BufferedReader; -import java.io.BufferedWriter; import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.util.Arrays; import java.util.List; import java.util.logging.Level; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; +import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.Note; +import org.bukkit.Note.Tone; +import org.bukkit.SkullType; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; -import org.bukkit.block.Chest; -import org.bukkit.block.Dispenser; +import org.bukkit.block.CommandBlock; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.block.Jukebox; +import org.bukkit.block.NoteBlock; import org.bukkit.block.Sign; -import org.bukkit.inventory.Inventory; +import org.bukkit.block.Skull; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; - import com.tommytony.war.War; -import com.tommytony.war.job.DeferredBlockResetsJob; -import com.tommytony.war.job.ZoneVolumeSaveJob; -import com.tommytony.war.utility.DeferredBlockReset; import com.tommytony.war.volume.Volume; import com.tommytony.war.volume.ZoneVolume; /** - * The ZoneVolumeMapper take the blocks from disk and sets them in the worlds, since the ZoneVolume doesn't hold its blocks in memory like regular Volumes. + * Loads and saves zone blocks to SQLite3 database. * - * @author tommytony, Tim Düsterhus - * @package com.tommytony.war.mappers + * @author cmastudios + * @since 1.8 */ public class ZoneVolumeMapper { + public static final int DATABASE_VERSION = 1; + /** * Loads the given volume * - * @param ZoneVolume - * volume Volume to load - * @param String - * zoneName Zone to load the volume from - * @param World - * world The world the zone is located + * @param ZoneVolume volume Volume to load + * @param String zoneName Zone to load the volume from + * @param World world The world the zone is located * @param boolean onlyLoadCorners Should only the corners be loaded * @return integer Changed blocks + * @throws SQLException Error communicating with SQLite3 database */ - public static int load(ZoneVolume volume, String zoneName, World world, boolean onlyLoadCorners) { - File cornersFile = new File(War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".corners"); - File blocksFile = new File(War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".blocks"); - File signsFile = new File(War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".signs"); - File invsFile = new File(War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".invs"); - int noOfResetBlocks = 0; - boolean failed = false; - if (!blocksFile.exists()) { - // The post 1.6 formatted files haven't been created yet so - // we need to use the old load. - noOfResetBlocks = PreDeGaulleZoneVolumeMapper.load(volume, zoneName, world, onlyLoadCorners); - - // The new 1.6 files aren't created yet. We just reset the zone (except deferred blocks which will soon execute on main thread ), - // so let's save to the new format as soon as the zone is fully reset. - ZoneVolumeMapper.saveAsJob(volume, zoneName, 2); - War.war.log("Warzone " + zoneName + " file converted!", Level.INFO); - - return noOfResetBlocks; - } else { - // 1.6 file exist, so go ahead with reset - BufferedReader cornersReader = null; - FileInputStream blocksStream = null; - BufferedReader signsReader = null; - BufferedReader invsReader = null; + public static int load(ZoneVolume volume, String zoneName, World world, boolean onlyLoadCorners) throws SQLException { + int changed = 0; + File databaseFile = new File(War.war.getDataFolder(), String.format("/dat/warzone-%s/volume-%s.sl3", zoneName, volume.getName())); + if (!databaseFile.exists()) { + // Convert warzone to nimitz file format. + changed = PreNimitzZoneVolumeMapper.load(volume, zoneName, world, onlyLoadCorners); + ZoneVolumeMapper.save(volume, zoneName); + War.war.log("Warzone " + zoneName + " converted to nimitz format!", Level.INFO); + return changed; + } + Connection databaseConnection = DriverManager.getConnection("jdbc:sqlite:" + databaseFile.getPath()); + Statement stmt = databaseConnection.createStatement(); + ResultSet versionQuery = stmt.executeQuery("PRAGMA user_version"); + int version = versionQuery.getInt("user_version"); + versionQuery.close(); + if (version > DATABASE_VERSION) { try { - cornersReader = new BufferedReader(new FileReader(cornersFile)); - blocksStream = new FileInputStream(blocksFile); - signsReader = new BufferedReader(new FileReader(signsFile)); - invsReader = new BufferedReader(new FileReader(invsFile)); - - // Get the corners - cornersReader.readLine(); - int x1 = Integer.parseInt(cornersReader.readLine()); - int y1 = Integer.parseInt(cornersReader.readLine()); - int z1 = Integer.parseInt(cornersReader.readLine()); - cornersReader.readLine(); - int x2 = Integer.parseInt(cornersReader.readLine()); - int y2 = Integer.parseInt(cornersReader.readLine()); - int z2 = Integer.parseInt(cornersReader.readLine()); - - volume.setCornerOne(world.getBlockAt(x1, y1, z1)); - volume.setCornerTwo(world.getBlockAt(x2, y2, z2)); - - // Allocate block byte arrays - int noOfBlocks = volume.getSizeX() * volume.getSizeY() * volume.getSizeZ(); - byte[] blockBytes = new byte[noOfBlocks * 2]; // one byte for type, one for data - - blocksStream.read(blockBytes); // read it all - - // Now use the block bytes to reset the world blocks - if (!onlyLoadCorners) { - DeferredBlockResetsJob deferred = new DeferredBlockResetsJob(world); - int blockReads = 0, visitedBlocks = 0, x = 0, y = 0, z = 0, i = 0, j = 0, k = 0; - int diskBlockType; - byte diskBlockData; - Block worldBlock; - int worldBlockId; - volume.clearBlocksThatDontFloat(); - x = volume.getMinX(); - for (i = 0; i < volume.getSizeX(); i++) { - y = volume.getMinY(); - for (j = 0; j < volume.getSizeY(); j++) { - z = volume.getMinZ(); - for (k = 0; k < volume.getSizeZ(); k++) { - try { - diskBlockType = blockBytes[visitedBlocks * 2]; - diskBlockData = blockBytes[visitedBlocks * 2 + 1]; - - worldBlock = volume.getWorld().getBlockAt(x, y, z); - worldBlockId = worldBlock.getTypeId(); - if (worldBlockId != diskBlockType || (worldBlockId == diskBlockType && worldBlock.getData() != diskBlockData) || (worldBlockId == diskBlockType && worldBlock.getData() == diskBlockData && (diskBlockType == Material.WALL_SIGN.getId() || diskBlockType == Material.SIGN_POST.getId() || diskBlockType == Material.CHEST.getId() || diskBlockType == Material.DISPENSER.getId()))) { - if (diskBlockType == Material.WALL_SIGN.getId() || diskBlockType == Material.SIGN_POST.getId()) { - // Signs read - String linesStr = signsReader.readLine(); - String[] lines = linesStr.split(";;"); - - // Signs set - if (diskBlockType == Material.WALL_SIGN.getId() && ((diskBlockData & 0x04) == 0x04) && i + 1 != volume.getSizeX()) { - // A sign post hanging on a wall south of here needs that block to be set first - deferred.add(new DeferredBlockReset(x, y, z, diskBlockType, diskBlockData, lines)); - } else { - worldBlock.setType(Material.getMaterial(diskBlockType)); - BlockState state = worldBlock.getState(); - state.setData(new org.bukkit.material.Sign(diskBlockType, diskBlockData)); - if (state instanceof Sign) { - Sign sign = (Sign) state; - if (lines != null && sign.getLines() != null) { - if (lines.length > 0) { - sign.setLine(0, lines[0]); - } - if (lines.length > 1) { - sign.setLine(1, lines[1]); - } - if (lines.length > 2) { - sign.setLine(2, lines[2]); - } - if (lines.length > 3) { - sign.setLine(3, lines[3]); - } - sign.update(true); - } - } - } - } else if (diskBlockType == Material.CHEST.getId() || diskBlockType == Material.TRAPPED_CHEST.getId()) { - // Chests read - List items = VolumeMapper.readInventoryString(invsReader.readLine()); - - // Chests set - worldBlock.setType(Material.getMaterial(diskBlockType)); - worldBlock.setData(diskBlockData); - BlockState state = worldBlock.getState(); - if (state instanceof Chest) { - Chest chest = (Chest) state; - if (items != null) { - int ii = 0; - chest.getBlockInventory().clear(); - for (ItemStack item : items) { - if (item != null) { - chest.getBlockInventory().setItem(ii, item); - ii++; - } - } - chest.update(true); - } - } - } else if (diskBlockType == Material.DISPENSER.getId()) { - // Dispensers read - List items = VolumeMapper.readInventoryString(invsReader.readLine()); - - // Dispensers set - worldBlock.setType(Material.getMaterial(diskBlockType)); - worldBlock.setData(diskBlockData); - BlockState state = worldBlock.getState(); - if (state instanceof Dispenser) { - Dispenser dispenser = (Dispenser) state; - if (items != null) { - int ii = 0; - dispenser.getInventory().clear(); - for (ItemStack item : items) { - if (item != null) { - dispenser.getInventory().setItem(ii, item); - ii++; - } - } - dispenser.update(true); - } - } - } else if (diskBlockType == Material.WOODEN_DOOR.getId() || diskBlockType == Material.IRON_DOOR_BLOCK.getId()) { - // Door blocks - deferred.add(new DeferredBlockReset(x, y, z, diskBlockType, diskBlockData)); - } else if (((diskBlockType == Material.TORCH.getId() && ((diskBlockData & 0x02) == 0x02)) || (diskBlockType == Material.REDSTONE_TORCH_OFF.getId() && ((diskBlockData & 0x02) == 0x02)) || (diskBlockType == Material.REDSTONE_TORCH_ON.getId() && ((diskBlockData & 0x02) == 0x02)) || (diskBlockType == Material.LEVER.getId() && ((diskBlockData & 0x02) == 0x02)) || (diskBlockType == Material.STONE_BUTTON.getId() && ((diskBlockData & 0x02) == 0x02)) || (diskBlockType == Material.LADDER.getId() && ((diskBlockData & 0x04) == 0x04)) || (diskBlockType == Material.RAILS.getId() && ((diskBlockData & 0x02) == 0x02))) && i + 1 != volume.getSizeX()) { - // Blocks that hang on a block south of themselves need to make sure that block is there before placing themselves... lol - // Change the block itself later on: - deferred.add(new DeferredBlockReset(x, y, z, diskBlockType, diskBlockData)); - } else { - // regular block - if (diskBlockType >= 0) { - worldBlock.setType(Material.getMaterial(diskBlockType)); - worldBlock.setData(diskBlockData); - } else { - // The larger than 127 block types were stored as bytes, - // but now -128 to -1 are the result of the bad cast from byte - // to int array above. To make matters worse let's make this - // quick a dirty patch. Anyway everything will break horribly - // once block ids get higher than 255. - worldBlock.setType(Material.getMaterial(256 + diskBlockType)); - worldBlock.setData(diskBlockData); - } - } - noOfResetBlocks++; - } - visitedBlocks++; - - blockReads++; - - } catch (Exception e) { - if (!failed) { - // Don't spam the console - War.war.getLogger().warning("Failed to reset block in zone volume " + volume.getName() + ". " + "Blocks read: " + blockReads + ". Visited blocks so far:" + visitedBlocks + ". Blocks reset: " + noOfResetBlocks + ". Error at x:" + x + " y:" + y + " z:" + z + ". Exception:" + e.getClass().toString() + " " + e.getMessage()); - e.printStackTrace(); - failed = true; - } - } finally { - z++; - } - } - y++; - } - x++; - } - if (!deferred.isEmpty()) { - War.war.getServer().getScheduler().scheduleSyncDelayedTask(War.war, deferred, 2); - } - } - } catch (FileNotFoundException e) { - War.war.log("Failed to find volume file " + volume.getName() + " for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); - } catch (IOException e) { - War.war.log("Failed to read volume file " + volume.getName() + " for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); + throw new IllegalStateException("Unsupported zone format " + version); } finally { - try { - if (cornersReader != null) { - cornersReader.close(); - } - if (blocksStream != null) { - blocksStream.close(); - } - if (signsReader != null) { - signsReader.close(); - } - if (invsReader != null) { - invsReader.close(); - } - } catch (IOException e) { - War.war.log("Failed to close volume file " + volume.getName() + " for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); - } + stmt.close(); + databaseConnection.close(); + } + } else if (version < DATABASE_VERSION) { + switch (version) { + // Run some update SQL for each old version } - return noOfResetBlocks; } - } - - /** - * Saves the given volume - * - * @param Volume - * volume Volume to save - * @param String - * zoneName The warzone the volume is located - * @return integer Number of written blocks - */ - public static int save(Volume volume, String zoneName) { - int noOfSavedBlocks = 0; - if (volume.hasTwoCorners()) { - BufferedWriter cornersWriter = null; - FileOutputStream blocksOutput = null; - BufferedWriter signsWriter = null; - BufferedWriter invsWriter = null; + ResultSet cornerQuery = stmt.executeQuery("SELECT * FROM corners"); + cornerQuery.next(); + final Block corner1 = world.getBlockAt(cornerQuery.getInt("x"), cornerQuery.getInt("y"), cornerQuery.getInt("z")); + cornerQuery.next(); + final Block corner2 = world.getBlockAt(cornerQuery.getInt("x"), cornerQuery.getInt("y"), cornerQuery.getInt("z")); + cornerQuery.close(); + volume.setCornerOne(corner1); + volume.setCornerTwo(corner2); + if (onlyLoadCorners) { + stmt.close(); + databaseConnection.close(); + return 0; + } + ResultSet query = stmt.executeQuery("SELECT * FROM blocks"); + while (query.next()) { + int x = query.getInt("x"), y = query.getInt("y"), z = query.getInt("z"); + BlockState modify = corner1.getRelative(x, y, z).getState(); + modify.setType(Material.valueOf(query.getString("type"))); + YamlConfiguration data = new YamlConfiguration(); try { - (new File(War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName)).mkdir(); - String path = War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName(); - cornersWriter = new BufferedWriter(new FileWriter(new File(path + ".corners"))); - blocksOutput = new FileOutputStream(new File(path + ".blocks")); - signsWriter = new BufferedWriter(new FileWriter(new File(path + ".signs"))); - invsWriter = new BufferedWriter(new FileWriter(new File(path + ".invs"))); - - cornersWriter.write("corner1"); - cornersWriter.newLine(); - cornersWriter.write(Integer.toString(volume.getCornerOne().getBlockX())); - cornersWriter.newLine(); - cornersWriter.write(Integer.toString(volume.getCornerOne().getBlockY())); - cornersWriter.newLine(); - cornersWriter.write(Integer.toString(volume.getCornerOne().getBlockZ())); - cornersWriter.newLine(); - cornersWriter.write("corner2"); - cornersWriter.newLine(); - cornersWriter.write(Integer.toString(volume.getCornerTwo().getBlockX())); - cornersWriter.newLine(); - cornersWriter.write(Integer.toString(volume.getCornerTwo().getBlockY())); - cornersWriter.newLine(); - cornersWriter.write(Integer.toString(volume.getCornerTwo().getBlockZ())); - cornersWriter.newLine(); - - int x = 0; - int y = 0; - int z = 0; - Block block; - int typeId; - byte data; - BlockState state; - - x = volume.getMinX(); - for (int i = 0; i < volume.getSizeX(); i++) { - y = volume.getMinY(); - for (int j = 0; j < volume.getSizeY(); j++) { - z = volume.getMinZ(); - for (int k = 0; k < volume.getSizeZ(); k++) { - try { - block = volume.getWorld().getBlockAt(x, y, z); - typeId = block.getTypeId(); - data = block.getData(); - state = block.getState(); - - blocksOutput.write((byte) typeId); - blocksOutput.write(data); - - if (state instanceof Sign) { - // Signs - String extra = ""; - Sign sign = (Sign) state; - if (sign.getLines() != null) { - for (String line : sign.getLines()) { - extra += line + ";;"; - } - signsWriter.write(extra); - signsWriter.newLine(); - } - } else if (state instanceof Chest) { - // Chests - Chest chest = (Chest) state; - Inventory inv = chest.getBlockInventory(); - List items = VolumeMapper.getItemListFromInv(inv); - invsWriter.write(VolumeMapper.buildInventoryStringFromItemList(items)); - invsWriter.newLine(); - } else if (state instanceof Dispenser) { - // Dispensers - Dispenser dispenser = (Dispenser) state; - Inventory inv = dispenser.getInventory(); - List items = VolumeMapper.getItemListFromInv(inv); - invsWriter.write(VolumeMapper.buildInventoryStringFromItemList(items)); - invsWriter.newLine(); - } - noOfSavedBlocks++; - } catch (Exception e) { - War.war.log("Unexpected error while saving a block to " + " file for zone " + zoneName + ". Blocks saved so far: " + noOfSavedBlocks + "Position: x:" + x + " y:" + y + " z:" + z + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); - } finally { - z++; - } + data.loadFromString(query.getString("data")); + modify.setData(data.getItemStack("data").getData()); + } catch (InvalidConfigurationException e) { + War.war.getLogger().log(Level.WARNING, "Exception loading some material data", e); + } + modify.update(true, false); // No-physics update, preventing the need for deferring blocks + modify = corner1.getRelative(x, y, z).getState(); // Grab a new instance + try { + if (modify instanceof Sign) { + final String[] lines = query.getString("sign").split("\n"); + for (int i = 0; i < lines.length; i++) { + ((Sign) modify).setLine(i, lines[i]); + } + } + if (modify instanceof InventoryHolder && query.getString("container") != null) { + YamlConfiguration config = new YamlConfiguration(); + config.loadFromString(query.getString("container")); + ((InventoryHolder) modify).getInventory().clear(); + for (Object obj : config.getList("items")) { + if (obj instanceof ItemStack) { + ((InventoryHolder) modify).getInventory().addItem((ItemStack) obj); } - y++; } - x++; } - } catch (IOException e) { - War.war.log("Failed to write volume file " + zoneName + " for warzone " + volume.getName() + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); - } catch (Exception e) { - War.war.log("Unexpected error caused failure to write volume file " + zoneName + " for warzone " + volume.getName() + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); - } finally { - try { - if (cornersWriter != null) { - cornersWriter.close(); + if (modify instanceof NoteBlock) { + String[] split = query.getString("note").split("\n"); + Note note = new Note(Integer.parseInt(split[1]), Tone.valueOf(split[0]), Boolean.parseBoolean(split[2])); + ((NoteBlock) modify).setNote(note); + } + if (modify instanceof Jukebox) { + ((Jukebox) modify).setPlaying(Material.valueOf(query.getString("record"))); + } + if (modify instanceof Skull && query.getString("skull") != null) { + String[] opts = query.getString("skull").split("\n"); + ((Skull) modify).setOwner(opts[0]); + ((Skull) modify).setSkullType(SkullType.valueOf(opts[1])); + ((Skull) modify).setRotation(BlockFace.valueOf(opts[2])); + } + if (modify instanceof CommandBlock && query.getString("command") != null) { + final String[] commandArray = query.getString("command").split("\n"); + ((CommandBlock) modify).setName(commandArray[0]); + ((CommandBlock) modify).setCommand(commandArray[1]); + } + if (modify instanceof CreatureSpawner) { + ((CreatureSpawner) modify).setSpawnedType(EntityType.valueOf(query.getString("mobid"))); + } + } catch (Exception ex) { + War.war.getLogger().log(Level.WARNING, "Exception loading some tile data", ex); + } + modify.update(true, false); + changed++; + } + query.close(); + stmt.close(); + databaseConnection.close(); + return changed; + } + + /** + * Save all war zone blocks to a SQLite3 database file. + * + * @param volume Volume to save (takes corner data and loads from world). + * @param zoneName Name of warzone to save. + * @return amount of changed blocks + * @throws SQLException + */ + public static int save(Volume volume, String zoneName) throws SQLException { + int changed = 0; + File warzoneDir = new File(War.war.getDataFolder().getPath() + "/dat/warzone-" + zoneName); + warzoneDir.mkdirs(); + File databaseFile = new File(War.war.getDataFolder(), String.format("/dat/warzone-%s/volume-%s.sl3", zoneName, volume.getName())); + Connection databaseConnection = DriverManager.getConnection("jdbc:sqlite:" + databaseFile.getPath()); + Statement stmt = databaseConnection.createStatement(); + stmt.executeUpdate("PRAGMA user_version = " + DATABASE_VERSION); + stmt.executeUpdate("CREATE TABLE IF NOT EXISTS blocks (x BIGINT, y BIGINT, z BIGINT, type TEXT, data BLOB, sign TEXT, container BLOB, note INT, record TEXT, skull TEXT, command TEXT, mobid TEXT)"); + stmt.executeUpdate("CREATE TABLE IF NOT EXISTS corners (pos INTEGER PRIMARY KEY NOT NULL UNIQUE, x INTEGER NOT NULL, y INTEGER NOT NULL, z INTEGER NOT NULL)"); + stmt.executeUpdate("DELETE FROM blocks"); + stmt.executeUpdate("DELETE FROM corners"); + stmt.close(); + PreparedStatement cornerStmt = databaseConnection.prepareStatement("INSERT INTO corners SELECT 1 AS pos, ? AS x, ? AS y, ? AS z UNION SELECT 2, ?, ?, ?"); + cornerStmt.setInt(1, volume.getCornerOne().getBlockX()); + cornerStmt.setInt(2, volume.getCornerOne().getBlockY()); + cornerStmt.setInt(3, volume.getCornerOne().getBlockZ()); + cornerStmt.setInt(4, volume.getCornerTwo().getBlockX()); + cornerStmt.setInt(5, volume.getCornerTwo().getBlockY()); + cornerStmt.setInt(6, volume.getCornerTwo().getBlockZ()); + cornerStmt.executeUpdate(); + cornerStmt.close(); + PreparedStatement dataStmt = databaseConnection.prepareStatement("INSERT INTO blocks VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + databaseConnection.setAutoCommit(false); + final int batchSize = 1000; + for (int i = 0, x = volume.getMinX(); i < volume.getSizeX(); i++, x++) { + for (int j = 0, y = volume.getMinY(); j < volume.getSizeY(); j++, y++) { + for (int k = 0, z = volume.getMinZ(); k < volume.getSizeZ(); k++, z++) { + final Block block = volume.getWorld().getBlockAt(x, y, z); + final Location relLoc = rebase(volume.getCornerOne(), block.getLocation()); + dataStmt.setInt(1, relLoc.getBlockX()); + dataStmt.setInt(2, relLoc.getBlockY()); + dataStmt.setInt(3, relLoc.getBlockZ()); + dataStmt.setString(4, block.getType().toString()); + YamlConfiguration data = new YamlConfiguration(); + data.set("data", block.getState().getData().toItemStack()); + dataStmt.setString(5, data.saveToString()); + if (block.getState() instanceof Sign) { + final String signText = StringUtils.join(((Sign) block.getState()).getLines(), "\n"); + dataStmt.setString(6, signText); + } else { + dataStmt.setNull(6, Types.VARCHAR); } - if (blocksOutput != null) { - blocksOutput.close(); + if (block.getState() instanceof InventoryHolder) { + List items = Arrays.asList(((InventoryHolder) block.getState()).getInventory().getContents()); + YamlConfiguration config = new YamlConfiguration(); + // Serialize to config, then store config in database + config.set("items", items); + dataStmt.setString(7, config.saveToString()); + } else { + dataStmt.setNull(7, Types.BLOB); } - if (signsWriter != null) { - signsWriter.close(); + if (block.getState() instanceof NoteBlock) { + Note note = ((NoteBlock) block.getState()).getNote(); + dataStmt.setString(8, note.getTone().toString() + '\n' + note.getOctave() + '\n' + note.isSharped()); + } else { + dataStmt.setNull(8, Types.VARCHAR); } - if (invsWriter != null) { - invsWriter.close(); + if (block.getState() instanceof Jukebox) { + dataStmt.setString(9, ((Jukebox) block.getState()).getPlaying().toString()); + } else { + dataStmt.setNull(9, Types.VARCHAR); + } + if (block.getState() instanceof Skull) { + dataStmt.setString(10, String.format("%s\n%s\n%s", + ((Skull) block.getState()).getOwner(), + ((Skull) block.getState()).getSkullType().toString(), + ((Skull) block.getState()).getRotation().toString())); + } else { + dataStmt.setNull(10, Types.VARCHAR); + } + if (block.getState() instanceof CommandBlock) { + dataStmt.setString(11, ((CommandBlock) block.getState()).getName() + + "\n" + ((CommandBlock) block.getState()).getCommand()); + } else { + dataStmt.setNull(11, Types.VARCHAR); + } + if (block.getState() instanceof CreatureSpawner) { + dataStmt.setString(12, ((CreatureSpawner) block.getState()).getSpawnedType().toString()); + } else { + dataStmt.setNull(12, Types.VARCHAR); + } + dataStmt.addBatch(); + if (++changed % batchSize == 0) { + dataStmt.executeBatch(); } - } catch (IOException e) { - War.war.log("Failed to close volume file " + volume.getName() + " for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); } } } - return noOfSavedBlocks; - } - - - - /** - * Saves the Volume as a background-job - * - * @param ZoneVolme - * volume volume to save - * @param String - * zoneName The zone the volume is located - * @param War - * war Instance of war - * @param long tickDelay delay before beginning the task - */ - private static void saveAsJob(ZoneVolume volume, String zoneName, long tickDelay) { - ZoneVolumeSaveJob job = new ZoneVolumeSaveJob(volume, zoneName); - War.war.getServer().getScheduler().scheduleSyncDelayedTask(War.war, job, tickDelay); + dataStmt.executeBatch(); // insert remaining records + databaseConnection.commit(); + dataStmt.close(); + databaseConnection.close(); + return changed; } - /** - * Deletes the given volume - * - * @param Volume - * volume volume to delete - * @param War - * war Instance of war - */ - public static void delete(Volume volume) { - ZoneVolumeMapper.deleteFile(War.war.getDataFolder().getPath() + "/dat/volume-" + volume.getName() + ".dat"); - ZoneVolumeMapper.deleteFile(War.war.getDataFolder().getPath() + "/dat/volume-" + volume.getName() + ".corners"); - ZoneVolumeMapper.deleteFile(War.war.getDataFolder().getPath() + "/dat/volume-" + volume.getName() + ".blocks"); - ZoneVolumeMapper.deleteFile(War.war.getDataFolder().getPath() + "/dat/volume-" + volume.getName() + ".signs"); - ZoneVolumeMapper.deleteFile(War.war.getDataFolder().getPath() + "/dat/volume-" + volume.getName() + ".invs"); - } - - /** - * Deletes a volume file - * - * @param String - * path path of file - * @param War - * war Instance of war - */ - private static void deleteFile(String path) { - File volFile = new File(path); - if (volFile.exists()) { - boolean deletedData = volFile.delete(); - if (!deletedData) { - War.war.log("Failed to delete file " + volFile.getName(), Level.WARNING); - } - } + public static Location rebase(final Location base, final Location exact) { + Validate.isTrue(base.getWorld().equals(exact.getWorld()), + "Locations must be in the same world"); + return new Location(base.getWorld(), + exact.getBlockX() - base.getBlockX(), + exact.getBlockY() - base.getBlockY(), + exact.getBlockZ() - base.getBlockZ()); } } diff --git a/war/src/main/java/com/tommytony/war/volume/Volume.java b/war/src/main/java/com/tommytony/war/volume/Volume.java index 9115fad..61a62c6 100644 --- a/war/src/main/java/com/tommytony/war/volume/Volume.java +++ b/war/src/main/java/com/tommytony/war/volume/Volume.java @@ -1,9 +1,7 @@ package com.tommytony.war.volume; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.logging.Level; import org.apache.commons.lang.Validate; import org.bukkit.Location; @@ -12,13 +10,8 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; -import org.bukkit.block.Chest; -import org.bukkit.block.Dispenser; -import org.bukkit.block.Sign; -import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; - import com.tommytony.war.War; import com.tommytony.war.job.BlockResetJob; import com.tommytony.war.utility.Direction; @@ -31,12 +24,9 @@ import com.tommytony.war.utility.Direction; public class Volume { private String name; private World world; - private int[][][] blockTypes = null; - private byte[][][] blockDatas = null; - private HashMap signLines = new HashMap(); - private HashMap> invBlockContents = new HashMap>(); private Location cornerOne; private Location cornerTwo; + private List blocks = new ArrayList(); public Volume(String name, World world) { this.name = name; @@ -78,81 +68,14 @@ public class Volume { this.cornerOne = location; } - public int saveBlocks() { - int noOfSavedBlocks = 0; - int x = 0; - int y = 0; - int z = 0; - try { - if (this.hasTwoCorners()) { - this.setBlockTypes(new int[this.getSizeX()][this.getSizeY()][this.getSizeZ()]); - this.setBlockDatas(new byte[this.getSizeX()][this.getSizeY()][this.getSizeZ()]); - this.getSignLines().clear(); - this.getInvBlockContents().clear(); - x = this.getMinX(); - for (int i = 0; i < this.getSizeX(); i++) { - y = this.getMinY(); - for (int j = 0; j < this.getSizeY(); j++) { - z = this.getMinZ(); - for (int k = 0; k < this.getSizeZ(); k++) { - try { - Block block = this.getWorld().getBlockAt(x, y, z); - this.getBlockTypes()[i][j][k] = block.getTypeId(); - this.getBlockDatas()[i][j][k] = block.getData(); - BlockState state = block.getState(); - if (state instanceof Sign) { - // Signs - Sign sign = (Sign) state; - if (sign.getLines() != null) { - this.getSignLines().put("sign-" + i + "-" + j + "-" + k, sign.getLines()); - } - - } else if (state instanceof Chest) { - // Chests - Chest chest = (Chest) state; - Inventory inv = chest.getInventory(); - int size = inv.getSize(); - List items = new ArrayList(); - for (int invIndex = 0; invIndex < size; invIndex++) { - ItemStack item = inv.getItem(invIndex); - if (item != null && item.getType().getId() != Material.AIR.getId()) { - items.add(item); - } - } - this.getInvBlockContents().put("chest-" + i + "-" + j + "-" + k, items); - } else if (state instanceof Dispenser) { - // Dispensers - Dispenser dispenser = (Dispenser) state; - Inventory inv = dispenser.getInventory(); - int size = inv.getSize(); - List items = new ArrayList(); - for (int invIndex = 0; invIndex < size; invIndex++) { - ItemStack item = inv.getItem(invIndex); - if (item != null && item.getType().getId() != Material.AIR.getId()) { - items.add(item); - } - } - this.getInvBlockContents().put("dispenser-" + i + "-" + j + "-" + k, items); - } - - noOfSavedBlocks++; - } catch (Exception e) { - War.war.getLogger().warning("Failed to save block in volume " + this.getName() + ". Saved blocks so far:" + noOfSavedBlocks + ". Error at x:" + x + " y:" + y + " z:" + z + ". Exception:" + e.getClass().toString() + e.getMessage()); - e.printStackTrace(); - } finally { - z++; - } - } - y++; - } - x++; + public void saveBlocks() { + for (int x = this.getMinX(); x <= this.getMaxX(); x++) { + for (int y = this.getMinY(); y <= this.getMaxY(); y++) { + for (int z = this.getMinZ(); z <= this.getMaxZ(); z++) { + this.blocks.add(world.getBlockAt(x, y, z).getState()); } } - } catch (Exception e) { - War.war.getLogger().warning("Failed to save volume " + this.getName() + " blocks. Saved blocks:" + noOfSavedBlocks + ". Error at x:" + x + " y:" + y + " z:" + z + ". Exception:" + e.getClass().toString() + " " + e.getMessage()); - e.printStackTrace(); } - return noOfSavedBlocks; } public void resetBlocksAsJob() { @@ -160,157 +83,10 @@ public class Volume { War.war.getServer().getScheduler().scheduleSyncDelayedTask(War.war, job); } - public int resetBlocks() { - int visitedBlocks = 0, noOfResetBlocks = 0, x = 0, y = 0, z = 0; - int currentBlockId = 0; - int oldBlockType = 0; - this.clearBlocksThatDontFloat(); - try { - if (this.hasTwoCorners() && this.isSaved()) { - x = this.getMinX(); - for (int i = 0; i < this.getSizeX(); i++) { - y = this.getMinY(); - for (int j = 0; j < this.getSizeY(); j++) { - z = this.getMinZ(); - for (int k = 0; k < this.getSizeZ(); k++) { - try { - oldBlockType = this.getBlockTypes()[i][j][k]; - byte oldBlockData = this.getBlockDatas()[i][j][k]; - Block currentBlock = this.getWorld().getBlockAt(x, y, z); - currentBlockId = currentBlock.getTypeId(); - if (currentBlockId != oldBlockType || (currentBlockId == oldBlockType && currentBlock.getData() != oldBlockData) || (currentBlockId == oldBlockType && currentBlock.getData() == oldBlockData && (oldBlockType == Material.WALL_SIGN.getId() || oldBlockType == Material.SIGN_POST.getId() || oldBlockType == Material.CHEST.getId() || oldBlockType == Material.DISPENSER.getId()))) { - if (oldBlockType == Material.WALL_SIGN.getId() || oldBlockType == Material.SIGN_POST.getId()) { - // Signs - if (oldBlockType == Material.SIGN_POST.getId() && ((oldBlockData & 0x04) == 0x04) && i + 1 != this.getSizeX()) { - Block southBlock = currentBlock.getRelative(Direction.SOUTH()); - int oldSouthBlockType = this.getBlockTypes()[i + 1][j][k]; - byte oldSouthBlockData = this.getBlockDatas()[i + 1][j][k]; - if (southBlock.getTypeId() != oldSouthBlockType) { - southBlock.setTypeId(oldSouthBlockType); - southBlock.setData(oldSouthBlockData); - } - } - currentBlock.setType(Material.getMaterial(oldBlockType)); - BlockState state = currentBlock.getState(); - state.setData(new org.bukkit.material.Sign(oldBlockType, oldBlockData)); - if (state instanceof Sign) { - Sign sign = (Sign) state; - String[] lines = this.getSignLines().get("sign-" + i + "-" + j + "-" + k); - if (lines != null && sign.getLines() != null) { - if (lines.length > 0) { - sign.setLine(0, lines[0]); - } - if (lines.length > 1) { - sign.setLine(1, lines[1]); - } - if (lines.length > 2) { - sign.setLine(2, lines[2]); - } - if (lines.length > 3) { - sign.setLine(3, lines[3]); - } - sign.update(true); - } - } - } else if (oldBlockType == Material.CHEST.getId()) { - // Chests - currentBlock.setType(Material.getMaterial(oldBlockType)); - currentBlock.setData(oldBlockData); - BlockState state = currentBlock.getState(); - if (state instanceof Chest) { - Chest chest = (Chest) state; - List contents = this.getInvBlockContents().get("chest-" + i + "-" + j + "-" + k); - if (contents != null) { - int ii = 0; - chest.getInventory().clear(); - for (ItemStack item : contents) { - if (item != null) { - chest.getInventory().setItem(ii, item); - ii++; - } - } - chest.update(true); - } - } - } else if (oldBlockType == Material.DISPENSER.getId()) { - // Dispensers - currentBlock.setType(Material.getMaterial(oldBlockType)); - currentBlock.setData(oldBlockData); - BlockState state = currentBlock.getState(); - if (state instanceof Dispenser) { - Dispenser dispenser = (Dispenser) state; - List contents = this.getInvBlockContents().get("dispenser-" + i + "-" + j + "-" + k); - if (contents != null) { - int ii = 0; - dispenser.getInventory().clear(); - for (ItemStack item : contents) { - if (item != null) { - dispenser.getInventory().setItem(ii, item); - ii++; - } - } - dispenser.update(true); - } - } - } else if (oldBlockType == Material.WOODEN_DOOR.getId() || oldBlockType == Material.IRON_DOOR_BLOCK.getId()) { - // Door blocks - - // Check if is bottom door block - if (j + 1 < this.getSizeY() && this.getBlockTypes()[i][j + 1][k] == oldBlockType) { - // set both door blocks right away - - Block blockAbove = this.getWorld().getBlockAt(x, y + 1, z); - blockAbove.setType(Material.getMaterial(oldBlockType)); - blockAbove.setData(this.getBlockDatas()[i][j + 1][k]); - - currentBlock.setType(Material.getMaterial(oldBlockType)); - currentBlock.setData(oldBlockData); - } - } else if (((oldBlockType == Material.TORCH.getId() && ((oldBlockData & 0x02) == 0x02)) || (oldBlockType == Material.REDSTONE_TORCH_OFF.getId() && ((oldBlockData & 0x02) == 0x02)) || (oldBlockType == Material.REDSTONE_TORCH_ON.getId() && ((oldBlockData & 0x02) == 0x02)) || (oldBlockType == Material.LEVER.getId() && ((oldBlockData & 0x02) == 0x02)) || (oldBlockType == Material.STONE_BUTTON.getId() && ((oldBlockData & 0x02) == 0x02)) || (oldBlockType == Material.LADDER.getId() && ((oldBlockData & 0x04) == 0x04)) || (oldBlockType == Material.RAILS.getId() && ((oldBlockData & 0x02) == 0x02))) && i + 1 != this.getSizeX()) { - // Blocks that hang on a block south of themselves need to make sure that block is there before placing themselves... lol - Block southBlock = currentBlock.getRelative(Direction.SOUTH()); - int oldSouthBlockType = this.getBlockTypes()[i + 1][j][k]; - byte oldSouthBlockData = this.getBlockDatas()[i + 1][j][k]; - if (southBlock.getTypeId() != oldSouthBlockType) { - southBlock.setTypeId(oldSouthBlockType); - southBlock.setData(oldSouthBlockData); - } - // change the block itself, now that we have a block to set it on - currentBlock.setType(Material.getMaterial(oldBlockType)); - currentBlock.setData(oldBlockData); - } else { - // regular block - currentBlock.setType(Material.getMaterial(oldBlockType)); - currentBlock.setData(oldBlockData); - } - noOfResetBlocks++; - } - visitedBlocks++; - } catch (Exception e) { - War.war.getLogger().warning("Failed to reset block in volume " + this.getName() + ". Visited blocks so far:" + visitedBlocks + ". Blocks reset: " + noOfResetBlocks + ". Error at x:" + x + " y:" + y + " z:" + z + ". Exception:" + e.getClass().toString() + " " + e.getMessage()); - e.printStackTrace(); - } finally { - z++; - } - } - y++; - } - x++; - } - } - } catch (Exception e) { - War.war.log("Failed to reset volume " + this.getName() + " blocks. Blocks visited: " + visitedBlocks + ". Blocks reset: " + noOfResetBlocks + ". Error at x:" + x + " y:" + y + " z:" + z + ". Current block: " + currentBlockId + ". Old block: " + oldBlockType + ". Exception: " + e.getClass().toString() + " " + e.getMessage(), Level.WARNING); - e.printStackTrace(); + public void resetBlocks() { + for (BlockState state : this.blocks) { + state.update(true, false); } - return noOfResetBlocks; - } - - public byte[][][] getBlockDatas() { - return this.blockDatas; - } - - public void setBlockDatas(byte[][][] data) { - this.blockDatas = data; } public void setCornerTwo(Block block) { @@ -400,11 +176,15 @@ public class Volume { } public boolean isSaved() { - return this.getBlockTypes() != null; + return this.blocks.size() > 0; } - public int[][][] getBlockTypes() { - return this.blockTypes; + public List getBlocks() { + return blocks; + } + + public void setBlocks(List blocks) { + this.blocks = blocks; } public Location getCornerOne() { @@ -429,10 +209,6 @@ public class Volume { return this.hasTwoCorners() && block.getWorld().getName().equals(this.world.getName()) && x <= this.getMaxX() && x >= this.getMinX() && y <= this.getMaxY() && y >= this.getMinY() && z <= this.getMaxZ() && z >= this.getMinZ(); } - public void setBlockTypes(int[][][] blockTypes) { - this.blockTypes = blockTypes; - } - public String getName() { return this.name; } @@ -532,30 +308,10 @@ public class Volume { this.replaceMaterials(nonFloatingBlocks, Material.AIR); } - public void setSignLines(HashMap signLines) { - this.signLines = signLines; - } - - public HashMap getSignLines() { - return this.signLines; - } - - public void setInvBlockContents(HashMap> invBlockContents) { - this.invBlockContents = invBlockContents; - } - - public HashMap> getInvBlockContents() { - return this.invBlockContents; - } - @Override public void finalize() { - this.blockDatas = null; - this.blockTypes = null; - this.signLines.clear(); - this.signLines = null; - this.invBlockContents.clear(); - this.invBlockContents = null; + this.blocks.clear(); + this.blocks = null; } public int size() { diff --git a/war/src/main/java/com/tommytony/war/volume/ZoneVolume.java b/war/src/main/java/com/tommytony/war/volume/ZoneVolume.java index e2d0d54..6a28fce 100644 --- a/war/src/main/java/com/tommytony/war/volume/ZoneVolume.java +++ b/war/src/main/java/com/tommytony/war/volume/ZoneVolume.java @@ -1,10 +1,12 @@ package com.tommytony.war.volume; +import java.sql.SQLException; +import java.util.logging.Level; + import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; - import com.tommytony.war.Team; import com.tommytony.war.War; import com.tommytony.war.Warzone; @@ -27,12 +29,17 @@ public class ZoneVolume extends Volume { } @Override - public int saveBlocks() { + public void saveBlocks() { // Save blocks directly to disk (i.e. don't put everything in memory) - int saved = ZoneVolumeMapper.save(this, this.zone.getName()); + int saved = 0; + try { + saved = ZoneVolumeMapper.save(this, this.zone.getName()); + } catch (SQLException ex) { + War.war.log("Failed to save warzone " + zone.getName() + ": " + ex.getMessage(), Level.WARNING); + ex.printStackTrace(); + } War.war.log("Saved " + saved + " blocks in warzone " + this.zone.getName() + ".", java.util.logging.Level.INFO); this.isSaved = true; - return saved; } @Override @@ -40,28 +47,23 @@ public class ZoneVolume extends Volume { return this.isSaved; } - public void loadCorners() { + public void loadCorners() throws SQLException { ZoneVolumeMapper.load(this, this.zone.getName(), this.getWorld(), true); this.isSaved = true; } @Override - public int resetBlocks() { + public void resetBlocks() { // Load blocks directly from disk and onto the map (i.e. no more in-memory warzone blocks) - int reset = ZoneVolumeMapper.load(this, this.zone.getName(), this.getWorld(), false); + int reset = 0; + try { + reset = ZoneVolumeMapper.load(this, this.zone.getName(), this.getWorld(), false); + } catch (SQLException ex) { + War.war.log("Failed to load warzone " + zone.getName() + ": " + ex.getMessage(), Level.WARNING); + ex.printStackTrace(); + } War.war.log("Reset " + reset + " blocks in warzone " + this.zone.getName() + ".", java.util.logging.Level.INFO); this.isSaved = true; - return reset; - } - - @Override - public void setBlockTypes(int[][][] blockTypes) { - return; - } - - @Override - public void setBlockDatas(byte[][][] blockData) { - return; } public void setNorthwest(Location block) throws NotNorthwestException, TooSmallException, TooBigException {