Closes gh-223. New zone file format. Reduced RAM usage for resets. Conversion happens during the first reset. Also, zones are not reset at startup or shutdown anymore (may add new setting for that).

This commit is contained in:
taoneill 2011-07-02 22:23:31 -04:00
parent 7fae2a22ff
commit 4d12279ca7
8 changed files with 775 additions and 286 deletions

View File

@ -97,7 +97,7 @@ public class WarEntityListener extends EntityListener {
war.badMsg(a, "Your attack missed! Your target is on your team."); war.badMsg(a, "Your attack missed! Your target is on your team.");
event.setCancelled(true); // ff is off event.setCancelled(true); // ff is off
} }
} else if (attackerTeam == null && defenderTeam == null && !war.isPvpInZonesOnly()){ } else if (attackerTeam == null && defenderTeam == null && (!war.isPvpInZonesOnly() || a.getLocation().getWorld().getName().equals("pvp"))){
// let normal PVP through is its not turned off // let normal PVP through is its not turned off
} else if (attackerTeam == null && defenderTeam == null && war.isPvpInZonesOnly()) { } else if (attackerTeam == null && defenderTeam == null && war.isPvpInZonesOnly()) {
war.badMsg(a, "Your attack missed! Global PVP is turned off. You can only attack other players in warzones. Try /warhub, /zones and /zone."); war.badMsg(a, "Your attack missed! Global PVP is turned off. You can only attack other players in warzones. Try /warhub, /zones and /zone.");

View File

@ -57,6 +57,7 @@ public class Warzone {
private boolean unbreakableZoneBlocks; private boolean unbreakableZoneBlocks;
private boolean disabled = false; private boolean disabled = false;
private boolean noCreatures; private boolean noCreatures;
private boolean resetOnEmpty = false;
private HashMap<String, InventoryStash> deadMenInventories = new HashMap<String, InventoryStash>(); private HashMap<String, InventoryStash> deadMenInventories = new HashMap<String, InventoryStash>();
private Location rallyPoint; private Location rallyPoint;
@ -863,7 +864,7 @@ public class Warzone {
break; break;
} }
} }
if(zoneEmpty) { if(zoneEmpty && resetOnEmpty) {
// reset the zone for a new game when the last player leaves // reset the zone for a new game when the last player leaves
for(Team team : this.getTeams()) { for(Team team : this.getTeams()) {
team.resetPoints(); team.resetPoints();
@ -1034,7 +1035,7 @@ public class Warzone {
this.getLobby().getVolume().resetBlocks(); this.getLobby().getVolume().resetBlocks();
this.getLobby().getVolume().finalize(); this.getLobby().getVolume().finalize();
} }
this.getVolume().resetBlocks(); //this.getVolume().resetBlocks();
this.getVolume().finalize(); this.getVolume().finalize();
} }
} }

View File

