Async greenhouse building

https://github.com/BentoBoxWorld/Greenhouses/issues/68
This commit is contained in:
tastybento 2021-01-16 18:57:01 -08:00
parent baa933881d
commit cd5a0ce2a1
7 changed files with 175 additions and 279 deletions

View File

@ -8,6 +8,7 @@ import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.util.BoundingBox; import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
@ -50,6 +51,12 @@ public class Greenhouse implements DataObject {
*/ */
public Greenhouse() {} public Greenhouse() {}
/**
* Create a greenhouse
* @param world - world
* @param walls - wall object
* @param ceilingHeight - ceiling height
*/
public Greenhouse(World world, Walls walls, int ceilingHeight) { public Greenhouse(World world, Walls walls, int ceilingHeight) {
this.location = new Location(world, walls.getMinX(), walls.getFloor(), walls.getMinZ()); this.location = new Location(world, walls.getMinX(), walls.getFloor(), walls.getMinZ());
Location location2 = new Location(world, walls.getMaxX() + 1D, ceilingHeight + 1D, walls.getMaxZ() + 1D); Location location2 = new Location(world, walls.getMaxX() + 1D, ceilingHeight + 1D, walls.getMaxZ() + 1D);
@ -147,10 +154,10 @@ public class Greenhouse implements DataObject {
} }
/** /**
* @param roofHopperLocation the roofHopperLocation to set * @param v the roofHopperLocation to set
*/ */
public void setRoofHopperLocation(Location roofHopperLocation) { public void setRoofHopperLocation(Vector v) {
this.roofHopperLocation = roofHopperLocation; this.roofHopperLocation = v.toLocation(getWorld());
} }
/** /**

View File

@ -5,13 +5,13 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Tag; import org.bukkit.Tag;
import org.bukkit.World; import org.bukkit.util.Vector;
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.data.Greenhouse;
import world.bentobox.greenhouses.greenhouse.Roof; import world.bentobox.greenhouses.greenhouse.Roof;
import world.bentobox.greenhouses.greenhouse.Walls; import world.bentobox.greenhouses.greenhouse.Walls;
@ -20,22 +20,18 @@ import world.bentobox.greenhouses.world.AsyncWorldCache;
public class GreenhouseFinder { public class GreenhouseFinder {
private Greenhouse gh = new Greenhouse(); private Greenhouse gh;
private final Set<Location> redGlass = new HashSet<>(); private final Set<Vector> redGlass = new HashSet<>();
// Counts
private int wallDoors = 0;
// Hoppers
private int ghHopper = 0;
// Air
private boolean airHoles = false;
// Other blocks
private boolean otherBlocks = false;
// Ceiling issue // Ceiling issue
private boolean inCeiling = false; private boolean inCeiling = false;
// The y height where other blocks were found // The y height where other blocks were found
// If this is the bottom layer, the player has most likely uneven walls // If this is the bottom layer, the player has most likely uneven walls
private int otherBlockLayer = -1; private int otherBlockLayer = -1;
private int wallBlockCount; private int wallBlockCount;
/**
* This is the count of the various items
*/
private CounterCheck cc = new CounterCheck();
class CounterCheck { class CounterCheck {
int doorCount; int doorCount;
@ -72,7 +68,7 @@ public class GreenhouseFinder {
gh.setOriginalBiome(location.getBlock().getBiome()); gh.setOriginalBiome(location.getBlock().getBiome());
// Now check to see if the floor really is the floor and the walls follow the rules // Now check to see if the floor really is the floor and the walls follow the rules
checkGreenhouse(gh, roof, walls).thenAccept(c -> { checkGreenhouse(cache, gh, roof, walls).thenAccept(c -> {
result.addAll(c); result.addAll(c);
r.complete(result); r.complete(result);
}); });
@ -84,34 +80,35 @@ public class GreenhouseFinder {
/** /**
* Check the greenhouse has the right number of everything * Check the greenhouse has the right number of everything
* @param cache
* @param gh2 - greenhouse * @param gh2 - greenhouse
* @param roof - roof object * @param roof - roof object
* @param walls - walls object * @param walls - walls object
* @return future set of Greenhouse Results * @return future set of Greenhouse Results
*/ */
CompletableFuture<Set<GreenhouseResult>> checkGreenhouse(Greenhouse gh2, Roof roof, Walls walls) { CompletableFuture<Set<GreenhouseResult>> checkGreenhouse(AsyncWorldCache cache, Greenhouse gh2, Roof roof, Walls walls) {
CompletableFuture<Set<GreenhouseResult>> r = new CompletableFuture<>();
Bukkit.getScheduler().runTaskAsynchronously(BentoBox.getInstance(), () -> checkGHAsync(r, cache, gh2, roof, walls));
return r;
}
private Set<GreenhouseResult> checkGHAsync(CompletableFuture<Set<GreenhouseResult>> r, AsyncWorldCache cache, Greenhouse gh2,
Roof roof, Walls walls) {
Set<GreenhouseResult> result = new HashSet<>(); Set<GreenhouseResult> result = new HashSet<>();
World world = roof.getLocation().getWorld(); cc = new CounterCheck();
int y; int y;
for (y = world.getMaxHeight() - 1; y >= walls.getFloor(); y--) { for (y = roof.getHeight(); y > walls.getFloor(); y--) {
CounterCheck cc = new CounterCheck();
wallBlockCount = 0; wallBlockCount = 0;
for (int x = walls.getMinX(); x <= walls.getMaxX(); x++) { for (int x = walls.getMinX(); x <= walls.getMaxX(); x++) {
for (int z = walls.getMinZ(); z <= walls.getMaxZ(); z++) { for (int z = walls.getMinZ(); z <= walls.getMaxZ(); z++) {
result.addAll(checkBlock(cc, roof, walls, world.getBlockAt(x, y, z))); checkBlock(cc, cache.getBlockType(x,y,z), roof, walls, new Vector(x, y, z));
} }
} }
if (wallBlockCount == 0 && y < roof.getHeight()) { if (wallBlockCount == 0 && y < roof.getHeight()) {
// This is the floor // This is the floor
break; break;
} else { } else {
wallDoors += cc.doorCount;
ghHopper += cc.hopperCount;
if (cc.airHole) {
airHoles = true;
}
if (cc.otherBlock) { if (cc.otherBlock) {
otherBlocks = true;
if (otherBlockLayer < 0) { if (otherBlockLayer < 0) {
otherBlockLayer = y; otherBlockLayer = y;
} }
@ -120,7 +117,8 @@ public class GreenhouseFinder {
} }
result.addAll(checkErrors(roof, y)); result.addAll(checkErrors(roof, y));
return CompletableFuture.completedFuture(result); Bukkit.getScheduler().runTask(BentoBox.getInstance(), () -> r.complete(result));
return result;
} }
Collection<GreenhouseResult> checkErrors(Roof roof, int y) { Collection<GreenhouseResult> checkErrors(Roof roof, int y) {
@ -130,102 +128,101 @@ public class GreenhouseFinder {
result.add(GreenhouseResult.FAIL_BELOW); result.add(GreenhouseResult.FAIL_BELOW);
} }
// Show errors // Show errors
if (airHoles && !inCeiling) { if (isAirHoles() && !inCeiling) {
result.add(GreenhouseResult.FAIL_HOLE_IN_WALL); result.add(GreenhouseResult.FAIL_HOLE_IN_WALL);
} else if (airHoles && inCeiling) { } else if (isAirHoles() && inCeiling) {
result.add(GreenhouseResult.FAIL_HOLE_IN_ROOF); result.add(GreenhouseResult.FAIL_HOLE_IN_ROOF);
} }
if (otherBlocks && otherBlockLayer == y + 1) { if (isOtherBlocks() && otherBlockLayer == y + 1) {
// Walls must be even all the way around // Walls must be even all the way around
result.add(GreenhouseResult.FAIL_UNEVEN_WALLS); result.add(GreenhouseResult.FAIL_UNEVEN_WALLS);
} else if (otherBlocks && otherBlockLayer == roof.getHeight()) { } else if (isOtherBlocks() && otherBlockLayer == roof.getHeight()) {
// Roof blocks must be glass, glowstone, doors or a hopper. // Roof blocks must be glass, glowstone, doors or a hopper.
result.add(GreenhouseResult.FAIL_BAD_ROOF_BLOCKS); result.add(GreenhouseResult.FAIL_BAD_ROOF_BLOCKS);
} else if (otherBlocks) { } else if (isOtherBlocks()) {
// "Wall blocks must be glass, glowstone, doors or a hopper. // "Wall blocks must be glass, glowstone, doors or a hopper.
result.add(GreenhouseResult.FAIL_BAD_WALL_BLOCKS); result.add(GreenhouseResult.FAIL_BAD_WALL_BLOCKS);
} }
if (wallDoors > 8) { if (this.getWallDoors() > 8) {
result.add(GreenhouseResult.FAIL_TOO_MANY_DOORS); result.add(GreenhouseResult.FAIL_TOO_MANY_DOORS);
} }
if (ghHopper > 1) { if (this.getGhHopper() > 1) {
result.add(GreenhouseResult.FAIL_TOO_MANY_HOPPERS); result.add(GreenhouseResult.FAIL_TOO_MANY_HOPPERS);
} }
return result; return result;
} }
Set<GreenhouseResult> checkBlock(CounterCheck cc, Roof roof, Walls walls, Block block) {
Set<GreenhouseResult> result = new HashSet<>();
World world = block.getWorld();
// Checking above greenhouse - no blocks allowed
if (block.getY() > roof.getHeight()) {
// We are above the greenhouse
if (!world.getEnvironment().equals(Environment.NETHER) && !block.isEmpty()) {
result.add(GreenhouseResult.FAIL_BLOCKS_ABOVE);
redGlass.add(block.getLocation());
}
} else {
// Check just the walls
checkWalls(block, roof, walls, cc);
}
return result;
}
/** /**
* Check a wall block * Check if block is allowed to be in that location
* @param block - block * @param cc - Counter Check object
* @param m - material of the block
* @param roof - roof object * @param roof - roof object
* @param walls - wall object * @param walls - walls object
* @param cc - count * @param v - vector location of the block
* @return true if block was in the wall * @return true if block is acceptable, false if not
*/ */
boolean checkWalls(Block block, Roof roof, Walls walls, CounterCheck cc) { boolean checkBlock(CounterCheck cc, Material m, Roof roof, Walls walls, Vector v) {
int x = block.getX(); final int x = v.getBlockX();
int y = block.getY(); final int y = v.getBlockY();
int z = block.getZ(); final int z = v.getBlockZ();
// Check wall blocks only // Check wall blocks only
if (y == roof.getHeight() || x == walls.getMinX() || x == walls.getMaxX() || z == walls.getMinZ() || z== walls.getMaxZ()) { if (y == roof.getHeight() || x == walls.getMinX() || x == walls.getMaxX() || z == walls.getMinZ() || z== walls.getMaxZ()) {
// Check for non-wall blocks or non-roof blocks at the top of walls // Check for non-wall blocks or non-roof blocks at the top of walls
if ((y != roof.getHeight() && !Walls.wallBlocks(block.getType())) || (y == roof.getHeight() && !Roof.roofBlocks(block.getType()))) { if ((y != roof.getHeight() && !Walls.wallBlocks(m)) || (y == roof.getHeight() && !Roof.roofBlocks(m))) {
if (block.isEmpty()) { if (m.equals(Material.AIR)) {
// Air hole found
cc.airHole = true; cc.airHole = true;
if (y == roof.getHeight()) { if (y == roof.getHeight()) {
// Air hole is in ceiling
inCeiling = true; inCeiling = true;
} }
} else { } else {
// A non-wall or roof block found
cc.otherBlock = true; cc.otherBlock = true;
} }
redGlass.add(block.getLocation()); // Record the incorrect location
redGlass.add(v);
return false;
} else { } else {
// Normal wall blocks // Normal wall blocks
wallBlockCount++; wallBlockCount++;
checkDoorsHoppers(cc, block); return checkDoorsHoppers(cc, m, v);
} }
return true;
} }
return false; return true;
} }
void checkDoorsHoppers(CounterCheck cc, Block block) { /**
* Check the count of doors and hopper and set the hopper location if it is found
* @param cc counter check
* @param m material of block
* @param v vector position of block
* @return false if there is an error, true if ok
*/
boolean checkDoorsHoppers(CounterCheck cc, Material m, Vector v) {
// Count doors // Count doors
if (Tag.DOORS.isTagged(block.getType())) { if (Tag.DOORS.isTagged(m)) {
cc.doorCount++; cc.doorCount++;
// If we already have 8 doors add these blocks to the red list // If we already have 8 doors add these blocks to the red list
if (wallDoors == 8) { if (cc.doorCount > 8) {
redGlass.add(block.getLocation()); redGlass.add(v);
return false;
} }
} }
// Count hoppers // Count hoppers
if (block.getType().equals(Material.HOPPER)) { if (m.equals(Material.HOPPER)) {
cc.hopperCount++; cc.hopperCount++;
if (ghHopper > 0) { if (cc.hopperCount > 1) {
// Problem! Add extra hoppers to the red glass list // Problem! Add extra hoppers to the red glass list
redGlass.add(block.getLocation()); redGlass.add(v);
return false;
} else { } else {
// This is the first hopper // This is the first hopper
gh.setRoofHopperLocation(block.getLocation()); gh.setRoofHopperLocation(v);
} }
} }
return true;
} }
/** /**
@ -238,7 +235,7 @@ public class GreenhouseFinder {
/** /**
* @return the redGlass * @return the redGlass
*/ */
public Set<Location> getRedGlass() { public Set<Vector> getRedGlass() {
return redGlass; return redGlass;
} }
@ -246,35 +243,28 @@ public class GreenhouseFinder {
* @return the wallDoors * @return the wallDoors
*/ */
int getWallDoors() { int getWallDoors() {
return wallDoors; return cc.doorCount;
}
/**
* @param wallDoors the wallDoors to set
*/
void setWallDoors(int wallDoors) {
this.wallDoors = wallDoors;
} }
/** /**
* @return the ghHopper * @return the ghHopper
*/ */
int getGhHopper() { int getGhHopper() {
return ghHopper; return cc.hopperCount;
} }
/** /**
* @return the airHoles * @return the airHoles
*/ */
boolean isAirHoles() { boolean isAirHoles() {
return airHoles; return cc.airHole;
} }
/** /**
* @return the otherBlocks * @return the otherBlocks
*/ */
boolean isOtherBlocks() { boolean isOtherBlocks() {
return otherBlocks; return cc.otherBlock;
} }
/** /**
@ -298,27 +288,6 @@ public class GreenhouseFinder {
return wallBlockCount; return wallBlockCount;
} }
/**
* @param ghHopper the ghHopper to set
*/
void setGhHopper(int ghHopper) {
this.ghHopper = ghHopper;
}
/**
* @param airHoles the airHoles to set
*/
void setAirHoles(boolean airHoles) {
this.airHoles = airHoles;
}
/**
* @param otherBlocks the otherBlocks to set
*/
void setOtherBlocks(boolean otherBlocks) {
this.otherBlocks = otherBlocks;
}
/** /**
* @param inCeiling the inCeiling to set * @param inCeiling the inCeiling to set
*/ */
@ -340,4 +309,30 @@ public class GreenhouseFinder {
this.wallBlockCount = wallBlockCount; this.wallBlockCount = wallBlockCount;
} }
/**
* @param gh the gh to set
*/
protected void setGh(Greenhouse gh) {
this.gh = gh;
}
public void setGhHopper(int i) {
cc.hopperCount = i;
}
public void setWallDoors(int i) {
cc.doorCount = i;
}
public void setAirHoles(boolean b) {
cc.airHole = b;
}
public void setOtherBlocks(boolean b) {
cc.otherBlock = b;
}
} }

View File

@ -68,8 +68,8 @@ public class PanelClick implements ClickHandler {
result.getResults().forEach(r -> user.sendMessage("greenhouses.commands.user.make.error." + r.name())); result.getResults().forEach(r -> user.sendMessage("greenhouses.commands.user.make.error." + r.name()));
if (!result.getFinder().getRedGlass().isEmpty()) { if (!result.getFinder().getRedGlass().isEmpty()) {
// Show red glass // Show red glass
result.getFinder().getRedGlass().forEach(rg -> user.getPlayer().sendBlockChange(rg, Material.RED_STAINED_GLASS.createBlockData())); result.getFinder().getRedGlass().stream().map(v -> v.toLocation(user.getWorld())).forEach(rg -> user.getPlayer().sendBlockChange(rg, Material.RED_STAINED_GLASS.createBlockData()));
Bukkit.getScheduler().runTaskLater(addon.getPlugin(), () -> result.getFinder().getRedGlass().forEach(rg -> user.getPlayer().sendBlockChange(rg, rg.getBlock().getBlockData())), 120L); Bukkit.getScheduler().runTaskLater(addon.getPlugin(), () -> result.getFinder().getRedGlass().stream().map(v -> v.toLocation(user.getWorld())).forEach(rg -> user.getPlayer().sendBlockChange(rg, rg.getBlock().getBlockData())), 120L);
} }
if (result.getResults().contains(GreenhouseResult.FAIL_INSUFFICIENT_BLOCKS)) { 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)));

View File

@ -113,8 +113,8 @@ class MakeCommand extends CompositeCommand {
result.getResults().forEach(r -> user.sendMessage("greenhouses.commands.user.make.error." + r.name())); result.getResults().forEach(r -> user.sendMessage("greenhouses.commands.user.make.error." + r.name()));
if (!result.getFinder().getRedGlass().isEmpty()) { if (!result.getFinder().getRedGlass().isEmpty()) {
// Show red glass // Show red glass
result.getFinder().getRedGlass().forEach(rg -> user.getPlayer().sendBlockChange(rg, Material.RED_STAINED_GLASS.createBlockData())); result.getFinder().getRedGlass().forEach(rg -> user.getPlayer().sendBlockChange(rg.toLocation(user.getWorld()), Material.RED_STAINED_GLASS.createBlockData()));
Bukkit.getScheduler().runTaskLater(getPlugin(), () -> result.getFinder().getRedGlass().forEach(rg -> user.getPlayer().sendBlockChange(rg, rg.getBlock().getBlockData())), 120L); Bukkit.getScheduler().runTaskLater(getPlugin(), () -> result.getFinder().getRedGlass().stream().map(v -> v.toLocation(user.getWorld())).forEach(rg -> user.getPlayer().sendBlockChange(rg, rg.getBlock().getBlockData())), 120L);
} }
if (br != null && result.getResults().contains(GreenhouseResult.FAIL_INSUFFICIENT_BLOCKS)) { 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))); 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)));

View File

@ -9,6 +9,7 @@ import org.bukkit.Bukkit;
import org.bukkit.ChunkSnapshot; import org.bukkit.ChunkSnapshot;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import world.bentobox.bentobox.util.Pair; import world.bentobox.bentobox.util.Pair;
@ -34,6 +35,19 @@ public class AsyncWorldCache {
cache = new HashMap<>(); cache = new HashMap<>();
} }
/**
* @return the world's environment
*/
public Environment getEnvironment() {
return world.getEnvironment();
}
/**
* @return maximum height of this world
*/
public int getMaxHeight() {
return world.getMaxHeight();
}
/** /**
* Get chunk snapshot from world * Get chunk snapshot from world
@ -89,7 +103,6 @@ public class AsyncWorldCache {
int xx = x >= 0 ? x % 16 : (16 + (x % 16)) % 16; int xx = x >= 0 ? x % 16 : (16 + (x % 16)) % 16;
int zz = z >= 0 ? z % 16 : (16 + (z % 16)) % 16; int zz = z >= 0 ? z % 16 : (16 + (z % 16)) % 16;
Material m = getSnap(x,z).getBlockType(xx, y, zz); Material m = getSnap(x,z).getBlockType(xx, y, zz);
return m; return m;
} }
@ -102,4 +115,13 @@ public class AsyncWorldCache {
return getBlockType(v.getBlockX(), v.getBlockY(), v.getBlockZ()); return getBlockType(v.getBlockX(), v.getBlockY(), v.getBlockZ());
} }
/**
* Check if block is AIR
* @param vector - vector
* @return true if AIR
*/
public boolean isEmpty(Vector vector) {
return getBlockType(vector).equals(Material.AIR);
}
} }

