Compare commits

...

92 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
tastybento f345496a6c Version 1.5.2 2021-03-07 13:45:01 -08:00
tastybento 19cd685900 Prevent pistons pulling blocks out.
Allow piston pushing of blocks above or below the greenhouse because
biomes are 3D now.

https://github.com/BentoBoxWorld/Greenhouses/issues/77
2021-02-18 17:09:42 -08:00
tastybento 999ea07ef0 Prevents piston-pushing of any wall or roof block
Fixes https://github.com/BentoBoxWorld/Greenhouses/issues/77
2021-02-17 16:49:42 -08:00
tastybento 29f04ef673 Fix bug with water in offhand and nether greenhouse
Fixes https://github.com/BentoBoxWorld/Greenhouses/issues/76
2021-02-17 12:43:39 -08:00
43 changed files with 1725 additions and 1096 deletions

View File

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

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

42
pom.xml
View File

@ -43,15 +43,15 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version> <java.version>17</java.version>
<powermock.version>2.0.2</powermock.version> <powermock.version>2.0.9</powermock.version>
<!-- More visible way how to change dependency versions --> <!-- More visible way how to change dependency versions -->
<spigot.version>1.16.3-R0.1-SNAPSHOT</spigot.version> <spigot.version>1.20.4-R0.1-SNAPSHOT</spigot.version>
<bentobox.version>1.15.4</bentobox.version> <bentobox.version>2.0.0-SNAPSHOT</bentobox.version>
<!-- Revision variable removes warning about dynamic version --> <!-- Revision variable removes warning about dynamic version -->
<revision>${build.version}-SNAPSHOT</revision> <revision>${build.version}-SNAPSHOT</revision>
<!-- This allows to change between versions and snapshots. --> <!-- This allows to change between versions and snapshots. -->
<build.version>1.5.1</build.version> <build.version>1.8.0</build.version>
<build.number>-LOCAL</build.number> <build.number>-LOCAL</build.number>
<sonar.projectKey>BentoBoxWorld_Greenhouses</sonar.projectKey> <sonar.projectKey>BentoBoxWorld_Greenhouses</sonar.projectKey>
<sonar.organization>bentobox-world</sonar.organization> <sonar.organization>bentobox-world</sonar.organization>
@ -126,7 +126,7 @@
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId> <artifactId>mockito-core</artifactId>
<version>3.0.0</version> <version>3.11.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -185,14 +185,21 @@
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version> <version>3.7.0</version>
<configuration> <configuration>
<source>${java.version}</source> <release>${java.version}</release>
<target>${java.version}</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>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>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@ -207,10 +214,12 @@
<show>public</show> <show>public</show>
<failOnError>false</failOnError> <failOnError>false</failOnError>
<additionalJOption>-Xdoclint:none</additionalJOption> <additionalJOption>-Xdoclint:none</additionalJOption>
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
<id>attach-javadocs</id> <id>attach-javadocs</id>
<phase>install</phase>
<goals> <goals>
<goal>jar</goal> <goal>jar</goal>
</goals> </goals>
@ -243,30 +252,37 @@
<plugin> <plugin>
<groupId>org.jacoco</groupId> <groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId> <artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.3</version> <version>0.8.10</version>
<configuration> <configuration>
<append>true</append> <append>true</append>
<excludes> <excludes>
<!-- This is required to prevent Jacoco from adding <!-- This is required to prevent Jacoco from adding
synthetic fields to a JavaBean class (causes errors in testing) --> synthetic fields to a JavaBean class (causes errors in testing) -->
<exclude>**/*Names*</exclude> <exclude>**/*Names*</exclude>
<!-- Prevents the Material is too large to mock error -->
<exclude>org/bukkit/Material*</exclude>
</excludes> </excludes>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
<id>pre-unit-test</id> <id>prepare-agent</id>
<goals> <goals>
<goal>prepare-agent</goal> <goal>prepare-agent</goal>
</goals> </goals>
</execution> </execution>
<execution> <execution>
<id>post-unit-test</id> <id>report</id>
<goals> <goals>
<goal>report</goal> <goal>report</goal>
</goals> </goals>
<configuration>
<formats>
<format>XML</format>
</formats>
</configuration>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </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;
import world.bentobox.bentobox.api.flags.Flag.Mode; import world.bentobox.bentobox.api.flags.Flag.Mode;
import world.bentobox.bentobox.api.flags.Flag.Type; import world.bentobox.bentobox.api.flags.Flag.Type;
import world.bentobox.greenhouses.greenhouse.Walls;
import world.bentobox.greenhouses.managers.GreenhouseManager; import world.bentobox.greenhouses.managers.GreenhouseManager;
import world.bentobox.greenhouses.managers.RecipeManager; import world.bentobox.greenhouses.managers.RecipeManager;
import world.bentobox.greenhouses.ui.user.UserCommand; import world.bentobox.greenhouses.ui.user.UserCommand;
@ -28,19 +29,13 @@ public class Greenhouses extends Addon {
public static final Flag GREENHOUSES = new Flag.Builder("GREENHOUSE", Material.GREEN_STAINED_GLASS) public static final Flag GREENHOUSES = new Flag.Builder("GREENHOUSE", Material.GREEN_STAINED_GLASS)
.mode(Mode.BASIC) .mode(Mode.BASIC)
.type(Type.PROTECTION).build(); .type(Type.PROTECTION).build();
private static Greenhouses instance;
private final Config<Settings> config; private final Config<Settings> config;
public static Greenhouses getInstance() {
return instance;
}
/** /**
* Constructor * Constructor
*/ */
public Greenhouses() { public Greenhouses() {
super(); super();
instance = this;
config = new Config<>(this, Settings.class); config = new Config<>(this, Settings.class);
} }
@ -92,9 +87,8 @@ public class Greenhouses extends Addon {
*/ */
@Override @Override
public void onDisable() { public void onDisable() {
if (manager != null) { if (manager != null && manager.getEcoMgr() != null) {
manager.saveGreenhouses(); manager.getEcoMgr().cancel();
if (manager.getEcoMgr() != null) manager.getEcoMgr().cancel();
} }
} }
@ -123,4 +117,15 @@ public class Greenhouses extends Addon {
return activeWorlds; return activeWorlds;
} }
/**
* Check if material is a wall material
* @param m - material
* @return true if wall material
*/
public boolean wallBlocks(Material m) {
return Walls.WALL_BLOCKS.contains(m)
|| (m.equals(Material.GLOWSTONE) && getSettings().isAllowGlowstone())
|| (m.name().endsWith("GLASS_PANE") && getSettings().isAllowPanes());
}
} }

View File

@ -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; package world.bentobox.greenhouses.data;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import org.bukkit.Location; import org.bukkit.Location;
@ -157,23 +159,27 @@ public class Greenhouse implements DataObject {
* @param v the roofHopperLocation to set * @param v the roofHopperLocation to set
*/ */
public void setRoofHopperLocation(@Nullable Vector v) { 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 * @return the boundingBox
*/ */
@Nullable @NonNull
public BoundingBox getBoundingBox() { public BoundingBox getBoundingBox() {
return boundingBox; return Objects.requireNonNull(boundingBox);
} }
/** /**
* @return a bounding box of the greenhouse that does not include the walls or roof * @return a bounding box of the greenhouse that does not include the walls or roof
*/ */
@Nullable @NonNull
public BoundingBox getInternalBoundingBox() { 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 @Nullable
public World getWorld() { 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 * @return true if inside the greenhouse
*/ */
public boolean contains(Location location2) { 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 * Get the biome recipe for this greenhouse
* @return biome recipe or null * @return biome recipe or a degenerate recipe
*/ */
@Nullable @NonNull
public BiomeRecipe getBiomeRecipe() { public BiomeRecipe getBiomeRecipe() {
return RecipeManager.getBiomeRecipies(biomeRecipeName).orElse(null); return RecipeManager.getBiomeRecipies(biomeRecipeName).orElse(new BiomeRecipe());
} }
/** /**
@ -245,8 +253,24 @@ public class Greenhouse implements DataObject {
/** /**
* @return the missingBlocks * @return the missingBlocks
*/ */
@Nullable @NonNull
public Map<Material, Integer> getMissingBlocks() { public Map<Material, Integer> getMissingBlocks() {
return missingBlocks; return Objects.requireNonNullElseGet(missingBlocks, HashMap::new);
}
/**
* Check if a location is a wall or roof block
* @param l - location
* @return true if wall or roof block
*/
public boolean isRoofOrWallBlock(Location l) {
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; package world.bentobox.greenhouses.greenhouse;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Random; import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -23,11 +25,13 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Bisected; import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.block.data.type.Cocoa;
import org.bukkit.block.data.type.GlowLichen;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Hoglin; import org.bukkit.entity.Hoglin;
import org.bukkit.entity.Piglin; import org.bukkit.entity.Piglin;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import com.google.common.base.Enums; 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.bentobox.util.Util;
import world.bentobox.greenhouses.Greenhouses; import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.data.Greenhouse; import world.bentobox.greenhouses.data.Greenhouse;
import world.bentobox.greenhouses.managers.EcoSystemManager.GrowthBlock;
import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult; import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult;
import world.bentobox.greenhouses.world.AsyncWorldCache; import world.bentobox.greenhouses.world.AsyncWorldCache;
@ -49,13 +54,37 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
private String name; private String name;
private String friendlyName; 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> 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 // Content requirements
// Material, Type, Qty. There can be more than one type of material required // Material, Type, Qty. There can be more than one type of material required
private final Map<Material, Integer> requiredBlocks = new EnumMap<>(Material.class); private final Map<Material, Integer> requiredBlocks = new EnumMap<>(Material.class);
// Plants /**
* Tree map of plants
*/
private final TreeMap<Double, GreenhousePlant> plantTree = new TreeMap<>(); private final TreeMap<Double, GreenhousePlant> plantTree = new TreeMap<>();
private final TreeMap<Double, GreenhousePlant> underwaterPlants = new TreeMap<>();
// Mobs // Mobs
// Entity Type, Material to Spawn on, Probability // Entity Type, Material to Spawn on, Probability
@ -63,8 +92,7 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
// Conversions // Conversions
// Original Material, Original Type, New Material, New Type, Probability // Original Material, Original Type, New Material, New Type, Probability
//private final Map<Material, GreenhouseBlockConversions> conversionBlocks = new EnumMap<>(Material.class); private final Multimap<Material, GreenhouseBlockConversions> conversionBlocks = ArrayListMultimap.create();
private Multimap<Material, GreenhouseBlockConversions> conversionBlocks = ArrayListMultimap.create();
private int mobLimit; private int mobLimit;
private int waterCoverage; private int waterCoverage;
@ -73,8 +101,12 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
private String permission = ""; private String permission = "";
private final Random random = new Random(); private final Random random = new Random();
private int maxMob;
/**
* Create a degenerate recipe with nothing in it
*/
public BiomeRecipe() {} public BiomeRecipe() {}
/** /**
@ -107,7 +139,7 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
/** /**
* @param mobType - entity type * @param mobType - entity type
* @param mobProbability - reltive probability * @param mobProbability - relative probability
* @param mobSpawnOn - material to spawn on * @param mobSpawnOn - material to spawn on
* @return true if add is successful * @return true if add is successful
*/ */
@ -121,7 +153,7 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
mobTree.put(lastProb + probability, new GreenhouseMob(mobType, mobSpawnOn)); mobTree.put(lastProb + probability, new GreenhouseMob(mobType, mobSpawnOn));
return true; return true;
} else { } 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; return false;
} }
} }
@ -136,11 +168,12 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
*/ */
public boolean addPlants(Material plantMaterial, double plantProbability, Material plantGrowOn) { public boolean addPlants(Material plantMaterial, double plantProbability, Material plantGrowOn) {
double probability = plantProbability/100; double probability = plantProbability/100;
TreeMap<Double, GreenhousePlant> map = UNDERWATER_PLANTS.contains(plantMaterial) ? underwaterPlants : plantTree;
// Add up all the probabilities in the list so far // Add up all the probabilities in the list so far
double lastProb = plantTree.isEmpty() ? 0D : plantTree.lastKey(); double lastProb = map.isEmpty() ? 0D : map.lastKey();
if ((1D - lastProb) >= probability) { if ((1D - lastProb) >= probability) {
// Add to probability tree // Add to probability tree
plantTree.put(lastProb + probability, new GreenhousePlant(plantMaterial, plantGrowOn)); map.put(lastProb + probability, new GreenhousePlant(plantMaterial, plantGrowOn));
} else { } else {
addon.logError("Plant chances add up to > 100% in " + type.toString() + " biome recipe! Skipping " + plantMaterial.toString()); addon.logError("Plant chances add up to > 100% in " + type.toString() + " biome recipe! Skipping " + plantMaterial.toString());
return false; return false;
@ -176,24 +209,30 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
* @return set of results from the check * @return set of results from the check
*/ */
private Set<GreenhouseResult> checkRecipeAsync(CompletableFuture<Set<GreenhouseResult>> r, Greenhouse gh) { private Set<GreenhouseResult> checkRecipeAsync(CompletableFuture<Set<GreenhouseResult>> r, Greenhouse gh) {
AsyncWorldCache cache = new AsyncWorldCache(gh.getWorld()); AsyncWorldCache cache = new AsyncWorldCache(addon, gh.getWorld());
Set<GreenhouseResult> result = new HashSet<>();
long area = gh.getArea(); long area = gh.getArea();
Map<Material, Integer> blockCount = new EnumMap<>(Material.class);
// Look through the greenhouse and count what is in there // Look through the greenhouse and count what is in there
for (int y = gh.getFloorHeight(); y< gh.getCeilingHeight();y++) { Map<Material, Integer> blockCount = countBlocks(gh, cache);
for (int x = (int) (gh.getBoundingBox().getMinX()+1); x < gh.getBoundingBox().getMaxX(); x++) {
for (int z = (int) (gh.getBoundingBox().getMinZ()+1); z < gh.getBoundingBox().getMaxZ(); z++) { // Calculate % water, ice and lava ratios and check them
Material t = cache.getBlockType(x, y, z); Set<GreenhouseResult> result = checkRatios(blockCount, area);
if (!t.equals(Material.AIR)) {
blockCount.putIfAbsent(t, 0); // Compare to the required blocks
blockCount.merge(t, 1, Integer::sum); Map<Material, Integer> missingBlocks = requiredBlocks.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue() - blockCount.getOrDefault(e.getKey(), 0)));
} // Remove any entries that are 0 or less
} missingBlocks.values().removeIf(v -> v <= 0);
} if (!missingBlocks.isEmpty()) {
result.add(GreenhouseResult.FAIL_INSUFFICIENT_BLOCKS);
gh.setMissingBlocks(missingBlocks);
} }
// Calculate % water, ice and lava ratios // Return to main thread to complete
Bukkit.getScheduler().runTask(addon.getPlugin(), () -> r.complete(result));
return result;
}
private Set<GreenhouseResult> checkRatios(Map<Material, Integer> blockCount, long area) {
Set<GreenhouseResult> result = new HashSet<>();
double waterRatio = (double)blockCount.getOrDefault(Material.WATER, 0)/area * 100; double waterRatio = (double)blockCount.getOrDefault(Material.WATER, 0)/area * 100;
double lavaRatio = (double)blockCount.getOrDefault(Material.LAVA, 0)/area * 100; double lavaRatio = (double)blockCount.getOrDefault(Material.LAVA, 0)/area * 100;
int ice = blockCount.entrySet().stream().filter(en -> en.getKey().equals(Material.ICE) int ice = blockCount.entrySet().stream().filter(en -> en.getKey().equals(Material.ICE)
@ -221,37 +260,55 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
if (iceCoverage > 0 && iceRatio < iceCoverage) { if (iceCoverage > 0 && iceRatio < iceCoverage) {
result.add(GreenhouseResult.FAIL_INSUFFICIENT_ICE); result.add(GreenhouseResult.FAIL_INSUFFICIENT_ICE);
} }
// Compare to the required blocks
Map<Material, Integer> missingBlocks = requiredBlocks.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue() - blockCount.getOrDefault(e.getKey(), 0)));
// Remove any entries that are 0 or less
missingBlocks.values().removeIf(v -> v <= 0);
if (!missingBlocks.isEmpty()) {
result.add(GreenhouseResult.FAIL_INSUFFICIENT_BLOCKS);
gh.setMissingBlocks(missingBlocks);
}
// Return to main thread to complete
Bukkit.getScheduler().runTask(addon.getPlugin(), () -> r.complete(result));
return result; return result;
} }
private Map<Material, Integer> countBlocks(Greenhouse gh, AsyncWorldCache cache) {
Map<Material, Integer> blockCount = new EnumMap<>(Material.class);
for (int y = gh.getFloorHeight(); y< gh.getCeilingHeight();y++) {
for (int x = (int) (gh.getBoundingBox().getMinX()+1); x < gh.getBoundingBox().getMaxX(); x++) {
for (int z = (int) (gh.getBoundingBox().getMinZ()+1); z < gh.getBoundingBox().getMaxZ(); z++) {
Material t = cache.getBlockType(x, y, z);
if (!t.equals(Material.AIR)) {
blockCount.putIfAbsent(t, 0);
blockCount.merge(t, 1, Integer::sum);
}
}
}
}
return blockCount;
}
/** /**
* Check if block should be converted * Check if block should be converted
* @param gh - greenhouse
* @param b - block to check * @param b - block to check
*/ */
public void convertBlock(Greenhouse gh, Block b) { public void convertBlock(Block b) {
conversionBlocks.get(b.getType()).stream().filter(Objects::nonNull) Material bType = b.getType();
.filter(bc -> random.nextDouble() < bc.getProbability()) // 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
.forEach(bc -> { if(conversionBlocks.keySet().contains(bType)) {
// Check if the block is in the right area, up, down, n,s,e,w for(GreenhouseBlockConversions conversionOption : conversionBlocks.get(bType)) {
if (ADJ_BLOCKS.stream().map(b::getRelative) rollTheDice(b, conversionOption);
.filter(r -> gh.contains(r.getLocation()))
.map(Block::getType)
.anyMatch(m -> bc.getLocalMaterial() == null || m == bc.getLocalMaterial())) {
// Convert!
b.setType(bc.getNewMaterial());
} }
}); }
}
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)); Location spawnLoc = b.getLocation().clone().add(new Vector(0.5, 0, 0.5));
return getRandomMob() return getRandomMob()
// Check if the spawn on block matches, if it exists // Check if the spawn on block matches, if it exists
.filter(m -> 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 // If spawn occurs, check if it can fit inside greenhouse
.map(m -> { .map(m -> {
Entity entity = b.getWorld().spawnEntity(spawnLoc, m.getMobType()); Entity entity = b.getWorld().spawnEntity(spawnLoc, m.mobType());
if (entity != null) { preventZombie(entity);
preventZombie(entity); return addon
return addon .getManager()
.getManager() .getMap()
.getMap() .getGreenhouse(b.getLocation()).map(gh -> {
.getGreenhouse(b.getLocation()).map(gh -> { if (!gh.getInternalBoundingBox().contains(entity.getBoundingBox())) {
BoundingBox interior = gh.getBoundingBox().clone(); entity.remove();
interior.expand(-1, -1, -1); return false;
if (!interior.contains(entity.getBoundingBox())) { }
entity.remove(); return true;
return false; }).orElse(false);
}
return true;
}).orElse(false);
}
return false;
}).orElse(false); }).orElse(false);
} }
/** /**
@ -375,13 +428,11 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
return; return;
} }
if (entity instanceof Piglin) { if (entity instanceof Piglin p) {
Piglin p = (Piglin)entity;
p.setImmuneToZombification(true); p.setImmuneToZombification(true);
return; return;
} }
if (entity instanceof Hoglin) { if (entity instanceof Hoglin h) {
Hoglin h = (Hoglin)entity;
h.setImmuneToZombification(true); h.setImmuneToZombification(true);
} }
} }
@ -395,18 +446,21 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
return key == null ? Optional.empty() : Optional.ofNullable(mobTree.get(key)); return key == null ? Optional.empty() : Optional.ofNullable(mobTree.get(key));
} }
private Optional<GreenhousePlant> getRandomPlant() { private Optional<GreenhousePlant> getRandomPlant(boolean underwater) {
// Grow a random plant that can grow // Grow a random plant that can grow
double r = random.nextDouble(); double r = random.nextDouble();
Double key = plantTree.ceilingKey(r); Double key = underwater ? underwaterPlants.ceilingKey(r) : plantTree.ceilingKey(r);
return key == null ? Optional.empty() : Optional.ofNullable(plantTree.get(key)); 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 * @return a list of blocks that are required for this recipe
*/ */
public List<String> getRecipeBlocks() { 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. * 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 * @return true if successful
*/ */
public boolean growPlant(Block bl) { public boolean growPlant(GrowthBlock block, boolean underwater) {
if (!bl.isEmpty()) { Block bl = block.block();
return false; return getRandomPlant(underwater).map(p -> {
} if (bl.getY() != 0 && canGrowOn(block, p) && plantIt(bl, p)) {
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);
}
bl.getWorld().spawnParticle(Particle.SNOWBALL, bl.getLocation(), 10, 2, 2, 2); bl.getWorld().spawnParticle(Particle.SNOWBALL, bl.getLocation(), 10, 2, 2, 2);
return true; return true;
} }
@ -448,6 +487,144 @@ public class BiomeRecipe implements Comparable<BiomeRecipe> {
}).orElse(false); }).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 * @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 * @return the mob types that may spawn due to this recipe
*/ */
public Set<EntityType> getMobTypes() { 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; import org.bukkit.Material;
class GreenhouseBlockConversions { record GreenhouseBlockConversions (Material oldMaterial, Material newMaterial, double probability, Material localMaterial) { }
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;
}
}

