2019-01-19 16:52:04 +01:00
|
|
|
package world.bentobox.greenhouses.greenhouse;
|
|
|
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.List;
|
2021-01-16 23:27:29 +01:00
|
|
|
import java.util.Objects;
|
|
|
|
import java.util.Optional;
|
2021-01-16 18:16:09 +01:00
|
|
|
import java.util.concurrent.CompletableFuture;
|
2019-01-19 16:52:04 +01:00
|
|
|
|
2021-01-16 18:16:09 +01:00
|
|
|
import org.bukkit.Bukkit;
|
2019-01-19 16:52:04 +01:00
|
|
|
import org.bukkit.Location;
|
|
|
|
import org.bukkit.Material;
|
2021-02-04 02:40:42 +01:00
|
|
|
import org.bukkit.Tag;
|
2019-01-19 16:52:04 +01:00
|
|
|
import org.bukkit.World;
|
|
|
|
import org.bukkit.util.Vector;
|
2021-01-16 23:27:29 +01:00
|
|
|
import org.eclipse.jdt.annotation.NonNull;
|
2019-01-19 16:52:04 +01:00
|
|
|
|
2021-01-16 18:16:09 +01:00
|
|
|
import world.bentobox.bentobox.BentoBox;
|
2020-08-23 00:52:18 +02:00
|
|
|
import world.bentobox.greenhouses.Greenhouses;
|
2021-01-16 18:16:09 +01:00
|
|
|
import world.bentobox.greenhouses.world.AsyncWorldCache;
|
2020-08-23 00:52:18 +02:00
|
|
|
|
2019-01-19 16:52:04 +01:00
|
|
|
/**
|
|
|
|
* Contains the parameters of a greenhouse roof
|
|
|
|
* @author tastybento
|
|
|
|
*
|
|
|
|
*/
|
2021-09-25 20:34:36 +02:00
|
|
|
@SuppressWarnings("deprecation")
|
2019-11-01 05:51:24 +01:00
|
|
|
public class Roof extends MinMaxXZ {
|
2020-08-23 00:52:18 +02:00
|
|
|
private static final List<Material> ROOF_BLOCKS;
|
2019-11-23 05:58:32 +01:00
|
|
|
static {
|
2021-08-01 08:10:07 +02:00
|
|
|
// Roof blocks
|
|
|
|
ROOF_BLOCKS = Arrays.stream(Material.values())
|
2021-09-25 20:34:36 +02:00
|
|
|
.filter(m -> !m.isLegacy())
|
2019-11-01 05:36:05 +01:00
|
|
|
.filter(Material::isBlock) // Blocks only, no items
|
2021-02-04 02:40:42 +01:00
|
|
|
.filter(m -> Tag.TRAPDOORS.isTagged(m) // All trapdoors
|
2021-01-10 19:51:35 +01:00
|
|
|
|| (m.name().contains("GLASS") && !m.name().contains("GLASS_PANE")) // All glass blocks
|
2021-08-01 08:10:07 +02:00
|
|
|
|| m.equals(Material.HOPPER)).toList();
|
2019-11-01 05:36:05 +01:00
|
|
|
}
|
2021-01-16 18:16:09 +01:00
|
|
|
/**
|
|
|
|
* Check if material is a roof material
|
|
|
|
* @param m - material
|
|
|
|
* @return true if roof material
|
|
|
|
*/
|
2021-01-16 23:27:29 +01:00
|
|
|
public static boolean roofBlocks(@NonNull Material m) {
|
|
|
|
return ROOF_BLOCKS.contains(Objects.requireNonNull(m))
|
2021-01-16 18:16:09 +01:00
|
|
|
|| (m.equals(Material.GLOWSTONE) && Greenhouses.getInstance().getSettings().isAllowGlowstone())
|
|
|
|
|| (m.name().endsWith("GLASS_PANE") && Greenhouses.getInstance().getSettings().isAllowPanes());
|
|
|
|
}
|
|
|
|
private final AsyncWorldCache cache;
|
2019-11-23 05:58:32 +01:00
|
|
|
private int height;
|
2021-01-16 18:16:09 +01:00
|
|
|
private final Location location;
|
2019-11-23 05:58:32 +01:00
|
|
|
private boolean roofFound;
|
2019-11-01 05:36:05 +01:00
|
|
|
|
2021-01-16 18:16:09 +01:00
|
|
|
private final World world;
|
|
|
|
|
|
|
|
|
2019-01-19 16:52:04 +01:00
|
|
|
/**
|
|
|
|
* Finds a roof from a starting location under the roof and characterizes it
|
2021-08-01 08:10:07 +02:00
|
|
|
* @param cache async world cache
|
2019-01-26 17:38:13 +01:00
|
|
|
* @param loc - starting location
|
2019-01-19 16:52:04 +01:00
|
|
|
*/
|
2021-01-16 18:16:09 +01:00
|
|
|
public Roof(AsyncWorldCache cache, Location loc) {
|
|
|
|
this.cache = cache;
|
2019-01-22 00:44:01 +01:00
|
|
|
this.location = loc;
|
2021-01-16 18:16:09 +01:00
|
|
|
this.world = loc.getWorld();
|
2019-11-12 20:38:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-16 18:16:09 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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();
|
2019-01-19 16:52:04 +01:00
|
|
|
// 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
|
2021-01-16 23:27:29 +01:00
|
|
|
Bukkit.getScheduler().runTaskAsynchronously(BentoBox.getInstance(), () -> {
|
2021-01-16 18:16:09 +01:00
|
|
|
boolean found = findRoof(loc);
|
2021-01-16 23:27:29 +01:00
|
|
|
Bukkit.getScheduler().runTask(BentoBox.getInstance(), () -> r.complete(found));
|
2021-01-16 18:16:09 +01:00
|
|
|
});
|
|
|
|
return r;
|
|
|
|
}
|
2019-11-23 06:23:42 +01:00
|
|
|
|
2021-01-16 23:27:29 +01:00
|
|
|
boolean findRoof(Vector loc) {
|
2019-11-23 06:23:42 +01:00
|
|
|
// This does a ever-growing check around the player to find a wall block. It is possible for the player
|
2019-01-26 17:38:13 +01:00
|
|
|
// to be outside the greenhouse in this situation, so a check is done later to make sure the player is inside
|
2021-01-16 23:27:29 +01:00
|
|
|
int startY = loc.getBlockY();
|
|
|
|
for (int y = startY; y < world.getMaxHeight(); y++) {
|
|
|
|
Vector v = new Vector(loc.getBlockX(),y,loc.getBlockZ());
|
|
|
|
if (roofBlocks(cache.getBlockType(v))) {
|
2019-11-23 06:23:42 +01:00
|
|
|
roofFound = true;
|
2021-01-16 23:27:29 +01:00
|
|
|
loc = v;
|
2019-11-23 06:23:42 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-01-19 16:52:04 +01:00
|
|
|
// 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
|
2021-01-16 18:16:09 +01:00
|
|
|
if (!roofFound) {
|
2021-01-16 23:27:29 +01:00
|
|
|
loc = spiralSearch(loc, startY);
|
|
|
|
if (!roofFound) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-01-16 18:16:09 +01:00
|
|
|
}
|
2019-01-19 16:52:04 +01:00
|
|
|
// Record the height
|
|
|
|
this.height = loc.getBlockY();
|
|
|
|
// Now we have a roof block, find how far we can go NSWE
|
|
|
|
minX = loc.getBlockX();
|
|
|
|
maxX = loc.getBlockX();
|
|
|
|
minZ = loc.getBlockZ();
|
|
|
|
maxZ = loc.getBlockZ();
|
2021-01-16 18:16:09 +01:00
|
|
|
expandCoords(loc);
|
2019-01-26 17:38:13 +01:00
|
|
|
int minx;
|
|
|
|
int maxx;
|
|
|
|
int minz;
|
|
|
|
int maxz;
|
2019-01-19 16:52:04 +01:00
|
|
|
// Now we have some idea of the mins and maxes, check each block and see if it goes further
|
|
|
|
do {
|
|
|
|
minx = minX;
|
|
|
|
maxx = maxX;
|
|
|
|
minz = minZ;
|
|
|
|
maxz = maxZ;
|
|
|
|
for (int x = minx; x <= maxx; x++) {
|
|
|
|
for (int z = minz; z <= maxz; z++) {
|
|
|
|
// This will push out the coords if possible
|
2021-01-16 18:16:09 +01:00
|
|
|
expandCoords(new Vector(x, loc.getBlockY(), z));
|
2019-01-19 16:52:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Repeat until nothing changes
|
|
|
|
} while (minx != minX || maxx != maxX || minz != minZ || maxz != maxZ);
|
|
|
|
// That's as much as we can do!
|
2019-11-12 20:38:17 +01:00
|
|
|
return true;
|
2019-01-19 16:52:04 +01:00
|
|
|
}
|
|
|
|
|
2021-01-16 18:16:09 +01:00
|
|
|
/**
|
|
|
|
* @return the height
|
|
|
|
*/
|
|
|
|
public int getHeight() {
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the location
|
|
|
|
*/
|
|
|
|
public Location getLocation() {
|
|
|
|
return location;
|
|
|
|
}
|
|
|
|
|
2021-01-16 23:27:29 +01:00
|
|
|
private Vector spiralSearch(Vector v, int startY) {
|
|
|
|
for (int radius = 0; radius < 3; radius++) {
|
|
|
|
for (int x = v.getBlockX() - radius; x <= v.getBlockX() + radius; x++) {
|
|
|
|
for (int z = v.getBlockZ() - radius; z <= v.getBlockZ() + radius; z++) {
|
2021-01-16 18:16:09 +01:00
|
|
|
if (!((x > v.getBlockX() - radius && x < v.getBlockX() + radius) && (z > v.getBlockZ() - radius && z < v.getBlockZ() + radius))) {
|
2021-01-16 23:27:29 +01:00
|
|
|
Optional<Vector> r = checkVertically(x, startY, z);
|
|
|
|
if (r.isPresent()) {
|
|
|
|
return r.get();
|
|
|
|
}
|
2020-10-11 17:08:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-16 23:27:29 +01:00
|
|
|
return v;
|
2020-10-11 17:08:17 +02:00
|
|
|
}
|
|
|
|
|
2021-01-16 18:16:09 +01:00
|
|
|
/**
|
|
|
|
* Get highest roof block
|
|
|
|
* @param x - x coord of current search
|
2021-01-16 23:27:29 +01:00
|
|
|
* @param startY - starting y coord
|
2021-01-16 18:16:09 +01:00
|
|
|
* @param z - z coord of current search
|
|
|
|
*/
|
2021-01-16 23:27:29 +01:00
|
|
|
private Optional<Vector> checkVertically(final int x, final int startY, final int z) {
|
|
|
|
if (!Walls.wallBlocks(cache.getBlockType(x, startY, z))) {
|
2020-10-11 17:08:17 +02:00
|
|
|
// Look up
|
2021-01-16 23:27:29 +01:00
|
|
|
for (int y = startY; y < world.getMaxHeight() && !roofFound; y++) {
|
2021-01-16 18:16:09 +01:00
|
|
|
if (roofBlocks(cache.getBlockType(x,y,z))) {
|
2021-01-16 23:27:29 +01:00
|
|
|
|
2020-10-11 17:08:17 +02:00
|
|
|
roofFound = true;
|
2021-01-16 23:27:29 +01:00
|
|
|
// Roof block found
|
|
|
|
return Optional.of(new Vector(x,y,z));
|
2020-10-11 17:08:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-16 23:27:29 +01:00
|
|
|
return Optional.empty();
|
2020-10-11 17:08:17 +02:00
|
|
|
}
|
|
|
|
|
2019-01-22 00:44:01 +01:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
2021-01-16 23:27:29 +01:00
|
|
|
return "Roof [height=" + height + ", roofFound=" + roofFound + ", minX=" + minX + ", maxX=" + maxX + ", minZ="
|
|
|
|
+ minZ + ", maxZ=" + maxZ + "]";
|
2019-01-19 16:52:04 +01:00
|
|
|
}
|
2021-01-16 18:16:09 +01:00
|
|
|
|
2021-01-16 23:27:29 +01:00
|
|
|
|
2019-01-19 16:52:04 +01:00
|
|
|
}
|