Compare commits

...

39 Commits

Author SHA1 Message Date
tastybento 93e3152efc Improved errors. 2024-01-21 08:24:40 -08:00
tastybento 0fc5857a4a Added mobs to biomes 2024-01-21 08:21:30 -08:00
tastybento d1e771bad6 Version 1.8.0 2024-01-21 08:21:14 -08:00
tastybento 04a519ad51
Merge branch 'master' into develop 2024-01-20 07:48:02 -08:00
tastybento 3fc14f5cd8 Update to latest Spigot API 2024-01-13 09:29:53 -08:00
tastybento 8ce5cc0e3c
Update pom.xml 1.7.5 2024-01-13 07:09:18 -08:00
tastybento 15c2cea475 BentoBox 2.0.0 2023-11-12 13:53:05 -08:00
tastybento 4084876c4b
Version 1.7.4 (#109)
* Version 1.7.3

* Add ${argLine} to get jacoco coverage

* Updated Jacoco POM entry

* Address bugs reported by SonarCloud

* Updated ReadMe

* Add max mobs option #99

* Use updated Bucket event

* Added tests to cover #99

* Fixes help text for user command.

Fixes #105

* Fixed maxmobs typo instead of maxmob

* Remove unused imports

* Update to new Bukkit Loader

* Remove debug

* Create plugin.yml (#106)

* Create plugin.yml

* Update pom.xml

* Update GreenhousesPladdon.java

* Removed static getInstance usage

* Version 1.7.4

* Refactored to reduce complexity

* Update surefire plugin

* Refactored to reduce complexity

* Minor typos and grammar fixes

* Reduced complexity

* Refactor to reduce complexity

* Refactor to reduce complexity

* Update Github Action build script

* Added distribution required for Github Action

* Update pom.xml

* Fixes mob spawning when no maxmob value given.

Found while doing #108

* Code clean up.

---------

Co-authored-by: BONNe <bonne@bonne.id.lv>
2023-09-19 22:18:57 -07:00
tastybento a7eeef7edc Code clean up. 2023-09-19 22:15:46 -07:00
tastybento ca4f1a3f43
Merge branch 'master' into develop 2023-09-19 21:52:51 -07:00
tastybento 6bc1c5e4bc Merge branch 'develop' of https://github.com/BentoBoxWorld/Greenhouses.git into develop 2023-09-19 21:48:54 -07:00
tastybento 53cb40e7c4 Fixes mob spawning when no maxmob value given.
Found while doing #108
2023-09-19 21:48:45 -07:00
tastybento e05e2806fe
Update pom.xml 2023-07-10 21:44:43 -07:00
tastybento 02c2135501 Added distribution required for Github Action 2023-06-24 13:55:46 -07:00
tastybento 605144e9f9 Update Github Action build script 2023-06-24 13:03:05 -07:00
tastybento 3f4647b547 Refactor to reduce complexity 2023-06-04 17:44:01 -07:00
tastybento e75780e710 Refactor to reduce complexity 2023-06-04 17:36:08 -07:00
tastybento 7e4f0764e6 Reduced complexity 2023-06-04 09:19:15 -07:00
tastybento 398c8e91d5 Minor typos and grammar fixes 2023-06-04 09:11:15 -07:00
tastybento 2eed3dcd56 Refactored to reduce complexity 2023-06-04 09:03:38 -07:00
tastybento 3dd950459f Update surefire plugin 2023-06-04 08:57:01 -07:00
tastybento cce4a655c6 Refactored to reduce complexity 2023-06-04 08:55:02 -07:00
tastybento a2c2975329 Version 1.7.4 2023-06-04 08:46:33 -07:00
tastybento e6a1cd17bb Removed static getInstance usage 2023-06-04 08:44:55 -07:00
BONNe db5ef4d5da
Create plugin.yml (#106)
* Create plugin.yml

* Update pom.xml

* Update GreenhousesPladdon.java
2023-04-08 18:39:46 +03:00
tastybento ac1d6e6638 Remove debug 2023-03-26 10:25:40 -07:00
BONNe 3740268dfc
Update to new Bukkit Loader 2023-03-26 14:04:06 +03:00
tastybento 308dc225cd Remove unused imports 2023-03-18 11:17:52 -04:00
tastybento 95474d6c53 Fixed maxmobs typo instead of maxmob 2023-03-16 22:40:43 -04:00
tastybento d2801dcd75 Fixes help text for user command.
Fixes #105
2023-03-10 08:50:18 -08:00
tastybento e4bbb70acb Added tests to cover #99 2023-03-01 18:30:35 -08:00
tastybento a4fc49689b Use updated Bucket event 2023-03-01 17:59:10 -08:00
tastybento 66270cf3e7 Add max mobs option #99 2023-03-01 08:26:34 -08:00
tastybento 4351247de2 Updated ReadMe 2023-02-25 08:22:44 -08:00
tastybento 9e407e659e Address bugs reported by SonarCloud 2023-02-09 17:27:57 -08:00
tastybento d6df904fbc Updated Jacoco POM entry 2023-02-09 17:09:21 -08:00
tastybento 9af8816995 Merge branch 'develop' of https://github.com/BentoBoxWorld/Greenhouses.git into develop 2023-02-09 17:08:13 -08:00
tastybento ce0eeae546
Add ${argLine} to get jacoco coverage 2023-02-09 15:18:43 -08:00
tastybento cf276bbb24 Version 1.7.3 2023-01-01 22:31:46 -08:00
22 changed files with 388 additions and 302 deletions

View File

@ -11,21 +11,22 @@ jobs:
name: Build name: Build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
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 17 - name: Set up JDK 17
uses: actions/setup-java@v1 uses: actions/setup-java@v3
with: with:
distribution: 'adopt'
java-version: 17 java-version: 17
- name: Cache SonarCloud packages - name: Cache SonarCloud packages
uses: actions/cache@v1 uses: actions/cache@v3
with: with:
path: ~/.sonar/cache path: ~/.sonar/cache
key: ${{ runner.os }}-sonar key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar
- name: Cache Maven packages - name: Cache Maven packages
uses: actions/cache@v1 uses: actions/cache@v3
with: with:
path: ~/.m2 path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}

View File

@ -15,7 +15,7 @@ Greenhouses are made out of glass and must contain the blocks found in the Biome
* Craft your own self-contained biome greenhouse on an island (or elsewhere if you like) * Craft your own self-contained biome greenhouse on an island (or elsewhere if you like)
* Greenhouses can grow plants that cannot normally be grown, like sunflowers * Greenhouses can grow plants that cannot normally be grown, like sunflowers
* Friendly mobs can spawn if your greenhouse is well designed - need slimes? Build a swamp greenhouse! * Friendly mobs can spawn if your greenhouse is well-designed - need slimes? Build a swamp greenhouse!
* Blocks change in biomes over time - dirt becomes sand in a desert, dirt becomes clay in a river, for example. * Blocks change in biomes over time - dirt becomes sand in a desert, dirt becomes clay in a river, for example.
* Greenhouses can run in multiple worlds. * Greenhouses can run in multiple worlds.
* Easy to use GUI shows greenhouse recipes (e.g. **/is greenhouses**) * Easy to use GUI shows greenhouse recipes (e.g. **/is greenhouses**)
@ -27,7 +27,7 @@ This example is for when you are in the BSkyBlock world. For AcidIsland, just us
1. Make glass blocks and build a rectangular set of walls with a flat roof. 1. Make glass blocks and build a rectangular set of walls with a flat roof.
2. Put a hopper in the wall or roof. 2. Put a hopper in the wall or roof.
3. Put a door in the wall so you can get in and out. 3. Put a door in the wall, so you can get in and out.
4. Type **/island greenhouses** and read the rules for the greenhouse you want. 4. Type **/island greenhouses** and read the rules for the greenhouse you want.
5. Exit the GUI and place blocks, water, lava, and ice so that you make your desired biome. 5. Exit the GUI and place blocks, water, lava, and ice so that you make your desired biome.
6. Type **/island greenhouses** again and click on the biome to make it. 6. Type **/island greenhouses** again and click on the biome to make it.
@ -42,7 +42,7 @@ This example is for when you are in the BSkyBlock world. For AcidIsland, just us
## FAQ ## FAQ
* Can I use stained glass? Yes, you can. It's pretty. * Can I use stained-glass? Yes, you can. It's pretty.
* Can I fill my greenhouse full of water? Yes. That's an ocean. * Can I fill my greenhouse full of water? Yes. That's an ocean.
* Will a squid spawn there? Maybe... okay, yes it will if it's a big enough ocean. * Will a squid spawn there? Maybe... okay, yes it will if it's a big enough ocean.
* How do I place a door high up in the wall if the wall is all glass? Place it on a hopper. * How do I place a door high up in the wall if the wall is all glass? Place it on a hopper.

12
pom.xml
View File

@ -46,12 +46,12 @@
<java.version>17</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.19.3-R0.1-SNAPSHOT</spigot.version> <spigot.version>1.20.4-R0.1-SNAPSHOT</spigot.version>
<bentobox.version>1.21.0</bentobox.version> <bentobox.version>2.0.0-SNAPSHOT</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. -->
<build.version>1.7.3</build.version> <build.version>1.8.0</build.version>
<build.number>-LOCAL</build.number> <build.number>-LOCAL</build.number>
<sonar.projectKey>BentoBoxWorld_Greenhouses</sonar.projectKey> <sonar.projectKey>BentoBoxWorld_Greenhouses</sonar.projectKey>
<sonar.organization>bentobox-world</sonar.organization> <sonar.organization>bentobox-world</sonar.organization>
@ -191,7 +191,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version> <version>3.1.0</version>
<configuration> <configuration>
<argLine> <argLine>
${argLine} ${argLine}
@ -252,13 +252,15 @@
<plugin> <plugin>
<groupId>org.jacoco</groupId> <groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId> <artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.7</version> <version>0.8.10</version>
<configuration> <configuration>
<append>true</append> <append>true</append>
<excludes> <excludes>
<!-- This is required to prevent Jacoco from adding <!-- This is required to prevent Jacoco from adding
synthetic fields to a JavaBean class (causes errors in testing) --> synthetic fields to a JavaBean class (causes errors in testing) -->
<exclude>**/*Names*</exclude> <exclude>**/*Names*</exclude>
<!-- Prevents the Material is too large to mock error -->
<exclude>org/bukkit/Material*</exclude>
</excludes> </excludes>
</configuration> </configuration>
<executions> <executions>

View File

@ -11,6 +11,7 @@ import world.bentobox.bentobox.api.configuration.Config;
import world.bentobox.bentobox.api.flags.Flag; import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.api.flags.Flag.Mode; import world.bentobox.bentobox.api.flags.Flag.Mode;
import world.bentobox.bentobox.api.flags.Flag.Type; import world.bentobox.bentobox.api.flags.Flag.Type;
import world.bentobox.greenhouses.greenhouse.Walls;
import world.bentobox.greenhouses.managers.GreenhouseManager; import world.bentobox.greenhouses.managers.GreenhouseManager;
import world.bentobox.greenhouses.managers.RecipeManager; import world.bentobox.greenhouses.managers.RecipeManager;
import world.bentobox.greenhouses.ui.user.UserCommand; import world.bentobox.greenhouses.ui.user.UserCommand;
@ -28,19 +29,13 @@ public class Greenhouses extends Addon {
public static final Flag GREENHOUSES = new Flag.Builder("GREENHOUSE", Material.GREEN_STAINED_GLASS) public static final Flag GREENHOUSES = new Flag.Builder("GREENHOUSE", Material.GREEN_STAINED_GLASS)
.mode(Mode.BASIC) .mode(Mode.BASIC)
.type(Type.PROTECTION).build(); .type(Type.PROTECTION).build();
private static Greenhouses instance;
private final Config<Settings> config; private final Config<Settings> config;
public static Greenhouses getInstance() {
return instance;
}
/** /**
* Constructor * Constructor
*/ */
public Greenhouses() { public Greenhouses() {
super(); super();
instance = this;
config = new Config<>(this, Settings.class); config = new Config<>(this, Settings.class);
} }
@ -122,4 +117,15 @@ public class Greenhouses extends Addon {
return activeWorlds; return activeWorlds;
} }
/**
* Check if material is a wall material
* @param m - material
* @return true if wall material
*/
public boolean wallBlocks(Material m) {
return Walls.WALL_BLOCKS.contains(m)
|| (m.equals(Material.GLOWSTONE) && getSettings().isAllowGlowstone())
|| (m.name().endsWith("GLASS_PANE") && getSettings().isAllowPanes());
}
} }

