Replace Bukkit Metadata for user placed blocks

This commit is contained in:
NuclearW
2012-05-07 22:38:22 -04:00
parent 37d146e8fa
commit b0157c9bd2
13 changed files with 488 additions and 31 deletions

View File

@@ -0,0 +1,106 @@
package com.gmail.nossr50.util.blockmeta;
import org.bukkit.World;
import org.bukkit.block.Block;
public interface ChunkletManager {
/**
* Informs the ChunkletManager a chunk is loaded, it should load appropriate data
*
* @param cx Chunk X coordiate that is loaded
* @param cz Chunk Z coordiate that is loaded
* @param world World that the chunk was loaded in
*/
public void chunkLoaded(int cx, int cz, World world);
/**
* Informs the ChunkletManager a chunk is unloaded, it should unload and save appropriate data
*
* @param cx Chunk X coordiate that is unloaded
* @param cz Chunk Z coordiate that is unloaded
* @param world World that the chunk was unloaded in
*/
public void chunkUnloaded(int cx, int cz, World world);
/**
* Save all ChunkletStores related to the given world
*
* @param world World to save
*/
public void saveWorld(World world);
/**
* Unload all ChunkletStores from memory related to the given world after saving them
*
* @param world World to unload
*/
public void unloadWorld(World world);
/**
* Save all ChunkletStores
*/
public void saveAll();
/**
* Unload all ChunkletStores after saving them
*/
public void unloadAll();
/**
* Check to see if a given location is set to true
*
* @param x X coordinate to check
* @param y Y coordinate to check
* @param z Z coordinate to check
* @param world World to check in
* @return true if the given location is set to true, false if otherwise
*/
public boolean isTrue(int x, int y, int z, World world);
/**
* Check to see if a given block location is set to true
*
* @param block Block location to check
* @return true if the given block location is set to true, false if otherwise
*/
public boolean isTrue(Block block);
/**
* Set a given location to true, should create stores as necessary if the location does not exist
*
* @param x X coordinate to set
* @param y Y coordinate to set
* @param z Z coordinate to set
* @param world World to set in
*/
public void setTrue(int x, int y, int z, World world);
/**
* Set a given block location to true, should create stores as necessary if the location does not exist
*
* @param block Block location to set
*/
public void setTrue(Block block);
/**
* Set a given location to false, should not create stores if one does not exist for the given location
*
* @param x X coordinate to set
* @param y Y coordinate to set
* @param z Z coordinate to set
* @param world World to set in
*/
public void setFalse(int x, int y, int z, World world);
/**
* Set a given block location to false, should not create stores if one does not exist for the given location
*
* @param block Block location to set
*/
public void setFalse(Block block);
/**
* Delete any ChunkletStores that are empty
*/
public void cleanUp();
}

View File

@@ -0,0 +1,36 @@
package com.gmail.nossr50.util.blockmeta;
import java.io.Serializable;
public interface ChunkletStore extends Serializable {
/**
* @param x x coordinate in current chunklet
* @param y y coordinate in current chunklet
* @param z z coordinate in current chunklet
* @return true if the value is true at the given coordinates, false if otherwise
*/
public boolean isTrue(int x, int y, int z);
/**
* Set the value to true at the given coordinates
*
* @param x x coordinate in current chunklet
* @param y y coordinate in current chunklet
* @param z z coordinate in current chunklet
*/
public void setTrue(int x, int y, int z);
/**
* Set the value to false at the given coordinates
*
* @param x x coordinate in current chunklet
* @param y y coordinate in current chunklet
* @param z z coordinate in current chunklet
*/
public void setFalse(int x, int y, int z);
/**
* @return true if all values in the chunklet are false, false if otherwise
*/
public boolean isEmpty();
}

View File

