2019-01-22 00:44:01 +01:00
|
|
|
package world.bentobox.greenhouses.managers;
|
|
|
|
|
2020-10-05 01:32:34 +02:00
|
|
|
import java.util.Collection;
|
2019-01-22 00:44:01 +01:00
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.Set;
|
2021-01-16 18:16:09 +01:00
|
|
|
import java.util.concurrent.CompletableFuture;
|
2019-01-22 00:44:01 +01:00
|
|
|
|
2021-01-17 03:57:01 +01:00
|
|
|
import org.bukkit.Bukkit;
|
2019-01-22 00:44:01 +01:00
|
|
|
import org.bukkit.Location;
|
|
|
|
import org.bukkit.Material;
|
2020-10-05 01:32:34 +02:00
|
|
|
import org.bukkit.Tag;
|
2021-01-17 03:57:01 +01:00
|
|
|
import org.bukkit.util.Vector;
|
2019-01-22 00:44:01 +01:00
|
|
|
|
2021-01-17 03:57:01 +01:00
|
|
|
import world.bentobox.bentobox.BentoBox;
|
2019-01-22 00:44:01 +01:00
|
|
|
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;
|
2021-01-16 18:16:09 +01:00
|
|
|
import world.bentobox.greenhouses.world.AsyncWorldCache;
|
2019-01-22 00:44:01 +01:00
|
|
|
|
|
|
|
public class GreenhouseFinder {
|
|
|
|
|
2021-01-17 03:57:01 +01:00
|
|
|
private Greenhouse gh;
|
|
|
|
private final Set<Vector> redGlass = new HashSet<>();
|
2020-10-05 01:32:34 +02:00
|
|
|
// Ceiling issue
|
|
|
|
private boolean inCeiling = false;
|
|
|
|
// The y height where other blocks were found
|
|
|
|
// If this is the bottom layer, the player has most likely uneven walls
|
|
|
|
private int otherBlockLayer = -1;
|
|
|
|
private int wallBlockCount;
|
2021-01-17 03:57:01 +01:00
|
|
|
/**
|
|
|
|
* This is the count of the various items
|
|
|
|
*/
|
|
|
|
private CounterCheck cc = new CounterCheck();
|
2019-01-22 00:44:01 +01:00
|
|
|
|
2020-10-05 01:32:34 +02:00
|
|
|
class CounterCheck {
|
|
|
|
int doorCount;
|
|
|
|
int hopperCount;
|
|
|
|
boolean airHole;
|
|
|
|
boolean otherBlock;
|
|
|
|
}
|
2019-01-22 00:44:01 +01:00
|
|
|
|
2020-08-23 00:52:18 +02:00
|
|
|
/**
|
|
|
|
* Find out if there is a greenhouse here
|
|
|
|
* @param location - start location
|
2021-01-16 18:16:09 +01:00
|
|
|
* @return future GreenhouseResult class
|
2020-08-23 00:52:18 +02:00
|
|
|
*/
|
2021-01-16 18:16:09 +01:00
|
|
|
public CompletableFuture<Set<GreenhouseResult>> find(Location location) {
|
|
|
|
CompletableFuture<Set<GreenhouseResult>> r = new CompletableFuture<>();
|
2019-01-22 00:44:01 +01:00
|
|
|
Set<GreenhouseResult> result = new HashSet<>();
|
|
|
|
redGlass.clear();
|
|
|
|
|
2021-01-16 18:16:09 +01:00
|
|
|
// Get a world cache
|
|
|
|
AsyncWorldCache cache = new AsyncWorldCache(location.getWorld());
|
2019-01-22 00:44:01 +01:00
|
|
|
// Find the roof
|
2021-01-16 18:16:09 +01:00
|
|
|
Roof roof = new Roof(cache, location);
|
|
|
|
roof.findRoof().thenAccept(found -> {
|
2021-01-17 20:42:54 +01:00
|
|
|
if (Boolean.FALSE.equals(found)) {
|
2021-01-16 18:16:09 +01:00
|
|
|
result.add(GreenhouseResult.FAIL_NO_ROOF);
|
|
|
|
r.complete(result);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Find the walls
|
2021-01-16 23:27:29 +01:00
|
|
|
new Walls(cache).findWalls(roof).thenAccept(walls -> {
|
2021-01-16 18:16:09 +01:00
|
|
|
// Make the initial greenhouse
|
|
|
|
gh = new Greenhouse(location.getWorld(), walls, roof.getHeight());
|
|
|
|
// Set the original biome
|
|
|
|
gh.setOriginalBiome(location.getBlock().getBiome());
|
2019-01-22 00:44:01 +01:00
|
|
|
|
2021-01-16 18:16:09 +01:00
|
|
|
// Now check to see if the floor really is the floor and the walls follow the rules
|
2021-01-17 20:42:54 +01:00
|
|
|
checkGreenhouse(cache, roof, walls).thenAccept(c -> {
|
2021-01-16 18:16:09 +01:00
|
|
|
result.addAll(c);
|
|
|
|
r.complete(result);
|
|
|
|
});
|
|
|
|
});
|
2020-10-05 01:32:34 +02:00
|
|
|
|
2021-01-16 18:16:09 +01:00
|
|
|
});
|
|
|
|
return r;
|
2020-10-05 01:32:34 +02:00
|
|
|
}
|
2019-01-22 00:44:01 +01:00
|
|
|
|
2021-01-16 18:16:09 +01:00
|
|
|
/**
|
|
|
|
* Check the greenhouse has the right number of everything
|
2021-01-17 03:57:01 +01:00
|
|
|
* @param cache
|
2021-01-16 18:16:09 +01:00
|
|
|
* @param gh2 - greenhouse
|
|
|
|
* @param roof - roof object
|
|
|
|
* @param walls - walls object
|
|
|
|
* @return future set of Greenhouse Results
|
|
|
|
*/
|
2021-01-17 20:42:54 +01:00
|
|
|
CompletableFuture<Set<GreenhouseResult>> checkGreenhouse(AsyncWorldCache cache, Roof roof, Walls walls) {
|
2021-01-17 03:57:01 +01:00
|
|
|
CompletableFuture<Set<GreenhouseResult>> r = new CompletableFuture<>();
|
2021-01-17 20:42:54 +01:00
|
|
|
Bukkit.getScheduler().runTaskAsynchronously(BentoBox.getInstance(), () -> checkGHAsync(r, cache, roof, walls));
|
2021-01-17 03:57:01 +01:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2021-01-17 20:42:54 +01:00
|
|
|
private Set<GreenhouseResult> checkGHAsync(CompletableFuture<Set<GreenhouseResult>> r, AsyncWorldCache cache,
|
2021-01-17 03:57:01 +01:00
|
|
|
Roof roof, Walls walls) {
|
2020-10-05 01:32:34 +02:00
|
|
|
Set<GreenhouseResult> result = new HashSet<>();
|
2021-01-17 03:57:01 +01:00
|
|
|
cc = new CounterCheck();
|
2019-01-26 17:38:13 +01:00
|
|
|
int y;
|
2021-01-17 03:57:01 +01:00
|
|
|
for (y = roof.getHeight(); y > walls.getFloor(); y--) {
|
2019-01-22 00:44:01 +01:00
|
|
|
wallBlockCount = 0;
|
2020-10-05 01:32:34 +02:00
|
|
|
for (int x = walls.getMinX(); x <= walls.getMaxX(); x++) {
|
|
|
|
for (int z = walls.getMinZ(); z <= walls.getMaxZ(); z++) {
|
2021-01-17 03:57:01 +01:00
|
|
|
checkBlock(cc, cache.getBlockType(x,y,z), roof, walls, new Vector(x, y, z));
|
2019-01-22 00:44:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (wallBlockCount == 0 && y < roof.getHeight()) {
|
|
|
|
// This is the floor
|
|
|
|
break;
|
|
|
|
} else {
|
2020-10-05 01:32:34 +02:00
|
|
|
if (cc.otherBlock) {
|
2019-01-22 00:44:01 +01:00
|
|
|
if (otherBlockLayer < 0) {
|
|
|
|
otherBlockLayer = y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-05 01:32:34 +02:00
|
|
|
|
|
|
|
result.addAll(checkErrors(roof, y));
|
2021-01-17 03:57:01 +01:00
|
|
|
Bukkit.getScheduler().runTask(BentoBox.getInstance(), () -> r.complete(result));
|
|
|
|
return result;
|
2020-10-05 01:32:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Collection<GreenhouseResult> checkErrors(Roof roof, int y) {
|
|
|
|
Set<GreenhouseResult> result = new HashSet<>();
|
2019-01-22 00:44:01 +01:00
|
|
|
// Check that the player is vertically in the greenhouse
|
|
|
|
if (roof.getLocation().getBlockY() <= y) {
|
|
|
|
result.add(GreenhouseResult.FAIL_BELOW);
|
|
|
|
}
|
|
|
|
// Show errors
|
2021-01-17 03:57:01 +01:00
|
|
|
if (isAirHoles() && !inCeiling) {
|
2019-01-22 00:44:01 +01:00
|
|
|
result.add(GreenhouseResult.FAIL_HOLE_IN_WALL);
|
2021-01-17 03:57:01 +01:00
|
|
|
} else if (isAirHoles() && inCeiling) {
|
2019-01-22 00:44:01 +01:00
|
|
|
result.add(GreenhouseResult.FAIL_HOLE_IN_ROOF);
|
|
|
|
}
|
2021-01-17 03:57:01 +01:00
|
|
|
if (isOtherBlocks() && otherBlockLayer == y + 1) {
|
2019-01-22 00:44:01 +01:00
|
|
|
// Walls must be even all the way around
|
|
|
|
result.add(GreenhouseResult.FAIL_UNEVEN_WALLS);
|
2021-01-17 03:57:01 +01:00
|
|
|
} else if (isOtherBlocks() && otherBlockLayer == roof.getHeight()) {
|
2019-01-22 00:44:01 +01:00
|
|
|
// Roof blocks must be glass, glowstone, doors or a hopper.
|
|
|
|
result.add(GreenhouseResult.FAIL_BAD_ROOF_BLOCKS);
|
2021-01-17 03:57:01 +01:00
|
|
|
} else if (isOtherBlocks()) {
|
2019-01-22 00:44:01 +01:00
|
|
|
// "Wall blocks must be glass, glowstone, doors or a hopper.
|
|
|
|
result.add(GreenhouseResult.FAIL_BAD_WALL_BLOCKS);
|
|
|
|
}
|
2021-01-17 03:57:01 +01:00
|
|
|
if (this.getWallDoors() > 8) {
|
2019-01-22 00:44:01 +01:00
|
|
|
result.add(GreenhouseResult.FAIL_TOO_MANY_DOORS);
|
|
|
|
}
|
2021-01-17 03:57:01 +01:00
|
|
|
if (this.getGhHopper() > 1) {
|
2019-01-22 00:44:01 +01:00
|
|
|
result.add(GreenhouseResult.FAIL_TOO_MANY_HOPPERS);
|
|
|
|
}
|
2020-10-05 01:32:34 +02:00
|
|
|
return result;
|
|
|
|
}
|
2019-01-22 00:44:01 +01:00
|
|
|
|
2020-10-05 01:32:34 +02:00
|
|
|
/**
|
2021-01-17 03:57:01 +01:00
|
|
|
* Check if block is allowed to be in that location
|
|
|
|
* @param cc - Counter Check object
|
|
|
|
* @param m - material of the block
|
2020-10-05 01:32:34 +02:00
|
|
|
* @param roof - roof object
|
2021-01-17 03:57:01 +01:00
|
|
|
* @param walls - walls object
|
|
|
|
* @param v - vector location of the block
|
|
|
|
* @return true if block is acceptable, false if not
|
2020-10-05 01:32:34 +02:00
|
|
|
*/
|
2021-01-17 03:57:01 +01:00
|
|
|
boolean checkBlock(CounterCheck cc, Material m, Roof roof, Walls walls, Vector v) {
|
|
|
|
final int x = v.getBlockX();
|
|
|
|
final int y = v.getBlockY();
|
|
|
|
final int z = v.getBlockZ();
|
2020-10-05 01:32:34 +02:00
|
|
|
// Check wall blocks only
|
|
|
|
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
|
2021-01-17 03:57:01 +01:00
|
|
|
if ((y != roof.getHeight() && !Walls.wallBlocks(m)) || (y == roof.getHeight() && !Roof.roofBlocks(m))) {
|
|
|
|
if (m.equals(Material.AIR)) {
|
|
|
|
// Air hole found
|
2020-10-05 01:32:34 +02:00
|
|
|
cc.airHole = true;
|
|
|
|
if (y == roof.getHeight()) {
|
2021-01-17 03:57:01 +01:00
|
|
|
// Air hole is in ceiling
|
2020-10-05 01:32:34 +02:00
|
|
|
inCeiling = true;
|
|
|
|
}
|
|
|
|
} else {
|
2021-01-17 03:57:01 +01:00
|
|
|
// A non-wall or roof block found
|
2020-10-05 01:32:34 +02:00
|
|
|
cc.otherBlock = true;
|
|
|
|
}
|
2021-01-17 03:57:01 +01:00
|
|
|
// Record the incorrect location
|
|
|
|
redGlass.add(v);
|
|
|
|
return false;
|
2020-10-05 01:32:34 +02:00
|
|
|
} else {
|
|
|
|
// Normal wall blocks
|
|
|
|
wallBlockCount++;
|
2021-01-17 03:57:01 +01:00
|
|
|
return checkDoorsHoppers(cc, m, v);
|
2020-10-05 01:32:34 +02:00
|
|
|
}
|
|
|
|
}
|
2021-01-17 03:57:01 +01:00
|
|
|
return true;
|
2020-10-05 01:32:34 +02:00
|
|
|
}
|
|
|
|
|
2021-01-17 03:57:01 +01:00
|
|
|
/**
|
|
|
|
* 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) {
|
2020-10-05 01:32:34 +02:00
|
|
|
// Count doors
|
2021-01-17 03:57:01 +01:00
|
|
|
if (Tag.DOORS.isTagged(m)) {
|
2020-10-05 01:32:34 +02:00
|
|
|
cc.doorCount++;
|
2021-01-17 03:57:01 +01:00
|
|
|
|
2020-10-05 01:32:34 +02:00
|
|
|
// If we already have 8 doors add these blocks to the red list
|
2021-01-17 03:57:01 +01:00
|
|
|
if (cc.doorCount > 8) {
|
|
|
|
redGlass.add(v);
|
|
|
|
return false;
|
2020-10-05 01:32:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Count hoppers
|
2021-01-17 03:57:01 +01:00
|
|
|
if (m.equals(Material.HOPPER)) {
|
2020-10-05 01:32:34 +02:00
|
|
|
cc.hopperCount++;
|
2021-01-17 03:57:01 +01:00
|
|
|
if (cc.hopperCount > 1) {
|
2020-10-05 01:32:34 +02:00
|
|
|
// Problem! Add extra hoppers to the red glass list
|
2021-01-17 03:57:01 +01:00
|
|
|
redGlass.add(v);
|
|
|
|
return false;
|
2020-10-05 01:32:34 +02:00
|
|
|
} else {
|
|
|
|
// This is the first hopper
|
2021-01-17 03:57:01 +01:00
|
|
|
gh.setRoofHopperLocation(v);
|
2020-10-05 01:32:34 +02:00
|
|
|
}
|
|
|
|
}
|
2021-01-17 03:57:01 +01:00
|
|
|
return true;
|
2020-10-05 01:32:34 +02:00
|
|
|
}
|
|
|
|
|
2019-01-22 00:44:01 +01:00
|
|
|
/**
|
2019-01-23 05:54:43 +01:00
|
|
|
* @return the greenhouse
|
2019-01-22 00:44:01 +01:00
|
|
|
*/
|
|
|
|
public Greenhouse getGh() {
|
|
|
|
return gh;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the redGlass
|
|
|
|
*/
|
2021-01-17 03:57:01 +01:00
|
|
|
public Set<Vector> getRedGlass() {
|
2019-01-22 00:44:01 +01:00
|
|
|
return redGlass;
|
|
|
|
}
|
|
|
|
|
2020-10-05 01:32:34 +02:00
|
|
|
/**
|
|
|
|
* @return the wallDoors
|
|
|
|
*/
|
|
|
|
int getWallDoors() {
|
2021-01-17 03:57:01 +01:00
|
|
|
return cc.doorCount;
|
2020-10-05 01:32:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the ghHopper
|
|
|
|
*/
|
|
|
|
int getGhHopper() {
|
2021-01-17 03:57:01 +01:00
|
|
|
return cc.hopperCount;
|
2020-10-05 01:32:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the airHoles
|
|
|
|
*/
|
|
|
|
boolean isAirHoles() {
|
2021-01-17 03:57:01 +01:00
|
|
|
return cc.airHole;
|
2020-10-05 01:32:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the otherBlocks
|
|
|
|
*/
|
|
|
|
boolean isOtherBlocks() {
|
2021-01-17 03:57:01 +01:00
|
|
|
return cc.otherBlock;
|
2020-10-05 01:32:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the inCeiling
|
|
|
|
*/
|
|
|
|
boolean isInCeiling() {
|
|
|
|
return inCeiling;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the otherBlockLayer
|
|
|
|
*/
|
|
|
|
int getOtherBlockLayer() {
|
|
|
|
return otherBlockLayer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the wallBlockCount
|
|
|
|
*/
|
|
|
|
int getWallBlockCount() {
|
|
|
|
return wallBlockCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param inCeiling the inCeiling to set
|
|
|
|
*/
|
|
|
|
void setInCeiling(boolean inCeiling) {
|
|
|
|
this.inCeiling = inCeiling;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param otherBlockLayer the otherBlockLayer to set
|
|
|
|
*/
|
|
|
|
void setOtherBlockLayer(int otherBlockLayer) {
|
|
|
|
this.otherBlockLayer = otherBlockLayer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param wallBlockCount the wallBlockCount to set
|
|
|
|
*/
|
|
|
|
void setWallBlockCount(int wallBlockCount) {
|
|
|
|
this.wallBlockCount = wallBlockCount;
|
|
|
|
}
|
|
|
|
|
2021-01-17 03:57:01 +01:00
|
|
|
/**
|
|
|
|
* @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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-01-22 00:44:01 +01:00
|
|
|
}
|