Made greenhouse ecosystem checking async.

https://github.com/BentoBoxWorld/Greenhouses/issues/68
This commit is contained in:
tastybento 2021-01-17 08:41:50 -08:00
parent cd5a0ce2a1
commit 27df88aaf3
4 changed files with 51 additions and 30 deletions

View File

@ -10,8 +10,10 @@ import java.util.Optional;
import java.util.Random; import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Particle; import org.bukkit.Particle;
@ -36,6 +38,7 @@ import world.bentobox.bentobox.util.Util;
import world.bentobox.greenhouses.Greenhouses; import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.data.Greenhouse; import world.bentobox.greenhouses.data.Greenhouse;
import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult; import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult;
import world.bentobox.greenhouses.world.AsyncWorldCache;
public class BiomeRecipe implements Comparable<BiomeRecipe> { public class BiomeRecipe implements Comparable<BiomeRecipe> {
private static final String CHANCE_FOR = "% chance for "; private static final String CHANCE_FOR = "% chance for ";
@ -155,21 +158,34 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
startupLog(" " + blockMaterial + " x " + blockQty); startupLog(" " + blockMaterial + " x " + blockQty);
} }
// Check required blocks
/** /**
* Checks greenhouse meets recipe requirements. * Checks greenhouse meets recipe requirements.
* @return GreenhouseResult - result * @return GreenhouseResult - result
*/ */
public Set<GreenhouseResult> checkRecipe(Greenhouse gh) { public CompletableFuture<Set<GreenhouseResult>> checkRecipe(Greenhouse gh) {
CompletableFuture<Set<GreenhouseResult>> 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<GreenhouseResult> checkRecipeAsync(CompletableFuture<Set<GreenhouseResult>> r, Greenhouse gh) {
AsyncWorldCache cache = new AsyncWorldCache(gh.getWorld());
Set<GreenhouseResult> result = new HashSet<>(); Set<GreenhouseResult> result = new HashSet<>();
long area = gh.getArea(); long area = gh.getArea();
Map<Material, Integer> blockCount = new EnumMap<>(Material.class); Map<Material, Integer> blockCount = new EnumMap<>(Material.class);
// Look through the greenhouse and count what is in there // Look through the greenhouse and count what is in there
for (int y = gh.getFloorHeight(); y< gh.getCeilingHeight();y++) { for (int y = gh.getFloorHeight(); y< gh.getCeilingHeight();y++) {
for (int x = (int) (gh.getBoundingBox().getMinX()+1); x < gh.getBoundingBox().getMaxX(); x++) { 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++) { for (int z = (int) (gh.getBoundingBox().getMinZ()+1); z < gh.getBoundingBox().getMaxZ(); z++) {
Block b = gh.getWorld().getBlockAt(x, y, z); Material t = cache.getBlockType(x, y, z);
Material t = b.getType();
if (!t.equals(Material.AIR)) { if (!t.equals(Material.AIR)) {
blockCount.putIfAbsent(t, 0); blockCount.putIfAbsent(t, 0);
blockCount.merge(t, 1, Integer::sum); blockCount.merge(t, 1, Integer::sum);
@ -213,6 +229,8 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
result.add(GreenhouseResult.FAIL_INSUFFICIENT_BLOCKS); result.add(GreenhouseResult.FAIL_INSUFFICIENT_BLOCKS);
gh.setMissingBlocks(missingBlocks); gh.setMissingBlocks(missingBlocks);
} }
// Return to main thread to complete
Bukkit.getScheduler().runTask(addon.getPlugin(), () -> r.complete(result));
return result; return result;
} }

View File

@ -101,10 +101,13 @@ public class EcoSystemManager {
//addon.log("Skipping verify for unloaded greenhouse at " + gh.getLocation()); //addon.log("Skipping verify for unloaded greenhouse at " + gh.getLocation());
return; return;
} }
if (!gh.getBiomeRecipe().checkRecipe(gh).isEmpty()) { gh.getBiomeRecipe().checkRecipe(gh).thenAccept(rs -> {
addon.log("Greenhouse failed verification at " + gh.getLocation()); if (!rs.isEmpty()) {
g.removeGreenhouse(gh); addon.log("Greenhouse failed verification at " + gh.getLocation());
} g.removeGreenhouse(gh);
}
});
} }
private void addMobs(Greenhouse gh) { private void addMobs(Greenhouse gh) {

View File

@ -167,10 +167,9 @@ public class GreenhouseManager implements Listener {
} }
// Check if the greenhouse meets the requested recipe // Check if the greenhouse meets the requested recipe
if (greenhouseRecipe != null) { if (greenhouseRecipe != null) {
checkRecipe(r, finder, greenhouseRecipe, resultSet); checkRecipe(finder, greenhouseRecipe, resultSet).thenAccept(r::complete);
return; return;
} }
// Try ordered recipes // Try ordered recipes
findRecipe(finder, resultSet); findRecipe(finder, resultSet);
r.complete(new GhResult().setFinder(finder).setResults(resultSet)); r.complete(new GhResult().setFinder(finder).setResults(resultSet));
@ -184,6 +183,8 @@ public class GreenhouseManager implements Listener {
* @param resultSet - result set from find * @param resultSet - result set from find
*/ */
private void findRecipe(GreenhouseFinder finder, Set<GreenhouseResult> resultSet) { private void findRecipe(GreenhouseFinder finder, Set<GreenhouseResult> resultSet) {
// TODO
/*
resultSet.add(addon.getRecipes().getBiomeRecipes().stream().sorted() resultSet.add(addon.getRecipes().getBiomeRecipes().stream().sorted()
.filter(r -> r.checkRecipe(finder.getGh()).isEmpty()).findFirst() .filter(r -> r.checkRecipe(finder.getGh()).isEmpty()).findFirst()
.map(r -> { .map(r -> {
@ -192,7 +193,7 @@ public class GreenhouseManager implements Listener {
activateGreenhouse(finder.getGh()); activateGreenhouse(finder.getGh());
handler.saveObjectAsync(finder.getGh()); handler.saveObjectAsync(finder.getGh());
return map.addGreenhouse(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 * @param resultSet - result set from finder
* @return Greenhouse result * @return Greenhouse result
*/ */
GhResult checkRecipe(CompletableFuture<GhResult> r, GreenhouseFinder finder, BiomeRecipe greenhouseRecipe, Set<GreenhouseResult> resultSet) { CompletableFuture<GhResult> checkRecipe(GreenhouseFinder finder, BiomeRecipe greenhouseRecipe, Set<GreenhouseResult> resultSet) {
resultSet = greenhouseRecipe.checkRecipe(finder.getGh()); CompletableFuture<GhResult> r = new CompletableFuture<>();
if (resultSet.isEmpty()) { greenhouseRecipe.checkRecipe(finder.getGh()).thenAccept(rs -> {
// Success - set recipe and add to map if (rs.isEmpty()) {
finder.getGh().setBiomeRecipe(greenhouseRecipe); // Success - set recipe and add to map
resultSet.add(map.addGreenhouse(finder.getGh())); finder.getGh().setBiomeRecipe(greenhouseRecipe);
activateGreenhouse(finder.getGh()); resultSet.add(map.addGreenhouse(finder.getGh()));
handler.saveObjectAsync(finder.getGh()); activateGreenhouse(finder.getGh());
} handler.saveObjectAsync(finder.getGh());
GhResult recipe = new GhResult().setFinder(finder).setResults(resultSet); }
r.complete(recipe); GhResult recipe = new GhResult().setFinder(finder).setResults(rs);
return recipe; r.complete(recipe);
});
return r;
} }
private void activateGreenhouse(Greenhouse gh) { private void activateGreenhouse(Greenhouse gh) {

View File

@ -13,7 +13,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -48,7 +47,6 @@ import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.Settings; import world.bentobox.greenhouses.Settings;
import world.bentobox.greenhouses.data.Greenhouse; import world.bentobox.greenhouses.data.Greenhouse;
import world.bentobox.greenhouses.managers.GreenhouseManager; import world.bentobox.greenhouses.managers.GreenhouseManager;
import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult;
import world.bentobox.greenhouses.managers.GreenhouseMap; import world.bentobox.greenhouses.managers.GreenhouseMap;
/** /**
@ -237,8 +235,8 @@ public class BiomeRecipeTest {
*/ */
@Test @Test
public void testCheckRecipe() { public void testCheckRecipe() {
Set<GreenhouseResult> result = br.checkRecipe(gh); br.checkRecipe(gh).thenAccept(result ->
assertTrue(result.isEmpty()); assertTrue(result.isEmpty()));
} }
/** /**
@ -247,8 +245,8 @@ public class BiomeRecipeTest {
@Test @Test
public void testCheckRecipeNotEnough() { public void testCheckRecipeNotEnough() {
br.addReqBlocks(Material.ACACIA_LEAVES, 3); br.addReqBlocks(Material.ACACIA_LEAVES, 3);
Set<GreenhouseResult> result = br.checkRecipe(gh); br.checkRecipe(gh).thenAccept(result ->
assertFalse(result.isEmpty()); assertFalse(result.isEmpty()));
} }