mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2025-08-03 13:05:30 +02:00
Replace Bukkit Metadata for user placed blocks
This commit is contained in:
@@ -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();
|
||||
}
|
@@ -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();
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user