View File

@ -16,6 +16,7 @@ import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.util.BoundingBox; import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -192,9 +193,11 @@ public class GreenhouseTest {
*/ */
@Test @Test
public void testSetRoofHopperLocation() { public void testSetRoofHopperLocation() {
Location l = new Location(world, 1,2,3); gh.setRoofHopperLocation(new Vector(1,2,3));
gh.setRoofHopperLocation(l); assertEquals(world, gh.getRoofHopperLocation().getWorld());
assertEquals(l, gh.getRoofHopperLocation()); assertEquals(1, gh.getRoofHopperLocation().getBlockX());
assertEquals(2, gh.getRoofHopperLocation().getBlockY());
assertEquals(3, gh.getRoofHopperLocation().getBlockZ());
} }
/** /**

View File

@ -2,7 +2,6 @@ package world.bentobox.greenhouses.managers;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
@ -10,7 +9,6 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.util.Collection; import java.util.Collection;
import java.util.Set;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -18,7 +16,7 @@ import org.bukkit.Material;
import org.bukkit.Tag; import org.bukkit.Tag;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.World.Environment; import org.bukkit.World.Environment;
import org.bukkit.block.Block; import org.bukkit.util.Vector;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -35,6 +33,7 @@ import world.bentobox.greenhouses.greenhouse.Roof;
import world.bentobox.greenhouses.greenhouse.Walls; import world.bentobox.greenhouses.greenhouse.Walls;
import world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck; import world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck;
import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult; import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult;
import world.bentobox.greenhouses.world.AsyncWorldCache;
/** /**
* @author tastybento * @author tastybento
@ -54,14 +53,15 @@ public class GreenhouseFinderTest {
private Location location; private Location location;
// Class under test // Class under test
private GreenhouseFinder gf; private GreenhouseFinder gf;
@Mock
private Block block;
private CounterCheck cc; private CounterCheck cc;
@Mock @Mock
private Roof roof; private Roof roof;
@Mock @Mock
private Walls walls; private Walls walls;
@Mock
private AsyncWorldCache cache;
/** /**
* @throws java.lang.Exception * @throws java.lang.Exception
*/ */
@ -75,13 +75,8 @@ public class GreenhouseFinderTest {
when(location.getWorld()).thenReturn(world); when(location.getWorld()).thenReturn(world);
// Block // Block
when(block.getX()).thenReturn(5); when(cache.getBlockType(any())).thenReturn(Material.GLASS);
when(block.getY()).thenReturn(14); when(cache.getBlockType(anyInt(), anyInt(), anyInt())).thenReturn(Material.GLASS);
when(block.getZ()).thenReturn(25);
when(block.getType()).thenReturn(Material.GLASS);
when(block.getLocation()).thenReturn(location);
when(block.getWorld()).thenReturn(world);
// Roof // Roof
when(roof.getHeight()).thenReturn(ROOF_HEIGHT); when(roof.getHeight()).thenReturn(ROOF_HEIGHT);
when(walls.getMinX()).thenReturn(5); when(walls.getMinX()).thenReturn(5);
@ -92,9 +87,8 @@ public class GreenhouseFinderTest {
when(roof.getLocation()).thenReturn(location); when(roof.getLocation()).thenReturn(location);
// World // World
when(world.getEnvironment()).thenReturn(Environment.NORMAL); when(cache.getEnvironment()).thenReturn(Environment.NORMAL);
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(block); when(cache.getMaxHeight()).thenReturn(30);
when(world.getMaxHeight()).thenReturn(30);
gf = new GreenhouseFinder(); gf = new GreenhouseFinder();
@ -107,7 +101,7 @@ public class GreenhouseFinderTest {
@Test @Test
public void testCheckGreenhouse() { public void testCheckGreenhouse() {
Greenhouse gh2 = new Greenhouse(world, walls, ROOF_HEIGHT); Greenhouse gh2 = new Greenhouse(world, walls, ROOF_HEIGHT);
gf.checkGreenhouse(gh2, roof, walls).thenAccept(result -> { gf.checkGreenhouse(cache, gh2, roof, walls).thenAccept(result -> {
assertTrue(result.isEmpty()); // Success assertTrue(result.isEmpty()); // Success
assertEquals(441, gf.getWallBlockCount()); assertEquals(441, gf.getWallBlockCount());
assertEquals(0, gf.getWallDoors()); assertEquals(0, gf.getWallDoors());
@ -181,151 +175,36 @@ public class GreenhouseFinderTest {
/** /**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkBlock(world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck, world.bentobox.greenhouses.greenhouse.Roof, world.bentobox.greenhouses.greenhouse.Walls, org.bukkit.block.Block)}. * Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkBlock(CounterCheck, Material, Roof, Walls, Vector)}
*/
@Test
public void testCheckBlock() {
// Block has to be > roof height
when(block.getY()).thenReturn(ROOF_HEIGHT + 1);
Set<GreenhouseResult> result = gf.checkBlock(cc, roof, walls, block);
result.forEach(gr -> assertEquals(GreenhouseResult.FAIL_BLOCKS_ABOVE, gr));
gf.getRedGlass().forEach(l -> assertEquals(location, l));
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkBlock(world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck, world.bentobox.greenhouses.greenhouse.Roof, world.bentobox.greenhouses.greenhouse.Walls, org.bukkit.block.Block)}.
*/ */
@Test @Test
public void testCheckBlockRoofHeight() { public void testCheckBlockRoofHeight() {
// Block has to be > roof height // Glass block should be ok at roof height
when(block.getY()).thenReturn(ROOF_HEIGHT); assertTrue(gf.checkBlock(cc, Material.GLASS, roof, walls, new Vector(0, ROOF_HEIGHT, 0)));
Set<GreenhouseResult> result = gf.checkBlock(cc, roof, walls, block);
assertTrue(result.isEmpty());
} }
/**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkBlock(world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck, world.bentobox.greenhouses.greenhouse.Roof, world.bentobox.greenhouses.greenhouse.Walls, org.bukkit.block.Block)}.
*/
@Test
public void testCheckBlockNether() {
when(world.getEnvironment()).thenReturn(Environment.NETHER);
// Block has to be > roof height
when(block.getY()).thenReturn(ROOF_HEIGHT + 1);
Set<GreenhouseResult> result = gf.checkBlock(cc, roof, walls, block);
assertTrue(result.isEmpty());
}
/** /**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkBlock(world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck, world.bentobox.greenhouses.greenhouse.Roof, world.bentobox.greenhouses.greenhouse.Walls, org.bukkit.block.Block)}. * Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkBlock(CounterCheck, Material, Roof, Walls, Vector)}
*/ */
@Test @Test
public void testCheckBlockAir() { public void testCheckBlockAir() {
when(block.isEmpty()).thenReturn(true); // Glass air should be not allowed at roof height
// Block has to be > roof height assertFalse(gf.checkBlock(cc, Material.AIR, roof, walls, new Vector(0, ROOF_HEIGHT, 0)));
when(block.getY()).thenReturn(ROOF_HEIGHT + 1);
Set<GreenhouseResult> result = gf.checkBlock(cc, roof, walls, block);
assertTrue(result.isEmpty());
} }
/**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkWalls(org.bukkit.block.Block, world.bentobox.greenhouses.greenhouse.Roof, world.bentobox.greenhouses.greenhouse.Walls, world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck)}.
*/
@Test
public void testCheckWallsAirHole() {
// Make block AIR
when(block.isEmpty()).thenReturn(true);
when(block.getType()).thenReturn(Material.AIR);
assertTrue(gf.checkWalls(block, roof, walls, cc));
assertFalse(gf.getRedGlass().isEmpty());
gf.getRedGlass().forEach(l -> assertEquals(location, l));
assertTrue(cc.airHole);
assertFalse(gf.isInCeiling());
}
/** /**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkWalls(org.bukkit.block.Block, world.bentobox.greenhouses.greenhouse.Roof, world.bentobox.greenhouses.greenhouse.Walls, world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck)}. * Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkDoorsHoppers(CounterCheck, Material, Vector)}
*/
@Test
public void testCheckWallsAirHoleInRoof() {
// Make block AIR
when(block.isEmpty()).thenReturn(true);
when(block.getType()).thenReturn(Material.AIR);
when(block.getY()).thenReturn(ROOF_HEIGHT);
assertTrue(gf.checkWalls(block, roof, walls, cc));
assertFalse(gf.getRedGlass().isEmpty());
gf.getRedGlass().stream().forEach(l -> assertEquals(location, l));
assertTrue(cc.airHole);
assertTrue(gf.isInCeiling());
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkWalls(org.bukkit.block.Block, world.bentobox.greenhouses.greenhouse.Roof, world.bentobox.greenhouses.greenhouse.Walls, world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck)}.
*/
@Test
public void testCheckWalls() {
// Make block GLASS
when(block.isEmpty()).thenReturn(false);
when(block.getType()).thenReturn(Material.GLASS);
assertTrue(gf.checkWalls(block, roof, walls, cc));
assertTrue(gf.getRedGlass().isEmpty());
assertFalse(cc.airHole);
assertFalse(gf.isInCeiling());
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkWalls(org.bukkit.block.Block, world.bentobox.greenhouses.greenhouse.Roof, world.bentobox.greenhouses.greenhouse.Walls, world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck)}.
*/
@Test
public void testCheckWallsInRoof() {
// Make block GLASS
when(block.isEmpty()).thenReturn(false);
when(block.getType()).thenReturn(Material.GLASS);
when(block.getY()).thenReturn(ROOF_HEIGHT);
assertTrue(gf.checkWalls(block, roof, walls, cc));
assertTrue(gf.getRedGlass().isEmpty());
assertFalse(cc.airHole);
assertFalse(gf.isInCeiling());
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkWalls(org.bukkit.block.Block, world.bentobox.greenhouses.greenhouse.Roof, world.bentobox.greenhouses.greenhouse.Walls, world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck)}.
*/
@Test
public void testCheckWallsNotInWall() {
when(block.getX()).thenReturn(0);
when(block.getY()).thenReturn(0);
when(block.getZ()).thenReturn(0);
// Make block GLASS
when(block.isEmpty()).thenReturn(false);
when(block.getType()).thenReturn(Material.GLASS);
assertFalse(gf.checkWalls(block, roof, walls, cc));
assertTrue(gf.getRedGlass().isEmpty());
assertFalse(cc.airHole);
assertFalse(gf.isInCeiling());
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkDoorsHoppers(world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck, org.bukkit.block.Block)}.
*/ */
@Test @Test
public void testCheckDoorsHoppers() { public void testCheckDoorsHoppers() {
when(Tag.DOORS.isTagged(any(Material.class))).thenReturn(true); when(Tag.DOORS.isTagged(any(Material.class))).thenReturn(true);
when(block.getType()).thenReturn(Material.ACACIA_DOOR); for (int i = 0; i < 8; i++) {
gf.checkDoorsHoppers(cc, block); assertTrue("Door number " + i, gf.checkDoorsHoppers(cc, Material.ACACIA_DOOR, new Vector(0,0,0)));
assertTrue(gf.getRedGlass().isEmpty()); }
} // 9th door will fail
assertFalse(gf.checkDoorsHoppers(cc, Material.ACACIA_DOOR, new Vector(0,0,0)));
/**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkDoorsHoppers(world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck, org.bukkit.block.Block)}.
*/
@Test
public void testCheckDoorsHoppersTooManyDoors() {
gf.setWallDoors(8);
when(Tag.DOORS.isTagged(any(Material.class))).thenReturn(true);
when(block.getType()).thenReturn(Material.ACACIA_DOOR);
CounterCheck cc = gf.new CounterCheck();
gf.checkDoorsHoppers(cc, block);
assertFalse(gf.getRedGlass().isEmpty());
} }
/** /**
@ -333,36 +212,26 @@ public class GreenhouseFinderTest {
*/ */
@Test @Test
public void testCheckDoorsHoppersHopper() { public void testCheckDoorsHoppersHopper() {
Greenhouse gh = new Greenhouse(world, walls, 10);
// Set the greenhouse so the world is known
gf.setGh(gh);
when(Tag.DOORS.isTagged(any(Material.class))).thenReturn(false); when(Tag.DOORS.isTagged(any(Material.class))).thenReturn(false);
when(block.getType()).thenReturn(Material.HOPPER);
when(block.getLocation()).thenReturn(location);
CounterCheck cc = gf.new CounterCheck(); CounterCheck cc = gf.new CounterCheck();
gf.checkDoorsHoppers(cc, block); assertTrue(gf.checkDoorsHoppers(cc, Material.HOPPER, new Vector(5,14,25)));
assertTrue(gf.getRedGlass().isEmpty()); assertTrue(gf.getRedGlass().isEmpty());
assertEquals(location, gf.getGh().getRoofHopperLocation()); assertEquals(5, gf.getGh().getRoofHopperLocation().getBlockX());
assertEquals(14, gf.getGh().getRoofHopperLocation().getBlockY());
assertEquals(25, gf.getGh().getRoofHopperLocation().getBlockZ());
assertFalse(gf.checkDoorsHoppers(cc, Material.HOPPER, new Vector(5,14,25)));
} }
/**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkDoorsHoppers(world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck, org.bukkit.block.Block)}.
*/
@Test
public void testCheckDoorsHoppersTooManyHoppers() {
gf.setGhHopper(3);
when(Tag.DOORS.isTagged(any(Material.class))).thenReturn(false);
when(block.getType()).thenReturn(Material.HOPPER);
when(block.getLocation()).thenReturn(location);
CounterCheck cc = gf.new CounterCheck();
gf.checkDoorsHoppers(cc, block);
assertFalse(gf.getRedGlass().isEmpty());
assertNull(gf.getGh().getRoofHopperLocation());
}
/** /**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#getGh()}. * Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#getGh()}.
*/ */
@Test @Test
public void testGetGh() { public void testGetGh() {
assertNotNull(gf.getGh()); assertNull(gf.getGh());
} }
/** /**