@ -26,7 +26,8 @@ public class RestoreWarzonesJob implements Runnable {
Warzone zone = WarzoneMapper.load(war, warzoneName, !newWarInstall); // cascade load, only load blocks if warzone exists Warzone zone = WarzoneMapper.load(war, warzoneName, !newWarInstall); // cascade load, only load blocks if warzone exists
if(zone != null) { // could have failed, would've been logged already if(zone != null) { // could have failed, would've been logged already
war.getWarzones().add(zone); war.getWarzones().add(zone);
zone.getVolume().resetBlocks(); //zone.getVolume().loadCorners();
zone.getVolume().loadCorners();
if(zone.getLobby() != null) { if(zone.getLobby() != null) {
zone.getLobby().getVolume().resetBlocks(); zone.getLobby().getVolume().resetBlocks();
} }

View File

@ -0,0 +1,21 @@
package com.tommytony.war.jobs;
import bukkit.tommytony.war.War;
import com.tommytony.war.mappers.ZoneVolumeMapper;
import com.tommytony.war.volumes.Volume;
public class ZoneVolumeSaveJob extends Thread {
private final Volume volume;
private final String zoneName;
private final War war;
public ZoneVolumeSaveJob(Volume volume, String zoneName, War war) {
this.volume = volume;
this.zoneName = zoneName;
this.war = war;
}
public void run() {
ZoneVolumeMapper.save(volume, zoneName, war);
}
}

View File

@ -0,0 +1,454 @@
package com.tommytony.war.mappers;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
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 org.bukkit.material.MaterialData;
import bukkit.tommytony.war.War;
import com.tommytony.war.jobs.DeferredBlockResetsJob;
import com.tommytony.war.jobs.ZoneVolumeSaveJob;
import com.tommytony.war.utils.DeferredBlockReset;
import com.tommytony.war.volumes.Volume;
import com.tommytony.war.volumes.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
*
*/
public class PreDeGaulleZoneVolumeMapper {
private static List<ItemStack> readInventoryString(String invString) {
List<ItemStack> items = new ArrayList<ItemStack>();
String[] itemsStrSplit = invString.split(";;");
for(String itemStr : itemsStrSplit) {
String[] itemStrSplit = itemStr.split(";");
if(itemStrSplit.length == 4) {
ItemStack stack = new ItemStack(Integer.parseInt(itemStrSplit[0]),
Integer.parseInt(itemStrSplit[1]));
stack.setData(new MaterialData(stack.getTypeId(),Byte.parseByte(itemStrSplit[3])));
short durability = (short)Integer.parseInt(itemStrSplit[2]);
stack.setDurability(durability);
items.add(stack);
} else if(itemStrSplit.length == 3) {
ItemStack stack = new ItemStack(Integer.parseInt(itemStrSplit[0]),
Integer.parseInt(itemStrSplit[1]));
short durability = (short)Integer.parseInt(itemStrSplit[2]);
stack.setDurability(durability);
items.add(stack);
} else {
items.add(new ItemStack(Integer.parseInt(itemStrSplit[0]),
Integer.parseInt(itemStrSplit[1])));
}
}
return items;
}
public static int load(ZoneVolume volume, String zoneName, War war,
World world, boolean onlyLoadCorners) {
BufferedReader in = null;
int noOfResetBlocks = 0;
try {
in = new BufferedReader(new FileReader(new File(war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".dat")));
String firstLine = in.readLine();
if(firstLine != null && !firstLine.equals("")) {
boolean height129Fix = false;
int x1 = Integer.parseInt(in.readLine());
int y1 = Integer.parseInt(in.readLine());
if(y1 == 128) {
height129Fix = true;
y1 = 127;
}
int z1 = Integer.parseInt(in.readLine());
in.readLine();
int x2 = Integer.parseInt(in.readLine());
int y2 = Integer.parseInt(in.readLine());
if(y2 == 128) {
height129Fix = true;
y2 = 127;
}
int z2 = Integer.parseInt(in.readLine());
volume.setCornerOne(world.getBlockAt(x1, y1, z1));
volume.setCornerTwo(world.getBlockAt(x2, y2, z2));
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();
String blockLine;
String[] blockSplit;
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 {
blockLine = in.readLine();
if(blockLine != null && !blockLine.equals("")) {
blockSplit = blockLine.split(",");
if(blockLine != null && !blockLine.equals("") && blockSplit.length > 1) {
diskBlockType = Integer.parseInt(blockSplit[0]);
diskBlockData = Byte.parseByte(blockSplit[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 = "";
if(blockSplit.length > 2) {
for(int o = 2; o < blockSplit.length; o++) {
linesStr += blockSplit[o];
}
String[] lines = linesStr.split(";;");
// Signs set
// A sign post hanging on a wall south of here will
if(diskBlockType == Material.SIGN_POST.getId() && ((diskBlockData & 0x04) == 0x04)
&& i+1 != volume.getSizeX()) {
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<ItemStack> items = null;
if(blockSplit.length > 2) {
String itemsStr = blockSplit[2];
items = readInventoryString(itemsStr);
}
// 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<ItemStack> items = null;
if(blockSplit.length > 2) {
String itemsStr = blockSplit[2];
//String itemsStr = lineScanner.nextLine();
items = readInventoryString(itemsStr);
}
// 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
if(j-1 > 0) {
Block blockBelow = world.getBlockAt(x, y-1, z);
boolean belowIsGlass = blockBelow.getTypeId() == Material.GLASS.getId();
// Set current block to glass if block below isn't glass.
// Having a glass block below means the current block is a door top.
if(belowIsGlass) {
// Top door block. Set both it and the block below as door.
blockBelow.setType(Material.getMaterial(diskBlockType));
blockBelow.setData(diskBlockData);
worldBlock.setType(Material.getMaterial(diskBlockType));
worldBlock.setData(diskBlockData);
} else {
worldBlock.setType(Material.GLASS);
}
}
} 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
worldBlock.setType(Material.getMaterial(diskBlockType));
worldBlock.setData(diskBlockData);
}
noOfResetBlocks++;
}
visitedBlocks++;
}
blockReads++;
}
} catch (Exception e) {
volume.getWar().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();
} finally {
z++;
}
}
if(height129Fix && j == volume.getSizeY() - 1) {
for(int skip = 0; skip < volume.getSizeZ(); skip++) {
in.readLine(); // throw away the extra vertical block I used to save pre 0.8
//scanner.nextLine();
}
}
y++;
}
x++;
}
if(!deferred.isEmpty()) {
war.getServer().getScheduler().scheduleSyncDelayedTask(war, deferred, 1);
}
}
}
} catch (IOException e) {
war.logWarn("Failed to read volume file " + volume.getName() +
" for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage());
e.printStackTrace();
} catch (Exception e) {
war.logWarn("Unexpected error caused failure to read volume file " + zoneName +
" for warzone " + volume.getName() + ". " + e.getClass().getName() + " " + e.getMessage());
e.printStackTrace();
} finally {
if(in != null)
//if(scanner != null)
try {
in.close();
in = null;
//scanner.close();
//scanner = null;
} catch (IOException e) {
war.logWarn("Failed to close file reader for volume " + volume.getName() +
" for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage());
e.printStackTrace();
}
}
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().getX())); out.newLine();
out.write(Integer.toString(volume.getCornerOne().getY())); out.newLine();
out.write(Integer.toString(volume.getCornerOne().getZ())); out.newLine();
out.write("corner2"); out.newLine();
out.write(Integer.toString(volume.getCornerTwo().getX())); out.newLine();
out.write(Integer.toString(volume.getCornerTwo().getY())); out.newLine();
out.write(Integer.toString(volume.getCornerTwo().getZ())); 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<ItemStack> items = new ArrayList<ItemStack>();
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<ItemStack> items = new ArrayList<ItemStack>();
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.logWarn("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());
e.printStackTrace();
} finally {
z++;
}
}
y++;
}
x++;
}
} catch (IOException e) {
war.logWarn("Failed to write volume file " + zoneName +
" for warzone " + volume.getName() + ". " + e.getClass().getName() + " " + e.getMessage());
e.printStackTrace();
} catch (Exception e) {
war.logWarn("Unexpected error caused failure to write volume file " + zoneName +
" for warzone " + volume.getName() + ". " + e.getClass().getName() + " " + e.getMessage());
e.printStackTrace();
}
finally {
if(out != null)
try {
out.close();
} catch (IOException e) {
war.logWarn("Failed to close file writer for volume " + volume.getName() +
" for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage());
e.printStackTrace();
}
}
}
return noOfSavedBlocks;
}
}