View File

@ -209,24 +209,30 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
* @return set of results from the check * @return set of results from the check
*/ */
private Set<GreenhouseResult> checkRecipeAsync(CompletableFuture<Set<GreenhouseResult>> r, Greenhouse gh) { private Set<GreenhouseResult> checkRecipeAsync(CompletableFuture<Set<GreenhouseResult>> r, Greenhouse gh) {
AsyncWorldCache cache = new AsyncWorldCache(gh.getWorld()); AsyncWorldCache cache = new AsyncWorldCache(addon, gh.getWorld());
Set<GreenhouseResult> result = new HashSet<>();
long area = gh.getArea(); long area = gh.getArea();
Map<Material, Integer> blockCount = new EnumMap<>(Material.class);
// Look through the greenhouse and count what is in there // Look through the greenhouse and count what is in there
for (int y = gh.getFloorHeight(); y< gh.getCeilingHeight();y++) { Map<Material, Integer> blockCount = countBlocks(gh, cache);
for (int x = (int) (gh.getBoundingBox().getMinX()+1); x < gh.getBoundingBox().getMaxX(); x++) {
for (int z = (int) (gh.getBoundingBox().getMinZ()+1); z < gh.getBoundingBox().getMaxZ(); z++) { // Calculate % water, ice and lava ratios and check them
Material t = cache.getBlockType(x, y, z); Set<GreenhouseResult> result = checkRatios(blockCount, area);
if (!t.equals(Material.AIR)) {
blockCount.putIfAbsent(t, 0); // Compare to the required blocks
blockCount.merge(t, 1, Integer::sum); Map<Material, Integer> missingBlocks = requiredBlocks.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue() - blockCount.getOrDefault(e.getKey(), 0)));
} // Remove any entries that are 0 or less
} missingBlocks.values().removeIf(v -> v <= 0);
} if (!missingBlocks.isEmpty()) {
result.add(GreenhouseResult.FAIL_INSUFFICIENT_BLOCKS);
gh.setMissingBlocks(missingBlocks);
} }
// Calculate % water, ice and lava ratios // Return to main thread to complete
Bukkit.getScheduler().runTask(addon.getPlugin(), () -> r.complete(result));
return result;
}
private Set<GreenhouseResult> checkRatios(Map<Material, Integer> blockCount, long area) {
Set<GreenhouseResult> result = new HashSet<>();
double waterRatio = (double)blockCount.getOrDefault(Material.WATER, 0)/area * 100; double waterRatio = (double)blockCount.getOrDefault(Material.WATER, 0)/area * 100;
double lavaRatio = (double)blockCount.getOrDefault(Material.LAVA, 0)/area * 100; double lavaRatio = (double)blockCount.getOrDefault(Material.LAVA, 0)/area * 100;
int ice = blockCount.entrySet().stream().filter(en -> en.getKey().equals(Material.ICE) int ice = blockCount.entrySet().stream().filter(en -> en.getKey().equals(Material.ICE)
@ -254,47 +260,57 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
if (iceCoverage > 0 && iceRatio < iceCoverage) { if (iceCoverage > 0 && iceRatio < iceCoverage) {
result.add(GreenhouseResult.FAIL_INSUFFICIENT_ICE); result.add(GreenhouseResult.FAIL_INSUFFICIENT_ICE);
} }
// Compare to the required blocks
Map<Material, Integer> missingBlocks = requiredBlocks.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue() - blockCount.getOrDefault(e.getKey(), 0)));
// Remove any entries that are 0 or less
missingBlocks.values().removeIf(v -> v <= 0);
if (!missingBlocks.isEmpty()) {
result.add(GreenhouseResult.FAIL_INSUFFICIENT_BLOCKS);
gh.setMissingBlocks(missingBlocks);
}
// Return to main thread to complete
Bukkit.getScheduler().runTask(addon.getPlugin(), () -> r.complete(result));
return result; return result;
} }
private Map<Material, Integer> countBlocks(Greenhouse gh, AsyncWorldCache cache) {
Map<Material, Integer> blockCount = new EnumMap<>(Material.class);
for (int y = gh.getFloorHeight(); y< gh.getCeilingHeight();y++) {
for (int x = (int) (gh.getBoundingBox().getMinX()+1); x < gh.getBoundingBox().getMaxX(); x++) {
for (int z = (int) (gh.getBoundingBox().getMinZ()+1); z < gh.getBoundingBox().getMaxZ(); z++) {
Material t = cache.getBlockType(x, y, z);
if (!t.equals(Material.AIR)) {
blockCount.putIfAbsent(t, 0);
blockCount.merge(t, 1, Integer::sum);
}
}
}
}
return blockCount;
}
/** /**
* Check if block should be converted * Check if block should be converted
* @param b - block to check * @param b - block to check
*/ */
public void convertBlock(Block b) { public void convertBlock(Block b) {
Material bType = b.getType(); Material bType = b.getType();
// Check if there is a block conversion for this block, as while the rest of the method wont do anything if .get() returns nothing anyway it still seems to be quite expensive // Check if there is a block conversion for this block, as while the rest of the method won't do anything if .get() returns nothing anyway it still seems to be quite expensive
if(conversionBlocks.keySet().contains(bType)) { if(conversionBlocks.keySet().contains(bType)) {
for(GreenhouseBlockConversions conversion_option : conversionBlocks.get(bType)) { for(GreenhouseBlockConversions conversionOption : conversionBlocks.get(bType)) {
rollTheDice(b, conversionOption);
// Roll the dice before bothering with checking the surrounding block as I think it's more common for greenhouses to be filled with convertable blocks and thus this dice roll wont be "wasted"
if(ThreadLocalRandom.current().nextDouble() < conversion_option.probability()) {
// Check if any of the adjacent blocks matches the required LocalMaterial, if there are any required LocalMaterials
if(conversion_option.localMaterial() != null) {
for(BlockFace adjacent_block : ADJ_BLOCKS) {
if(b.getRelative(adjacent_block).getType() == conversion_option.localMaterial()) {
b.setType(conversion_option.newMaterial());
break;
}
}
} else {
b.setType(conversion_option.newMaterial());
}
}
} }
} }
} }
private void rollTheDice(Block b, GreenhouseBlockConversions conversion_option) {
// Roll the dice before bothering with checking the surrounding block as I think it's more common for greenhouses to be filled with convertable blocks and thus this dice roll wont be "wasted"
if(ThreadLocalRandom.current().nextDouble() < conversion_option.probability()) {
// Check if any of the adjacent blocks matches the required LocalMaterial, if there are any required LocalMaterials
if(conversion_option.localMaterial() != null) {
for(BlockFace adjacent_block : ADJ_BLOCKS) {
if(b.getRelative(adjacent_block).getType() == conversion_option.localMaterial()) {
b.setType(conversion_option.newMaterial());
break;
}
}
} else {
b.setType(conversion_option.newMaterial());
}
}
}
/** /**
* @return the type * @return the type
*/ */
@ -376,7 +392,7 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
} }
// Center spawned mob // Center spawned mob
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));
boolean result = 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()) .filter(m -> Optional.of(m.mobSpawnOn())
.map(b.getRelative(BlockFace.DOWN).getType()::equals) .map(b.getRelative(BlockFace.DOWN).getType()::equals)
@ -396,7 +412,6 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
return true; return true;
}).orElse(false); }).orElse(false);
}).orElse(false); }).orElse(false);
return result;
} }
/** /**
@ -435,7 +450,10 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
// Grow a random plant that can grow // Grow a random plant that can grow
double r = random.nextDouble(); double r = random.nextDouble();
Double key = underwater ? underwaterPlants.ceilingKey(r) : plantTree.ceilingKey(r); Double key = underwater ? underwaterPlants.ceilingKey(r) : plantTree.ceilingKey(r);
return key == null ? Optional.empty() : Optional.ofNullable(underwater ? underwaterPlants.get(key) : plantTree.get(key)); if (key == null) {
return Optional.empty();
}
return Optional.ofNullable(underwater ? underwaterPlants.get(key) : plantTree.get(key));
} }
/** /**
@ -461,11 +479,9 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
public boolean growPlant(GrowthBlock block, boolean underwater) { public boolean growPlant(GrowthBlock block, boolean underwater) {
Block bl = block.block(); Block bl = block.block();
return getRandomPlant(underwater).map(p -> { return getRandomPlant(underwater).map(p -> {
if (bl.getY() != 0 && canGrowOn(block, p)) { if (bl.getY() != 0 && canGrowOn(block, p) && plantIt(bl, p)) {
if (plantIt(bl, p)) { bl.getWorld().spawnParticle(Particle.SNOWBALL, bl.getLocation(), 10, 2, 2, 2);
bl.getWorld().spawnParticle(Particle.SNOWBALL, bl.getLocation(), 10, 2, 2, 2); return true;
return true;
}
} }
return false; return false;
}).orElse(false); }).orElse(false);
@ -554,14 +570,12 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
BlockFace d = null; BlockFace d = null;
boolean waterLogged = false; boolean waterLogged = false;
for (BlockFace adj : ADJ_BLOCKS) { for (BlockFace adj : ADJ_BLOCKS) {
if (b.getRelative(adj).getType().equals(Material.AIR)) { Material type = b.getRelative(adj).getType();
if (type.equals(Material.AIR) || type.equals(Material.WATER)) {
d = adj; d = adj;
break; if (type.equals(Material.WATER)) {
} waterLogged = true;
// Lichen can grow under water too }
if (b.getRelative(adj).getType().equals(Material.WATER)) {
d = adj;
waterLogged = true;
break; break;
} }
} }

View File

@ -23,33 +23,17 @@ import world.bentobox.greenhouses.world.AsyncWorldCache;
* @author tastybento * @author tastybento
* *
*/ */
@SuppressWarnings("deprecation")
public class Roof extends MinMaxXZ { public class Roof extends MinMaxXZ {
private static final List<Material> ROOF_BLOCKS; private static final List<Material> ROOF_BLOCKS = Arrays.stream(Material.values())
static { .filter(Material::isBlock) // Blocks only, no items
// Roof blocks .filter(m -> Tag.TRAPDOORS.isTagged(m) // All trapdoors
ROOF_BLOCKS = Arrays.stream(Material.values()) || (m.name().contains("GLASS") && !m.name().contains("GLASS_PANE")) // All glass blocks
.filter(m -> !m.isLegacy()) || m.equals(Material.HOPPER)).toList();
.filter(Material::isBlock) // Blocks only, no items
.filter(m -> Tag.TRAPDOORS.isTagged(m) // All trapdoors
|| (m.name().contains("GLASS") && !m.name().contains("GLASS_PANE")) // All glass blocks
|| m.equals(Material.HOPPER)).toList();
}
/**
* Check if material is a roof material
* @param m - material
* @return true if roof material
*/
public static boolean roofBlocks(@NonNull Material m) {
return ROOF_BLOCKS.contains(Objects.requireNonNull(m))
|| (m.equals(Material.GLOWSTONE) && Greenhouses.getInstance().getSettings().isAllowGlowstone())
|| (m.name().endsWith("GLASS_PANE") && Greenhouses.getInstance().getSettings().isAllowPanes());
}
private final AsyncWorldCache cache; private final AsyncWorldCache cache;
private int height; private int height;
private final Location location; private final Location location;
private boolean roofFound; private boolean roofFound;
private final Greenhouses addon;
private final World world; private final World world;
@ -58,13 +42,23 @@ public class Roof extends MinMaxXZ {
* @param cache async world cache * @param cache async world cache
* @param loc - starting location * @param loc - starting location
*/ */
public Roof(AsyncWorldCache cache, Location loc) { public Roof(AsyncWorldCache cache, Location loc, Greenhouses addon) {
this.cache = cache; this.cache = cache;
this.location = loc; this.location = loc;
this.addon = addon;
this.world = loc.getWorld(); this.world = loc.getWorld();
} }
/**
* Check if material is a roof material
* @param m - material
* @return true if roof material
*/
public boolean roofBlocks(@NonNull Material m) {
return ROOF_BLOCKS.contains(Objects.requireNonNull(m))
|| (m.equals(Material.GLOWSTONE) && addon.getSettings().isAllowGlowstone())
|| (m.name().endsWith("GLASS_PANE") && addon.getSettings().isAllowPanes());
}
/** /**
* This takes any location and tries to go as far as possible in NWSE directions finding contiguous roof blocks * This takes any location and tries to go as far as possible in NWSE directions finding contiguous roof blocks
@ -124,7 +118,7 @@ public class Roof extends MinMaxXZ {
} }
boolean findRoof(Vector loc) { boolean findRoof(Vector loc) {
// This does a ever-growing check around the player to find a wall block. It is possible for the player // This does an 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 // to be outside the greenhouse in this situation, so a check is done later to make sure the player is inside
int startY = loc.getBlockY(); int startY = loc.getBlockY();
for (int y = startY; y < world.getMaxHeight(); y++) { for (int y = startY; y < world.getMaxHeight(); y++) {
@ -136,7 +130,7 @@ public class Roof extends MinMaxXZ {
} }
} }
// If the roof was not found start going around in circles until something is found // 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 // Expand in ever-increasing squares around location until a wall block is found
if (!roofFound) { if (!roofFound) {
loc = spiralSearch(loc, startY); loc = spiralSearch(loc, startY);
if (!roofFound) { if (!roofFound) {
@ -205,13 +199,13 @@ public class Roof extends MinMaxXZ {
} }
/** /**
* Get highest roof block * Get the highest roof block
* @param x - x coord of current search * @param x - x coord of current search
* @param startY - starting y coord * @param startY - starting y coord
* @param z - z coord of current search * @param z - z coord of current search
*/ */
private Optional<Vector> checkVertically(final int x, final int startY, final int z) { private Optional<Vector> checkVertically(final int x, final int startY, final int z) {
if (!Walls.wallBlocks(cache.getBlockType(x, startY, z))) { if (!addon.wallBlocks(cache.getBlockType(x, startY, z))) {
// Look up // Look up
for (int y = startY; y < world.getMaxHeight() && !roofFound; y++) { for (int y = startY; y < world.getMaxHeight() && !roofFound; y++) {
if (roofBlocks(cache.getBlockType(x,y,z))) { if (roofBlocks(cache.getBlockType(x,y,z))) {

View File

@ -9,25 +9,17 @@ import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.BentoBox;
import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.world.AsyncWorldCache; import world.bentobox.greenhouses.world.AsyncWorldCache;
@SuppressWarnings("deprecation")
public class Walls extends MinMaxXZ { public class Walls extends MinMaxXZ {
private static final List<Material> WALL_BLOCKS; public static final List<Material> WALL_BLOCKS = Arrays.stream(Material.values())
static { .filter(Material::isBlock) // Blocks only, no items
// Hoppers .filter(m -> !m.name().contains("TRAPDOOR")) // No trap doors
WALL_BLOCKS = Arrays.stream(Material.values()) .filter(m -> m.name().contains("DOOR") // All doors
.filter(Material::isBlock) // Blocks only, no items || (m.name().contains("GLASS") && !m.name().contains("GLASS_PANE")) // All glass blocks
.filter(m -> !m.isLegacy()) || m.equals(Material.HOPPER)).toList();
.filter(m -> !m.name().contains("TRAPDOOR")) // No trap doors
.filter(m -> m.name().contains("DOOR") // All doors
|| (m.name().contains("GLASS") && !m.name().contains("GLASS_PANE")) // All glass blocks
|| m.equals(Material.HOPPER)).toList();
}
private int floor; private int floor;
private final AsyncWorldCache cache; private final AsyncWorldCache cache;
static class WallFinder { static class WallFinder {
@ -177,17 +169,6 @@ public class Walls extends MinMaxXZ {
} }
/**
* Check if material is a wall material
* @param m - material
* @return true if wall material
*/
public static boolean wallBlocks(Material m) {
return WALL_BLOCKS.contains(m)
|| (m.equals(Material.GLOWSTONE) && Greenhouses.getInstance().getSettings().isAllowGlowstone())
|| (m.name().endsWith("GLASS_PANE") && Greenhouses.getInstance().getSettings().isAllowPanes());
}
/** /**
* @return the floor * @return the floor
*/ */

View File

@ -53,7 +53,7 @@ public class GreenhouseGuard implements Listener {
if (from.isPresent() && addon.getSettings().isAllowFlowOut()) { if (from.isPresent() && addon.getSettings().isAllowFlowOut()) {
return; return;
} }
// Otherwise cancel - the flow is not allowed // Otherwise, cancel - the flow is not allowed
e.setCancelled(true); e.setCancelled(true);
} }

View File

@ -95,17 +95,17 @@ public class EcoSystemManager {
return; return;
} }
final BoundingBox ibb = gh.getInternalBoundingBox(); final BoundingBox ibb = gh.getInternalBoundingBox();
int gh_min_x = NumberConversions.floor(ibb.getMinX()); int ghMinX = NumberConversions.floor(ibb.getMinX());
int gh_max_x = NumberConversions.floor(ibb.getMaxX()); int ghMaxX = NumberConversions.floor(ibb.getMaxX());
int gh_min_y = NumberConversions.floor(gh.getBoundingBox().getMinY()); // Note: this gets the floor int ghMinY = NumberConversions.floor(gh.getBoundingBox().getMinY()); // Note: this gets the floor
int gh_max_y = NumberConversions.floor(ibb.getMaxY()); int ghMaxY = NumberConversions.floor(ibb.getMaxY());
int gh_min_z = NumberConversions.floor(ibb.getMinZ()); int ghMinZ = NumberConversions.floor(ibb.getMinZ());
int gh_max_z = NumberConversions.floor(ibb.getMaxZ()); int ghMaxZ = NumberConversions.floor(ibb.getMaxZ());
BiomeRecipe biomeRecipe = gh.getBiomeRecipe(); BiomeRecipe biomeRecipe = gh.getBiomeRecipe();
for (int x = gh_min_x; x < gh_max_x; x++) { for (int x = ghMinX; x < ghMaxX; x++) {
for (int z = gh_min_z; z < gh_max_z; z++) { for (int z = ghMinZ; z < ghMaxZ; z++) {
for (int y = gh_min_y; y < gh_max_y; y++) { for (int y = ghMinY; y < ghMaxY; y++) {
Block b = world.getBlockAt(x, y, z); Block b = world.getBlockAt(x, y, z);
if(!b.isEmpty()) { if(!b.isEmpty()) {
@ -167,7 +167,7 @@ public class EcoSystemManager {
Collections.shuffle(list, new Random(System.currentTimeMillis())); Collections.shuffle(list, new Random(System.currentTimeMillis()));
Iterator<GrowthBlock> it = list.iterator(); Iterator<GrowthBlock> it = list.iterator();
// Check if the greenhouse is full // Check if the greenhouse is full
if (sum >= gh.getBiomeRecipe().getMaxMob()) { if (gh.getBiomeRecipe().getMaxMob() > -1 && sum >= gh.getBiomeRecipe().getMaxMob()) {
return false; return false;
} }
while (it.hasNext() && (sum == 0 || gh.getArea() / sum >= gh.getBiomeRecipe().getMobLimit())) { while (it.hasNext() && (sum == 0 || gh.getArea() / sum >= gh.getBiomeRecipe().getMobLimit())) {
@ -241,36 +241,39 @@ 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));
if (checkBlock(result, b, ignoreLiquid)) {
// Check floor blocks break;
if (!ignoreLiquid) {
// Check ceiling blocks
if (b.isEmpty() && !b.getRelative(BlockFace.UP).isEmpty()) {
result.add(new GrowthBlock(b, false));
}
if (!b.isEmpty() && !Tag.LEAVES.isTagged(b.getType())
&& (b.getRelative(BlockFace.UP).isEmpty()
|| b.getRelative(BlockFace.UP).isPassable()
|| Tag.LEAVES.isTagged(b.getRelative(BlockFace.UP).getType())
)
) {
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;
} }
private boolean checkBlock(List<GrowthBlock> result, Block b, boolean ignoreLiquid) {
// Check floor blocks
if (!ignoreLiquid) {
// Check ceiling blocks
if (b.isEmpty() && !b.getRelative(BlockFace.UP).isEmpty()) {
result.add(new GrowthBlock(b, false));
}
if (!b.isEmpty() && !Tag.LEAVES.isTagged(b.getType())
&& (b.getRelative(BlockFace.UP).isEmpty()
|| b.getRelative(BlockFace.UP).isPassable()
|| Tag.LEAVES.isTagged(b.getRelative(BlockFace.UP).getType())
)
) {
result.add(new GrowthBlock(b.getRelative(BlockFace.UP), true));
return true;
}
} else {
if (!b.isEmpty() && !b.isLiquid() && b.getRelative(BlockFace.UP).isLiquid()) {
result.add(new GrowthBlock(b.getRelative(BlockFace.UP), true));
return true;
}
}
return false;
}
private int getBoneMeal(Greenhouse gh) { private int getBoneMeal(Greenhouse gh) {
Hopper hopper = getHopper(gh); Hopper hopper = getHopper(gh);

View File

@ -12,6 +12,7 @@ import org.bukkit.Tag;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.BentoBox;
import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.data.Greenhouse; import world.bentobox.greenhouses.data.Greenhouse;
import world.bentobox.greenhouses.greenhouse.Roof; import world.bentobox.greenhouses.greenhouse.Roof;
import world.bentobox.greenhouses.greenhouse.Walls; import world.bentobox.greenhouses.greenhouse.Walls;
@ -28,10 +29,11 @@ public class GreenhouseFinder {
// If this is the bottom layer, the player has most likely uneven walls // If this is the bottom layer, the player has most likely uneven walls
private int otherBlockLayer = -1; private int otherBlockLayer = -1;
private int wallBlockCount; private int wallBlockCount;
private final Greenhouses addon;
/** /**
* This is the count of the various items * This is the count of the various items
*/ */
private CounterCheck cc = new CounterCheck(); private CounterCheck counterCheck = new CounterCheck();
static class CounterCheck { static class CounterCheck {
int doorCount; int doorCount;
@ -40,6 +42,13 @@ public class GreenhouseFinder {
boolean otherBlock; boolean otherBlock;
} }
/**
* @param addon Addon
*/
public GreenhouseFinder(Greenhouses addon) {
this.addon = addon;
}
/** /**
* Find out if there is a greenhouse here * Find out if there is a greenhouse here
* @param location - start location * @param location - start location
@ -51,9 +60,9 @@ public class GreenhouseFinder {
redGlass.clear(); redGlass.clear();
// Get a world cache // Get a world cache
AsyncWorldCache cache = new AsyncWorldCache(location.getWorld()); AsyncWorldCache cache = new AsyncWorldCache(addon, location.getWorld());
// Find the roof // Find the roof
Roof roof = new Roof(cache, location); Roof roof = new Roof(cache, location, addon);
roof.findRoof().thenAccept(found -> { roof.findRoof().thenAccept(found -> {
if (Boolean.FALSE.equals(found)) { if (Boolean.FALSE.equals(found)) {
result.add(GreenhouseResult.FAIL_NO_ROOF); result.add(GreenhouseResult.FAIL_NO_ROOF);
@ -87,30 +96,26 @@ public class GreenhouseFinder {
*/ */
CompletableFuture<Set<GreenhouseResult>> checkGreenhouse(AsyncWorldCache cache, Roof roof, Walls walls) { CompletableFuture<Set<GreenhouseResult>> checkGreenhouse(AsyncWorldCache cache, Roof roof, Walls walls) {
CompletableFuture<Set<GreenhouseResult>> r = new CompletableFuture<>(); CompletableFuture<Set<GreenhouseResult>> r = new CompletableFuture<>();
Bukkit.getScheduler().runTaskAsynchronously(BentoBox.getInstance(), () -> checkGHAsync(r, cache, roof, walls)); Bukkit.getScheduler().runTaskAsynchronously(BentoBox.getInstance(), () -> checkGreenhouseAsync(r, cache, roof, walls));
return r; return r;
} }
private Set<GreenhouseResult> checkGHAsync(CompletableFuture<Set<GreenhouseResult>> r, AsyncWorldCache cache, private Set<GreenhouseResult> checkGreenhouseAsync(CompletableFuture<Set<GreenhouseResult>> r, AsyncWorldCache cache,
Roof roof, Walls walls) { Roof roof, Walls walls) {
cc = new CounterCheck(); counterCheck = new CounterCheck();
int y; int y;
for (y = roof.getHeight(); y > walls.getFloor(); y--) { for (y = roof.getHeight(); y > walls.getFloor(); y--) {
wallBlockCount = 0; wallBlockCount = 0;
for (int x = walls.getMinX(); x <= walls.getMaxX(); x++) { for (int x = walls.getMinX(); x <= walls.getMaxX(); x++) {
for (int z = walls.getMinZ(); z <= walls.getMaxZ(); z++) { for (int z = walls.getMinZ(); z <= walls.getMaxZ(); z++) {
checkBlock(cc, cache.getBlockType(x,y,z), roof, walls, new Vector(x, y, z)); checkBlock(counterCheck, cache.getBlockType(x,y,z), roof, walls, new Vector(x, y, z));
} }
} }
if (wallBlockCount == 0 && y < roof.getHeight()) { if (wallBlockCount == 0 && y < roof.getHeight()) {
// This is the floor // This is the floor
break; break;
} else { } else if (counterCheck.otherBlock && otherBlockLayer < 0) {
if (cc.otherBlock) { otherBlockLayer = y;
if (otherBlockLayer < 0) {
otherBlockLayer = y;
}
}
} }
} }
@ -138,7 +143,7 @@ public class GreenhouseFinder {
// Roof blocks must be glass, glowstone, doors or a hopper. // Roof blocks must be glass, glowstone, doors or a hopper.
result.add(GreenhouseResult.FAIL_BAD_ROOF_BLOCKS); result.add(GreenhouseResult.FAIL_BAD_ROOF_BLOCKS);
} else if (isOtherBlocks()) { } else if (isOtherBlocks()) {
// "Wall blocks must be glass, glowstone, doors or a hopper. // Wall blocks must be glass, glowstone, doors or a hopper.
result.add(GreenhouseResult.FAIL_BAD_WALL_BLOCKS); result.add(GreenhouseResult.FAIL_BAD_WALL_BLOCKS);
} }
if (this.getWallDoors() > 8) { if (this.getWallDoors() > 8) {
@ -166,7 +171,8 @@ public class GreenhouseFinder {
// Check wall blocks only // Check wall blocks only
if (y == roof.getHeight() || x == walls.getMinX() || x == walls.getMaxX() || z == walls.getMinZ() || z== walls.getMaxZ()) { 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 // Check for non-wall blocks or non-roof blocks at the top of walls
if ((y != roof.getHeight() && !Walls.wallBlocks(m)) || (y == roof.getHeight() && !Roof.roofBlocks(m))) { if ((y != roof.getHeight() && !addon.wallBlocks(m))
|| (y == roof.getHeight() && !roof.roofBlocks(m))) {
if (m.equals(Material.AIR)) { if (m.equals(Material.AIR)) {
// Air hole found // Air hole found
cc.airHole = true; cc.airHole = true;
@ -241,28 +247,28 @@ public class GreenhouseFinder {
* @return the wallDoors * @return the wallDoors
*/ */
int getWallDoors() { int getWallDoors() {
return cc.doorCount; return counterCheck.doorCount;
} }
/** /**
* @return the ghHopper * @return the ghHopper
*/ */
int getGhHopper() { int getGhHopper() {
return cc.hopperCount; return counterCheck.hopperCount;
} }
/** /**
* @return the airHoles * @return the airHoles
*/ */
boolean isAirHoles() { boolean isAirHoles() {
return cc.airHole; return counterCheck.airHole;
} }
/** /**
* @return the otherBlocks * @return the otherBlocks
*/ */
boolean isOtherBlocks() { boolean isOtherBlocks() {
return cc.otherBlock; return counterCheck.otherBlock;
} }
/** /**
@ -315,21 +321,21 @@ public class GreenhouseFinder {
} }
public void setGhHopper(int i) { public void setGhHopper(int i) {
cc.hopperCount = i; counterCheck.hopperCount = i;
} }
public void setWallDoors(int i) { public void setWallDoors(int i) {
cc.doorCount = i; counterCheck.doorCount = i;
} }
public void setAirHoles(boolean b) { public void setAirHoles(boolean b) {
cc.airHole = b; counterCheck.airHole = b;
} }
public void setOtherBlocks(boolean b) { public void setOtherBlocks(boolean b) {
cc.otherBlock = b; counterCheck.otherBlock = b;
} }

View File

@ -96,19 +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);
case FAIL_OVERLAPPING -> addon.logError("Greenhouse overlaps with another greenhouse. Skipping..."); case FAIL_OVERLAPPING -> addon.logError("Greenhouse overlaps with another greenhouse. Skipping...");
case NULL -> addon.logError("Null location of greenhouse. Cannot load. Skipping..."); case NULL -> addon.logError("Null location of greenhouse. Cannot load. Skipping...");
case SUCCESS -> activateGreenhouse(g); case SUCCESS -> activateGreenhouse(g);
case FAIL_NO_WORLD -> addon.logError("Database contains greenhouse for a non-loaded world. Skipping..."); case FAIL_NO_WORLD -> addon.logError("Database contains greenhouse for a non-loaded world. Skipping...");
case FAIL_UNKNOWN_RECIPE -> { case FAIL_UNKNOWN_RECIPE -> {
addon.logError("Greenhouse uses a recipe that does not exist in the biomes.yml. Skipping..."); addon.logError("Greenhouse uses a recipe that does not exist in the biomes.yml. Skipping...");
addon.logError("Greenhouse Id " + g.getUniqueId()); addon.logError("Greenhouse Id " + g.getUniqueId());
} }
default -> { default -> {
} }
} }
}); });
addon.log("Loaded " + map.getSize() + " greenhouses."); addon.log("Loaded " + map.getSize() + " greenhouses.");
@ -153,7 +153,7 @@ public class GreenhouseManager implements Listener {
*/ */
public CompletableFuture<GhResult> tryToMakeGreenhouse(Location location, BiomeRecipe greenhouseRecipe) { public CompletableFuture<GhResult> tryToMakeGreenhouse(Location location, BiomeRecipe greenhouseRecipe) {
CompletableFuture<GhResult> r = new CompletableFuture<>(); CompletableFuture<GhResult> r = new CompletableFuture<>();
GreenhouseFinder finder = new GreenhouseFinder(); GreenhouseFinder finder = new GreenhouseFinder(addon);
finder.find(location).thenAccept(resultSet -> { finder.find(location).thenAccept(resultSet -> {
if (!resultSet.isEmpty()) { if (!resultSet.isEmpty()) {
// Failure! // Failure!

View File

@ -6,7 +6,6 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import org.bukkit.Location; import org.bukkit.Location;
@ -138,7 +137,7 @@ public class GreenhouseMap {
* @return a list of all the Greenhouses * @return a list of all the Greenhouses
*/ */
public List<Greenhouse> getGreenhouses() { public List<Greenhouse> getGreenhouses() {
return greenhouses.values().stream().flatMap(List::stream).collect(Collectors.toList()); return greenhouses.values().stream().flatMap(List::stream).toList();
} }
/** /**

View File

@ -30,6 +30,7 @@ public class RecipeManager {
private static final int MAXIMUM_INVENTORY_SIZE = 49; private static final int MAXIMUM_INVENTORY_SIZE = 49;
private final Greenhouses addon; private final Greenhouses addon;
private static final List<BiomeRecipe> biomeRecipes = new ArrayList<>(); private static final List<BiomeRecipe> biomeRecipes = new ArrayList<>();
private static final String COULD_NOT_PARSE = "Could not parse ";
public RecipeManager(Greenhouses addon) { public RecipeManager(Greenhouses addon) {
this.addon = addon; this.addon = addon;
@ -179,45 +180,54 @@ public class RecipeManager {
ConfigurationSection conversionSec = biomeRecipeConfig.getConfigurationSection("conversions"); ConfigurationSection conversionSec = biomeRecipeConfig.getConfigurationSection("conversions");
if (conversionSec != null) { if (conversionSec != null) {
for (String oldMat : conversionSec.getKeys(false)) { for (String oldMat : conversionSec.getKeys(false)) {
try { parseConversions(oldMat, conversionSec, b);
Material oldMaterial = Material.valueOf(oldMat.toUpperCase(Locale.ENGLISH));
String conversions = conversionSec.getString(oldMat);
if (!Objects.requireNonNull(conversions).isEmpty()) {
String[] split = conversions.split(":");
double convChance = Double.parseDouble(split[0]);
Material newMaterial = Material.valueOf(split[1]);
Material localMaterial = null;
if(split.length > 2) {
localMaterial = Material.valueOf(split[2]);
}
b.addConvBlocks(oldMaterial, newMaterial, convChance, localMaterial);
}
} catch (Exception e) {
addon.logError("Could not parse " + oldMat);
}
} }
} }
// Get the list of conversions // Get the list of conversions
for (String oldMat : biomeRecipeConfig.getStringList("conversion-list")) { for (String oldMat : biomeRecipeConfig.getStringList("conversion-list")) {
try { parseConversionList(oldMat, b);
// Split the string
String[] split = oldMat.split(":");
Material oldMaterial = Material.valueOf(split[0].toUpperCase());
double convChance = Double.parseDouble(split[1]);
Material newMaterial = Material.valueOf(split[2]);
Material localMaterial = null;
if(split.length > 3) {
localMaterial = Material.valueOf(split[3]);
}
b.addConvBlocks(oldMaterial, newMaterial, convChance, localMaterial);
} catch (Exception e) {
addon.logError("Could not parse " + oldMat);
}
} }
} }
private void parseConversionList(String oldMat, BiomeRecipe b) {
try {
// Split the string
String[] split = oldMat.split(":");
Material oldMaterial = Material.valueOf(split[0].toUpperCase());
double convChance = Double.parseDouble(split[1]);
Material newMaterial = Material.valueOf(split[2]);
Material localMaterial = null;
if(split.length > 3) {
localMaterial = Material.valueOf(split[3]);
}
b.addConvBlocks(oldMaterial, newMaterial, convChance, localMaterial);
} catch (Exception e) {
addon.logError(COULD_NOT_PARSE + oldMat);
}
}
private void parseConversions(String oldMat, ConfigurationSection conversionSec, BiomeRecipe b) {
try {
Material oldMaterial = Material.valueOf(oldMat.toUpperCase(Locale.ENGLISH));
String conversions = conversionSec.getString(oldMat);
if (!Objects.requireNonNull(conversions).isEmpty()) {
String[] split = conversions.split(":");
double convChance = Double.parseDouble(split[0]);
Material newMaterial = Material.valueOf(split[1]);
Material localMaterial = null;
if(split.length > 2) {
localMaterial = Material.valueOf(split[2]);
}
b.addConvBlocks(oldMaterial, newMaterial, convChance, localMaterial);
}
} catch (Exception e) {
addon.logError(COULD_NOT_PARSE + oldMat);
}
}
private void loadMobs(ConfigurationSection biomeRecipeConfig, BiomeRecipe b) { private void loadMobs(ConfigurationSection biomeRecipeConfig, BiomeRecipe b) {
ConfigurationSection temp = biomeRecipeConfig.getConfigurationSection("mobs"); ConfigurationSection temp = biomeRecipeConfig.getConfigurationSection("mobs");
// Mob EntityType: Probability:Spawn on Material // Mob EntityType: Probability:Spawn on Material
@ -235,7 +245,7 @@ public class RecipeManager {
Material mobSpawnOn = Material.valueOf(split[1]); Material mobSpawnOn = Material.valueOf(split[1]);
b.addMobs(mobType, mobProbability, mobSpawnOn); b.addMobs(mobType, mobProbability, mobSpawnOn);
} catch (Exception e) { } catch (Exception e) {
addon.logError("Could not parse " + s.getKey()); addon.logError(COULD_NOT_PARSE + s.getKey());
} }
} }

View File

@ -27,14 +27,16 @@ public class AsyncWorldCache {
private final World world; private final World world;
private final Map<Pair<Integer, Integer>, ChunkSnapshot> cache; private final Map<Pair<Integer, Integer>, ChunkSnapshot> cache;
private final Greenhouses addon;
/** /**
* Chunk cache. This class is designed to be run async and blocks futures * Chunk cache. This class is designed to be run async and blocks futures
* @param world - world to cache * @param world - world to cache
*/ */
public AsyncWorldCache(World world) { public AsyncWorldCache(Greenhouses addon, World world) {
this.world = world; this.world = world;
cache = new HashMap<>(); cache = new HashMap<>();
this.addon = addon;
} }
/** /**
@ -59,7 +61,7 @@ public class AsyncWorldCache {
*/ */
private CompletableFuture<ChunkSnapshot> getAChunk(int x, int z) { private CompletableFuture<ChunkSnapshot> getAChunk(int x, int z) {
CompletableFuture<ChunkSnapshot> r = new CompletableFuture<>(); CompletableFuture<ChunkSnapshot> r = new CompletableFuture<>();
Bukkit.getScheduler().runTask(Greenhouses.getInstance().getPlugin(), () -> Bukkit.getScheduler().runTask(addon.getPlugin(), () ->
Util.getChunkAtAsync(world, x, z).thenAccept(chunk -> r.complete(chunk.getChunkSnapshot()))); Util.getChunkAtAsync(world, x, z).thenAccept(chunk -> r.complete(chunk.getChunkSnapshot())));
return r; return r;
} }
@ -104,7 +106,7 @@ public class AsyncWorldCache {
try { try {
return Objects.requireNonNull(getSnap(x, z)).getBlockType(xx, y, zz); return Objects.requireNonNull(getSnap(x, z)).getBlockType(xx, y, zz);
} catch (InterruptedException | ExecutionException e) { } catch (InterruptedException | ExecutionException e) {
Greenhouses.getInstance().logError("Chunk could not be obtained async! " + e); addon.logError("Chunk could not be obtained async! " + e);
// Restore interrupted state... // Restore interrupted state...
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
return Material.AIR; return Material.AIR;

View File

@ -35,6 +35,8 @@ biomes:
# Entity name: % chance:Block on which the mob will spawn # Entity name: % chance:Block on which the mob will spawn
mobs: mobs:
SQUID: 10:WATER SQUID: 10:WATER
GLOW_SQUID: 5:WATER
TURTLE: 10:SAND
# The minimum number of blocks each mob requires. # The minimum number of blocks each mob requires.
# Mobs will not spawn if there is more than 1 per this number of # Mobs will not spawn if there is more than 1 per this number of
# blocks in the greenhouse. e.g., in this case only 2 mobs will spawn if the # blocks in the greenhouse. e.g., in this case only 2 mobs will spawn if the
@ -53,6 +55,9 @@ biomes:
SAND: 1 SAND: 1
watercoverage: 50 watercoverage: 50
icecoverage: 10 icecoverage: 10
mobs:
SQUID: 10:WATER
GLOW_SQUID: 10:WATER
ThreeWolfMoon: ThreeWolfMoon:
friendlyname: "Three Wolf Moon Forest" friendlyname: "Three Wolf Moon Forest"
# Could do with more wolves, but the magic works with 3. # Could do with more wolves, but the magic works with 3.
@ -67,7 +72,9 @@ biomes:
plants: plants:
TALL_GRASS: 10:GRASS_BLOCK TALL_GRASS: 10:GRASS_BLOCK
mobs: mobs:
WOLF: 10:SNOW WOLF: 15:SNOW
FOX: 15:GRASS_BLOCK
RABBIT: 7:GRASS_BLOCK
moblimit: 9 moblimit: 9
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in # Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# the greenhouse at once. Spawning will stop when this limit is reached. # the greenhouse at once. Spawning will stop when this limit is reached.
@ -87,6 +94,7 @@ biomes:
TALL_GRASS: 10:GRASS_BLOCK TALL_GRASS: 10:GRASS_BLOCK
mobs: mobs:
RABBIT: 10:SNOW RABBIT: 10:SNOW
FOX: 7:GRASS_BLOCK
moblimit: 9 moblimit: 9
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in # Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# the greenhouse at once. Spawning will stop when this limit is reached. # the greenhouse at once. Spawning will stop when this limit is reached.
@ -115,6 +123,14 @@ biomes:
- DIRT:30:SAND:SAND - DIRT:30:SAND:SAND
- GRASS_BLOCK:30:SAND:SAND - GRASS_BLOCK:30:SAND:SAND
- COARSE_DIRT:30:GRAVEL:SAND - COARSE_DIRT:30:GRAVEL:SAND
mobs:
RABBIT: 10:SAND
HUSK: 10:SAND
moblimit: 9
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# the greenhouse at once. Spawning will stop when this limit is reached.
# If this value is not given, there is no maximum.
maxmobs: 20
FOREST: FOREST:
friendlyname: "Flowery forest" friendlyname: "Flowery forest"
biome: FLOWER_FOREST biome: FLOWER_FOREST
@ -129,6 +145,17 @@ biomes:
ORANGE_TULIP: 2:GRASS_BLOCK ORANGE_TULIP: 2:GRASS_BLOCK
SUNFLOWER: 4:GRASS_BLOCK SUNFLOWER: 4:GRASS_BLOCK
TALL_GRASS: 20:GRASS_BLOCK TALL_GRASS: 20:GRASS_BLOCK
mobs:
SHEEP: 10:GRASS_BLOCK
CHICKEN: 7:GRASS_BLOCK
PIG: 10:GRASS_BLOCK
COW: 10:GRASS_BLOCK
WOLF: 5:GRASS_BLOCK
moblimit: 9
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# the greenhouse at once. Spawning will stop when this limit is reached.
# If this value is not given, there is no maximum.
maxmobs: 20
NETHER: NETHER:
friendlyname: "&cNether" friendlyname: "&cNether"
biome: NETHER_WASTES biome: NETHER_WASTES
@ -164,6 +191,9 @@ biomes:
watercoverage: 0 watercoverage: 0
mobs: mobs:
SKELETON: 10:SOUL_SAND SKELETON: 10:SOUL_SAND
GHAST: 10:SOUL_SAND
ENDERMAN: 1:SOUL_SAND
STRIDER: 20:LAVA
moblimit: 9 moblimit: 9
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in # Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# the greenhouse at once. Spawning will stop when this limit is reached. # the greenhouse at once. Spawning will stop when this limit is reached.
@ -234,6 +264,10 @@ biomes:
FERN: 20:GRASS_BLOCK FERN: 20:GRASS_BLOCK
TALL_GRASS: 20:GRASS_BLOCK TALL_GRASS: 20:GRASS_BLOCK
COCOA: 10:JUNGLE_LOG COCOA: 10:JUNGLE_LOG
mobs:
PARROT: 30:GRASS_BLOCK
CHICKEN: 20:GRASS_BLOCK
PANDA: 1:GRASS_BLOCK
MUSHROOM_FIELDS: MUSHROOM_FIELDS:
friendlyname: "Mushroom Fields" friendlyname: "Mushroom Fields"
biome: MUSHROOM_FIELDS biome: MUSHROOM_FIELDS
@ -261,7 +295,13 @@ biomes:
watercoverage: 95 watercoverage: 95
mobs: mobs:
SQUID: 10:WATER SQUID: 10:WATER
DROWNED: 1:WATER
COD: 40:WATER
DOLPHIN: 20:WATER
SQUID: 20:WATER
GLOW_SQUID: 10:WATER
moblimit: 9 moblimit: 9
maxmobs: 20
PLAINS: PLAINS:
friendlyname: "Horse Plains" friendlyname: "Horse Plains"
biome: PLAINS biome: PLAINS
@ -272,7 +312,12 @@ biomes:
plants: plants:
TALL_GRASS: 10:GRASS_BLOCK TALL_GRASS: 10:GRASS_BLOCK
mobs: mobs:
HORSE: 10:GRASS_BLOCK HORSE: 18:GRASS_BLOCK
DONKEY: 2:GRASS_BLOCK
COW: 20:GRASS_BLOCK
CHICKEN: 25:GRASS_BLOCK
PIG: 25:GRASS_BLOCK
SHEEP: 25:GRASS_BLOCK
moblimit: 1 moblimit: 1
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in # Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# the greenhouse at once. Spawning will stop when this limit is reached. # the greenhouse at once. Spawning will stop when this limit is reached.
@ -293,6 +338,15 @@ biomes:
# So, for below, dirt has a 50% chance of changing into clay if it is next to water! # So, for below, dirt has a 50% chance of changing into clay if it is next to water!
conversion-list: conversion-list:
- DIRT:50:CLAY:WATER - DIRT:50:CLAY:WATER
mobs:
SALMON: 10:WATER
SQUID: 10:WATER
GLOW_SQUID: 5:WATER
moblimit: 1
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# the greenhouse at once. Spawning will stop when this limit is reached.
# If this value is not given, there is no maximum.
maxmobs: 10
SAVANNA: SAVANNA:
biome: SAVANNA biome: SAVANNA
icon: ACACIA_LEAVES icon: ACACIA_LEAVES
@ -303,6 +357,18 @@ biomes:
GRASS_BLOCK: 4 GRASS_BLOCK: 4
plants: plants:
TALL_GRASS: 10:GRASS_BLOCK TALL_GRASS: 10:GRASS_BLOCK
mobs:
HORSE: 2:GRASS_BLOCK
DONKEY: 2:GRASS_BLOCK
COW: 20:GRASS_BLOCK
CHICKEN: 25:GRASS_BLOCK
PIG: 25:GRASS_BLOCK
SHEEP: 25:GRASS_BLOCK
moblimit: 1
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# the greenhouse at once. Spawning will stop when this limit is reached.
# If this value is not given, there is no maximum.
maxmobs: 10
SWAMP: SWAMP:
friendlyname: "&2Slimy Swamp" friendlyname: "&2Slimy Swamp"
biome: SWAMP biome: SWAMP
@ -321,6 +387,7 @@ biomes:
LILY_PAD: 5:WATER LILY_PAD: 5:WATER
mobs: mobs:
SLIME: 5:WATER SLIME: 5:WATER
FROG: 20:WATER
moblimit: 3 moblimit: 3
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in # Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# the greenhouse at once. Spawning will stop when this limit is reached. # the greenhouse at once. Spawning will stop when this limit is reached.
@ -344,6 +411,7 @@ biomes:
mobs: mobs:
skeleton: 5:STONE skeleton: 5:STONE
glow_squid: 5:WATER glow_squid: 5:WATER
BAT: 10:STONE
moblimit: 5 moblimit: 5
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in # Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# the greenhouse at once. Spawning will stop when this limit is reached. # the greenhouse at once. Spawning will stop when this limit is reached.

View File

@ -53,15 +53,18 @@ greenhouses:
FAIL_BAD_WALL_BLOCKS: "&c Wall contains disallowed blocks!" FAIL_BAD_WALL_BLOCKS: "&c Wall contains disallowed blocks!"
FAIL_BELOW: "&c You must be inside the greenhouse to try to make it" FAIL_BELOW: "&c You must be inside the greenhouse to try to make it"
FAIL_BLOCKS_ABOVE: "&c There can be no blocks above the greenhouse! Red glass blocks should show the problem blocks." FAIL_BLOCKS_ABOVE: "&c There can be no blocks above the greenhouse! Red glass blocks should show the problem blocks."
FAIL_HOLE_IN_ROOF: "&c There is a hole in the roof or it is not flat! Red glass blocks should show the problem." FAIL_HOLE_IN_ROOF: |
&c There is a hole in the roof or it is not flat!
&c Red glass blocks should show the problem.
&c Make sure you are inside your greenhouse to make it.
FAIL_HOLE_IN_WALL: "&c There is a hole in the wall!" FAIL_HOLE_IN_WALL: "&c There is a hole in the wall!"
FAIL_NO_ROOF: "&c There seems to be no roof!" FAIL_NO_ROOF: "&c There seems to be no roof! Make sure you are inside the greenhouse to make it."
FAIL_TOO_MANY_DOORS: "&c You cannot have more than 4 doors in the greenhouse!" FAIL_TOO_MANY_DOORS: "&c You cannot have more than 4 doors in the greenhouse!"
FAIL_TOO_MANY_HOPPERS: "&c Only one hopper is allowed in the walls or roof." FAIL_TOO_MANY_HOPPERS: "&c Only one hopper is allowed in the walls or roof."
FAIL_UNEVEN_WALLS: "&c The walls are uneven. Red glass blocks should show the problem blocks." FAIL_UNEVEN_WALLS: "&c The walls are uneven. Red glass blocks should show the problem blocks."
FAIL_INSUFFICIENT_ICE: "&c Insufficent ice to make this recipe" FAIL_INSUFFICIENT_ICE: "&c Insufficient ice to make this recipe"
FAIL_INSUFFICIENT_LAVA: "&c Insufficent lava to make this recipe" FAIL_INSUFFICIENT_LAVA: "&c Insufficient lava to make this recipe"
FAIL_INSUFFICIENT_WATER: "&c Insufficent water to make this recipe" FAIL_INSUFFICIENT_WATER: "&c Insufficient water to make this recipe"
FAIL_NO_ICE: "&c Ice is required to make this recipe" FAIL_NO_ICE: "&c Ice is required to make this recipe"
FAIL_NO_LAVA: "&c Lava is required to make this recipe" FAIL_NO_LAVA: "&c Lava is required to make this recipe"
FAIL_NO_WATER: "&c Water is required to make this recipe" FAIL_NO_WATER: "&c Water is required to make this recipe"

View File

@ -5,7 +5,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -61,7 +60,7 @@ public class GreenhouseTest {
// RecipeManager // RecipeManager
PowerMockito.mockStatic(RecipeManager.class); PowerMockito.mockStatic(RecipeManager.class);
when(br.getName()).thenReturn("test"); when(br.getName()).thenReturn("test");
when(RecipeManager.getBiomeRecipies(eq("test"))).thenReturn(Optional.of(br)); when(RecipeManager.getBiomeRecipies("test")).thenReturn(Optional.of(br));
// Walls // Walls
when(walls.getMinX()).thenReturn(MINX); when(walls.getMinX()).thenReturn(MINX);
when(walls.getMinZ()).thenReturn(MINZ); when(walls.getMinZ()).thenReturn(MINZ);

View File

@ -151,7 +151,7 @@ public class BiomeRecipeTest {
double convChance = 100D; double convChance = 100D;
Material localMaterial = Material.WATER; Material localMaterial = Material.WATER;
br.addConvBlocks(oldMaterial, newMaterial, convChance, localMaterial); br.addConvBlocks(oldMaterial, newMaterial, convChance, localMaterial);
verify(addon).log(eq(" 100.0% chance for Sand to convert to Clay")); verify(addon).log(" 100.0% chance for Sand to convert to Clay");
} }
/** /**
@ -163,7 +163,7 @@ public class BiomeRecipeTest {
int mobProbability = 50; int mobProbability = 50;
Material mobSpawnOn = Material.GRASS_BLOCK; Material mobSpawnOn = Material.GRASS_BLOCK;
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
verify(addon).log(eq(" 50.0% chance for Cat to spawn on Grass Block.")); verify(addon).log(" 50.0% chance for Cat to spawn on Grass Block.");
} }
/** /**
@ -177,7 +177,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
verify(addon).logError(eq("Mob chances add up to > 100% in BADLANDS biome recipe! Skipping CAT")); verify(addon).logError("Mob chances add up to > 100% in BADLANDS biome recipe! Skipping CAT");
} }
/** /**
@ -190,7 +190,7 @@ public class BiomeRecipeTest {
Material mobSpawnOn = Material.GRASS_BLOCK; Material mobSpawnOn = Material.GRASS_BLOCK;
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
verify(addon).logError(eq("Mob chances add up to > 100% in BADLANDS biome recipe! Skipping CAT")); verify(addon).logError("Mob chances add up to > 100% in BADLANDS biome recipe! Skipping CAT");
} }
/** /**
@ -202,7 +202,7 @@ public class BiomeRecipeTest {
int plantProbability = 20; int plantProbability = 20;
Material plantGrowOn = Material.DIRT; Material plantGrowOn = Material.DIRT;
br.addPlants(plantMaterial, plantProbability, plantGrowOn); br.addPlants(plantMaterial, plantProbability, plantGrowOn);
verify(addon).log(eq(" 20.0% chance for Jungle Sapling to grow on Dirt")); verify(addon).log(" 20.0% chance for Jungle Sapling to grow on Dirt");
} }
/** /**
@ -215,7 +215,7 @@ public class BiomeRecipeTest {
Material plantGrowOn = Material.DIRT; Material plantGrowOn = Material.DIRT;
br.addPlants(plantMaterial, plantProbability, plantGrowOn); br.addPlants(plantMaterial, plantProbability, plantGrowOn);
br.addPlants(plantMaterial, plantProbability, plantGrowOn); br.addPlants(plantMaterial, plantProbability, plantGrowOn);
verify(addon).logError(eq("Plant chances add up to > 100% in BADLANDS biome recipe! Skipping JUNGLE_SAPLING")); verify(addon).logError("Plant chances add up to > 100% in BADLANDS biome recipe! Skipping JUNGLE_SAPLING");
} }
/** /**
@ -226,7 +226,7 @@ public class BiomeRecipeTest {
Material blockMaterial = Material.BLACK_CONCRETE; Material blockMaterial = Material.BLACK_CONCRETE;
int blockQty = 30; int blockQty = 30;
br.addReqBlocks(blockMaterial, blockQty); br.addReqBlocks(blockMaterial, blockQty);
verify(addon).log(eq(" BLACK_CONCRETE x 30")); verify(addon).log(" BLACK_CONCRETE x 30");
} }
/** /**
@ -451,7 +451,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
assertFalse(br.spawnMob(block)); assertFalse(br.spawnMob(block));
verify(world).spawnEntity(eq(location), eq(EntityType.CAT)); verify(world).spawnEntity(location, EntityType.CAT);
verify(location).add(any(Vector.class)); verify(location).add(any(Vector.class));
} }
@ -477,7 +477,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
assertTrue(br.spawnMob(block)); assertTrue(br.spawnMob(block));
verify(world).spawnEntity(eq(location), eq(EntityType.CAT)); verify(world).spawnEntity(location, EntityType.CAT);
verify(location).add(any(Vector.class)); verify(location).add(any(Vector.class));
} }
@ -504,7 +504,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
assertTrue(br.spawnMob(block)); assertTrue(br.spawnMob(block));
verify(world).spawnEntity(eq(location), eq(EntityType.HOGLIN)); verify(world).spawnEntity(location, EntityType.HOGLIN);
verify(location).add(any(Vector.class)); verify(location).add(any(Vector.class));
verify(hoglin).setImmuneToZombification(true); verify(hoglin).setImmuneToZombification(true);
} }
@ -532,7 +532,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
assertTrue(br.spawnMob(block)); assertTrue(br.spawnMob(block));
verify(world).spawnEntity(eq(location), eq(EntityType.PIGLIN)); verify(world).spawnEntity(location, EntityType.PIGLIN);
verify(location).add(any(Vector.class)); verify(location).add(any(Vector.class));
verify(piglin).setImmuneToZombification(true); verify(piglin).setImmuneToZombification(true);
} }
@ -562,7 +562,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
assertTrue(br.spawnMob(block)); assertTrue(br.spawnMob(block));
verify(world).spawnEntity(eq(location), eq(EntityType.PIGLIN)); verify(world).spawnEntity(location, EntityType.PIGLIN);
verify(location).add(any(Vector.class)); verify(location).add(any(Vector.class));
verify(piglin, never()).setImmuneToZombification(true); verify(piglin, never()).setImmuneToZombification(true);
} }
@ -586,7 +586,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
assertFalse(br.spawnMob(block)); assertFalse(br.spawnMob(block));
verify(world, never()).spawnEntity(eq(location), eq(EntityType.CAT)); verify(world, never()).spawnEntity(location, EntityType.CAT);
} }
/** /**
@ -706,8 +706,8 @@ public class BiomeRecipeTest {
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), false)); 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(Half.BOTTOM);
verify(bisected).setHalf(eq(Half.TOP)); verify(bisected).setHalf(Half.TOP);
} }
/** /**
@ -722,8 +722,8 @@ public class BiomeRecipeTest {
when(block.isEmpty()).thenReturn(true); when(block.isEmpty()).thenReturn(true);
Block ob = mock(Block.class); Block ob = mock(Block.class);
when(ob.getType()).thenReturn(Material.GRASS_BLOCK); when(ob.getType()).thenReturn(Material.GRASS_BLOCK);
when(block.getRelative(eq(BlockFace.DOWN))).thenReturn(ob); when(block.getRelative(BlockFace.DOWN)).thenReturn(ob);
when(block.getRelative(eq(BlockFace.UP))).thenReturn(ob); when(block.getRelative(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), false)); assertFalse(br.growPlant(new GrowthBlock(block, true), false));
} }

View File

@ -50,8 +50,6 @@ public class RoofTest {
public void setUp() { public void setUp() {
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS); PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
when(Tag.TRAPDOORS.isTagged(Material.BIRCH_TRAPDOOR)).thenReturn(true); when(Tag.TRAPDOORS.isTagged(Material.BIRCH_TRAPDOOR)).thenReturn(true);
PowerMockito.mockStatic(Greenhouses.class, Mockito.RETURNS_MOCKS);
when(Greenhouses.getInstance()).thenReturn(addon);
s = new Settings(); s = new Settings();
when(addon.getSettings()).thenReturn(s); when(addon.getSettings()).thenReturn(s);
@ -89,14 +87,14 @@ public class RoofTest {
when(location.clone()).thenReturn(location); when(location.clone()).thenReturn(location);
// Test // Test
roof = new Roof(cache, location); roof = new Roof(cache, location, addon);
assertTrue(roof.findRoof(new Vector(10,10,10))); assertTrue(roof.findRoof(new Vector(10,10,10)));
} }
@Test @Test
public void testNoGlass() { public void testNoGlass() {
when(cache.getBlockType(anyInt(), anyInt(), anyInt())).thenReturn(Material.AIR); when(cache.getBlockType(anyInt(), anyInt(), anyInt())).thenReturn(Material.AIR);
roof = new Roof(cache, location); roof = new Roof(cache, location, addon);
assertFalse(roof.findRoof(new Vector(10,10,10))); assertFalse(roof.findRoof(new Vector(10,10,10)));
} }
@ -169,13 +167,13 @@ public class RoofTest {
*/ */
@Test @Test
public void testWallBlocks() { public void testWallBlocks() {
assertFalse(Roof.roofBlocks(Material.ACACIA_BOAT)); assertFalse(roof.roofBlocks(Material.ACACIA_BOAT));
assertTrue(Roof.roofBlocks(Material.GLASS)); assertTrue(roof.roofBlocks(Material.GLASS));
assertTrue(Roof.roofBlocks(Material.GLOWSTONE)); assertTrue(roof.roofBlocks(Material.GLOWSTONE));
assertFalse(Roof.roofBlocks(Material.ACACIA_DOOR)); assertFalse(roof.roofBlocks(Material.ACACIA_DOOR));
assertTrue(Roof.roofBlocks(Material.HOPPER)); assertTrue(roof.roofBlocks(Material.HOPPER));
assertTrue(Roof.roofBlocks(Material.PURPLE_STAINED_GLASS_PANE)); assertTrue(roof.roofBlocks(Material.PURPLE_STAINED_GLASS_PANE));
assertTrue(Roof.roofBlocks(Material.BIRCH_TRAPDOOR)); assertTrue(roof.roofBlocks(Material.BIRCH_TRAPDOOR));
} }
/** /**
@ -185,12 +183,12 @@ public class RoofTest {
public void testWallBlocksNoGlowStoneNoPanes() { public void testWallBlocksNoGlowStoneNoPanes() {
s.setAllowGlowstone(false); s.setAllowGlowstone(false);
s.setAllowPanes(false); s.setAllowPanes(false);
assertFalse(Roof.roofBlocks(Material.ACACIA_BOAT)); assertFalse(roof.roofBlocks(Material.ACACIA_BOAT));
assertTrue(Roof.roofBlocks(Material.GLASS)); assertTrue(roof.roofBlocks(Material.GLASS));
assertFalse(Roof.roofBlocks(Material.GLOWSTONE)); assertFalse(roof.roofBlocks(Material.GLOWSTONE));
assertFalse(Roof.roofBlocks(Material.ACACIA_DOOR)); assertFalse(roof.roofBlocks(Material.ACACIA_DOOR));
assertTrue(Roof.roofBlocks(Material.HOPPER)); assertTrue(roof.roofBlocks(Material.HOPPER));
assertFalse(Roof.roofBlocks(Material.PURPLE_STAINED_GLASS_PANE)); assertFalse(roof.roofBlocks(Material.PURPLE_STAINED_GLASS_PANE));
assertTrue(Roof.roofBlocks(Material.BIRCH_TRAPDOOR)); assertTrue(roof.roofBlocks(Material.BIRCH_TRAPDOOR));
} }
} }

View File

@ -64,12 +64,10 @@ public class WallsTest {
when(Tag.TRAPDOORS.isTagged(Material.BIRCH_TRAPDOOR)).thenReturn(true); when(Tag.TRAPDOORS.isTagged(Material.BIRCH_TRAPDOOR)).thenReturn(true);
// Declare mock after mocking Bukkit // Declare mock after mocking Bukkit
roof = mock(Roof.class); roof = mock(Roof.class);
PowerMockito.mockStatic(Greenhouses.class, Mockito.RETURNS_MOCKS);
when(Greenhouses.getInstance()).thenReturn(addon);
s = new Settings(); s = new Settings();
when(addon.getSettings()).thenReturn(s); when(addon.getSettings()).thenReturn(s);
when(addon.getPlugin()).thenReturn(plugin); when(addon.getPlugin()).thenReturn(plugin);
when(addon.wallBlocks(any())).thenCallRealMethod();
walls = new Walls(cache); walls = new Walls(cache);
when(world.getMaxHeight()).thenReturn(255); when(world.getMaxHeight()).thenReturn(255);
when(location.getWorld()).thenReturn(world); when(location.getWorld()).thenReturn(world);
@ -201,13 +199,13 @@ public class WallsTest {
*/ */
@Test @Test
public void testWallBlocks() { public void testWallBlocks() {
assertFalse(Walls.wallBlocks(Material.ACACIA_BOAT)); assertFalse(addon.wallBlocks(Material.ACACIA_BOAT));
assertTrue(Walls.wallBlocks(Material.GLASS)); assertTrue(addon.wallBlocks(Material.GLASS));
assertTrue(Walls.wallBlocks(Material.GLOWSTONE)); assertTrue(addon.wallBlocks(Material.GLOWSTONE));
assertTrue(Walls.wallBlocks(Material.ACACIA_DOOR)); assertTrue(addon.wallBlocks(Material.ACACIA_DOOR));
assertTrue(Walls.wallBlocks(Material.HOPPER)); assertTrue(addon.wallBlocks(Material.HOPPER));
assertTrue(Walls.wallBlocks(Material.PURPLE_STAINED_GLASS_PANE)); assertTrue(addon.wallBlocks(Material.PURPLE_STAINED_GLASS_PANE));
assertFalse(Walls.wallBlocks(Material.BIRCH_TRAPDOOR)); assertFalse(addon.wallBlocks(Material.BIRCH_TRAPDOOR));
} }
/** /**
@ -217,13 +215,13 @@ public class WallsTest {
public void testWallBlocksNoGlowStoneNoPanes() { public void testWallBlocksNoGlowStoneNoPanes() {
s.setAllowGlowstone(false); s.setAllowGlowstone(false);
s.setAllowPanes(false); s.setAllowPanes(false);
assertFalse(Walls.wallBlocks(Material.ACACIA_BOAT)); assertFalse(addon.wallBlocks(Material.ACACIA_BOAT));
assertTrue(Walls.wallBlocks(Material.GLASS)); assertTrue(addon.wallBlocks(Material.GLASS));
assertFalse(Walls.wallBlocks(Material.GLOWSTONE)); assertFalse(addon.wallBlocks(Material.GLOWSTONE));
assertTrue(Walls.wallBlocks(Material.ACACIA_DOOR)); assertTrue(addon.wallBlocks(Material.ACACIA_DOOR));
assertTrue(Walls.wallBlocks(Material.HOPPER)); assertTrue(addon.wallBlocks(Material.HOPPER));
assertFalse(Walls.wallBlocks(Material.PURPLE_STAINED_GLASS_PANE)); assertFalse(addon.wallBlocks(Material.PURPLE_STAINED_GLASS_PANE));
assertFalse(Walls.wallBlocks(Material.BIRCH_TRAPDOOR)); assertFalse(addon.wallBlocks(Material.BIRCH_TRAPDOOR));
} }
/** /**

View File

@ -83,22 +83,22 @@ public class EcoSystemManagerTest {
// Liquid false // Liquid false
when(air.isEmpty()).thenReturn(true); when(air.isEmpty()).thenReturn(true);
when(air.isPassable()).thenReturn(true); when(air.isPassable()).thenReturn(true);
when(air.getRelative(eq(BlockFace.UP))).thenReturn(air); when(air.getRelative(BlockFace.UP)).thenReturn(air);
// Plant // Plant
// Empty false // Empty false
// Liquid false // Liquid false
when(plant.isPassable()).thenReturn(true); when(plant.isPassable()).thenReturn(true);
when(plant.getRelative(eq(BlockFace.UP))).thenReturn(air); when(plant.getRelative(BlockFace.UP)).thenReturn(air);
// Liquid // Liquid
// Empty false // Empty false
when(liquid.isLiquid()).thenReturn(true); when(liquid.isLiquid()).thenReturn(true);
when(liquid.isPassable()).thenReturn(true); when(liquid.isPassable()).thenReturn(true);
when(liquid.getRelative(eq(BlockFace.UP))).thenReturn(air); when(liquid.getRelative(BlockFace.UP)).thenReturn(air);
// Default for block // Default for block
// Empty false // Empty false
// Passable false // Passable false
// Liquid false // Liquid false
when(block.getRelative(eq(BlockFace.UP))).thenReturn(air); when(block.getRelative(BlockFace.UP)).thenReturn(air);
// Recipe // Recipe
when(recipe.noMobs()).thenReturn(true); when(recipe.noMobs()).thenReturn(true);

View File

@ -71,12 +71,14 @@ public class GreenhouseFinderTest {
when(Tag.TRAPDOORS.isTagged(Material.BIRCH_TRAPDOOR)).thenReturn(true); when(Tag.TRAPDOORS.isTagged(Material.BIRCH_TRAPDOOR)).thenReturn(true);
// Declare mock after mocking Bukkit // Declare mock after mocking Bukkit
roof = mock(Roof.class); roof = mock(Roof.class);
when(roof.roofBlocks(any())).thenCallRealMethod();
// Location // Location
when(location.getBlockX()).thenReturn(5); when(location.getBlockX()).thenReturn(5);
when(location.getBlockY()).thenReturn(14); when(location.getBlockY()).thenReturn(14);
when(location.getBlockZ()).thenReturn(25); when(location.getBlockZ()).thenReturn(25);
when(location.getWorld()).thenReturn(world); when(location.getWorld()).thenReturn(world);
// Addon
when(addon.wallBlocks(any())).thenCallRealMethod();
// Block // Block
when(cache.getBlockType(any())).thenReturn(Material.GLASS); when(cache.getBlockType(any())).thenReturn(Material.GLASS);
when(cache.getBlockType(anyInt(), anyInt(), anyInt())).thenReturn(Material.GLASS); when(cache.getBlockType(anyInt(), anyInt(), anyInt())).thenReturn(Material.GLASS);
@ -94,7 +96,7 @@ public class GreenhouseFinderTest {
when(cache.getMaxHeight()).thenReturn(30); when(cache.getMaxHeight()).thenReturn(30);
gf = new GreenhouseFinder(); gf = new GreenhouseFinder(addon);
cc = new CounterCheck(); cc = new CounterCheck();
} }