Merge branch 'develop'
This commit is contained in:
commit
fe0a794e68
|
@ -14,10 +14,10 @@ jobs:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||||
- name: Set up JDK 16
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@v1
|
uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 16
|
java-version: 17
|
||||||
- name: Cache SonarCloud packages
|
- name: Cache SonarCloud packages
|
||||||
uses: actions/cache@v1
|
uses: actions/cache@v1
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
/target/
|
/target/
|
||||||
/.classpath
|
/.classpath
|
||||||
/.project
|
/.project
|
||||||
|
/.DS_Store
|
||||||
|
/Greenhouses-addon.iml
|
||||||
|
/.idea/
|
||||||
|
|
6
pom.xml
6
pom.xml
|
@ -43,11 +43,11 @@
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<java.version>16</java.version>
|
<java.version>17</java.version>
|
||||||
<powermock.version>2.0.9</powermock.version>
|
<powermock.version>2.0.9</powermock.version>
|
||||||
<!-- More visible way how to change dependency versions -->
|
<!-- More visible way how to change dependency versions -->
|
||||||
<spigot.version>1.18.1-R0.1-SNAPSHOT</spigot.version>
|
<spigot.version>1.19.3-R0.1-SNAPSHOT</spigot.version>
|
||||||
<bentobox.version>1.18.1</bentobox.version>
|
<bentobox.version>1.21.0</bentobox.version>
|
||||||
<!-- Revision variable removes warning about dynamic version -->
|
<!-- Revision variable removes warning about dynamic version -->
|
||||||
<revision>${build.version}-SNAPSHOT</revision>
|
<revision>${build.version}-SNAPSHOT</revision>
|
||||||
<!-- This allows to change between versions and snapshots. -->
|
<!-- This allows to change between versions and snapshots. -->
|
||||||
|
|
|
@ -2,6 +2,7 @@ package world.bentobox.greenhouses.greenhouse;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -24,6 +25,8 @@ import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.BlockFace;
|
import org.bukkit.block.BlockFace;
|
||||||
import org.bukkit.block.data.Bisected;
|
import org.bukkit.block.data.Bisected;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.block.data.Waterlogged;
|
||||||
|
import org.bukkit.block.data.type.GlowLichen;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.EntityType;
|
import org.bukkit.entity.EntityType;
|
||||||
import org.bukkit.entity.Hoglin;
|
import org.bukkit.entity.Hoglin;
|
||||||
|
@ -34,6 +37,7 @@ import com.google.common.base.Enums;
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
|
import world.bentobox.bentobox.BentoBox;
|
||||||
import world.bentobox.bentobox.util.Util;
|
import world.bentobox.bentobox.util.Util;
|
||||||
import world.bentobox.greenhouses.Greenhouses;
|
import world.bentobox.greenhouses.Greenhouses;
|
||||||
import world.bentobox.greenhouses.data.Greenhouse;
|
import world.bentobox.greenhouses.data.Greenhouse;
|
||||||
|
@ -60,12 +64,26 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final List<BlockFace> ADJ_BLOCKS = Arrays.asList( BlockFace.DOWN, BlockFace.EAST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP, BlockFace.WEST);
|
private static final List<BlockFace> ADJ_BLOCKS = Arrays.asList( BlockFace.DOWN, BlockFace.EAST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP, BlockFace.WEST);
|
||||||
|
private static final List<Material> UNDERWATER_PLANTS;
|
||||||
|
static {
|
||||||
|
List<Material> m = new ArrayList<>();
|
||||||
|
Arrays.stream(Material.values()).filter(c -> c.name().contains("CORAL")).forEach(m::add);
|
||||||
|
m.add(Material.SEA_LANTERN);
|
||||||
|
m.add(Material.SEA_PICKLE);
|
||||||
|
m.add(Material.SEAGRASS);
|
||||||
|
m.add(Material.KELP);
|
||||||
|
m.add(Material.GLOW_LICHEN);
|
||||||
|
UNDERWATER_PLANTS = Collections.unmodifiableList(m);
|
||||||
|
}
|
||||||
|
|
||||||
// Content requirements
|
// Content requirements
|
||||||
// Material, Type, Qty. There can be more than one type of material required
|
// Material, Type, Qty. There can be more than one type of material required
|
||||||
private final Map<Material, Integer> requiredBlocks = new EnumMap<>(Material.class);
|
private final Map<Material, Integer> requiredBlocks = new EnumMap<>(Material.class);
|
||||||
// Plants
|
/**
|
||||||
|
* Tree map of plants
|
||||||
|
*/
|
||||||
private final TreeMap<Double, GreenhousePlant> plantTree = new TreeMap<>();
|
private final TreeMap<Double, GreenhousePlant> plantTree = new TreeMap<>();
|
||||||
|
private final TreeMap<Double, GreenhousePlant> underwaterPlants = new TreeMap<>();
|
||||||
|
|
||||||
// Mobs
|
// Mobs
|
||||||
// Entity Type, Material to Spawn on, Probability
|
// Entity Type, Material to Spawn on, Probability
|
||||||
|
@ -148,11 +166,12 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
|
||||||
*/
|
*/
|
||||||
public boolean addPlants(Material plantMaterial, double plantProbability, Material plantGrowOn) {
|
public boolean addPlants(Material plantMaterial, double plantProbability, Material plantGrowOn) {
|
||||||
double probability = plantProbability/100;
|
double probability = plantProbability/100;
|
||||||
|
TreeMap<Double, GreenhousePlant> map = UNDERWATER_PLANTS.contains(plantMaterial) ? underwaterPlants : plantTree;
|
||||||
// Add up all the probabilities in the list so far
|
// Add up all the probabilities in the list so far
|
||||||
double lastProb = plantTree.isEmpty() ? 0D : plantTree.lastKey();
|
double lastProb = map.isEmpty() ? 0D : map.lastKey();
|
||||||
if ((1D - lastProb) >= probability) {
|
if ((1D - lastProb) >= probability) {
|
||||||
// Add to probability tree
|
// Add to probability tree
|
||||||
plantTree.put(lastProb + probability, new GreenhousePlant(plantMaterial, plantGrowOn));
|
map.put(lastProb + probability, new GreenhousePlant(plantMaterial, plantGrowOn));
|
||||||
} else {
|
} else {
|
||||||
addon.logError("Plant chances add up to > 100% in " + type.toString() + " biome recipe! Skipping " + plantMaterial.toString());
|
addon.logError("Plant chances add up to > 100% in " + type.toString() + " biome recipe! Skipping " + plantMaterial.toString());
|
||||||
return false;
|
return false;
|
||||||
|
@ -357,7 +376,9 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
|
||||||
Location spawnLoc = b.getLocation().clone().add(new Vector(0.5, 0, 0.5));
|
Location spawnLoc = b.getLocation().clone().add(new Vector(0.5, 0, 0.5));
|
||||||
return getRandomMob()
|
return getRandomMob()
|
||||||
// Check if the spawn on block matches, if it exists
|
// Check if the spawn on block matches, if it exists
|
||||||
.filter(m -> Optional.of(m.mobSpawnOn()).map(b.getRelative(BlockFace.DOWN).getType()::equals).orElse(true))
|
.filter(m -> Optional.of(m.mobSpawnOn())
|
||||||
|
.map(b.getRelative(BlockFace.DOWN).getType()::equals)
|
||||||
|
.orElse(true))
|
||||||
// If spawn occurs, check if it can fit inside greenhouse
|
// If spawn occurs, check if it can fit inside greenhouse
|
||||||
.map(m -> {
|
.map(m -> {
|
||||||
Entity entity = b.getWorld().spawnEntity(spawnLoc, m.mobType());
|
Entity entity = b.getWorld().spawnEntity(spawnLoc, m.mobType());
|
||||||
|
@ -408,11 +429,11 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
|
||||||
return key == null ? Optional.empty() : Optional.ofNullable(mobTree.get(key));
|
return key == null ? Optional.empty() : Optional.ofNullable(mobTree.get(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<GreenhousePlant> getRandomPlant() {
|
private Optional<GreenhousePlant> getRandomPlant(boolean underwater) {
|
||||||
// Grow a random plant that can grow
|
// Grow a random plant that can grow
|
||||||
double r = random.nextDouble();
|
double r = random.nextDouble();
|
||||||
Double key = plantTree.ceilingKey(r);
|
Double key = underwater ? underwaterPlants.ceilingKey(r) : plantTree.ceilingKey(r);
|
||||||
return key == null ? Optional.empty() : Optional.ofNullable(plantTree.get(key));
|
return key == null ? Optional.empty() : Optional.ofNullable(underwater ? underwaterPlants.get(key) : plantTree.get(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -432,28 +453,34 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
|
||||||
/**
|
/**
|
||||||
* Plants a plant on block bl if it makes sense.
|
* Plants a plant on block bl if it makes sense.
|
||||||
* @param block - block that can have growth
|
* @param block - block that can have growth
|
||||||
|
* @param underwater - if the block is underwater or not
|
||||||
* @return true if successful
|
* @return true if successful
|
||||||
*/
|
*/
|
||||||
public boolean growPlant(GrowthBlock block) {
|
public boolean growPlant(GrowthBlock block, boolean underwater) {
|
||||||
Block bl = block.block();
|
Block bl = block.block();
|
||||||
if (!bl.isEmpty()) {
|
return getRandomPlant(underwater).map(p -> {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return getRandomPlant().map(p -> {
|
|
||||||
if (bl.getY() != 0 && canGrowOn(block, p)) {
|
if (bl.getY() != 0 && canGrowOn(block, p)) {
|
||||||
if (!isBisected(bl, p)) {
|
if (plantIt(bl, p)) {
|
||||||
return false;
|
bl.getWorld().spawnParticle(Particle.SNOWBALL, bl.getLocation(), 10, 2, 2, 2);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
bl.getWorld().spawnParticle(Particle.SNOWBALL, bl.getLocation(), 10, 2, 2, 2);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}).orElse(false);
|
}).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isBisected(Block bl, GreenhousePlant p) {
|
/**
|
||||||
|
* Plants the plant
|
||||||
|
* @param bl - block to turn into a plant
|
||||||
|
* @param p - the greenhouse plant to be grown
|
||||||
|
* @return true if successful, false if not
|
||||||
|
*/
|
||||||
|
private boolean plantIt(Block bl, GreenhousePlant p) {
|
||||||
|
boolean underwater = bl.getType().equals(Material.WATER);
|
||||||
BlockData dataBottom = p.plantMaterial().createBlockData();
|
BlockData dataBottom = p.plantMaterial().createBlockData();
|
||||||
|
// Check if this is a double-height plant
|
||||||
if (dataBottom instanceof Bisected bi) {
|
if (dataBottom instanceof Bisected bi) {
|
||||||
|
// Double-height plant
|
||||||
bi.setHalf(Bisected.Half.BOTTOM);
|
bi.setHalf(Bisected.Half.BOTTOM);
|
||||||
BlockData dataTop = p.plantMaterial().createBlockData();
|
BlockData dataTop = p.plantMaterial().createBlockData();
|
||||||
((Bisected) dataTop).setHalf(Bisected.Half.TOP);
|
((Bisected) dataTop).setHalf(Bisected.Half.TOP);
|
||||||
|
@ -463,18 +490,92 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
|
||||||
} else {
|
} else {
|
||||||
return false; // No room
|
return false; // No room
|
||||||
}
|
}
|
||||||
|
} else if (p.plantMaterial().equals(Material.GLOW_LICHEN)) {
|
||||||
|
return placeLichen(bl);
|
||||||
} else {
|
} else {
|
||||||
bl.setBlockData(dataBottom, false);
|
if (dataBottom instanceof Waterlogged wl) {
|
||||||
|
wl.setWaterlogged(underwater);
|
||||||
|
bl.setBlockData(wl, false);
|
||||||
|
} else {
|
||||||
|
// Single height plant
|
||||||
|
bl.setBlockData(dataBottom, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the placing of Glow Lichen. This needs to stick to a block rather than grow on it.
|
||||||
|
* If the block is set to Glow Lichen then it appears as an air block with 6 sides of lichen so
|
||||||
|
* they need to be switched off and only the side next to the block should be set.
|
||||||
|
* @param bl - block where plants would usually be placed
|
||||||
|
* @return true if successful, false if not
|
||||||
|
*/
|
||||||
|
private boolean placeLichen(Block bl) {
|
||||||
|
// Get the source block below this one
|
||||||
|
Block b = bl.getRelative(BlockFace.DOWN);
|
||||||
|
|
||||||
|
// Find a spot for licen
|
||||||
|
BlockFace d = null;
|
||||||
|
boolean waterLogged = false;
|
||||||
|
for (BlockFace adj : ADJ_BLOCKS) {
|
||||||
|
if (b.getRelative(adj).getType().equals(Material.AIR)) {
|
||||||
|
d = adj;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Lichen can grow under water too
|
||||||
|
if (b.getRelative(adj).getType().equals(Material.WATER)) {
|
||||||
|
d = adj;
|
||||||
|
waterLogged = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Block bb = b.getRelative(d);
|
||||||
|
bb.setType(Material.GLOW_LICHEN);
|
||||||
|
BlockFace opp = d.getOppositeFace();
|
||||||
|
|
||||||
|
if(bb.getBlockData() instanceof GlowLichen v){
|
||||||
|
for (BlockFace f : v.getAllowedFaces()) {
|
||||||
|
v.setFace(f, false);
|
||||||
|
}
|
||||||
|
v.setFace(opp, true);
|
||||||
|
v.setWaterlogged(waterLogged);
|
||||||
|
bb.setBlockData(v);
|
||||||
|
bb.getState().setBlockData(v);
|
||||||
|
bb.getState().update(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a particular plant can group at the location of a block
|
||||||
|
* @param block - block being checked
|
||||||
|
* @param p - greenhouse plant
|
||||||
|
* @return true if it can be grown otherwise false
|
||||||
|
*/
|
||||||
private boolean canGrowOn(GrowthBlock block, GreenhousePlant p) {
|
private boolean canGrowOn(GrowthBlock block, GreenhousePlant p) {
|
||||||
// Ceiling plants can only grow on ceiling blocks
|
// Ceiling plants can only grow on ceiling blocks
|
||||||
if (CEILING_PLANTS.contains(p.plantMaterial()) && Boolean.TRUE.equals(block.floor())) {
|
if (CEILING_PLANTS.contains(p.plantMaterial()) && Boolean.TRUE.equals(block.floor())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return p.plantGrownOn().equals(block.block().getRelative(Boolean.TRUE.equals(block.floor()) ? BlockFace.DOWN : BlockFace.UP).getType());
|
// Underwater plants can only be placed in water and regular plants cannot be placed in water
|
||||||
|
if (block.block().getType().equals(Material.WATER)) {
|
||||||
|
BentoBox.getInstance().logDebug("Water block");
|
||||||
|
if (!UNDERWATER_PLANTS.contains(p.plantMaterial())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BentoBox.getInstance().logDebug("Water plant");
|
||||||
|
} else if (UNDERWATER_PLANTS.contains(p.plantMaterial())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.plantGrownOn().equals(block.block().getRelative(Boolean.TRUE.equals(block.floor()) ?
|
||||||
|
BlockFace.DOWN :
|
||||||
|
BlockFace.UP).getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -69,7 +69,7 @@ public class Walls extends MinMaxXZ {
|
||||||
// The player is under the roof
|
// The player is under the roof
|
||||||
// Assume the player is inside the greenhouse they are trying to create
|
// Assume the player is inside the greenhouse they are trying to create
|
||||||
final Location loc = roof.getLocation();
|
final Location loc = roof.getLocation();
|
||||||
floor = getFloorY(roof.getHeight(), roof.getMinX(), roof.getMaxX(), roof.getMinZ(), roof.getMaxZ());
|
floor = getFloorY(roof.getHeight(), roof.getMinX(), roof.getMaxX(), roof.getMinZ(), roof.getMaxZ(), loc.getWorld().getMinHeight());
|
||||||
// Now start with the player's x and z location
|
// Now start with the player's x and z location
|
||||||
WallFinder wf = new WallFinder();
|
WallFinder wf = new WallFinder();
|
||||||
minX = loc.getBlockX();
|
minX = loc.getBlockX();
|
||||||
|
@ -85,7 +85,7 @@ public class Walls extends MinMaxXZ {
|
||||||
minZ--;
|
minZ--;
|
||||||
maxZ++;
|
maxZ++;
|
||||||
// Find the floor again, only looking within the walls
|
// Find the floor again, only looking within the walls
|
||||||
floor = getFloorY(roof.getHeight(), minX, maxX, minZ,maxZ);
|
floor = getFloorY(roof.getHeight(), minX, maxX, minZ,maxZ,loc.getWorld().getMinHeight());
|
||||||
// Complete on main thread
|
// Complete on main thread
|
||||||
Bukkit.getScheduler().runTask(BentoBox.getInstance(), () -> r.complete(this));
|
Bukkit.getScheduler().runTask(BentoBox.getInstance(), () -> r.complete(this));
|
||||||
return this;
|
return this;
|
||||||
|
@ -159,7 +159,7 @@ public class Walls extends MinMaxXZ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int getFloorY(int y, int minX, int maxX, int minZ, int maxZ) {
|
int getFloorY(int y, int minX, int maxX, int minZ, int maxZ, int minY) {
|
||||||
// Find the floor - defined as the last y under the roof where there are no wall blocks
|
// Find the floor - defined as the last y under the roof where there are no wall blocks
|
||||||
int wallBlockCount;
|
int wallBlockCount;
|
||||||
do {
|
do {
|
||||||
|
@ -172,7 +172,7 @@ public class Walls extends MinMaxXZ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} while( y-- > 0 && wallBlockCount > 0);
|
} while( y-- > minY && wallBlockCount > 0);
|
||||||
return y + 1;
|
return y + 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,9 +183,13 @@ public class EcoSystemManager {
|
||||||
int bonemeal = getBoneMeal(gh);
|
int bonemeal = getBoneMeal(gh);
|
||||||
if (bonemeal > 0) {
|
if (bonemeal > 0) {
|
||||||
// Get a list of all available blocks
|
// Get a list of all available blocks
|
||||||
List<GrowthBlock> list = getAvailableBlocks(gh, true);
|
List<GrowthBlock> list = getAvailableBlocks(gh, false);
|
||||||
Collections.shuffle(list);
|
Collections.shuffle(list);
|
||||||
int plantsGrown = list.stream().limit(bonemeal).mapToInt(bl -> gh.getBiomeRecipe().growPlant(bl) ? 1 : 0).sum();
|
int plantsGrown = list.stream().limit(bonemeal).mapToInt(bl -> gh.getBiomeRecipe().growPlant(bl, false) ? 1 : 0).sum();
|
||||||
|
// Underwater plants
|
||||||
|
list = getAvailableBlocks(gh, true);
|
||||||
|
Collections.shuffle(list);
|
||||||
|
plantsGrown += list.stream().limit(bonemeal).mapToInt(bl -> gh.getBiomeRecipe().growPlant(bl, true) ? 1 : 0).sum();
|
||||||
if (plantsGrown > 0) {
|
if (plantsGrown > 0) {
|
||||||
setBoneMeal(gh, bonemeal - (int)Math.ceil((double)plantsGrown / PLANTS_PER_BONEMEAL ));
|
setBoneMeal(gh, bonemeal - (int)Math.ceil((double)plantsGrown / PLANTS_PER_BONEMEAL ));
|
||||||
}
|
}
|
||||||
|
@ -208,6 +212,7 @@ public class EcoSystemManager {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record GrowthBlock(Block block, Boolean floor) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of the lowest level blocks inside the greenhouse. May be air, liquid or plants.
|
* Get a list of the lowest level blocks inside the greenhouse. May be air, liquid or plants.
|
||||||
|
@ -225,26 +230,31 @@ public class EcoSystemManager {
|
||||||
for (double z = ibb.getMinZ(); z < ibb.getMaxZ(); z++) {
|
for (double z = ibb.getMinZ(); z < ibb.getMaxZ(); z++) {
|
||||||
for (double y = ibb.getMaxY() - 1; y >= bb.getMinY(); y--) {
|
for (double y = ibb.getMaxY() - 1; y >= bb.getMinY(); y--) {
|
||||||
Block b = gh.getWorld().getBlockAt(NumberConversions.floor(x), NumberConversions.floor(y), NumberConversions.floor(z));
|
Block b = gh.getWorld().getBlockAt(NumberConversions.floor(x), NumberConversions.floor(y), NumberConversions.floor(z));
|
||||||
// Check ceiling blocks
|
|
||||||
if (b.isEmpty() && !b.getRelative(BlockFace.UP).isEmpty()) {
|
|
||||||
result.add(new GrowthBlock(b, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check floor blocks
|
// Check floor blocks
|
||||||
if (!(b.isEmpty() || (ignoreLiquid && b.isLiquid()))
|
if (!ignoreLiquid) {
|
||||||
&& (b.getRelative(BlockFace.UP).isEmpty()
|
// Check ceiling blocks
|
||||||
|| (b.getRelative(BlockFace.UP).isPassable() && !b.isLiquid())
|
if (b.isEmpty() && !b.getRelative(BlockFace.UP).isEmpty()) {
|
||||||
|| (ignoreLiquid && b.isLiquid() && b.getRelative(BlockFace.UP).isPassable()))) {
|
result.add(new GrowthBlock(b, false));
|
||||||
result.add(new GrowthBlock(b.getRelative(BlockFace.UP), true));
|
}
|
||||||
break;
|
if (!b.isEmpty() && (b.getRelative(BlockFace.UP).isEmpty() || b.getRelative(BlockFace.UP).isPassable())) {
|
||||||
|
result.add(new GrowthBlock(b.getRelative(BlockFace.UP), true));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!b.isEmpty() && !b.isLiquid() && b.getRelative(BlockFace.UP).isLiquid()) {
|
||||||
|
result.add(new GrowthBlock(b.getRelative(BlockFace.UP), true));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public record GrowthBlock(Block block, Boolean floor) {}
|
|
||||||
|
|
||||||
private int getBoneMeal(Greenhouse gh) {
|
private int getBoneMeal(Greenhouse gh) {
|
||||||
Hopper hopper = getHopper(gh);
|
Hopper hopper = getHopper(gh);
|
||||||
|
|
|
@ -96,29 +96,19 @@ public class GreenhouseManager implements Listener {
|
||||||
handler.loadObjects().forEach(g -> {
|
handler.loadObjects().forEach(g -> {
|
||||||
GreenhouseResult result = map.addGreenhouse(g);
|
GreenhouseResult result = map.addGreenhouse(g);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case FAIL_NO_ISLAND:
|
case FAIL_NO_ISLAND ->
|
||||||
// Delete the failed greenhouse
|
// Delete the failed greenhouse
|
||||||
toBeRemoved.add(g);
|
toBeRemoved.add(g);
|
||||||
break;
|
case FAIL_OVERLAPPING -> addon.logError("Greenhouse overlaps with another greenhouse. Skipping...");
|
||||||
case FAIL_OVERLAPPING:
|
case NULL -> addon.logError("Null location of greenhouse. Cannot load. Skipping...");
|
||||||
addon.logError("Greenhouse overlaps with another greenhouse. Skipping...");
|
case SUCCESS -> activateGreenhouse(g);
|
||||||
break;
|
case FAIL_NO_WORLD -> addon.logError("Database contains greenhouse for a non-loaded world. Skipping...");
|
||||||
case NULL:
|
case FAIL_UNKNOWN_RECIPE -> {
|
||||||
addon.logError("Null location of greenhouse. Cannot load. Skipping...");
|
addon.logError("Greenhouse uses a recipe that does not exist in the biomes.yml. Skipping...");
|
||||||
break;
|
addon.logError("Greenhouse Id " + g.getUniqueId());
|
||||||
case SUCCESS:
|
}
|
||||||
activateGreenhouse(g);
|
default -> {
|
||||||
break;
|
}
|
||||||
case FAIL_NO_WORLD:
|
|
||||||
addon.logError("Database contains greenhouse for a non-loaded world. Skipping...");
|
|
||||||
break;
|
|
||||||
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());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
addon.log("Loaded " + map.getSize() + " greenhouses.");
|
addon.log("Loaded " + map.getSize() + " greenhouses.");
|
||||||
|
|
|
@ -107,7 +107,9 @@ public class GreenhouseMap {
|
||||||
private boolean isOverlapping(Greenhouse greenhouse) {
|
private boolean isOverlapping(Greenhouse greenhouse) {
|
||||||
return greenhouse.getLocation() != null && addon.getIslands().getIslandAt(greenhouse.getLocation()).map(i -> {
|
return greenhouse.getLocation() != null && addon.getIslands().getIslandAt(greenhouse.getLocation()).map(i -> {
|
||||||
greenhouses.putIfAbsent(i, new ArrayList<>());
|
greenhouses.putIfAbsent(i, new ArrayList<>());
|
||||||
return greenhouses.get(i).stream().anyMatch(g -> g.getBoundingBox().overlaps(greenhouse.getBoundingBox()));
|
return greenhouses.get(i).stream().anyMatch(g ->
|
||||||
|
g.getLocation().getWorld().equals(greenhouse.getLocation().getWorld()) &&
|
||||||
|
g.getBoundingBox().overlaps(greenhouse.getBoundingBox()));
|
||||||
}).orElse(false);
|
}).orElse(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
package world.bentobox.greenhouses.managers;
|
package world.bentobox.greenhouses.managers;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
|
|
|
@ -285,3 +285,22 @@ biomes:
|
||||||
mobs:
|
mobs:
|
||||||
SLIME: 5:WATER
|
SLIME: 5:WATER
|
||||||
moblimit: 3
|
moblimit: 3
|
||||||
|
DRIPSTONE_CAVES:
|
||||||
|
friendlyname: "&6Drippy Drops"
|
||||||
|
biome: dripstone_caves
|
||||||
|
icon: DRIPSTONE_BLOCK
|
||||||
|
priority: 15
|
||||||
|
contents:
|
||||||
|
STONE: 8
|
||||||
|
CLAY: 8
|
||||||
|
# 50% water cove rage required
|
||||||
|
watercoverage: 25
|
||||||
|
conversions:
|
||||||
|
CLAY: 50:DRIPSTONE_BLOCK:WATER
|
||||||
|
STONE: 0.005:COPPER_ORE:STONE
|
||||||
|
plants:
|
||||||
|
GLOW_LICHEN: 20:STONE
|
||||||
|
mobs:
|
||||||
|
skeleton: 5:STONE
|
||||||
|
glow_squid: 5:WATER
|
||||||
|
moblimit: 5
|
|
@ -611,7 +611,7 @@ public class BiomeRecipeTest {
|
||||||
@Test
|
@Test
|
||||||
public void testGrowPlantNotAir() {
|
public void testGrowPlantNotAir() {
|
||||||
when(block.getType()).thenReturn(Material.SOUL_SAND);
|
when(block.getType()).thenReturn(Material.SOUL_SAND);
|
||||||
assertFalse(br.growPlant(new GrowthBlock(block, true)));
|
assertFalse(br.growPlant(new GrowthBlock(block, true), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -621,7 +621,7 @@ public class BiomeRecipeTest {
|
||||||
public void testGrowPlantNoPlants() {
|
public void testGrowPlantNoPlants() {
|
||||||
when(block.getType()).thenReturn(Material.AIR);
|
when(block.getType()).thenReturn(Material.AIR);
|
||||||
when(block.isEmpty()).thenReturn(true);
|
when(block.isEmpty()).thenReturn(true);
|
||||||
assertFalse(br.growPlant(new GrowthBlock(block, true)));
|
assertFalse(br.growPlant(new GrowthBlock(block, true), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -633,7 +633,7 @@ public class BiomeRecipeTest {
|
||||||
when(block.getType()).thenReturn(Material.AIR);
|
when(block.getType()).thenReturn(Material.AIR);
|
||||||
when(block.isEmpty()).thenReturn(true);
|
when(block.isEmpty()).thenReturn(true);
|
||||||
assertTrue(br.addPlants(Material.BAMBOO_SAPLING, 100, Material.GRASS_BLOCK));
|
assertTrue(br.addPlants(Material.BAMBOO_SAPLING, 100, Material.GRASS_BLOCK));
|
||||||
assertFalse(br.growPlant(new GrowthBlock(block, true)));
|
assertFalse(br.growPlant(new GrowthBlock(block, true), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -649,7 +649,7 @@ public class BiomeRecipeTest {
|
||||||
|
|
||||||
when(block.getRelative(any())).thenReturn(ob);
|
when(block.getRelative(any())).thenReturn(ob);
|
||||||
assertTrue(br.addPlants(Material.BAMBOO_SAPLING, 100, Material.GRASS_BLOCK));
|
assertTrue(br.addPlants(Material.BAMBOO_SAPLING, 100, Material.GRASS_BLOCK));
|
||||||
assertTrue(br.growPlant(new GrowthBlock(block, true)));
|
assertTrue(br.growPlant(new GrowthBlock(block, true), false));
|
||||||
verify(world).spawnParticle(eq(Particle.SNOWBALL), any(Location.class), anyInt(), anyDouble(), anyDouble(), anyDouble());
|
verify(world).spawnParticle(eq(Particle.SNOWBALL), any(Location.class), anyInt(), anyDouble(), anyDouble(), anyDouble());
|
||||||
verify(block).setBlockData(eq(bd), eq(false));
|
verify(block).setBlockData(eq(bd), eq(false));
|
||||||
}
|
}
|
||||||
|
@ -667,7 +667,7 @@ public class BiomeRecipeTest {
|
||||||
|
|
||||||
when(block.getRelative(any())).thenReturn(ob);
|
when(block.getRelative(any())).thenReturn(ob);
|
||||||
assertTrue(br.addPlants(Material.SPORE_BLOSSOM, 100, Material.GLASS));
|
assertTrue(br.addPlants(Material.SPORE_BLOSSOM, 100, Material.GLASS));
|
||||||
assertTrue(br.growPlant(new GrowthBlock(block, false)));
|
assertTrue(br.growPlant(new GrowthBlock(block, false), false));
|
||||||
verify(world).spawnParticle(eq(Particle.SNOWBALL), any(Location.class), anyInt(), anyDouble(), anyDouble(), anyDouble());
|
verify(world).spawnParticle(eq(Particle.SNOWBALL), any(Location.class), anyInt(), anyDouble(), anyDouble(), anyDouble());
|
||||||
verify(block).setBlockData(eq(bd), eq(false));
|
verify(block).setBlockData(eq(bd), eq(false));
|
||||||
}
|
}
|
||||||
|
@ -686,7 +686,7 @@ public class BiomeRecipeTest {
|
||||||
when(block.getRelative(any())).thenReturn(ob);
|
when(block.getRelative(any())).thenReturn(ob);
|
||||||
assertTrue(br.addPlants(Material.SPORE_BLOSSOM, 100, Material.GLASS));
|
assertTrue(br.addPlants(Material.SPORE_BLOSSOM, 100, Material.GLASS));
|
||||||
// Not a ceiling block
|
// Not a ceiling block
|
||||||
assertFalse(br.growPlant(new GrowthBlock(block, true)));
|
assertFalse(br.growPlant(new GrowthBlock(block, true), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -704,7 +704,7 @@ public class BiomeRecipeTest {
|
||||||
when(block.getRelative(BlockFace.DOWN)).thenReturn(ob);
|
when(block.getRelative(BlockFace.DOWN)).thenReturn(ob);
|
||||||
when(block.getRelative(BlockFace.UP)).thenReturn(block);
|
when(block.getRelative(BlockFace.UP)).thenReturn(block);
|
||||||
assertTrue(br.addPlants(Material.SUNFLOWER, 100, Material.GRASS_BLOCK));
|
assertTrue(br.addPlants(Material.SUNFLOWER, 100, Material.GRASS_BLOCK));
|
||||||
assertTrue(br.growPlant(new GrowthBlock(block, true)));
|
assertTrue(br.growPlant(new GrowthBlock(block, true), false));
|
||||||
verify(world).spawnParticle(eq(Particle.SNOWBALL), any(Location.class), anyInt(), anyDouble(), anyDouble(), anyDouble());
|
verify(world).spawnParticle(eq(Particle.SNOWBALL), any(Location.class), anyInt(), anyDouble(), anyDouble(), anyDouble());
|
||||||
verify(bisected).setHalf(eq(Half.BOTTOM));
|
verify(bisected).setHalf(eq(Half.BOTTOM));
|
||||||
verify(bisected).setHalf(eq(Half.TOP));
|
verify(bisected).setHalf(eq(Half.TOP));
|
||||||
|
@ -725,7 +725,7 @@ public class BiomeRecipeTest {
|
||||||
when(block.getRelative(eq(BlockFace.DOWN))).thenReturn(ob);
|
when(block.getRelative(eq(BlockFace.DOWN))).thenReturn(ob);
|
||||||
when(block.getRelative(eq(BlockFace.UP))).thenReturn(ob);
|
when(block.getRelative(eq(BlockFace.UP))).thenReturn(ob);
|
||||||
assertTrue(br.addPlants(Material.SUNFLOWER, 100, Material.GRASS_BLOCK));
|
assertTrue(br.addPlants(Material.SUNFLOWER, 100, Material.GRASS_BLOCK));
|
||||||
assertFalse(br.growPlant(new GrowthBlock(block, true)));
|
assertFalse(br.growPlant(new GrowthBlock(block, true), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -177,15 +177,15 @@ public class WallsTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link world.bentobox.greenhouses.greenhouse.Walls#getFloorY(int, int, int, int, int)}.
|
* Test method for {@link world.bentobox.greenhouses.greenhouse.Walls#getFloorY(int, int, int, int, int, int)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetFloorYZeroY() {
|
public void testGetFloorYZeroY() {
|
||||||
assertEquals(0, walls.getFloorY(10, 0, 1, 0, 1));
|
assertEquals(-64, walls.getFloorY(10, 0, 1, 0, 1, -64));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link world.bentobox.greenhouses.greenhouse.Walls#getFloorY(int, int, int, int, int)}.
|
* Test method for {@link world.bentobox.greenhouses.greenhouse.Walls#getFloorY(int, int, int, int, int, int)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetFloorY() {
|
public void testGetFloorY() {
|
||||||
|
@ -193,7 +193,7 @@ public class WallsTest {
|
||||||
Material.GLASS, Material.GLASS,
|
Material.GLASS, Material.GLASS,
|
||||||
Material.GLASS, Material.GLASS,
|
Material.GLASS, Material.GLASS,
|
||||||
Material.AIR);
|
Material.AIR);
|
||||||
assertEquals(8, walls.getFloorY(10, 0, 1, 0, 1));
|
assertEquals(8, walls.getFloorY(10, 0, 1, 0, 1, -64));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -123,6 +123,17 @@ public class EcoSystemManagerTest {
|
||||||
when(liquid.getRelative(eq(BlockFace.UP))).thenReturn(liquid);
|
when(liquid.getRelative(eq(BlockFace.UP))).thenReturn(liquid);
|
||||||
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(liquid);
|
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(liquid);
|
||||||
List<GrowthBlock> result = eco.getAvailableBlocks(gh, false);
|
List<GrowthBlock> result = eco.getAvailableBlocks(gh, false);
|
||||||
|
assertEquals(16, result.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(Greenhouse, boolean)}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetAvailableBlocksAllLiquid2() {
|
||||||
|
when(liquid.getRelative(eq(BlockFace.UP))).thenReturn(liquid);
|
||||||
|
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(liquid);
|
||||||
|
List<GrowthBlock> result = eco.getAvailableBlocks(gh, true);
|
||||||
assertEquals(0, result.size());
|
assertEquals(0, result.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue