Compare commits

...

88 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 5fd9cbfd36
Release 1.7.3 (#107)
* 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

---------

Co-authored-by: tastybento <tastybento@wasteofplastic.com>
Co-authored-by: tastybento <tastybento@users.noreply.github.com>
2023-04-15 15:19: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
tastybento de6a939bb9 Adds support for COCOA #97 2023-01-01 22:29:02 -08:00
tastybento 10a1d63778 Remove debug
https://github.com/BentoBoxWorld/Greenhouses/issues/97
2023-01-01 21:17:39 -08:00
tastybento bba0b33133 Version 1.7.2 2022-12-29 20:00:16 -08:00
tastybento 4b69c39496 Version 1.7.1
Fix - not sure why it didn't survive the merge...
2022-12-29 19:59:14 -08:00
tastybento fe0a794e68 Merge branch 'develop' 2022-12-29 19:47:48 -08:00
tastybento 1975df2732 Fixes #92
A world check was not being done in the overlap check.
2022-12-29 19:33:59 -08:00
tastybento 1f0b579d5a Enables water plants to be grown under water.
Fixes #93
2022-12-29 18:59:50 -08:00
tastybento e5c62047ff Use new switch statement 2022-12-29 11:33:34 -08:00
tastybento 02490d3b85 Fix for glow lichen growing
Fixes https://github.com/BentoBoxWorld/Greenhouses/issues/96
2022-12-29 09:57:21 -08:00
tastybento 717903e346 Version 1.17.1
Java 17 update
2022-12-29 09:56:49 -08:00
Zorua162 61478ff4d5
Fixed issue where greenhouses could not be created below y=0 (#95)
* Fixed issue where greenhouses could not be greated below y=0

* Made the world floor change work with different lower world limits by using World#getMinHeight()
2022-10-30 18:50:40 +02:00
BONNe a96d4d4c67
Release 1.7.0 (#91)
* Version 1.6.1

* Version 1.6.1

* Added Blue Orchids spawning in the Swamp biome

* Version 1.7.0

1.18.1 update

* German translation (#86)

* Translate de.yml via GitLocalize

* Translate de.yml via GitLocalize

Co-authored-by: mt-gitlocalize <mt@gitlocalize.com>
Co-authored-by: xXjojojXx <sven.f92@gmx.de>

* Translate hu.yml via GitLocalize (#87)

Co-authored-by: driverdakid <tamascsiszar99@icloud.com>

* Translate ja.yml via GitLocalize (#88)

Co-authored-by: tastybento <tastybento@wasteofplastic.com>

* Translate zh-CN.yml via GitLocalize (#89)

Co-authored-by: tastybento <tastybento@wasteofplastic.com>

* Code refactoring around BoundingBox

* Fix test.

* Remove saving of greenhouses on exit.

https://github.com/BentoBoxWorld/Greenhouses/issues/85

* Add Pladdon Class (#90)

* Add Pladdon Class

Add Greenhouses Pladdon class.

* Add Spigot Annotations API

* Fix test. Avoid ambiguity.

* Add natural spawn protection listener.

Fixes #84

* Update gitignore for Eclipse

* Remove some code smells.

Co-authored-by: tastybento <tastybento@wasteofplastic.com>
Co-authored-by: Florian CUNY <poslovitch@bentobox.world>
Co-authored-by: gitlocalize-app[bot] <55277160+gitlocalize-app[bot]@users.noreply.github.com>
Co-authored-by: mt-gitlocalize <mt@gitlocalize.com>
Co-authored-by: xXjojojXx <sven.f92@gmx.de>
Co-authored-by: driverdakid <tamascsiszar99@icloud.com>
2022-05-16 14:49:06 +03:00
tastybento 8af2b2057d Remove some code smells. 2022-03-20 15:09:45 +00:00
tastybento 6f6745e849 Update gitignore for Eclipse 2022-03-20 15:01:53 +00:00
BONNe 0a016c2eaa Add natural spawn protection listener.
Fixes #84
2022-02-27 21:33:21 +02:00
tastybento d64be1c518 Fix test. Avoid ambiguity. 2022-02-19 11:34:27 -08:00
BONNe e2b779a9cb
Add Pladdon Class (#90)
* Add Pladdon Class

Add Greenhouses Pladdon class.

* Add Spigot Annotations API
2022-02-19 11:17:08 -08:00
tastybento 06230e4957 Remove saving of greenhouses on exit.
https://github.com/BentoBoxWorld/Greenhouses/issues/85
2022-01-01 16:03:04 -08:00
tastybento 0e76838721 Fix test. 2021-12-31 15:38:19 -08:00
tastybento 9a7cad85af Merge branch 'develop' of https://github.com/BentoBoxWorld/Greenhouses.git into develop 2021-12-31 13:32:15 -08:00
tastybento 5808c5933a Code refactoring around BoundingBox 2021-12-31 13:32:03 -08:00
gitlocalize-app[bot] cf7b1c7164
Translate zh-CN.yml via GitLocalize (#89)
Co-authored-by: tastybento <tastybento@wasteofplastic.com>
2021-12-31 09:25:28 -08:00
gitlocalize-app[bot] c5b80b2f4a
Translate ja.yml via GitLocalize (#88)
Co-authored-by: tastybento <tastybento@wasteofplastic.com>
2021-12-31 09:24:08 -08:00
gitlocalize-app[bot] b90559122b
Translate hu.yml via GitLocalize (#87)
Co-authored-by: driverdakid <tamascsiszar99@icloud.com>
2021-12-31 09:20:45 -08:00
gitlocalize-app[bot] df60720e75
German translation (#86)
* Translate de.yml via GitLocalize

* Translate de.yml via GitLocalize

Co-authored-by: mt-gitlocalize <mt@gitlocalize.com>
Co-authored-by: xXjojojXx <sven.f92@gmx.de>
2021-12-31 09:18:46 -08:00
tastybento 6e41588405 Merged branch 'develop' https://github.com/BentoBoxWorld/Greenhouses.git
into develop

Conflicts:
	pom.xml
2021-12-21 14:29:52 -08:00
tastybento b7c30cb608 Version 1.7.0
1.18.1 update
2021-12-21 14:28:31 -08:00
Florian CUNY 925e50eb46
Added Blue Orchids spawning in the Swamp biome 2021-10-31 11:16:06 +01:00
Florian CUNY 61e1db5f43
Version 1.6.1 2021-10-31 11:14:13 +01:00
tastybento 024b311180 Version 1.6.1 2021-09-26 13:01:01 -07:00
tastybento 4aec983c81 Cauldron will fill up with snow
Also, snow will pile up as expected.

https://github.com/BentoBoxWorld/Greenhouses/issues/83
2021-09-26 12:54:46 -07:00
tastybento c660575456 Remove lag from legacy Material support issue
Spigot pulls in all the legacy marerials if you loop through the
material values.
2021-09-25 11:34:36 -07:00
tastybento 354806c060 Fills up cauldrons with snow.
Fixes https://github.com/BentoBoxWorld/Greenhouses/issues/82
2021-09-25 11:19:39 -07:00
tastybento 47bead9145 Fixes bug where floor blocks were not converted.
This was introduced by commit db3054ab0c

https://github.com/BentoBoxWorld/Greenhouses/issues/81
2021-09-25 11:04:01 -07:00
tastybento 8a3e0eb403 Conde clean up from IntelliJ 2021-09-18 10:33:48 -07:00
tastybento 4708a70e24 Added support for ceiling growing plants.
VINES, WEEPING_VINES_PLANT, SPORE_BLOSSOM, CAVE_VINES_PLANT,
TWISTING_VINES_PLANT

https://github.com/BentoBoxWorld/Greenhouses/issues/81
2021-09-18 10:12:47 -07:00
tastybento 308cb7f16a Version 1.6.0
Changes to Java 16 surefire module declarations.
2021-09-18 10:08:24 -07:00
tastybento 818f6fc925 Null checks. 2021-08-01 16:17:12 -07:00
tastybento 0b9019fbfa Fix test 2021-08-01 15:29:36 -07:00
tastybento e61e76134b Make BiomeRecipe nonNull 2021-08-01 15:26:21 -07:00
tastybento a44d9d1578 Java 16 Action 2021-07-31 23:13:22 -07:00
tastybento 38de645e6b Move to Java 16 2021-07-31 23:10:07 -07:00
tastybento de4a4c17c0 Merge branch 'develop' of https://github.com/BentoBoxWorld/Greenhouses.git into develop 2021-07-31 15:09:30 -07:00
Rosskaman d1d3004262
Allow omitting LocalMaterial in biomes.yml if you don't want a local blo… (#79) 2021-05-09 11:47:54 -07:00
Rosskaman db3054ab0c
Optimize convertBlocks and convertBlock methods by reducing the amoun… (#78) 2021-04-19 07:26:43 -07:00
tastybento 9621b2f5eb Version 1.5.4 2021-04-08 17:15:08 -07:00
tastybento 7154877f14 Blocks under the walls were classed as walls.
Fixes https://github.com/BentoBoxWorld/Greenhouses/issues/77
2021-04-08 17:13:32 -07:00
tastybento 80c985ad7d Version 1.5.3 2021-03-07 13:46:34 -08:00
43 changed files with 1681 additions and 1046 deletions

View File

@ -11,21 +11,22 @@ jobs:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Set up JDK 11
uses: actions/setup-java@v1
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: 11
distribution: 'adopt'
java-version: 17
- name: Cache SonarCloud packages
uses: actions/cache@v1
uses: actions/cache@v3
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Maven packages
uses: actions/cache@v1
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/target/
/.classpath
/.project
/.DS_Store
/Greenhouses-addon.iml
/.idea/

View File

@ -1,8 +1,9 @@
# Greenhouses - an add-on for BentoBox
## Note for 1.15.x + servers
Biomes have changed so that they take up a 4x4 area and so greenhouse biomes now can bleed outside of the greenhouse. Unfortunately, this cannot be mitigated (as far as I know). If you have a good imagination, you can say that the biome of the greenhouse influences the surroundings a bit and it is natural! So it's a feature, not a bug!
[![Build Status](https://ci.codemc.org/buildStatus/icon?job=BentoBoxWorld/Greenhouses)](https://ci.codemc.org/job/BentoBoxWorld/job/Greenhouses/)[
![Bugs](https://sonarcloud.io/api/project_badges/measure?project=BentoBoxWorld_Greenhouses&metric=bugs)](https://sonarcloud.io/dashboard?id=BentoBoxWorld_Greenhouses)
[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=BentoBoxWorld_Greenhouses&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=BentoBoxWorld_Greenhouses)
[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=BentoBoxWorld_Greenhouses&metric=ncloc)](https://sonarcloud.io/dashboard?id=BentoBoxWorld_Greenhouses)
## About
@ -14,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)
* 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.
* Greenhouses can run in multiple worlds.
* Easy to use GUI shows greenhouse recipes (e.g. **/is greenhouses**)
@ -26,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.
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.
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.
@ -41,7 +42,7 @@ This example is for when you are in the BSkyBlock world. For AcidIsland, just us
## 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.
* 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.

42
pom.xml
View File

@ -43,15 +43,15 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<powermock.version>2.0.2</powermock.version>
<java.version>17</java.version>
<powermock.version>2.0.9</powermock.version>
<!-- More visible way how to change dependency versions -->
<spigot.version>1.16.3-R0.1-SNAPSHOT</spigot.version>
<bentobox.version>1.16.0</bentobox.version>
<spigot.version>1.20.4-R0.1-SNAPSHOT</spigot.version>
<bentobox.version>2.0.0-SNAPSHOT</bentobox.version>
<!-- Revision variable removes warning about dynamic version -->
<revision>${build.version}-SNAPSHOT</revision>
<!-- This allows to change between versions and snapshots. -->
<build.version>1.5.2</build.version>
<build.version>1.8.0</build.version>
<build.number>-LOCAL</build.number>
<sonar.projectKey>BentoBoxWorld_Greenhouses</sonar.projectKey>
<sonar.organization>bentobox-world</sonar.organization>
@ -126,7 +126,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.0.0</version>
<version>3.11.2</version>
<scope>test</scope>
</dependency>
<dependency>
@ -185,14 +185,21 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<release>${java.version}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<version>3.1.0</version>
<configuration>
<argLine>
${argLine}
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens java.base/java.util.concurrent=ALL-UNNAMED
</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -207,10 +214,12 @@
<show>public</show>
<failOnError>false</failOnError>
<additionalJOption>-Xdoclint:none</additionalJOption>
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<phase>install</phase>
<goals>
<goal>jar</goal>
</goals>
@ -243,30 +252,37 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.3</version>
<version>0.8.10</version>
<configuration>
<append>true</append>
<excludes>
<!-- This is required to prevent Jacoco from adding
synthetic fields to a JavaBean class (causes errors in testing) -->
<exclude>**/*Names*</exclude>
<!-- Prevents the Material is too large to mock error -->
<exclude>org/bukkit/Material*</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>pre-unit-test</id>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>post-unit-test</id>
<id>report</id>
<goals>
<goal>report</goal>
</goals>
<configuration>
<formats>
<format>XML</format>
</formats>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
</project>

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.Mode;
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.RecipeManager;
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)
.mode(Mode.BASIC)
.type(Type.PROTECTION).build();
private static Greenhouses instance;
private final Config<Settings> config;
public static Greenhouses getInstance() {
return instance;
}
/**
* Constructor
*/
public Greenhouses() {
super();
instance = this;
config = new Config<>(this, Settings.class);
}
@ -92,9 +87,8 @@ public class Greenhouses extends Addon {
*/
@Override
public void onDisable() {
if (manager != null) {
manager.saveGreenhouses();
if (manager.getEcoMgr() != null) manager.getEcoMgr().cancel();
if (manager != null && manager.getEcoMgr() != null) {
manager.getEcoMgr().cancel();
}
}
@ -123,4 +117,15 @@ public class Greenhouses extends Addon {
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

@ -0,0 +1,18 @@
package world.bentobox.greenhouses;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.Pladdon;
/**
* @author tastybento
*/
public class GreenhousesPladdon extends Pladdon
{
@Override
public Addon getAddon()
{
return new Greenhouses();
}
}

View File

@ -1,6 +1,8 @@
package world.bentobox.greenhouses.data;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import org.bukkit.Location;
@ -157,23 +159,27 @@ public class Greenhouse implements DataObject {
* @param v the roofHopperLocation to set
*/
public void setRoofHopperLocation(@Nullable Vector v) {
this.roofHopperLocation = v == null ? null : v.toLocation(getWorld());
if (v == null || getWorld() == null) {
this.roofHopperLocation = null;
} else {
this.roofHopperLocation = v.toLocation(getWorld());
}
}
/**
* @return the boundingBox
*/
@Nullable
@NonNull
public BoundingBox getBoundingBox() {
return boundingBox;
return Objects.requireNonNull(boundingBox);
}
/**
* @return a bounding box of the greenhouse that does not include the walls or roof
*/
@Nullable
@NonNull
public BoundingBox getInternalBoundingBox() {
return boundingBox == null ? null : boundingBox.clone().expand(-1D);
return getBoundingBox().clone().expand(-1D);
}
/**
@ -205,7 +211,7 @@ public class Greenhouse implements DataObject {
*/
@Nullable
public World getWorld() {
return this.getLocation().getWorld();
return this.getLocation() == null ? null : this.getLocation().getWorld();
}
/**
@ -214,7 +220,9 @@ public class Greenhouse implements DataObject {
* @return true if inside the greenhouse
*/
public boolean contains(Location location2) {
return location.getWorld().equals(location2.getWorld()) && boundingBox.contains(location2.toVector());
return getLocation() != null && getLocation().getWorld() != null
&& getLocation().getWorld().equals(location2.getWorld())
&& getBoundingBox().contains(location2.toVector());
}
/**
@ -228,11 +236,11 @@ public class Greenhouse implements DataObject {
/**
* Get the biome recipe for this greenhouse
* @return biome recipe or null
* @return biome recipe or a degenerate recipe
*/
@Nullable
@NonNull
public BiomeRecipe getBiomeRecipe() {
return RecipeManager.getBiomeRecipies(biomeRecipeName).orElse(null);
return RecipeManager.getBiomeRecipies(biomeRecipeName).orElse(new BiomeRecipe());
}
/**
@ -245,9 +253,9 @@ public class Greenhouse implements DataObject {
/**
* @return the missingBlocks
*/
@Nullable
@NonNull
public Map<Material, Integer> getMissingBlocks() {
return missingBlocks;
return Objects.requireNonNullElseGet(missingBlocks, HashMap::new);
}
/**
@ -256,11 +264,13 @@ public class Greenhouse implements DataObject {
* @return true if wall or roof block
*/
public boolean isRoofOrWallBlock(Location l) {
return ((l.getBlockY() == getCeilingHeight() - 1)
|| l.getBlockX() == (int)getBoundingBox().getMinX()
|| l.getBlockX() == (int)getBoundingBox().getMaxX() - 1
|| l.getBlockZ() == (int)getBoundingBox().getMinZ()
|| l.getBlockZ() == (int)getBoundingBox().getMaxZ() - 1
);
final BoundingBox bb = getBoundingBox();
return (l.getBlockY() > this.getFloorHeight()
&& ((l.getBlockY() == getCeilingHeight() - 1)
|| l.getBlockX() == (int)bb.getMinX()
|| l.getBlockX() == (int)bb.getMaxX() - 1
|| l.getBlockZ() == (int)bb.getMinZ()
|| l.getBlockZ() == (int)bb.getMaxZ() - 1
));
}
}

View File

@ -1,16 +1,18 @@
package world.bentobox.greenhouses.greenhouse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
@ -23,11 +25,13 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.block.data.type.Cocoa;
import org.bukkit.block.data.type.GlowLichen;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Hoglin;
import org.bukkit.entity.Piglin;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import com.google.common.base.Enums;
@ -37,6 +41,7 @@ import com.google.common.collect.Multimap;
import world.bentobox.bentobox.util.Util;
import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.data.Greenhouse;
import world.bentobox.greenhouses.managers.EcoSystemManager.GrowthBlock;
import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult;
import world.bentobox.greenhouses.world.AsyncWorldCache;
@ -49,13 +54,37 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
private String name;
private String friendlyName;
private static final List<Material> CEILING_PLANTS = new ArrayList<>();
static {
CEILING_PLANTS.add(Material.VINE);
Enums.getIfPresent(Material.class, "SPORE_BLOSSOM").toJavaUtil().ifPresent(CEILING_PLANTS::add);
Enums.getIfPresent(Material.class, "CAVE_VINES_PLANT").toJavaUtil().ifPresent(CEILING_PLANTS::add);
Enums.getIfPresent(Material.class, "TWISTING_VINES_PLANT").toJavaUtil().ifPresent(CEILING_PLANTS::add);
Enums.getIfPresent(Material.class, "WEEPING_VINES_PLANT").toJavaUtil().ifPresent(CEILING_PLANTS::add);
}
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> SIDE_BLOCKS = Arrays.asList( BlockFace.EAST, BlockFace.NORTH, BlockFace.SOUTH, 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
// Material, Type, Qty. There can be more than one type of material required
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> underwaterPlants = new TreeMap<>();
// Mobs
// Entity Type, Material to Spawn on, Probability
@ -63,8 +92,7 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
// Conversions
// Original Material, Original Type, New Material, New Type, Probability
//private final Map<Material, GreenhouseBlockConversions> conversionBlocks = new EnumMap<>(Material.class);
private Multimap<Material, GreenhouseBlockConversions> conversionBlocks = ArrayListMultimap.create();
private final Multimap<Material, GreenhouseBlockConversions> conversionBlocks = ArrayListMultimap.create();
private int mobLimit;
private int waterCoverage;
@ -73,8 +101,12 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
private String permission = "";
private final Random random = new Random();
private int maxMob;
/**
* Create a degenerate recipe with nothing in it
*/
public BiomeRecipe() {}
/**
@ -107,7 +139,7 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
/**
* @param mobType - entity type
* @param mobProbability - reltive probability
* @param mobProbability - relative probability
* @param mobSpawnOn - material to spawn on
* @return true if add is successful
*/
@ -121,7 +153,7 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
mobTree.put(lastProb + probability, new GreenhouseMob(mobType, mobSpawnOn));
return true;
} else {
addon.logError("Mob chances add up to > 100% in " + type.toString() + " biome recipe! Skipping " + mobType.toString());
addon.logError("Mob chances add up to > 100% in " + type.toString() + " biome recipe! Skipping " + mobType);
return false;
}
}
@ -136,11 +168,12 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
*/
public boolean addPlants(Material plantMaterial, double plantProbability, Material plantGrowOn) {
double probability = plantProbability/100;
TreeMap<Double, GreenhousePlant> map = UNDERWATER_PLANTS.contains(plantMaterial) ? underwaterPlants : plantTree;
// 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) {
// Add to probability tree
plantTree.put(lastProb + probability, new GreenhousePlant(plantMaterial, plantGrowOn));
map.put(lastProb + probability, new GreenhousePlant(plantMaterial, plantGrowOn));
} else {
addon.logError("Plant chances add up to > 100% in " + type.toString() + " biome recipe! Skipping " + plantMaterial.toString());
return false;
@ -176,24 +209,30 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
* @return set of results from the check
*/
private Set<GreenhouseResult> checkRecipeAsync(CompletableFuture<Set<GreenhouseResult>> r, Greenhouse gh) {
AsyncWorldCache cache = new AsyncWorldCache(gh.getWorld());
Set<GreenhouseResult> result = new HashSet<>();
AsyncWorldCache cache = new AsyncWorldCache(addon, gh.getWorld());
long area = gh.getArea();
Map<Material, Integer> blockCount = new EnumMap<>(Material.class);
// Look through the greenhouse and count what is in there
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);
}
}
}
Map<Material, Integer> blockCount = countBlocks(gh, cache);
// Calculate % water, ice and lava ratios and check them
Set<GreenhouseResult> result = checkRatios(blockCount, area);
// 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);
}
// 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 lavaRatio = (double)blockCount.getOrDefault(Material.LAVA, 0)/area * 100;
int ice = blockCount.entrySet().stream().filter(en -> en.getKey().equals(Material.ICE)
@ -221,37 +260,55 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
if (iceCoverage > 0 && iceRatio < iceCoverage) {
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;
}
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
* @param gh - greenhouse
* @param b - block to check
*/
public void convertBlock(Greenhouse gh, Block b) {
conversionBlocks.get(b.getType()).stream().filter(Objects::nonNull)
.filter(bc -> random.nextDouble() < bc.getProbability())
.forEach(bc -> {
// Check if the block is in the right area, up, down, n,s,e,w
if (ADJ_BLOCKS.stream().map(b::getRelative)
.filter(r -> gh.contains(r.getLocation()))
.map(Block::getType)
.anyMatch(m -> bc.getLocalMaterial() == null || m == bc.getLocalMaterial())) {
// Convert!
b.setType(bc.getNewMaterial());
public void convertBlock(Block b) {
Material bType = b.getType();
// 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)) {
for(GreenhouseBlockConversions conversionOption : conversionBlocks.get(bType)) {
rollTheDice(b, conversionOption);
}
});
}
}
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());
}
}
}
/**
@ -337,28 +394,24 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
Location spawnLoc = b.getLocation().clone().add(new Vector(0.5, 0, 0.5));
return getRandomMob()
// Check if the spawn on block matches, if it exists
.filter(m -> m.getMobSpawnOn().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
.map(m -> {
Entity entity = b.getWorld().spawnEntity(spawnLoc, m.getMobType());
if (entity != null) {
preventZombie(entity);
return addon
.getManager()
.getMap()
.getGreenhouse(b.getLocation()).map(gh -> {
BoundingBox interior = gh.getBoundingBox().clone();
interior.expand(-1, -1, -1);
if (!interior.contains(entity.getBoundingBox())) {
entity.remove();
return false;
}
return true;
}).orElse(false);
}
return false;
Entity entity = b.getWorld().spawnEntity(spawnLoc, m.mobType());
preventZombie(entity);
return addon
.getManager()
.getMap()
.getGreenhouse(b.getLocation()).map(gh -> {
if (!gh.getInternalBoundingBox().contains(entity.getBoundingBox())) {
entity.remove();
return false;
}
return true;
}).orElse(false);
}).orElse(false);
}
/**
@ -375,13 +428,11 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
return;
}
if (entity instanceof Piglin) {
Piglin p = (Piglin)entity;
if (entity instanceof Piglin p) {
p.setImmuneToZombification(true);
return;
}
if (entity instanceof Hoglin) {
Hoglin h = (Hoglin)entity;
if (entity instanceof Hoglin h) {
h.setImmuneToZombification(true);
}
}
@ -395,18 +446,21 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
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
double r = random.nextDouble();
Double key = plantTree.ceilingKey(r);
return key == null ? Optional.empty() : Optional.ofNullable(plantTree.get(key));
Double key = underwater ? underwaterPlants.ceilingKey(r) : plantTree.ceilingKey(r);
if (key == null) {
return Optional.empty();
}
return Optional.ofNullable(underwater ? underwaterPlants.get(key) : plantTree.get(key));
}
/**
* @return a list of blocks that are required for this recipe
*/
public List<String> getRecipeBlocks() {
return requiredBlocks.entrySet().stream().map(en -> Util.prettifyText(en.getKey().toString()) + " x " + en.getValue()).collect(Collectors.toList());
return requiredBlocks.entrySet().stream().map(en -> Util.prettifyText(en.getKey().toString()) + " x " + en.getValue()).toList();
}
/**
@ -418,29 +472,14 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
/**
* Plants a plant on block bl if it makes sense.
* @param bl - block
* @param block - block that can have growth
* @param underwater - if the block is underwater or not
* @return true if successful
*/
public boolean growPlant(Block bl) {
if (!bl.isEmpty()) {
return false;
}
return getRandomPlant().map(p -> {
if (bl.getY() != 0 && p.getPlantGrownOn().map(m -> m.equals(bl.getRelative(BlockFace.DOWN).getType())).orElse(false)) {
BlockData dataBottom = p.getPlantMaterial().createBlockData();
if (dataBottom instanceof Bisected) {
((Bisected) dataBottom).setHalf(Bisected.Half.BOTTOM);
BlockData dataTop = p.getPlantMaterial().createBlockData();
((Bisected) dataTop).setHalf(Bisected.Half.TOP);
if (bl.getRelative(BlockFace.UP).getType().equals(Material.AIR)) {
bl.setBlockData(dataBottom, false);
bl.getRelative(BlockFace.UP).setBlockData(dataTop, false);
} else {
return false; // No room
}
} else {
bl.setBlockData(dataBottom, false);
}
public boolean growPlant(GrowthBlock block, boolean underwater) {
Block bl = block.block();
return getRandomPlant(underwater).map(p -> {
if (bl.getY() != 0 && canGrowOn(block, p) && plantIt(bl, p)) {
bl.getWorld().spawnParticle(Particle.SNOWBALL, bl.getLocation(), 10, 2, 2, 2);
return true;
}
@ -448,6 +487,144 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
}).orElse(false);
}
/**
* 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();
// Check if this is a double-height plant
if (dataBottom instanceof Bisected bi) {
// Double-height plant
bi.setHalf(Bisected.Half.BOTTOM);
BlockData dataTop = p.plantMaterial().createBlockData();
((Bisected) dataTop).setHalf(Bisected.Half.TOP);
if (bl.getRelative(BlockFace.UP).getType().equals(Material.AIR)) {
bl.setBlockData(dataBottom, false);
bl.getRelative(BlockFace.UP).setBlockData(dataTop, false);
} else {
return false; // No room
}
} else if (p.plantMaterial().equals(Material.GLOW_LICHEN)) {
return placeLichen(bl);
} else if (p.plantMaterial().equals(Material.COCOA)) {
return placeCocoa(bl);
} else {
if (dataBottom instanceof Waterlogged wl) {
wl.setWaterlogged(underwater);
bl.setBlockData(wl, false);
} else {
// Single height plant
bl.setBlockData(dataBottom, false);
}
}
return true;
}
private boolean placeCocoa(Block bl) {
// Get the source block below this one
Block b = bl.getRelative(BlockFace.DOWN);
if (!b.getType().equals(Material.JUNGLE_LOG)) {
return false;
}
// Find a spot for cocoa
BlockFace d = null;
for (BlockFace adj : SIDE_BLOCKS) {
if (b.getRelative(adj).getType().equals(Material.AIR)) {
d = adj;
break;
}
}
if (d == null) {
return false;
}
Block bb = b.getRelative(d);
bb.setType(Material.COCOA);
BlockFace opp = d.getOppositeFace();
if(bb.getBlockData() instanceof Cocoa v){
v.setFacing(opp);
bb.setBlockData(v);
bb.getState().setBlockData(v);
bb.getState().update(true);
return true;
}
return false;
}
/**
* 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) {
Material type = b.getRelative(adj).getType();
if (type.equals(Material.AIR) || type.equals(Material.WATER)) {
d = adj;
if (type.equals(Material.WATER)) {
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) {
// Ceiling plants can only grow on ceiling blocks
if (CEILING_PLANTS.contains(p.plantMaterial()) && Boolean.TRUE.equals(block.floor())) {
return false;
}
// Underwater plants can only be placed in water and regular plants cannot be placed in water
if (block.block().getType().equals(Material.WATER)) {
if (!UNDERWATER_PLANTS.contains(p.plantMaterial())) {
return false;
}
} 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());
}
/**
* @param friendlyName - set the friendly name
*/
@ -549,7 +726,22 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
* @return the mob types that may spawn due to this recipe
*/
public Set<EntityType> getMobTypes() {
return mobTree.values().stream().map(GreenhouseMob::getMobType).collect(Collectors.toSet());
return mobTree.values().stream().map(GreenhouseMob::mobType).collect(Collectors.toSet());
}
/**
* Set the maximum number of mobs in a greenhouse
* @param maxMob maximum
*/
public void setMaxMob(int maxMob) {
this.maxMob = maxMob;
}
/**
* @return the maxMob
*/
public int getMaxMob() {
return maxMob;
}

View File

@ -2,41 +2,4 @@ package world.bentobox.greenhouses.greenhouse;
import org.bukkit.Material;
class GreenhouseBlockConversions {
private final Material oldMaterial;
private final Material newMaterial;
private final double probability;
private final Material localMaterial;
public GreenhouseBlockConversions(Material oldMaterial, Material newMaterial, double probability, Material localMaterial) {
this.oldMaterial = oldMaterial;
this.newMaterial = newMaterial;
this.probability = probability;
this.localMaterial = localMaterial;
}
/**
* @return the oldMaterial
*/
public Material getOldMaterial() {
return oldMaterial;
}
/**
* @return the newMaterial
*/
public Material getNewMaterial() {
return newMaterial;
}
/**
* @return the probability
*/
public double getProbability() {
return probability;
}
/**
* @return the localMaterial
*/
public Material getLocalMaterial() {
return localMaterial;
}
}
record GreenhouseBlockConversions (Material oldMaterial, Material newMaterial, double probability, Material localMaterial) { }

View File

@ -1,31 +1,6 @@
package world.bentobox.greenhouses.greenhouse;
import java.util.Optional;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
class GreenhouseMob {
private final EntityType mobType;
private final Material mobSpawnOn;
/**
* @param mobType - entity type of mob
* @param mobSpawnOn - material on which it much spawn, or null if any
*/
public GreenhouseMob(EntityType mobType, Material mobSpawnOn) {
this.mobType = mobType;
this.mobSpawnOn = mobSpawnOn;
}
/**
* @return the mobType
*/
public EntityType getMobType() {
return mobType;
}
/**
* @return the mobSpawnOn
*/
public Optional<Material> getMobSpawnOn() {
return Optional.of(mobSpawnOn);
}
}
record GreenhouseMob(EntityType mobType, Material mobSpawnOn) { }

View File

@ -1,32 +1,5 @@
package world.bentobox.greenhouses.greenhouse;
import java.util.Optional;
import org.bukkit.Material;
class GreenhousePlant {
private final Material plantMaterial;
private final Material plantGrownOn;
/**
* Describes a recipe plant
* @param plantMaterial - material
* @param plantGrownOn - material on which this grows
*/
public GreenhousePlant(Material plantMaterial,Material plantGrownOn) {
this.plantMaterial = plantMaterial;
this.plantGrownOn = plantGrownOn;
}
/**
* @return the plantMaterial
*/
public Material getPlantMaterial() {
return plantMaterial;
}
/**
* @return the plantGrownOn
*/
public Optional<Material> getPlantGrownOn() {
return Optional.ofNullable(plantGrownOn);
}
}
record GreenhousePlant(Material plantMaterial,Material plantGrownOn) { }

View File

@ -1,12 +1,10 @@
package world.bentobox.greenhouses.greenhouse;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -26,46 +24,41 @@ import world.bentobox.greenhouses.world.AsyncWorldCache;
*
*/
public class Roof extends MinMaxXZ {
private static final List<Material> ROOF_BLOCKS;
static {
List<Material> r = Arrays.stream(Material.values())
.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)) // Hoppers
.collect(Collectors.toList());
ROOF_BLOCKS = Collections.unmodifiableList(r);
}
/**
* 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 static final List<Material> ROOF_BLOCKS = Arrays.stream(Material.values())
.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();
private final AsyncWorldCache cache;
private int height;
private final Location location;
private boolean roofFound;
private final Greenhouses addon;
private final World world;
/**
* Finds a roof from a starting location under the roof and characterizes it
* @param cache
* @param cache async world cache
* @param loc - starting location
*/
public Roof(AsyncWorldCache cache, Location loc) {
public Roof(AsyncWorldCache cache, Location loc, Greenhouses addon) {
this.cache = cache;
this.location = loc;
this.addon = addon;
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
@ -125,7 +118,7 @@ public class Roof extends MinMaxXZ {
}
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
int startY = loc.getBlockY();
for (int y = startY; y < world.getMaxHeight(); y++) {
@ -137,7 +130,7 @@ public class Roof extends MinMaxXZ {
}
}
// 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) {
loc = spiralSearch(loc, startY);
if (!roofFound) {
@ -206,14 +199,13 @@ public class Roof extends MinMaxXZ {
}
/**
* Get highest roof block
* @param v - vector of search block
* Get the highest roof block
* @param x - x coord of current search
* @param startY - starting y coord
* @param z - z coord of current search
*/
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
for (int y = startY; y < world.getMaxHeight() && !roofFound; y++) {
if (roofBlocks(cache.getBlockType(x,y,z))) {

View File

@ -1,37 +1,28 @@
package world.bentobox.greenhouses.greenhouse;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.world.AsyncWorldCache;
public class Walls extends MinMaxXZ {
private static final List<Material> WALL_BLOCKS;
static {
List<Material> w = Arrays.stream(Material.values())
.filter(Material::isBlock) // Blocks only, no items
.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)) // Hoppers
.collect(Collectors.toList());
WALL_BLOCKS = Collections.unmodifiableList(w);
}
public static final List<Material> WALL_BLOCKS = Arrays.stream(Material.values())
.filter(Material::isBlock) // Blocks only, no items
.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 final AsyncWorldCache cache;
class WallFinder {
static class WallFinder {
int radiusMinX;
int radiusMaxX;
int radiusMinZ;
@ -70,7 +61,7 @@ public class Walls extends MinMaxXZ {
// The player is under the roof
// Assume the player is inside the greenhouse they are trying to create
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
WallFinder wf = new WallFinder();
minX = loc.getBlockX();
@ -86,7 +77,7 @@ public class Walls extends MinMaxXZ {
minZ--;
maxZ++;
// 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
Bukkit.getScheduler().runTask(BentoBox.getInstance(), () -> r.complete(this));
return this;
@ -160,7 +151,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
int wallBlockCount;
do {
@ -173,22 +164,11 @@ public class Walls extends MinMaxXZ {
}
}
} while( y-- > 0 && wallBlockCount > 0);
} while( y-- > minY && wallBlockCount > 0);
return y + 1;
}
/**
* 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
*/

View File

@ -1,7 +1,5 @@
package world.bentobox.greenhouses.listeners;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
@ -34,13 +32,8 @@ public class GreenhouseEvents implements Listener {
private static final String BIOME = "[biome]";
private static final Set<Biome> NETHER_BIOMES;
static {
Set<Biome> nb = new HashSet<>();
nb.add(Biome.NETHER_WASTES);
nb.add(Biome.WARPED_FOREST);
nb.add(Biome.CRIMSON_FOREST);
nb.add(Biome.SOUL_SAND_VALLEY);
nb.add(Biome.BASALT_DELTAS);
NETHER_BIOMES = Collections.unmodifiableSet(nb);
NETHER_BIOMES = Set.of(Biome.NETHER_WASTES, Biome.WARPED_FOREST, Biome.CRIMSON_FOREST,
Biome.SOUL_SAND_VALLEY, Biome.BASALT_DELTAS);
}
private final Greenhouses addon;
@ -115,10 +108,18 @@ public class GreenhouseEvents implements Listener {
handleTransition(User.getInstance(e.getPlayer()), e.getTo(), e.getFrom());
}
/**
* @param user user
* @param toLoc to location
* @param fromLoc from location
*/
private void handleTransition(User user, Location toLoc, Location fromLoc) {
if (user == null) {
return;
}
Optional<Greenhouse> to = addon.getManager().getMap().getGreenhouse(toLoc);
Optional<Greenhouse> from = addon.getManager().getMap().getGreenhouse(fromLoc);
if (!to.isPresent() && !from.isPresent()) {
if (to.isEmpty() && from.isEmpty()) {
return;
}
if (to.isPresent() && from.isPresent()) {
@ -131,15 +132,13 @@ public class GreenhouseEvents implements Listener {
return;
}
// from is a greenhouse
if (from.isPresent() && !to.isPresent()) {
if (from.isPresent()) {
// Exiting
user.sendMessage("greenhouses.event.leaving", BIOME, from.get().getBiomeRecipe().getFriendlyName());
return;
}
if (!from.isPresent()) {
// Entering
user.sendMessage("greenhouses.event.entering", BIOME, to.get().getBiomeRecipe().getFriendlyName());
}
// Entering
user.sendMessage("greenhouses.event.entering", BIOME, to.get().getBiomeRecipe().getFriendlyName());
}
@ -163,7 +162,9 @@ public class GreenhouseEvents implements Listener {
addon.getManager().getMap().getGreenhouse(e.getBlock().getLocation())
.filter(g -> g.isRoofOrWallBlock(e.getBlock().getLocation()))
.ifPresent(g -> {
user.sendMessage("greenhouses.event.broke", BIOME, Util.prettifyText(g.getOriginalBiome().name()));
if (g.getOriginalBiome() != null) {
user.sendMessage("greenhouses.event.broke", BIOME, Util.prettifyText(g.getOriginalBiome().name()));
}
addon.getManager().removeGreenhouse(g);
});
}

View File

@ -10,6 +10,7 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockFromToEvent;
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.event.entity.CreatureSpawnEvent;
import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.data.Greenhouse;
@ -38,7 +39,7 @@ public class GreenhouseGuard implements Listener {
// 1. inside district or outside - always ok
// 2. inside to outside - allowFlowOut determines
// 3. outside to inside - allowFlowIn determines
if (!to.isPresent() && !from.isPresent()) {
if (to.isEmpty() && from.isEmpty()) {
return;
}
if (to.isPresent() && from.isPresent() && to.equals(from)) {
@ -52,7 +53,7 @@ public class GreenhouseGuard implements Listener {
if (from.isPresent() && addon.getSettings().isAllowFlowOut()) {
return;
}
// Otherwise cancel - the flow is not allowed
// Otherwise, cancel - the flow is not allowed
e.setCancelled(true);
}
@ -64,9 +65,7 @@ public class GreenhouseGuard implements Listener {
public void onPistonPush(BlockPistonExtendEvent e) {
e.setCancelled(e.getBlocks().stream()
.map(Block::getLocation)
.filter(this::inGreenhouse)
.findFirst()
.isPresent());
.anyMatch(this::inGreenhouse));
}
/**
@ -77,11 +76,26 @@ public class GreenhouseGuard implements Listener {
public void onPistonPull(BlockPistonRetractEvent e) {
e.setCancelled(e.getBlocks().stream()
.map(Block::getLocation)
.filter(this::inGreenhouse)
.findFirst()
.isPresent());
.anyMatch(this::inGreenhouse));
}
/**
* Guard Greenhouse from natural entity spawning.
*
* @param spawnEvent the spawn event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onCreatureSpawn(CreatureSpawnEvent spawnEvent)
{
if (CreatureSpawnEvent.SpawnReason.NATURAL == spawnEvent.getSpawnReason())
{
// Natural spawn events should be cancelled. Greenhouse spawns its own mobs.
spawnEvent.setCancelled(this.inGreenhouse(spawnEvent.getLocation()));
}
}
private boolean inGreenhouse(Location l) {
return addon.getManager().getMap().getGreenhouse(l).map(g -> g.isRoofOrWallBlock(l)).orElse(false);
}

View File

@ -13,10 +13,10 @@ import world.bentobox.greenhouses.Greenhouses;
*/
public class IslandChangeEvents implements Listener {
private Greenhouses addon;
private final Greenhouses addon;
/**
* @param addon
* @param addon greenhouse addon
*/
public IslandChangeEvents(Greenhouses addon) {
this.addon = addon;

View File

@ -4,6 +4,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@ -12,12 +14,17 @@ import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Hopper;
import org.bukkit.block.data.Levelled;
import org.bukkit.block.data.type.Snow;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockFormEvent;
import org.bukkit.event.weather.WeatherChangeEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.BoundingBox;
import com.google.common.base.Enums;
import world.bentobox.bentobox.util.Util;
import world.bentobox.greenhouses.Greenhouses;
@ -41,13 +48,22 @@ public class SnowTracker implements Listener {
}
/**
* @param gh - greenhouse
* @return true if snow was create, false if not.
*/
private boolean getAirBlocks(Greenhouse gh) {
if (gh.getLocation() == null) {
// Greenhouse does not have a location for some reason.
return false;
}
boolean createdSnow = false;
List<Block> waterBlocks = new ArrayList<>();
for (int x = (int)gh.getBoundingBox().getMinX() + 1; x < (int)gh.getBoundingBox().getMaxX() -1; x++) {
for (int z = (int)gh.getBoundingBox().getMinZ() + 1; z < (int)gh.getBoundingBox().getMaxZ() - 1; z++) {
for (int y = (int)gh.getBoundingBox().getMaxY() - 2; y >= (int)gh.getBoundingBox().getMinY(); y--) {
Block b = gh.getLocation().getWorld().getBlockAt(x, y, z);
final BoundingBox bb = gh.getBoundingBox();
for (int x = (int)bb.getMinX() + 1; x < (int)bb.getMaxX() -1; x++) {
for (int z = (int)bb.getMinZ() + 1; z < (int)bb.getMaxZ() - 1; z++) {
for (int y = (int)bb.getMaxY() - 2; y >= (int)bb.getMinY(); y--) {
Block b = Objects.requireNonNull(gh.getLocation().getWorld()).getBlockAt(x, y, z);
Material type = b.getType();
if (type.equals(Material.AIR) || type.equals(Material.SNOW)) {
b.getWorld().spawnParticle(Particle.SNOWBALL, b.getLocation(), 5);
@ -59,9 +75,11 @@ public class SnowTracker implements Listener {
// Not water
if (Math.random() < addon.getSettings().getSnowDensity()
&& !b.isLiquid()
&& b.getRelative(BlockFace.UP).getType().equals(Material.AIR)) {
b.getRelative(BlockFace.UP).setType(Material.SNOW);
createdSnow = true;
&& (b.getRelative(BlockFace.UP).getType().equals(Material.AIR)
|| b.getRelative(BlockFace.UP).getType().equals(Material.SNOW))) {
createdSnow = placeSnow(b);
}
}
@ -81,9 +99,49 @@ public class SnowTracker implements Listener {
return createdSnow;
}
private boolean placeSnow(Block b) {
Optional<Material> snowCauldron = Enums.getIfPresent(Material.class, "POWDER_SNOW_CAULDRON").toJavaUtil();
if (snowCauldron.isPresent()) {
if (b.getType().equals(Material.CAULDRON)) {
b.setType(snowCauldron.get());
return true;
} else if (b.getType().equals(snowCauldron.get())) {
// Fill up the snow cauldron some more
return incrementLevel(b);
}
}
// Pile up snow
if (b.getRelative(BlockFace.UP).getType().equals(Material.SNOW)) {
return incrementLevel(b.getRelative(BlockFace.UP));
} else {
b.getRelative(BlockFace.UP).setType(Material.SNOW);
}
return true;
}
private boolean incrementLevel(Block b) {
if (b.getBlockData() instanceof Levelled data) {
int max = data.getMaximumLevel();
if (data.getLevel() < max) {
data.setLevel(data.getLevel() + 1);
b.setBlockData(data);
return true;
}
}
if (b.getBlockData() instanceof Snow data) {
int max = data.getMaximumLayers();
if (data.getLayers() < max) {
data.setLayers(data.getLayers() + 1);
b.setBlockData(data);
return true;
}
}
return false;
}
/**
* TODO finish
* @param e
* @param e block form event
*/
@EventHandler
public void onBlockFormEvent(final BlockFormEvent e) {
@ -108,7 +166,7 @@ public class SnowTracker implements Listener {
private void removeWaterBucketAndShake(Greenhouse g) {
// Scatter snow
if (getAirBlocks(g)) {
if (getAirBlocks(g) && g.getRoofHopperLocation() != null) {
Hopper h = ((Hopper)g.getRoofHopperLocation().getBlock().getState());
h.getInventory().removeItem(new ItemStack(Material.WATER_BUCKET));
h.getInventory().addItem(new ItemStack(Material.BUCKET));
@ -117,18 +175,16 @@ public class SnowTracker implements Listener {
private void shakeGlobes(World world) {
addon.getManager().getMap().getGreenhouses().stream().filter(g -> g.getBiomeRecipe().getIceCoverage() > 0)
.filter(g -> (g.getLocation().getWorld().isChunkLoaded(((int) g.getBoundingBox().getMaxX()) >> 4, ((int) g.getBoundingBox().getMaxZ()) >> 4) && g.getLocation().getWorld().isChunkLoaded(((int) g.getBoundingBox().getMinX()) >> 4, ((int) g.getBoundingBox().getMinZ()) >> 4)))
.filter(g -> (Objects.requireNonNull(Objects.requireNonNull(g.getLocation()).getWorld()).isChunkLoaded(((int) g.getBoundingBox().getMaxX()) >> 4, ((int) g.getBoundingBox().getMaxZ()) >> 4) && g.getLocation().getWorld().isChunkLoaded(((int) g.getBoundingBox().getMinX()) >> 4, ((int) g.getBoundingBox().getMinZ()) >> 4)))
.filter(g -> g.getLocation().getWorld().equals(world))
.filter(g -> !g.isBroken())
.filter(g -> g.getRoofHopperLocation() != null)
.forEach(g -> {
Util.getChunkAtAsync(g.getRoofHopperLocation()).thenRun(() -> {
if (g.getRoofHopperLocation().getBlock().getType().equals(Material.HOPPER)
&& ((Hopper)g.getRoofHopperLocation().getBlock().getState()).getInventory().contains(Material.WATER_BUCKET)) {
removeWaterBucketAndShake(g);
}
});
});
.forEach(g -> Util.getChunkAtAsync(g.getRoofHopperLocation()).thenRun(() -> {
if (g.getRoofHopperLocation().getBlock().getType().equals(Material.HOPPER)
&& ((Hopper)g.getRoofHopperLocation().getBlock().getState()).getInventory().contains(Material.WATER_BUCKET)) {
removeWaterBucketAndShake(g);
}
}));
}
private void startSnow(World world) {

View File

@ -9,15 +9,19 @@ import java.util.Objects;
import java.util.Random;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Hopper;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.NumberConversions;
import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.data.Greenhouse;
import world.bentobox.greenhouses.greenhouse.BiomeRecipe;
/**
* Runs the ecosystem for a greenhouse
@ -54,7 +58,7 @@ public class EcoSystemManager {
}
// Kick block conversion growing
long blockTick = addon.getSettings().getBlockTick() * 60 * 20l; // In minutes
long blockTick = addon.getSettings().getBlockTick() * 60 * 20L; // In minutes
if (blockTick > 0) {
addon.log("Kicking off block conversion scheduler every " + addon.getSettings().getBlockTick() + MINUTES);
@ -83,22 +87,40 @@ public class EcoSystemManager {
}
private void convertBlocks(Greenhouse gh) {
if(!gh.getLocation().getWorld().isChunkLoaded(((int) gh.getBoundingBox().getMaxX()) >> 4, ((int) gh.getBoundingBox().getMaxZ()) >> 4) || !gh.getLocation().getWorld().isChunkLoaded(((int) gh.getBoundingBox().getMinX()) >> 4, ((int) gh.getBoundingBox().getMinZ()) >> 4)){
final World world = gh.getWorld();
final BoundingBox bb = gh.getBoundingBox();
if(world == null || gh.getLocation() == null || gh.getLocation().getWorld() == null
|| !gh.getLocation().getWorld().isChunkLoaded(((int) bb.getMaxX()) >> 4, ((int) bb.getMaxZ()) >> 4)
|| !gh.getLocation().getWorld().isChunkLoaded(((int) bb.getMinX()) >> 4, ((int) bb.getMinZ()) >> 4)){
return;
}
for (double x = gh.getInternalBoundingBox().getMinX(); x < gh.getInternalBoundingBox().getMaxX(); x++) {
for (double z = gh.getInternalBoundingBox().getMinZ(); z < gh.getInternalBoundingBox().getMaxZ(); z++) {
for (double y = gh.getInternalBoundingBox().getMaxY() - 1; y >= gh.getBoundingBox().getMinY() && y > 0; y--) {
Block b = gh.getWorld().getBlockAt(NumberConversions.floor(x), NumberConversions.floor(y), NumberConversions.floor(z)).getRelative(BlockFace.DOWN);
if (!b.isEmpty()) gh.getBiomeRecipe().convertBlock(gh, b);
final BoundingBox ibb = gh.getInternalBoundingBox();
int ghMinX = NumberConversions.floor(ibb.getMinX());
int ghMaxX = NumberConversions.floor(ibb.getMaxX());
int ghMinY = NumberConversions.floor(gh.getBoundingBox().getMinY()); // Note: this gets the floor
int ghMaxY = NumberConversions.floor(ibb.getMaxY());
int ghMinZ = NumberConversions.floor(ibb.getMinZ());
int ghMaxZ = NumberConversions.floor(ibb.getMaxZ());
BiomeRecipe biomeRecipe = gh.getBiomeRecipe();
for (int x = ghMinX; x < ghMaxX; x++) {
for (int z = ghMinZ; z < ghMaxZ; z++) {
for (int y = ghMinY; y < ghMaxY; y++) {
Block b = world.getBlockAt(x, y, z);
if(!b.isEmpty()) {
biomeRecipe.convertBlock(b);
}
}
}
}
}
private void verify(Greenhouse gh) {
if(!gh.getLocation().getWorld().isChunkLoaded(((int) gh.getBoundingBox().getMaxX()) >> 4, ((int) gh.getBoundingBox().getMaxZ()) >> 4) || !gh.getLocation().getWorld().isChunkLoaded(((int) gh.getBoundingBox().getMinX()) >> 4, ((int) gh.getBoundingBox().getMinZ()) >> 4)){
//addon.log("Skipping verify for unloaded greenhouse at " + gh.getLocation());
if(gh.getLocation() == null || gh.getLocation().getWorld() == null
|| !gh.getLocation().getWorld().isChunkLoaded(((int) gh.getBoundingBox().getMaxX()) >> 4, ((int) gh.getBoundingBox().getMaxZ()) >> 4)
|| !gh.getLocation().getWorld().isChunkLoaded(((int) gh.getBoundingBox().getMinX()) >> 4, ((int) gh.getBoundingBox().getMinZ()) >> 4)){
// Skipping verify for unloaded greenhouse
return;
}
gh.getBiomeRecipe().checkRecipe(gh).thenAccept(rs -> {
@ -110,21 +132,29 @@ public class EcoSystemManager {
}
private void addMobs(Greenhouse gh) {
if(!gh.getLocation().getWorld().isChunkLoaded(((int) gh.getBoundingBox().getMaxX()) >> 4, ((int) gh.getBoundingBox().getMaxZ()) >> 4) || !gh.getLocation().getWorld().isChunkLoaded(((int) gh.getBoundingBox().getMinX()) >> 4, ((int) gh.getBoundingBox().getMinZ()) >> 4)){
//addon.log("Skipping addmobs for unloaded greenhouse at " + gh.getLocation());
return;
/**
* Try to spawn mobs in a greenhouse
* @param gh greenhouse
* @return true if mobs were spawned, false if not
*/
boolean addMobs(Greenhouse gh) {
final BoundingBox bb = gh.getBoundingBox();
if(gh.getLocation() == null || gh.getLocation().getWorld() == null || gh.getWorld() == null
|| !gh.getLocation().getWorld().isChunkLoaded(((int) bb.getMaxX()) >> 4, ((int) bb.getMaxZ()) >> 4)
|| !gh.getLocation().getWorld().isChunkLoaded(((int) bb.getMinX()) >> 4, ((int) bb.getMinZ()) >> 4)){
// Skipping addmobs for unloaded greenhouse
return false;
}
if (gh.getBiomeRecipe().noMobs()) {
return;
return false;
}
// Check greenhouse chunks are loaded
for (double blockX = gh.getBoundingBox().getMinX(); blockX < gh.getBoundingBox().getMaxX(); blockX+=16) {
for (double blockZ = gh.getBoundingBox().getMinZ(); blockZ < gh.getBoundingBox().getMaxZ(); blockZ+=16) {
for (double blockX = bb.getMinX(); blockX < bb.getMaxX(); blockX+=16) {
for (double blockZ = bb.getMinZ(); blockZ < bb.getMaxZ(); blockZ+=16) {
int chunkX = (int)(blockX / 16);
int chunkZ = (int)(blockZ / 16);
if (!gh.getWorld().isChunkLoaded(chunkX, chunkZ)) {
return;
return false;
}
}
}
@ -133,17 +163,21 @@ public class EcoSystemManager {
.filter(e -> gh.getBiomeRecipe().getMobTypes().contains(e.getType()))
.filter(e -> gh.contains(e.getLocation())).count();
// Get the blocks in the greenhouse where spawning could occur
List<Block> list = new ArrayList<>(getAvailableBlocks(gh, false));
List<GrowthBlock> list = new ArrayList<>(getAvailableBlocks(gh, false));
Collections.shuffle(list, new Random(System.currentTimeMillis()));
Iterator<Block> it = list.iterator();
Iterator<GrowthBlock> it = list.iterator();
// Check if the greenhouse is full
if (gh.getBiomeRecipe().getMaxMob() > -1 && sum >= gh.getBiomeRecipe().getMaxMob()) {
return false;
}
while (it.hasNext() && (sum == 0 || gh.getArea() / sum >= gh.getBiomeRecipe().getMobLimit())) {
// Spawn something if chance says so
if (gh.getBiomeRecipe().spawnMob(it.next())) {
if (gh.getBiomeRecipe().spawnMob(it.next().block())) {
// Add a mob to the sum in the greenhouse
sum++;
}
}
return sum > 0;
}
/**
@ -151,16 +185,22 @@ public class EcoSystemManager {
* @param gh - greenhouse
*/
private void growPlants(Greenhouse gh) {
if(!gh.getLocation().getWorld().isChunkLoaded(((int) gh.getBoundingBox().getMaxX()) >> 4, ((int) gh.getBoundingBox().getMaxZ()) >> 4) || !gh.getLocation().getWorld().isChunkLoaded(((int) gh.getBoundingBox().getMinX()) >> 4, ((int) gh.getBoundingBox().getMinZ()) >> 4)){
//addon.log("Skipping growplants for unloaded greenhouse at " + gh.getLocation());
final BoundingBox bb = gh.getBoundingBox();
if (gh.getLocation() == null || gh.getLocation().getWorld() == null
|| !gh.getLocation().getWorld().isChunkLoaded(((int) bb.getMaxX()) >> 4, ((int) bb.getMaxZ()) >> 4) || !gh.getLocation().getWorld().isChunkLoaded(((int) bb.getMinX()) >> 4, ((int) bb.getMinZ()) >> 4)){
//Skipping growplants for unloaded greenhouse
return;
}
int bonemeal = getBoneMeal(gh);
if (bonemeal > 0) {
// Get a list of all available blocks
List<Block> list = getAvailableBlocks(gh, true);
List<GrowthBlock> list = getAvailableBlocks(gh, false);
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) {
setBoneMeal(gh, bonemeal - (int)Math.ceil((double)plantsGrown / PLANTS_PER_BONEMEAL ));
}
@ -183,24 +223,25 @@ 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.
* These blocks sit just above solid blocks
* These blocks sit just above solid blocks. Leaves are ignored too.
* @param gh - greenhouse
* @param ignoreliquid - true if liquid blocks should be treated like air blocks
* @param ignoreLiquid - true if liquid blocks should be treated like air blocks
* @return List of blocks
*/
public List<Block> getAvailableBlocks(Greenhouse gh, boolean ignoreLiquid) {
List<Block> result = new ArrayList<>();
for (double x = gh.getInternalBoundingBox().getMinX(); x < gh.getInternalBoundingBox().getMaxX(); x++) {
for (double z = gh.getInternalBoundingBox().getMinZ(); z < gh.getInternalBoundingBox().getMaxZ(); z++) {
for (double y = gh.getInternalBoundingBox().getMaxY() - 1; y >= gh.getBoundingBox().getMinY(); y--) {
protected List<GrowthBlock> getAvailableBlocks(Greenhouse gh, boolean ignoreLiquid) {
final BoundingBox bb = gh.getBoundingBox();
final BoundingBox ibb = gh.getInternalBoundingBox();
List<GrowthBlock> result = new ArrayList<>();
if (gh.getWorld() == null) return result;
for (double x = ibb.getMinX(); x < ibb.getMaxX(); x++) {
for (double z = ibb.getMinZ(); z < ibb.getMaxZ(); z++) {
for (double y = ibb.getMaxY() - 1; y >= bb.getMinY(); y--) {
Block b = gh.getWorld().getBlockAt(NumberConversions.floor(x), NumberConversions.floor(y), NumberConversions.floor(z));
if (!(b.isEmpty() || (ignoreLiquid && b.isLiquid()))
&& (b.getRelative(BlockFace.UP).isEmpty()
|| (b.getRelative(BlockFace.UP).isPassable() && !b.isLiquid())
|| (ignoreLiquid && b.isLiquid() && b.getRelative(BlockFace.UP).isPassable()))) {
result.add(b.getRelative(BlockFace.UP));
if (checkBlock(result, b, ignoreLiquid)) {
break;
}
}
@ -209,6 +250,31 @@ public class EcoSystemManager {
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) {
Hopper hopper = getHopper(gh);
if (hopper == null || !hopper.getInventory().contains(Material.BONE_MEAL)) {
@ -219,12 +285,14 @@ public class EcoSystemManager {
.mapToInt(ItemStack::getAmount).sum();
}
/**
* Get the hopper
* @param gh greenhouse
* @return hopper block or null if it does not exist
*/
private Hopper getHopper(Greenhouse gh) {
if (gh.getRoofHopperLocation() == null) {
return null;
}
// Check if the hopper block is still a hopper
if (gh.getRoofHopperLocation().getBlock().getType() != Material.HOPPER) {
if (gh.getRoofHopperLocation() == null || !gh.getRoofHopperLocation().getBlock().getType().equals(Material.HOPPER)) {
gh.setRoofHopperLocation(null);
return null;
}

View File

@ -12,6 +12,7 @@ import org.bukkit.Tag;
import org.bukkit.util.Vector;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.data.Greenhouse;
import world.bentobox.greenhouses.greenhouse.Roof;
import world.bentobox.greenhouses.greenhouse.Walls;
@ -28,18 +29,26 @@ public class GreenhouseFinder {
// If this is the bottom layer, the player has most likely uneven walls
private int otherBlockLayer = -1;
private int wallBlockCount;
private final Greenhouses addon;
/**
* This is the count of the various items
*/
private CounterCheck cc = new CounterCheck();
private CounterCheck counterCheck = new CounterCheck();
class CounterCheck {
static class CounterCheck {
int doorCount;
int hopperCount;
boolean airHole;
boolean otherBlock;
}
/**
* @param addon Addon
*/
public GreenhouseFinder(Greenhouses addon) {
this.addon = addon;
}
/**
* Find out if there is a greenhouse here
* @param location - start location
@ -51,9 +60,9 @@ public class GreenhouseFinder {
redGlass.clear();
// Get a world cache
AsyncWorldCache cache = new AsyncWorldCache(location.getWorld());
AsyncWorldCache cache = new AsyncWorldCache(addon, location.getWorld());
// Find the roof
Roof roof = new Roof(cache, location);
Roof roof = new Roof(cache, location, addon);
roof.findRoof().thenAccept(found -> {
if (Boolean.FALSE.equals(found)) {
result.add(GreenhouseResult.FAIL_NO_ROOF);
@ -80,43 +89,37 @@ public class GreenhouseFinder {
/**
* Check the greenhouse has the right number of everything
* @param cache
* @param gh2 - greenhouse
* @param cache async world cache
* @param roof - roof object
* @param walls - walls object
* @return future set of Greenhouse Results
*/
CompletableFuture<Set<GreenhouseResult>> checkGreenhouse(AsyncWorldCache cache, Roof roof, Walls walls) {
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;
}
private Set<GreenhouseResult> checkGHAsync(CompletableFuture<Set<GreenhouseResult>> r, AsyncWorldCache cache,
private Set<GreenhouseResult> checkGreenhouseAsync(CompletableFuture<Set<GreenhouseResult>> r, AsyncWorldCache cache,
Roof roof, Walls walls) {
Set<GreenhouseResult> result = new HashSet<>();
cc = new CounterCheck();
counterCheck = new CounterCheck();
int y;
for (y = roof.getHeight(); y > walls.getFloor(); y--) {
wallBlockCount = 0;
for (int x = walls.getMinX(); x <= walls.getMaxX(); x++) {
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()) {
// This is the floor
break;
} else {
if (cc.otherBlock) {
if (otherBlockLayer < 0) {
otherBlockLayer = y;
}
}
} else if (counterCheck.otherBlock && otherBlockLayer < 0) {
otherBlockLayer = y;
}
}
result.addAll(checkErrors(roof, y));
Set<GreenhouseResult> result = new HashSet<>(checkErrors(roof, y));
Bukkit.getScheduler().runTask(BentoBox.getInstance(), () -> r.complete(result));
return result;
}
@ -140,7 +143,7 @@ public class GreenhouseFinder {
// Roof blocks must be glass, glowstone, doors or a hopper.
result.add(GreenhouseResult.FAIL_BAD_ROOF_BLOCKS);
} 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);
}
if (this.getWallDoors() > 8) {
@ -168,7 +171,8 @@ public class GreenhouseFinder {
// Check wall blocks only
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
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)) {
// Air hole found
cc.airHole = true;
@ -243,28 +247,28 @@ public class GreenhouseFinder {
* @return the wallDoors
*/
int getWallDoors() {
return cc.doorCount;
return counterCheck.doorCount;
}
/**
* @return the ghHopper
*/
int getGhHopper() {
return cc.hopperCount;
return counterCheck.hopperCount;
}
/**
* @return the airHoles
*/
boolean isAirHoles() {
return cc.airHole;
return counterCheck.airHole;
}
/**
* @return the otherBlocks
*/
boolean isOtherBlocks() {
return cc.otherBlock;
return counterCheck.otherBlock;
}
/**
@ -317,21 +321,21 @@ public class GreenhouseFinder {
}
public void setGhHopper(int i) {
cc.hopperCount = i;
counterCheck.hopperCount = i;
}
public void setWallDoors(int i) {
cc.doorCount = i;
counterCheck.doorCount = i;
}
public void setAirHoles(boolean b) {
cc.airHole = b;
counterCheck.airHole = b;
}
public void setOtherBlocks(boolean b) {
cc.otherBlock = b;
counterCheck.otherBlock = b;
}

View File

@ -3,6 +3,7 @@ package world.bentobox.greenhouses.managers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@ -11,6 +12,7 @@ import org.bukkit.Location;
import org.bukkit.block.Biome;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.util.BoundingBox;
import world.bentobox.bentobox.api.events.BentoBoxReadyEvent;
import world.bentobox.bentobox.database.Database;
@ -94,29 +96,19 @@ public class GreenhouseManager implements Listener {
handler.loadObjects().forEach(g -> {
GreenhouseResult result = map.addGreenhouse(g);
switch (result) {
case FAIL_NO_ISLAND:
// Delete the failed greenhouse
toBeRemoved.add(g);
break;
case FAIL_OVERLAPPING:
addon.logError("Greenhouse overlaps with another greenhouse. Skipping...");
break;
case NULL:
addon.logError("Null location of greenhouse. Cannot load. Skipping...");
break;
case SUCCESS:
activateGreenhouse(g);
break;
case FAIL_NO_WORLD:
addon.logError("Database contains greenhouse for a non-loaded world. Skipping...");
break;
case FAIL_UNKNOWN_RECIPE:
case FAIL_NO_ISLAND ->
// Delete the failed greenhouse
toBeRemoved.add(g);
case FAIL_OVERLAPPING -> addon.logError("Greenhouse overlaps with another greenhouse. Skipping...");
case NULL -> addon.logError("Null location of greenhouse. Cannot load. Skipping...");
case SUCCESS -> activateGreenhouse(g);
case FAIL_NO_WORLD -> addon.logError("Database contains greenhouse for a non-loaded world. Skipping...");
case FAIL_UNKNOWN_RECIPE -> {
addon.logError("Greenhouse uses a recipe that does not exist in the biomes.yml. Skipping...");
addon.logError("Greenhouse Id " + g.getUniqueId());
break;
default:
break;
}
default -> {
}
}
});
addon.log("Loaded " + map.getSize() + " greenhouses.");
@ -124,27 +116,28 @@ public class GreenhouseManager implements Listener {
toBeRemoved.forEach(handler::deleteObject);
}
/**
* Saves all the greenhouses to database
*/
public void saveGreenhouses() {
addon.log("Saving greenhouses...");
map.getGreenhouses().forEach(handler::saveObjectAsync);
}
/**
* Removes the greenhouse from the world and resets biomes
* @param g - greenhouse
* @param gh - greenhouse
*/
public void removeGreenhouse(Greenhouse g) {
handler.deleteObject(g);
map.removeGreenhouse(g);
addon.log("Returning biome to original state: " + g.getOriginalBiome().toString());
for (int x = (int)g.getBoundingBox().getMinX(); x<= (int)g.getBoundingBox().getMaxX(); x+=4) {
for (int z = (int)g.getBoundingBox().getMinZ(); z<= (int)g.getBoundingBox().getMaxZ(); z+=4) {
for (int y = (int)g.getBoundingBox().getMinY(); y<= (int)g.getBoundingBox().getMaxY(); y+=4) {
public void removeGreenhouse(Greenhouse gh) {
handler.deleteObject(gh);
map.removeGreenhouse(gh);
if (gh.getOriginalBiome() == null) {
addon.logError("Greenhouse had no original biome: " + gh.getLocation());
return;
}
if (gh.getLocation() == null || gh.getLocation().getWorld() == null) {
// Greenhouse is messed up. It's being deleted anyway.
return;
}
addon.log("Returning biome to original state: " + gh.getOriginalBiome().toString());
final BoundingBox bb = gh.getBoundingBox();
for (int x = (int)bb.getMinX(); x<= (int)bb.getMaxX(); x+=4) {
for (int z = (int)bb.getMinZ(); z<= (int)bb.getMaxZ(); z+=4) {
for (int y = (int)bb.getMinY(); y<= (int)bb.getMaxY(); y+=4) {
// Set back to the original biome
g.getLocation().getWorld().setBiome(x, y, z, g.getOriginalBiome());
gh.getLocation().getWorld().setBiome(x, y, z, gh.getOriginalBiome());
}
}
}
@ -160,7 +153,7 @@ public class GreenhouseManager implements Listener {
*/
public CompletableFuture<GhResult> tryToMakeGreenhouse(Location location, BiomeRecipe greenhouseRecipe) {
CompletableFuture<GhResult> r = new CompletableFuture<>();
GreenhouseFinder finder = new GreenhouseFinder();
GreenhouseFinder finder = new GreenhouseFinder(addon);
finder.find(location).thenAccept(resultSet -> {
if (!resultSet.isEmpty()) {
// Failure!
@ -185,7 +178,6 @@ public class GreenhouseManager implements Listener {
/**
* Tries to match the greenhouse to a recipe by going through all of them in order
* @param finder - finder object
* @param resultSet - result set from find
*/
private CompletableFuture<Set<GreenhouseResult>> findRecipe(GreenhouseFinder finder) {
CompletableFuture<Set<GreenhouseResult>> r = new CompletableFuture<>();
@ -214,7 +206,6 @@ public class GreenhouseManager implements Listener {
/**
* Checks to see if the greenhouse meets the designated recipe and returns the result
* @param r - completable future
* @param finder - finder object
* @param greenhouseRecipe - recipe requested
* @param resultSet - result set from finder
@ -243,10 +234,11 @@ public class GreenhouseManager implements Listener {
addon.logError("Biome recipe error - no such biome for " + gh.getBiomeRecipe().getName());
return;
}
for (int x = (int)gh.getBoundingBox().getMinX(); x < gh.getBoundingBox().getMaxX(); x+=4) {
for (int z = (int)gh.getBoundingBox().getMinZ(); z < gh.getBoundingBox().getMaxZ(); z+=4) {
for (int y = (int)gh.getBoundingBox().getMinY(); y < gh.getBoundingBox().getMaxY(); y+=4) {
gh.getWorld().setBiome(x, y, z, ghBiome);
final BoundingBox bb = gh.getBoundingBox();
for (int x = (int)bb.getMinX(); x < bb.getMaxX(); x+=4) {
for (int z = (int)bb.getMinZ(); z < bb.getMaxZ(); z+=4) {
for (int y = (int)bb.getMinY(); y < bb.getMaxY(); y+=4) {
Objects.requireNonNull(gh.getWorld()).setBiome(x, y, z, ghBiome);
}
}
}
@ -256,7 +248,7 @@ public class GreenhouseManager implements Listener {
* Result of the greenhouse make effort
*
*/
public class GhResult {
public static class GhResult {
private Set<GreenhouseResult> results;
private GreenhouseFinder finder;

View File

@ -6,7 +6,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.bukkit.Location;
@ -34,7 +33,7 @@ public class GreenhouseMap {
*/
public GreenhouseResult addGreenhouse(Greenhouse greenhouse) {
// Validation checks
if (greenhouse.getBiomeRecipe() == null) {
if (greenhouse.getBiomeRecipe().getBiome() == null) {
return GreenhouseResult.FAIL_UNKNOWN_RECIPE;
}
if (greenhouse.getWorld() == null) {
@ -105,9 +104,11 @@ public class GreenhouseMap {
}
private boolean isOverlapping(Greenhouse greenhouse) {
return addon.getIslands().getIslandAt(greenhouse.getLocation()).map(i -> {
return greenhouse.getLocation() != null && addon.getIslands().getIslandAt(greenhouse.getLocation()).map(i -> {
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);
}
@ -117,13 +118,15 @@ public class GreenhouseMap {
* @param greenhouse - greenhouse
*/
protected void removeGreenhouse(Greenhouse greenhouse) {
addon.getIslands().getIslandAt(greenhouse.getLocation()).ifPresent(i -> {
if (greenhouses.containsKey(i)) greenhouses.get(i).remove(greenhouse);
});
if (greenhouse.getLocation() != null) {
addon.getIslands().getIslandAt(greenhouse.getLocation()).ifPresent(i -> {
if (greenhouses.containsKey(i)) greenhouses.get(i).remove(greenhouse);
});
}
}
/**
* @param island
* @param island island
*/
public void removeGreenhouses(Island island) {
greenhouses.remove(island);
@ -134,7 +137,7 @@ public class GreenhouseMap {
* @return a list of all the Greenhouses
*/
public List<Greenhouse> getGreenhouses() {
return greenhouses.values().stream().flatMap(List::stream).collect(Collectors.toList());
return greenhouses.values().stream().flatMap(List::stream).toList();
}
/**

View File

@ -7,6 +7,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
@ -29,6 +30,7 @@ public class RecipeManager {
private static final int MAXIMUM_INVENTORY_SIZE = 49;
private final Greenhouses addon;
private static final List<BiomeRecipe> biomeRecipes = new ArrayList<>();
private static final String COULD_NOT_PARSE = "Could not parse ";
public RecipeManager(Greenhouses addon) {
this.addon = addon;
@ -68,6 +70,7 @@ public class RecipeManager {
}
ConfigurationSection biomeSection = biomeConfig.getConfigurationSection("biomes");
// Loop through all the entries
assert biomeSection != null;
for (String type: biomeSection.getValues(false).keySet()) {
processEntries(type, biomeSection);
// Check maximum number
@ -82,6 +85,7 @@ public class RecipeManager {
private void processEntries(String biomeType, ConfigurationSection biomeSection) {
try {
ConfigurationSection biomeRecipeConfig = biomeSection.getConfigurationSection(biomeType);
assert biomeRecipeConfig != null;
Biome thisBiome = loadBiome(biomeType, biomeRecipeConfig);
if (thisBiome == null) return;
int priority = biomeRecipeConfig.getInt("priority", 0);
@ -124,7 +128,7 @@ public class RecipeManager {
addon.logError("No biome defined in the biome reciepe " + biomeType + ". Skipping...");
return null;
}
String name = biomeRecipeConfig.getString("biome").toUpperCase(Locale.ENGLISH);
String name = Objects.requireNonNull(biomeRecipeConfig.getString("biome")).toUpperCase(Locale.ENGLISH);
if (Enums.getIfPresent(Biome.class, name).isPresent()) {
return Biome.valueOf(name);
}
@ -152,6 +156,7 @@ public class RecipeManager {
b.setLavacoverage(biomeRecipeConfig.getInt("lavacoverage",-1));
b.setIcecoverage(biomeRecipeConfig.getInt("icecoverage",-1));
b.setMobLimit(biomeRecipeConfig.getInt("moblimit", 9));
b.setMaxMob(biomeRecipeConfig.getInt("maxmobs", -1));
return b;
}
@ -175,44 +180,59 @@ public class RecipeManager {
ConfigurationSection conversionSec = biomeRecipeConfig.getConfigurationSection("conversions");
if (conversionSec != null) {
for (String oldMat : conversionSec.getKeys(false)) {
try {
Material oldMaterial = Material.valueOf(oldMat.toUpperCase(Locale.ENGLISH));
String conversions = conversionSec.getString(oldMat);
if (!conversions.isEmpty()) {
String[] split = conversions.split(":");
double convChance = Double.parseDouble(split[0]);
Material newMaterial = Material.valueOf(split[1]);
Material localMaterial = Material.valueOf(split[2]);
b.addConvBlocks(oldMaterial, newMaterial, convChance, localMaterial);
}
} catch (Exception e) {
addon.logError("Could not parse " + oldMat);
}
parseConversions(oldMat, conversionSec, b);
}
}
// Get the list of conversions
for (String oldMat : biomeRecipeConfig.getStringList("conversion-list")) {
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 = Material.valueOf(split[3]);
b.addConvBlocks(oldMaterial, newMaterial, convChance, localMaterial);
} catch (Exception e) {
addon.logError("Could not parse " + oldMat);
}
parseConversionList(oldMat, b);
}
}
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) {
ConfigurationSection temp = biomeRecipeConfig.getConfigurationSection("mobs");
// Mob EntityType: Probability:Spawn on Material
if (temp != null) {
((HashMap<String,Object>)temp.getValues(false)).entrySet().forEach(s -> parseMob(s,b));
temp.getValues(false).entrySet().forEach(s -> parseMob(s,b));
}
}
@ -225,7 +245,7 @@ public class RecipeManager {
Material mobSpawnOn = Material.valueOf(split[1]);
b.addMobs(mobType, mobProbability, mobSpawnOn);
} catch (Exception e) {
addon.logError("Could not parse " + s.getKey());
addon.logError(COULD_NOT_PARSE + s.getKey());
}
}

View File

@ -13,7 +13,7 @@ import world.bentobox.greenhouses.greenhouse.BiomeRecipe;
public class Panel {
private static final String COVERAGE = "[coverage]";
private Greenhouses addon;
private final Greenhouses addon;
public Panel(Greenhouses addon) {
super();

View File

@ -22,8 +22,8 @@ import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult;
*/
public class PanelClick implements ClickHandler {
private Greenhouses addon;
private BiomeRecipe br;
private final Greenhouses addon;
private final BiomeRecipe br;
public PanelClick(Greenhouses addon, BiomeRecipe br) {
this.addon = addon;

View File

@ -52,7 +52,7 @@ class MakeCommand extends CompositeCommand {
@Override
public boolean execute(User user, String label, List<String> args) {
if (args.isEmpty()) {
new Panel((Greenhouses)this.getAddon()).showPanel(user);
new Panel(this.getAddon()).showPanel(user);
return true;
}
// Check recipe given matches
@ -83,7 +83,7 @@ class MakeCommand extends CompositeCommand {
private Map<String, BiomeRecipe> getRecipes(User user) {
return ((Greenhouses)getAddon()).getRecipes().getBiomeRecipes().stream()
.filter(br -> user.hasPermission(br.getPermission()))
.collect(Collectors.toMap(br -> br.getName(), br -> br));
.collect(Collectors.toMap(BiomeRecipe::getName, br -> br));
}
/**
@ -129,7 +129,7 @@ class MakeCommand extends CompositeCommand {
@Override
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
return Optional.of(new ArrayList<String>(this.getRecipes(user).keySet()));
return Optional.of(new ArrayList<>(this.getRecipes(user).keySet()));
}
}

View File

@ -40,7 +40,7 @@ class RemoveCommand extends CompositeCommand {
user.sendMessage("greenhouses.errors.no-rank");
return false;
}
Greenhouses addon = ((Greenhouses)this.getAddon());
Greenhouses addon = this.getAddon();
// Remove greenhouse if it exists
if (!addon.getManager().getMap().getGreenhouse(user.getLocation()).map(gh -> {
user.sendMessage("general.success");

View File

@ -30,8 +30,7 @@ public class UserCommand extends CompositeCommand {
public void setup() {
this.setPermission("greenhouses.player");
this.setOnlyPlayer(true);
this.setParametersHelp("greenhouses.command.parameters");
this.setDescription("greenhouses.command.description");
this.setDescription("greenhouses.commands.user.description");
//new InfoCommand(this);
//new ListCommand(this);

View File

@ -2,6 +2,7 @@ package world.bentobox.greenhouses.world;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@ -26,14 +27,16 @@ public class AsyncWorldCache {
private final World world;
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
* @param world - world to cache
*/
public AsyncWorldCache(World world) {
public AsyncWorldCache(Greenhouses addon, World world) {
this.world = world;
cache = new HashMap<>();
this.addon = addon;
}
/**
@ -58,7 +61,7 @@ public class AsyncWorldCache {
*/
private CompletableFuture<ChunkSnapshot> getAChunk(int x, int z) {
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())));
return r;
}
@ -101,9 +104,9 @@ public class AsyncWorldCache {
int xx = x >= 0 ? x % 16 : (16 + (x % 16)) % 16;
int zz = z >= 0 ? z % 16 : (16 + (z % 16)) % 16;
try {
return getSnap(x,z).getBlockType(xx, y, zz);
return Objects.requireNonNull(getSnap(x, z)).getBlockType(xx, y, zz);
} 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...
Thread.currentThread().interrupt();
return Material.AIR;

View File

@ -35,11 +35,17 @@ biomes:
# Entity name: % chance:Block on which the mob will spawn
mobs:
SQUID: 10:WATER
GLOW_SQUID: 5:WATER
TURTLE: 10:SAND
# The minimum number of blocks each mob requires.
# 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
# greenhouse area is 18 blocks
# greenhouse area is 18 blocks. This enables bigger greenhouses to spawn more.
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: 5
Snowy_beach:
friendlyname: "Snowy beach"
biome: SNOWY_BEACH
@ -49,6 +55,9 @@ biomes:
SAND: 1
watercoverage: 50
icecoverage: 10
mobs:
SQUID: 10:WATER
GLOW_SQUID: 10:WATER
ThreeWolfMoon:
friendlyname: "Three Wolf Moon Forest"
# Could do with more wolves, but the magic works with 3.
@ -63,11 +72,17 @@ biomes:
plants:
TALL_GRASS: 10:GRASS_BLOCK
mobs:
WOLF: 10:SNOW
WOLF: 15:SNOW
FOX: 15:GRASS_BLOCK
RABBIT: 7: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: 5
Cold_Rabbit:
friendlyname: "Cold Taiga Forest"
biome: TAIGA_HILLS
biome: OLD_GROWTH_SPRUCE_TAIGA
icon: SPRUCE_SAPLING
priority: 20
contents:
@ -79,7 +94,12 @@ biomes:
TALL_GRASS: 10:GRASS_BLOCK
mobs:
RABBIT: 10:SNOW
FOX: 7: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
DESERT:
friendlyname: "Desert"
biome: DESERT
@ -103,6 +123,14 @@ biomes:
- DIRT:30:SAND:SAND
- GRASS_BLOCK:30:SAND: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:
friendlyname: "Flowery forest"
biome: FLOWER_FOREST
@ -117,6 +145,17 @@ biomes:
ORANGE_TULIP: 2:GRASS_BLOCK
SUNFLOWER: 4: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:
friendlyname: "&cNether"
biome: NETHER_WASTES
@ -134,6 +173,10 @@ biomes:
STRIDER: 10:LAVA
ENDERMAN: 5:NETHERRACK
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: 50
permission: greenhouses.biome.nether
SOUL_SAND_VALLEY:
friendlyname: "&cSoul Sand Valley"
@ -148,7 +191,14 @@ biomes:
watercoverage: 0
mobs:
SKELETON: 10:SOUL_SAND
GHAST: 10:SOUL_SAND
ENDERMAN: 1:SOUL_SAND
STRIDER: 20:LAVA
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: 50
permission: greenhouses.biome.nether
# Conversion list - in this case, an adjacent block is required to convert
# Format is:
@ -173,6 +223,10 @@ biomes:
PIGLIN: 10:CRIMSON_NYLIUM
HOGLIN: 10:CRIMSON_NYLIUM
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: 50
permission: greenhouses.biome.nether
WARPED_FOREST:
friendlyname: "&cWarped Forest"
@ -190,6 +244,10 @@ biomes:
STRIDER: 10:LAVA
ENDERMAN: 20:WARPED_NYLIUM
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: 50
permission: greenhouses.biome.nether
JUNGLE:
biome: JUNGLE
@ -205,6 +263,11 @@ biomes:
ROSE_BUSH: 20:GRASS_BLOCK
FERN: 20:GRASS_BLOCK
TALL_GRASS: 20:GRASS_BLOCK
COCOA: 10:JUNGLE_LOG
mobs:
PARROT: 30:GRASS_BLOCK
CHICKEN: 20:GRASS_BLOCK
PANDA: 1:GRASS_BLOCK
MUSHROOM_FIELDS:
friendlyname: "Mushroom Fields"
biome: MUSHROOM_FIELDS
@ -220,6 +283,10 @@ biomes:
mobs:
MUSHROOM_COW: 10:MYCELIUM
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
OCEAN:
biome: OCEAN
icon: WATER_BUCKET
@ -228,7 +295,13 @@ biomes:
watercoverage: 95
mobs:
SQUID: 10:WATER
DROWNED: 1:WATER
COD: 40:WATER
DOLPHIN: 20:WATER
SQUID: 20:WATER
GLOW_SQUID: 10:WATER
moblimit: 9
maxmobs: 20
PLAINS:
friendlyname: "Horse Plains"
biome: PLAINS
@ -239,8 +312,17 @@ biomes:
plants:
TALL_GRASS: 10:GRASS_BLOCK
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
# 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
RIVER:
friendlyname: "Clay river"
biome: RIVER
@ -256,6 +338,15 @@ biomes:
# So, for below, dirt has a 50% chance of changing into clay if it is next to water!
conversion-list:
- 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:
biome: SAVANNA
icon: ACACIA_LEAVES
@ -266,6 +357,18 @@ biomes:
GRASS_BLOCK: 4
plants:
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:
friendlyname: "&2Slimy Swamp"
biome: SWAMP
@ -280,7 +383,37 @@ biomes:
plants:
RED_MUSHROOM: 20:GRASS_BLOCK
BROWN_MUSHROOM: 20:GRASS_BLOCK
BLUE_ORCHID: 10:GRASS_BLOCK
LILY_PAD: 5:WATER
mobs:
SLIME: 5:WATER
FROG: 20:WATER
moblimit: 3
# 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
dripstone_caves:
friendlyname: "&6Drippy Drops"
biome: dripstone_caves
icon: DRIPSTONE_BLOCK
priority: 15
contents:
STONE: 8
CLAY: 8
# 50% water coverage 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
BAT: 10:STONE
moblimit: 5
# 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: 25

View File

@ -0,0 +1,163 @@
---
protection:
flags:
GREENHOUSE:
name: Gewächshäuser
description: |-
&bUmschalten, wer
&bdie Gewächshäuser kontrollieren kann
greenhouses:
general:
greenhouses: Gewächshäuser
errors:
move: Gehe zuerst in ein Gewächshaus, das dir gehört.
no-rank: "& cDu hast keinen Rang, um das zu tun."
notyours: Das ist nicht dein Gewächshaus!
not-inside: "& cDu bist nicht in einem Gewächshaus!"
tooexpensive: Du kannst dir das nicht leisten [price]
alreadyexists: Gewächshaus existiert bereits!
norecipe: Kann kein Gewächshaus bauen!
event:
broke: Du hast das Gewächshaus kaputt gemacht! Biome auf [biome] umstellen!
entering: Betreten des Gewächshauses [biome]
leaving: Das Gewächshaus verlassen [biome]
recipe:
blockscolor: "&f"
title: "[[biome] recipe]"
watermustbe: Wasser > [coverage]% der Bodenfläche.
icemustbe: Eisblöcke > [coverage]% der Bodenfläche.
lavamustbe: Lava > [coverage]% der Bodenfläche.
minimumblockstitle: "[Minimum blocks required]"
nootherblocks: Keine weiteren Blöcke erforderlich.
missing: Gewächshaus fehlt
commands:
user:
remove:
description: Entfernt ein Gewächshaus, in dem Sie stehen, wenn Sie der Eigentümer
sind
make:
description: Versuche ein Gewächshaus zu bauen
parameters: "<recipe>"
error:
already: "&cEs gibt hier schon ein Gewächshaus!"
FAIL_BAD_ROOF_BLOCKS: "&cDach enthält unzulässige Blöcke!"
FAIL_BAD_WALL_BLOCKS: "&cWand enthält unzulässige Blöcke!"
FAIL_BELOW: "&cDu musst im Gewächshaus sein, um es zu versuchen."
FAIL_BLOCKS_ABOVE: "&cEs dürfen keine Blöcke über dem Gewächshaus sein!
Rote Glasblöcke sollten die Problemblöcke anzeigen."
FAIL_HOLE_IN_ROOF: "&cIn dem Dach ist ein Loch oder es ist nicht flach!
Rote Glasblöcke sollten das Problem anzeigen."
FAIL_HOLE_IN_WALL: "&cIn der Wand ist ein Loch!"
FAIL_NO_ROOF: "&cEs scheint kein Dach zu geben!"
FAIL_TOO_MANY_DOORS: "&cEs dürfen nicht mehr als 4 Türen im Gewächshaus
sein!"
FAIL_TOO_MANY_HOPPERS: "&cIn den Wänden oder im Dach ist nur ein Trichter
zulässig."
FAIL_UNEVEN_WALLS: "&cDie Wände sind uneben. Rote Glasblöcke sollten die
Problemblöcke anzeigen."
FAIL_INSUFFICIENT_ICE: "&cZu wenig Eis für dieses Rezept"
FAIL_INSUFFICIENT_LAVA: "&cZu wenig Lava für dieses Rezept"
FAIL_INSUFFICIENT_WATER: "&cZu wenig Wasser für dieses Rezept"
FAIL_NO_ICE: "&cFür dieses Rezept wird Eis benötigt"
FAIL_NO_LAVA: "&cFür dieses Rezept wird Lava benötigt"
FAIL_NO_WATER: "&cFür dieses Rezept wird Wasser benötigt"
FAIL_NO_RECIPE_FOUND: "&c Zu diesem Gewächshaus konnte kein passendes Rezept
gefunden werden"
FAIL_INSUFFICIENT_BLOCKS: "&cWeitere Blöcke sind erforderlich, um dieses
Rezept zu erstellen!"
FAIL_OVERLAPPING: "&cGewächshäuser können sich keine Wände teilen, sorry."
success: "&2Du hast erfolgreich ein [biome] Biom Gewächshaus gebaut! Beim
nächsten Teleport oder Login wird Biom synchronisiert."
missing-blocks: "[material] x [number] &cFehlt"
unknown-recipe: "&Unbekanntes Rezept"
try-these: "&cVersuche einen von diesen:"
recipe-format: "&3[name]"
info:
title: "&A[Wie man ein Gewächshaus baut]"
instructions: "&EStelle einen Kasten aus Glas mit 4 Wänden und einem flachen
&EGlasdach her und füge bis zu &F4 Türen &Ein den Wänden hinzu. &EPlatziere
&F1 Trichter &Ein eine Wand oder ein Dach und füge Wassereimer hinzu. &EUm
Schnee und/oder Knochenmehl herzustellen, um Pflanzen automatisch wachsen
zu lassen. &EPrüfe die Biom-Rezepte, welche Blöcke in einem Gewächshaus
sein müssen, um ein &EGewächshaus erfolgreich zu machen."
help:
help: Hilfe
make: Versucht ein Gewächshaus zu bauen
remove: Entfernt ein Gewächshaus, in dem du stehst, wenn du der Besitzer bist
info: Wie man ein Gewächshaus baut
list: Listet alle Gewächshausbiome auf, die hergestellt werden können
recipe: Erklärt dir, wie man das Gewächshaus biome macht
opengui: Öffnet die Gewächshaus-GUI
list:
title: "[Gewächshaus-Biom-Rezepte]"
info: Benutze /greenhouse recipe <number> um Details über die Herstellung jedes
Gewächshauses zu sehen
error:
greenhouseProtected: Gewächshaus geschützt
move: Gehe zuerst in ein Gewächshaus, das dir gehört.
notowner: Du musst der Besitzer dieses Gewächshauses sein, um das zu tun.
removing: Gewächshaus entfernen!
notyours: Das ist nicht dein Gewächshaus!
notinside: Du bist nicht in einem Gewächshaus!
tooexpensive: du kannst dir das nicht leisten [price]
alreadyexists: Gewächshaus existiert bereits!
norecipe: Kann kein Gewächshaus bauen!
messages:
enter: Betreten des [biome] Gewächshauses von [owner]!
leave: Verlässt jetzt das Gewächshaus von [owner].
youarein: Du bist jetzt in [owner]'s [biome] Gewächshaus!
removed: Dieses Gewächshaus ist nicht mehr ...
removedmessage: Ein [biome] Gewächshaus von dir ist nicht mehr!
ecolost: Dein Gewächshaus in [location] hat sein Ökosystem verloren und wurde entfernt.
info:
title: "&A [Gewächshaus bauen]"
instructions: "&EStelle einen Kasten aus Glas mit 4 Wänden und einem flachen &EGlasdach
her und füge bis zu &F4 Türen &Ein den Wänden hinzu. &EPlatziere &F1 Trichter
&Ein eine Wand oder ein Dach und füge Wassereimer hinzu. &EUm Schnee und/oder
Knochenmehl herzustellen, um Pflanzen automatisch wachsen zu lassen. &EPrüfe die
\ Biom-Rezepte, welche Blöcke in einem Gewächshaus sein müssen, um ein &EGewächshaus
erfolgreich zu machen."
info: "[Gewächshaus Info]"
none: Keiner
nomore: "&4Du kannst keine Gewächshäuser mehr bauen!"
onemore: "&6Du kannst noch ein weiteres Gewächshaus bauen."
youcanbuild: "&ADu kannst bis zu [number] mehr Gewächshäuser bauen!"
unlimited: "&ADu kannst eine unbegrenzte Anzahl von Gewächshäusern bauen!"
welcome: "&BHerzlich willkommen! Klicken Sie hier für Anweisungen"
recipe:
blockscolor: "&f"
hint: benutze /greenhouse list, um eine Liste von Rezeptnummern zu sehen!
wrongnumber: Die Rezeptnummer muss zwischen 1 und [size] liegen
title: "[[biome] recipe]"
nowater: Kein Wasser erlaubt.
noice: Kein Eis erlaubt.
nolava: Keine Lava erlaubt.
watermustbe: Wasser > [coverage]% der Bodenfläche.
icemustbe: Eisblöcke > [coverage]% der Bodenfläche.
lavamustbe: Lava > [coverage]% der Bodenfläche.
minimumblockstitle: "[Minimum blocks required]"
nootherblocks: Keine weiteren Blöcke erforderlich.
missing: Gewächshaus fehlt
event:
broke: Du hast das Gewächshaus kaputt gemacht! Biome auf [biome] umstellen!
fix: repariere das Gewächshaus und baue es dann wieder auf
cannotplace: Blöcke können nicht über einem Gewächshaus platziert werden!
pistonerror: Kolben können keine Blöcke über ein Gewächshaus schieben!
limits:
noneallowed: Die Berechtigungen erlauben dir keine Gewächshäuser, deshalb wurden
[nummer] entfernt.
limitedto: Die Berechtigungen beschränken dich auf [limit] Gewächshäuser, so dass
[number] entfernt wurden.
adminHelp:
reload: Konfiguration aus Datei neu laden.
info: Liefert Informationen über das Gewächshaus, in dem du dich befindest
reload:
configReloaded: Konfiguration aus Datei neu geladen.
admininfo:
error: Gewächshaus-Info nur im Spiel verfügbar
error2: Versetzt dich in ein Gewächshaus, um Infos zu sehen.
flags: "[Greenhouse Flags]"
news:
headline: "[Greenhouse News]"
controlpanel:
title: "&AGewächshäuser"

View File

@ -38,9 +38,10 @@ greenhouses:
minimumblockstitle: "[Minimum blocks required]"
nootherblocks: "No other blocks required."
missing: "Greenhouse is missing"
commands:
user:
description: "Opens the Greenhouse selection GUI"
remove:
description: "Removes a greenhouse that you are standing in if you are the owner"
make:
@ -52,15 +53,18 @@ greenhouses:
FAIL_BAD_WALL_BLOCKS: "&c Wall contains disallowed blocks!"
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_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_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_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_INSUFFICIENT_ICE: "&c Insufficent ice to make this recipe"
FAIL_INSUFFICIENT_LAVA: "&c Insufficent lava to make this recipe"
FAIL_INSUFFICIENT_WATER: "&c Insufficent water to make this recipe"
FAIL_INSUFFICIENT_ICE: "&c Insufficient ice to make this recipe"
FAIL_INSUFFICIENT_LAVA: "&c Insufficient lava 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_LAVA: "&c Lava is required to make this recipe"
FAIL_NO_WATER: "&c Water is required to make this recipe"

View File

@ -1,189 +1,153 @@
###########################################################################################
# This is a YML file. Be careful when editing. Check your edits in a YAML checker like #
# the one at http://yaml-online-parser.appspot.com #
# If this file is deleted, then it will be recreate at the next reload. #
###########################################################################################
---
protection:
flags:
GREENHOUSE:
name: Greenhouses
description: |
&bÁllítsd be, hogy ki
&bkezelheti az üvegházat
description: "&bÁllítsd be, hogy ki\n&bkezelheti az üvegházat \n"
greenhouses:
general:
greenhouses: "Üvegházak"
greenhouses: Üvegházak
errors:
move: "Menj a saját üvegházadhoz."
move: Menj a saját üvegházadhoz.
no-rank: "&cNincs rangod ehhez."
notyours: "Ez nem a te üvegházad!"
notyours: Ez nem a te üvegházad!
not-inside: "&cNem vagy üvegházban!"
tooexpensive: "Ehhez nincs elég pénzed, ennyi szükséges: [price]"
alreadyexists: "Az üvegház már létezik!"
norecipe: "Nem tudsz üvegházat csinálni!"
tooexpensive: 'Ehhez nincs elég pénzed, ennyi szükséges: [price]'
alreadyexists: Az üvegház már létezik!
norecipe: Nem tudsz üvegházat csinálni!
event:
broke: "Összetörted az üvegházad! Visszaállítjuk a biome-ot [biome]-ra/re!"
entering: "Belépés a(z) [biome] üvegházba."
leaving: "Kilépés a(z) [biome] üvegházból."
broke: Összetörted az üvegházad! Visszaállítjuk a biome-ot [biome]-ra/re!
entering: Belépés a(z) [biome] üvegházba.
leaving: Kilépés a(z) [biome] üvegházból.
recipe:
blockscolor: "&f"
title: "[[biome] recept]"
watermustbe: "Víz > [coverage]% kell, hogy legyen az alapterületen."
icemustbe: "Jég blokk > [coverage]% kell, hogy legyen az alapterületen."
lavamustbe: "Láva > [coverage]% kell, hogy legyen az alapterületen."
minimumblockstitle: "[Minimum blokkmennyiség]"
nootherblocks: "Nem szükséges több blokk."
missing: "Hiányzó üvegház."
blockscolor: "&f"
title: "[[biome] recept]"
watermustbe: Víz > [coverage]% kell, hogy legyen az alapterületen.
icemustbe: Jég blokk > [coverage]% kell, hogy legyen az alapterületen.
lavamustbe: Láva > [coverage]% kell, hogy legyen az alapterületen.
minimumblockstitle: "[Minimum blokkmennyiség]"
nootherblocks: Nem szükséges több blokk.
missing: Hiányzó üvegház.
commands:
user:
remove:
description: "Ha az üvegházadban állsz és te vagy a tulaja, akkor törli azt."
description: Ha az üvegházadban állsz és te vagy a tulaja, akkor törli azt.
make:
description: "Megpróbál készíteni egy üvegházat."
description: Megpróbál készíteni egy üvegházat.
parameters: "<recipe>"
error:
already: "Az üvegház már létezik!"
already: Az üvegház már létezik!
FAIL_BAD_ROOF_BLOCKS: "&cA tető nem engedélyezett blokkokat tartalmaz!"
FAIL_BAD_WALL_BLOCKS: "&cA fal nem engedélyezett blokkokat tartalmaz!"
FAIL_BELOW: "&cAz üvegházban kell lenned, hogy megpróbáld elkészíteni"
FAIL_BLOCKS_ABOVE: "&cAz üvegház felett nem lehetnek blokkok! A piros üvegblokkoknak meg kell mutatniuk a problémás blokkokat."
FAIL_HOLE_IN_ROOF: "&cVan egy lyuk a tetőn, vagy nem sík! A piros üvegblokkoknak meg kell mutatniuk a problémát."
FAIL_BLOCKS_ABOVE: "&cAz üvegház felett nem lehetnek blokkok! A piros üvegblokkoknak
meg kell mutatniuk a problémás blokkokat."
FAIL_HOLE_IN_ROOF: "&cVan egy lyuk a tetőn, vagy nem sík! A piros üvegblokkoknak
meg kell mutatniuk a problémát."
FAIL_HOLE_IN_WALL: "&cVan egy lyuk a falban!"
FAIL_NO_ROOF: "&cÚgy tűnik, nincs tető!"
FAIL_TOO_MANY_DOORS: "&cAz üvegházban nem lehet négynél több ajtó!"
FAIL_TOO_MANY_HOPPERS: "&cCsak egy tölcsér megengedett a falakban vagy a tetőben."
FAIL_UNEVEN_WALLS: "&cA falak egyenetlenek. A piros üvegblokkoknak meg kell mutatniuk a problémás blokkokat."
FAIL_TOO_MANY_HOPPERS: "&cCsak egy tölcsér megengedett a falakban vagy a
tetőben."
FAIL_UNEVEN_WALLS: "&cA falak egyenetlenek. A piros üvegblokkoknak meg kell
mutatniuk a problémás blokkokat."
FAIL_INSUFFICIENT_ICE: "&cNem elegendő a jég ehhez a recept elkészítéséhez."
FAIL_INSUFFICIENT_LAVA: "&cNem elegendő a láva ehhez a recept elkészítéséhez."
FAIL_INSUFFICIENT_WATER: "&cNem elegendő a víz ehhez a recept elkészítéséhez."
FAIL_NO_ICE: "&cA jég szükséges ehhez a recepthez."
FAIL_NO_LAVA: "&cA láva szükséges ehhez a recepthez."
FAIL_NO_WATER: "&cA víz szükséges ehhez a recepthez."
FAIL_NO_RECIPE_FOUND: "&c Nem található ilyen recept ebben a melegházban."
FAIL_INSUFFICIENT_BLOCKS: "&cTovábbi blokkokra van szükség a recept elkészítéséhez!"
FAIL_OVERLAPPING: "&cAz üvegházak nem oszthatják meg a falakat, bocs."
success: "Sikeresen elkészítettél egy [biome] üvegházat! Az éghajlat szinkronizálódik a következő teleportálásnál, vagy belépésnél."
success: Sikeresen elkészítettél egy [biome] üvegházat! Az éghajlat szinkronizálódik
a következő teleportálásnál, vagy belépésnél.
missing-blocks: "&cHiányzik [material] x [number]"
unknown-recipe: "&cIsmeretlen recept"
try-these: "&cPróbálj meg egyet az alábbiak közül:"
recipe-format: "&3[name]"
info:
title: "&A[Hogyan Készíts Üvegházat]"
instructions: |
&EKészíts egy üvegdobozt 4 fallal, egy üvegtetővel,
&Eés akár 4 ajtót is tehetsz a falba.
&ERakj a falba vagy a tetőbe &F1 tölcsért, &Eés helyezz bele vizes vödröket,
&Ehogy havat és/vagy csontlisztet készíts, mellyel automatikusan tudod növeszteni a növényeidet.
&ENézd meg az éghajlatokhoz tartozó recepteket, hogy megtudd milyen blokkok legyenek feltétlenül
&Eaz üvegházban ahhoz, hogy sikeresen elkészítsd.
######### Old locale for reference
instructions: "&EKészíts egy üvegdobozt 4 fallal, egy üvegtetővel,\n&Eés akár
4 ajtót is tehetsz a falba.\n&ERakj a falba vagy a tetőbe &F1 tölcsért,
&Eés helyezz bele vizes vödröket,\n&Ehogy havat és/vagy csontlisztet készíts,
mellyel automatikusan tudod növeszteni a növényeidet.\n&ENézd meg az éghajlatokhoz
tartozó recepteket, hogy megtudd milyen blokkok legyenek feltétlenül\n&Eaz
üvegházban ahhoz, hogy sikeresen elkészítsd. \n"
help:
help: "help"
make: "Tries to make a greenhouse"
remove: "Removes a greenhouse that you are standing in if you are the owner"
info: "How to make a greenhouse"
list: "Lists all the greenhouse biomes that can be made"
recipe: "Tells you how to make greenhouse biome"
opengui: "Opens the Greenhouse GUI"
help: help
make: Tries to make a greenhouse
remove: Removes a greenhouse that you are standing in if you are the owner
info: How to make a greenhouse
list: Lists all the greenhouse biomes that can be made
recipe: Tells you how to make greenhouse biome
opengui: Opens the Greenhouse GUI
list:
title: "[Greenhouse Biome Recipes]"
info: "Use /greenhouse recipe <number> to see details on how to make each greenhouse"
################
#General Errors#
################
title: "[Greenhouse Biome Recipes]"
info: Use /greenhouse recipe <number> to see details on how to make each greenhouse
error:
greenhouseProtected: "Greenhouse protected"
move: "Move to a greenhouse you own first."
notowner: "You must be the owner of this greenhouse to do that."
removing: "Removing greenhouse!"
notyours: "This is not your greenhouse!"
notinside: "You are not in a greenhouse!"
tooexpensive: "You cannot afford [price]"
alreadyexists: "Greenhouse already exists!"
norecipe: "Cannot make a greenhouse!"
greenhouseProtected: Greenhouse protected
move: Move to a greenhouse you own first.
notowner: You must be the owner of this greenhouse to do that.
removing: Removing greenhouse!
notyours: This is not your greenhouse!
notinside: You are not in a greenhouse!
tooexpensive: You cannot afford [price]
alreadyexists: Greenhouse already exists!
norecipe: Cannot make a greenhouse!
messages:
enter: "Entering [owner]'s [biome] greenhouse!"
leave: "Now leaving [owner]'s greenhouse."
youarein: "You are now in [owner]'s [biome] greenhouse!"
removed: "This greenhouse is no more..."
removedmessage: "A [biome] greenhouse of yours is no more!"
ecolost: "Your greenhouse at [location] lost its eco system and was removed."
enter: Entering [owner]'s [biome] greenhouse!
leave: Now leaving [owner]'s greenhouse.
youarein: You are now in [owner]'s [biome] greenhouse!
removed: This greenhouse is no more...
removedmessage: A [biome] greenhouse of yours is no more!
ecolost: Your greenhouse at [location] lost its eco system and was removed.
info:
title: "&A[How To Build A Greenhouse]"
instructions: |
&EMake a box out of out of glass with 4 walls and a flat glass
&Eroof and add up to &F4 doors &Ein the walls.
&EPlace &F1 hopper &Ein a wall or roof and add water buckets.
&Eto make snow and/or bonemeal to grow plants automatically.
&ECheck the biome recipes for what blocks must be inside a
&Egreenhouse to make one successfully.
info: "[Greenhouse Info]"
none: "None"
nomore: "&4You cannot build any more greenhouses!"
onemore: "&6You can build one more greenhouse."
youcanbuild: "&AYou can build up to [number] more greenhouses!"
unlimited: "&AYou can build an unlimited number of greenhouses!"
welcome: "&BWelcome! Click here for instructions"
title: "&A[How To Build A Greenhouse]"
instructions: "&EMake a box out of out of glass with 4 walls and a flat glass\n&Eroof
and add up to &F4 doors &Ein the walls.\n&EPlace &F1 hopper &Ein a wall or roof
and add water buckets.\n&Eto make snow and/or bonemeal to grow plants automatically.\n&ECheck
the biome recipes for what blocks must be inside a\n&Egreenhouse to make one successfully.
\n"
info: "[Greenhouse Info]"
none: None
nomore: "&4You cannot build any more greenhouses!"
onemore: "&6You can build one more greenhouse."
youcanbuild: "&AYou can build up to [number] more greenhouses!"
unlimited: "&AYou can build an unlimited number of greenhouses!"
welcome: "&BWelcome! Click here for instructions"
recipe:
blockscolor: "&f"
hint: "Use /greenhouse list to see a list of recipe numbers!"
wrongnumber: "Recipe number must be between 1 and [size]"
title: "[[biome] recipe]"
nowater: "No water allowed."
noice: "No ice allowed."
nolava: "No lava allowed."
watermustbe: "Water > [coverage]% of floor area."
icemustbe: "Ice blocks > [coverage]% of floor area."
lavamustbe: "Lava > [coverage]% of floor area."
minimumblockstitle: "[Minimum blocks required]"
nootherblocks: "No other blocks required."
missing: "Greenhouse is missing"
blockscolor: "&f"
hint: Use /greenhouse list to see a list of recipe numbers!
wrongnumber: Recipe number must be between 1 and [size]
title: "[[biome] recipe]"
nowater: No water allowed.
noice: No ice allowed.
nolava: No lava allowed.
watermustbe: Water > [coverage]% of floor area.
icemustbe: Ice blocks > [coverage]% of floor area.
lavamustbe: Lava > [coverage]% of floor area.
minimumblockstitle: "[Minimum blocks required]"
nootherblocks: No other blocks required.
missing: Greenhouse is missing
event:
broke: "You broke this greenhouse! Reverting biome to [biome]!"
fix: "Fix the greenhouse and then make it again."
cannotplace: "Blocks cannot be placed above a greenhouse!"
pistonerror: "Pistons cannot push blocks over a greenhouse!"
broke: You broke this greenhouse! Reverting biome to [biome]!
fix: Fix the greenhouse and then make it again.
cannotplace: Blocks cannot be placed above a greenhouse!
pistonerror: Pistons cannot push blocks over a greenhouse!
limits:
noneallowed: "Permissions do not allow you any greenhouses so [number] were removed."
limitedto: "Permissions limit you to [limit] greenhouses so [number] were removed."
##################################
#Admin commands that use /gadmin #
##################################
#Help
noneallowed: Permissions do not allow you any greenhouses so [number] were removed.
limitedto: Permissions limit you to [limit] greenhouses so [number] were removed.
adminHelp:
reload: "reload configuration from file."
info: "provides info on the greenhouse you are in"
#reload
reload: reload configuration from file.
info: provides info on the greenhouse you are in
reload:
configReloaded: "Configuration reloaded from file."
configReloaded: Configuration reloaded from file.
admininfo:
error: "Greenhouse info only available in-game"
error2: "Put yourself in a greenhouse to see info."
flags: "[Greenhouse Flags]"
error: Greenhouse info only available in-game
error2: Put yourself in a greenhouse to see info.
flags: "[Greenhouse Flags]"
news:
headline: "[Greenhouse News]"
headline: "[Greenhouse News]"
controlpanel:
title: "&AGreenhouses"
title: "&AGreenhouses"

View File

@ -1,37 +1,42 @@
---
adminHelp:
info: あなたがいる温室に関する情報を提供します
reload: ファイルから設定をリロードします。
admininfo:
error: ゲーム内でのみ利用可能な温室情報
error2: 温室で情報を確認してください。
flags: "[温室旗]"
controlpanel:
title: "A温室"
error:
alreadyexists: 温室はすでに存在します!
greenhouseProtected: 温室保護
move: 最初に所有する温室に移動します。
norecipe: 温室を作ることができません!
notinside: あなたは温室の中にいません!
notowner: それを行うには、この温室の所有者でなければなりません。
notyours: これはあなたの温室ではありません!
removing: 温室を撤去!
tooexpensive: あなたは余裕がない[price]
event:
broke: あなたはこの温室を壊しました!バイオームを[biome]に戻しています!
cannotplace: ブロックを温室の上に置くことはできません!
fix: 温室を修理してから、もう一度作ります。
pistonerror: ピストンは温室の上でブロックを押すことができません!
protection:
flags:
GREENHOUSE:
name: 温室
description: |-
&b誰が温室を制御できるかを
&b設定する
greenhouses:
general:
greenhouses: 温室
errors:
move: 最初に所有する温室に移動します。
no-rank: "cあなたにはそれをするランクがありません。"
notyours: これはあなたの温室ではありません!
not-inside: "&cあなたは温室の中にいません"
tooexpensive: あなたは余裕がない[price]
alreadyexists: 温室はすでに存在します!
norecipe: 温室を作ることができません!
event:
broke: "&c温室を壊しましたバイオームを [biome]に戻しています!"
entering: "[biome]の温室に入る"
leaving: "[biome]の温室を離れる"
recipe:
blockscolor: "f"
title: "[[biome]レシピ]"
watermustbe: 水>[coverage]床面積の%。
icemustbe: 氷のブロック>床面積の[coverage]%。
lavamustbe: 溶岩> [coverage]床面積の%。
minimumblockstitle: "[必要な最小ブロック]"
nootherblocks: 他のブロックは必要ありません。
missing: 温室がありません
commands:
user:
info:
title: "A [温室の作り方]"
instructions: 4つの壁と平らなガラス屋根でガラスから箱を作り、壁に最大4つのドアを追加します。 1つのホッパーを壁または屋根に置き、水バケツを追加します。
雪や骨粉を作り、植物を自動的に育てます。 バイオームレシピを確認して、温室内で正常にブロックするために必要なブロックを確認してください。
remove:
description: あなたが所有者である場合、あなたが立っている温室を取り除きます
make:
description: 温室を作ってみる
parameters: "<レシピ>"
error:
already: "cここには温室がすでにあります"
FAIL_BAD_ROOF_BLOCKS: "c屋根には許可されていないブロックが含まれています"
@ -40,97 +45,99 @@ greenhouses:
FAIL_BLOCKS_ABOVE: "c温室の上にブロックを置くことはできません赤いガラスブロックに問題のあるブロックが表示されます。"
FAIL_HOLE_IN_ROOF: "c屋根に穴があるか、平らではありません赤いガラスブロックが問題を示しているはずです。"
FAIL_HOLE_IN_WALL: "c壁に穴が開いています"
FAIL_INSUFFICIENT_ICE: "cこのレシピを作成するには氷が足りません"
FAIL_INSUFFICIENT_LAVA: "cこのレシピを作るには溶岩が足りません"
FAIL_INSUFFICIENT_WATER: "cこのレシピを作るのに水が足りません"
FAIL_NO_ROOF: "c屋根がないようです"
FAIL_TOO_MANY_DOORS: "c温室には4つ以上のドアを置くことはできません"
FAIL_TOO_MANY_HOPPERS: "c壁または屋根に使用できるホッパーは1つだけです。"
FAIL_UNEVEN_WALLS: "c壁が不均一です。赤いガラスブロックに問題のあるブロックが表示されます。"
FAIL_INSUFFICIENT_ICE: "cこのレシピを作成するには氷が足りません"
FAIL_INSUFFICIENT_LAVA: "cこのレシピを作るには溶岩が足りません"
FAIL_INSUFFICIENT_WATER: "cこのレシピを作るのに水が足りません"
FAIL_NO_ICE: このレシピを作成するにはc氷が必要です
FAIL_NO_LAVA: このレシピを作成するにはc溶岩が必要です
FAIL_NO_WATER: このレシピを作成するにはc水が必要です
parameters: "<レシピ>"
FAIL_NO_RECIPE_FOUND: "cこの温室に一致するレシピが見つかりませんでした"
FAIL_INSUFFICIENT_BLOCKS: "&cこのレシピを作成するには、さらに多くのブロックが必要です。"
FAIL_OVERLAPPING: "c温室は壁を共有できません。申し訳ありません。"
success: "2あなたは[biome]バイオーム温室を無事に作成しました!バイオームは次のテレポートまたはログインで同期します。"
remove:
description: あなたが所有者である場合、あなたが立っている温室を取り除きます
errors:
alreadyexists: 温室はすでに存在します!
move: 最初に所有する温室に移動します。
no-rank: "cあなたにはそれをするランクがありません。"
norecipe: 温室を作ることができません!
not-inside: "cあなたは温室の中にいません"
notyours: これはあなたの温室ではありません!
tooexpensive: あなたは余裕がない[price]
general:
greenhouses: 温室
recipe:
blockscolor: "f"
minimumblockstitle: "[必要な最小ブロック]"
missing: 温室がありません
nootherblocks: 他のブロックは必要ありません。
title: "[[biome]レシピ]"
watermustbe: 水>[coverage]床面積の%。
icemustbe: 氷のブロック>床面積の[coverage]%。
lavamustbe: 溶岩> [coverage]床面積の%。
event:
broke: "&c温室を壊しましたバイオームを [biome]に戻しています!"
entering: "[biome]の温室に入る"
leaving: "[biome]の温室を離れる"
missing-blocks: "&c欠落[material] x [number]"
unknown-recipe: "c不明なレシピ"
try-these: "c次のいずれかを試してください。"
recipe-format: "&3[name]"
info:
title: "A [温室の作り方]"
instructions: 4つの壁と平らなガラス屋根でガラスから箱を作り、壁に最大4つのドアを追加します。 1つのホッパーを壁または屋根に置き、水バケツを追加します。
雪や骨粉を作り、植物を自動的に育てます。 バイオームレシピを確認して、温室内で正常にブロックするために必要なブロックを確認してください。
help:
help: 手助け
make: 温室を作ろうとする
remove: あなたが所有者である場合、あなたが立っている温室を取り除きます
info: 温室の作り方
list: 作成可能なすべての温室バイオームをリストします
make: 温室を作ろうとする
recipe: 温室バイオームの作り方を説明します
remove: あなたが所有者である場合、あなたが立っている温室を取り除きます
opengui: 温室のGUI
info:
info: "[温室情報]"
instructions: "E 4つの壁と平らなガラスのE屋根でガラスから箱を作り、壁にF 4のドアEを追加します。 E壁と屋根にF 1ホッパーEを配置し、ウォーターバケツEを追加して雪や骨粉を作り、植物を自動的に成長させます。
Eバイオームレシピを確認して、E温室内で正常にブロックを作成するために必要なブロックを確認します。"
nomore: "4これ以上温室を建設することはできません"
none: 無し
onemore: "6温室をもう1つ構築できます。"
title: "A [温室の作り方]"
unlimited: "A温室を無制限に構築できます"
welcome: "B ようこそ!手順についてはここをクリックしてください"
youcanbuild: "A温室を最大[number]個まで構築できます!"
limits:
limitedto: 許可により温室が[limit]に制限されるため、[number]が削除されました。
noneallowed: 許可により温室が許可されないため、[number]は削除されました。
list:
title: "[温室効果バイオームのレシピ]"
info: "/greenhouse recipe <番号>を使用する各温室の作り方の詳細を見る"
error:
greenhouseProtected: 温室保護
move: 最初に所有する温室に移動します。
notowner: それを行うには、この温室の所有者でなければなりません。
removing: 温室を撤去!
notyours: これはあなたの温室ではありません!
notinside: あなたは温室の中にいません!
tooexpensive: あなたは余裕がない[price]
alreadyexists: 温室はすでに存在します!
norecipe: 温室を作ることができません!
messages:
ecolost: "[location]の温室はエコシステムを失い、撤去されました。"
leave: "[owner]の温室を離れます。"
removed: この温室はもうありません...
enter: "[owner]の[biome]の温室に入る!"
leave: "[owner]の温室を離れます。"
youarein: あなたは今[owner]の[biome]の温室にいます!
removed: この温室はもうありません...
removedmessage: あなたの[biome]の温室はもうありません!
news:
headline: "[温室ニュース]"
protection:
flags:
GREENHOUSE:
name: 温室
description: |-
b誰が温室を制御できるかを
b設定する
ecolost: "[location]の温室はエコシステムを失い、撤去されました。"
info:
title: "A [温室の作り方]"
instructions: "E 4つの壁と平らなガラスのE屋根でガラスから箱を作り、壁にF 4のドアEを追加します。 E壁と屋根にF 1ホッパーEを配置し、ウォーターバケツEを追加して雪や骨粉を作り、植物を自動的に成長させます。
Eバイオームレシピを確認して、E温室内で正常にブロックを作成するために必要なブロックを確認します。"
info: "[温室情報]"
none: 無し
nomore: "4これ以上温室を建設することはできません"
onemore: "6温室をもう1つ構築できます。"
youcanbuild: "A温室を最大[number]個まで構築できます!"
unlimited: "A温室を無制限に構築できます"
welcome: "B ようこそ!手順についてはここをクリックしてください"
recipe:
blockscolor: "f"
hint: "/ greenhouse listを使用して、レシピ番号のリストを表示します"
wrongnumber: レシピ番号は1から[size]の間でなければなりません
title: "[[biome]レシピ]"
nowater: 水は許可されません。
noice: 氷は許可されていません。
nolava: 溶岩は許可されていません。
watermustbe: 水> [coverage]床面積の%。
icemustbe: 氷のブロック&gt;床面積の[coverage]%。
lavamustbe: 溶岩> [coverage]床面積の%。
minimumblockstitle: "[必要な最小ブロック]"
missing: 温室がありません
noice: 氷は許可されていません。
nolava: 溶岩は許可されていません。
nootherblocks: 他のブロックは必要ありません。
nowater: 水は許可されません。
title: "[[biome]レシピ]"
watermustbe: 水> [coverage]床面積の%。
wrongnumber: レシピ番号は1から[size]の間でなければなりません
missing: 温室がありません
event:
broke: あなたはこの温室を壊しました!バイオームを[biome]に戻しています!
fix: 温室を修理してから、もう一度作ります。
cannotplace: ブロックを温室の上に置くことはできません!
pistonerror: ピストンは温室の上でブロックを押すことができません!
limits:
noneallowed: 許可により温室が許可されないため、[number]は削除されました。
limitedto: 許可により温室が[limit]に制限されるため、[number]が削除されました。
adminHelp:
reload: ファイルから設定をリロードします。
info: あなたがいる温室に関する情報を提供します
reload:
configReloaded: ファイルから構成が再ロードされました。
admininfo:
error: ゲーム内でのみ利用可能な温室情報
error2: 温室で情報を確認してください。
flags: "[温室旗]"
news:
headline: "[温室ニュース]"
controlpanel:
title: "A温室"

View File

@ -1,7 +1,4 @@
#
# This is a YML file. Be careful when editing. Check your edits in a YAML checker like #
# the one at http://yaml-online-parser.appspot.com #
# If this file is deleted, then it will be recreate at the next reload. #
---
protection:
flags:
GREENHOUSE:
@ -12,9 +9,9 @@ greenhouses:
greenhouses: 温室
errors:
move: 移动到你拥有的第一个温室.
no-rank: '&c你没有足够的阶级去做这个.'
no-rank: "&c你没有足够的阶级去做这个."
notyours: 这不是你的温室!
not-inside: '&c你并不处于一个温室之中!'
not-inside: "&c你并不处于一个温室之中!"
tooexpensive: 你的钱不足以支付 [price]
alreadyexists: 温室已经存在!
norecipe: 无法创建一个温室!
@ -23,12 +20,12 @@ greenhouses:
entering: 你进入一个 [biome] 温室
leaving: 你离开了 [biome] 温室
recipe:
blockscolor: '&f'
title: '[[biome] 配方]'
blockscolor: "&f"
title: "[[biome] 配方]"
watermustbe: 水在地面上的占比需要大于[coverage]%.
icemustbe: 冰在地面上的占比需要大于[coverage]%.
lavamustbe: 岩浆在地面上的占比需要大于[coverage]%.
minimumblockstitle: '[最少所需的方块数目]'
minimumblockstitle: "[最少所需的方块数目]"
nootherblocks: 没有其它需要的方块了.
missing: 温室缺失了
commands:
@ -37,39 +34,37 @@ greenhouses:
description: 如果你是你现在所处的温室的主人则移除这个温室
make:
description: 尝试建造一个温室
parameters: <recipe>
parameters: "<recipe>"
error:
already: '&c这已经有一个温室了!'
FAIL_BAD_ROOF_BLOCKS: '&c屋顶包含了不被允许的方块!'
FAIL_BAD_WALL_BLOCKS: '&c墙壁包含了不被允许的方块!'
FAIL_BELOW: '&c你必须处于温室结构内才能尝试建造它'
FAIL_BLOCKS_ABOVE: '&c温室的上方不能有方块违规方块已被标红.'
FAIL_HOLE_IN_ROOF: '&c屋顶上有一个洞或者屋顶并不平整违规方块已被标红.'
FAIL_HOLE_IN_WALL: '&c墙上有一个洞!'
FAIL_NO_ROOF: '&c这儿看起来没有屋顶!'
FAIL_TOO_MANY_DOORS: '&c你的温室最多只能有四个门!'
FAIL_TOO_MANY_HOPPERS: '&c墙或屋顶上至多有一个漏斗.'
FAIL_UNEVEN_WALLS: '&c墙壁不平坦违规方块已被标红.'
FAIL_INSUFFICIENT_ICE: '&c冰的数目不足以建造这个温室'
FAIL_INSUFFICIENT_LAVA: '&c岩浆的数目不足以建造这个温室'
FAIL_INSUFFICIENT_WATER: '&c水的数目不足以建造这个温室'
FAIL_NO_ICE: '&c对于这个温室来说冰是必须的'
FAIL_NO_LAVA: '&c对于这个温室来说岩浆是必须的'
FAIL_NO_WATER: '&c对于这个温室来说水是必须的'
FAIL_INSUFFICIENT_BLOCKS: '&c你所用的方块数目不足!'
FAIL_OVERLAPPING: '&c温室间不能共享墙壁.'
success: '&2你成功的建造了一个 [biome] 群系温室! 在你下次登陆时生物群系将会刷新.'
missing-blocks: '&c缺少了 [material] x [number]'
unknown-recipe: '&c未知的温室配方'
try-these: '&c尝试以下操作:'
recipe-format: '&3[name]'
already: "&c这已经有一个温室了!"
FAIL_BAD_ROOF_BLOCKS: "&c屋顶包含了不被允许的方块!"
FAIL_BAD_WALL_BLOCKS: "&c墙壁包含了不被允许的方块!"
FAIL_BELOW: "&c你必须处于温室结构内才能尝试建造它"
FAIL_BLOCKS_ABOVE: "&c温室的上方不能有方块违规方块已被标红."
FAIL_HOLE_IN_ROOF: "&c屋顶上有一个洞或者屋顶并不平整违规方块已被标红."
FAIL_HOLE_IN_WALL: "&c墙上有一个洞!"
FAIL_NO_ROOF: "&c这儿看起来没有屋顶!"
FAIL_TOO_MANY_DOORS: "&c你的温室最多只能有四个门!"
FAIL_TOO_MANY_HOPPERS: "&c墙或屋顶上至多有一个漏斗."
FAIL_UNEVEN_WALLS: "&c墙壁不平坦违规方块已被标红."
FAIL_INSUFFICIENT_ICE: "&c冰的数目不足以建造这个温室"
FAIL_INSUFFICIENT_LAVA: "&c岩浆的数目不足以建造这个温室"
FAIL_INSUFFICIENT_WATER: "&c水的数目不足以建造这个温室"
FAIL_NO_ICE: "&c对于这个温室来说冰是必须的"
FAIL_NO_LAVA: "&c对于这个温室来说岩浆是必须的"
FAIL_NO_WATER: "&c对于这个温室来说水是必须的"
FAIL_NO_RECIPE_FOUND: "&c 找不到与此温室相匹配的配方"
FAIL_INSUFFICIENT_BLOCKS: "&c你所用的方块数目不足!"
FAIL_OVERLAPPING: "&c温室间不能共享墙壁."
success: "&2你成功的建造了一个 [biome] 群系温室! 在你下次登陆时生物群系将会刷新."
missing-blocks: "&c缺少了 [material] x [number]"
unknown-recipe: "&c未知的温室配方"
try-these: "&c尝试以下操作:"
recipe-format: "&3[name]"
info:
title: '&A[温室建造指南]'
instructions: "&E用玻璃建造一个有四面墙和屋顶的平整的立方体\n\
&E最多只能有 &F4 扇门. &E\n在墙壁或屋顶内&E放置 &F一个漏斗\
\ \n&E来放置骨粉或雪\
\ 来让作物自动生长.\n&E检查温室配方确保\
\ 你的温室包含足够的必要方块\n&E温室就顺利建造了. \n"
title: "&A[温室建造指南]"
instructions: "&E用玻璃建造一个有四面墙和屋顶的平整的立方体\n&E最多只能有 &F4 扇门. &E\n在墙壁或屋顶内&E放置 &F一个漏斗
\n&E来放置骨粉或雪 来让作物自动生长.\n&E检查温室配方确保 你的温室包含足够的必要方块\n&E温室就顺利建造了. \n"
help:
help: 帮助
make: 尝试建造一个温室
@ -79,7 +74,7 @@ help:
recipe: 告知你如何制造一个温室
opengui: 打开温室GUI
list:
title: '[温室建造指南]'
title: "[温室建造指南]"
info: 使用指令 /greenhouse recipe <number> 来查看建造每一个温室的细节
error:
greenhouseProtected: 温室已被保护
@ -99,31 +94,28 @@ messages:
removedmessage: 你的 [biome] 温室已经被移除!
ecolost: 你位于 [location] 的温室生态环境遭到破坏,它已经不再是温室了.
info:
title: '&A[如何建造一个温室]'
instructions: "&E用玻璃建造一个有四面墙和屋顶的平整的立方体\n\
&E最多只能有 &F4 扇门. &E\n在墙壁或屋顶内&E放置 &F一个漏斗\
\ \n&E来放置骨粉或雪\
\ 来让作物自动生长.\n&E检查温室配方确保\
\ 你的温室包含足够的必要方块\n&E温室就顺利建造了. \n"
info: '[温室信息]'
title: "&A[如何建造一个温室]"
instructions: "&E用玻璃建造一个有四面墙和屋顶的平整的立方体\n&E最多只能有 &F4 扇门. &E\n在墙壁或屋顶内&E放置 &F一个漏斗 \n&E来放置骨粉或雪
来让作物自动生长.\n&E检查温室配方确保 你的温室包含足够的必要方块\n&E温室就顺利建造了. \n"
info: "[温室信息]"
none:
nomore: '&4你无法建造更多的温室了!'
onemore: '&6你可以再建造一个温室.'
youcanbuild: '&A你最多能建造 [number] 个温室!'
unlimited: '&A你能建造无限多个温室!'
welcome: '&B你好! 点击这里获得更多提示'
nomore: "&4你无法建造更多的温室了!"
onemore: "&6你可以再建造一个温室."
youcanbuild: "&A你最多能建造 [number] 个温室!"
unlimited: "&A你能建造无限多个温室!"
welcome: "&B你好! 点击这里获得更多提示"
recipe:
blockscolor: '&f'
blockscolor: "&f"
hint: 使用 /greenhouse list 来看见所有温室配方的编号!
wrongnumber: 温室配方编号必须位于 1 与 [size] 之间
title: '[[biome] 配方]'
title: "[[biome] 配方]"
nowater: 不允许有水.
noice: 不允许有冰.
nolava: 不允许有岩浆.
watermustbe: 水在地面上的占比需要大于 [coverage]%.
icemustbe: 冰在地面上的占比需要大于 [coverage]%.
lavamustbe: 岩浆在地面上的占比需要大于 [coverage]%.
minimumblockstitle: '[最少所需的方块]'
minimumblockstitle: "[最少所需的方块]"
nootherblocks: 没有其它必要的方块了.
missing: 温室缺失了
event:
@ -142,8 +134,8 @@ reload:
admininfo:
error: 查看温室信息功能仅能在游戏中使用
error2: 进入一个温室才能查看其信息.
flags: '[Greenhouse Flags]'
flags: "[Greenhouse Flags]"
news:
headline: '[温室新闻]'
headline: "[温室新闻]"
controlpanel:
title: '&A温室'
title: "&A温室"

View File

@ -0,0 +1,9 @@
name: BentoBox-Greenhouses
main: world.bentobox.greenhouses.GreenhousesPladdon
version: ${project.version}${build.number}
api-version: "1.19"
authors: [tastybento]
contributors: ["The BentoBoxWorld Community"]
website: https://bentobox.world
description: ${project.description}

View File

@ -17,7 +17,7 @@ public class SettingsTest {
private Settings s;
@Before
public void setUp() throws Exception {
public void setUp() {
s = new Settings();
}

View File

@ -2,9 +2,9 @@ package world.bentobox.greenhouses.data;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -55,15 +55,12 @@ public class GreenhouseTest {
@Mock
private BiomeRecipe br;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
public void setUp() {
// RecipeManager
PowerMockito.mockStatic(RecipeManager.class);
when(br.getName()).thenReturn("test");
when(RecipeManager.getBiomeRecipies(eq("test"))).thenReturn(Optional.of(br));
when(RecipeManager.getBiomeRecipies("test")).thenReturn(Optional.of(br));
// Walls
when(walls.getMinX()).thenReturn(MINX);
when(walls.getMinZ()).thenReturn(MINZ);
@ -74,10 +71,9 @@ public class GreenhouseTest {
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
public void tearDown() {
Mockito.framework().clearInlineMocks();
}
@ -189,7 +185,7 @@ public class GreenhouseTest {
}
/**
* Test method for {@link world.bentobox.greenhouses.data.Greenhouse#setRoofHopperLocation(org.bukkit.Location)}.
* Test method for {@link world.bentobox.greenhouses.data.Greenhouse#setRoofHopperLocation(Vector)}.
*/
@Test
public void testSetRoofHopperLocation() {
@ -279,7 +275,7 @@ public class GreenhouseTest {
*/
@Test
public void testGetBiomeRecipe() {
assertNull(gh.getBiomeRecipe());
assertNotNull(gh.getBiomeRecipe());
}
/**
@ -288,7 +284,7 @@ public class GreenhouseTest {
@Test
public void testSetMissingBlocks() {
gh.setMissingBlocks(Collections.singletonMap(Material.ACACIA_BOAT, 20));
assertTrue(gh.getMissingBlocks().get(Material.ACACIA_BOAT) == 20);
assertEquals(20, (int) gh.getMissingBlocks().get(Material.ACACIA_BOAT));
}
/**
@ -296,7 +292,7 @@ public class GreenhouseTest {
*/
@Test
public void testGetMissingBlocks() {
assertNull(gh.getMissingBlocks());
assertNotNull(gh.getMissingBlocks());
}
}

View File

@ -46,6 +46,7 @@ import world.bentobox.bentobox.BentoBox;
import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.Settings;
import world.bentobox.greenhouses.data.Greenhouse;
import world.bentobox.greenhouses.managers.EcoSystemManager.GrowthBlock;
import world.bentobox.greenhouses.managers.GreenhouseManager;
import world.bentobox.greenhouses.managers.GreenhouseMap;
@ -61,7 +62,6 @@ public class BiomeRecipeTest {
@Mock
private Greenhouses addon;
private Biome type;
@Mock
private Greenhouse gh;
@ -85,20 +85,19 @@ public class BiomeRecipeTest {
@Mock
private Settings settings;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
public void setUp() {
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.createBlockData(any(Material.class))).thenReturn(bd);
type = Biome.BADLANDS;
Biome type = Biome.BADLANDS;
// Greenhouse
when(gh.getArea()).thenReturn(100);
when(gh.getFloorHeight()).thenReturn(100);
when(gh.getCeilingHeight()).thenReturn(120);
bb = new BoundingBox(10, 100, 10, 20, 120, 20);
when(gh.getBoundingBox()).thenReturn(bb);
BoundingBox ibb = bb.clone().expand(-1);
when(gh.getInternalBoundingBox()).thenReturn(ibb);
when(gh.getWorld()).thenReturn(world);
when(gh.contains(any())).thenReturn(true);
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(block);
@ -152,50 +151,50 @@ public class BiomeRecipeTest {
double convChance = 100D;
Material localMaterial = Material.WATER;
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");
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#addMobs(org.bukkit.entity.EntityType, int, org.bukkit.Material)}.
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#addMobs(org.bukkit.entity.EntityType, double, org.bukkit.Material)}.
*/
@Test
public void testAddMobs() {
EntityType mobType = EntityType.CAT;
int mobProbability = 50;
Material mobSpawnOn = Material.GRASS_PATH;
Material mobSpawnOn = Material.GRASS_BLOCK;
br.addMobs(mobType, mobProbability, mobSpawnOn);
verify(addon).log(eq(" 50.0% chance for Cat to spawn on Grass Path."));
verify(addon).log(" 50.0% chance for Cat to spawn on Grass Block.");
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#addMobs(org.bukkit.entity.EntityType, int, org.bukkit.Material)}.
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#addMobs(org.bukkit.entity.EntityType, double, org.bukkit.Material)}.
*/
@Test
public void testAddMobsOver100Percent() {
EntityType mobType = EntityType.CAT;
int mobProbability = 50;
Material mobSpawnOn = Material.GRASS_PATH;
Material mobSpawnOn = Material.GRASS_BLOCK;
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");
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#addMobs(org.bukkit.entity.EntityType, int, org.bukkit.Material)}.
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#addMobs(org.bukkit.entity.EntityType, double, org.bukkit.Material)}.
*/
@Test
public void testAddMobsOver100PercentDouble() {
EntityType mobType = EntityType.CAT;
double mobProbability = 50.5;
Material mobSpawnOn = Material.GRASS_PATH;
Material mobSpawnOn = Material.GRASS_BLOCK;
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");
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#addPlants(org.bukkit.Material, int, org.bukkit.Material)}.
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#addPlants(org.bukkit.Material, double, org.bukkit.Material)}.
*/
@Test
public void testAddPlants() {
@ -203,11 +202,11 @@ public class BiomeRecipeTest {
int plantProbability = 20;
Material plantGrowOn = Material.DIRT;
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");
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#addPlants(org.bukkit.Material, int, org.bukkit.Material)}.
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#addPlants(org.bukkit.Material, double, org.bukkit.Material)}.
*/
@Test
public void testAddPlantsOver100Percent() {
@ -216,7 +215,7 @@ public class BiomeRecipeTest {
Material plantGrowOn = Material.DIRT;
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");
}
/**
@ -227,7 +226,7 @@ public class BiomeRecipeTest {
Material blockMaterial = Material.BLACK_CONCRETE;
int blockQty = 30;
br.addReqBlocks(blockMaterial, blockQty);
verify(addon).log(eq(" BLACK_CONCRETE x 30"));
verify(addon).log(" BLACK_CONCRETE x 30");
}
/**
@ -263,29 +262,10 @@ public class BiomeRecipeTest {
Block ab = mock(Block.class);
when(ab.getType()).thenReturn(Material.WATER);
when(b.getRelative(any())).thenReturn(ab);
br.convertBlock(gh, b);
br.convertBlock(b);
verify(b).setType(Material.CLAY);
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#convertBlock(org.bukkit.block.Block)}.
*/
@Test
public void testConvertBlockNotInGreenhouse() {
// Setup
this.testAddConvBlocks();
// Mock
Block b = mock(Block.class);
when(b.getType()).thenReturn(Material.SAND);
Block ab = mock(Block.class);
when(ab.getType()).thenReturn(Material.WATER);
when(b.getRelative(any())).thenReturn(ab);
when(ab.getLocation()).thenReturn(location);
when(gh.contains(any())).thenReturn(false);
br.convertBlock(gh, b);
verify(b, never()).setType(any());
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#convertBlock(org.bukkit.block.Block)}.
*/
@ -299,7 +279,7 @@ public class BiomeRecipeTest {
Block ab = mock(Block.class);
when(ab.getType()).thenReturn(Material.SAND);
when(b.getRelative(any())).thenReturn(ab);
br.convertBlock(gh, b);
br.convertBlock(b);
verify(b, never()).setType(Material.CLAY);
}
@ -311,10 +291,30 @@ public class BiomeRecipeTest {
// Mock
Block b = mock(Block.class);
when(b.getType()).thenReturn(Material.SAND);
br.convertBlock(gh, b);
br.convertBlock(b);
verify(b, never()).setType(Material.CLAY);
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#convertBlock(org.bukkit.block.Block)}.
*/
@Test
public void testConvertBlockNoLocalBlock() {
// Setup
Material oldMaterial = Material.SAND;
Material newMaterial = Material.CLAY;
double convChance = 100D;
br.addConvBlocks(oldMaterial, newMaterial, convChance, null);
// Mock
Block b = mock(Block.class);
when(b.getType()).thenReturn(Material.SAND);
br.convertBlock(b);
verify(b, never()).getRelative(any());
verify(b).setType(Material.CLAY);
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#convertBlock(org.bukkit.block.Block)}.
*/
@ -333,7 +333,7 @@ public class BiomeRecipeTest {
Block ab = mock(Block.class);
when(ab.getType()).thenReturn(Material.WATER);
when(b.getRelative(any())).thenReturn(ab);
br.convertBlock(gh, b);
br.convertBlock(b);
verify(b, never()).setType(Material.CLAY);
}
@ -435,12 +435,12 @@ public class BiomeRecipeTest {
@Test
public void testSpawnMobOutsideWall() {
when(block.getY()).thenReturn(10);
when(block.getType()).thenReturn(Material.GRASS_PATH);
when(block.getType()).thenReturn(Material.GRASS_BLOCK);
when(block.getRelative(any())).thenReturn(block);
EntityType mobType = EntityType.CAT;
int mobProbability = 100;
Material mobSpawnOn = Material.GRASS_PATH;
Material mobSpawnOn = Material.GRASS_BLOCK;
Entity cat = mock(Cat.class);
// Same box as greenhouse
@ -451,7 +451,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn);
assertFalse(br.spawnMob(block));
verify(world).spawnEntity(eq(location), eq(EntityType.CAT));
verify(world).spawnEntity(location, EntityType.CAT);
verify(location).add(any(Vector.class));
}
@ -461,12 +461,12 @@ public class BiomeRecipeTest {
@Test
public void testSpawnMob() {
when(block.getY()).thenReturn(10);
when(block.getType()).thenReturn(Material.GRASS_PATH);
when(block.getType()).thenReturn(Material.GRASS_BLOCK);
when(block.getRelative(any())).thenReturn(block);
EntityType mobType = EntityType.CAT;
int mobProbability = 100;
Material mobSpawnOn = Material.GRASS_PATH;
Material mobSpawnOn = Material.GRASS_BLOCK;
Entity cat = mock(Cat.class);
// Exactly 1 block smaller than the greenhouse blocks
@ -477,7 +477,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn);
assertTrue(br.spawnMob(block));
verify(world).spawnEntity(eq(location), eq(EntityType.CAT));
verify(world).spawnEntity(location, EntityType.CAT);
verify(location).add(any(Vector.class));
}
@ -487,12 +487,12 @@ public class BiomeRecipeTest {
@Test
public void testSpawnMobHoglin() {
when(block.getY()).thenReturn(10);
when(block.getType()).thenReturn(Material.GRASS_PATH);
when(block.getType()).thenReturn(Material.GRASS_BLOCK);
when(block.getRelative(any())).thenReturn(block);
EntityType mobType = EntityType.HOGLIN;
int mobProbability = 100;
Material mobSpawnOn = Material.GRASS_PATH;
Material mobSpawnOn = Material.GRASS_BLOCK;
Hoglin hoglin = mock(Hoglin.class);
// Exactly 1 block smaller than the greenhouse blocks
@ -504,7 +504,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn);
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(hoglin).setImmuneToZombification(true);
}
@ -515,12 +515,12 @@ public class BiomeRecipeTest {
@Test
public void testSpawnMobPiglin() {
when(block.getY()).thenReturn(10);
when(block.getType()).thenReturn(Material.GRASS_PATH);
when(block.getType()).thenReturn(Material.GRASS_BLOCK);
when(block.getRelative(any())).thenReturn(block);
EntityType mobType = EntityType.PIGLIN;
int mobProbability = 100;
Material mobSpawnOn = Material.GRASS_PATH;
Material mobSpawnOn = Material.GRASS_BLOCK;
Piglin piglin = mock(Piglin.class);
// Exactly 1 block smaller than the greenhouse blocks
@ -532,7 +532,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn);
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(piglin).setImmuneToZombification(true);
}
@ -545,12 +545,12 @@ public class BiomeRecipeTest {
when(world.getEnvironment()).thenReturn(Environment.NETHER);
when(block.getY()).thenReturn(10);
when(block.getType()).thenReturn(Material.GRASS_PATH);
when(block.getType()).thenReturn(Material.GRASS_BLOCK);
when(block.getRelative(any())).thenReturn(block);
EntityType mobType = EntityType.PIGLIN;
int mobProbability = 100;
Material mobSpawnOn = Material.GRASS_PATH;
Material mobSpawnOn = Material.GRASS_BLOCK;
Piglin piglin = mock(Piglin.class);
// Exactly 1 block smaller than the greenhouse blocks
@ -562,7 +562,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn);
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(piglin, never()).setImmuneToZombification(true);
}
@ -573,12 +573,12 @@ public class BiomeRecipeTest {
@Test
public void testSpawnMobWrongSurface() {
when(block.getY()).thenReturn(10);
when(block.getType()).thenReturn(Material.GRASS_BLOCK);
when(block.getType()).thenReturn(Material.STONE);
when(block.getRelative(any())).thenReturn(block);
EntityType mobType = EntityType.CAT;
int mobProbability = 100;
Material mobSpawnOn = Material.GRASS_PATH;
Material mobSpawnOn = Material.GRASS_BLOCK;
Entity cat = mock(Cat.class);
when(world.spawnEntity(any(), any())).thenReturn(cat);
@ -586,28 +586,9 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn);
assertFalse(br.spawnMob(block));
verify(world, never()).spawnEntity(eq(location), eq(EntityType.CAT));
verify(world, never()).spawnEntity(location, EntityType.CAT);
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#spawnMob(org.bukkit.block.Block)}.
*/
@Test
public void testSpawnMobFailToSpawn() {
when(block.getY()).thenReturn(10);
when(block.getType()).thenReturn(Material.GRASS_PATH);
when(block.getRelative(any())).thenReturn(block);
EntityType mobType = EntityType.CAT;
int mobProbability = 100;
Material mobSpawnOn = Material.GRASS_PATH;
br.addMobs(mobType, mobProbability, mobSpawnOn);
assertFalse(br.spawnMob(block));
verify(world).spawnEntity(eq(location), eq(EntityType.CAT));
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#getRecipeBlocks()}.
*/
@ -630,7 +611,7 @@ public class BiomeRecipeTest {
@Test
public void testGrowPlantNotAir() {
when(block.getType()).thenReturn(Material.SOUL_SAND);
assertFalse(br.growPlant(block));
assertFalse(br.growPlant(new GrowthBlock(block, true), false));
}
/**
@ -640,7 +621,7 @@ public class BiomeRecipeTest {
public void testGrowPlantNoPlants() {
when(block.getType()).thenReturn(Material.AIR);
when(block.isEmpty()).thenReturn(true);
assertFalse(br.growPlant(block));
assertFalse(br.growPlant(new GrowthBlock(block, true), false));
}
/**
@ -652,7 +633,7 @@ public class BiomeRecipeTest {
when(block.getType()).thenReturn(Material.AIR);
when(block.isEmpty()).thenReturn(true);
assertTrue(br.addPlants(Material.BAMBOO_SAPLING, 100, Material.GRASS_BLOCK));
assertFalse(br.growPlant(block));
assertFalse(br.growPlant(new GrowthBlock(block, true), false));
}
/**
@ -668,11 +649,46 @@ public class BiomeRecipeTest {
when(block.getRelative(any())).thenReturn(ob);
assertTrue(br.addPlants(Material.BAMBOO_SAPLING, 100, Material.GRASS_BLOCK));
assertTrue(br.growPlant(block));
assertTrue(br.growPlant(new GrowthBlock(block, true), false));
verify(world).spawnParticle(eq(Particle.SNOWBALL), any(Location.class), anyInt(), anyDouble(), anyDouble(), anyDouble());
verify(block).setBlockData(eq(bd), eq(false));
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#growPlant(org.bukkit.block.Block)}.
*/
@Test
public void testGrowPlantCeilingPlants() {
when(block.getY()).thenReturn(10);
when(block.getType()).thenReturn(Material.AIR);
when(block.isEmpty()).thenReturn(true);
Block ob = mock(Block.class);
when(ob.getType()).thenReturn(Material.GLASS);
when(block.getRelative(any())).thenReturn(ob);
assertTrue(br.addPlants(Material.SPORE_BLOSSOM, 100, Material.GLASS));
assertTrue(br.growPlant(new GrowthBlock(block, false), false));
verify(world).spawnParticle(eq(Particle.SNOWBALL), any(Location.class), anyInt(), anyDouble(), anyDouble(), anyDouble());
verify(block).setBlockData(eq(bd), eq(false));
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#growPlant(org.bukkit.block.Block)}.
*/
@Test
public void testGrowPlantCeilingPlantsFail() {
when(block.getY()).thenReturn(10);
when(block.getType()).thenReturn(Material.AIR);
when(block.isEmpty()).thenReturn(true);
Block ob = mock(Block.class);
when(ob.getType()).thenReturn(Material.GLASS);
when(block.getRelative(any())).thenReturn(ob);
assertTrue(br.addPlants(Material.SPORE_BLOSSOM, 100, Material.GLASS));
// Not a ceiling block
assertFalse(br.growPlant(new GrowthBlock(block, true), false));
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#growPlant(org.bukkit.block.Block)}.
*/
@ -685,13 +701,13 @@ public class BiomeRecipeTest {
when(block.isEmpty()).thenReturn(true);
Block ob = mock(Block.class);
when(ob.getType()).thenReturn(Material.GRASS_BLOCK);
when(block.getRelative(eq(BlockFace.DOWN))).thenReturn(ob);
when(block.getRelative(eq(BlockFace.UP))).thenReturn(block);
when(block.getRelative(BlockFace.DOWN)).thenReturn(ob);
when(block.getRelative(BlockFace.UP)).thenReturn(block);
assertTrue(br.addPlants(Material.SUNFLOWER, 100, Material.GRASS_BLOCK));
assertTrue(br.growPlant(block));
assertTrue(br.growPlant(new GrowthBlock(block, true), false));
verify(world).spawnParticle(eq(Particle.SNOWBALL), any(Location.class), anyInt(), anyDouble(), anyDouble(), anyDouble());
verify(bisected).setHalf(eq(Half.BOTTOM));
verify(bisected).setHalf(eq(Half.TOP));
verify(bisected).setHalf(Half.BOTTOM);
verify(bisected).setHalf(Half.TOP);
}
/**
@ -706,10 +722,10 @@ public class BiomeRecipeTest {
when(block.isEmpty()).thenReturn(true);
Block ob = mock(Block.class);
when(ob.getType()).thenReturn(Material.GRASS_BLOCK);
when(block.getRelative(eq(BlockFace.DOWN))).thenReturn(ob);
when(block.getRelative(eq(BlockFace.UP))).thenReturn(ob);
when(block.getRelative(BlockFace.DOWN)).thenReturn(ob);
when(block.getRelative(BlockFace.UP)).thenReturn(ob);
assertTrue(br.addPlants(Material.SUNFLOWER, 100, Material.GRASS_BLOCK));
assertFalse(br.growPlant(block));
assertFalse(br.growPlant(new GrowthBlock(block, true), false));
}
/**
@ -751,8 +767,8 @@ public class BiomeRecipeTest {
*/
@Test
public void testSetType() {
br.setType(Biome.BADLANDS_PLATEAU);
assertEquals(Biome.BADLANDS_PLATEAU, br.getBiome());
br.setType(Biome.BADLANDS);
assertEquals(Biome.BADLANDS, br.getBiome());
}
/**

View File

@ -46,15 +46,10 @@ public class RoofTest {
@Mock
private AsyncWorldCache cache;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
public void setUp() {
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
when(Tag.TRAPDOORS.isTagged(Material.BIRCH_TRAPDOOR)).thenReturn(true);
PowerMockito.mockStatic(Greenhouses.class, Mockito.RETURNS_MOCKS);
when(Greenhouses.getInstance()).thenReturn(addon);
s = new Settings();
when(addon.getSettings()).thenReturn(s);
@ -92,14 +87,14 @@ public class RoofTest {
when(location.clone()).thenReturn(location);
// Test
roof = new Roof(cache, location);
roof = new Roof(cache, location, addon);
assertTrue(roof.findRoof(new Vector(10,10,10)));
}
@Test
public void testNoGlass() {
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)));
}
@ -172,13 +167,13 @@ public class RoofTest {
*/
@Test
public void testWallBlocks() {
assertFalse(Roof.roofBlocks(Material.ACACIA_BOAT));
assertTrue(Roof.roofBlocks(Material.GLASS));
assertTrue(Roof.roofBlocks(Material.GLOWSTONE));
assertFalse(Roof.roofBlocks(Material.ACACIA_DOOR));
assertTrue(Roof.roofBlocks(Material.HOPPER));
assertTrue(Roof.roofBlocks(Material.PURPLE_STAINED_GLASS_PANE));
assertTrue(Roof.roofBlocks(Material.BIRCH_TRAPDOOR));
assertFalse(roof.roofBlocks(Material.ACACIA_BOAT));
assertTrue(roof.roofBlocks(Material.GLASS));
assertTrue(roof.roofBlocks(Material.GLOWSTONE));
assertFalse(roof.roofBlocks(Material.ACACIA_DOOR));
assertTrue(roof.roofBlocks(Material.HOPPER));
assertTrue(roof.roofBlocks(Material.PURPLE_STAINED_GLASS_PANE));
assertTrue(roof.roofBlocks(Material.BIRCH_TRAPDOOR));
}
/**
@ -188,12 +183,12 @@ public class RoofTest {
public void testWallBlocksNoGlowStoneNoPanes() {
s.setAllowGlowstone(false);
s.setAllowPanes(false);
assertFalse(Roof.roofBlocks(Material.ACACIA_BOAT));
assertTrue(Roof.roofBlocks(Material.GLASS));
assertFalse(Roof.roofBlocks(Material.GLOWSTONE));
assertFalse(Roof.roofBlocks(Material.ACACIA_DOOR));
assertTrue(Roof.roofBlocks(Material.HOPPER));
assertFalse(Roof.roofBlocks(Material.PURPLE_STAINED_GLASS_PANE));
assertTrue(Roof.roofBlocks(Material.BIRCH_TRAPDOOR));
assertFalse(roof.roofBlocks(Material.ACACIA_BOAT));
assertTrue(roof.roofBlocks(Material.GLASS));
assertFalse(roof.roofBlocks(Material.GLOWSTONE));
assertFalse(roof.roofBlocks(Material.ACACIA_DOOR));
assertTrue(roof.roofBlocks(Material.HOPPER));
assertFalse(roof.roofBlocks(Material.PURPLE_STAINED_GLASS_PANE));
assertTrue(roof.roofBlocks(Material.BIRCH_TRAPDOOR));
}
}

View File

@ -58,21 +58,16 @@ public class WallsTest {
private CompletableFuture<Walls> r;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
public void setUp() {
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
when(Tag.TRAPDOORS.isTagged(Material.BIRCH_TRAPDOOR)).thenReturn(true);
// Declare mock after mocking Bukkit
roof = mock(Roof.class);
PowerMockito.mockStatic(Greenhouses.class, Mockito.RETURNS_MOCKS);
when(Greenhouses.getInstance()).thenReturn(addon);
s = new Settings();
when(addon.getSettings()).thenReturn(s);
when(addon.getPlugin()).thenReturn(plugin);
when(addon.wallBlocks(any())).thenCallRealMethod();
walls = new Walls(cache);
when(world.getMaxHeight()).thenReturn(255);
when(location.getWorld()).thenReturn(world);
@ -102,7 +97,7 @@ public class WallsTest {
*/
@Test
public void testLookAround() {
WallFinder wf = walls.new WallFinder();
WallFinder wf = new WallFinder();
walls.lookAround(location, wf, roof);
assertTrue(wf.stopMaxX);
assertTrue(wf.stopMaxZ);
@ -119,7 +114,7 @@ public class WallsTest {
*/
@Test
public void testAnalyzeFindings() {
WallFinder wf = walls.new WallFinder();
WallFinder wf = new WallFinder();
walls.analyzeFindings(wf, roof);
assertFalse(wf.stopMaxX);
assertFalse(wf.stopMaxZ);
@ -140,7 +135,7 @@ public class WallsTest {
walls.maxX = 1;
walls.minZ = -1;
walls.maxZ = 1;
WallFinder wf = walls.new WallFinder();
WallFinder wf = new WallFinder();
walls.analyzeFindings(wf, roof);
assertTrue(wf.stopMaxX);
assertTrue(wf.stopMaxZ);
@ -153,11 +148,11 @@ public class WallsTest {
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.Walls#lookAtBlockFaces(world.bentobox.greenhouses.greenhouse.Walls.WallFinder, org.bukkit.World, int, int, int)}.
* Test method for {@link world.bentobox.greenhouses.greenhouse.Walls#lookAtBlockFaces(WallFinder, int, int, int)}.
*/
@Test
public void testLookAtBlockFaces() {
WallFinder wf = walls.new WallFinder();
WallFinder wf = new WallFinder();
walls.lookAtBlockFaces(wf, 0, 5, -1);
assertTrue(wf.stopMaxX);
assertTrue(wf.stopMaxZ);
@ -166,12 +161,12 @@ public class WallsTest {
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.Walls#lookAtBlockFaces(world.bentobox.greenhouses.greenhouse.Walls.WallFinder, org.bukkit.World, int, int, int)}.
* Test method for {@link world.bentobox.greenhouses.greenhouse.Walls#lookAtBlockFaces(WallFinder, int, int, int)}.
*/
@Test
public void testLookAtBlockFacesNoGlass() {
when(cache.getBlockType(anyInt(), anyInt(), anyInt())).thenReturn(Material.AIR);
WallFinder wf = walls.new WallFinder();
WallFinder wf = new WallFinder();
walls.lookAtBlockFaces(wf, 0, 5, -1);
assertFalse(wf.stopMaxX);
assertFalse(wf.stopMaxZ);
@ -180,15 +175,15 @@ public class WallsTest {
}
/**
* Test method for {@link world.bentobox.greenhouses.greenhouse.Walls#getFloorY(org.bukkit.World, int, int, int, int, int)}.
* Test method for {@link world.bentobox.greenhouses.greenhouse.Walls#getFloorY(int, int, int, int, int, int)}.
*/
@Test
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(org.bukkit.World, int, int, int, int, int)}.
* Test method for {@link world.bentobox.greenhouses.greenhouse.Walls#getFloorY(int, int, int, int, int, int)}.
*/
@Test
public void testGetFloorY() {
@ -196,7 +191,7 @@ public class WallsTest {
Material.GLASS, Material.GLASS,
Material.GLASS, Material.GLASS,
Material.AIR);
assertEquals(8, walls.getFloorY(10, 0, 1, 0, 1));
assertEquals(8, walls.getFloorY(10, 0, 1, 0, 1, -64));
}
/**
@ -204,13 +199,13 @@ public class WallsTest {
*/
@Test
public void testWallBlocks() {
assertFalse(Walls.wallBlocks(Material.ACACIA_BOAT));
assertTrue(Walls.wallBlocks(Material.GLASS));
assertTrue(Walls.wallBlocks(Material.GLOWSTONE));
assertTrue(Walls.wallBlocks(Material.ACACIA_DOOR));
assertTrue(Walls.wallBlocks(Material.HOPPER));
assertTrue(Walls.wallBlocks(Material.PURPLE_STAINED_GLASS_PANE));
assertFalse(Walls.wallBlocks(Material.BIRCH_TRAPDOOR));
assertFalse(addon.wallBlocks(Material.ACACIA_BOAT));
assertTrue(addon.wallBlocks(Material.GLASS));
assertTrue(addon.wallBlocks(Material.GLOWSTONE));
assertTrue(addon.wallBlocks(Material.ACACIA_DOOR));
assertTrue(addon.wallBlocks(Material.HOPPER));
assertTrue(addon.wallBlocks(Material.PURPLE_STAINED_GLASS_PANE));
assertFalse(addon.wallBlocks(Material.BIRCH_TRAPDOOR));
}
/**
@ -220,13 +215,13 @@ public class WallsTest {
public void testWallBlocksNoGlowStoneNoPanes() {
s.setAllowGlowstone(false);
s.setAllowPanes(false);
assertFalse(Walls.wallBlocks(Material.ACACIA_BOAT));
assertTrue(Walls.wallBlocks(Material.GLASS));
assertFalse(Walls.wallBlocks(Material.GLOWSTONE));
assertTrue(Walls.wallBlocks(Material.ACACIA_DOOR));
assertTrue(Walls.wallBlocks(Material.HOPPER));
assertFalse(Walls.wallBlocks(Material.PURPLE_STAINED_GLASS_PANE));
assertFalse(Walls.wallBlocks(Material.BIRCH_TRAPDOOR));
assertFalse(addon.wallBlocks(Material.ACACIA_BOAT));
assertTrue(addon.wallBlocks(Material.GLASS));
assertFalse(addon.wallBlocks(Material.GLOWSTONE));
assertTrue(addon.wallBlocks(Material.ACACIA_DOOR));
assertTrue(addon.wallBlocks(Material.HOPPER));
assertFalse(addon.wallBlocks(Material.PURPLE_STAINED_GLASS_PANE));
assertFalse(addon.wallBlocks(Material.BIRCH_TRAPDOOR));
}
/**

View File

@ -27,9 +27,9 @@ import org.bukkit.event.player.PlayerBucketEmptyEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -81,11 +81,8 @@ public class GreenhouseEventsTest {
@Mock
private ItemStack waterBucket;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
public void setUp() {
PowerMockito.mockStatic(User.class);
when(User.getInstance(any(Player.class))).thenReturn(user);
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
@ -130,14 +127,7 @@ public class GreenhouseEventsTest {
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
}
/**
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPlayerInteractInNether(org.bukkit.event.player.PlayerInteractEvent)}.
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPlayerInteractInNether(PlayerBucketEmptyEvent)}.
*/
@Test
public void testOnPlayerInteractInNetherInGreenhouse() {
@ -148,13 +138,13 @@ public class GreenhouseEventsTest {
when(nextBlock.getLocation()).thenReturn(location);
ItemStack item = mock(ItemStack.class);
when(item.getType()).thenReturn(Material.WATER_BUCKET);
PlayerBucketEmptyEvent e = new PlayerBucketEmptyEvent(player, nextBlock, clickedBlock, BlockFace.UP, Material.WATER_BUCKET, item);
PlayerBucketEmptyEvent e = new PlayerBucketEmptyEvent(player, nextBlock, clickedBlock, BlockFace.UP, Material.WATER_BUCKET, item, EquipmentSlot.HAND);
ghe.onPlayerInteractInNether(e);
verify(nextBlock).setType(Material.WATER);
}
/**
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPlayerInteractInNether(org.bukkit.event.player.PlayerInteractEvent)}.
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPlayerInteractInNether(PlayerBucketEmptyEvent)}.
*/
@Test
public void testOnPlayerInteractInNetherOutsideOfGreenhouse() {
@ -165,13 +155,13 @@ public class GreenhouseEventsTest {
when(nextBlock.getLocation()).thenReturn(mock(Location.class));
ItemStack item = mock(ItemStack.class);
when(item.getType()).thenReturn(Material.WATER_BUCKET);
PlayerBucketEmptyEvent e = new PlayerBucketEmptyEvent(player, nextBlock, clickedBlock, BlockFace.UP, Material.WATER_BUCKET, item);
PlayerBucketEmptyEvent e = new PlayerBucketEmptyEvent(player, nextBlock, clickedBlock, BlockFace.UP, Material.WATER_BUCKET, item, EquipmentSlot.HAND);
ghe.onPlayerInteractInNether(e);
verify(nextBlock, never()).setType(Material.WATER);
}
/**
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPlayerInteractInNether(org.bukkit.event.player.PlayerInteractEvent)}.
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPlayerInteractInNether(PlayerBucketEmptyEvent)}.
*/
@Test
public void testOnPlayerInteractInNetherGreenhouse() {
@ -181,13 +171,13 @@ public class GreenhouseEventsTest {
when(clickedBlock.getRelative(any())).thenReturn(nextBlock);
ItemStack item = mock(ItemStack.class);
when(item.getType()).thenReturn(Material.WATER_BUCKET);
PlayerBucketEmptyEvent e = new PlayerBucketEmptyEvent(player, nextBlock, clickedBlock, BlockFace.UP, Material.WATER_BUCKET, item);
PlayerBucketEmptyEvent e = new PlayerBucketEmptyEvent(player, nextBlock, clickedBlock, BlockFace.UP, Material.WATER_BUCKET, item, EquipmentSlot.HAND);
ghe.onPlayerInteractInNether(e);
verify(nextBlock, never()).setType(Material.WATER);
}
/**
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPlayerInteractInNether(org.bukkit.event.player.PlayerInteractEvent)}.
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPlayerInteractInNether(PlayerBucketEmptyEvent)}.
*/
@Test
public void testOnPlayerInteractInNetherNotInNether() {
@ -200,13 +190,13 @@ public class GreenhouseEventsTest {
when(nextBlock.getWorld()).thenReturn(world);
ItemStack item = mock(ItemStack.class);
when(item.getType()).thenReturn(Material.WATER_BUCKET);
PlayerBucketEmptyEvent e = new PlayerBucketEmptyEvent(player, nextBlock, clickedBlock, BlockFace.UP, Material.WATER_BUCKET, item);
PlayerBucketEmptyEvent e = new PlayerBucketEmptyEvent(player, nextBlock, clickedBlock, BlockFace.UP, Material.WATER_BUCKET, item, EquipmentSlot.HAND);
ghe.onPlayerInteractInNether(e);
verify(nextBlock, never()).setType(Material.WATER);
}
/**
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPlayerInteractInNether(org.bukkit.event.player.PlayerInteractEvent)}.
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPlayerInteractInNether(PlayerBucketEmptyEvent)}.
*/
@Test
public void testOnPlayerInteractInNetherNotWaterBucket() {
@ -216,13 +206,13 @@ public class GreenhouseEventsTest {
when(clickedBlock.getRelative(any())).thenReturn(nextBlock);
ItemStack item = mock(ItemStack.class);
when(item.getType()).thenReturn(Material.ACACIA_BOAT);
PlayerBucketEmptyEvent e = new PlayerBucketEmptyEvent(player, nextBlock, clickedBlock, BlockFace.UP, Material.WATER, item);
PlayerBucketEmptyEvent e = new PlayerBucketEmptyEvent(player, nextBlock, clickedBlock, BlockFace.UP, Material.WATER, item, EquipmentSlot.HAND);
ghe.onPlayerInteractInNether(e);
verify(nextBlock, never()).setType(Material.WATER);
}
/**
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPlayerInteractInNether(org.bukkit.event.player.PlayerInteractEvent)}.
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPlayerInteractInNether(PlayerBucketEmptyEvent)}.
*/
@Test
public void testOnPlayerInteractInNetherNotInGreenhouse() {
@ -233,7 +223,7 @@ public class GreenhouseEventsTest {
when(clickedBlock.getRelative(any())).thenReturn(nextBlock);
ItemStack item = mock(ItemStack.class);
when(item.getType()).thenReturn(Material.WATER_BUCKET);
PlayerBucketEmptyEvent e = new PlayerBucketEmptyEvent(player, nextBlock, clickedBlock, BlockFace.UP, Material.WATER_BUCKET, item);
PlayerBucketEmptyEvent e = new PlayerBucketEmptyEvent(player, nextBlock, clickedBlock, BlockFace.UP, Material.WATER_BUCKET, item, EquipmentSlot.HAND);
ghe.onPlayerInteractInNether(e);
verify(nextBlock, never()).setType(Material.WATER);
}
@ -307,7 +297,7 @@ public class GreenhouseEventsTest {
ghe.onIceBreak(e);
verify(block).setType(Material.AIR);
assertTrue(e.isCancelled());
verify(world).playSound(any(), eq(Sound.BLOCK_GLASS_BREAK), eq(1F), eq(1F));
verify(world).playSound(any(Location.class), eq(Sound.BLOCK_GLASS_BREAK), eq(1F), eq(1F));
}

View File

@ -1,39 +1,47 @@
/**
*
*/
package world.bentobox.greenhouses.managers;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.List;
import java.util.Optional;
import org.bukkit.Bukkit;
import org.bukkit.Keyed;
import org.bukkit.Location;
import org.bukkit.Tag;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.greenhouses.data.Greenhouse;
import world.bentobox.greenhouses.greenhouse.BiomeRecipe;
import world.bentobox.greenhouses.managers.EcoSystemManager.GrowthBlock;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class})
@PrepareForTest({Bukkit.class, BentoBox.class, Tag.class, RecipeManager.class})
public class EcoSystemManagerTest {
private Greenhouse gh;
@ -47,14 +55,21 @@ public class EcoSystemManagerTest {
private Block liquid;
@Mock
private Block plant;
@Mock
private BiomeRecipe recipe;
// CUT
private EcoSystemManager eco;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
public void setUp() {
PowerMockito.mockStatic(Tag.class, Mockito.RETURNS_MOCKS);
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
@SuppressWarnings("unchecked")
Tag<Keyed> tag = mock(Tag.class);
when(Bukkit.getTag(anyString(), any(), any())).thenReturn(tag);
gh = new Greenhouse();
// 4x4x4 greenhouse
BoundingBox bb = BoundingBox.of(new Vector(0,0,0), new Vector(6,5,6));
@ -68,100 +83,110 @@ public class EcoSystemManagerTest {
// Liquid false
when(air.isEmpty()).thenReturn(true);
when(air.isPassable()).thenReturn(true);
when(air.getRelative(eq(BlockFace.UP))).thenReturn(air);
when(air.getRelative(BlockFace.UP)).thenReturn(air);
// Plant
// Empty false
// Liquid false
when(plant.isPassable()).thenReturn(true);
when(plant.getRelative(eq(BlockFace.UP))).thenReturn(air);
when(plant.getRelative(BlockFace.UP)).thenReturn(air);
// Liquid
// Empty false
when(liquid.isLiquid()).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
// Empty false
// Passable false
// Liquid false
when(block.getRelative(eq(BlockFace.UP))).thenReturn(air);
when(block.getRelative(BlockFace.UP)).thenReturn(air);
// Recipe
when(recipe.noMobs()).thenReturn(true);
PowerMockito.mockStatic(RecipeManager.class, Mockito.RETURNS_MOCKS);
when(RecipeManager.getBiomeRecipies(any())).thenReturn(Optional.of(recipe));
eco = new EcoSystemManager(null, null);
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(world.bentobox.greenhouses.data.Greenhouse)}.
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(Greenhouse, boolean)}.
*/
@Test
public void testGetAvailableBlocksAirAboveBlock() {
List<Block> result = eco.getAvailableBlocks(gh, false);
List<GrowthBlock> result = eco.getAvailableBlocks(gh, false);
assertEquals(16, result.size());
assertEquals(air, result.get(0));
assertEquals(air, result.get(0).block());
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(world.bentobox.greenhouses.data.Greenhouse)}.
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(Greenhouse, boolean)}.
*/
@Test
public void testGetAvailableBlocksPlantAboveBlock() {
when(block.getRelative(eq(BlockFace.UP))).thenReturn(plant);
List<Block> result = eco.getAvailableBlocks(gh, false);
List<GrowthBlock> result = eco.getAvailableBlocks(gh, false);
assertEquals(16, result.size());
assertEquals(plant, result.get(0));
assertEquals(plant, result.get(0).block());
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(world.bentobox.greenhouses.data.Greenhouse)}.
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(Greenhouse, boolean)}.
*/
@Test
public void testGetAvailableBlocksAllAir() {
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(air);
List<Block> result = eco.getAvailableBlocks(gh, false);
List<GrowthBlock> result = eco.getAvailableBlocks(gh, false);
assertEquals(0, result.size());
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(world.bentobox.greenhouses.data.Greenhouse)}.
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(Greenhouse, boolean)}.
*/
@Test
public void testGetAvailableBlocksAllLiquid() {
when(liquid.getRelative(eq(BlockFace.UP))).thenReturn(liquid);
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(liquid);
List<Block> 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());
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(world.bentobox.greenhouses.data.Greenhouse)}.
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(Greenhouse, boolean)}.
*/
@Test
public void testGetAvailableBlocksAllPlant() {
when(plant.getRelative(eq(BlockFace.UP))).thenReturn(plant);
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(plant);
List<Block> result = eco.getAvailableBlocks(gh, false);
List<GrowthBlock> result = eco.getAvailableBlocks(gh, false);
assertEquals(16, result.size());
assertEquals(plant, result.get(0));
assertEquals(plant, result.get(0).block());
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(world.bentobox.greenhouses.data.Greenhouse)}.
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(Greenhouse, boolean)}.
*/
@Test
public void testGetAvailableBlocksLiquidAboveBlockIgnoreLiquids() {
when(block.getRelative(eq(BlockFace.UP))).thenReturn(liquid);
List<Block> result = eco.getAvailableBlocks(gh, true);
List<GrowthBlock> result = eco.getAvailableBlocks(gh, true);
assertEquals(16, result.size());
assertEquals(liquid, result.get(0));
assertEquals(liquid, result.get(0).block());
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(world.bentobox.greenhouses.data.Greenhouse)}.
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(Greenhouse, boolean)}.
*/
@Test
public void testGetAvailableBlocksAirAboveLiquidNotIgnoreLiquids() {
@ -171,15 +196,15 @@ public class EcoSystemManagerTest {
when(liquid.getRelative(eq(BlockFace.UP))).thenReturn(air);
when(block.getRelative(eq(BlockFace.UP))).thenReturn(liquid);
List<Block> result = eco.getAvailableBlocks(gh, false);
List<GrowthBlock> result = eco.getAvailableBlocks(gh, false);
assertEquals(16, result.size());
for (int i = 0; i< result.size(); i++) {
assertEquals(air, result.get(i));
for (GrowthBlock value : result) {
assertEquals(air, value.block());
}
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(world.bentobox.greenhouses.data.Greenhouse)}.
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(Greenhouse, boolean)}.
*/
@Test
public void testGetAvailableBlocksAirAboveLiquidIgnoreLiquids() {
@ -189,10 +214,63 @@ public class EcoSystemManagerTest {
when(liquid.getRelative(eq(BlockFace.UP))).thenReturn(air);
when(block.getRelative(eq(BlockFace.UP))).thenReturn(liquid);
List<Block> result = eco.getAvailableBlocks(gh, true);
List<GrowthBlock> result = eco.getAvailableBlocks(gh, true);
assertEquals(16, result.size());
for (int i = 0; i< result.size(); i++) {
assertEquals(liquid, result.get(i));
for (GrowthBlock value : result) {
assertEquals(liquid, value.block());
}
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#addMobs(Greenhouse)}.
*/
@Test
public void testAddMobsChunkNotLoaded() {
assertFalse(eco.addMobs(gh));
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#addMobs(Greenhouse)}.
*/
@Test
public void testAddMobsChunkLoadedNoMobs() {
when(world.isChunkLoaded(anyInt(), anyInt())).thenReturn(true);
assertFalse(eco.addMobs(gh));
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#addMobs(Greenhouse)}.
*/
@Test
public void testAddMobsChunkLoadedWithMobsInRecipeMaxMobsZero() {
when(world.isChunkLoaded(anyInt(), anyInt())).thenReturn(true);
when(recipe.noMobs()).thenReturn(false);
assertFalse(eco.addMobs(gh));
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#addMobs(Greenhouse)}.
*/
@Test
public void testAddMobsChunkLoadedWithMobsInRecipeMaxMobsNotZero() {
// Nothing spawned here
when(world.isChunkLoaded(anyInt(), anyInt())).thenReturn(true);
when(recipe.noMobs()).thenReturn(false);
when(recipe.getMaxMob()).thenReturn(10);
assertFalse(eco.addMobs(gh));
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#addMobs(Greenhouse)}.
*/
@Test
public void testAddMobsSpawnMob() {
// Nothing spawned here
when(world.isChunkLoaded(anyInt(), anyInt())).thenReturn(true);
when(recipe.noMobs()).thenReturn(false);
when(recipe.getMaxMob()).thenReturn(10);
when(recipe.spawnMob(any())).thenReturn(true);
assertTrue(eco.addMobs(gh));
}
}

View File

@ -64,20 +64,21 @@ public class GreenhouseFinderTest {
private AsyncWorldCache cache;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
public void setUp() {
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
when(Tag.TRAPDOORS.isTagged(Material.BIRCH_TRAPDOOR)).thenReturn(true);
// Declare mock after mocking Bukkit
roof = mock(Roof.class);
when(roof.roofBlocks(any())).thenCallRealMethod();
// Location
when(location.getBlockX()).thenReturn(5);
when(location.getBlockY()).thenReturn(14);
when(location.getBlockZ()).thenReturn(25);
when(location.getWorld()).thenReturn(world);
// Addon
when(addon.wallBlocks(any())).thenCallRealMethod();
// Block
when(cache.getBlockType(any())).thenReturn(Material.GLASS);
when(cache.getBlockType(anyInt(), anyInt(), anyInt())).thenReturn(Material.GLASS);
@ -95,12 +96,12 @@ public class GreenhouseFinderTest {
when(cache.getMaxHeight()).thenReturn(30);
gf = new GreenhouseFinder();
cc = gf.new CounterCheck();
gf = new GreenhouseFinder(addon);
cc = new CounterCheck();
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkGreenhouse(world.bentobox.greenhouses.data.Greenhouse, world.bentobox.greenhouses.greenhouse.Roof, world.bentobox.greenhouses.greenhouse.Walls)}.
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkGreenhouse(AsyncWorldCache, Roof, Walls)}.
*/
@Test
public void testCheckGreenhouse() {
@ -225,7 +226,7 @@ public class GreenhouseFinderTest {
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkDoorsHoppers(world.bentobox.greenhouses.managers.GreenhouseFinder.CounterCheck, org.bukkit.block.Block)}.
* Test method for {@link world.bentobox.greenhouses.managers.GreenhouseFinder#checkDoorsHoppers(CounterCheck, Material, Vector)}.
*/
@Test
public void testCheckDoorsHoppersHopper() {
@ -233,7 +234,7 @@ public class GreenhouseFinderTest {
// Set the greenhouse so the world is known
gf.setGh(gh);
when(Tag.DOORS.isTagged(any(Material.class))).thenReturn(false);
CounterCheck cc = gf.new CounterCheck();
CounterCheck cc = new CounterCheck();
assertTrue(gf.checkDoorsHoppers(cc, Material.HOPPER, new Vector(5,14,25)));
assertTrue(gf.getRedGlass().isEmpty());
assertEquals(5, gf.getGh().getRoofHopperLocation().getBlockX());