Skip to content

Commit

Permalink
Made roof search async
Browse files Browse the repository at this point in the history
  • Loading branch information
tastybento committed Jan 16, 2021
1 parent 08e9c25 commit cc11402
Show file tree
Hide file tree
Showing 10 changed files with 362 additions and 171 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,11 @@ public int getMaxZ() {
public int getArea() {
return (maxX - minX) * (maxZ - minZ);
}

@Override
public String toString() {
return "MinMaxXZ [minX=" + minX + ", maxX=" + maxX + ", minZ=" + minZ + ", maxZ=" + maxZ + "]";
}


}
230 changes: 124 additions & 106 deletions src/main/java/world/bentobox/greenhouses/greenhouse/Roof.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,26 @@
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
* @author tastybento
*
*/
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())
Expand All @@ -29,48 +33,119 @@ 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
minX = loc.getBlockX();
maxX = loc.getBlockX();
minZ = loc.getBlockZ();
maxZ = loc.getBlockZ();
expandCoords(world, loc.toVector());
expandCoords(loc);
int minx;
int maxx;
int minz;
Expand All @@ -84,7 +159,7 @@ private boolean findRoof(Location loc) {
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
Expand All @@ -93,119 +168,62 @@ private boolean findRoof(Location loc) {
return true;
}

private void spiralSearch(Location loc, int roofY) {
/**
* @return the height
*/
public int getHeight() {
return height;
}


/**
* @return the location
*/
public Location getLocation() {
return location;
}

private void spiralSearch(Vector v, 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);
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);
}
}
}
}

}

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())) {
/**
* 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(world.getBlockAt(x,y,z).getType())) {
if (roofBlocks(cache.getBlockType(x,y,z))) {
roofFound = true;
loc = new Location(world,x,y,z);
// Move roof up because there is a higher block
v = new Vector(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
*/
public int getHeight() {
return height;
}

/**
* @return the location
*/
public Location getLocation() {
return location;
}


/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@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 + "]";
}

}
10 changes: 8 additions & 2 deletions src/main/java/world/bentobox/greenhouses/greenhouse/Walls.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
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;
Expand Down Expand Up @@ -43,7 +44,12 @@ boolean isSearching() {
}
}

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();
Expand All @@ -65,7 +71,7 @@ public Walls findWalls(Roof roof) {
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) {
Expand Down

0 comments on commit cc11402

Please sign in to comment.