View File

@ -1,31 +1,6 @@
package world.bentobox.greenhouses.greenhouse; package world.bentobox.greenhouses.greenhouse;
import java.util.Optional;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
class GreenhouseMob { record GreenhouseMob(EntityType mobType, Material mobSpawnOn) { }
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);
}
}

View File

@ -1,32 +1,5 @@
package world.bentobox.greenhouses.greenhouse; package world.bentobox.greenhouses.greenhouse;
import java.util.Optional;
import org.bukkit.Material; import org.bukkit.Material;
class GreenhousePlant { record GreenhousePlant(Material plantMaterial,Material plantGrownOn) { }
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);
}
}

View File

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

View File

@ -1,37 +1,28 @@
package world.bentobox.greenhouses.greenhouse; package world.bentobox.greenhouses.greenhouse;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.BentoBox;
import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.world.AsyncWorldCache; import world.bentobox.greenhouses.world.AsyncWorldCache;
public class Walls extends MinMaxXZ { public class Walls extends MinMaxXZ {
private static final List<Material> WALL_BLOCKS; public static final List<Material> WALL_BLOCKS = Arrays.stream(Material.values())
static { .filter(Material::isBlock) // Blocks only, no items
List<Material> w = Arrays.stream(Material.values()) .filter(m -> !m.name().contains("TRAPDOOR")) // No trap doors
.filter(Material::isBlock) // Blocks only, no items .filter(m -> m.name().contains("DOOR") // All doors
.filter(m -> !m.name().contains("TRAPDOOR")) // No trap doors || (m.name().contains("GLASS") && !m.name().contains("GLASS_PANE")) // All glass blocks
.filter(m -> m.name().contains("DOOR") // All doors || m.equals(Material.HOPPER)).toList();
|| (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);
}
private int floor; private int floor;
private final AsyncWorldCache cache; private final AsyncWorldCache cache;
class WallFinder { static class WallFinder {
int radiusMinX; int radiusMinX;
int radiusMaxX; int radiusMaxX;
int radiusMinZ; int radiusMinZ;
@ -70,7 +61,7 @@ public class Walls extends MinMaxXZ {
// The player is under the roof // The player is under the roof
// Assume the player is inside the greenhouse they are trying to create // Assume the player is inside the greenhouse they are trying to create
final Location loc = roof.getLocation(); final Location loc = roof.getLocation();
floor = getFloorY(roof.getHeight(), roof.getMinX(), roof.getMaxX(), roof.getMinZ(), roof.getMaxZ()); floor = getFloorY(roof.getHeight(), roof.getMinX(), roof.getMaxX(), roof.getMinZ(), roof.getMaxZ(), loc.getWorld().getMinHeight());
// Now start with the player's x and z location // Now start with the player's x and z location
WallFinder wf = new WallFinder(); WallFinder wf = new WallFinder();
minX = loc.getBlockX(); minX = loc.getBlockX();
@ -86,7 +77,7 @@ public class Walls extends MinMaxXZ {
minZ--; minZ--;
maxZ++; maxZ++;
// Find the floor again, only looking within the walls // Find the floor again, only looking within the walls
floor = getFloorY(roof.getHeight(), minX, maxX, minZ,maxZ); floor = getFloorY(roof.getHeight(), minX, maxX, minZ,maxZ,loc.getWorld().getMinHeight());
// Complete on main thread // Complete on main thread
Bukkit.getScheduler().runTask(BentoBox.getInstance(), () -> r.complete(this)); Bukkit.getScheduler().runTask(BentoBox.getInstance(), () -> r.complete(this));
return this; return this;
@ -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 // Find the floor - defined as the last y under the roof where there are no wall blocks
int wallBlockCount; int wallBlockCount;
do { do {
@ -173,22 +164,11 @@ public class Walls extends MinMaxXZ {
} }
} }
} while( y-- > 0 && wallBlockCount > 0); } while( y-- > minY && wallBlockCount > 0);
return y + 1; 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 * @return the floor
*/ */

View File

@ -1,7 +1,5 @@
package world.bentobox.greenhouses.listeners; package world.bentobox.greenhouses.listeners;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@ -17,7 +15,6 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.player.PlayerBucketEmptyEvent; import org.bukkit.event.player.PlayerBucketEmptyEvent;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent;
@ -35,13 +32,8 @@ public class GreenhouseEvents implements Listener {
private static final String BIOME = "[biome]"; private static final String BIOME = "[biome]";
private static final Set<Biome> NETHER_BIOMES; private static final Set<Biome> NETHER_BIOMES;
static { static {
Set<Biome> nb = new HashSet<>(); NETHER_BIOMES = Set.of(Biome.NETHER_WASTES, Biome.WARPED_FOREST, Biome.CRIMSON_FOREST,
nb.add(Biome.NETHER_WASTES); Biome.SOUL_SAND_VALLEY, Biome.BASALT_DELTAS);
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);
} }
private final Greenhouses addon; private final Greenhouses addon;
@ -69,7 +61,12 @@ public class GreenhouseEvents implements Listener {
.map(gh -> gh.getBiomeRecipe().getBiome()).map(NETHER_BIOMES::contains).orElse(false)) { .map(gh -> gh.getBiomeRecipe().getBiome()).map(NETHER_BIOMES::contains).orElse(false)) {
// Not in Nether, in a nether greenhouse // Not in Nether, in a nether greenhouse
e.setCancelled(true); e.setCancelled(true);
e.getPlayer().getInventory().getItemInMainHand().setType(Material.BUCKET); if (e.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.WATER_BUCKET)) {
e.getPlayer().getInventory().getItemInMainHand().setType(Material.BUCKET);
} else if (e.getPlayer().getInventory().getItemInOffHand().getType().equals(Material.WATER_BUCKET)) {
e.getPlayer().getInventory().getItemInOffHand().setType(Material.BUCKET);
}
b.getWorld().spawnParticle(Particle.SMOKE_NORMAL, b.getLocation(), 10); b.getWorld().spawnParticle(Particle.SMOKE_NORMAL, b.getLocation(), 10);
b.getWorld().playSound(b.getLocation(), Sound.ENTITY_GENERIC_EXTINGUISH_FIRE, 1F, 5F); b.getWorld().playSound(b.getLocation(), Sound.ENTITY_GENERIC_EXTINGUISH_FIRE, 1F, 5F);
} }
@ -111,10 +108,18 @@ public class GreenhouseEvents implements Listener {
handleTransition(User.getInstance(e.getPlayer()), e.getTo(), e.getFrom()); 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) { private void handleTransition(User user, Location toLoc, Location fromLoc) {
if (user == null) {
return;
}
Optional<Greenhouse> to = addon.getManager().getMap().getGreenhouse(toLoc); Optional<Greenhouse> to = addon.getManager().getMap().getGreenhouse(toLoc);
Optional<Greenhouse> from = addon.getManager().getMap().getGreenhouse(fromLoc); Optional<Greenhouse> from = addon.getManager().getMap().getGreenhouse(fromLoc);
if (!to.isPresent() && !from.isPresent()) { if (to.isEmpty() && from.isEmpty()) {
return; return;
} }
if (to.isPresent() && from.isPresent()) { if (to.isPresent() && from.isPresent()) {
@ -127,15 +132,13 @@ public class GreenhouseEvents implements Listener {
return; return;
} }
// from is a greenhouse // from is a greenhouse
if (from.isPresent() && !to.isPresent()) { if (from.isPresent()) {
// Exiting // Exiting
user.sendMessage("greenhouses.event.leaving", BIOME, from.get().getBiomeRecipe().getFriendlyName()); user.sendMessage("greenhouses.event.leaving", BIOME, from.get().getBiomeRecipe().getFriendlyName());
return; return;
} }
if (!from.isPresent()) { // Entering
// Entering user.sendMessage("greenhouses.event.entering", BIOME, to.get().getBiomeRecipe().getFriendlyName());
user.sendMessage("greenhouses.event.entering", BIOME, to.get().getBiomeRecipe().getFriendlyName());
}
} }
@ -156,35 +159,15 @@ public class GreenhouseEvents implements Listener {
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled=true) @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled=true)
public void onBlockBreak(final BlockBreakEvent e) { public void onBlockBreak(final BlockBreakEvent e) {
User user = User.getInstance(e.getPlayer()); User user = User.getInstance(e.getPlayer());
addon.getManager().getMap().getGreenhouse(e.getBlock().getLocation()).ifPresent(g -> { addon.getManager().getMap().getGreenhouse(e.getBlock().getLocation())
// Check to see if wall or roof block broken .filter(g -> g.isRoofOrWallBlock(e.getBlock().getLocation()))
if ((e.getBlock().getLocation().getBlockY() == g.getCeilingHeight() - 1) .ifPresent(g -> {
|| e.getBlock().getLocation().getBlockX() == (int)g.getBoundingBox().getMinX() if (g.getOriginalBiome() != null) {
|| e.getBlock().getLocation().getBlockX() == (int)g.getBoundingBox().getMaxX() - 1
|| e.getBlock().getLocation().getBlockZ() == (int)g.getBoundingBox().getMinZ()
|| e.getBlock().getLocation().getBlockZ() == (int)g.getBoundingBox().getMaxZ() - 1
) {
user.sendMessage("greenhouses.event.broke", BIOME, Util.prettifyText(g.getOriginalBiome().name())); user.sendMessage("greenhouses.event.broke", BIOME, Util.prettifyText(g.getOriginalBiome().name()));
addon.getManager().removeGreenhouse(g);
} }
addon.getManager().removeGreenhouse(g);
}); });
} }
private boolean checkBlockHeight(Block block) {
return addon.getManager().getMap().getGreenhouse(block.getLocation())
.filter(g -> g.getCeilingHeight() < block.getY())
.filter(g -> !block.getWorld().getEnvironment().equals(World.Environment.NETHER))
.isPresent();
}
/**
* Check to see if anyone is sneaking a block over a greenhouse by using a piston
* @param e - event
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled=true)
public void onPistonPush(final BlockPistonExtendEvent e) {
e.setCancelled(e.getBlocks().stream().anyMatch(this::checkBlockHeight));
}
} }

View File

@ -2,10 +2,15 @@ package world.bentobox.greenhouses.listeners;
import java.util.Optional; import java.util.Optional;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockFromToEvent; 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.Greenhouses;
import world.bentobox.greenhouses.data.Greenhouse; import world.bentobox.greenhouses.data.Greenhouse;
@ -18,7 +23,7 @@ public class GreenhouseGuard implements Listener {
} }
// Stop lava flow or water into or out of a greenhouse // Stop lava flow or water into or out of a greenhouse
@EventHandler(priority = EventPriority.NORMAL) @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onFlow(final BlockFromToEvent e) { public void onFlow(final BlockFromToEvent e) {
// Flow may be allowed anyway // Flow may be allowed anyway
if (addon.getSettings().isAllowFlowIn() && addon.getSettings().isAllowFlowOut()) { if (addon.getSettings().isAllowFlowIn() && addon.getSettings().isAllowFlowOut()) {
@ -34,7 +39,7 @@ public class GreenhouseGuard implements Listener {
// 1. inside district or outside - always ok // 1. inside district or outside - always ok
// 2. inside to outside - allowFlowOut determines // 2. inside to outside - allowFlowOut determines
// 3. outside to inside - allowFlowIn determines // 3. outside to inside - allowFlowIn determines
if (!to.isPresent() && !from.isPresent()) { if (to.isEmpty() && from.isEmpty()) {
return; return;
} }
if (to.isPresent() && from.isPresent() && to.equals(from)) { if (to.isPresent() && from.isPresent() && to.equals(from)) {
@ -48,10 +53,51 @@ public class GreenhouseGuard implements Listener {
if (from.isPresent() && addon.getSettings().isAllowFlowOut()) { if (from.isPresent() && addon.getSettings().isAllowFlowOut()) {
return; return;
} }
// Otherwise cancel - the flow is not allowed // Otherwise, cancel - the flow is not allowed
e.setCancelled(true); e.setCancelled(true);
} }
/**
* Prevents pistons from pushing greenhouse wall or roof blocks
* @param e - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onPistonPush(BlockPistonExtendEvent e) {
e.setCancelled(e.getBlocks().stream()
.map(Block::getLocation)
.anyMatch(this::inGreenhouse));
}
/**
* Prevents sticky pistons from pulling greenhouse wall or roof blocks
* @param e - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onPistonPull(BlockPistonRetractEvent e) {
e.setCancelled(e.getBlocks().stream()
.map(Block::getLocation)
.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 { public class IslandChangeEvents implements Listener {
private Greenhouses addon; private final Greenhouses addon;
/** /**
* @param addon * @param addon greenhouse addon
*/ */
public IslandChangeEvents(Greenhouses addon) { public IslandChangeEvents(Greenhouses addon) {
this.addon = addon; this.addon = addon;

View File

@ -4,6 +4,8 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
@ -12,12 +14,17 @@ import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.Hopper; 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.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.BlockFormEvent;
import org.bukkit.event.weather.WeatherChangeEvent; import org.bukkit.event.weather.WeatherChangeEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitTask; 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.bentobox.util.Util;
import world.bentobox.greenhouses.Greenhouses; 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) { private boolean getAirBlocks(Greenhouse gh) {
if (gh.getLocation() == null) {
// Greenhouse does not have a location for some reason.
return false;
}
boolean createdSnow = false; boolean createdSnow = false;
List<Block> waterBlocks = new ArrayList<>(); List<Block> waterBlocks = new ArrayList<>();
for (int x = (int)gh.getBoundingBox().getMinX() + 1; x < (int)gh.getBoundingBox().getMaxX() -1; x++) { final BoundingBox bb = gh.getBoundingBox();
for (int z = (int)gh.getBoundingBox().getMinZ() + 1; z < (int)gh.getBoundingBox().getMaxZ() - 1; z++) { for (int x = (int)bb.getMinX() + 1; x < (int)bb.getMaxX() -1; x++) {
for (int y = (int)gh.getBoundingBox().getMaxY() - 2; y >= (int)gh.getBoundingBox().getMinY(); y--) { for (int z = (int)bb.getMinZ() + 1; z < (int)bb.getMaxZ() - 1; z++) {
Block b = gh.getLocation().getWorld().getBlockAt(x, y, 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(); Material type = b.getType();
if (type.equals(Material.AIR) || type.equals(Material.SNOW)) { if (type.equals(Material.AIR) || type.equals(Material.SNOW)) {
b.getWorld().spawnParticle(Particle.SNOWBALL, b.getLocation(), 5); b.getWorld().spawnParticle(Particle.SNOWBALL, b.getLocation(), 5);
@ -59,9 +75,11 @@ public class SnowTracker implements Listener {
// Not water // Not water
if (Math.random() < addon.getSettings().getSnowDensity() if (Math.random() < addon.getSettings().getSnowDensity()
&& !b.isLiquid() && !b.isLiquid()
&& b.getRelative(BlockFace.UP).getType().equals(Material.AIR)) { && (b.getRelative(BlockFace.UP).getType().equals(Material.AIR)
b.getRelative(BlockFace.UP).setType(Material.SNOW); || b.getRelative(BlockFace.UP).getType().equals(Material.SNOW))) {
createdSnow = true;
createdSnow = placeSnow(b);
} }
} }
@ -81,9 +99,49 @@ public class SnowTracker implements Listener {
return createdSnow; 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 * TODO finish
* @param e * @param e block form event
*/ */
@EventHandler @EventHandler
public void onBlockFormEvent(final BlockFormEvent e) { public void onBlockFormEvent(final BlockFormEvent e) {
@ -108,7 +166,7 @@ public class SnowTracker implements Listener {
private void removeWaterBucketAndShake(Greenhouse g) { private void removeWaterBucketAndShake(Greenhouse g) {
// Scatter snow // Scatter snow
if (getAirBlocks(g)) { if (getAirBlocks(g) && g.getRoofHopperLocation() != null) {
Hopper h = ((Hopper)g.getRoofHopperLocation().getBlock().getState()); Hopper h = ((Hopper)g.getRoofHopperLocation().getBlock().getState());
h.getInventory().removeItem(new ItemStack(Material.WATER_BUCKET)); h.getInventory().removeItem(new ItemStack(Material.WATER_BUCKET));
h.getInventory().addItem(new ItemStack(Material.BUCKET)); h.getInventory().addItem(new ItemStack(Material.BUCKET));
@ -117,18 +175,16 @@ public class SnowTracker implements Listener {
private void shakeGlobes(World world) { private void shakeGlobes(World world) {
addon.getManager().getMap().getGreenhouses().stream().filter(g -> g.getBiomeRecipe().getIceCoverage() > 0) 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.getLocation().getWorld().equals(world))
.filter(g -> !g.isBroken()) .filter(g -> !g.isBroken())
.filter(g -> g.getRoofHopperLocation() != null) .filter(g -> g.getRoofHopperLocation() != null)
.forEach(g -> { .forEach(g -> Util.getChunkAtAsync(g.getRoofHopperLocation()).thenRun(() -> {
Util.getChunkAtAsync(g.getRoofHopperLocation()).thenRun(() -> { if (g.getRoofHopperLocation().getBlock().getType().equals(Material.HOPPER)
if (g.getRoofHopperLocation().getBlock().getType().equals(Material.HOPPER) && ((Hopper)g.getRoofHopperLocation().getBlock().getState()).getInventory().contains(Material.WATER_BUCKET)) {
&& ((Hopper)g.getRoofHopperLocation().getBlock().getState()).getInventory().contains(Material.WATER_BUCKET)) { removeWaterBucketAndShake(g);
removeWaterBucketAndShake(g); }
} }));
});
});
} }
private void startSnow(World world) { private void startSnow(World world) {

View File

@ -9,15 +9,19 @@ import java.util.Objects;
import java.util.Random; import java.util.Random;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.Hopper; import org.bukkit.block.Hopper;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitTask; import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.NumberConversions; import org.bukkit.util.NumberConversions;
import world.bentobox.greenhouses.Greenhouses; import world.bentobox.greenhouses.Greenhouses;
import world.bentobox.greenhouses.data.Greenhouse; import world.bentobox.greenhouses.data.Greenhouse;
import world.bentobox.greenhouses.greenhouse.BiomeRecipe;
/** /**
* Runs the ecosystem for a greenhouse * Runs the ecosystem for a greenhouse
@ -54,7 +58,7 @@ public class EcoSystemManager {
} }
// Kick block conversion growing // 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) { if (blockTick > 0) {
addon.log("Kicking off block conversion scheduler every " + addon.getSettings().getBlockTick() + MINUTES); addon.log("Kicking off block conversion scheduler every " + addon.getSettings().getBlockTick() + MINUTES);
@ -83,22 +87,40 @@ public class EcoSystemManager {
} }
private void convertBlocks(Greenhouse gh) { 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; return;
} }
for (double x = gh.getInternalBoundingBox().getMinX(); x < gh.getInternalBoundingBox().getMaxX(); x++) { final BoundingBox ibb = gh.getInternalBoundingBox();
for (double z = gh.getInternalBoundingBox().getMinZ(); z < gh.getInternalBoundingBox().getMaxZ(); z++) { int ghMinX = NumberConversions.floor(ibb.getMinX());
for (double y = gh.getInternalBoundingBox().getMaxY() - 1; y >= gh.getBoundingBox().getMinY() && y > 0; y--) { int ghMaxX = NumberConversions.floor(ibb.getMaxX());
Block b = gh.getWorld().getBlockAt(NumberConversions.floor(x), NumberConversions.floor(y), NumberConversions.floor(z)).getRelative(BlockFace.DOWN); int ghMinY = NumberConversions.floor(gh.getBoundingBox().getMinY()); // Note: this gets the floor
if (!b.isEmpty()) gh.getBiomeRecipe().convertBlock(gh, b); 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) { 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)){ if(gh.getLocation() == null || gh.getLocation().getWorld() == null
//addon.log("Skipping verify for unloaded greenhouse at " + gh.getLocation()); || !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; return;
} }
gh.getBiomeRecipe().checkRecipe(gh).thenAccept(rs -> { 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)){ * Try to spawn mobs in a greenhouse
//addon.log("Skipping addmobs for unloaded greenhouse at " + gh.getLocation()); * @param gh greenhouse
return; * @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()) { if (gh.getBiomeRecipe().noMobs()) {
return; return false;
} }
// Check greenhouse chunks are loaded // Check greenhouse chunks are loaded
for (double blockX = gh.getBoundingBox().getMinX(); blockX < gh.getBoundingBox().getMaxX(); blockX+=16) { for (double blockX = bb.getMinX(); blockX < bb.getMaxX(); blockX+=16) {
for (double blockZ = gh.getBoundingBox().getMinZ(); blockZ < gh.getBoundingBox().getMaxZ(); blockZ+=16) { for (double blockZ = bb.getMinZ(); blockZ < bb.getMaxZ(); blockZ+=16) {
int chunkX = (int)(blockX / 16); int chunkX = (int)(blockX / 16);
int chunkZ = (int)(blockZ / 16); int chunkZ = (int)(blockZ / 16);
if (!gh.getWorld().isChunkLoaded(chunkX, chunkZ)) { 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.getBiomeRecipe().getMobTypes().contains(e.getType()))
.filter(e -> gh.contains(e.getLocation())).count(); .filter(e -> gh.contains(e.getLocation())).count();
// Get the blocks in the greenhouse where spawning could occur // 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())); Collections.shuffle(list, new Random(System.currentTimeMillis()));
Iterator<Block> it = list.iterator(); Iterator<GrowthBlock> it = list.iterator();
// Check if the greenhouse is full // 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())) { while (it.hasNext() && (sum == 0 || gh.getArea() / sum >= gh.getBiomeRecipe().getMobLimit())) {
// Spawn something if chance says so // 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 // Add a mob to the sum in the greenhouse
sum++; sum++;
} }
} }
return sum > 0;
} }
/** /**
@ -151,16 +185,22 @@ public class EcoSystemManager {
* @param gh - greenhouse * @param gh - greenhouse
*/ */
private void growPlants(Greenhouse gh) { 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)){ final BoundingBox bb = gh.getBoundingBox();
//addon.log("Skipping growplants for unloaded greenhouse at " + gh.getLocation()); 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; return;
} }
int bonemeal = getBoneMeal(gh); int bonemeal = getBoneMeal(gh);
if (bonemeal > 0) { if (bonemeal > 0) {
// Get a list of all available blocks // Get a list of all available blocks
List<Block> list = getAvailableBlocks(gh, true); List<GrowthBlock> list = getAvailableBlocks(gh, false);
Collections.shuffle(list); Collections.shuffle(list);
int plantsGrown = list.stream().limit(bonemeal).mapToInt(bl -> gh.getBiomeRecipe().growPlant(bl) ? 1 : 0).sum(); int plantsGrown = list.stream().limit(bonemeal).mapToInt(bl -> gh.getBiomeRecipe().growPlant(bl, false) ? 1 : 0).sum();
// Underwater plants
list = getAvailableBlocks(gh, true);
Collections.shuffle(list);
plantsGrown += list.stream().limit(bonemeal).mapToInt(bl -> gh.getBiomeRecipe().growPlant(bl, true) ? 1 : 0).sum();
if (plantsGrown > 0) { if (plantsGrown > 0) {
setBoneMeal(gh, bonemeal - (int)Math.ceil((double)plantsGrown / PLANTS_PER_BONEMEAL )); setBoneMeal(gh, bonemeal - (int)Math.ceil((double)plantsGrown / PLANTS_PER_BONEMEAL ));
} }
@ -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. * 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 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 * @return List of blocks
*/ */
public List<Block> getAvailableBlocks(Greenhouse gh, boolean ignoreLiquid) { protected List<GrowthBlock> getAvailableBlocks(Greenhouse gh, boolean ignoreLiquid) {
List<Block> result = new ArrayList<>(); final BoundingBox bb = gh.getBoundingBox();
for (double x = gh.getInternalBoundingBox().getMinX(); x < gh.getInternalBoundingBox().getMaxX(); x++) { final BoundingBox ibb = gh.getInternalBoundingBox();
for (double z = gh.getInternalBoundingBox().getMinZ(); z < gh.getInternalBoundingBox().getMaxZ(); z++) { List<GrowthBlock> result = new ArrayList<>();
for (double y = gh.getInternalBoundingBox().getMaxY() - 1; y >= gh.getBoundingBox().getMinY(); y--) { 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)); Block b = gh.getWorld().getBlockAt(NumberConversions.floor(x), NumberConversions.floor(y), NumberConversions.floor(z));
if (!(b.isEmpty() || (ignoreLiquid && b.isLiquid())) if (checkBlock(result, b, ignoreLiquid)) {
&& (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));
break; break;
} }
} }
@ -209,6 +250,31 @@ public class EcoSystemManager {
return result; return result;
} }
private boolean checkBlock(List<GrowthBlock> result, Block b, boolean ignoreLiquid) {
// Check floor blocks
if (!ignoreLiquid) {
// Check ceiling blocks
if (b.isEmpty() && !b.getRelative(BlockFace.UP).isEmpty()) {
result.add(new GrowthBlock(b, false));
}
if (!b.isEmpty() && !Tag.LEAVES.isTagged(b.getType())
&& (b.getRelative(BlockFace.UP).isEmpty()
|| b.getRelative(BlockFace.UP).isPassable()
|| Tag.LEAVES.isTagged(b.getRelative(BlockFace.UP).getType())
)
) {
result.add(new GrowthBlock(b.getRelative(BlockFace.UP), true));
return true;
}
} else {
if (!b.isEmpty() && !b.isLiquid() && b.getRelative(BlockFace.UP).isLiquid()) {
result.add(new GrowthBlock(b.getRelative(BlockFace.UP), true));
return true;
}
}
return false;
}
private int getBoneMeal(Greenhouse gh) { private int getBoneMeal(Greenhouse gh) {
Hopper hopper = getHopper(gh); Hopper hopper = getHopper(gh);
if (hopper == null || !hopper.getInventory().contains(Material.BONE_MEAL)) { if (hopper == null || !hopper.getInventory().contains(Material.BONE_MEAL)) {
@ -219,12 +285,14 @@ public class EcoSystemManager {
.mapToInt(ItemStack::getAmount).sum(); .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) { private Hopper getHopper(Greenhouse gh) {
if (gh.getRoofHopperLocation() == null) {
return null;
}
// Check if the hopper block is still a hopper // 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); gh.setRoofHopperLocation(null);
return null; return null;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -52,7 +52,7 @@ class MakeCommand extends CompositeCommand {
@Override @Override
public boolean execute(User user, String label, List<String> args) { public boolean execute(User user, String label, List<String> args) {
if (args.isEmpty()) { if (args.isEmpty()) {
new Panel((Greenhouses)this.getAddon()).showPanel(user); new Panel(this.getAddon()).showPanel(user);
return true; return true;
} }
// Check recipe given matches // Check recipe given matches
@ -83,7 +83,7 @@ class MakeCommand extends CompositeCommand {
private Map<String, BiomeRecipe> getRecipes(User user) { private Map<String, BiomeRecipe> getRecipes(User user) {
return ((Greenhouses)getAddon()).getRecipes().getBiomeRecipes().stream() return ((Greenhouses)getAddon()).getRecipes().getBiomeRecipes().stream()
.filter(br -> user.hasPermission(br.getPermission())) .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 @Override
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) { 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"); user.sendMessage("greenhouses.errors.no-rank");
return false; return false;
} }
Greenhouses addon = ((Greenhouses)this.getAddon()); Greenhouses addon = this.getAddon();
// Remove greenhouse if it exists // Remove greenhouse if it exists
if (!addon.getManager().getMap().getGreenhouse(user.getLocation()).map(gh -> { if (!addon.getManager().getMap().getGreenhouse(user.getLocation()).map(gh -> {
user.sendMessage("general.success"); user.sendMessage("general.success");

View File

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

View File

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

View File

@ -35,11 +35,17 @@ biomes:
# Entity name: % chance:Block on which the mob will spawn # Entity name: % chance:Block on which the mob will spawn
mobs: mobs:
SQUID: 10:WATER SQUID: 10:WATER
GLOW_SQUID: 5:WATER
TURTLE: 10:SAND
# The minimum number of blocks each mob requires. # The minimum number of blocks each mob requires.
# Mobs will not spawn if there is more than 1 per this number of # Mobs will not spawn if there is more than 1 per this number of
# blocks in the greenhouse. e.g., in this case only 2 mobs will spawn if the # blocks in the greenhouse. e.g., in this case only 2 mobs will spawn if the
# greenhouse area is 18 blocks # greenhouse area is 18 blocks. This enables bigger greenhouses to spawn more.
moblimit: 9 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: Snowy_beach:
friendlyname: "Snowy beach" friendlyname: "Snowy beach"
biome: SNOWY_BEACH biome: SNOWY_BEACH
@ -49,6 +55,9 @@ biomes:
SAND: 1 SAND: 1
watercoverage: 50 watercoverage: 50
icecoverage: 10 icecoverage: 10
mobs:
SQUID: 10:WATER
GLOW_SQUID: 10:WATER
ThreeWolfMoon: ThreeWolfMoon:
friendlyname: "Three Wolf Moon Forest" friendlyname: "Three Wolf Moon Forest"
# Could do with more wolves, but the magic works with 3. # Could do with more wolves, but the magic works with 3.
@ -63,11 +72,17 @@ biomes:
plants: plants:
TALL_GRASS: 10:GRASS_BLOCK TALL_GRASS: 10:GRASS_BLOCK
mobs: mobs:
WOLF: 10:SNOW WOLF: 15:SNOW
FOX: 15:GRASS_BLOCK
RABBIT: 7:GRASS_BLOCK
moblimit: 9 moblimit: 9
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# 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: Cold_Rabbit:
friendlyname: "Cold Taiga Forest" friendlyname: "Cold Taiga Forest"
biome: TAIGA_HILLS biome: OLD_GROWTH_SPRUCE_TAIGA
icon: SPRUCE_SAPLING icon: SPRUCE_SAPLING
priority: 20 priority: 20
contents: contents:
@ -79,7 +94,12 @@ biomes:
TALL_GRASS: 10:GRASS_BLOCK TALL_GRASS: 10:GRASS_BLOCK
mobs: mobs:
RABBIT: 10:SNOW RABBIT: 10:SNOW
FOX: 7:GRASS_BLOCK
moblimit: 9 moblimit: 9
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# 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: DESERT:
friendlyname: "Desert" friendlyname: "Desert"
biome: DESERT biome: DESERT
@ -103,6 +123,14 @@ biomes:
- DIRT:30:SAND:SAND - DIRT:30:SAND:SAND
- GRASS_BLOCK:30:SAND:SAND - GRASS_BLOCK:30:SAND:SAND
- COARSE_DIRT:30:GRAVEL:SAND - COARSE_DIRT:30:GRAVEL:SAND
mobs:
RABBIT: 10:SAND
HUSK: 10:SAND
moblimit: 9
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# the greenhouse at once. Spawning will stop when this limit is reached.
# If this value is not given, there is no maximum.
maxmobs: 20
FOREST: FOREST:
friendlyname: "Flowery forest" friendlyname: "Flowery forest"
biome: FLOWER_FOREST biome: FLOWER_FOREST
@ -117,6 +145,17 @@ biomes:
ORANGE_TULIP: 2:GRASS_BLOCK ORANGE_TULIP: 2:GRASS_BLOCK
SUNFLOWER: 4:GRASS_BLOCK SUNFLOWER: 4:GRASS_BLOCK
TALL_GRASS: 20:GRASS_BLOCK TALL_GRASS: 20:GRASS_BLOCK
mobs:
SHEEP: 10:GRASS_BLOCK
CHICKEN: 7:GRASS_BLOCK
PIG: 10:GRASS_BLOCK
COW: 10:GRASS_BLOCK
WOLF: 5:GRASS_BLOCK
moblimit: 9
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# the greenhouse at once. Spawning will stop when this limit is reached.
# If this value is not given, there is no maximum.
maxmobs: 20
NETHER: NETHER:
friendlyname: "&cNether" friendlyname: "&cNether"
biome: NETHER_WASTES biome: NETHER_WASTES
@ -134,6 +173,10 @@ biomes:
STRIDER: 10:LAVA STRIDER: 10:LAVA
ENDERMAN: 5:NETHERRACK ENDERMAN: 5:NETHERRACK
moblimit: 9 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 permission: greenhouses.biome.nether
SOUL_SAND_VALLEY: SOUL_SAND_VALLEY:
friendlyname: "&cSoul Sand Valley" friendlyname: "&cSoul Sand Valley"
@ -148,7 +191,14 @@ biomes:
watercoverage: 0 watercoverage: 0
mobs: mobs:
SKELETON: 10:SOUL_SAND SKELETON: 10:SOUL_SAND
GHAST: 10:SOUL_SAND
ENDERMAN: 1:SOUL_SAND
STRIDER: 20:LAVA
moblimit: 9 moblimit: 9
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# 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 permission: greenhouses.biome.nether
# Conversion list - in this case, an adjacent block is required to convert # Conversion list - in this case, an adjacent block is required to convert
# Format is: # Format is:
@ -173,6 +223,10 @@ biomes:
PIGLIN: 10:CRIMSON_NYLIUM PIGLIN: 10:CRIMSON_NYLIUM
HOGLIN: 10:CRIMSON_NYLIUM HOGLIN: 10:CRIMSON_NYLIUM
moblimit: 9 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 permission: greenhouses.biome.nether
WARPED_FOREST: WARPED_FOREST:
friendlyname: "&cWarped Forest" friendlyname: "&cWarped Forest"
@ -190,6 +244,10 @@ biomes:
STRIDER: 10:LAVA STRIDER: 10:LAVA
ENDERMAN: 20:WARPED_NYLIUM ENDERMAN: 20:WARPED_NYLIUM
moblimit: 9 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 permission: greenhouses.biome.nether
JUNGLE: JUNGLE:
biome: JUNGLE biome: JUNGLE
@ -205,6 +263,11 @@ biomes:
ROSE_BUSH: 20:GRASS_BLOCK ROSE_BUSH: 20:GRASS_BLOCK
FERN: 20:GRASS_BLOCK FERN: 20:GRASS_BLOCK
TALL_GRASS: 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: MUSHROOM_FIELDS:
friendlyname: "Mushroom Fields" friendlyname: "Mushroom Fields"
biome: MUSHROOM_FIELDS biome: MUSHROOM_FIELDS
@ -220,6 +283,10 @@ biomes:
mobs: mobs:
MUSHROOM_COW: 10:MYCELIUM MUSHROOM_COW: 10:MYCELIUM
moblimit: 9 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: OCEAN:
biome: OCEAN biome: OCEAN
icon: WATER_BUCKET icon: WATER_BUCKET
@ -228,7 +295,13 @@ biomes:
watercoverage: 95 watercoverage: 95
mobs: mobs:
SQUID: 10:WATER SQUID: 10:WATER
DROWNED: 1:WATER
COD: 40:WATER
DOLPHIN: 20:WATER
SQUID: 20:WATER
GLOW_SQUID: 10:WATER
moblimit: 9 moblimit: 9
maxmobs: 20
PLAINS: PLAINS:
friendlyname: "Horse Plains" friendlyname: "Horse Plains"
biome: PLAINS biome: PLAINS
@ -239,8 +312,17 @@ biomes:
plants: plants:
TALL_GRASS: 10:GRASS_BLOCK TALL_GRASS: 10:GRASS_BLOCK
mobs: mobs:
HORSE: 10:GRASS_BLOCK HORSE: 18:GRASS_BLOCK
DONKEY: 2:GRASS_BLOCK
COW: 20:GRASS_BLOCK
CHICKEN: 25:GRASS_BLOCK
PIG: 25:GRASS_BLOCK
SHEEP: 25:GRASS_BLOCK
moblimit: 1 moblimit: 1
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# 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: RIVER:
friendlyname: "Clay river" friendlyname: "Clay river"
biome: 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! # So, for below, dirt has a 50% chance of changing into clay if it is next to water!
conversion-list: conversion-list:
- DIRT:50:CLAY:WATER - DIRT:50:CLAY:WATER
mobs:
SALMON: 10:WATER
SQUID: 10:WATER
GLOW_SQUID: 5:WATER
moblimit: 1
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# the greenhouse at once. Spawning will stop when this limit is reached.
# If this value is not given, there is no maximum.
maxmobs: 10
SAVANNA: SAVANNA:
biome: SAVANNA biome: SAVANNA
icon: ACACIA_LEAVES icon: ACACIA_LEAVES
@ -266,6 +357,18 @@ biomes:
GRASS_BLOCK: 4 GRASS_BLOCK: 4
plants: plants:
TALL_GRASS: 10:GRASS_BLOCK TALL_GRASS: 10:GRASS_BLOCK
mobs:
HORSE: 2:GRASS_BLOCK
DONKEY: 2:GRASS_BLOCK
COW: 20:GRASS_BLOCK
CHICKEN: 25:GRASS_BLOCK
PIG: 25:GRASS_BLOCK
SHEEP: 25:GRASS_BLOCK
moblimit: 1
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# the greenhouse at once. Spawning will stop when this limit is reached.
# If this value is not given, there is no maximum.
maxmobs: 10
SWAMP: SWAMP:
friendlyname: "&2Slimy Swamp" friendlyname: "&2Slimy Swamp"
biome: SWAMP biome: SWAMP
@ -280,7 +383,37 @@ biomes:
plants: plants:
RED_MUSHROOM: 20:GRASS_BLOCK RED_MUSHROOM: 20:GRASS_BLOCK
BROWN_MUSHROOM: 20:GRASS_BLOCK BROWN_MUSHROOM: 20:GRASS_BLOCK
BLUE_ORCHID: 10:GRASS_BLOCK
LILY_PAD: 5:WATER LILY_PAD: 5:WATER
mobs: mobs:
SLIME: 5:WATER SLIME: 5:WATER
FROG: 20:WATER
moblimit: 3 moblimit: 3
# Maxmobs - this is the maximum number of greenhouse-spawed mobs allowed in
# 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]" minimumblockstitle: "[Minimum blocks required]"
nootherblocks: "No other blocks required." nootherblocks: "No other blocks required."
missing: "Greenhouse is missing" missing: "Greenhouse is missing"
commands: commands:
user: user:
description: "Opens the Greenhouse selection GUI"
remove: remove:
description: "Removes a greenhouse that you are standing in if you are the owner" description: "Removes a greenhouse that you are standing in if you are the owner"
make: make:
@ -52,15 +53,18 @@ greenhouses:
FAIL_BAD_WALL_BLOCKS: "&c Wall contains disallowed blocks!" FAIL_BAD_WALL_BLOCKS: "&c Wall contains disallowed blocks!"
FAIL_BELOW: "&c You must be inside the greenhouse to try to make it" FAIL_BELOW: "&c You must be inside the greenhouse to try to make it"
FAIL_BLOCKS_ABOVE: "&c There can be no blocks above the greenhouse! Red glass blocks should show the problem blocks." FAIL_BLOCKS_ABOVE: "&c There can be no blocks above the greenhouse! Red glass blocks should show the problem blocks."
FAIL_HOLE_IN_ROOF: "&c There is a hole in the roof or it is not flat! Red glass blocks should show the problem." FAIL_HOLE_IN_ROOF: |
&c There is a hole in the roof or it is not flat!
&c Red glass blocks should show the problem.
&c Make sure you are inside your greenhouse to make it.
FAIL_HOLE_IN_WALL: "&c There is a hole in the wall!" FAIL_HOLE_IN_WALL: "&c There is a hole in the wall!"
FAIL_NO_ROOF: "&c There seems to be no roof!" FAIL_NO_ROOF: "&c There seems to be no roof! Make sure you are inside the greenhouse to make it."
FAIL_TOO_MANY_DOORS: "&c You cannot have more than 4 doors in the greenhouse!" FAIL_TOO_MANY_DOORS: "&c You cannot have more than 4 doors in the greenhouse!"
FAIL_TOO_MANY_HOPPERS: "&c Only one hopper is allowed in the walls or roof." FAIL_TOO_MANY_HOPPERS: "&c Only one hopper is allowed in the walls or roof."
FAIL_UNEVEN_WALLS: "&c The walls are uneven. Red glass blocks should show the problem blocks." FAIL_UNEVEN_WALLS: "&c The walls are uneven. Red glass blocks should show the problem blocks."
FAIL_INSUFFICIENT_ICE: "&c Insufficent ice to make this recipe" FAIL_INSUFFICIENT_ICE: "&c Insufficient ice to make this recipe"
FAIL_INSUFFICIENT_LAVA: "&c Insufficent lava to make this recipe" FAIL_INSUFFICIENT_LAVA: "&c Insufficient lava to make this recipe"
FAIL_INSUFFICIENT_WATER: "&c Insufficent water to make this recipe" FAIL_INSUFFICIENT_WATER: "&c Insufficient water to make this recipe"
FAIL_NO_ICE: "&c Ice is required to make this recipe" FAIL_NO_ICE: "&c Ice is required to make this recipe"
FAIL_NO_LAVA: "&c Lava is required to make this recipe" FAIL_NO_LAVA: "&c Lava is required to make this recipe"
FAIL_NO_WATER: "&c Water is required to make this recipe" FAIL_NO_WATER: "&c Water is required to make this recipe"

View File

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

View File

@ -1,37 +1,42 @@
--- ---
adminHelp: protection:
info: あなたがいる温室に関する情報を提供します flags:
reload: ファイルから設定をリロードします。 GREENHOUSE:
admininfo: name: 温室
error: ゲーム内でのみ利用可能な温室情報 description: |-
error2: 温室で情報を確認してください。 &b誰が温室を制御できるかを
flags: "[温室旗]" &b設定する
controlpanel:
title: "A温室"
error:
alreadyexists: 温室はすでに存在します!
greenhouseProtected: 温室保護
move: 最初に所有する温室に移動します。
norecipe: 温室を作ることができません!
notinside: あなたは温室の中にいません!
notowner: それを行うには、この温室の所有者でなければなりません。
notyours: これはあなたの温室ではありません!
removing: 温室を撤去!
tooexpensive: あなたは余裕がない[price]
event:
broke: あなたはこの温室を壊しました!バイオームを[biome]に戻しています!
cannotplace: ブロックを温室の上に置くことはできません!
fix: 温室を修理してから、もう一度作ります。
pistonerror: ピストンは温室の上でブロックを押すことができません!
greenhouses: 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: commands:
user: user:
info: remove:
title: "A [温室の作り方]" description: あなたが所有者である場合、あなたが立っている温室を取り除きます
instructions: 4つの壁と平らなガラス屋根でガラスから箱を作り、壁に最大4つのドアを追加します。 1つのホッパーを壁または屋根に置き、水バケツを追加します。
雪や骨粉を作り、植物を自動的に育てます。 バイオームレシピを確認して、温室内で正常にブロックするために必要なブロックを確認してください。
make: make:
description: 温室を作ってみる description: 温室を作ってみる
parameters: "<レシピ>"
error: error:
already: "cここには温室がすでにあります" already: "cここには温室がすでにあります"
FAIL_BAD_ROOF_BLOCKS: "c屋根には許可されていないブロックが含まれています" FAIL_BAD_ROOF_BLOCKS: "c屋根には許可されていないブロックが含まれています"
@ -40,97 +45,99 @@ greenhouses:
FAIL_BLOCKS_ABOVE: "c温室の上にブロックを置くことはできません赤いガラスブロックに問題のあるブロックが表示されます。" FAIL_BLOCKS_ABOVE: "c温室の上にブロックを置くことはできません赤いガラスブロックに問題のあるブロックが表示されます。"
FAIL_HOLE_IN_ROOF: "c屋根に穴があるか、平らではありません赤いガラスブロックが問題を示しているはずです。" FAIL_HOLE_IN_ROOF: "c屋根に穴があるか、平らではありません赤いガラスブロックが問題を示しているはずです。"
FAIL_HOLE_IN_WALL: "c壁に穴が開いています" FAIL_HOLE_IN_WALL: "c壁に穴が開いています"
FAIL_INSUFFICIENT_ICE: "cこのレシピを作成するには氷が足りません"
FAIL_INSUFFICIENT_LAVA: "cこのレシピを作るには溶岩が足りません"
FAIL_INSUFFICIENT_WATER: "cこのレシピを作るのに水が足りません"
FAIL_NO_ROOF: "c屋根がないようです" FAIL_NO_ROOF: "c屋根がないようです"
FAIL_TOO_MANY_DOORS: "c温室には4つ以上のドアを置くことはできません" FAIL_TOO_MANY_DOORS: "c温室には4つ以上のドアを置くことはできません"
FAIL_TOO_MANY_HOPPERS: "c壁または屋根に使用できるホッパーは1つだけです。" FAIL_TOO_MANY_HOPPERS: "c壁または屋根に使用できるホッパーは1つだけです。"
FAIL_UNEVEN_WALLS: "c壁が不均一です。赤いガラスブロックに問題のあるブロックが表示されます。" FAIL_UNEVEN_WALLS: "c壁が不均一です。赤いガラスブロックに問題のあるブロックが表示されます。"
FAIL_INSUFFICIENT_ICE: "cこのレシピを作成するには氷が足りません"
FAIL_INSUFFICIENT_LAVA: "cこのレシピを作るには溶岩が足りません"
FAIL_INSUFFICIENT_WATER: "cこのレシピを作るのに水が足りません"
FAIL_NO_ICE: このレシピを作成するにはc氷が必要です FAIL_NO_ICE: このレシピを作成するにはc氷が必要です
FAIL_NO_LAVA: このレシピを作成するにはc溶岩が必要です FAIL_NO_LAVA: このレシピを作成するにはc溶岩が必要です
FAIL_NO_WATER: このレシピを作成するにはc水が必要です FAIL_NO_WATER: このレシピを作成するにはc水が必要です
parameters: "<レシピ>" FAIL_NO_RECIPE_FOUND: "cこの温室に一致するレシピが見つかりませんでした"
FAIL_INSUFFICIENT_BLOCKS: "&cこのレシピを作成するには、さらに多くのブロックが必要です。"
FAIL_OVERLAPPING: "c温室は壁を共有できません。申し訳ありません。"
success: "2あなたは[biome]バイオーム温室を無事に作成しました!バイオームは次のテレポートまたはログインで同期します。" success: "2あなたは[biome]バイオーム温室を無事に作成しました!バイオームは次のテレポートまたはログインで同期します。"
remove: missing-blocks: "&c欠落[material] x [number]"
description: あなたが所有者である場合、あなたが立っている温室を取り除きます unknown-recipe: "c不明なレシピ"
errors: try-these: "c次のいずれかを試してください。"
alreadyexists: 温室はすでに存在します! recipe-format: "&3[name]"
move: 最初に所有する温室に移動します。 info:
no-rank: "cあなたにはそれをするランクがありません。" title: "A [温室の作り方]"
norecipe: 温室を作ることができません! instructions: 4つの壁と平らなガラス屋根でガラスから箱を作り、壁に最大4つのドアを追加します。 1つのホッパーを壁または屋根に置き、水バケツを追加します。
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]の温室を離れる"
help: help:
help: 手助け help: 手助け
make: 温室を作ろうとする
remove: あなたが所有者である場合、あなたが立っている温室を取り除きます
info: 温室の作り方 info: 温室の作り方
list: 作成可能なすべての温室バイオームをリストします list: 作成可能なすべての温室バイオームをリストします
make: 温室を作ろうとする
recipe: 温室バイオームの作り方を説明します recipe: 温室バイオームの作り方を説明します
remove: あなたが所有者である場合、あなたが立っている温室を取り除きます
opengui: 温室のGUI 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: list:
title: "[温室効果バイオームのレシピ]" title: "[温室効果バイオームのレシピ]"
info: "/greenhouse recipe <番号>を使用する各温室の作り方の詳細を見る" info: "/greenhouse recipe <番号>を使用する各温室の作り方の詳細を見る"
error:
greenhouseProtected: 温室保護
move: 最初に所有する温室に移動します。
notowner: それを行うには、この温室の所有者でなければなりません。
removing: 温室を撤去!
notyours: これはあなたの温室ではありません!
notinside: あなたは温室の中にいません!
tooexpensive: あなたは余裕がない[price]
alreadyexists: 温室はすでに存在します!
norecipe: 温室を作ることができません!
messages: messages:
ecolost: "[location]の温室はエコシステムを失い、撤去されました。"
leave: "[owner]の温室を離れます。"
removed: この温室はもうありません...
enter: "[owner]の[biome]の温室に入る!" enter: "[owner]の[biome]の温室に入る!"
leave: "[owner]の温室を離れます。"
youarein: あなたは今[owner]の[biome]の温室にいます! youarein: あなたは今[owner]の[biome]の温室にいます!
removed: この温室はもうありません...
removedmessage: あなたの[biome]の温室はもうありません! removedmessage: あなたの[biome]の温室はもうありません!
news: ecolost: "[location]の温室はエコシステムを失い、撤去されました。"
headline: "[温室ニュース]" info:
protection: title: "A [温室の作り方]"
flags: instructions: "E 4つの壁と平らなガラスのE屋根でガラスから箱を作り、壁にF 4のドアEを追加します。 E壁と屋根にF 1ホッパーEを配置し、ウォーターバケツEを追加して雪や骨粉を作り、植物を自動的に成長させます。
GREENHOUSE: Eバイオームレシピを確認して、E温室内で正常にブロックを作成するために必要なブロックを確認します。"
name: 温室 info: "[温室情報]"
description: |- none: 無し
b誰が温室を制御できるかを nomore: "4これ以上温室を建設することはできません"
b設定する onemore: "6温室をもう1つ構築できます。"
youcanbuild: "A温室を最大[number]個まで構築できます!"
unlimited: "A温室を無制限に構築できます"
welcome: "B ようこそ!手順についてはここをクリックしてください"
recipe: recipe:
blockscolor: "f" blockscolor: "f"
hint: "/ greenhouse listを使用して、レシピ番号のリストを表示します" hint: "/ greenhouse listを使用して、レシピ番号のリストを表示します"
wrongnumber: レシピ番号は1から[size]の間でなければなりません
title: "[[biome]レシピ]"
nowater: 水は許可されません。
noice: 氷は許可されていません。
nolava: 溶岩は許可されていません。
watermustbe: 水> [coverage]床面積の%。
icemustbe: 氷のブロック&gt;床面積の[coverage]%。 icemustbe: 氷のブロック&gt;床面積の[coverage]%。
lavamustbe: 溶岩> [coverage]床面積の%。 lavamustbe: 溶岩> [coverage]床面積の%。
minimumblockstitle: "[必要な最小ブロック]" minimumblockstitle: "[必要な最小ブロック]"
missing: 温室がありません
noice: 氷は許可されていません。
nolava: 溶岩は許可されていません。
nootherblocks: 他のブロックは必要ありません。 nootherblocks: 他のブロックは必要ありません。
nowater: 水は許可されません。 missing: 温室がありません
title: "[[biome]レシピ]" event:
watermustbe: 水> [coverage]床面積の%。 broke: あなたはこの温室を壊しました!バイオームを[biome]に戻しています!
wrongnumber: レシピ番号は1から[size]の間でなければなりません fix: 温室を修理してから、もう一度作ります。
cannotplace: ブロックを温室の上に置くことはできません!
pistonerror: ピストンは温室の上でブロックを押すことができません!
limits:
noneallowed: 許可により温室が許可されないため、[number]は削除されました。
limitedto: 許可により温室が[limit]に制限されるため、[number]が削除されました。
adminHelp:
reload: ファイルから設定をリロードします。
info: あなたがいる温室に関する情報を提供します
reload: reload:
configReloaded: ファイルから構成が再ロードされました。 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: protection:
flags: flags:
GREENHOUSE: GREENHOUSE:
@ -12,9 +9,9 @@ greenhouses:
greenhouses: 温室 greenhouses: 温室
errors: errors:
move: 移动到你拥有的第一个温室. move: 移动到你拥有的第一个温室.
no-rank: '&c你没有足够的阶级去做这个.' no-rank: "&c你没有足够的阶级去做这个."
notyours: 这不是你的温室! notyours: 这不是你的温室!
not-inside: '&c你并不处于一个温室之中!' not-inside: "&c你并不处于一个温室之中!"
tooexpensive: 你的钱不足以支付 [price] tooexpensive: 你的钱不足以支付 [price]
alreadyexists: 温室已经存在! alreadyexists: 温室已经存在!
norecipe: 无法创建一个温室! norecipe: 无法创建一个温室!
@ -23,12 +20,12 @@ greenhouses:
entering: 你进入一个 [biome] 温室 entering: 你进入一个 [biome] 温室
leaving: 你离开了 [biome] 温室 leaving: 你离开了 [biome] 温室
recipe: recipe:
blockscolor: '&f' blockscolor: "&f"
title: '[[biome] 配方]' title: "[[biome] 配方]"
watermustbe: 水在地面上的占比需要大于[coverage]%. watermustbe: 水在地面上的占比需要大于[coverage]%.
icemustbe: 冰在地面上的占比需要大于[coverage]%. icemustbe: 冰在地面上的占比需要大于[coverage]%.
lavamustbe: 岩浆在地面上的占比需要大于[coverage]%. lavamustbe: 岩浆在地面上的占比需要大于[coverage]%.
minimumblockstitle: '[最少所需的方块数目]' minimumblockstitle: "[最少所需的方块数目]"
nootherblocks: 没有其它需要的方块了. nootherblocks: 没有其它需要的方块了.
missing: 温室缺失了 missing: 温室缺失了
commands: commands:
@ -37,39 +34,37 @@ greenhouses:
description: 如果你是你现在所处的温室的主人则移除这个温室 description: 如果你是你现在所处的温室的主人则移除这个温室
make: make:
description: 尝试建造一个温室 description: 尝试建造一个温室
parameters: <recipe> parameters: "<recipe>"
error: error:
already: '&c这已经有一个温室了!' already: "&c这已经有一个温室了!"
FAIL_BAD_ROOF_BLOCKS: '&c屋顶包含了不被允许的方块!' FAIL_BAD_ROOF_BLOCKS: "&c屋顶包含了不被允许的方块!"
FAIL_BAD_WALL_BLOCKS: '&c墙壁包含了不被允许的方块!' FAIL_BAD_WALL_BLOCKS: "&c墙壁包含了不被允许的方块!"
FAIL_BELOW: '&c你必须处于温室结构内才能尝试建造它' FAIL_BELOW: "&c你必须处于温室结构内才能尝试建造它"
FAIL_BLOCKS_ABOVE: '&c温室的上方不能有方块违规方块已被标红.' FAIL_BLOCKS_ABOVE: "&c温室的上方不能有方块违规方块已被标红."
FAIL_HOLE_IN_ROOF: '&c屋顶上有一个洞或者屋顶并不平整违规方块已被标红.' FAIL_HOLE_IN_ROOF: "&c屋顶上有一个洞或者屋顶并不平整违规方块已被标红."
FAIL_HOLE_IN_WALL: '&c墙上有一个洞!' FAIL_HOLE_IN_WALL: "&c墙上有一个洞!"
FAIL_NO_ROOF: '&c这儿看起来没有屋顶!' FAIL_NO_ROOF: "&c这儿看起来没有屋顶!"
FAIL_TOO_MANY_DOORS: '&c你的温室最多只能有四个门!' FAIL_TOO_MANY_DOORS: "&c你的温室最多只能有四个门!"
FAIL_TOO_MANY_HOPPERS: '&c墙或屋顶上至多有一个漏斗.' FAIL_TOO_MANY_HOPPERS: "&c墙或屋顶上至多有一个漏斗."
FAIL_UNEVEN_WALLS: '&c墙壁不平坦违规方块已被标红.' FAIL_UNEVEN_WALLS: "&c墙壁不平坦违规方块已被标红."
FAIL_INSUFFICIENT_ICE: '&c冰的数目不足以建造这个温室' FAIL_INSUFFICIENT_ICE: "&c冰的数目不足以建造这个温室"
FAIL_INSUFFICIENT_LAVA: '&c岩浆的数目不足以建造这个温室' FAIL_INSUFFICIENT_LAVA: "&c岩浆的数目不足以建造这个温室"
FAIL_INSUFFICIENT_WATER: '&c水的数目不足以建造这个温室' FAIL_INSUFFICIENT_WATER: "&c水的数目不足以建造这个温室"
FAIL_NO_ICE: '&c对于这个温室来说冰是必须的' FAIL_NO_ICE: "&c对于这个温室来说冰是必须的"
FAIL_NO_LAVA: '&c对于这个温室来说岩浆是必须的' FAIL_NO_LAVA: "&c对于这个温室来说岩浆是必须的"
FAIL_NO_WATER: '&c对于这个温室来说水是必须的' FAIL_NO_WATER: "&c对于这个温室来说水是必须的"
FAIL_INSUFFICIENT_BLOCKS: '&c你所用的方块数目不足!' FAIL_NO_RECIPE_FOUND: "&c 找不到与此温室相匹配的配方"
FAIL_OVERLAPPING: '&c温室间不能共享墙壁.' FAIL_INSUFFICIENT_BLOCKS: "&c你所用的方块数目不足!"
success: '&2你成功的建造了一个 [biome] 群系温室! 在你下次登陆时生物群系将会刷新.' FAIL_OVERLAPPING: "&c温室间不能共享墙壁."
missing-blocks: '&c缺少了 [material] x [number]' success: "&2你成功的建造了一个 [biome] 群系温室! 在你下次登陆时生物群系将会刷新."
unknown-recipe: '&c未知的温室配方' missing-blocks: "&c缺少了 [material] x [number]"
try-these: '&c尝试以下操作:' unknown-recipe: "&c未知的温室配方"
recipe-format: '&3[name]' try-these: "&c尝试以下操作:"
recipe-format: "&3[name]"
info: info:
title: '&A[温室建造指南]' title: "&A[温室建造指南]"
instructions: "&E用玻璃建造一个有四面墙和屋顶的平整的立方体\n\ instructions: "&E用玻璃建造一个有四面墙和屋顶的平整的立方体\n&E最多只能有 &F4 扇门. &E\n在墙壁或屋顶内&E放置 &F一个漏斗
&E最多只能有 &F4 扇门. &E\n在墙壁或屋顶内&E放置 &F一个漏斗\ \n&E来放置骨粉或雪 来让作物自动生长.\n&E检查温室配方确保 你的温室包含足够的必要方块\n&E温室就顺利建造了. \n"
\ \n&E来放置骨粉或雪\
\ 来让作物自动生长.\n&E检查温室配方确保\
\ 你的温室包含足够的必要方块\n&E温室就顺利建造了. \n"
help: help:
help: 帮助 help: 帮助
make: 尝试建造一个温室 make: 尝试建造一个温室
@ -79,7 +74,7 @@ help:
recipe: 告知你如何制造一个温室 recipe: 告知你如何制造一个温室
opengui: 打开温室GUI opengui: 打开温室GUI
list: list:
title: '[温室建造指南]' title: "[温室建造指南]"
info: 使用指令 /greenhouse recipe <number> 来查看建造每一个温室的细节 info: 使用指令 /greenhouse recipe <number> 来查看建造每一个温室的细节
error: error:
greenhouseProtected: 温室已被保护 greenhouseProtected: 温室已被保护
@ -99,31 +94,28 @@ messages:
removedmessage: 你的 [biome] 温室已经被移除! removedmessage: 你的 [biome] 温室已经被移除!
ecolost: 你位于 [location] 的温室生态环境遭到破坏,它已经不再是温室了. ecolost: 你位于 [location] 的温室生态环境遭到破坏,它已经不再是温室了.
info: info:
title: '&A[如何建造一个温室]' title: "&A[如何建造一个温室]"
instructions: "&E用玻璃建造一个有四面墙和屋顶的平整的立方体\n\ instructions: "&E用玻璃建造一个有四面墙和屋顶的平整的立方体\n&E最多只能有 &F4 扇门. &E\n在墙壁或屋顶内&E放置 &F一个漏斗 \n&E来放置骨粉或雪
&E最多只能有 &F4 扇门. &E\n在墙壁或屋顶内&E放置 &F一个漏斗\ 来让作物自动生长.\n&E检查温室配方确保 你的温室包含足够的必要方块\n&E温室就顺利建造了. \n"
\ \n&E来放置骨粉或雪\ info: "[温室信息]"
\ 来让作物自动生长.\n&E检查温室配方确保\
\ 你的温室包含足够的必要方块\n&E温室就顺利建造了. \n"
info: '[温室信息]'
none: none:
nomore: '&4你无法建造更多的温室了!' nomore: "&4你无法建造更多的温室了!"
onemore: '&6你可以再建造一个温室.' onemore: "&6你可以再建造一个温室."
youcanbuild: '&A你最多能建造 [number] 个温室!' youcanbuild: "&A你最多能建造 [number] 个温室!"
unlimited: '&A你能建造无限多个温室!' unlimited: "&A你能建造无限多个温室!"
welcome: '&B你好! 点击这里获得更多提示' welcome: "&B你好! 点击这里获得更多提示"
recipe: recipe:
blockscolor: '&f' blockscolor: "&f"
hint: 使用 /greenhouse list 来看见所有温室配方的编号! hint: 使用 /greenhouse list 来看见所有温室配方的编号!
wrongnumber: 温室配方编号必须位于 1 与 [size] 之间 wrongnumber: 温室配方编号必须位于 1 与 [size] 之间
title: '[[biome] 配方]' title: "[[biome] 配方]"
nowater: 不允许有水. nowater: 不允许有水.
noice: 不允许有冰. noice: 不允许有冰.
nolava: 不允许有岩浆. nolava: 不允许有岩浆.
watermustbe: 水在地面上的占比需要大于 [coverage]%. watermustbe: 水在地面上的占比需要大于 [coverage]%.
icemustbe: 冰在地面上的占比需要大于 [coverage]%. icemustbe: 冰在地面上的占比需要大于 [coverage]%.
lavamustbe: 岩浆在地面上的占比需要大于 [coverage]%. lavamustbe: 岩浆在地面上的占比需要大于 [coverage]%.
minimumblockstitle: '[最少所需的方块]' minimumblockstitle: "[最少所需的方块]"
nootherblocks: 没有其它必要的方块了. nootherblocks: 没有其它必要的方块了.
missing: 温室缺失了 missing: 温室缺失了
event: event:
@ -142,8 +134,8 @@ reload:
admininfo: admininfo:
error: 查看温室信息功能仅能在游戏中使用 error: 查看温室信息功能仅能在游戏中使用
error2: 进入一个温室才能查看其信息. error2: 进入一个温室才能查看其信息.
flags: '[Greenhouse Flags]' flags: "[Greenhouse Flags]"
news: news:
headline: '[温室新闻]' headline: "[温室新闻]"
controlpanel: 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; private Settings s;
@Before @Before
public void setUp() throws Exception { public void setUp() {
s = new Settings(); 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.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -55,15 +55,12 @@ public class GreenhouseTest {
@Mock @Mock
private BiomeRecipe br; private BiomeRecipe br;
/**
* @throws java.lang.Exception
*/
@Before @Before
public void setUp() throws Exception { public void setUp() {
// RecipeManager // RecipeManager
PowerMockito.mockStatic(RecipeManager.class); PowerMockito.mockStatic(RecipeManager.class);
when(br.getName()).thenReturn("test"); when(br.getName()).thenReturn("test");
when(RecipeManager.getBiomeRecipies(eq("test"))).thenReturn(Optional.of(br)); when(RecipeManager.getBiomeRecipies("test")).thenReturn(Optional.of(br));
// Walls // Walls
when(walls.getMinX()).thenReturn(MINX); when(walls.getMinX()).thenReturn(MINX);
when(walls.getMinZ()).thenReturn(MINZ); when(walls.getMinZ()).thenReturn(MINZ);
@ -74,10 +71,9 @@ public class GreenhouseTest {
} }
/** /**
* @throws java.lang.Exception
*/ */
@After @After
public void tearDown() throws Exception { public void tearDown() {
Mockito.framework().clearInlineMocks(); 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 @Test
public void testSetRoofHopperLocation() { public void testSetRoofHopperLocation() {
@ -279,7 +275,7 @@ public class GreenhouseTest {
*/ */
@Test @Test
public void testGetBiomeRecipe() { public void testGetBiomeRecipe() {
assertNull(gh.getBiomeRecipe()); assertNotNull(gh.getBiomeRecipe());
} }
/** /**
@ -288,7 +284,7 @@ public class GreenhouseTest {
@Test @Test
public void testSetMissingBlocks() { public void testSetMissingBlocks() {
gh.setMissingBlocks(Collections.singletonMap(Material.ACACIA_BOAT, 20)); 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 @Test
public void testGetMissingBlocks() { 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.Greenhouses;
import world.bentobox.greenhouses.Settings; import world.bentobox.greenhouses.Settings;
import world.bentobox.greenhouses.data.Greenhouse; import world.bentobox.greenhouses.data.Greenhouse;
import world.bentobox.greenhouses.managers.EcoSystemManager.GrowthBlock;
import world.bentobox.greenhouses.managers.GreenhouseManager; import world.bentobox.greenhouses.managers.GreenhouseManager;
import world.bentobox.greenhouses.managers.GreenhouseMap; import world.bentobox.greenhouses.managers.GreenhouseMap;
@ -61,7 +62,6 @@ public class BiomeRecipeTest {
@Mock @Mock
private Greenhouses addon; private Greenhouses addon;
private Biome type;
@Mock @Mock
private Greenhouse gh; private Greenhouse gh;
@ -85,20 +85,19 @@ public class BiomeRecipeTest {
@Mock @Mock
private Settings settings; private Settings settings;
/**
* @throws java.lang.Exception
*/
@Before @Before
public void setUp() throws Exception { public void setUp() {
PowerMockito.mockStatic(Bukkit.class); PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.createBlockData(any(Material.class))).thenReturn(bd); when(Bukkit.createBlockData(any(Material.class))).thenReturn(bd);
type = Biome.BADLANDS; Biome type = Biome.BADLANDS;
// Greenhouse // Greenhouse
when(gh.getArea()).thenReturn(100); when(gh.getArea()).thenReturn(100);
when(gh.getFloorHeight()).thenReturn(100); when(gh.getFloorHeight()).thenReturn(100);
when(gh.getCeilingHeight()).thenReturn(120); when(gh.getCeilingHeight()).thenReturn(120);
bb = new BoundingBox(10, 100, 10, 20, 120, 20); bb = new BoundingBox(10, 100, 10, 20, 120, 20);
when(gh.getBoundingBox()).thenReturn(bb); when(gh.getBoundingBox()).thenReturn(bb);
BoundingBox ibb = bb.clone().expand(-1);
when(gh.getInternalBoundingBox()).thenReturn(ibb);
when(gh.getWorld()).thenReturn(world); when(gh.getWorld()).thenReturn(world);
when(gh.contains(any())).thenReturn(true); when(gh.contains(any())).thenReturn(true);
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(block); when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(block);
@ -152,50 +151,50 @@ public class BiomeRecipeTest {
double convChance = 100D; double convChance = 100D;
Material localMaterial = Material.WATER; Material localMaterial = Material.WATER;
br.addConvBlocks(oldMaterial, newMaterial, convChance, localMaterial); br.addConvBlocks(oldMaterial, newMaterial, convChance, localMaterial);
verify(addon).log(eq(" 100.0% chance for Sand to convert to Clay")); verify(addon).log(" 100.0% chance for Sand to convert to Clay");
} }
/** /**
* 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 @Test
public void testAddMobs() { public void testAddMobs() {
EntityType mobType = EntityType.CAT; EntityType mobType = EntityType.CAT;
int mobProbability = 50; int mobProbability = 50;
Material mobSpawnOn = Material.GRASS_PATH; Material mobSpawnOn = Material.GRASS_BLOCK;
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
verify(addon).log(eq(" 50.0% chance for Cat to spawn on Grass 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 @Test
public void testAddMobsOver100Percent() { public void testAddMobsOver100Percent() {
EntityType mobType = EntityType.CAT; EntityType mobType = EntityType.CAT;
int mobProbability = 50; 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); 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 @Test
public void testAddMobsOver100PercentDouble() { public void testAddMobsOver100PercentDouble() {
EntityType mobType = EntityType.CAT; EntityType mobType = EntityType.CAT;
double mobProbability = 50.5; double mobProbability = 50.5;
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); 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 @Test
public void testAddPlants() { public void testAddPlants() {
@ -203,11 +202,11 @@ public class BiomeRecipeTest {
int plantProbability = 20; int plantProbability = 20;
Material plantGrowOn = Material.DIRT; Material plantGrowOn = Material.DIRT;
br.addPlants(plantMaterial, plantProbability, plantGrowOn); br.addPlants(plantMaterial, plantProbability, plantGrowOn);
verify(addon).log(eq(" 20.0% chance for Jungle Sapling to grow on Dirt")); verify(addon).log(" 20.0% chance for Jungle Sapling to grow on Dirt");
} }
/** /**
* 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 @Test
public void testAddPlantsOver100Percent() { public void testAddPlantsOver100Percent() {
@ -216,7 +215,7 @@ public class BiomeRecipeTest {
Material plantGrowOn = Material.DIRT; Material plantGrowOn = Material.DIRT;
br.addPlants(plantMaterial, plantProbability, plantGrowOn); br.addPlants(plantMaterial, plantProbability, plantGrowOn);
br.addPlants(plantMaterial, plantProbability, plantGrowOn); br.addPlants(plantMaterial, plantProbability, plantGrowOn);
verify(addon).logError(eq("Plant chances add up to > 100% in BADLANDS biome recipe! Skipping JUNGLE_SAPLING")); verify(addon).logError("Plant chances add up to > 100% in BADLANDS biome recipe! Skipping JUNGLE_SAPLING");
} }
/** /**
@ -227,7 +226,7 @@ public class BiomeRecipeTest {
Material blockMaterial = Material.BLACK_CONCRETE; Material blockMaterial = Material.BLACK_CONCRETE;
int blockQty = 30; int blockQty = 30;
br.addReqBlocks(blockMaterial, blockQty); br.addReqBlocks(blockMaterial, blockQty);
verify(addon).log(eq(" BLACK_CONCRETE x 30")); verify(addon).log(" BLACK_CONCRETE x 30");
} }
/** /**
@ -263,29 +262,10 @@ public class BiomeRecipeTest {
Block ab = mock(Block.class); Block ab = mock(Block.class);
when(ab.getType()).thenReturn(Material.WATER); when(ab.getType()).thenReturn(Material.WATER);
when(b.getRelative(any())).thenReturn(ab); when(b.getRelative(any())).thenReturn(ab);
br.convertBlock(gh, b); br.convertBlock(b);
verify(b).setType(Material.CLAY); 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)}. * 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); Block ab = mock(Block.class);
when(ab.getType()).thenReturn(Material.SAND); when(ab.getType()).thenReturn(Material.SAND);
when(b.getRelative(any())).thenReturn(ab); when(b.getRelative(any())).thenReturn(ab);
br.convertBlock(gh, b); br.convertBlock(b);
verify(b, never()).setType(Material.CLAY); verify(b, never()).setType(Material.CLAY);
} }
@ -311,10 +291,30 @@ public class BiomeRecipeTest {
// Mock // Mock
Block b = mock(Block.class); Block b = mock(Block.class);
when(b.getType()).thenReturn(Material.SAND); when(b.getType()).thenReturn(Material.SAND);
br.convertBlock(gh, b); br.convertBlock(b);
verify(b, never()).setType(Material.CLAY); 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)}. * 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); Block ab = mock(Block.class);
when(ab.getType()).thenReturn(Material.WATER); when(ab.getType()).thenReturn(Material.WATER);
when(b.getRelative(any())).thenReturn(ab); when(b.getRelative(any())).thenReturn(ab);
br.convertBlock(gh, b); br.convertBlock(b);
verify(b, never()).setType(Material.CLAY); verify(b, never()).setType(Material.CLAY);
} }
@ -435,12 +435,12 @@ public class BiomeRecipeTest {
@Test @Test
public void testSpawnMobOutsideWall() { public void testSpawnMobOutsideWall() {
when(block.getY()).thenReturn(10); 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); when(block.getRelative(any())).thenReturn(block);
EntityType mobType = EntityType.CAT; EntityType mobType = EntityType.CAT;
int mobProbability = 100; int mobProbability = 100;
Material mobSpawnOn = Material.GRASS_PATH; Material mobSpawnOn = Material.GRASS_BLOCK;
Entity cat = mock(Cat.class); Entity cat = mock(Cat.class);
// Same box as greenhouse // Same box as greenhouse
@ -451,7 +451,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
assertFalse(br.spawnMob(block)); assertFalse(br.spawnMob(block));
verify(world).spawnEntity(eq(location), eq(EntityType.CAT)); verify(world).spawnEntity(location, EntityType.CAT);
verify(location).add(any(Vector.class)); verify(location).add(any(Vector.class));
} }
@ -461,12 +461,12 @@ public class BiomeRecipeTest {
@Test @Test
public void testSpawnMob() { public void testSpawnMob() {
when(block.getY()).thenReturn(10); 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); when(block.getRelative(any())).thenReturn(block);
EntityType mobType = EntityType.CAT; EntityType mobType = EntityType.CAT;
int mobProbability = 100; int mobProbability = 100;
Material mobSpawnOn = Material.GRASS_PATH; Material mobSpawnOn = Material.GRASS_BLOCK;
Entity cat = mock(Cat.class); Entity cat = mock(Cat.class);
// Exactly 1 block smaller than the greenhouse blocks // Exactly 1 block smaller than the greenhouse blocks
@ -477,7 +477,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
assertTrue(br.spawnMob(block)); assertTrue(br.spawnMob(block));
verify(world).spawnEntity(eq(location), eq(EntityType.CAT)); verify(world).spawnEntity(location, EntityType.CAT);
verify(location).add(any(Vector.class)); verify(location).add(any(Vector.class));
} }
@ -487,12 +487,12 @@ public class BiomeRecipeTest {
@Test @Test
public void testSpawnMobHoglin() { public void testSpawnMobHoglin() {
when(block.getY()).thenReturn(10); 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); when(block.getRelative(any())).thenReturn(block);
EntityType mobType = EntityType.HOGLIN; EntityType mobType = EntityType.HOGLIN;
int mobProbability = 100; int mobProbability = 100;
Material mobSpawnOn = Material.GRASS_PATH; Material mobSpawnOn = Material.GRASS_BLOCK;
Hoglin hoglin = mock(Hoglin.class); Hoglin hoglin = mock(Hoglin.class);
// Exactly 1 block smaller than the greenhouse blocks // Exactly 1 block smaller than the greenhouse blocks
@ -504,7 +504,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
assertTrue(br.spawnMob(block)); assertTrue(br.spawnMob(block));
verify(world).spawnEntity(eq(location), eq(EntityType.HOGLIN)); verify(world).spawnEntity(location, EntityType.HOGLIN);
verify(location).add(any(Vector.class)); verify(location).add(any(Vector.class));
verify(hoglin).setImmuneToZombification(true); verify(hoglin).setImmuneToZombification(true);
} }
@ -515,12 +515,12 @@ public class BiomeRecipeTest {
@Test @Test
public void testSpawnMobPiglin() { public void testSpawnMobPiglin() {
when(block.getY()).thenReturn(10); 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); when(block.getRelative(any())).thenReturn(block);
EntityType mobType = EntityType.PIGLIN; EntityType mobType = EntityType.PIGLIN;
int mobProbability = 100; int mobProbability = 100;
Material mobSpawnOn = Material.GRASS_PATH; Material mobSpawnOn = Material.GRASS_BLOCK;
Piglin piglin = mock(Piglin.class); Piglin piglin = mock(Piglin.class);
// Exactly 1 block smaller than the greenhouse blocks // Exactly 1 block smaller than the greenhouse blocks
@ -532,7 +532,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
assertTrue(br.spawnMob(block)); assertTrue(br.spawnMob(block));
verify(world).spawnEntity(eq(location), eq(EntityType.PIGLIN)); verify(world).spawnEntity(location, EntityType.PIGLIN);
verify(location).add(any(Vector.class)); verify(location).add(any(Vector.class));
verify(piglin).setImmuneToZombification(true); verify(piglin).setImmuneToZombification(true);
} }
@ -545,12 +545,12 @@ public class BiomeRecipeTest {
when(world.getEnvironment()).thenReturn(Environment.NETHER); when(world.getEnvironment()).thenReturn(Environment.NETHER);
when(block.getY()).thenReturn(10); 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); when(block.getRelative(any())).thenReturn(block);
EntityType mobType = EntityType.PIGLIN; EntityType mobType = EntityType.PIGLIN;
int mobProbability = 100; int mobProbability = 100;
Material mobSpawnOn = Material.GRASS_PATH; Material mobSpawnOn = Material.GRASS_BLOCK;
Piglin piglin = mock(Piglin.class); Piglin piglin = mock(Piglin.class);
// Exactly 1 block smaller than the greenhouse blocks // Exactly 1 block smaller than the greenhouse blocks
@ -562,7 +562,7 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
assertTrue(br.spawnMob(block)); assertTrue(br.spawnMob(block));
verify(world).spawnEntity(eq(location), eq(EntityType.PIGLIN)); verify(world).spawnEntity(location, EntityType.PIGLIN);
verify(location).add(any(Vector.class)); verify(location).add(any(Vector.class));
verify(piglin, never()).setImmuneToZombification(true); verify(piglin, never()).setImmuneToZombification(true);
} }
@ -573,12 +573,12 @@ public class BiomeRecipeTest {
@Test @Test
public void testSpawnMobWrongSurface() { public void testSpawnMobWrongSurface() {
when(block.getY()).thenReturn(10); when(block.getY()).thenReturn(10);
when(block.getType()).thenReturn(Material.GRASS_BLOCK); when(block.getType()).thenReturn(Material.STONE);
when(block.getRelative(any())).thenReturn(block); when(block.getRelative(any())).thenReturn(block);
EntityType mobType = EntityType.CAT; EntityType mobType = EntityType.CAT;
int mobProbability = 100; int mobProbability = 100;
Material mobSpawnOn = Material.GRASS_PATH; Material mobSpawnOn = Material.GRASS_BLOCK;
Entity cat = mock(Cat.class); Entity cat = mock(Cat.class);
when(world.spawnEntity(any(), any())).thenReturn(cat); when(world.spawnEntity(any(), any())).thenReturn(cat);
@ -586,28 +586,9 @@ public class BiomeRecipeTest {
br.addMobs(mobType, mobProbability, mobSpawnOn); br.addMobs(mobType, mobProbability, mobSpawnOn);
assertFalse(br.spawnMob(block)); assertFalse(br.spawnMob(block));
verify(world, never()).spawnEntity(eq(location), eq(EntityType.CAT)); verify(world, never()).spawnEntity(location, EntityType.CAT);
} }
/**
* 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()}. * Test method for {@link world.bentobox.greenhouses.greenhouse.BiomeRecipe#getRecipeBlocks()}.
*/ */
@ -630,7 +611,7 @@ public class BiomeRecipeTest {
@Test @Test
public void testGrowPlantNotAir() { public void testGrowPlantNotAir() {
when(block.getType()).thenReturn(Material.SOUL_SAND); when(block.getType()).thenReturn(Material.SOUL_SAND);
assertFalse(br.growPlant(block)); assertFalse(br.growPlant(new GrowthBlock(block, true), false));
} }
/** /**
@ -640,7 +621,7 @@ public class BiomeRecipeTest {
public void testGrowPlantNoPlants() { public void testGrowPlantNoPlants() {
when(block.getType()).thenReturn(Material.AIR); when(block.getType()).thenReturn(Material.AIR);
when(block.isEmpty()).thenReturn(true); when(block.isEmpty()).thenReturn(true);
assertFalse(br.growPlant(block)); assertFalse(br.growPlant(new GrowthBlock(block, true), false));
} }
/** /**
@ -652,7 +633,7 @@ public class BiomeRecipeTest {
when(block.getType()).thenReturn(Material.AIR); when(block.getType()).thenReturn(Material.AIR);
when(block.isEmpty()).thenReturn(true); when(block.isEmpty()).thenReturn(true);
assertTrue(br.addPlants(Material.BAMBOO_SAPLING, 100, Material.GRASS_BLOCK)); assertTrue(br.addPlants(Material.BAMBOO_SAPLING, 100, Material.GRASS_BLOCK));
assertFalse(br.growPlant(block)); assertFalse(br.growPlant(new GrowthBlock(block, true), false));
} }
/** /**
@ -668,11 +649,46 @@ public class BiomeRecipeTest {
when(block.getRelative(any())).thenReturn(ob); when(block.getRelative(any())).thenReturn(ob);
assertTrue(br.addPlants(Material.BAMBOO_SAPLING, 100, Material.GRASS_BLOCK)); assertTrue(br.addPlants(Material.BAMBOO_SAPLING, 100, Material.GRASS_BLOCK));
assertTrue(br.growPlant(block)); assertTrue(br.growPlant(new GrowthBlock(block, true), false));
verify(world).spawnParticle(eq(Particle.SNOWBALL), any(Location.class), anyInt(), anyDouble(), anyDouble(), anyDouble()); verify(world).spawnParticle(eq(Particle.SNOWBALL), any(Location.class), anyInt(), anyDouble(), anyDouble(), anyDouble());
verify(block).setBlockData(eq(bd), eq(false)); verify(block).setBlockData(eq(bd), eq(false));
} }
/**
* 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)}. * 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); when(block.isEmpty()).thenReturn(true);
Block ob = mock(Block.class); Block ob = mock(Block.class);
when(ob.getType()).thenReturn(Material.GRASS_BLOCK); when(ob.getType()).thenReturn(Material.GRASS_BLOCK);
when(block.getRelative(eq(BlockFace.DOWN))).thenReturn(ob); when(block.getRelative(BlockFace.DOWN)).thenReturn(ob);
when(block.getRelative(eq(BlockFace.UP))).thenReturn(block); when(block.getRelative(BlockFace.UP)).thenReturn(block);
assertTrue(br.addPlants(Material.SUNFLOWER, 100, Material.GRASS_BLOCK)); assertTrue(br.addPlants(Material.SUNFLOWER, 100, Material.GRASS_BLOCK));
assertTrue(br.growPlant(block)); assertTrue(br.growPlant(new GrowthBlock(block, true), false));
verify(world).spawnParticle(eq(Particle.SNOWBALL), any(Location.class), anyInt(), anyDouble(), anyDouble(), anyDouble()); verify(world).spawnParticle(eq(Particle.SNOWBALL), any(Location.class), anyInt(), anyDouble(), anyDouble(), anyDouble());
verify(bisected).setHalf(eq(Half.BOTTOM)); verify(bisected).setHalf(Half.BOTTOM);
verify(bisected).setHalf(eq(Half.TOP)); verify(bisected).setHalf(Half.TOP);
} }
/** /**
@ -706,10 +722,10 @@ public class BiomeRecipeTest {
when(block.isEmpty()).thenReturn(true); when(block.isEmpty()).thenReturn(true);
Block ob = mock(Block.class); Block ob = mock(Block.class);
when(ob.getType()).thenReturn(Material.GRASS_BLOCK); when(ob.getType()).thenReturn(Material.GRASS_BLOCK);
when(block.getRelative(eq(BlockFace.DOWN))).thenReturn(ob); when(block.getRelative(BlockFace.DOWN)).thenReturn(ob);
when(block.getRelative(eq(BlockFace.UP))).thenReturn(ob); when(block.getRelative(BlockFace.UP)).thenReturn(ob);
assertTrue(br.addPlants(Material.SUNFLOWER, 100, Material.GRASS_BLOCK)); assertTrue(br.addPlants(Material.SUNFLOWER, 100, Material.GRASS_BLOCK));
assertFalse(br.growPlant(block)); assertFalse(br.growPlant(new GrowthBlock(block, true), false));
} }
/** /**
@ -751,8 +767,8 @@ public class BiomeRecipeTest {
*/ */
@Test @Test
public void testSetType() { public void testSetType() {
br.setType(Biome.BADLANDS_PLATEAU); br.setType(Biome.BADLANDS);
assertEquals(Biome.BADLANDS_PLATEAU, br.getBiome()); assertEquals(Biome.BADLANDS, br.getBiome());
} }
/** /**

View File

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

View File

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

View File

@ -9,7 +9,6 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.Optional; import java.util.Optional;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -24,15 +23,13 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.player.PlayerBucketEmptyEvent; import org.bukkit.event.player.PlayerBucketEmptyEvent;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.PlayerInventory;
import org.bukkit.util.BoundingBox;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -84,11 +81,8 @@ public class GreenhouseEventsTest {
@Mock @Mock
private ItemStack waterBucket; private ItemStack waterBucket;
/**
* @throws java.lang.Exception
*/
@Before @Before
public void setUp() throws Exception { public void setUp() {
PowerMockito.mockStatic(User.class); PowerMockito.mockStatic(User.class);
when(User.getInstance(any(Player.class))).thenReturn(user); when(User.getInstance(any(Player.class))).thenReturn(user);
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS); PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
@ -133,14 +127,7 @@ public class GreenhouseEventsTest {
} }
/** /**
* @throws java.lang.Exception * Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPlayerInteractInNether(PlayerBucketEmptyEvent)}.
*/
@After
public void tearDown() throws Exception {
}
/**
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPlayerInteractInNether(org.bukkit.event.player.PlayerInteractEvent)}.
*/ */
@Test @Test
public void testOnPlayerInteractInNetherInGreenhouse() { public void testOnPlayerInteractInNetherInGreenhouse() {
@ -151,13 +138,13 @@ public class GreenhouseEventsTest {
when(nextBlock.getLocation()).thenReturn(location); when(nextBlock.getLocation()).thenReturn(location);
ItemStack item = mock(ItemStack.class); ItemStack item = mock(ItemStack.class);
when(item.getType()).thenReturn(Material.WATER_BUCKET); 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); ghe.onPlayerInteractInNether(e);
verify(nextBlock).setType(Material.WATER); 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 @Test
public void testOnPlayerInteractInNetherOutsideOfGreenhouse() { public void testOnPlayerInteractInNetherOutsideOfGreenhouse() {
@ -168,13 +155,13 @@ public class GreenhouseEventsTest {
when(nextBlock.getLocation()).thenReturn(mock(Location.class)); when(nextBlock.getLocation()).thenReturn(mock(Location.class));
ItemStack item = mock(ItemStack.class); ItemStack item = mock(ItemStack.class);
when(item.getType()).thenReturn(Material.WATER_BUCKET); 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); ghe.onPlayerInteractInNether(e);
verify(nextBlock, never()).setType(Material.WATER); 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 @Test
public void testOnPlayerInteractInNetherGreenhouse() { public void testOnPlayerInteractInNetherGreenhouse() {
@ -184,13 +171,13 @@ public class GreenhouseEventsTest {
when(clickedBlock.getRelative(any())).thenReturn(nextBlock); when(clickedBlock.getRelative(any())).thenReturn(nextBlock);
ItemStack item = mock(ItemStack.class); ItemStack item = mock(ItemStack.class);
when(item.getType()).thenReturn(Material.WATER_BUCKET); 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); ghe.onPlayerInteractInNether(e);
verify(nextBlock, never()).setType(Material.WATER); 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 @Test
public void testOnPlayerInteractInNetherNotInNether() { public void testOnPlayerInteractInNetherNotInNether() {
@ -203,13 +190,13 @@ public class GreenhouseEventsTest {
when(nextBlock.getWorld()).thenReturn(world); when(nextBlock.getWorld()).thenReturn(world);
ItemStack item = mock(ItemStack.class); ItemStack item = mock(ItemStack.class);
when(item.getType()).thenReturn(Material.WATER_BUCKET); 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); ghe.onPlayerInteractInNether(e);
verify(nextBlock, never()).setType(Material.WATER); 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 @Test
public void testOnPlayerInteractInNetherNotWaterBucket() { public void testOnPlayerInteractInNetherNotWaterBucket() {
@ -219,13 +206,13 @@ public class GreenhouseEventsTest {
when(clickedBlock.getRelative(any())).thenReturn(nextBlock); when(clickedBlock.getRelative(any())).thenReturn(nextBlock);
ItemStack item = mock(ItemStack.class); ItemStack item = mock(ItemStack.class);
when(item.getType()).thenReturn(Material.ACACIA_BOAT); 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); ghe.onPlayerInteractInNether(e);
verify(nextBlock, never()).setType(Material.WATER); 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 @Test
public void testOnPlayerInteractInNetherNotInGreenhouse() { public void testOnPlayerInteractInNetherNotInGreenhouse() {
@ -236,7 +223,7 @@ public class GreenhouseEventsTest {
when(clickedBlock.getRelative(any())).thenReturn(nextBlock); when(clickedBlock.getRelative(any())).thenReturn(nextBlock);
ItemStack item = mock(ItemStack.class); ItemStack item = mock(ItemStack.class);
when(item.getType()).thenReturn(Material.WATER_BUCKET); 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); ghe.onPlayerInteractInNether(e);
verify(nextBlock, never()).setType(Material.WATER); verify(nextBlock, never()).setType(Material.WATER);
} }
@ -310,7 +297,7 @@ public class GreenhouseEventsTest {
ghe.onIceBreak(e); ghe.onIceBreak(e);
verify(block).setType(Material.AIR); verify(block).setType(Material.AIR);
assertTrue(e.isCancelled()); 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));
} }
@ -430,8 +417,7 @@ public class GreenhouseEventsTest {
*/ */
@Test @Test
public void testOnBlockBreak() { public void testOnBlockBreak() {
BoundingBox bb = BoundingBox.of(location, location2); when(gh1.isRoofOrWallBlock(any())).thenReturn(true);
when(gh1.getBoundingBox()).thenReturn(bb);
// Location is a wall block // Location is a wall block
Block block = mock(Block.class); Block block = mock(Block.class);
when(block.getLocation()).thenReturn(location); when(block.getLocation()).thenReturn(location);
@ -441,34 +427,4 @@ public class GreenhouseEventsTest {
verify(gm).removeGreenhouse(any()); verify(gm).removeGreenhouse(any());
} }
/**
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPistonPush(org.bukkit.event.block.BlockPistonExtendEvent)}.
*/
@Test
public void testOnPistonPush() {
Block block = mock(Block.class);
when(block.getLocation()).thenReturn(location);
when(block.getY()).thenReturn(255);
when(block.getWorld()).thenReturn(world);
when(world.getEnvironment()).thenReturn(Environment.NORMAL);
BlockPistonExtendEvent e = new BlockPistonExtendEvent(block, Collections.singletonList(block), BlockFace.EAST);
ghe.onPistonPush(e);
assertTrue(e.isCancelled());
}
/**
* Test method for {@link world.bentobox.greenhouses.listeners.GreenhouseEvents#onPistonPush(org.bukkit.event.block.BlockPistonExtendEvent)}.
*/
@Test
public void testOnPistonPushUnderGH() {
Block block = mock(Block.class);
when(block.getLocation()).thenReturn(location);
when(block.getY()).thenReturn(0);
when(block.getWorld()).thenReturn(world);
when(world.getEnvironment()).thenReturn(Environment.NORMAL);
BlockPistonExtendEvent e = new BlockPistonExtendEvent(block, Collections.singletonList(block), BlockFace.EAST);
ghe.onPistonPush(e);
assertFalse(e.isCancelled());
}
} }

View File

@ -1,39 +1,47 @@
/**
*
*/
package world.bentobox.greenhouses.managers; package world.bentobox.greenhouses.managers;
import static org.junit.Assert.assertEquals; 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.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.util.List; import java.util.List;
import java.util.Optional;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Keyed;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Tag;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.util.BoundingBox; import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunner;
import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.BentoBox;
import world.bentobox.greenhouses.data.Greenhouse; import world.bentobox.greenhouses.data.Greenhouse;
import world.bentobox.greenhouses.greenhouse.BiomeRecipe;
import world.bentobox.greenhouses.managers.EcoSystemManager.GrowthBlock;
/** /**
* @author tastybento * @author tastybento
* *
*/ */
@RunWith(PowerMockRunner.class) @RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class}) @PrepareForTest({Bukkit.class, BentoBox.class, Tag.class, RecipeManager.class})
public class EcoSystemManagerTest { public class EcoSystemManagerTest {
private Greenhouse gh; private Greenhouse gh;
@ -47,14 +55,21 @@ public class EcoSystemManagerTest {
private Block liquid; private Block liquid;
@Mock @Mock
private Block plant; private Block plant;
@Mock
private BiomeRecipe recipe;
// CUT // CUT
private EcoSystemManager eco; private EcoSystemManager eco;
/** /**
* @throws java.lang.Exception
*/ */
@Before @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(); gh = new Greenhouse();
// 4x4x4 greenhouse // 4x4x4 greenhouse
BoundingBox bb = BoundingBox.of(new Vector(0,0,0), new Vector(6,5,6)); BoundingBox bb = BoundingBox.of(new Vector(0,0,0), new Vector(6,5,6));
@ -68,100 +83,110 @@ public class EcoSystemManagerTest {
// Liquid false // Liquid false
when(air.isEmpty()).thenReturn(true); when(air.isEmpty()).thenReturn(true);
when(air.isPassable()).thenReturn(true); when(air.isPassable()).thenReturn(true);
when(air.getRelative(eq(BlockFace.UP))).thenReturn(air); when(air.getRelative(BlockFace.UP)).thenReturn(air);
// Plant // Plant
// Empty false // Empty false
// Liquid false // Liquid false
when(plant.isPassable()).thenReturn(true); when(plant.isPassable()).thenReturn(true);
when(plant.getRelative(eq(BlockFace.UP))).thenReturn(air); when(plant.getRelative(BlockFace.UP)).thenReturn(air);
// Liquid // Liquid
// Empty false // Empty false
when(liquid.isLiquid()).thenReturn(true); when(liquid.isLiquid()).thenReturn(true);
when(liquid.isPassable()).thenReturn(true); when(liquid.isPassable()).thenReturn(true);
when(liquid.getRelative(eq(BlockFace.UP))).thenReturn(air); when(liquid.getRelative(BlockFace.UP)).thenReturn(air);
// Default for block // Default for block
// Empty false // Empty false
// Passable false // Passable false
// Liquid false // Liquid false
when(block.getRelative(eq(BlockFace.UP))).thenReturn(air); when(block.getRelative(BlockFace.UP)).thenReturn(air);
// Recipe
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); eco = new EcoSystemManager(null, null);
} }
/** /**
* @throws java.lang.Exception * Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(Greenhouse, boolean)}.
*/
@After
public void tearDown() throws Exception {
}
/**
* Test method for {@link world.bentobox.greenhouses.managers.EcoSystemManager#getAvailableBlocks(world.bentobox.greenhouses.data.Greenhouse)}.
*/ */
@Test @Test
public void testGetAvailableBlocksAirAboveBlock() { public void testGetAvailableBlocksAirAboveBlock() {
List<Block> result = eco.getAvailableBlocks(gh, false); List<GrowthBlock> result = eco.getAvailableBlocks(gh, false);
assertEquals(16, result.size()); 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 @Test
public void testGetAvailableBlocksPlantAboveBlock() { public void testGetAvailableBlocksPlantAboveBlock() {
when(block.getRelative(eq(BlockFace.UP))).thenReturn(plant); 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(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 @Test
public void testGetAvailableBlocksAllAir() { public void testGetAvailableBlocksAllAir() {
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(air); 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()); 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 @Test
public void testGetAvailableBlocksAllLiquid() { public void testGetAvailableBlocksAllLiquid() {
when(liquid.getRelative(eq(BlockFace.UP))).thenReturn(liquid); when(liquid.getRelative(eq(BlockFace.UP))).thenReturn(liquid);
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(liquid); when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(liquid);
List<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()); 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 @Test
public void testGetAvailableBlocksAllPlant() { public void testGetAvailableBlocksAllPlant() {
when(plant.getRelative(eq(BlockFace.UP))).thenReturn(plant); when(plant.getRelative(eq(BlockFace.UP))).thenReturn(plant);
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).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(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 @Test
public void testGetAvailableBlocksLiquidAboveBlockIgnoreLiquids() { public void testGetAvailableBlocksLiquidAboveBlockIgnoreLiquids() {
when(block.getRelative(eq(BlockFace.UP))).thenReturn(liquid); 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(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 @Test
public void testGetAvailableBlocksAirAboveLiquidNotIgnoreLiquids() { public void testGetAvailableBlocksAirAboveLiquidNotIgnoreLiquids() {
@ -171,15 +196,15 @@ public class EcoSystemManagerTest {
when(liquid.getRelative(eq(BlockFace.UP))).thenReturn(air); when(liquid.getRelative(eq(BlockFace.UP))).thenReturn(air);
when(block.getRelative(eq(BlockFace.UP))).thenReturn(liquid); 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()); assertEquals(16, result.size());
for (int i = 0; i< result.size(); i++) { for (GrowthBlock value : result) {
assertEquals(air, result.get(i)); 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 @Test
public void testGetAvailableBlocksAirAboveLiquidIgnoreLiquids() { public void testGetAvailableBlocksAirAboveLiquidIgnoreLiquids() {
@ -189,10 +214,63 @@ public class EcoSystemManagerTest {
when(liquid.getRelative(eq(BlockFace.UP))).thenReturn(air); when(liquid.getRelative(eq(BlockFace.UP))).thenReturn(air);
when(block.getRelative(eq(BlockFace.UP))).thenReturn(liquid); 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(16, result.size());
for (int i = 0; i< result.size(); i++) { for (GrowthBlock value : result) {
assertEquals(liquid, result.get(i)); 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; private AsyncWorldCache cache;
/** /**
* @throws java.lang.Exception
*/ */
@Before @Before
public void setUp() throws Exception { public void setUp() {
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS); PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
when(Tag.TRAPDOORS.isTagged(Material.BIRCH_TRAPDOOR)).thenReturn(true); when(Tag.TRAPDOORS.isTagged(Material.BIRCH_TRAPDOOR)).thenReturn(true);
// Declare mock after mocking Bukkit // Declare mock after mocking Bukkit
roof = mock(Roof.class); roof = mock(Roof.class);
when(roof.roofBlocks(any())).thenCallRealMethod();
// Location // Location
when(location.getBlockX()).thenReturn(5); when(location.getBlockX()).thenReturn(5);
when(location.getBlockY()).thenReturn(14); when(location.getBlockY()).thenReturn(14);
when(location.getBlockZ()).thenReturn(25); when(location.getBlockZ()).thenReturn(25);
when(location.getWorld()).thenReturn(world); when(location.getWorld()).thenReturn(world);
// Addon
when(addon.wallBlocks(any())).thenCallRealMethod();
// Block // Block
when(cache.getBlockType(any())).thenReturn(Material.GLASS); when(cache.getBlockType(any())).thenReturn(Material.GLASS);
when(cache.getBlockType(anyInt(), anyInt(), anyInt())).thenReturn(Material.GLASS); when(cache.getBlockType(anyInt(), anyInt(), anyInt())).thenReturn(Material.GLASS);
@ -95,12 +96,12 @@ public class GreenhouseFinderTest {
when(cache.getMaxHeight()).thenReturn(30); when(cache.getMaxHeight()).thenReturn(30);
gf = new GreenhouseFinder(); gf = new GreenhouseFinder(addon);
cc = gf.new CounterCheck(); 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 @Test
public void testCheckGreenhouse() { 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 @Test
public void testCheckDoorsHoppersHopper() { public void testCheckDoorsHoppersHopper() {
@ -233,7 +234,7 @@ public class GreenhouseFinderTest {
// Set the greenhouse so the world is known // Set the greenhouse so the world is known
gf.setGh(gh); gf.setGh(gh);
when(Tag.DOORS.isTagged(any(Material.class))).thenReturn(false); 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.checkDoorsHoppers(cc, Material.HOPPER, new Vector(5,14,25)));
assertTrue(gf.getRedGlass().isEmpty()); assertTrue(gf.getRedGlass().isEmpty());
assertEquals(5, gf.getGh().getRoofHopperLocation().getBlockX()); assertEquals(5, gf.getGh().getRoofHopperLocation().getBlockX());