View File

@ -3,6 +3,9 @@ package com.tommytony.war.mappers;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader; import java.io.FileReader;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
@ -23,6 +26,7 @@ import org.bukkit.material.MaterialData;
import bukkit.tommytony.war.War; import bukkit.tommytony.war.War;
import com.tommytony.war.jobs.DeferredBlockResetsJob; import com.tommytony.war.jobs.DeferredBlockResetsJob;
import com.tommytony.war.jobs.ZoneVolumeSaveJob;
import com.tommytony.war.utils.DeferredBlockReset; import com.tommytony.war.utils.DeferredBlockReset;
import com.tommytony.war.volumes.Volume; import com.tommytony.war.volumes.Volume;
import com.tommytony.war.volumes.ZoneVolume; import com.tommytony.war.volumes.ZoneVolume;
@ -36,55 +40,73 @@ import com.tommytony.war.volumes.ZoneVolume;
*/ */
public class ZoneVolumeMapper { public class ZoneVolumeMapper {
public static int load(ZoneVolume volume, String zoneName, War war, World world) { public static int load(ZoneVolume volume, String zoneName, War war, World world, boolean onlyLoadCorners) {
BufferedReader in = null; File cornersFile = new File(war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".corners");
File blocksFile = new File(war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".blocks");
File signsFile = new File(war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".signs");
File invsFile = new File(war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".invs");
int noOfResetBlocks = 0; int noOfResetBlocks = 0;
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, war, 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, war, 2);
war.logInfo("Warzone " + zoneName + " file converted!");
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 { try {
if(zoneName.equals("")) in = new BufferedReader(new FileReader(new File(war.getDataFolder().getPath() + cornersReader = new BufferedReader(new FileReader(cornersFile));
"/dat/volume-" + volume.getName() + ".dat"))); // for the warhub blocksStream = new FileInputStream(blocksFile);
else in = new BufferedReader(new FileReader(new File(war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".dat"))); signsReader = new BufferedReader(new FileReader(signsFile));
String firstLine = in.readLine(); invsReader = new BufferedReader(new FileReader(invsFile));
if(firstLine != null && !firstLine.equals("")) {
boolean height129Fix = false; // Get the corners
int x1 = Integer.parseInt(in.readLine()); cornersReader.readLine();
int y1 = Integer.parseInt(in.readLine()); int x1 = Integer.parseInt(cornersReader.readLine());
if(y1 == 128) { int y1 = Integer.parseInt(cornersReader.readLine());
height129Fix = true; int z1 = Integer.parseInt(cornersReader.readLine());
y1 = 127; cornersReader.readLine();
} int x2 = Integer.parseInt(cornersReader.readLine());
int z1 = Integer.parseInt(in.readLine()); int y2 = Integer.parseInt(cornersReader.readLine());
in.readLine(); int z2 = Integer.parseInt(cornersReader.readLine());
int x2 = Integer.parseInt(in.readLine());
int y2 = Integer.parseInt(in.readLine());
if(y2 == 128) {
height129Fix = true;
y2 = 127;
}
int z2 = Integer.parseInt(in.readLine());
volume.setCornerOne(world.getBlockAt(x1, y1, z1)); volume.setCornerOne(world.getBlockAt(x1, y1, z1));
volume.setCornerTwo(world.getBlockAt(x2, y2, z2)); 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); DeferredBlockResetsJob deferred = new DeferredBlockResetsJob(world);
int blockReads = 0, visitedBlocks = 0, x = 0, y = 0, z = 0; int blockReads = 0, visitedBlocks = 0, x = 0, y = 0, z = 0, i = 0, j = 0 , k = 0;
int diskBlockType; int diskBlockType;
byte diskBlockData; byte diskBlockData;
Block worldBlock; Block worldBlock;
int worldBlockId; int worldBlockId;
volume.clearBlocksThatDontFloat(); volume.clearBlocksThatDontFloat();
x = volume.getMinX(); x = volume.getMinX();
for(int i = 0; i < volume.getSizeX(); i++){ for(i = 0; i < volume.getSizeX(); i++){
y = volume.getMinY(); y = volume.getMinY();
for(int j = 0; j < volume.getSizeY(); j++) { for(j = 0; j < volume.getSizeY(); j++) {
z = volume.getMinZ(); z = volume.getMinZ();
for(int k = 0; k < volume.getSizeZ(); k++) { for(k = 0; k < volume.getSizeZ(); k++) {
try { try {
String blockLine = in.readLine(); diskBlockType = blockBytes[visitedBlocks*2];
if(blockLine != null && !blockLine.equals("")) { diskBlockData = blockBytes[visitedBlocks*2+1];
String[] blockSplit = blockLine.split(",");
if(blockLine != null && !blockLine.equals("") && blockSplit.length > 1) {
diskBlockType = Integer.parseInt(blockSplit[0]);
diskBlockData = Byte.parseByte(blockSplit[1]);
worldBlock = volume.getWorld().getBlockAt(x, y, z); worldBlock = volume.getWorld().getBlockAt(x, y, z);
worldBlockId = worldBlock.getTypeId(); worldBlockId = worldBlock.getTypeId();
if(worldBlockId != diskBlockType || if(worldBlockId != diskBlockType ||
@ -97,17 +119,13 @@ public class ZoneVolumeMapper {
if(diskBlockType == Material.WALL_SIGN.getId() if(diskBlockType == Material.WALL_SIGN.getId()
|| diskBlockType == Material.SIGN_POST.getId()) { || diskBlockType == Material.SIGN_POST.getId()) {
// Signs read // Signs read
String linesStr = ""; String linesStr = signsReader.readLine();
if(blockSplit.length > 2) {
for(int o = 2; o < blockSplit.length; o++) {
linesStr += blockSplit[o];
}
String[] lines = linesStr.split(";;"); String[] lines = linesStr.split(";;");
// Signs set // Signs set
// A sign post hanging on a wall south of here will
if(diskBlockType == Material.SIGN_POST.getId() && ((diskBlockData & 0x04) == 0x04) if(diskBlockType == Material.SIGN_POST.getId() && ((diskBlockData & 0x04) == 0x04)
&& i+1 != volume.getSizeX()) { && 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)); deferred.add(new DeferredBlockReset(x, y, z, diskBlockType, diskBlockData, lines));
} else { } else {
worldBlock.setType(Material.getMaterial(diskBlockType)); worldBlock.setType(Material.getMaterial(diskBlockType));
@ -115,7 +133,6 @@ public class ZoneVolumeMapper {
state.setData(new org.bukkit.material.Sign(diskBlockType, diskBlockData)); state.setData(new org.bukkit.material.Sign(diskBlockType, diskBlockData));
if(state instanceof Sign) { if(state instanceof Sign) {
Sign sign = (Sign)state; Sign sign = (Sign)state;
//String[] lines = this.getSignLines().get("sign-" + i + "-" + j + "-" + k);
if(lines != null && sign.getLines() != null) { if(lines != null && sign.getLines() != null) {
if(lines.length>0)sign.setLine(0, lines[0]); if(lines.length>0)sign.setLine(0, lines[0]);
if(lines.length>1)sign.setLine(1, lines[1]); if(lines.length>1)sign.setLine(1, lines[1]);
@ -125,34 +142,9 @@ public class ZoneVolumeMapper {
} }
} }
} }
}
} else if(diskBlockType == Material.CHEST.getId()) { } else if(diskBlockType == Material.CHEST.getId()) {
// Chests read // Chests read
List<ItemStack> items = new ArrayList<ItemStack>(); List<ItemStack> items = readInventoryString(invsReader.readLine());
if(blockSplit.length > 2) {
String itemsStr = blockSplit[2];
String[] itemsStrSplit = itemsStr.split(";;");
for(String itemStr : itemsStrSplit) {
String[] itemStrSplit = itemStr.split(";");
if(itemStrSplit.length == 4) {
ItemStack stack = new ItemStack(Integer.parseInt(itemStrSplit[0]),
Integer.parseInt(itemStrSplit[1]));
stack.setData(new MaterialData(stack.getTypeId(),Byte.parseByte(itemStrSplit[3])));
short durability = (short)Integer.parseInt(itemStrSplit[2]);
stack.setDurability(durability);
items.add(stack);
} else if(itemStrSplit.length == 3) {
ItemStack stack = new ItemStack(Integer.parseInt(itemStrSplit[0]),
Integer.parseInt(itemStrSplit[1]));
short durability = (short)Integer.parseInt(itemStrSplit[2]);
stack.setDurability(durability);
items.add(stack);
} else {
items.add(new ItemStack(Integer.parseInt(itemStrSplit[0]),
Integer.parseInt(itemStrSplit[1])));
}
}
}
// Chests set // Chests set
worldBlock.setType(Material.getMaterial(diskBlockType)); worldBlock.setType(Material.getMaterial(diskBlockType));
@ -174,31 +166,7 @@ public class ZoneVolumeMapper {
} }
} else if(diskBlockType == Material.DISPENSER.getId()) { } else if(diskBlockType == Material.DISPENSER.getId()) {
// Dispensers read // Dispensers read
List<ItemStack> items = new ArrayList<ItemStack>(); List<ItemStack> items = readInventoryString(invsReader.readLine());
if(blockSplit.length > 2) {
String itemsStr = blockSplit[2];
String[] itemsStrSplit = itemsStr.split(";;");
for(String itemStr : itemsStrSplit) {
String[] itemStrSplit = itemStr.split(";");
if(itemStrSplit.length == 4) {
ItemStack stack = new ItemStack(Integer.parseInt(itemStrSplit[0]),
Integer.parseInt(itemStrSplit[1]));
stack.setData(new MaterialData(stack.getTypeId(),Byte.parseByte(itemStrSplit[3])));
short durability = (short)Integer.parseInt(itemStrSplit[2]);
stack.setDurability(durability);
items.add(stack);
} else if(itemStrSplit.length == 3) {
ItemStack stack = new ItemStack(Integer.parseInt(itemStrSplit[0]),
Integer.parseInt(itemStrSplit[1]));
short durability = (short)Integer.parseInt(itemStrSplit[2]);
stack.setDurability(durability);
items.add(stack);
} else {
items.add(new ItemStack(Integer.parseInt(itemStrSplit[0]),
Integer.parseInt(itemStrSplit[1])));
}
}
}
// Dispensers set // Dispensers set
worldBlock.setType(Material.getMaterial(diskBlockType)); worldBlock.setType(Material.getMaterial(diskBlockType));
@ -236,16 +204,6 @@ public class ZoneVolumeMapper {
worldBlock.setType(Material.GLASS); worldBlock.setType(Material.GLASS);
} }
} }
// Check if is bottom door block
// if(j+1 <= volume.getSizeY() && getBlockTypes()[i][j+1][k] == diskBlockType) {
// // set both door blocks right away
// worldBlock.setType(Material.getMaterial(diskBlockType));
// worldBlock.setData(diskBlockData);
// Block blockAbove = volume.getWorld().getBlockAt(x, y+1, z);
// blockAbove.setType(Material.getMaterial(diskBlockType));
// blockAbove.setData(getBlockDatas()[i][j+1][k]);
// }
} else if(((diskBlockType == Material.TORCH.getId() && ((diskBlockData & 0x02) == 0x02)) } else if(((diskBlockType == Material.TORCH.getId() && ((diskBlockData & 0x02) == 0x02))
|| (diskBlockType == Material.REDSTONE_TORCH_OFF.getId() && ((diskBlockData & 0x02) == 0x02)) || (diskBlockType == Material.REDSTONE_TORCH_OFF.getId() && ((diskBlockData & 0x02) == 0x02))
|| (diskBlockType == Material.REDSTONE_TORCH_ON.getId() && ((diskBlockData & 0x02) == 0x02)) || (diskBlockType == Material.REDSTONE_TORCH_ON.getId() && ((diskBlockData & 0x02) == 0x02))
@ -265,9 +223,8 @@ public class ZoneVolumeMapper {
noOfResetBlocks++; noOfResetBlocks++;
} }
visitedBlocks++; visitedBlocks++;
}
blockReads++; blockReads++;
}
} catch (Exception e) { } catch (Exception e) {
volume.getWar().getLogger().warning("Failed to reset block in zone volume " + volume.getName() + ". " volume.getWar().getLogger().warning("Failed to reset block in zone volume " + volume.getName() + ". "
@ -280,11 +237,6 @@ public class ZoneVolumeMapper {
z++; z++;
} }
} }
if(height129Fix && j == volume.getSizeY() - 1) {
for(int skip = 0; skip < volume.getSizeZ(); skip++) {
in.readLine(); // throw away the extra vertical block I used to save pre 0.8
}
}
y++; y++;
} }
x++; x++;
@ -293,45 +245,79 @@ public class ZoneVolumeMapper {
war.getServer().getScheduler().scheduleSyncDelayedTask(war, deferred, 1); war.getServer().getScheduler().scheduleSyncDelayedTask(war, deferred, 1);
} }
} }
} catch (FileNotFoundException e) {
war.logWarn("Failed to find volume file " + volume.getName() +
" for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage());
e.printStackTrace();
} catch (IOException e) { } catch (IOException e) {
war.logWarn("Failed to read volume file " + volume.getName() + war.logWarn("Failed to read volume file " + volume.getName() +
" for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage()); " for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
} catch (Exception e) {
war.logWarn("Unexpected error caused failure to read volume file " + zoneName +
" for warzone " + volume.getName() + ". " + e.getClass().getName() + " " + e.getMessage());
e.printStackTrace();
} finally { } finally {
if(in != null)
try { try {
in.close(); if(cornersReader != null) cornersReader.close();
if(blocksStream != null) blocksStream.close();
if(signsReader != null) signsReader.close();
if(invsReader != null) invsReader.close();
} catch (IOException e) { } catch (IOException e) {
war.logWarn("Failed to close file reader for volume " + volume.getName() + war.logWarn("Failed to close volume file " + volume.getName() +
" for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage()); " for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
} }
} }
return noOfResetBlocks; return noOfResetBlocks;
} }
}
private static List<ItemStack> readInventoryString(String invString) {
List<ItemStack> items = new ArrayList<ItemStack>();
String[] itemsStrSplit = invString.split(";;");
for(String itemStr : itemsStrSplit) {
String[] itemStrSplit = itemStr.split(";");
if(itemStrSplit.length == 4) {
ItemStack stack = new ItemStack(Integer.parseInt(itemStrSplit[0]),
Integer.parseInt(itemStrSplit[1]));
stack.setData(new MaterialData(stack.getTypeId(),Byte.parseByte(itemStrSplit[3])));
short durability = (short)Integer.parseInt(itemStrSplit[2]);
stack.setDurability(durability);
items.add(stack);
} else if(itemStrSplit.length == 3) {
ItemStack stack = new ItemStack(Integer.parseInt(itemStrSplit[0]),
Integer.parseInt(itemStrSplit[1]));
short durability = (short)Integer.parseInt(itemStrSplit[2]);
stack.setDurability(durability);
items.add(stack);
} else {
items.add(new ItemStack(Integer.parseInt(itemStrSplit[0]),
Integer.parseInt(itemStrSplit[1])));
}
}
return items;
}
public static int save(Volume volume, String zoneName, War war) { public static int save(Volume volume, String zoneName, War war) {
int noOfSavedBlocks = 0; int noOfSavedBlocks = 0;
if(volume.hasTwoCorners()) { if(volume.hasTwoCorners()) {
BufferedWriter out = null; BufferedWriter cornersWriter = null;
FileOutputStream blocksOutput = null;
BufferedWriter signsWriter = null;
BufferedWriter invsWriter = null;
try { try {
(new File(war.getDataFolder().getPath() +"/dat/warzone-"+zoneName)).mkdir(); (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"))); String path = war.getDataFolder().getPath() + "/dat/warzone-" + zoneName + "/volume-" + volume.getName();
else out = new BufferedWriter(new FileWriter(new File(war.getDataFolder().getPath() + cornersWriter = new BufferedWriter(new FileWriter(new File(path + ".corners")));
"/dat/warzone-" + zoneName + "/volume-" + volume.getName() + ".dat"))); 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")));
out.write("corner1"); out.newLine(); cornersWriter.write("corner1"); cornersWriter.newLine();
out.write(Integer.toString(volume.getCornerOne().getX())); out.newLine(); cornersWriter.write(Integer.toString(volume.getCornerOne().getX())); cornersWriter.newLine();
out.write(Integer.toString(volume.getCornerOne().getY())); out.newLine(); cornersWriter.write(Integer.toString(volume.getCornerOne().getY())); cornersWriter.newLine();
out.write(Integer.toString(volume.getCornerOne().getZ())); out.newLine(); cornersWriter.write(Integer.toString(volume.getCornerOne().getZ())); cornersWriter.newLine();
out.write("corner2"); out.newLine(); cornersWriter.write("corner2"); cornersWriter.newLine();
out.write(Integer.toString(volume.getCornerTwo().getX())); out.newLine(); cornersWriter.write(Integer.toString(volume.getCornerTwo().getX())); cornersWriter.newLine();
out.write(Integer.toString(volume.getCornerTwo().getY())); out.newLine(); cornersWriter.write(Integer.toString(volume.getCornerTwo().getY())); cornersWriter.newLine();
out.write(Integer.toString(volume.getCornerTwo().getZ())); out.newLine(); cornersWriter.write(Integer.toString(volume.getCornerTwo().getZ())); cornersWriter.newLine();
int x = 0; int x = 0;
int y = 0; int y = 0;
@ -353,7 +339,8 @@ public class ZoneVolumeMapper {
data = block.getData(); data = block.getData();
state = block.getState(); state = block.getState();
out.write(typeId + "," + data + ","); blocksOutput.write((byte)typeId);
blocksOutput.write(data);
if(state instanceof Sign) { if(state instanceof Sign) {
// Signs // Signs
@ -363,9 +350,9 @@ public class ZoneVolumeMapper {
for(String line : sign.getLines()) { for(String line : sign.getLines()) {
extra += line + ";;"; extra += line + ";;";
} }
out.write(extra); signsWriter.write(extra);
signsWriter.newLine();
} }
} else if(state instanceof Chest) { } else if(state instanceof Chest) {
// Chests // Chests
Chest chest = (Chest)state; Chest chest = (Chest)state;
@ -390,7 +377,8 @@ public class ZoneVolumeMapper {
extra += ";;"; extra += ";;";
} }
} }
out.write(extra); invsWriter.write(extra);
invsWriter.newLine();
} }
} else if(state instanceof Dispenser) { } else if(state instanceof Dispenser) {
// Dispensers // Dispensers
@ -416,11 +404,11 @@ public class ZoneVolumeMapper {
extra += ";;"; extra += ";;";
} }
} }
out.write(extra); invsWriter.write(extra);
invsWriter.newLine();
} }
} }
noOfSavedBlocks++; noOfSavedBlocks++;
out.newLine();
} }
catch (Exception e) { catch (Exception e) {
war.logWarn("Unexpected error while saving a block to " + war.logWarn("Unexpected error while saving a block to " +
@ -445,11 +433,13 @@ public class ZoneVolumeMapper {
e.printStackTrace(); e.printStackTrace();
} }
finally { finally {
if(out != null)
try { try {
out.close(); if(cornersWriter != null) cornersWriter.close();
if(blocksOutput != null) blocksOutput.close();
if(signsWriter != null) signsWriter.close();
if(invsWriter != null) invsWriter.close();
} catch (IOException e) { } catch (IOException e) {
war.logWarn("Failed to close file writer for volume " + volume.getName() + war.logWarn("Failed to close volume file " + volume.getName() +
" for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage()); " for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
} }
@ -458,13 +448,28 @@ public class ZoneVolumeMapper {
return noOfSavedBlocks; return noOfSavedBlocks;
} }
private static void saveAsJob(ZoneVolume volume, String zoneName, War war, long tickDelay) {
ZoneVolumeSaveJob job = new ZoneVolumeSaveJob(volume, zoneName, war);
war.getServer().getScheduler().scheduleSyncDelayedTask(war, job, tickDelay);
}
public static void delete(Volume volume, War war) { public static void delete(Volume volume, War war) {
File volFile= new File("War/dat/volume-" + volume.getName()); deleteFile("War/dat/volume-" + volume.getName() + ".dat", war);
deleteFile("War/dat/volume-" + volume.getName() + ".corners", war);
deleteFile("War/dat/volume-" + volume.getName() + ".blocks", war);
deleteFile("War/dat/volume-" + volume.getName() + ".signs", war);
deleteFile("War/dat/volume-" + volume.getName() + ".invs", war);
}
private static void deleteFile(String path, War war) {
File volFile= new File(path);
if(volFile.exists()) {
boolean deletedData = volFile.delete(); boolean deletedData = volFile.delete();
if(!deletedData) { if(!deletedData) {
war.logWarn("Failed to delete file " + volFile.getName()); war.logWarn("Failed to delete file " + volFile.getName());
} }
} }
}
} }

View File

@ -489,14 +489,17 @@ public class Volume {
private void switchMaterials(Material[] oldTypes, Material newType) { private void switchMaterials(Material[] oldTypes, Material newType) {
try { try {
int i = 0, j = 0, k = 0;
int x, y, z;
Block currentBlock = null;
if(hasTwoCorners() && isSaved()) { if(hasTwoCorners() && isSaved()) {
int x = getMinX(); x = getMinX();
for(int i = 0; i < getSizeX(); i++){ for(i = 0; i < getSizeX(); i++){
int y = getMaxY(); y = getMaxY();
for(int j = getSizeY(); j > 0; j--){ for(j = getSizeY(); j > 0; j--){
int z = getMinZ(); z = getMinZ();
for(int k = 0;k < getSizeZ(); k++) { for(k = 0;k < getSizeZ(); k++) {
Block currentBlock = getWorld().getBlockAt(x, y, z); currentBlock = getWorld().getBlockAt(x, y, z);
for(Material oldType : oldTypes) { for(Material oldType : oldTypes) {
if(currentBlock.getType().getId() == oldType.getId()) { if(currentBlock.getType().getId() == oldType.getId()) {
currentBlock.setType(newType); currentBlock.setType(newType);

View File

@ -39,10 +39,14 @@ public class ZoneVolume extends Volume {
return isSaved; return isSaved;
} }
public void loadCorners() {
ZoneVolumeMapper.load(this, zone.getName(), this.getWar(), this.getWorld(), true);
}
@Override @Override
public int resetBlocks() { public int resetBlocks() {
// Load blocks directly from disk and onto the map (i.e. no more in-memory warzone blocks) // Load blocks directly from disk and onto the map (i.e. no more in-memory warzone blocks)
int reset = ZoneVolumeMapper.load(this, zone.getName(), this.getWar(), this.getWorld()); int reset = ZoneVolumeMapper.load(this, zone.getName(), this.getWar(), this.getWorld(), false);
getWar().logInfo("Reset " + reset + " blocks in warzone " + zone.getName() + "."); getWar().logInfo("Reset " + reset + " blocks in warzone " + zone.getName() + ".");
isSaved = true; isSaved = true;
return reset; return reset;