Made roof search async

This commit is contained in:
tastybento 2021-01-16 09:16:09 -08:00
parent 08e9c25172
commit cc114027da
10 changed files with 362 additions and 171 deletions

View File

@ -46,4 +46,11 @@ public abstract class MinMaxXZ {
public int getArea() {
return (maxX - minX) * (maxZ - minZ);
}
@Override
public String toString() {
return "MinMaxXZ [minX=" + minX + ", maxX=" + maxX + ", minZ=" + minZ + ", maxZ=" + maxZ + "]";
}
}

View File

@ -3,15 +3,18 @@ package world.bentobox.greenhouses.greenhouse;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
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.World;
import org.bukkit.block.Block;
import org.bukkit.util.Vector;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.world.AsyncWorldCache;
/**
* Contains the parameters of a greenhouse roof
@ -19,6 +22,7 @@ import world.bentobox.greenhouses.Greenhouses;
*
*/
public class Roof extends MinMaxXZ {
private static final BentoBox PLUGIN = Greenhouses.getInstance().getPlugin();
private static final List<Material> ROOF_BLOCKS;
static {
List<Material> r = Arrays.stream(Material.values())
@ -29,40 +33,111 @@ public class Roof extends MinMaxXZ {
.collect(Collectors.toList());
ROOF_BLOCKS = Collections.unmodifiableList(r);
}
private final Location location;
/**
* Check if material is a roof material
* @param m - material
* @return true if roof material
*/
public static boolean roofBlocks(Material m) {
return ROOF_BLOCKS.contains(m)
|| (m.equals(Material.GLOWSTONE) && Greenhouses.getInstance().getSettings().isAllowGlowstone())
|| (m.name().endsWith("GLASS_PANE") && Greenhouses.getInstance().getSettings().isAllowPanes());
}
private final AsyncWorldCache cache;
private int height;
private final Location location;
private boolean roofFound;
private final World world;
/**
* Finds a roof from a starting location under the roof and characterizes it
* @param cache
* @param loc - starting location
*/
public Roof(Location loc) {
public Roof(AsyncWorldCache cache, Location loc) {
this.cache = cache;
this.location = loc;
roofFound = findRoof(loc);
this.world = loc.getWorld();
}
private boolean findRoof(Location loc) {
World world = loc.getWorld();
/**
* This takes any location and tries to go as far as possible in NWSE directions finding contiguous roof blocks
* up to 100 in any direction
* @param vector - vector to start search
*/
private void expandCoords(Vector vector) {
Vector maxx = vector.clone();
Vector minx = vector.clone();
Vector maxz = vector.clone();
Vector minz = vector.clone();
int limit = 0;
while (roofBlocks(cache.getBlockType(maxx)) && limit < 100) {
limit++;
maxx.add(new Vector(1,0,0));
}
// Set Max x
if (maxx.getBlockX() - 1 > maxX) {
maxX = maxx.getBlockX() - 1;
}
limit = 0;
while (roofBlocks(cache.getBlockType(minx)) && limit < 100) {
limit++;
minx.subtract(new Vector(1,0,0));
}
if (minx.getBlockX() + 1 < minX) {
minX = minx.getBlockX() + 1;
}
limit = 0;
while (roofBlocks(cache.getBlockType(maxz)) && limit < 100) {
limit++;
maxz.add(new Vector(0,0,1));
}
if (maxz.getBlockZ() - 1 > maxZ) {
maxZ = maxz.getBlockZ() - 1;
}
limit = 0;
while (roofBlocks(cache.getBlockType(minz)) && limit < 100) {
limit++;
minz.subtract(new Vector(0,0,1));
}
if (minz.getBlockZ() + 1 < minZ) {
minZ = minz.getBlockZ() + 1;
}
}
public CompletableFuture<Boolean> findRoof() {
CompletableFuture<Boolean> r = new CompletableFuture<>();
Vector loc = location.toVector();
// This section tries to find a roof block
// Try just going up - this covers every case except if the player is standing under a hole
roofFound = false;
Bukkit.getScheduler().runTaskAsynchronously(PLUGIN, () -> {
boolean found = findRoof(loc);
Bukkit.getScheduler().runTask(PLUGIN, () -> r.complete(found));
});
return r;
}
private boolean findRoof(Vector loc) {
// This does a ever-growing check around the player to find a wall block. It is possible for the player
// to be outside the greenhouse in this situation, so a check is done later to make sure the player is inside
int roofY = loc.getBlockY();
for (int y = roofY; y < world.getMaxHeight(); y++) {
if (roofBlocks(world.getBlockAt(loc.getBlockX(),y,loc.getBlockZ()).getType())) {
if (roofBlocks(cache.getBlockType(loc.getBlockX(),y,loc.getBlockZ()))) {
roofFound = true;
loc = new Location(world,loc.getBlockX(),y,loc.getBlockZ());
loc = new Vector(loc.getBlockX(),y,loc.getBlockZ());
break;
}
}
// If the roof was not found start going around in circles until something is found
// Expand in ever increasing squares around location until a wall block is found
spiralSearch(loc, roofY);
if (!roofFound) return false;
if (!roofFound) {
return false;
}
// Record the height
this.height = loc.getBlockY();
// Now we have a roof block, find how far we can go NSWE
@ -70,7 +145,7 @@ public class Roof extends MinMaxXZ {
maxX = loc.getBlockX();
minZ = loc.getBlockZ();
maxZ = loc.getBlockZ();
expandCoords(world, loc.toVector());
expandCoords(loc);
int minx;
int maxx;
int minz;
@ -84,7 +159,7 @@ public class Roof extends MinMaxXZ {
for (int x = minx; x <= maxx; x++) {
for (int z = minz; z <= maxz; z++) {
// This will push out the coords if possible
expandCoords(world, new Vector(x, loc.getBlockY(), z));
expandCoords(new Vector(x, loc.getBlockY(), z));
}
}
// Repeat until nothing changes
@ -93,98 +168,6 @@ public class Roof extends MinMaxXZ {
return true;
}
private void spiralSearch(Location loc, int roofY) {
for (int radius = 0; radius < 3 && !roofFound; radius++) {
for (int x = loc.getBlockX() - radius; x <= loc.getBlockX() + radius && !roofFound; x++) {
for (int z = loc.getBlockZ() - radius; z <= loc.getBlockZ() + radius && !roofFound; z++) {
if (!((x > loc.getBlockX() - radius && x < loc.getBlockX() + radius) && (z > loc.getBlockZ() - radius && z < loc.getBlockZ() + radius))) {
checkVertically(loc, x, roofY, z);
}
}
}
}
}
private void checkVertically(Location loc, int x, int roofY, int z) {
World world = loc.getWorld();
Block b = world.getBlockAt(x, roofY, z);
if (!Walls.wallBlocks(b.getType())) {
// Look up
for (int y = roofY; y < world.getMaxHeight() && !roofFound; y++) {
if (roofBlocks(world.getBlockAt(x,y,z).getType())) {
roofFound = true;
loc = new Location(world,x,y,z);
}
}
}
}
/**
* This takes any location and tries to go as far as possible in NWSE directions finding contiguous roof blocks
* up to 100 in any direction
* @param height - location to start search
*/
private void expandCoords(World world, Vector height) {
Location maxx = height.toLocation(world);
Location minx = height.toLocation(world);
Location maxz = height.toLocation(world);
Location minz = height.toLocation(world);
int limit = 0;
while (ROOF_BLOCKS
.contains(world.getBlockAt(maxx).getType()) && limit < 100) {
limit++;
maxx.add(new Vector(1,0,0));
}
if (maxx.getBlockX()-1 > maxX) {
maxX = maxx.getBlockX()-1;
}
while (roofBlocks(world.getBlockAt(minx).getType()) && limit < 200) {
limit++;
minx.subtract(new Vector(1,0,0));
}
if (minx.getBlockX() + 1 < minX) {
minX = minx.getBlockX() + 1;
}
while (roofBlocks(world.getBlockAt(maxz).getType()) && limit < 300) {
limit++;
maxz.add(new Vector(0,0,1));
}
if (maxz.getBlockZ() - 1 > maxZ) {
maxZ = maxz.getBlockZ() - 1;
}
while (roofBlocks(world.getBlockAt(minz).getType()) && limit < 400) {
limit++;
minz.subtract(new Vector(0,0,1));
}
if (minz.getBlockZ() + 1 < minZ) {
minZ = minz.getBlockZ() + 1;
}
}
/**
* Check if material is a roof material
* @param m - material
* @return true if roof material
*/
public static boolean roofBlocks(Material m) {
return ROOF_BLOCKS.contains(m)
|| (m.equals(Material.GLOWSTONE) && Greenhouses.getInstance().getSettings().isAllowGlowstone())
|| (m.name().endsWith("GLASS_PANE") && Greenhouses.getInstance().getSettings().isAllowPanes());
}
/**
* @return the roofFound
*/
public boolean isRoofFound() {
return roofFound;
}
/**
* @return the height
*/
@ -192,6 +175,7 @@ public class Roof extends MinMaxXZ {
return height;
}
/**
* @return the location
*/
@ -199,13 +183,47 @@ public class Roof extends MinMaxXZ {
return location;
}
private void spiralSearch(Vector v, int roofY) {
for (int radius = 0; radius < 3 && !roofFound; radius++) {
for (int x = v.getBlockX() - radius; x <= v.getBlockX() + radius && !roofFound; x++) {
for (int z = v.getBlockZ() - radius; z <= v.getBlockZ() + radius && !roofFound; z++) {
if (!((x > v.getBlockX() - radius && x < v.getBlockX() + radius) && (z > v.getBlockZ() - radius && z < v.getBlockZ() + radius))) {
checkVertically(v, x, roofY, z);
}
}
}
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
}
/**
* Get highest roof block
* @param v - vector of search block
* @param x - x coord of current search
* @param roofY - roof y coord
* @param z - z coord of current search
*/
private void checkVertically(Vector v, final int x, final int roofY, final int z) {
if (!Walls.wallBlocks(cache.getBlockType(x, roofY, z))) {
// Look up
for (int y = roofY; y < world.getMaxHeight() && !roofFound; y++) {
if (roofBlocks(cache.getBlockType(x,y,z))) {
roofFound = true;
// Move roof up because there is a higher block
v = new Vector(x,y,z);
}
}
}
}
@Override
public String toString() {
return "Roof [location=" + location + ", minX=" + minX + ", maxX=" + maxX + ", minZ=" + minZ + ", maxZ=" + maxZ
+ ", height=" + height + ", roofFound=" + roofFound + "]";
return "Roof [" + (cache != null ? "cache=" + cache + ", " : "") + "height=" + height + ", "
+ (location != null ? "location=" + location + ", " : "") + "roofFound=" + roofFound + ", "
+ (world != null ? "world=" + world + ", " : "") + "minX=" + minX + ", maxX=" + maxX + ", minZ=" + minZ
+ ", maxZ=" + maxZ + "]";
}
}

View File

@ -3,6 +3,7 @@ package world.bentobox.greenhouses.greenhouse;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import org.bukkit.Location;
@ -43,7 +44,12 @@ public class Walls extends MinMaxXZ {
}
}
public Walls findWalls(Roof roof) {
/**
* Find walls given a roof
* @param roof - the roof
* @return Future walls
*/
public CompletableFuture<Walls> findWalls(Roof roof) {
// The player is under the roof
// Assume the player is inside the greenhouse they are trying to create
Location loc = roof.getLocation();
@ -65,7 +71,7 @@ public class Walls extends MinMaxXZ {
maxZ++;
// Find the floor again, only looking within the walls
floor = getFloorY(world, roof.getHeight(), minX, maxX, minZ,maxZ);
return this;
return CompletableFuture.completedFuture(this);
}
void lookAround(Location loc, WallFinder wf, Roof roof) {

View File

@ -3,6 +3,7 @@ package world.bentobox.greenhouses.managers;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import org.bukkit.Location;
import org.bukkit.Material;
@ -11,10 +12,12 @@ import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.block.Block;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.greenhouses.data.Greenhouse;
import world.bentobox.greenhouses.greenhouse.Roof;
import world.bentobox.greenhouses.greenhouse.Walls;
import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult;
import world.bentobox.greenhouses.world.AsyncWorldCache;
public class GreenhouseFinder {
@ -45,32 +48,50 @@ public class GreenhouseFinder {
/**
* Find out if there is a greenhouse here
* @param location - start location
* @return GreenhouseResult class
* @return future GreenhouseResult class
*/
public Set<GreenhouseResult> find(Location location) {
public CompletableFuture<Set<GreenhouseResult>> find(Location location) {
CompletableFuture<Set<GreenhouseResult>> r = new CompletableFuture<>();
Set<GreenhouseResult> result = new HashSet<>();
redGlass.clear();
// Get a world cache
AsyncWorldCache cache = new AsyncWorldCache(location.getWorld());
// Find the roof
Roof roof = new Roof(location);
if (!roof.isRoofFound()) {
result.add(GreenhouseResult.FAIL_NO_ROOF);
return result;
}
// Find the walls
Walls walls = new Walls().findWalls(roof);
// Make the initial greenhouse
gh = new Greenhouse(location.getWorld(), walls, roof.getHeight());
// Set the original biome
gh.setOriginalBiome(location.getBlock().getBiome());
Roof roof = new Roof(cache, location);
roof.findRoof().thenAccept(found -> {
if (!found) {
result.add(GreenhouseResult.FAIL_NO_ROOF);
r.complete(result);
return;
}
BentoBox.getInstance().logDebug(roof);
// Find the walls
new Walls().findWalls(roof).thenAccept(walls -> {
// Make the initial greenhouse
gh = new Greenhouse(location.getWorld(), walls, roof.getHeight());
// Set the original biome
gh.setOriginalBiome(location.getBlock().getBiome());
// Now check to see if the floor really is the floor and the walls follow the rules
result.addAll(checkGreenhouse(gh, roof, walls));
// Now check to see if the floor really is the floor and the walls follow the rules
checkGreenhouse(gh, roof, walls).thenAccept(c -> {
result.addAll(c);
r.complete(result);
});
});
return result;
});
return r;
}
Set<GreenhouseResult> checkGreenhouse(Greenhouse gh2, Roof roof, Walls walls) {
/**
* Check the greenhouse has the right number of everything
* @param gh2 - greenhouse
* @param roof - roof object
* @param walls - walls object
* @return future set of Greenhouse Results
*/
CompletableFuture<Set<GreenhouseResult>> checkGreenhouse(Greenhouse gh2, Roof roof, Walls walls) {
Set<GreenhouseResult> result = new HashSet<>();
World world = roof.getLocation().getWorld();
int y;
@ -101,7 +122,7 @@ public class GreenhouseFinder {
}
result.addAll(checkErrors(roof, y));
return result;
return CompletableFuture.completedFuture(result);
}
Collection<GreenhouseResult> checkErrors(Roof roof, int y) {

View File

@ -3,6 +3,7 @@ package world.bentobox.greenhouses.managers;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import org.bukkit.Location;
import org.bukkit.block.Biome;
@ -153,29 +154,36 @@ public class GreenhouseManager implements Listener {
* If type is stated then only this specific type will be checked
* @param location - location to start search from
* @param greenhouseRecipe - recipe requested, or null for a best-effort search
* @return - greenhouse result {@link GhResult}
* @return - future greenhouse result {@link GhResult}
*/
public GhResult tryToMakeGreenhouse(Location location, BiomeRecipe greenhouseRecipe) {
public CompletableFuture<GhResult> tryToMakeGreenhouse(Location location, BiomeRecipe greenhouseRecipe) {
CompletableFuture<GhResult> r = new CompletableFuture<>();
GreenhouseFinder finder = new GreenhouseFinder();
Set<GreenhouseResult> resultSet = finder.find(location);
if (!resultSet.isEmpty()) {
// Failure!
return new GhResult().setFinder(finder).setResults(resultSet);
}
// Check if the greenhouse meets the requested recipe
if (greenhouseRecipe != null) {
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());
finder.find(location).thenAccept(resultSet -> {
if (!resultSet.isEmpty()) {
// Failure!
r.complete(new GhResult().setFinder(finder).setResults(resultSet));
return;
}
// Check if the greenhouse meets the requested recipe
if (greenhouseRecipe != null) {
checkRecipe(r, finder, greenhouseRecipe, resultSet);
return;
}
return new GhResult().setFinder(finder).setResults(resultSet);
}
// Try ordered recipes
// Try ordered recipes
findRecipe(finder, resultSet);
r.complete(new GhResult().setFinder(finder).setResults(resultSet));
});
return r;
}
/**
* Tries to match the greenhouse to a recipe by going through all of them in order
* @param finder - finder object
* @param resultSet - result set from find
*/
private void findRecipe(GreenhouseFinder finder, Set<GreenhouseResult> resultSet) {
resultSet.add(addon.getRecipes().getBiomeRecipes().stream().sorted()
.filter(r -> r.checkRecipe(finder.getGh()).isEmpty()).findFirst()
.map(r -> {
@ -185,7 +193,29 @@ public class GreenhouseManager implements Listener {
handler.saveObjectAsync(finder.getGh());
return map.addGreenhouse(finder.getGh());
}).orElse(GreenhouseResult.FAIL_NO_RECIPE_FOUND));
return new GhResult().setFinder(finder).setResults(resultSet);
}
/**
* Checks to see if the greenhouse meets the designated recipe and returns the result
* @param r - completable future
* @param finder - finder object
* @param greenhouseRecipe - recipe requested
* @param resultSet - result set from finder
* @return Greenhouse result
*/
GhResult checkRecipe(CompletableFuture<GhResult> r, GreenhouseFinder finder, BiomeRecipe greenhouseRecipe, Set<GreenhouseResult> 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;
}
private void activateGreenhouse(Greenhouse gh) {

View File

@ -55,12 +55,15 @@ public class PanelClick implements ClickHandler {
user.sendMessage("greenhouses.commands.user.make.error.already");
return false;
}
GhResult result = addon.getManager().tryToMakeGreenhouse(location, br);
addon.getManager().tryToMakeGreenhouse(location, br).thenAccept(r -> processResult(user, r));
return true;
}
void processResult(User user, GhResult result) {
if (result.getResults().contains(GreenhouseResult.SUCCESS)) {
// Success
user.sendMessage("greenhouses.commands.user.make.success", "[biome]", result.getFinder().getGh().getBiomeRecipe().getFriendlyName());
return true;
return;
}
result.getResults().forEach(r -> user.sendMessage("greenhouses.commands.user.make.error." + r.name()));
if (!result.getFinder().getRedGlass().isEmpty()) {
@ -69,8 +72,7 @@ public class PanelClick implements ClickHandler {
Bukkit.getScheduler().runTaskLater(addon.getPlugin(), () -> result.getFinder().getRedGlass().forEach(rg -> user.getPlayer().sendBlockChange(rg, rg.getBlock().getBlockData())), 120L);
}
if (result.getResults().contains(GreenhouseResult.FAIL_INSUFFICIENT_BLOCKS)) {
result.getFinder().getGh().getMissingBlocks().forEach((k,v) -> user.sendMessage("greenhouses.commands.user.make.missing-blocks", "[material]", Util.prettifyText(k.toString()), TextVariables.NUMBER, String.valueOf(v)));
result.getFinder().getGh().getMissingBlocks().forEach((k,v) -> user.sendMessage("greenhouses.commands.user.make.missing-blocks", "[material]", Util.prettifyText(k.toString()), TextVariables.NUMBER, String.valueOf(v)));
}
return true;
}
}

View File

@ -76,7 +76,7 @@ class MakeCommand extends CompositeCommand {
return getRecipes(user).get(arg);
}
/**
* Get a string list of recipies the player has permission to use
* Get a string list of recipes the player has permission to use
* @param user - user
* @return list
*/
@ -99,7 +99,12 @@ class MakeCommand extends CompositeCommand {
user.sendMessage("greenhouses.commands.user.make.error.already");
return false;
}
GhResult result = ((Greenhouses)this.getAddon()).getManager().tryToMakeGreenhouse(location, br);
// Try to make the greenhouse
((Greenhouses)this.getAddon()).getManager().tryToMakeGreenhouse(location, br).thenAccept(result -> informUser(user, br, result));
return true;
}
private boolean informUser(User user, BiomeRecipe br, GhResult result) {
if (result.getResults().contains(GreenhouseResult.SUCCESS)) {
// Success
user.sendMessage("greenhouses.commands.user.make.success", "[biome]", result.getFinder().getGh().getBiomeRecipe().getFriendlyName());
@ -114,7 +119,7 @@ class MakeCommand extends CompositeCommand {
if (br != null && result.getResults().contains(GreenhouseResult.FAIL_INSUFFICIENT_BLOCKS)) {
result.getFinder().getGh().getMissingBlocks().forEach((k,v) -> user.sendMessage("greenhouses.commands.user.make.missing-blocks", "[material]", Util.prettifyText(k.toString()), TextVariables.NUMBER, String.valueOf(v)));
}
return true;
return false;
}
@Override

View File

@ -0,0 +1,105 @@
package world.bentobox.greenhouses.world;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import org.bukkit.Bukkit;
import org.bukkit.ChunkSnapshot;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.util.Vector;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.util.Pair;
import world.bentobox.bentobox.util.Util;
import world.bentobox.greenhouses.Greenhouses;
/**
* Provides a thread-safe cache world chunks
* @author tastybento
*
*/
public class AsyncWorldCache {
private final World world;
private final Map<Pair<Integer, Integer>, ChunkSnapshot> cache;
/**
* Chunk cache. This class is designed to be run async and blocks futures
* @param world - world to cache
*/
public AsyncWorldCache(World world) {
this.world = world;
cache = new HashMap<>();
}
/**
* Get chunk snapshot from world
* @param x - coord
* @param z - coord
* @return future chunk snapshot
*/
private CompletableFuture<ChunkSnapshot> getAChunk(int x, int z) {
CompletableFuture<ChunkSnapshot> r = new CompletableFuture<>();
Bukkit.getScheduler().runTask(Greenhouses.getInstance().getPlugin(), () ->
Util.getChunkAtAsync(world, x, z).thenAccept(chunk -> r.complete(chunk.getChunkSnapshot())));
return r;
}
/**
* Get snapshot from cache or world
* @param x - block coord
* @param z - block coord
* @return chunk snapshot
*/
private ChunkSnapshot getSnap(int x, int z) {
// Convert from block to chunk coords
Pair<Integer, Integer> key = new Pair<>((x >> 4), (z >> 4));
// Get from cache if it is available
if (cache.containsKey(key)) {
return cache.get(key);
}
ChunkSnapshot cs;
try {
// Block on getting the chunk because this is running async
cs = getAChunk(key.x, key.z).get();
} catch (InterruptedException | ExecutionException e) {
// Try again...
return getSnap(x,z);
}
// Store in cache
cache.put(key, cs);
return cs;
}
/**
* Get block material for block at corresponding coordinates
*
* @param x block coordinate
* @param y 0-255
* @param z block coordinate
* @return material type
*/
public Material getBlockType(int x, int y, int z) {
// Convert block coords to chunk coords
int xx = x >= 0 ? x % 16 : 15 + (x % 16);
int zz = z >= 0 ? z % 16 : 15 + (z % 16);
Material m = getSnap(x,z).getBlockType(xx, y, zz);
BentoBox.getInstance().logDebug(m);
return m;
}
/**
* Get block material for block at corresponding coordinates
* @param v - vector
* @return Material
*/
public Material getBlockType(Vector v) {
return getBlockType(v.getBlockX(), v.getBlockY(), v.getBlockZ());
}
}

View File

@ -22,6 +22,7 @@ import org.powermock.modules.junit4.PowerMockRunner;
import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.Settings;
import world.bentobox.greenhouses.world.AsyncWorldCache;
/**
@ -42,6 +43,7 @@ public class RoofTest {
@Mock
private Greenhouses addon;
private Settings s;
private AsyncWorldCache cache;
/**
* @throws java.lang.Exception
@ -89,15 +91,17 @@ public class RoofTest {
when(location.getBlock()).thenReturn(block);
when(location.clone()).thenReturn(location);
cache = new AsyncWorldCache(world);
// Test
roof = new Roof(location);
roof = new Roof(cache, location);
roof.findRoof();
}
@Test
public void testNoGlass() {
when(block.getType()).thenReturn(Material.AIR);
roof = new Roof(location);
roof = new Roof(cache, location);
roof.findRoof();
}
/**
@ -140,14 +144,6 @@ public class RoofTest {
assertEquals(1406, roof.getArea());
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.Roof#isRoofFound()}.
*/
@Test
public void testIsRoofFound() {
assertTrue(roof.isRoofFound());
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.Roof#getHeight()}.
*/

View File

@ -107,11 +107,12 @@ public class GreenhouseFinderTest {
@Test
public void testCheckGreenhouse() {
Greenhouse gh2 = new Greenhouse(world, walls, ROOF_HEIGHT);
Set<GreenhouseResult> result = gf.checkGreenhouse(gh2, roof, walls);
assertTrue(result.isEmpty()); // Success
assertEquals(441, gf.getWallBlockCount());
assertEquals(0, gf.getWallDoors());
assertEquals(0, gf.getGhHopper());
gf.checkGreenhouse(gh2, roof, walls).thenAccept(result -> {
assertTrue(result.isEmpty()); // Success
assertEquals(441, gf.getWallBlockCount());
assertEquals(0, gf.getWallDoors());
assertEquals(0, gf.getGhHopper());
});
}
/**