@@ -0,0 +1,227 @@
package com.gmail.nossr50.util.blockmeta;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Block;
public class HashChunkletManager implements ChunkletManager {
private HashMap<String, ChunkletStore> store = new HashMap<String, ChunkletStore>();
public void chunkLoaded(int cx, int cz, World world) {
File dataDir = new File(world.getWorldFolder(), "mcmmo_data");
File cxDir = new File(dataDir, "" + cx);
if(!cxDir.exists()) return;
File czDir = new File(cxDir, "" + cz);
if(!czDir.exists()) return;
for(int y = 1; y <= 4; y++) {
File yFile = new File(czDir, "" + y);
if(!yFile.exists()) {
continue;
} else {
ChunkletStore in = deserializeChunkletStore(yFile);
if(in != null) {
store.put(world.getName() + "," + cx + "," + cz + "," + y, in);
}
}
}
}
public void chunkUnloaded(int cx, int cz, World world) {
boolean found = false;
for(String key : store.keySet()) {
if(key.startsWith(world.getName() + "," + cx + "," + cz)) found = true;
}
if(!found) return;
File dataDir = new File(world.getWorldFolder(), "mcmmo_data");
File cxDir = new File(dataDir, "" + cx);
if(!cxDir.exists()) cxDir.mkdir();
File czDir = new File(cxDir, "" + cz);
if(!czDir.exists()) czDir.mkdir();
for(int y = 1; y <= 4; y++) {
File yFile = new File(czDir, "" + y);
if(store.containsKey(world.getName() + "," + cx + "," + cz + "," + y)) {
ChunkletStore out = store.get(world.getName() + "," + cx + "," + cz + "," + y);
serializeChunkletStore(out, yFile);
}
}
}
public void saveWorld(World world) {
String worldName = world.getName();
File dataDir = new File(world.getWorldFolder(), "mcmmo_data");
for(String key : store.keySet()) {
String[] info = key.split(",");
if(worldName.equals(info[0])) {
File cxDir = new File(dataDir, "" + info[1]);
if(!cxDir.exists()) cxDir.mkdir();
File czDir = new File(cxDir, "" + info[2]);
if(!czDir.exists()) czDir.mkdir();
File yFile = new File(czDir, "" + info[3]);
serializeChunkletStore(store.get(key), yFile);
}
}
}
public void unloadWorld(World world) {
saveWorld(world);
String worldName = world.getName();
for(String key : store.keySet()) {
String tempWorldName = key.split(",")[0];
if(tempWorldName.equals(worldName)) {
store.remove(key);
}
}
}
public void saveAll() {
for(World world : Bukkit.getWorlds()) {
saveWorld(world);
}
}
public void unloadAll() {
saveAll();
for(World world : Bukkit.getWorlds()) {
unloadWorld(world);
}
}
public boolean isTrue(int x, int y, int z, World world) {
int cx = x / 16;
int cz = z / 16;
int cy = y / 64;
if(!store.containsKey(world.getName() + "," + cx + "," + cz + "," + cy)) return false;
ChunkletStore check = store.get(world.getName() + "," + cx + "," + cz + "," + cy);
int ix = Math.abs(x) % 16;
int iz = Math.abs(z) % 16;
int iy = Math.abs(y) % 64;
return check.isTrue(ix, iy, iz);
}
public boolean isTrue(Block block) {
return isTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
}
public void setTrue(int x, int y, int z, World world) {
int cx = x / 16;
int cz = z / 16;
int cy = y / 64;
int ix = Math.abs(x) % 16;
int iz = Math.abs(z) % 16;
int iy = Math.abs(y) % 64;
ChunkletStore cStore;
if(!store.containsKey(world.getName() + "," + cx + "," + cz + "," + cy)) {
cStore = new PrimitiveChunkletStore();
store.put(world.getName() + "," + cx + "," + cz + "," + cy, cStore);
}
cStore = store.get(world.getName() + "," + cx + "," + cz + "," + cy);
cStore.setTrue(ix, iy, iz);
}
public void setTrue(Block block) {
setTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
}
public void setFalse(int x, int y, int z, World world) {
int cx = x / 16;
int cz = z / 16;
int cy = y / 64;
int ix = Math.abs(x) % 16;
int iz = Math.abs(z) % 16;
int iy = Math.abs(y) % 64;
ChunkletStore cStore;
if(!store.containsKey(world.getName() + "," + cx + "," + cz + "," + cy)) {
return; // No need to make a store for something we will be setting to false
}
cStore = store.get(world.getName() + "," + cx + "," + cz + "," + cy);
cStore.setFalse(ix, iy, iz);
}
public void setFalse(Block block) {
setFalse(block.getX(), block.getY(), block.getZ(), block.getWorld());
}
public void cleanUp() {
for(String key : store.keySet()) {
if(store.get(key).isEmpty()) {
String[] info = key.split(",");
File dataDir = new File(Bukkit.getWorld(info[0]).getWorldFolder(), "mcmmo_data");
File cxDir = new File(dataDir, "" + info[1]);
if(!cxDir.exists()) continue;
File czDir = new File(cxDir, "" + info[2]);
if(!czDir.exists()) continue;
File yFile = new File(czDir, "" + info[3]);
yFile.delete();
//Delete empty directories
if(czDir.list().length == 0) czDir.delete();
if(cxDir.list().length == 0) cxDir.delete();
}
}
}
/**
* @param cStore ChunkletStore to save
* @param location Where on the disk to put it
*/
private void serializeChunkletStore(ChunkletStore cStore, File location) {
try {
FileOutputStream fileOut = new FileOutputStream(location);
ObjectOutputStream objOut = new ObjectOutputStream(fileOut);
objOut.writeObject(cStore);
objOut.close();
fileOut.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
/**
* @param location Where on the disk to read from
* @return ChunkletStore from the specified location
*/
private ChunkletStore deserializeChunkletStore(File location) {
ChunkletStore storeIn = null;
try {
FileInputStream fileIn = new FileInputStream(location);
ObjectInputStream objIn = new ObjectInputStream(fileIn);
storeIn = (ChunkletStore) objIn.readObject();
objIn.close();
fileIn.close();
} catch (IOException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
return storeIn;
}
}

View File

@@ -0,0 +1,31 @@
package com.gmail.nossr50.util.blockmeta;
public class PrimitiveChunkletStore implements ChunkletStore {
private static final long serialVersionUID = -3453078050608607478L;
/** X, Z, Y */
private boolean[][][] store = new boolean[16][16][64];
public boolean isTrue(int x, int y, int z) {
return store[x][z][y];
}
public void setTrue(int x, int y, int z) {
store[x][z][y] = true;
}
public void setFalse(int x, int y, int z) {
store[x][z][y] = false;
}
public boolean isEmpty() {
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {
for(int y = 0; y < 64; y++) {
if(store[x][z][y]) return false;
}
}
}
return true;
}
}