Greenhouses/src/main/java/world/bentobox/greenhouses/managers/GreenhouseManager.java

313 lines
11 KiB
Java
Raw Normal View History

2019-01-22 00:44:01 +01:00
package world.bentobox.greenhouses.managers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
2021-01-16 18:16:09 +01:00
import java.util.concurrent.CompletableFuture;
2021-01-17 18:35:06 +01:00
import java.util.stream.Collectors;
2019-01-22 00:44:01 +01:00
import org.bukkit.Location;
2020-11-16 00:02:13 +01:00
import org.bukkit.block.Biome;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
2021-12-31 22:32:03 +01:00
import org.bukkit.util.BoundingBox;
2019-01-22 00:44:01 +01:00
import world.bentobox.bentobox.api.events.BentoBoxReadyEvent;
2019-01-22 00:44:01 +01:00
import world.bentobox.bentobox.database.Database;
import world.bentobox.bentobox.database.objects.Island;
2019-01-22 00:44:01 +01:00
import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.data.Greenhouse;
import world.bentobox.greenhouses.greenhouse.BiomeRecipe;
import world.bentobox.greenhouses.listeners.GreenhouseEvents;
import world.bentobox.greenhouses.listeners.GreenhouseGuard;
import world.bentobox.greenhouses.listeners.IslandChangeEvents;
import world.bentobox.greenhouses.listeners.SnowTracker;
2019-01-22 00:44:01 +01:00
public class GreenhouseManager implements Listener {
2019-01-22 00:44:01 +01:00
2019-01-22 02:53:34 +01:00
/**
* Result of greenhouse making
*
*/
2019-01-22 00:44:01 +01:00
public enum GreenhouseResult {
FAIL_NO_ROOF,
FAIL_BELOW,
FAIL_BLOCKS_ABOVE,
FAIL_HOLE_IN_WALL,
FAIL_HOLE_IN_ROOF,
FAIL_UNEVEN_WALLS,
FAIL_BAD_ROOF_BLOCKS,
FAIL_BAD_WALL_BLOCKS,
FAIL_TOO_MANY_DOORS,
FAIL_TOO_MANY_HOPPERS,
FAIL_NO_WATER,
FAIL_NO_LAVA,
FAIL_NO_ICE,
FAIL_INSUFFICIENT_WATER,
FAIL_INSUFFICIENT_LAVA,
2019-01-22 02:53:34 +01:00
FAIL_INSUFFICIENT_ICE,
FAIL_NO_ISLAND,
FAIL_OVERLAPPING,
NULL,
SUCCESS,
FAIL_NO_RECIPE_FOUND,
2020-11-16 00:02:13 +01:00
FAIL_INSUFFICIENT_BLOCKS,
FAIL_NO_WORLD, FAIL_UNKNOWN_RECIPE
2019-01-22 00:44:01 +01:00
}
2019-01-26 17:38:13 +01:00
private final Greenhouses addon;
2019-01-22 00:44:01 +01:00
// Greenhouses
2019-01-26 17:38:13 +01:00
private final GreenhouseMap map;
private final Database<Greenhouse> handler;
2019-07-08 00:45:47 +02:00
private EcoSystemManager ecoMgr;
2019-01-22 00:44:01 +01:00
public GreenhouseManager(Greenhouses addon) {
this.addon = addon;
handler = new Database<>(addon, Greenhouse.class);
map = new GreenhouseMap(addon);
}
@EventHandler
public void startManager(BentoBoxReadyEvent e) {
2019-01-22 00:44:01 +01:00
loadGreenhouses();
// Start ecosystems
2019-07-08 00:45:47 +02:00
ecoMgr = new EcoSystemManager(addon, this);
ecoMgr.setup();
// Register listeners
addon.registerListener(new SnowTracker(addon));
addon.registerListener(new GreenhouseEvents(addon));
addon.registerListener(new GreenhouseGuard(addon));
addon.registerListener(new IslandChangeEvents(addon));
2019-01-22 00:44:01 +01:00
}
public GreenhouseMap getMap() {
return map;
}
/**
* Load all known greenhouses
*/
2019-01-26 17:38:13 +01:00
private void loadGreenhouses() {
2019-07-08 00:45:47 +02:00
map.clear();
2019-01-22 00:44:01 +01:00
addon.log("Loading greenhouses...");
List<Greenhouse> toBeRemoved = new ArrayList<>();
2019-01-22 00:44:01 +01:00
handler.loadObjects().forEach(g -> {
2019-01-22 02:53:34 +01:00
GreenhouseResult result = map.addGreenhouse(g);
2019-01-22 00:44:01 +01:00
switch (result) {
2022-12-29 20:33:34 +01:00
case FAIL_NO_ISLAND ->
// Delete the failed greenhouse
toBeRemoved.add(g);
case FAIL_OVERLAPPING -> addon.logError("Greenhouse overlaps with another greenhouse. Skipping...");
case NULL -> addon.logError("Null location of greenhouse. Cannot load. Skipping...");
case SUCCESS -> activateGreenhouse(g);
case FAIL_NO_WORLD -> addon.logError("Database contains greenhouse for a non-loaded world. Skipping...");
case FAIL_UNKNOWN_RECIPE -> {
addon.logError("Greenhouse uses a recipe that does not exist in the biomes.yml. Skipping...");
addon.logError("Greenhouse Id " + g.getUniqueId());
}
default -> {
}
2019-01-22 00:44:01 +01:00
}
});
addon.log("Loaded " + map.getSize() + " greenhouses.");
// Remove the old or outdated greenhouses
toBeRemoved.forEach(handler::deleteObject);
2019-01-22 00:44:01 +01:00
}
/**
* Removes the greenhouse from the world and resets biomes
2021-12-31 22:32:03 +01:00
* @param gh - greenhouse
2019-01-22 00:44:01 +01:00
*/
2021-12-31 22:32:03 +01:00
public void removeGreenhouse(Greenhouse gh) {
handler.deleteObject(gh);
map.removeGreenhouse(gh);
if (gh.getOriginalBiome() == null) {
addon.logError("Greenhouse had no original biome: " + gh.getLocation());
2021-08-02 01:17:12 +02:00
return;
}
2021-12-31 22:32:03 +01:00
if (gh.getLocation() == null || gh.getLocation().getWorld() == null) {
2021-08-02 01:17:12 +02:00
// Greenhouse is messed up. It's being deleted anyway.
return;
}
2021-12-31 22:32:03 +01:00
addon.log("Returning biome to original state: " + gh.getOriginalBiome().toString());
final BoundingBox bb = gh.getBoundingBox();
for (int x = (int)bb.getMinX(); x<= (int)bb.getMaxX(); x+=4) {
for (int z = (int)bb.getMinZ(); z<= (int)bb.getMaxZ(); z+=4) {
for (int y = (int)bb.getMinY(); y<= (int)bb.getMaxY(); y+=4) {
// Set back to the original biome
2021-12-31 22:32:03 +01:00
gh.getLocation().getWorld().setBiome(x, y, z, gh.getOriginalBiome());
2019-01-22 00:44:01 +01:00
}
}
}
}
/**
* Checks that a greenhouse meets specs and makes it
* If type is stated then only this specific type will be checked
2019-01-26 17:38:13 +01:00
* @param location - location to start search from
* @param greenhouseRecipe - recipe requested, or null for a best-effort search
2021-01-16 18:16:09 +01:00
* @return - future greenhouse result {@link GhResult}
2019-01-22 00:44:01 +01:00
*/
2021-01-16 18:16:09 +01:00
public CompletableFuture<GhResult> tryToMakeGreenhouse(Location location, BiomeRecipe greenhouseRecipe) {
CompletableFuture<GhResult> r = new CompletableFuture<>();
2019-01-22 00:44:01 +01:00
GreenhouseFinder finder = new GreenhouseFinder();
2021-01-16 18:16:09 +01:00
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(finder, greenhouseRecipe, resultSet).thenAccept(r::complete);
2021-01-16 18:16:09 +01:00
return;
2019-01-22 00:44:01 +01:00
}
2021-01-16 18:16:09 +01:00
// Try ordered recipes
2021-01-17 18:35:06 +01:00
findRecipe(finder).thenAccept(rs -> {
resultSet.addAll(rs);
r.complete(new GhResult().setFinder(finder).setResults(resultSet));
});
2021-01-16 18:16:09 +01:00
});
return r;
}
/**
* Tries to match the greenhouse to a recipe by going through all of them in order
* @param finder - finder object
*/
2021-01-17 18:35:06 +01:00
private CompletableFuture<Set<GreenhouseResult>> findRecipe(GreenhouseFinder finder) {
CompletableFuture<Set<GreenhouseResult>> r = new CompletableFuture<>();
// Get sorted list of all recipes
List<BiomeRecipe> list = addon.getRecipes().getBiomeRecipes().stream().sorted().collect(Collectors.toList());
findRecipe(r, list, finder);
return r;
}
private void findRecipe(CompletableFuture<Set<GreenhouseResult>> r, List<BiomeRecipe> list,
GreenhouseFinder finder) {
if (list.isEmpty()) {
r.complete(Collections.singleton(GreenhouseResult.FAIL_NO_RECIPE_FOUND));
return;
}
BiomeRecipe br = list.get(0);
list.remove(0);
br.checkRecipe(finder.getGh()).thenAccept(results -> {
if (results.isEmpty()) {
r.complete(Collections.singleton(GreenhouseResult.SUCCESS));
2021-01-17 18:35:06 +01:00
} else {
findRecipe(r, list, finder);
2021-01-17 18:35:06 +01:00
}
});
2021-01-16 18:16:09 +01:00
}
/**
* Checks to see if the greenhouse meets the designated recipe and returns the result
* @param finder - finder object
* @param greenhouseRecipe - recipe requested
* @param resultSet - result set from finder
* @return Greenhouse result
*/
CompletableFuture<GhResult> checkRecipe(GreenhouseFinder finder, BiomeRecipe greenhouseRecipe, Set<GreenhouseResult> resultSet) {
CompletableFuture<GhResult> r = new CompletableFuture<>();
greenhouseRecipe.checkRecipe(finder.getGh()).thenAccept(rs -> {
if (rs.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());
rs.addAll(resultSet);
}
GhResult recipe = new GhResult().setFinder(finder).setResults(rs);
r.complete(recipe);
});
return r;
2019-01-22 00:44:01 +01:00
}
private void activateGreenhouse(Greenhouse gh) {
2020-11-16 00:02:13 +01:00
Biome ghBiome = gh.getBiomeRecipe().getBiome();
if (ghBiome == null) {
addon.logError("Biome recipe error - no such biome for " + gh.getBiomeRecipe().getName());
return;
}
2021-12-31 22:32:03 +01:00
final BoundingBox bb = gh.getBoundingBox();
for (int x = (int)bb.getMinX(); x < bb.getMaxX(); x+=4) {
for (int z = (int)bb.getMinZ(); z < bb.getMaxZ(); z+=4) {
for (int y = (int)bb.getMinY(); y < bb.getMaxY(); y+=4) {
2021-09-18 19:33:48 +02:00
Objects.requireNonNull(gh.getWorld()).setBiome(x, y, z, ghBiome);
}
}
}
}
2019-01-22 00:44:01 +01:00
/**
* Result of the greenhouse make effort
*
*/
2021-09-18 19:33:48 +02:00
public static class GhResult {
2019-01-22 00:44:01 +01:00
private Set<GreenhouseResult> results;
private GreenhouseFinder finder;
/**
* @return the results
*/
public Set<GreenhouseResult> getResults() {
return results;
}
/**
* @return the finder
*/
public GreenhouseFinder getFinder() {
return finder;
}
/**
* @param results the results to set
*/
2019-01-26 17:38:13 +01:00
GhResult setResults(Set<GreenhouseResult> results) {
2019-01-22 00:44:01 +01:00
this.results = results;
return this;
}
/**
* @param finder the finder to set
*/
2019-01-26 17:38:13 +01:00
GhResult setFinder(GreenhouseFinder finder) {
2019-01-22 00:44:01 +01:00
this.finder = finder;
return this;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "GhResult [results=" + results + ", finder=" + finder + "]";
}
2019-01-22 00:44:01 +01:00
}
2019-07-08 00:45:47 +02:00
/**
* @return the ecoMgr
*/
public EcoSystemManager getEcoMgr() {
return ecoMgr;
}
/**
* Removes all greenhouses on island
* @param island - island
*/
public void removeGreenhouses(Island island) {
map.getGreenhouses(island).forEach(handler::deleteObject);
map.removeGreenhouses(island);
}
2019-01-22 00:44:01 +01:00
}