From 27df88aaf31b5488f08ded9227155d0ba32a4f10 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 17 Jan 2021 08:41:50 -0800 Subject: [PATCH] Made greenhouse ecosystem checking async. https://github.com/BentoBoxWorld/Greenhouses/issues/68 --- .../greenhouses/greenhouse/BiomeRecipe.java | 26 +++++++++++--- .../managers/EcoSystemManager.java | 11 +++--- .../managers/GreenhouseManager.java | 34 ++++++++++--------- .../greenhouse/BiomeRecipeTest.java | 10 +++--- 4 files changed, 51 insertions(+), 30 deletions(-) diff --git a/src/main/java/world/bentobox/greenhouses/greenhouse/BiomeRecipe.java b/src/main/java/world/bentobox/greenhouses/greenhouse/BiomeRecipe.java index 42c3476..9baaa42 100644 --- a/src/main/java/world/bentobox/greenhouses/greenhouse/BiomeRecipe.java +++ b/src/main/java/world/bentobox/greenhouses/greenhouse/BiomeRecipe.java @@ -10,8 +10,10 @@ import java.util.Optional; import java.util.Random; import java.util.Set; import java.util.TreeMap; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Particle; @@ -36,6 +38,7 @@ import world.bentobox.bentobox.util.Util; import world.bentobox.greenhouses.Greenhouses; import world.bentobox.greenhouses.data.Greenhouse; import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult; +import world.bentobox.greenhouses.world.AsyncWorldCache; public class BiomeRecipe implements Comparable { private static final String CHANCE_FOR = "% chance for "; @@ -155,21 +158,34 @@ public class BiomeRecipe implements Comparable { startupLog(" " + blockMaterial + " x " + blockQty); } - // Check required blocks /** * Checks greenhouse meets recipe requirements. * @return GreenhouseResult - result */ - public Set checkRecipe(Greenhouse gh) { + public CompletableFuture> checkRecipe(Greenhouse gh) { + CompletableFuture> r = new CompletableFuture<>(); + Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> checkRecipeAsync(r, gh)); + return r; + + } + + /** + * Check greenhouse meets recipe requirements. Expected to be run async. + * @param r - future to complete when done + * @param gh - greenhouse + * @return set of results from the check + */ + private Set checkRecipeAsync(CompletableFuture> r, Greenhouse gh) { + AsyncWorldCache cache = new AsyncWorldCache(gh.getWorld()); Set result = new HashSet<>(); long area = gh.getArea(); Map blockCount = new EnumMap<>(Material.class); + // Look through the greenhouse and count what is in there for (int y = gh.getFloorHeight(); y< gh.getCeilingHeight();y++) { for (int x = (int) (gh.getBoundingBox().getMinX()+1); x < gh.getBoundingBox().getMaxX(); x++) { for (int z = (int) (gh.getBoundingBox().getMinZ()+1); z < gh.getBoundingBox().getMaxZ(); z++) { - Block b = gh.getWorld().getBlockAt(x, y, z); - Material t = b.getType(); + Material t = cache.getBlockType(x, y, z); if (!t.equals(Material.AIR)) { blockCount.putIfAbsent(t, 0); blockCount.merge(t, 1, Integer::sum); @@ -213,6 +229,8 @@ public class BiomeRecipe implements Comparable { result.add(GreenhouseResult.FAIL_INSUFFICIENT_BLOCKS); gh.setMissingBlocks(missingBlocks); } + // Return to main thread to complete + Bukkit.getScheduler().runTask(addon.getPlugin(), () -> r.complete(result)); return result; } diff --git a/src/main/java/world/bentobox/greenhouses/managers/EcoSystemManager.java b/src/main/java/world/bentobox/greenhouses/managers/EcoSystemManager.java index 569d8ef..0138a05 100644 --- a/src/main/java/world/bentobox/greenhouses/managers/EcoSystemManager.java +++ b/src/main/java/world/bentobox/greenhouses/managers/EcoSystemManager.java @@ -101,10 +101,13 @@ public class EcoSystemManager { //addon.log("Skipping verify for unloaded greenhouse at " + gh.getLocation()); return; } - if (!gh.getBiomeRecipe().checkRecipe(gh).isEmpty()) { - addon.log("Greenhouse failed verification at " + gh.getLocation()); - g.removeGreenhouse(gh); - } + gh.getBiomeRecipe().checkRecipe(gh).thenAccept(rs -> { + if (!rs.isEmpty()) { + addon.log("Greenhouse failed verification at " + gh.getLocation()); + g.removeGreenhouse(gh); + } + }); + } private void addMobs(Greenhouse gh) { diff --git a/src/main/java/world/bentobox/greenhouses/managers/GreenhouseManager.java b/src/main/java/world/bentobox/greenhouses/managers/GreenhouseManager.java index 984e191..87a673a 100644 --- a/src/main/java/world/bentobox/greenhouses/managers/GreenhouseManager.java +++ b/src/main/java/world/bentobox/greenhouses/managers/GreenhouseManager.java @@ -167,10 +167,9 @@ public class GreenhouseManager implements Listener { } // Check if the greenhouse meets the requested recipe if (greenhouseRecipe != null) { - checkRecipe(r, finder, greenhouseRecipe, resultSet); + checkRecipe(finder, greenhouseRecipe, resultSet).thenAccept(r::complete); return; } - // Try ordered recipes findRecipe(finder, resultSet); r.complete(new GhResult().setFinder(finder).setResults(resultSet)); @@ -184,6 +183,8 @@ public class GreenhouseManager implements Listener { * @param resultSet - result set from find */ private void findRecipe(GreenhouseFinder finder, Set resultSet) { + // TODO + /* resultSet.add(addon.getRecipes().getBiomeRecipes().stream().sorted() .filter(r -> r.checkRecipe(finder.getGh()).isEmpty()).findFirst() .map(r -> { @@ -192,7 +193,7 @@ public class GreenhouseManager implements Listener { activateGreenhouse(finder.getGh()); handler.saveObjectAsync(finder.getGh()); return map.addGreenhouse(finder.getGh()); - }).orElse(GreenhouseResult.FAIL_NO_RECIPE_FOUND)); + }).orElse(GreenhouseResult.FAIL_NO_RECIPE_FOUND));*/ } /** @@ -203,19 +204,20 @@ public class GreenhouseManager implements Listener { * @param resultSet - result set from finder * @return Greenhouse result */ - GhResult checkRecipe(CompletableFuture r, GreenhouseFinder finder, BiomeRecipe greenhouseRecipe, Set resultSet) { - resultSet = greenhouseRecipe.checkRecipe(finder.getGh()); - if (resultSet.isEmpty()) { - // Success - set recipe and add to map - finder.getGh().setBiomeRecipe(greenhouseRecipe); - resultSet.add(map.addGreenhouse(finder.getGh())); - activateGreenhouse(finder.getGh()); - handler.saveObjectAsync(finder.getGh()); - } - GhResult recipe = new GhResult().setFinder(finder).setResults(resultSet); - r.complete(recipe); - return recipe; - + CompletableFuture checkRecipe(GreenhouseFinder finder, BiomeRecipe greenhouseRecipe, Set resultSet) { + CompletableFuture r = new CompletableFuture<>(); + greenhouseRecipe.checkRecipe(finder.getGh()).thenAccept(rs -> { + if (rs.isEmpty()) { + // Success - set recipe and add to map + finder.getGh().setBiomeRecipe(greenhouseRecipe); + resultSet.add(map.addGreenhouse(finder.getGh())); + activateGreenhouse(finder.getGh()); + handler.saveObjectAsync(finder.getGh()); + } + GhResult recipe = new GhResult().setFinder(finder).setResults(rs); + r.complete(recipe); + }); + return r; } private void activateGreenhouse(Greenhouse gh) { diff --git a/src/test/java/world/bentobox/greenhouses/greenhouse/BiomeRecipeTest.java b/src/test/java/world/bentobox/greenhouses/greenhouse/BiomeRecipeTest.java index e5d9909..08c8282 100644 --- a/src/test/java/world/bentobox/greenhouses/greenhouse/BiomeRecipeTest.java +++ b/src/test/java/world/bentobox/greenhouses/greenhouse/BiomeRecipeTest.java @@ -13,7 +13,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.Optional; -import java.util.Set; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -48,7 +47,6 @@ import world.bentobox.greenhouses.Greenhouses; import world.bentobox.greenhouses.Settings; import world.bentobox.greenhouses.data.Greenhouse; import world.bentobox.greenhouses.managers.GreenhouseManager; -import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult; import world.bentobox.greenhouses.managers.GreenhouseMap; /** @@ -237,8 +235,8 @@ public class BiomeRecipeTest { */ @Test public void testCheckRecipe() { - Set result = br.checkRecipe(gh); - assertTrue(result.isEmpty()); + br.checkRecipe(gh).thenAccept(result -> + assertTrue(result.isEmpty())); } /** @@ -247,8 +245,8 @@ public class BiomeRecipeTest { @Test public void testCheckRecipeNotEnough() { br.addReqBlocks(Material.ACACIA_LEAVES, 3); - Set result = br.checkRecipe(gh); - assertFalse(result.isEmpty()); + br.checkRecipe(gh).thenAccept(result -> + assertFalse(result.isEmpty())); }