From 5b5ec10bda1f09f7f3a68d1b426ec55a20ffc916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20R=C4=99bacz?= Date: Tue, 14 Dec 2021 21:40:18 +0100 Subject: [PATCH] Made all metadata calls async. Removed ChunkBusyExceptio, ChunkNotLoadedException and ChunkAlreadyLoadedException --- README.md | 4 +- build.gradle | 2 +- .../blockmetadata/BlockMetadataStorage.java | 185 ++++++++---------- .../event/BlockDestroyHandler.java | 9 +- .../blockmetadata/event/BlockMoveHandler.java | 12 +- .../blockmetadata/event/ChunkLoadHandler.java | 16 +- .../event/PluginDisableHandler.java | 6 +- .../ChunkAlreadyLoadedException.java | 7 - .../exception/ChunkBusyException.java | 7 - .../exception/ChunkNotLoadedException.java | 7 - .../BlockIntegerMetadataStorageTest.java | 2 +- .../BlockMetadataStorageTest.java | 110 +++++------ .../event/BlockDestroyHandlerTest.java | 9 +- .../event/BlockMoveHandlerTest.java | 19 +- .../event/ChunkLoadHandlerTest.java | 18 +- 15 files changed, 160 insertions(+), 253 deletions(-) delete mode 100644 src/main/java/me/matoosh/blockmetadata/exception/ChunkAlreadyLoadedException.java delete mode 100644 src/main/java/me/matoosh/blockmetadata/exception/ChunkBusyException.java delete mode 100644 src/main/java/me/matoosh/blockmetadata/exception/ChunkNotLoadedException.java diff --git a/README.md b/README.md index bb223a5..2b8fd0f 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ repositories { } dependencies { - implementation 'com.github.itsMatoosh:block-metadata:1.3.1' + implementation 'com.github.itsMatoosh:block-metadata:1.4.0' } ``` ### Adding Block Metadata by Maven @@ -28,7 +28,7 @@ Modify your pom.xml file to include the following: com.github.itsMatoosh block-metadata - 1.3.1 + 1.4.0 ``` diff --git a/build.gradle b/build.gradle index e22b7c5..c9b1a8e 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { } group 'me.matoosh' -version '1.3.1' +version '1.4.0' sourceCompatibility = JavaVersion.VERSION_1_8 diff --git a/src/main/java/me/matoosh/blockmetadata/BlockMetadataStorage.java b/src/main/java/me/matoosh/blockmetadata/BlockMetadataStorage.java index 26132c9..2e32564 100644 --- a/src/main/java/me/matoosh/blockmetadata/BlockMetadataStorage.java +++ b/src/main/java/me/matoosh/blockmetadata/BlockMetadataStorage.java @@ -12,9 +12,6 @@ import me.matoosh.blockmetadata.event.BlockMoveHandler; import me.matoosh.blockmetadata.event.ChunkLoadHandler; import me.matoosh.blockmetadata.event.PluginDisableHandler; -import me.matoosh.blockmetadata.exception.ChunkAlreadyLoadedException; -import me.matoosh.blockmetadata.exception.ChunkBusyException; -import me.matoosh.blockmetadata.exception.ChunkNotLoadedException; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.block.Block; @@ -30,7 +27,6 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; -import java.util.concurrent.ExecutionException; import java.util.function.Function; /** @@ -131,113 +127,124 @@ public BlockMetadataStorage(JavaPlugin plugin, Path dataPath) { * Get metadata of a block. * @param block The block. * @return Current metadata of the block. Null if no data stored. - * @throws ChunkBusyException Thrown if the chunk is busy. */ - public T getMetadata(@NonNull Block block) throws ChunkBusyException { + public CompletableFuture getMetadata(@NonNull Block block) { // get chunk - Map metadata = getMetadataInChunk(block.getChunk()); - if (metadata == null) { - // no data for this chunk - return null; - } + return getMetadataInChunk(block.getChunk()).thenApply((metadata) -> { + if (metadata == null) { + // no data for this chunk + return null; + } - // get block metadata - return metadata.get(getBlockKeyInChunk(block)); + // get block metadata + return metadata.get(getBlockKeyInChunk(block)); + }); } /** * Set metadata of a block. * @param block The block. - * @param metadata Metadata to set to the block. - * @throws ChunkBusyException Thrown if the chunk is busy. + * @param data Metadata to set to the block. */ - public void setMetadata(@NonNull Block block, T metadata) throws ChunkBusyException { - if (metadata == null) { + public CompletableFuture setMetadata(@NonNull Block block, T data) { + if (data == null) { // clear metadata - removeMetadata(block); + return removeMetadata(block).thenApply((s) -> null); } else { // set metadata - modifyMetadataInChunk(block.getChunk()).put(getBlockKeyInChunk(block), metadata); + return getMetadataInChunk(block.getChunk()).thenApply((d) -> { + // make sure theres a map to put data in + if (d == null) { + d = new HashMap<>(); + } + d.put(getBlockKeyInChunk(block), data); + + // set chunk as dirty + LoadedChunkData loadedChunkData = loadedChunks.get(block.getChunk()); + loadedChunkData.setDirty(true); + + // update the data + metadata.put(block.getChunk(), d); + + return null; + }); } } /** * Removes metadata for a block. * @param block The block. - * @throws ChunkBusyException Thrown if the chunk is busy. * @return The removed metadata value. Null if no value was stored. */ - public T removeMetadata(@NonNull Block block) throws ChunkBusyException { - // cache chunk + public CompletableFuture removeMetadata(@NonNull Block block) { Chunk chunk = block.getChunk(); + return getMetadataInChunk(chunk).thenApply((metadata) -> { + // no metadata in chunk + if (metadata == null) { + return null; + } - // check if there are durabilities in the chunk - if (!hasMetadataForChunk(chunk)) { - return null; - } - - // get chunk - Map metadata = modifyMetadataInChunk(chunk); - - // remove from map - T value = metadata.remove(getBlockKeyInChunk(block)); + // remove metadata value from map + T value = metadata.remove(getBlockKeyInChunk(block)); - // check if last value - if (metadata.size() < 1) { - // remove chunk from storage - removeMetadataForChunk(chunk); - } + // if this was the last one left remove metadata entry for this chunk + if (metadata.size() == 0) { + removeMetadataForChunk(chunk); + } - return value; + return value; + }); } /** * Checks whether there are metadata stored for a given chunk. * @param chunk The chunk to check. * @return Whether there are metadata stored for the given chunk. - * @throws ChunkBusyException Thrown if the chunk is busy. */ - public boolean hasMetadataForChunk(@NonNull Chunk chunk) throws ChunkBusyException { - ensureChunkReady(chunk); - return metadata.containsKey(chunk); + public CompletableFuture hasMetadataForChunk(@NonNull Chunk chunk) { + return loadChunk(chunk).thenApply((s) -> metadata.containsKey(chunk)); } /** * Removes all metadata stored for a given chunk. * @param chunk The chunk to remove metadata from. - * @throws ChunkBusyException Thrown if the chunk is busy. */ - public void removeMetadataForChunk(@NonNull Chunk chunk) throws ChunkBusyException { - ensureChunkReady(chunk); - metadata.remove(chunk); - LoadedChunkData loadedChunkData = loadedChunks.get(chunk); - loadedChunkData.setDirty(true); + public CompletableFuture> removeMetadataForChunk(@NonNull Chunk chunk) { + return loadChunk(chunk).thenRun(() -> { + // set chunk as dirty + LoadedChunkData loadedChunkData = loadedChunks.get(chunk); + loadedChunkData.setDirty(true); + }).thenApply((s) -> metadata.remove(chunk)); } /** - * Gets metadata of blocks in a chunk to be modified. - * Sets the chunk as dirty. + * Gets metadata of blocks in a chunk. * @param chunk The chunk in which the metadata are. * @return Map of metadata. - * @throws ChunkBusyException Thrown if the chunk is busy. */ - public Map modifyMetadataInChunk(@NonNull Chunk chunk) throws ChunkBusyException { - ensureChunkReady(chunk); - Map data = metadata.computeIfAbsent(chunk, k -> new HashMap<>()); - LoadedChunkData loadedChunkData = loadedChunks.get(chunk); - loadedChunkData.setDirty(true); - return data; + public CompletableFuture> getMetadataInChunk(@NonNull Chunk chunk) { + return loadChunk(chunk).thenApply((s) -> metadata.get(chunk)); } + /** - * Gets metadata of blocks in a chunk. - * @param chunk The chunk in which the metadata are. - * @return Map of metadata. - * @throws ChunkBusyException Thrown if the chunk is busy. + * Sets all the data in a given chunk to the specified data. + * @param chunk The chunk for which to set metadata. + * @param data The metadata map. */ - public Map getMetadataInChunk(@NonNull Chunk chunk) throws ChunkBusyException { - ensureChunkReady(chunk); - return metadata.get(chunk); + public CompletableFuture setMetadataInChunk(@NonNull Chunk chunk, Map data) { + return loadChunk(chunk).thenRun(() -> { + // set chunk as dirt + LoadedChunkData loadedChunkData = loadedChunks.get(chunk); + loadedChunkData.setDirty(true); + + // update the data + if (data == null || data.size() == 0) { + metadata.remove(chunk); + } else { + metadata.put(chunk, data); + } + }); } /** @@ -358,7 +365,7 @@ private CompletableFuture>> readRegionData(Path regio * @return The number of bytes that were written to disk. */ private CompletableFuture bufferRegionData( - @NonNull Path regionFile, @NonNull Map> data) { + @NonNull Path regionFile, Map> data) { RegionTask regionTask = busyRegions.get(regionFile); if (regionTask != null) { regionTask.setBuffer(data); @@ -376,7 +383,7 @@ private CompletableFuture bufferRegionData( * @return The number of bytes that were written to disk. */ private CompletableFuture writeRegionData( - @NonNull Path regionFile, @NonNull Map> data) { + @NonNull Path regionFile, Map> data) { // remove old file to overwrite return CompletableFuture.supplyAsync(() -> { try { @@ -385,6 +392,9 @@ private CompletableFuture writeRegionData( return false; } }).thenApply((s) -> { + // remove empty region files + if (data == null) return null; + // serialize to yaml try { return mapper.writeValueAsString(data); @@ -401,8 +411,7 @@ private CompletableFuture writeRegionData( * Persists metadata of specified chunks on disk. * @param chunks Chunks to persist metadata for. */ - public CompletableFuture persistChunks(Chunk... chunks) - throws ChunkNotLoadedException { + public CompletableFuture persistChunks(Chunk... chunks) { CompletableFuture[] tasks = new CompletableFuture[chunks.length]; for (int i = 0; i < chunks.length; i++) { tasks[i] = persistChunk(chunks[i]); @@ -413,10 +422,8 @@ public CompletableFuture persistChunks(Chunk... chunks) /** * Persists chunk metadata on disk and unloads the metadata from memory. * @param chunk The chunk to persist. - * @throws ChunkNotLoadedException Thrown if the chunk isn't loaded. */ - public CompletableFuture persistChunk(@NonNull Chunk chunk) - throws ChunkNotLoadedException { + public CompletableFuture persistChunk(@NonNull Chunk chunk) { // check if chunk dirty if (!isChunkDirty(chunk)) { // not dirty, nothing to save to disk @@ -488,8 +495,7 @@ private CompletableFuture persistChunkAsync(@NonNull Chunk chunk) { * Loads chunk metadata for each specified chunk. * @param chunks Chunks to load metadata for. */ - public CompletableFuture loadChunks(Chunk... chunks) - throws ChunkAlreadyLoadedException { + public CompletableFuture loadChunks(Chunk... chunks) { CompletableFuture[] tasks = new CompletableFuture[chunks.length]; for (int i = 0; i < chunks.length; i++) { tasks[i] = loadChunk(chunks[i]); @@ -501,10 +507,10 @@ public CompletableFuture loadChunks(Chunk... chunks) * Loads chunk metadata into memory. * @param chunk The chunk. */ - public CompletableFuture loadChunk(@NonNull Chunk chunk) throws ChunkAlreadyLoadedException { + public CompletableFuture loadChunk(@NonNull Chunk chunk) { // check if chunk loaded if (isChunkLoaded(chunk)) { - throw new ChunkAlreadyLoadedException(); + return CompletableFuture.completedFuture(null); } // check if chunk is already loading @@ -550,31 +556,6 @@ private CompletableFuture loadChunkAsync(@NonNull Chunk chunk) { }); } - /** - * Ensures that a chunk is ready to be interacted with. - * Loads chunk if not loaded. - * @param chunk The chunk. - * @throws ChunkBusyException Thrown if the chunk is busy. - */ - public void ensureChunkReady(@NonNull Chunk chunk) throws ChunkBusyException { - // ensure chunk is loaded - if (!isChunkLoaded(chunk)) { - // load chunk first - try { - loadChunk(chunk).get(); - if (!chunk.isLoaded()) { - chunk.load(); - } - } catch (InterruptedException | ExecutionException | ChunkAlreadyLoadedException ex) { - // should not happen - ex.printStackTrace(); - } - } else if (isChunkBusy(chunk)) { - // ensure chunk is not busy - throw new ChunkBusyException(); - } - } - /** * Checks whether the specified chunk is busy. * A chunk is busy if it's being saved. @@ -610,10 +591,10 @@ public boolean isChunkLoaded(Chunk chunk) { * @param chunk The chunk. * @return Whether the chunk is dirty. */ - public boolean isChunkDirty(Chunk chunk) throws ChunkNotLoadedException { + public boolean isChunkDirty(Chunk chunk) { LoadedChunkData loadedChunkData = loadedChunks.get(chunk); if (loadedChunkData == null) { - throw new ChunkNotLoadedException(); + return false; } return loadedChunkData.isDirty(); } diff --git a/src/main/java/me/matoosh/blockmetadata/event/BlockDestroyHandler.java b/src/main/java/me/matoosh/blockmetadata/event/BlockDestroyHandler.java index e9bcdc3..cc01e79 100644 --- a/src/main/java/me/matoosh/blockmetadata/event/BlockDestroyHandler.java +++ b/src/main/java/me/matoosh/blockmetadata/event/BlockDestroyHandler.java @@ -2,7 +2,6 @@ import lombok.RequiredArgsConstructor; import me.matoosh.blockmetadata.BlockMetadataStorage; -import me.matoosh.blockmetadata.exception.ChunkBusyException; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -22,7 +21,7 @@ public class BlockDestroyHandler implements Listener { private final BlockMetadataStorage storage; @EventHandler(priority = EventPriority.LOW) - public void onBlockDestroy(BlockBreakEvent event) throws ChunkBusyException { + public void onBlockDestroy(BlockBreakEvent event) { if (event.isCancelled()) { return; } @@ -30,7 +29,7 @@ public void onBlockDestroy(BlockBreakEvent event) throws ChunkBusyException { } @EventHandler(priority = EventPriority.LOW) - public void onEntityChangeBlock(EntityChangeBlockEvent event) throws ChunkBusyException { + public void onEntityChangeBlock(EntityChangeBlockEvent event) { if (event.isCancelled()) { return; } @@ -38,7 +37,7 @@ public void onEntityChangeBlock(EntityChangeBlockEvent event) throws ChunkBusyEx } @EventHandler(priority = EventPriority.LOW) - public void onBlockBurn(BlockBurnEvent event) throws ChunkBusyException { + public void onBlockBurn(BlockBurnEvent event) { if (event.isCancelled()) { return; } @@ -46,7 +45,7 @@ public void onBlockBurn(BlockBurnEvent event) throws ChunkBusyException { } @EventHandler(priority = EventPriority.LOW) - public void onBlockFade(BlockFadeEvent event) throws ChunkBusyException { + public void onBlockFade(BlockFadeEvent event) { if (event.isCancelled()) { return; } diff --git a/src/main/java/me/matoosh/blockmetadata/event/BlockMoveHandler.java b/src/main/java/me/matoosh/blockmetadata/event/BlockMoveHandler.java index 1a8e3f6..b8cb33b 100644 --- a/src/main/java/me/matoosh/blockmetadata/event/BlockMoveHandler.java +++ b/src/main/java/me/matoosh/blockmetadata/event/BlockMoveHandler.java @@ -2,7 +2,6 @@ import lombok.RequiredArgsConstructor; import me.matoosh.blockmetadata.BlockMetadataStorage; -import me.matoosh.blockmetadata.exception.ChunkBusyException; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.event.EventHandler; @@ -15,6 +14,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutionException; /** * Handles preserving block metadata when moving blocks with a piston. @@ -26,7 +26,7 @@ public class BlockMoveHandler implements Listener { private final BlockMetadataStorage storage; @EventHandler(priority = EventPriority.LOW) - public void onBlockPistonExtend(BlockPistonExtendEvent event) throws ChunkBusyException { + public void onBlockPistonExtend(BlockPistonExtendEvent event) throws ExecutionException, InterruptedException { if (event.isCancelled()) { return; } @@ -34,7 +34,7 @@ public void onBlockPistonExtend(BlockPistonExtendEvent event) throws ChunkBusyEx } @EventHandler(priority = EventPriority.LOW) - public void onBlockPistonRetract(BlockPistonRetractEvent event) throws ChunkBusyException { + public void onBlockPistonRetract(BlockPistonRetractEvent event) throws ExecutionException, InterruptedException { if (event.isCancelled()) { return; } @@ -46,14 +46,14 @@ public void onBlockPistonRetract(BlockPistonRetractEvent event) throws ChunkBusy * Preserves blocks' metadata. * @param blocks The blocks that were moved. * @param direction The direction in which the blocks were moved. - * @throws ChunkBusyException thrown if the chunk is busy. */ - private void onBlocksMoveByPiston(List blocks, BlockFace direction) throws ChunkBusyException { + private void onBlocksMoveByPiston(List blocks, BlockFace direction) + throws ExecutionException, InterruptedException { // cache origin block metadata Map cachedMetadata = new HashMap<>(); for (Block origin : blocks) { // remove block metadata - T metadata = storage.removeMetadata(origin); + T metadata = storage.removeMetadata(origin).get(); // skip if no metadata stored if (metadata == null) { diff --git a/src/main/java/me/matoosh/blockmetadata/event/ChunkLoadHandler.java b/src/main/java/me/matoosh/blockmetadata/event/ChunkLoadHandler.java index 4e1bf1d..7560175 100644 --- a/src/main/java/me/matoosh/blockmetadata/event/ChunkLoadHandler.java +++ b/src/main/java/me/matoosh/blockmetadata/event/ChunkLoadHandler.java @@ -2,11 +2,8 @@ import lombok.RequiredArgsConstructor; import me.matoosh.blockmetadata.BlockMetadataStorage; -import me.matoosh.blockmetadata.exception.ChunkAlreadyLoadedException; -import me.matoosh.blockmetadata.exception.ChunkNotLoadedException; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkUnloadEvent; import java.io.Serializable; @@ -20,19 +17,8 @@ public class ChunkLoadHandler implements Listener { private final BlockMetadataStorage storage; - @EventHandler - public void onChunkLoad(ChunkLoadEvent event) { - try { - storage.loadChunk(event.getChunk()); - } catch (ChunkAlreadyLoadedException ignored) { - } - } - @EventHandler public void onChunkUnload(ChunkUnloadEvent event) { - try { - storage.persistChunk(event.getChunk()); - } catch (ChunkNotLoadedException ignored) { - } + storage.persistChunk(event.getChunk()); } } diff --git a/src/main/java/me/matoosh/blockmetadata/event/PluginDisableHandler.java b/src/main/java/me/matoosh/blockmetadata/event/PluginDisableHandler.java index 0b09b42..7425a3e 100644 --- a/src/main/java/me/matoosh/blockmetadata/event/PluginDisableHandler.java +++ b/src/main/java/me/matoosh/blockmetadata/event/PluginDisableHandler.java @@ -3,7 +3,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import me.matoosh.blockmetadata.BlockMetadataStorage; -import me.matoosh.blockmetadata.exception.ChunkNotLoadedException; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; @@ -56,10 +55,7 @@ public void onServerStop(PluginDisableEvent event) private void saveMetadataInWorld(World world) { log.info("Saving metadata in world " + world.getName()); for (Chunk c : world.getLoadedChunks()) { - try { - storage.persistChunk(c); - } catch (ChunkNotLoadedException ignored) { - } + storage.persistChunk(c); } } } diff --git a/src/main/java/me/matoosh/blockmetadata/exception/ChunkAlreadyLoadedException.java b/src/main/java/me/matoosh/blockmetadata/exception/ChunkAlreadyLoadedException.java deleted file mode 100644 index 2a6ea2f..0000000 --- a/src/main/java/me/matoosh/blockmetadata/exception/ChunkAlreadyLoadedException.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.matoosh.blockmetadata.exception; - -/** - * Indicates the the specified chunk has already been loaded. - */ -public class ChunkAlreadyLoadedException extends Exception { -} diff --git a/src/main/java/me/matoosh/blockmetadata/exception/ChunkBusyException.java b/src/main/java/me/matoosh/blockmetadata/exception/ChunkBusyException.java deleted file mode 100644 index e13dfd1..0000000 --- a/src/main/java/me/matoosh/blockmetadata/exception/ChunkBusyException.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.matoosh.blockmetadata.exception; - -/** - * Indicates that the requested chunk is currently loading/saving. - */ -public class ChunkBusyException extends Exception { -} diff --git a/src/main/java/me/matoosh/blockmetadata/exception/ChunkNotLoadedException.java b/src/main/java/me/matoosh/blockmetadata/exception/ChunkNotLoadedException.java deleted file mode 100644 index 6c42331..0000000 --- a/src/main/java/me/matoosh/blockmetadata/exception/ChunkNotLoadedException.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.matoosh.blockmetadata.exception; - -/** - * Indicates that the chunk is not loaded. - */ -public class ChunkNotLoadedException extends Exception { -} diff --git a/src/test/java/me/matoosh/blockmetadata/BlockIntegerMetadataStorageTest.java b/src/test/java/me/matoosh/blockmetadata/BlockIntegerMetadataStorageTest.java index d972e99..d3365a8 100644 --- a/src/test/java/me/matoosh/blockmetadata/BlockIntegerMetadataStorageTest.java +++ b/src/test/java/me/matoosh/blockmetadata/BlockIntegerMetadataStorageTest.java @@ -10,7 +10,7 @@ public class BlockIntegerMetadataStorageTest extends BlockMetadataStorageTest { protected abstract T createMetadata(); @BeforeEach - void setUp() throws ExecutionException, InterruptedException, - ChunkAlreadyLoadedException, IOException { + void setUp() throws ExecutionException, InterruptedException, IOException { ServerMock server = MockBukkit.mock(); MockPlugin mockPlugin = MockBukkit.createMockPlugin(); world = server.addSimpleWorld("test-world"); @@ -56,140 +52,126 @@ void tearDown() { } @Test - void getMetadataNull() throws ChunkBusyException { + void getMetadataNull() throws ExecutionException, InterruptedException { T metadata = blockMetadataStorage.getMetadata( - sampleChunk.getBlock(0, 0, 0)); + sampleChunk.getBlock(0, 0, 0)).get(); assertNull(metadata); } @Test - void setGetMetadata() throws ChunkBusyException { + void setGetMetadata() throws ExecutionException, InterruptedException { // set metadata on a block T metadata = createMetadata(); - blockMetadataStorage.setMetadata(sampleBlock, metadata); + blockMetadataStorage.setMetadata(sampleBlock, metadata).get(); // retrieve the metadata - T metadataRetrieved = blockMetadataStorage.getMetadata(sampleBlock); + T metadataRetrieved = blockMetadataStorage.getMetadata(sampleBlock).get(); // ensure that the metadata was retrieved correctly assertEquals(metadata, metadataRetrieved); } @Test - void ensureChunkReadyAutoloadChunk() throws ChunkNotLoadedException, ExecutionException, InterruptedException, ChunkBusyException { + void ensureChunkReadyAutoloadChunk() throws ExecutionException, InterruptedException { // unload the sample chunk blockMetadataStorage.persistChunk(sampleChunk).get(); // ensure chunk is not loaded assertFalse(blockMetadataStorage.isChunkLoaded(sampleChunk)); - // ensure chunk ready - blockMetadataStorage.ensureChunkReady(sampleChunk); + // load the sample chunk + blockMetadataStorage.loadChunk(sampleChunk).get(); // ensure chunk is loaded now assertTrue(blockMetadataStorage.isChunkLoaded(sampleChunk)); } @Test - void ensureChunkReadyChunkBusy() { - // ensure chunk is not loaded - assertTrue(blockMetadataStorage.isChunkLoaded(sampleChunk)); - - // ensure chunk ready - assertDoesNotThrow(() -> blockMetadataStorage.ensureChunkReady(sampleChunk)); - } - - @Test - void removeMetadata() throws ChunkBusyException { + void removeMetadata() throws ExecutionException, InterruptedException { // set metadata on a block T metadata = createMetadata(); - blockMetadataStorage.setMetadata(sampleBlock, metadata); + blockMetadataStorage.setMetadata(sampleBlock, metadata).get(); // remove metadata from block - blockMetadataStorage.removeMetadata(sampleBlock); + blockMetadataStorage.removeMetadata(sampleBlock).get(); // retrieve the metadata - T metadataRetrieved = blockMetadataStorage.getMetadata(sampleBlock); + T metadataRetrieved = blockMetadataStorage.getMetadata(sampleBlock).get(); // ensure the retrieved metadata is null assertNull(metadataRetrieved); } @Test - void hasMetadataForChunk() throws ChunkBusyException { + void hasMetadataForChunk() throws ExecutionException, InterruptedException { // initially there should be no metadata - assertFalse(blockMetadataStorage.hasMetadataForChunk(sampleChunk)); + assertFalse(blockMetadataStorage.hasMetadataForChunk(sampleChunk).get()); // set some metadata T metadata = createMetadata(); - blockMetadataStorage.setMetadata(sampleBlock, metadata); + blockMetadataStorage.setMetadata(sampleBlock, metadata).get(); // there should now be metadata in chunk - assertTrue(blockMetadataStorage.hasMetadataForChunk(sampleChunk)); + assertTrue(blockMetadataStorage.hasMetadataForChunk(sampleChunk).get()); // remove metadata from the block blockMetadataStorage.removeMetadata(sampleBlock); - assertFalse(blockMetadataStorage.hasMetadataForChunk(sampleChunk)); + assertFalse(blockMetadataStorage.hasMetadataForChunk(sampleChunk).get()); } @Test - void removeMetadataForChunk() throws ChunkBusyException { + void removeMetadataForChunk() throws ExecutionException, InterruptedException { // initially there should be no metadata - assertFalse(blockMetadataStorage.hasMetadataForChunk(sampleChunk)); + assertFalse(blockMetadataStorage.hasMetadataForChunk(sampleChunk).get()); // set some metadata T metadata = createMetadata(); - blockMetadataStorage.setMetadata(sampleBlock, metadata); + blockMetadataStorage.setMetadata(sampleBlock, metadata).get(); // there should now be metadata in chunk - assertTrue(blockMetadataStorage.hasMetadataForChunk(sampleChunk)); + assertTrue(blockMetadataStorage.hasMetadataForChunk(sampleChunk).get()); // remove metadata from the block - blockMetadataStorage.removeMetadataForChunk(sampleChunk); - assertFalse(blockMetadataStorage.hasMetadataForChunk(sampleChunk)); + blockMetadataStorage.removeMetadataForChunk(sampleChunk).get(); + assertFalse(blockMetadataStorage.hasMetadataForChunk(sampleChunk).get()); } @Test - void modifyMetadataInChunk() throws ChunkNotLoadedException, ChunkBusyException { - // get metadata - assertEquals(0, blockMetadataStorage.modifyMetadataInChunk(sampleChunk).size()); + void setMetadataSetsChunkDirty() throws ExecutionException, InterruptedException { + // set metadata on block + T metadata = createMetadata(); + blockMetadataStorage.setMetadata(sampleBlock, metadata).get(); // ensure the chunk is dirty now assertTrue(blockMetadataStorage.isChunkDirty(sampleChunk)); - // set metadata on block - T metadata = createMetadata(); - blockMetadataStorage.setMetadata(sampleBlock, metadata); - // get metadata - Map retrievedMetadata = blockMetadataStorage.modifyMetadataInChunk(sampleChunk); + Map retrievedMetadata = blockMetadataStorage.getMetadataInChunk(sampleChunk).get(); + // make sure only 1 block is set with metadata assertEquals(1, retrievedMetadata.size()); // ensure the block we set metadata for is in the map assertTrue(retrievedMetadata.containsKey(BlockMetadataStorage .getBlockKeyInChunk(sampleBlock))); - // ensure the chunk is dirty now - assertTrue(blockMetadataStorage.isChunkDirty(sampleChunk)); // remove metadata from block - blockMetadataStorage.removeMetadata(sampleBlock); - // make sure there are no blocks with metadata - assertEquals(0, blockMetadataStorage.modifyMetadataInChunk(sampleChunk).size()); + blockMetadataStorage.removeMetadata(sampleBlock).get(); + // ensure the chunk is dirty now assertTrue(blockMetadataStorage.isChunkDirty(sampleChunk)); } @Test - void getMetadataInChunk() throws ChunkBusyException { + void noMetadataRemovesChunkMap() throws ExecutionException, InterruptedException { // get metadata - assertNull(blockMetadataStorage.getMetadataInChunk(sampleChunk)); + assertNull(blockMetadataStorage.getMetadataInChunk(sampleChunk).get()); // set metadata on block T metadata = createMetadata(); - blockMetadataStorage.setMetadata(sampleBlock, metadata); + blockMetadataStorage.setMetadata(sampleBlock, metadata).get(); // get metadata - Map retrievedMetadata = blockMetadataStorage.getMetadataInChunk(sampleChunk); + Map retrievedMetadata = blockMetadataStorage.getMetadataInChunk(sampleChunk).get(); // make sure only 1 block is set with metadata assertEquals(1, retrievedMetadata.size()); // ensure the block we set metadata for is in the map @@ -197,22 +179,20 @@ void getMetadataInChunk() throws ChunkBusyException { .getBlockKeyInChunk(sampleBlock))); // remove metadata from block - blockMetadataStorage.removeMetadata(sampleBlock); - // get metadata - retrievedMetadata = blockMetadataStorage.getMetadataInChunk(sampleChunk); + blockMetadataStorage.removeMetadata(sampleBlock).get(); + // make sure there are no blocks with metadata - assertNull(retrievedMetadata); + assertNull(blockMetadataStorage.getMetadataInChunk(sampleChunk).get()); } @Test - void persistChunk() throws ChunkNotLoadedException, ChunkBusyException, - ExecutionException, InterruptedException, ChunkAlreadyLoadedException { + void persistChunk() throws ExecutionException, InterruptedException { // ensure sample chunk is loaded assertTrue(blockMetadataStorage.isChunkLoaded(sampleChunk)); // set metadata on chunk T metadata = createMetadata(); - blockMetadataStorage.setMetadata(sampleBlock, metadata); + blockMetadataStorage.setMetadata(sampleBlock, metadata).get(); // save chunk blockMetadataStorage.persistChunk(sampleChunk).get(); @@ -230,13 +210,12 @@ void persistChunk() throws ChunkNotLoadedException, ChunkBusyException, assertTrue(blockMetadataStorage.isChunkLoaded(sampleChunk)); // check if metadata is available - T metadataRetrieved = blockMetadataStorage.getMetadata(sampleBlock); + T metadataRetrieved = blockMetadataStorage.getMetadata(sampleBlock).get(); assertEquals(metadata, metadataRetrieved); } @Test - void loadChunk() throws ChunkAlreadyLoadedException, ExecutionException, - InterruptedException, ChunkNotLoadedException { + void loadChunk() throws ExecutionException, InterruptedException { // get chunk Chunk toLoad = world.getChunkAt(1, 1); @@ -257,8 +236,7 @@ void loadChunk() throws ChunkAlreadyLoadedException, ExecutionException, } @Test - void isChunkBusy() throws ChunkNotLoadedException, ExecutionException, - InterruptedException, ChunkAlreadyLoadedException { + void isChunkBusy() throws ExecutionException, InterruptedException { // normally shouldn't be busy assertFalse(blockMetadataStorage.isChunkBusy(sampleChunk)); diff --git a/src/test/java/me/matoosh/blockmetadata/event/BlockDestroyHandlerTest.java b/src/test/java/me/matoosh/blockmetadata/event/BlockDestroyHandlerTest.java index 427adf5..a2588d0 100644 --- a/src/test/java/me/matoosh/blockmetadata/event/BlockDestroyHandlerTest.java +++ b/src/test/java/me/matoosh/blockmetadata/event/BlockDestroyHandlerTest.java @@ -5,7 +5,6 @@ import be.seeseemelk.mockbukkit.WorldMock; import be.seeseemelk.mockbukkit.entity.PlayerMock; import me.matoosh.blockmetadata.BlockMetadataStorage; -import me.matoosh.blockmetadata.exception.ChunkBusyException; import org.bukkit.block.Block; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockBurnEvent; @@ -49,7 +48,7 @@ void tearDown() { } @Test - void onBlockDestroy() throws ChunkBusyException { + void onBlockDestroy() { PlayerMock player = server.addPlayer(); blockDestroyHandler.onBlockDestroy( new BlockBreakEvent(sampleBlock, player)); @@ -58,7 +57,7 @@ void onBlockDestroy() throws ChunkBusyException { } @Test - void onBlockBurn() throws ChunkBusyException { + void onBlockBurn() { blockDestroyHandler.onBlockBurn( new BlockBurnEvent(sampleBlock, null)); verify(blockMetadataStorage, times(1)) @@ -66,7 +65,7 @@ void onBlockBurn() throws ChunkBusyException { } @Test - void onBlockFade() throws ChunkBusyException { + void onBlockFade() { blockDestroyHandler.onBlockFade( new BlockFadeEvent(sampleBlock, sampleBlock.getState())); verify(blockMetadataStorage, times(1)) @@ -74,7 +73,7 @@ void onBlockFade() throws ChunkBusyException { } @Test - void onEntityChangeBlock() throws ChunkBusyException { + void onEntityChangeBlock() { blockDestroyHandler.onEntityChangeBlock( new EntityChangeBlockEvent(null, sampleBlock, sampleBlock.getBlockData())); verify(blockMetadataStorage, times(1)) diff --git a/src/test/java/me/matoosh/blockmetadata/event/BlockMoveHandlerTest.java b/src/test/java/me/matoosh/blockmetadata/event/BlockMoveHandlerTest.java index dc52641..db0dda3 100644 --- a/src/test/java/me/matoosh/blockmetadata/event/BlockMoveHandlerTest.java +++ b/src/test/java/me/matoosh/blockmetadata/event/BlockMoveHandlerTest.java @@ -4,7 +4,6 @@ import be.seeseemelk.mockbukkit.ServerMock; import be.seeseemelk.mockbukkit.WorldMock; import me.matoosh.blockmetadata.BlockMetadataStorage; -import me.matoosh.blockmetadata.exception.ChunkBusyException; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.event.block.BlockPistonExtendEvent; @@ -21,6 +20,8 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.stream.Stream; import static org.mockito.ArgumentMatchers.any; @@ -59,11 +60,11 @@ void tearDown() { @ParameterizedTest @MethodSource("directionGenerator") - void extendSingleBlock(BlockFace direction) throws ChunkBusyException { + void extendSingleBlock(BlockFace direction) throws ExecutionException, InterruptedException { // mock origin Block origin = pistonBlock.getRelative(direction); when(blockMetadataStorage.removeMetadata(origin)) - .thenReturn(createSampleMetadata()); + .thenReturn(CompletableFuture.completedFuture(createSampleMetadata())); // mock destination Block destination = origin.getRelative(direction); @@ -81,11 +82,11 @@ void extendSingleBlock(BlockFace direction) throws ChunkBusyException { @ParameterizedTest @MethodSource("directionGenerator") - void extendSingleBlockNoMetadata(BlockFace direction) throws ChunkBusyException { + void extendSingleBlockNoMetadata(BlockFace direction) throws ExecutionException, InterruptedException { // mock origin Block origin = pistonBlock.getRelative(direction); when(blockMetadataStorage.removeMetadata(origin)) - .thenReturn(null); + .thenReturn(CompletableFuture.completedFuture(null)); // fire the piston extend event List blocks = new ArrayList<>(); @@ -99,11 +100,11 @@ void extendSingleBlockNoMetadata(BlockFace direction) throws ChunkBusyException @ParameterizedTest @MethodSource("directionGenerator") - void retractSingleBlock(BlockFace direction) throws ChunkBusyException { + void retractSingleBlock(BlockFace direction) throws ExecutionException, InterruptedException { // mock origin Block origin = pistonBlock.getRelative(direction); when(blockMetadataStorage.removeMetadata(origin)) - .thenReturn(createSampleMetadata()); + .thenReturn(CompletableFuture.completedFuture(createSampleMetadata())); // mock destination Block destination = origin.getRelative(direction); @@ -121,11 +122,11 @@ void retractSingleBlock(BlockFace direction) throws ChunkBusyException { @ParameterizedTest @MethodSource("directionGenerator") - void retractSingleBlockNoMetadata(BlockFace direction) throws ChunkBusyException { + void retractSingleBlockNoMetadata(BlockFace direction) throws ExecutionException, InterruptedException { // mock origin Block origin = pistonBlock.getRelative(direction); when(blockMetadataStorage.removeMetadata(origin)) - .thenReturn(null); + .thenReturn(CompletableFuture.completedFuture(null)); // fire the piston extend event List blocks = new ArrayList<>(); diff --git a/src/test/java/me/matoosh/blockmetadata/event/ChunkLoadHandlerTest.java b/src/test/java/me/matoosh/blockmetadata/event/ChunkLoadHandlerTest.java index b88dfb1..7279e81 100644 --- a/src/test/java/me/matoosh/blockmetadata/event/ChunkLoadHandlerTest.java +++ b/src/test/java/me/matoosh/blockmetadata/event/ChunkLoadHandlerTest.java @@ -3,10 +3,7 @@ import be.seeseemelk.mockbukkit.ChunkMock; import be.seeseemelk.mockbukkit.WorldMock; import me.matoosh.blockmetadata.BlockMetadataStorage; -import me.matoosh.blockmetadata.exception.ChunkAlreadyLoadedException; -import me.matoosh.blockmetadata.exception.ChunkNotLoadedException; import org.bukkit.Material; -import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkUnloadEvent; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -16,7 +13,8 @@ import java.io.Serializable; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; @ExtendWith(MockitoExtension.class) abstract class ChunkLoadHandlerTest { @@ -34,17 +32,7 @@ abstract class ChunkLoadHandlerTest { * Verifies that a chunk load/unload causes metadata load/unload. */ @Test - void onChunkLoadUnload() throws ChunkAlreadyLoadedException, ChunkNotLoadedException { - // ensure chunk load wasnt called yet - verify(blockMetadataStorage, never()).loadChunk(sampleChunk); - - // trigger chunk load event - chunkLoadHandler.onChunkLoad(new ChunkLoadEvent(sampleChunk, false)); - - // assert that the chunk load caused metadata load - verify(blockMetadataStorage, times(1)) - .loadChunk(sampleChunk); - + void onChunkLoadUnload() { // trigger chunk unload event chunkLoadHandler.onChunkUnload(new ChunkUnloadEvent(sampleChunk, true));