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.");
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
} 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.");

View File

@ -57,6 +57,7 @@ public class Warzone {
private boolean unbreakableZoneBlocks;
private boolean disabled = false;
private boolean noCreatures;
private boolean resetOnEmpty = false;
private HashMap<String, InventoryStash> deadMenInventories = new HashMap<String, InventoryStash>();
private Location rallyPoint;
@ -863,7 +864,7 @@ public class Warzone {
break;
}
}
if(zoneEmpty) {
if(zoneEmpty && resetOnEmpty) {
// reset the zone for a new game when the last player leaves
for(Team team : this.getTeams()) {
team.resetPoints();
@ -1034,7 +1035,7 @@ public class Warzone {
this.getLobby().getVolume().resetBlocks();
this.getLobby().getVolume().finalize();
}
this.getVolume().resetBlocks();
//this.getVolume().resetBlocks();
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
if(zone != null) { // could have failed, would've been logged already
war.getWarzones().add(zone);
zone.getVolume().resetBlocks();
//zone.getVolume().loadCorners();
zone.getVolume().loadCorners();
if(zone.getLobby() != null) {
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.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;
@ -23,6 +26,7 @@ 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;
@ -36,238 +40,191 @@ import com.tommytony.war.volumes.ZoneVolume;
*/
public class ZoneVolumeMapper {
public static int load(ZoneVolume volume, String zoneName, War war, World world) {
BufferedReader in = null;
public static int load(ZoneVolume volume, String zoneName, War war, World world, boolean onlyLoadCorners) {
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;
try {
if(zoneName.equals("")) in = new BufferedReader(new FileReader(new File(war.getDataFolder().getPath() +
"/dat/volume-" + volume.getName() + ".dat"))); // for the warhub
else 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());
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 {
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));
DeferredBlockResetsJob deferred = new DeferredBlockResetsJob(world);
int blockReads = 0, visitedBlocks = 0, x = 0, y = 0, z = 0;
int diskBlockType;
byte diskBlockData;
Block worldBlock;
int worldBlockId;
volume.clearBlocksThatDontFloat();
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 {
String blockLine = in.readLine();
if(blockLine != null && !blockLine.equals("")) {
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);
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(";;");
// 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
// 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;
//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(diskBlockType == Material.CHEST.getId()) {
// Chests read
List<ItemStack> items = new ArrayList<ItemStack>();
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
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 = new ArrayList<ItemStack>();
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
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);
}
}
// 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))
|| (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));
// Signs set
if(diskBlockType == Material.SIGN_POST.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 {
// regular block
worldBlock.setType(Material.getMaterial(diskBlockType));
worldBlock.setData(diskBlockData);
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);
}
}
}
noOfResetBlocks++;
} else if(diskBlockType == Material.CHEST.getId()) {
// Chests read
List<ItemStack> items = 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<ItemStack> items = 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
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);
}
visitedBlocks++;
noOfResetBlocks++;
}
visitedBlocks++;
blockReads++;
}
} catch (Exception e) {
volume.getWar().getLogger().warning("Failed to reset block in zone volume " + volume.getName() + ". "
@ -279,59 +236,88 @@ public class ZoneVolumeMapper {
} 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
}
y++;
}
y++;
x++;
}
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(!deferred.isEmpty()) {
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) {
war.logWarn("Failed to read volume file " + volume.getName() +
" for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage());
e.printStackTrace();
} finally {
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) {
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());
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) {
int noOfSavedBlocks = 0;
if(volume.hasTwoCorners()) {
BufferedWriter out = null;
BufferedWriter cornersWriter = null;
FileOutputStream blocksOutput = null;
BufferedWriter signsWriter = null;
BufferedWriter invsWriter = 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")));
String path = 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")));
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();
cornersWriter.write("corner1"); cornersWriter.newLine();
cornersWriter.write(Integer.toString(volume.getCornerOne().getX())); cornersWriter.newLine();
cornersWriter.write(Integer.toString(volume.getCornerOne().getY())); cornersWriter.newLine();
cornersWriter.write(Integer.toString(volume.getCornerOne().getZ())); cornersWriter.newLine();
cornersWriter.write("corner2"); cornersWriter.newLine();
cornersWriter.write(Integer.toString(volume.getCornerTwo().getX())); cornersWriter.newLine();
cornersWriter.write(Integer.toString(volume.getCornerTwo().getY())); cornersWriter.newLine();
cornersWriter.write(Integer.toString(volume.getCornerTwo().getZ())); cornersWriter.newLine();
int x = 0;
int y = 0;
@ -353,7 +339,8 @@ public class ZoneVolumeMapper {
data = block.getData();
state = block.getState();
out.write(typeId + "," + data + ",");
blocksOutput.write((byte)typeId);
blocksOutput.write(data);
if(state instanceof Sign) {
// Signs
@ -363,9 +350,9 @@ public class ZoneVolumeMapper {
for(String line : sign.getLines()) {
extra += line + ";;";
}
out.write(extra);
signsWriter.write(extra);
signsWriter.newLine();
}
} else if(state instanceof Chest) {
// Chests
Chest chest = (Chest)state;
@ -390,7 +377,8 @@ public class ZoneVolumeMapper {
extra += ";;";
}
}
out.write(extra);
invsWriter.write(extra);
invsWriter.newLine();
}
} else if(state instanceof Dispenser) {
// Dispensers
@ -416,11 +404,11 @@ public class ZoneVolumeMapper {
extra += ";;";
}
}
out.write(extra);
invsWriter.write(extra);
invsWriter.newLine();
}
}
noOfSavedBlocks++;
out.newLine();
}
catch (Exception e) {
war.logWarn("Unexpected error while saving a block to " +
@ -445,24 +433,41 @@ public class ZoneVolumeMapper {
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();
}
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.logWarn("Failed to close volume file " + volume.getName() +
" for warzone " + zoneName + ". " + e.getClass().getName() + " " + e.getMessage());
e.printStackTrace();
}
}
}
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) {
File volFile= new File("War/dat/volume-" + volume.getName());
boolean deletedData = volFile.delete();
if(!deletedData) {
war.logWarn("Failed to delete file " + volFile.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();
if(!deletedData) {
war.logWarn("Failed to delete file " + volFile.getName());
}
}
}

View File

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

View File

@ -39,10 +39,14 @@ public class ZoneVolume extends Volume {
return isSaved;
}
public void loadCorners() {
ZoneVolumeMapper.load(this, zone.getName(), this.getWar(), this.getWorld(), true);
}
@Override
public int resetBlocks() {
// 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() + ".");
isSaved = true;
return reset;