mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2024-11-25 14:46:46 +01:00
Merge branch 'master' of github.com:mcMMO-Dev/mcMMO
This commit is contained in:
commit
7ea3a2bf07
4
pom.xml
4
pom.xml
@ -121,6 +121,10 @@
|
|||||||
</artifactSet>
|
</artifactSet>
|
||||||
<!-- <dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml</dependencyReducedPomLocation>-->
|
<!-- <dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml</dependencyReducedPomLocation>-->
|
||||||
<relocations>
|
<relocations>
|
||||||
|
<relocation>
|
||||||
|
<pattern>net.kyori.examination</pattern>
|
||||||
|
<shadedPattern>com.gmail.nossr50.kyori.examination</shadedPattern>
|
||||||
|
</relocation>
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>net.kyori.adventure</pattern>
|
<pattern>net.kyori.adventure</pattern>
|
||||||
<shadedPattern>com.gmail.nossr50.mcmmo.kyori.adventure</shadedPattern>
|
<shadedPattern>com.gmail.nossr50.mcmmo.kyori.adventure</shadedPattern>
|
||||||
|
@ -253,12 +253,18 @@ public class BlockListener implements Listener {
|
|||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
public void onBlockGrow(BlockGrowEvent event)
|
public void onBlockGrow(BlockGrowEvent event)
|
||||||
{
|
{
|
||||||
|
Block block = event.getBlock();
|
||||||
|
World world = block.getWorld();
|
||||||
|
|
||||||
/* WORLD BLACKLIST CHECK */
|
/* WORLD BLACKLIST CHECK */
|
||||||
if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld()))
|
if(WorldBlacklist.isWorldBlacklisted(world))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
BlockState blockState = event.getBlock().getState();
|
// Minecraft is dumb, the events still throw when a plant "grows" higher than the max block height. Even though no new block is created
|
||||||
mcMMO.getPlaceStore().setFalse(blockState);
|
if (block.getY() >= world.getMaxHeight())
|
||||||
|
return;
|
||||||
|
|
||||||
|
mcMMO.getPlaceStore().setFalse(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -345,7 +345,6 @@ public class mcMMO extends JavaPlugin {
|
|||||||
|
|
||||||
formulaManager.saveFormula();
|
formulaManager.saveFormula();
|
||||||
holidayManager.saveAnniversaryFiles();
|
holidayManager.saveAnniversaryFiles();
|
||||||
placeStore.cleanUp(); // Cleanup empty metadata stores
|
|
||||||
placeStore.closeAll();
|
placeStore.closeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,32 +2,36 @@ package com.gmail.nossr50.util.blockmeta;
|
|||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class BitSetChunkStore implements ChunkStore, Serializable {
|
public class BitSetChunkStore implements ChunkStore {
|
||||||
private static final long serialVersionUID = -1L;
|
|
||||||
transient private boolean dirty = false;
|
|
||||||
// Bitset store conforms to a "bottom-up" bit ordering consisting of a stack of {worldHeight} Y planes, each Y plane consists of 16 Z rows of 16 X bits.
|
|
||||||
private BitSet store;
|
|
||||||
private static final int CURRENT_VERSION = 8;
|
private static final int CURRENT_VERSION = 8;
|
||||||
private static final int MAGIC_NUMBER = 0xEA5EDEBB;
|
private static final int MAGIC_NUMBER = 0xEA5EDEBB;
|
||||||
private int cx;
|
|
||||||
private int cz;
|
|
||||||
private int worldHeight;
|
|
||||||
private UUID worldUid;
|
|
||||||
|
|
||||||
public BitSetChunkStore(World world, int cx, int cz) {
|
private final int cx;
|
||||||
this.cx = cx;
|
private final int cz;
|
||||||
this.cz = cz;
|
private final int worldHeight;
|
||||||
this.worldUid = world.getUID();
|
private final UUID worldUid;
|
||||||
this.worldHeight = world.getMaxHeight();
|
// Bitset store conforms to a "bottom-up" bit ordering consisting of a stack of {worldHeight} Y planes, each Y plane consists of 16 Z rows of 16 X bits.
|
||||||
this.store = new BitSet(16 * 16 * worldHeight);
|
private final BitSet store;
|
||||||
|
|
||||||
|
private transient boolean dirty = false;
|
||||||
|
|
||||||
|
public BitSetChunkStore(@NotNull World world, int cx, int cz) {
|
||||||
|
this(world.getUID(), world.getMaxHeight(), cx, cz);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BitSetChunkStore() {}
|
private BitSetChunkStore(@NotNull UUID worldUid, int worldHeight, int cx, int cz) {
|
||||||
|
this.cx = cx;
|
||||||
|
this.cz = cz;
|
||||||
|
this.worldUid = worldUid;
|
||||||
|
this.worldHeight = worldHeight;
|
||||||
|
this.store = new BitSet(16 * 16 * worldHeight);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDirty() {
|
public boolean isDirty() {
|
||||||
@ -50,7 +54,7 @@ public class BitSetChunkStore implements ChunkStore, Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UUID getWorldId() {
|
public @NotNull UUID getWorldId() {
|
||||||
return worldUid;
|
return worldUid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,58 +85,24 @@ public class BitSetChunkStore implements ChunkStore, Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int coordToIndex(int x, int y, int z) {
|
private int coordToIndex(int x, int y, int z) {
|
||||||
|
return coordToIndex(x, y, z, worldHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int coordToIndex(int x, int y, int z, int worldHeight) {
|
||||||
if (x < 0 || x >= 16 || y < 0 || y >= worldHeight || z < 0 || z >= 16)
|
if (x < 0 || x >= 16 || y < 0 || y >= worldHeight || z < 0 || z >= 16)
|
||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException(String.format("x: %d y: %d z: %d World Height: %d", x, y, z, worldHeight));
|
||||||
return (z * 16 + x) + (256 * y);
|
return (z * 16 + x) + (256 * y);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fixWorldHeight() {
|
private static int getWorldHeight(UUID worldUid, int storedWorldHeight)
|
||||||
|
{
|
||||||
World world = Bukkit.getWorld(worldUid);
|
World world = Bukkit.getWorld(worldUid);
|
||||||
|
|
||||||
// Not sure how this case could come up, but might as well handle it gracefully. Loading a chunkstore for an unloaded world?
|
// Not sure how this case could come up, but might as well handle it gracefully. Loading a chunkstore for an unloaded world?
|
||||||
if (world == null)
|
if (world == null)
|
||||||
return;
|
return storedWorldHeight;
|
||||||
|
|
||||||
// Lop off any extra data if the world height has shrunk
|
return world.getMaxHeight();
|
||||||
int currentWorldHeight = world.getMaxHeight();
|
|
||||||
if (currentWorldHeight < worldHeight)
|
|
||||||
{
|
|
||||||
store.clear(coordToIndex(16, currentWorldHeight, 16), store.length());
|
|
||||||
worldHeight = currentWorldHeight;
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
// If the world height has grown, update the worldHeight variable, but don't bother marking it dirty as unless something else changes we don't need to force a file write;
|
|
||||||
else if (currentWorldHeight > worldHeight)
|
|
||||||
worldHeight = currentWorldHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
|
||||||
throw new UnsupportedOperationException("Serializable support should only be used for legacy deserialization");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
||||||
in.readInt(); // Magic number
|
|
||||||
in.readInt(); // Format version
|
|
||||||
long lsb = in.readLong();
|
|
||||||
long msb = in.readLong();
|
|
||||||
worldUid = new UUID(msb, lsb);
|
|
||||||
cx = in.readInt();
|
|
||||||
cz = in.readInt();
|
|
||||||
|
|
||||||
boolean[][][] oldStore = (boolean[][][]) in.readObject();
|
|
||||||
worldHeight = oldStore[0][0].length;
|
|
||||||
store = new BitSet(16 * 16 * worldHeight / 8);
|
|
||||||
for (int x = 0; x < 16; x++) {
|
|
||||||
for (int z = 0; z < 16; z++) {
|
|
||||||
for (int y = 0; y < worldHeight; y++) {
|
|
||||||
store.set(coordToIndex(x, y, z), oldStore[x][z][y]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dirty = true;
|
|
||||||
fixWorldHeight();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void serialize(DataOutputStream out) throws IOException {
|
private void serialize(DataOutputStream out) throws IOException {
|
||||||
@ -153,7 +123,7 @@ public class BitSetChunkStore implements ChunkStore, Serializable {
|
|||||||
dirty = false;
|
dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BitSetChunkStore deserialize(DataInputStream in) throws IOException {
|
private static BitSetChunkStore deserialize(@NotNull DataInputStream in) throws IOException {
|
||||||
int magic = in.readInt();
|
int magic = in.readInt();
|
||||||
// Can be used to determine the format of the file
|
// Can be used to determine the format of the file
|
||||||
int fileVersionNumber = in.readInt();
|
int fileVersionNumber = in.readInt();
|
||||||
@ -161,28 +131,36 @@ public class BitSetChunkStore implements ChunkStore, Serializable {
|
|||||||
if (magic != MAGIC_NUMBER || fileVersionNumber != CURRENT_VERSION)
|
if (magic != MAGIC_NUMBER || fileVersionNumber != CURRENT_VERSION)
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
|
|
||||||
BitSetChunkStore chunkStore = new BitSetChunkStore();
|
|
||||||
|
|
||||||
long lsb = in.readLong();
|
long lsb = in.readLong();
|
||||||
long msb = in.readLong();
|
long msb = in.readLong();
|
||||||
chunkStore.worldUid = new UUID(msb, lsb);
|
UUID worldUid = new UUID(msb, lsb);
|
||||||
chunkStore.cx = in.readInt();
|
int cx = in.readInt();
|
||||||
chunkStore.cz = in.readInt();
|
int cz = in.readInt();
|
||||||
|
|
||||||
chunkStore.worldHeight = in.readInt();
|
int worldHeight = in.readInt();
|
||||||
byte[] temp = new byte[in.readInt()];
|
byte[] temp = new byte[in.readInt()];
|
||||||
in.readFully(temp);
|
in.readFully(temp);
|
||||||
chunkStore.store = BitSet.valueOf(temp);
|
BitSet stored = BitSet.valueOf(temp);
|
||||||
|
|
||||||
|
int currentWorldHeight = getWorldHeight(worldUid, worldHeight);
|
||||||
|
|
||||||
|
boolean worldHeightShrunk = currentWorldHeight < worldHeight;
|
||||||
|
// Lop off extra data if world height has shrunk
|
||||||
|
if (worldHeightShrunk)
|
||||||
|
stored.clear(coordToIndex(16, currentWorldHeight, 16, worldHeight), stored.length());
|
||||||
|
|
||||||
|
BitSetChunkStore chunkStore = new BitSetChunkStore(worldUid, currentWorldHeight, cx, cz);
|
||||||
|
chunkStore.store.or(stored);
|
||||||
|
chunkStore.dirty = worldHeightShrunk; // In the expanded case there is no reason to re-write it unless the data changes
|
||||||
|
|
||||||
chunkStore.fixWorldHeight();
|
|
||||||
return chunkStore;
|
return chunkStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Serialization {
|
public static class Serialization {
|
||||||
|
|
||||||
public static final short STREAM_MAGIC = (short)0xACDC;
|
public static final short STREAM_MAGIC = (short)0xACDC; // Rock on
|
||||||
|
|
||||||
public static ChunkStore readChunkStore(DataInputStream inputStream) throws IOException {
|
public static @NotNull ChunkStore readChunkStore(DataInputStream inputStream) throws IOException {
|
||||||
if (inputStream.markSupported())
|
if (inputStream.markSupported())
|
||||||
inputStream.mark(2);
|
inputStream.mark(2);
|
||||||
short magicNumber = inputStream.readShort();
|
short magicNumber = inputStream.readShort();
|
||||||
@ -196,7 +174,7 @@ public class BitSetChunkStore implements ChunkStore, Serializable {
|
|||||||
{
|
{
|
||||||
// Creates a new stream with the two magic number bytes and then the rest of the original stream... Java is so dumb. I just wanted to look at two bytes.
|
// Creates a new stream with the two magic number bytes and then the rest of the original stream... Java is so dumb. I just wanted to look at two bytes.
|
||||||
PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream, 2);
|
PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream, 2);
|
||||||
pushbackInputStream.unread((magicNumber >>> 0) & 0xFF);
|
pushbackInputStream.unread((magicNumber) & 0xFF);
|
||||||
pushbackInputStream.unread((magicNumber >>> 8) & 0xFF);
|
pushbackInputStream.unread((magicNumber >>> 8) & 0xFF);
|
||||||
inputStream = new DataInputStream(pushbackInputStream);
|
inputStream = new DataInputStream(pushbackInputStream);
|
||||||
}
|
}
|
||||||
@ -216,8 +194,61 @@ public class BitSetChunkStore implements ChunkStore, Serializable {
|
|||||||
((BitSetChunkStore)chunkStore).serialize(outputStream);
|
((BitSetChunkStore)chunkStore).serialize(outputStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles loading the old serialized classes even though we have changed name/package
|
// Handles loading the old serialized class
|
||||||
private static class LegacyDeserializationInputStream extends ObjectInputStream {
|
private static class LegacyDeserializationInputStream extends ObjectInputStream {
|
||||||
|
private static class LegacyChunkStoreDeserializer implements Serializable
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = -1L;
|
||||||
|
|
||||||
|
private int cx;
|
||||||
|
private int cz;
|
||||||
|
private int worldHeight;
|
||||||
|
private UUID worldUid;
|
||||||
|
private boolean[][][] store;
|
||||||
|
|
||||||
|
private LegacyChunkStoreDeserializer() {}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("You goofed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
|
in.readInt(); // Magic number
|
||||||
|
in.readInt(); // Format version
|
||||||
|
long lsb = in.readLong();
|
||||||
|
long msb = in.readLong();
|
||||||
|
|
||||||
|
worldUid = new UUID(msb, lsb);
|
||||||
|
cx = in.readInt();
|
||||||
|
cz = in.readInt();
|
||||||
|
|
||||||
|
store = (boolean[][][]) in.readObject();
|
||||||
|
worldHeight = store[0][0].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BitSetChunkStore convert()
|
||||||
|
{
|
||||||
|
int currentWorldHeight = getWorldHeight(worldUid, worldHeight);
|
||||||
|
|
||||||
|
BitSetChunkStore converted = new BitSetChunkStore(worldUid, currentWorldHeight, cx, cz);
|
||||||
|
|
||||||
|
// Read old data into new chunkstore
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
for (int y = 0; y < worldHeight && y < currentWorldHeight; y++) {
|
||||||
|
converted.store.set(converted.coordToIndex(x, y, z), store[x][z][y]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Mark dirty so it will be re-written in new format on close
|
||||||
|
converted.dirty = true;
|
||||||
|
return converted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public LegacyDeserializationInputStream(InputStream in) throws IOException {
|
public LegacyDeserializationInputStream(InputStream in) throws IOException {
|
||||||
super(in);
|
super(in);
|
||||||
enableResolveObject(true);
|
enableResolveObject(true);
|
||||||
@ -227,13 +258,14 @@ public class BitSetChunkStore implements ChunkStore, Serializable {
|
|||||||
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
|
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
|
||||||
ObjectStreamClass read = super.readClassDescriptor();
|
ObjectStreamClass read = super.readClassDescriptor();
|
||||||
if (read.getName().contentEquals("com.gmail.nossr50.util.blockmeta.chunkmeta.PrimitiveChunkStore"))
|
if (read.getName().contentEquals("com.gmail.nossr50.util.blockmeta.chunkmeta.PrimitiveChunkStore"))
|
||||||
return ObjectStreamClass.lookup(BitSetChunkStore.class);
|
return ObjectStreamClass.lookup(LegacyChunkStoreDeserializer.class);
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChunkStore readLegacyChunkStore(){
|
public ChunkStore readLegacyChunkStore(){
|
||||||
try {
|
try {
|
||||||
return (ChunkStore) readObject();
|
LegacyChunkStoreDeserializer deserializer = (LegacyChunkStoreDeserializer)readObject();
|
||||||
|
return deserializer.convert();
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1,126 +1,10 @@
|
|||||||
package com.gmail.nossr50.util.blockmeta;
|
package com.gmail.nossr50.util.blockmeta;
|
||||||
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.bukkit.block.BlockState;
|
|
||||||
|
|
||||||
public interface ChunkManager {
|
public interface ChunkManager extends UserBlockTracker {
|
||||||
void closeAll();
|
void closeAll();
|
||||||
|
void chunkUnloaded(int cx, int cz, @NotNull World world);
|
||||||
/**
|
void unloadWorld(@NotNull World world);
|
||||||
* Saves a given Chunk's Chunklet data
|
|
||||||
*
|
|
||||||
* @param cx Chunk X coordinate that is to be saved
|
|
||||||
* @param cz Chunk Z coordinate that is to be saved
|
|
||||||
* @param world World that the Chunk is in
|
|
||||||
*/
|
|
||||||
void saveChunk(int cx, int cz, World world);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Informs the ChunkletManager a chunk is unloaded
|
|
||||||
*
|
|
||||||
* @param cx Chunk X coordinate that is unloaded
|
|
||||||
* @param cz Chunk Z coordinate that is unloaded
|
|
||||||
* @param world World that the chunk was unloaded in
|
|
||||||
*/
|
|
||||||
void chunkUnloaded(int cx, int cz, World world);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save all ChunkletStores related to the given world
|
|
||||||
*
|
|
||||||
* @param world World to save
|
|
||||||
*/
|
|
||||||
void saveWorld(World world);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unload all ChunkletStores from memory related to the given world after saving them
|
|
||||||
*
|
|
||||||
* @param world World to unload
|
|
||||||
*/
|
|
||||||
void unloadWorld(World world);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save all ChunkletStores
|
|
||||||
*/
|
|
||||||
void saveAll();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
boolean isTrue(Block block);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check to see if a given BlockState location is set to true
|
|
||||||
*
|
|
||||||
* @param blockState BlockState to check
|
|
||||||
* @return true if the given BlockState location is set to true, false if otherwise
|
|
||||||
*/
|
|
||||||
boolean isTrue(BlockState blockState);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
void setTrue(Block block);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a given BlockState location to true, should create stores as necessary if the location does not exist
|
|
||||||
*
|
|
||||||
* @param blockState BlockState location to set
|
|
||||||
*/
|
|
||||||
void setTrue(BlockState blockState);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
void setFalse(Block block);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a given BlockState location to false, should not create stores if one does not exist for the given location
|
|
||||||
*
|
|
||||||
* @param blockState BlockState location to set
|
|
||||||
*/
|
|
||||||
void setFalse(BlockState blockState);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete any ChunkletStores that are empty
|
|
||||||
*/
|
|
||||||
void cleanUp();
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package com.gmail.nossr50.util.blockmeta;
|
package com.gmail.nossr50.util.blockmeta;
|
||||||
|
|
||||||
import com.gmail.nossr50.config.HiddenConfig;
|
import com.gmail.nossr50.config.HiddenConfig;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class ChunkManagerFactory {
|
public class ChunkManagerFactory {
|
||||||
public static ChunkManager getChunkManager() {
|
public static @NotNull ChunkManager getChunkManager() {
|
||||||
HiddenConfig hConfig = HiddenConfig.getInstance();
|
HiddenConfig hConfig = HiddenConfig.getInstance();
|
||||||
|
|
||||||
if (hConfig.getChunkletsEnabled()) {
|
if (hConfig.getChunkletsEnabled()) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package com.gmail.nossr50.util.blockmeta;
|
package com.gmail.nossr50.util.blockmeta;
|
||||||
|
|
||||||
import org.bukkit.World;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ public interface ChunkStore {
|
|||||||
*/
|
*/
|
||||||
int getChunkZ();
|
int getChunkZ();
|
||||||
|
|
||||||
UUID getWorldId();
|
@NotNull UUID getWorldId();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the value at the given coordinates
|
* Checks the value at the given coordinates
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
package com.gmail.nossr50.util.blockmeta;
|
package com.gmail.nossr50.util.blockmeta;
|
||||||
|
|
||||||
import com.gmail.nossr50.mcMMO;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.BlockState;
|
import org.bukkit.block.BlockState;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class HashChunkManager implements ChunkManager {
|
public class HashChunkManager implements ChunkManager {
|
||||||
@ -21,7 +25,10 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
{
|
{
|
||||||
if (!chunkStore.isDirty())
|
if (!chunkStore.isDirty())
|
||||||
continue;
|
continue;
|
||||||
writeChunkStore(Bukkit.getWorld(chunkStore.getWorldId()), chunkStore);
|
World world = Bukkit.getWorld(chunkStore.getWorldId());
|
||||||
|
if (world == null)
|
||||||
|
continue; // Oh well
|
||||||
|
writeChunkStore(world, chunkStore);
|
||||||
}
|
}
|
||||||
// Clear in memory chunks
|
// Clear in memory chunks
|
||||||
chunkMap.clear();
|
chunkMap.clear();
|
||||||
@ -32,7 +39,7 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
regionMap.clear();
|
regionMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized ChunkStore readChunkStore(World world, int cx, int cz) throws IOException {
|
private synchronized @Nullable ChunkStore readChunkStore(@NotNull World world, int cx, int cz) throws IOException {
|
||||||
McMMOSimpleRegionFile rf = getSimpleRegionFile(world, cx, cz, false);
|
McMMOSimpleRegionFile rf = getSimpleRegionFile(world, cx, cz, false);
|
||||||
if (rf == null)
|
if (rf == null)
|
||||||
return null; // If there is no region file, there can't be a chunk
|
return null; // If there is no region file, there can't be a chunk
|
||||||
@ -43,7 +50,7 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void writeChunkStore(World world, ChunkStore data) {
|
private synchronized void writeChunkStore(@NotNull World world, @NotNull ChunkStore data) {
|
||||||
if (!data.isDirty())
|
if (!data.isDirty())
|
||||||
return; // Don't save unchanged data
|
return; // Don't save unchanged data
|
||||||
try {
|
try {
|
||||||
@ -58,7 +65,7 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized McMMOSimpleRegionFile getSimpleRegionFile(World world, int cx, int cz, boolean createIfAbsent) {
|
private synchronized @Nullable McMMOSimpleRegionFile getSimpleRegionFile(World world, int cx, int cz, boolean createIfAbsent) {
|
||||||
CoordinateKey regionKey = toRegionKey(world.getUID(), cx, cz);
|
CoordinateKey regionKey = toRegionKey(world.getUID(), cx, cz);
|
||||||
|
|
||||||
return regionMap.computeIfAbsent(regionKey, k -> {
|
return regionMap.computeIfAbsent(regionKey, k -> {
|
||||||
@ -73,7 +80,7 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChunkStore loadChunk(int cx, int cz, World world) {
|
private @Nullable ChunkStore loadChunk(int cx, int cz, World world) {
|
||||||
try {
|
try {
|
||||||
return readChunkStore(world, cx, cz);
|
return readChunkStore(world, cx, cz);
|
||||||
}
|
}
|
||||||
@ -82,7 +89,7 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unloadChunk(int cx, int cz, World world) {
|
private void unloadChunk(int cx, int cz, @NotNull World world) {
|
||||||
CoordinateKey chunkKey = toChunkKey(world.getUID(), cx, cz);
|
CoordinateKey chunkKey = toChunkKey(world.getUID(), cx, cz);
|
||||||
ChunkStore chunkStore = chunkMap.remove(chunkKey); // Remove from chunk map
|
ChunkStore chunkStore = chunkMap.remove(chunkKey); // Remove from chunk map
|
||||||
if (chunkStore == null)
|
if (chunkStore == null)
|
||||||
@ -102,56 +109,12 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void saveChunk(int cx, int cz, World world) {
|
public synchronized void chunkUnloaded(int cx, int cz, @NotNull World world) {
|
||||||
if (world == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CoordinateKey chunkKey = toChunkKey(world.getUID(), cx, cz);
|
|
||||||
|
|
||||||
ChunkStore out = chunkMap.get(chunkKey);
|
|
||||||
|
|
||||||
if (out == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!out.isDirty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
writeChunkStore(world, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void chunkUnloaded(int cx, int cz, World world) {
|
|
||||||
if (world == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
unloadChunk(cx, cz, world);
|
unloadChunk(cx, cz, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void saveWorld(World world) {
|
public synchronized void unloadWorld(@NotNull World world) {
|
||||||
if (world == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
UUID wID = world.getUID();
|
|
||||||
|
|
||||||
// Save all teh chunks
|
|
||||||
for (ChunkStore chunkStore : chunkMap.values()) {
|
|
||||||
if (!chunkStore.isDirty())
|
|
||||||
continue;
|
|
||||||
if (!wID.equals(chunkStore.getWorldId()))
|
|
||||||
continue;
|
|
||||||
try {
|
|
||||||
writeChunkStore(world, chunkStore);
|
|
||||||
}
|
|
||||||
catch (Exception ignore) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void unloadWorld(World world) {
|
|
||||||
if (world == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
UUID wID = world.getUID();
|
UUID wID = world.getUID();
|
||||||
|
|
||||||
// Save and remove all the chunks
|
// Save and remove all the chunks
|
||||||
@ -177,18 +140,7 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private synchronized boolean isTrue(int x, int y, int z, @NotNull World world) {
|
||||||
public synchronized void saveAll() {
|
|
||||||
for (World world : mcMMO.p.getServer().getWorlds()) {
|
|
||||||
saveWorld(world);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized boolean isTrue(int x, int y, int z, World world) {
|
|
||||||
if (world == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
CoordinateKey chunkKey = blockCoordinateToChunkKey(world.getUID(), x, y, z);
|
CoordinateKey chunkKey = blockCoordinateToChunkKey(world.getUID(), x, y, z);
|
||||||
|
|
||||||
// Get chunk, load from file if necessary
|
// Get chunk, load from file if necessary
|
||||||
@ -214,67 +166,36 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean isTrue(Block block) {
|
public synchronized boolean isTrue(@NotNull Block block) {
|
||||||
if (block == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return isTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
return isTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean isTrue(BlockState blockState) {
|
public synchronized boolean isTrue(@NotNull BlockState blockState) {
|
||||||
if (blockState == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return isTrue(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld());
|
return isTrue(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setTrue(int x, int y, int z, World world) {
|
public synchronized void setTrue(@NotNull Block block) {
|
||||||
set(x, y, z, world, true);
|
set(block.getX(), block.getY(), block.getZ(), block.getWorld(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setTrue(Block block) {
|
public synchronized void setTrue(@NotNull BlockState blockState) {
|
||||||
if (block == null)
|
set(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld(), true);
|
||||||
return;
|
|
||||||
|
|
||||||
setTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setTrue(BlockState blockState) {
|
public synchronized void setFalse(@NotNull Block block) {
|
||||||
if (blockState == null)
|
set(block.getX(), block.getY(), block.getZ(), block.getWorld(), false);
|
||||||
return;
|
|
||||||
|
|
||||||
setTrue(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setFalse(int x, int y, int z, World world) {
|
public synchronized void setFalse(@NotNull BlockState blockState) {
|
||||||
set(x, y, z, world, false);
|
set(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private synchronized void set(int x, int y, int z, @NotNull World world, boolean value){
|
||||||
public synchronized void setFalse(Block block) {
|
|
||||||
if (block == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
setFalse(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void setFalse(BlockState blockState) {
|
|
||||||
if (blockState == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
setFalse(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld());
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void set(int x, int y, int z, World world, boolean value){
|
|
||||||
if (world == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CoordinateKey chunkKey = blockCoordinateToChunkKey(world.getUID(), x, y, z);
|
CoordinateKey chunkKey = blockCoordinateToChunkKey(world.getUID(), x, y, z);
|
||||||
|
|
||||||
// Get/Load/Create chunkstore
|
// Get/Load/Create chunkstore
|
||||||
@ -307,15 +228,15 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
cStore.set(ix, y, iz, value);
|
cStore.set(ix, y, iz, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CoordinateKey blockCoordinateToChunkKey(UUID worldUid, int x, int y, int z) {
|
private CoordinateKey blockCoordinateToChunkKey(@NotNull UUID worldUid, int x, int y, int z) {
|
||||||
return toChunkKey(worldUid, x >> 4, z >> 4);
|
return toChunkKey(worldUid, x >> 4, z >> 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CoordinateKey toChunkKey(UUID worldUid, int cx, int cz){
|
private CoordinateKey toChunkKey(@NotNull UUID worldUid, int cx, int cz){
|
||||||
return new CoordinateKey(worldUid, cx, cz);
|
return new CoordinateKey(worldUid, cx, cz);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CoordinateKey toRegionKey(UUID worldUid, int cx, int cz) {
|
private CoordinateKey toRegionKey(@NotNull UUID worldUid, int cx, int cz) {
|
||||||
// Compute region index (32x32 chunk regions)
|
// Compute region index (32x32 chunk regions)
|
||||||
int rx = cx >> 5;
|
int rx = cx >> 5;
|
||||||
int rz = cz >> 5;
|
int rz = cz >> 5;
|
||||||
@ -323,11 +244,11 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final class CoordinateKey {
|
private static final class CoordinateKey {
|
||||||
public final UUID worldID;
|
public final @NotNull UUID worldID;
|
||||||
public final int x;
|
public final int x;
|
||||||
public final int z;
|
public final int z;
|
||||||
|
|
||||||
private CoordinateKey(UUID worldID, int x, int z) {
|
private CoordinateKey(@NotNull UUID worldID, int x, int z) {
|
||||||
this.worldID = worldID;
|
this.worldID = worldID;
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.z = z;
|
this.z = z;
|
||||||
@ -348,7 +269,4 @@ public class HashChunkManager implements ChunkManager {
|
|||||||
return Objects.hash(worldID, x, z);
|
return Objects.hash(worldID, x, z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void cleanUp() {}
|
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.gmail.nossr50.util.blockmeta;
|
package com.gmail.nossr50.util.blockmeta;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.zip.DeflaterOutputStream;
|
import java.util.zip.DeflaterOutputStream;
|
||||||
@ -54,7 +57,7 @@ public class McMMOSimpleRegionFile {
|
|||||||
private final int segmentMask;
|
private final int segmentMask;
|
||||||
|
|
||||||
// File location
|
// File location
|
||||||
private final File parent;
|
private final @NotNull File parent;
|
||||||
// File access
|
// File access
|
||||||
private final RandomAccessFile file;
|
private final RandomAccessFile file;
|
||||||
|
|
||||||
@ -62,7 +65,7 @@ public class McMMOSimpleRegionFile {
|
|||||||
private final int rx;
|
private final int rx;
|
||||||
private final int rz;
|
private final int rz;
|
||||||
|
|
||||||
public McMMOSimpleRegionFile(File f, int rx, int rz) {
|
public McMMOSimpleRegionFile(@NotNull File f, int rx, int rz) {
|
||||||
this.rx = rx;
|
this.rx = rx;
|
||||||
this.rz = rz;
|
this.rz = rz;
|
||||||
this.parent = f;
|
this.parent = f;
|
||||||
@ -104,7 +107,7 @@ public class McMMOSimpleRegionFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized DataOutputStream getOutputStream(int x, int z) {
|
public synchronized @NotNull DataOutputStream getOutputStream(int x, int z) {
|
||||||
int index = getChunkIndex(x, z); // Get chunk index
|
int index = getChunkIndex(x, z); // Get chunk index
|
||||||
return new DataOutputStream(new DeflaterOutputStream(new McMMOSimpleChunkBuffer(this, index)));
|
return new DataOutputStream(new DeflaterOutputStream(new McMMOSimpleChunkBuffer(this, index)));
|
||||||
}
|
}
|
||||||
@ -144,7 +147,7 @@ public class McMMOSimpleRegionFile {
|
|||||||
file.writeInt(chunkNumBytes[index]);
|
file.writeInt(chunkNumBytes[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized DataInputStream getInputStream(int x, int z) throws IOException {
|
public synchronized @Nullable DataInputStream getInputStream(int x, int z) throws IOException {
|
||||||
int index = getChunkIndex(x, z); // Get chunk index
|
int index = getChunkIndex(x, z); // Get chunk index
|
||||||
int byteLength = chunkNumBytes[index]; // Get byte length of data
|
int byteLength = chunkNumBytes[index]; // Get byte length of data
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package com.gmail.nossr50.util.blockmeta;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.BlockState;
|
import org.bukkit.block.BlockState;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class NullChunkManager implements ChunkManager {
|
public class NullChunkManager implements ChunkManager {
|
||||||
|
|
||||||
@ -10,53 +11,30 @@ public class NullChunkManager implements ChunkManager {
|
|||||||
public void closeAll() {}
|
public void closeAll() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveChunk(int cx, int cz, World world) {}
|
public void chunkUnloaded(int cx, int cz, @NotNull World world) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void chunkUnloaded(int cx, int cz, World world) {}
|
public void unloadWorld(@NotNull World world) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveWorld(World world) {}
|
public boolean isTrue(@NotNull Block block) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unloadWorld(World world) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void saveAll() {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isTrue(int x, int y, int z, World world) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTrue(Block block) {
|
public boolean isTrue(@NotNull BlockState blockState) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTrue(BlockState blockState) {
|
public void setTrue(@NotNull Block block) {}
|
||||||
return false;
|
|
||||||
}
|
@Override
|
||||||
|
public void setTrue(@NotNull BlockState blockState) {}
|
||||||
@Override
|
|
||||||
public void setTrue(int x, int y, int z, World world) {}
|
@Override
|
||||||
|
public void setFalse(@NotNull Block block) {}
|
||||||
@Override
|
|
||||||
public void setTrue(Block block) {}
|
@Override
|
||||||
|
public void setFalse(@NotNull BlockState blockState) {}
|
||||||
@Override
|
|
||||||
public void setTrue(BlockState blockState) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFalse(int x, int y, int z, World world) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFalse(Block block) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFalse(BlockState blockState) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cleanUp() {}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package com.gmail.nossr50.util.blockmeta;
|
||||||
|
|
||||||
|
import com.gmail.nossr50.mcMMO;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockState;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains blockstore methods that are safe for external plugins to access.
|
||||||
|
* An instance can be retrieved via {@link mcMMO#getPlaceStore() mcMMO.getPlaceStore()}
|
||||||
|
*/
|
||||||
|
public interface UserBlockTracker {
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
boolean isTrue(@NotNull Block block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if a given BlockState location is set to true
|
||||||
|
*
|
||||||
|
* @param blockState BlockState to check
|
||||||
|
* @return true if the given BlockState location is set to true, false if otherwise
|
||||||
|
*/
|
||||||
|
boolean isTrue(@NotNull BlockState blockState);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a given block location to true
|
||||||
|
*
|
||||||
|
* @param block Block location to set
|
||||||
|
*/
|
||||||
|
void setTrue(@NotNull Block block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a given BlockState location to true
|
||||||
|
*
|
||||||
|
* @param blockState BlockState location to set
|
||||||
|
*/
|
||||||
|
void setTrue(@NotNull BlockState blockState);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a given block location to false
|
||||||
|
*
|
||||||
|
* @param block Block location to set
|
||||||
|
*/
|
||||||
|
void setFalse(@NotNull Block block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a given BlockState location to false
|
||||||
|
*
|
||||||
|
* @param blockState BlockState location to set
|
||||||
|
*/
|
||||||
|
void setFalse(@NotNull BlockState blockState);
|
||||||
|
}
|
@ -2,6 +2,8 @@ import com.gmail.nossr50.util.blockmeta.*;
|
|||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
@ -140,9 +142,20 @@ public class ChunkStoreTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testRegressionChunkMirrorBug() {
|
public void testRegressionChunkMirrorBug() {
|
||||||
ChunkManager chunkManager = new HashChunkManager();
|
ChunkManager chunkManager = new HashChunkManager();
|
||||||
chunkManager.setTrue(15,0,15, mockWorld);
|
Block mockBlockA = mock(Block.class);
|
||||||
chunkManager.setFalse(-15, 0, -15, mockWorld);
|
Mockito.when(mockBlockA.getX()).thenReturn(15);
|
||||||
Assert.assertTrue(chunkManager.isTrue(15, 0, 15, mockWorld));
|
Mockito.when(mockBlockA.getZ()).thenReturn(15);
|
||||||
|
Mockito.when(mockBlockA.getY()).thenReturn(0);
|
||||||
|
Mockito.when(mockBlockA.getWorld()).thenReturn(mockWorld);
|
||||||
|
Block mockBlockB = mock(Block.class);
|
||||||
|
Mockito.when(mockBlockB.getX()).thenReturn(-15);
|
||||||
|
Mockito.when(mockBlockB.getZ()).thenReturn(-15);
|
||||||
|
Mockito.when(mockBlockB.getY()).thenReturn(0);
|
||||||
|
Mockito.when(mockBlockB.getWorld()).thenReturn(mockWorld);
|
||||||
|
|
||||||
|
chunkManager.setTrue(mockBlockA);
|
||||||
|
chunkManager.setFalse(mockBlockB);
|
||||||
|
Assert.assertTrue(chunkManager.isTrue(mockBlockA));
|
||||||
}
|
}
|
||||||
|
|
||||||
private interface Delegate {
|
private interface Delegate {
|
||||||
@ -227,7 +240,7 @@ public class ChunkStoreTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UUID getWorldId() {
|
public @NotNull UUID getWorldId() {
|
||||||
return worldUid;
|
return worldUid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user