1
mirror of https://github.com/StarWishsama/Slimefun4.git synced 2024-09-20 03:35:51 +00:00

Merge branch 'master' into SfGuideEvent

This commit is contained in:
LinoxGH 2020-10-03 23:09:25 +03:00 committed by GitHub
commit 869051b093
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
160 changed files with 2723 additions and 885 deletions

7
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,7 @@
# Modifications to the source code should be handled by the review team
*.java @Slimefun/code-reviewers
# Modifications to sensitive files should be reviewed by maintainers
/.github/ @Slimefun/slimefun4-maintainers
pom.xml @Slimefun/slimefun4-maintainers
CONTRIBUTING.md @Slimefun/slimefun4-maintainers

View File

@ -6,25 +6,25 @@
This document should serve the purpose of outlining the behaviour we expect from any participant of the project.
## Scope
## :mag_right: Scope
This Code of Conduct applies to all sections of the [Slimefun4 GitHub repository](https://github.com/Slimefun/Slimefun4), our [Slimefun GitHub organization](https://github.com/Slimefun) and all repositories owned by said organization.<br>
For our official Discord server, please refer to our article on [Discord Rules](https://github.com/Slimefun/Slimefun4/wiki/Discord-Rules).
Everyone who engages with this project on any of these repositories is expected to follow the Code of Conduct.<br>
This includes maintainers, contributors, sponsors and anyone who engages in the "Issues" section on GitHub.
## Engagement
## :loudspeaker: Engagement
This is an Open-Source project, anyone is welcome to engage and contribute!<br>
We generally expect users to engage in the Issues section by reporting bugs or commenting on bug reports to give additional context, help, guidance or to propose possible solutions and fixes.
Pull Requests are very much welcome and encouraged! They keep the project alive, so if you see an Issue and know how to fix it, feel free to create a Pull Request!
Issues that are considered "good first issues", indicated by the [good first issue](https://github.com/Slimefun/Slimefun4/labels/good%20first%20issue) label, are generally expected to be beginner-friendly.
And even if you shouldn't know where to start or how to proceed, our [Discord Server](https://github.com/Slimefun/Slimefun4#discord) and its community will be there for you!
And even if you shouldn't know where to start or how to proceed, our [Discord Server](https://discord.gg/slimefun) and its community will be there for you!
When commenting, please keep in mind that this software is offered for **free**. Don't expect to receive lightning-fast replies 24 hours a day.
Everyone here works on this project in their free time and usually has work, school, university or family to take care of, so we appreciate patience and understanding.
## Our Standards
## :scroll: Our Standards
Examples of behavior that contributes to a positive environment for our community include but are not limited to:
* Demonstrating empathy and kindness towards other people
* Being respectful of differing opinions, viewpoints, and experiences
@ -43,7 +43,7 @@ Examples of unacceptable behavior include but are not limited to:
* Impatient, aggresive and toxic behaviour
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Enforcement Responsibilities
## :round_pushpin: Enforcement Responsibilities
Our project maintainers are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
@ -57,16 +57,16 @@ decisions when appropriate.
You can see a list of people who are recognized as "project maintainers" for Slimefun on the Slimefun GitHub organization:<br>
https://github.com/orgs/Slimefun/people
## Enforcement
## :wrench: Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders (labelled on Discord as "Admins" or "Moderators") responsible for enforcement on our [Discord Server](https://github.com/Slimefun/Slimefun4#discord).
reported to the community leaders (labelled on Discord as "Admins" or "Moderators") responsible for enforcement on our [Discord Server](discord.gg/slimefun).
If you want your issue to be handled discreetly, message `TheBusyBiscuit#2610` or `Walshy#9709` privately on Discord and state your concerns.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Attribution
## :balance_scale: Attribution
This Code of Conduct is a **modified version** of the original [Contributor Covenant Code of Conduct](https://www.contributor-covenant.org),
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.

View File

@ -9,37 +9,37 @@ assignees: ''
<!-- FILL IN THE FORM BELOW -->
## Description (REQUIRED)
## :round_pushpin: Description (REQUIRED)
<!-- A clear and detailed description of what went wrong. -->
<!-- The more information you can provide, the easier we can handle this problem. -->
<!-- Start writing below this line -->
## Steps to reproduce the Issue (REQUIRED)
## :bookmark_tabs: Steps to reproduce the Issue (REQUIRED)
<!-- Tell us the exact steps to reproduce this issue, the more detailed the easier we can reproduce it. -->
<!-- Youtube Videos and Screenshots are recommended! -->
<!-- Youtube Videos and Screenshots are recommended!!! -->
<!-- Start writing below this line -->
## Expected behavior (REQUIRED)
## :bulb: Expected behavior (REQUIRED)
<!-- What were you expecting to happen? -->
<!-- What do you think would have been the correct behaviour? -->
<!-- Start writing below this line -->
## Server Log
## :scroll: Server Log
<!-- Take a look at your Server Log and post any errors you can find via https://pastebin.com/ -->
<!-- If you are unsure about it, post your full log, you can find it under /logs/latest.log -->
<!-- Start writing below this line -->
<!-- Paste your link(s) below this line -->
## Error Reports
## :open_file_folder: /error-reports/ Folder
<!-- Check the folder /plugins/Slimefun/error-reports/ and upload all files inside that folder. -->
<!-- You can also post these files via https://pastebin.com/ -->
<!-- Start writing below this line -->
<!-- Paste your link(s) below this line -->
## Environment (REQUIRED)
## :compass: Environment (REQUIRED)
<!-- Any info without the exact version numbers will be closed! -->
<!-- "latest" IS NOT A VERSION NUMBER. -->
<!-- We recommend running "/sf versions" and showing us a screenshot of that. -->

View File

@ -7,5 +7,5 @@ contact_links:
url: https://github.com/Slimefun/Slimefun4/wiki/How-to-report-bugs
about: Guidelines on how to make good Bug reports
- name: Discord Server (for Questions and Suggestions)
url: https://discord.gg/fsD4Bkh
url: https://discord.gg/slimefun
about: Please ask and answer questions here.

View File

@ -0,0 +1,57 @@
---
name: Hacktoberfest Issue
about: "- DO NOT USE - Please post your suggestions on discord and we will create
an issue for you if applicable."
title: ''
labels: Hacktoberfest
assignees: ''
---
<!-- READ ME FIRST -->
<!-- If you wanna submit an idea for Hacktoberfest, please go to our discord server -->
<!-- And post your ideas there, this issue format is for internal purposes only. -->
<!-- If we like your idea, we will happily convert it into an actual issue. -->
This Issue is part of [Hacktoberfest](https://hacktoberfest.digitalocean.com/) - A yearly event which encourages participation in the open-source community. [Sign up on their website](https://hacktoberfest.digitalocean.com/) and submit **four pull requests during october (Oct 1st - Oct 31st)** to any public open-source project on GitHub and earn a limited-edition T-shirt or plant a tree!
## :mag_right: Scope
The following bullet points explain what the scope of this feature should be.
It should give a general idea of what we want, you can of course deviate from this as needed.
<!-- Please list the scope using bullet points below -->
## :anchor: Difficulty
Here is our honest estimate on how difficult (on a scale of 1-5) the implementation may be:
<!-- Please rate on a scale of 1-5 -->
<!-- white_cirlce = empty; large_blue_circle = filled out -->
:white_circle::white_circle::white_circle::white_circle::white_circle:
## :construction: Technical Challenges
These are some challenges which may need to be overcome, we wanna be as transparent as possible, so here is some guidance on what may present itself as an obstacle.
<!-- Please list possible obstacles as bullet points below -->
## :memo: Relevant Classes or Snippets
Here are some classes or code snippets which we think might help you get a better understanding where to look for in this gigantic codebase
<!-- Please list relevant classes or snippets below and include a link! -->
## :book: Useful Resources
If you need help on how to get started, maybe try looking into the following resources!
<!-- List helpful resources below -->
* Hacktoberfest
* [Getting started with Hacktoberfest](https://hacktoberfest.digitalocean.com/details#get-started)
* [Hacktoberfest FAQ](https://hacktoberfest.digitalocean.com/faq)
* GitHub/Open-Source
* [How to contribute to Open-Source](https://opensource.guide/how-to-contribute/)
* [Working with forks](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/working-with-forks)
* [Creating a Pull Request](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork)
* Slimefun
* [Contributing to Slimefun](https://github.com/Slimefun/Slimefun4/blob/master/CONTRIBUTING.md)
* [Code of Conduct](https://github.com/Slimefun/Slimefun4/blob/master/.github/CODE_OF_CONDUCT.md)
<hr>
If you want to work on this, simply comment down below and state your interests! Please also comment again if you have changed your mind. Anyone is allowed to discuss in the comments below, feel free to collaborate and work together :heart: <br>
You can always ask for help here if you get stuck.

View File

@ -10,7 +10,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: hmarr/auto-approve-action@v2.0.0
- name: Approve via actions
uses: hmarr/auto-approve-action@v2.0.0
if: github.actor == 'gitlocalize-app[bot]' || github.actor == 'renovate[bot]'
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
- name: Approve via TheBusyBot
uses: hmarr/auto-approve-action@v2.0.0
if: github.actor == 'gitlocalize-app[bot]' || github.actor == 'renovate[bot]'
with:
github-token: "${{ secrets.ACCESS_TOKEN }}"

View File

@ -10,7 +10,7 @@ jobs:
name: Invalid Issues
runs-on: ubuntu-latest
if: contains(github.event.issue.labels.*.name, 'Bug Report') == false
if: contains(github.event.issue.labels.*.name, 'Bug Report') == false && contains(github.event.issue.labels.*.name, 'Hacktoberfest') == false
steps:
- name: Close Issue
uses: maxkomarychev/octions/octions/issues/update@master

View File

@ -43,7 +43,7 @@ jobs:
* [ ] Your issue is not a bug, please only use this issue tracker to report bugs. Any other kind of communication should happen on discord.
* [ ] Your issue has already been reported before, it is a duplicate. Check the other issues first before posting!
* [ ] You posted an error without using pastebin. Please always post errors via pastebin otherwise they become nearly unreadable.
* [ ] You seem to be reporting multiple bugs at once. Please make a seperate issue for each bug you encountered, so we can properly handle them individually.
* [ ] You seem to be reporting multiple bugs at once. Please make a separate issue for each bug you encountered, so we can properly handle them individually.
* [ ] Your issue has already been fixed in a later version of Slimefun or CS-CoreLib, you should update.
* [ ] You are using an outdated and unsupported version of Slimefun / CS-CoreLib, again, you should update.
* [ ] You are using an unofficially modified build of Slimefun. We only support official versions of Slimefun - for obvious reasons.

View File

@ -23,4 +23,4 @@ jobs:
print_all: False
retry_count: 2
## These URLs will always be correct, even if their services may be offline right now
white_listed_patterns: http://textures.minecraft.net/texture/,https://pastebin.com/,https://www.spigotmc.org/threads/spigot-bungeecord-1-16-1.447405/#post-3852349
white_listed_patterns: http://textures.minecraft.net/texture/,https://pastebin.com/,https://www.spigotmc.org/threads/spigot-bungeecord-1-16-1.447405/#post-3852349,https://gitlocalize.com/repo/3841

View File

@ -2,6 +2,7 @@
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of contents**
- [Release Candidate 17 (TBD)](#release-candidate-17-tbd)
- [Release Candidate 16 (07 Sep 2020)](#release-candidate-16-07-sep-2020)
- [Release Candidate 15 (01 Aug 2020)](#release-candidate-15-01-aug-2020)
- [Release Candidate 14 (12 Jul 2020)](#release-candidate-14-12-jul-2020)
@ -21,6 +22,40 @@
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Release Candidate 17 (TBD)
#### Additions
* Added /sf charge
* Added Energized Energy Capacitor
* Added various new fuel types to the Coal Generator
* Added a config option for Grappling Hooks to not be consumed on use
* Added Talisman of the Caveman
* You can now convert any gold ingot into gold dust with slightly less returns
#### Changes
* Improved Auto-Updater (Multi-Threading and more)
* General performance improvements
* /sf cheat now shows seasonal categories all year through
#### Fixes
* Fixed #2300
* Fixed #2296
* Fixed colors of Cheat Sheet Slimefun Guide
* Fixed Cheat Sheet Slimefun Guide being unable to open the settings menu via shift + right click
* Fixed #2320
* Fixed some issues with ChestTerminal
* Fixed #2325
* Fixed Climbing Pick having no animation in creative mode
* Fixed #2322
* Fixed some cargo incompatibilities with overflowing inventories
* Fixed #2353
* Fixed #2359
* Fixed #2356
* Fixed #2358
* Fixed #2360
* Fixed #2351
* Fixed #2357
## Release Candidate 16 (07 Sep 2020)
https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#16
@ -107,6 +142,7 @@ https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#16
* Fixed #2266
* Fixed #2275
* Fixed Multi Tools consuming hunger points when holding a Wind Staff in your off hand
* Fixed Teleports getting stuck sometimes
## Release Candidate 15 (01 Aug 2020)
https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#15
@ -224,7 +260,7 @@ https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#14
* Fixed a rare concurrency issue with world saving
* Fixed some contributors showing up twice
* Fixed #2062
* Fixed Grappling hooks disappearing when fired at Item frames or paintaings
* Fixed Grappling hooks disappearing when fired at Item frames or paintings
* Fixed Grappling hooks not getting removed when the Player leaves
* Fixed Grappling hooks making Bat sounds
* Fixed #1959
@ -270,7 +306,7 @@ https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#13
* Auto Disenchanting is now a tiny bit faster
* Small performance improvements
* Dried Kelp Blocks can now be used as fuel for Tier 1 Androids
* Androids now have a seperate category in the Slimefun Guide
* Androids now have a separate category in the Slimefun Guide
* Android Interface recipes now require steel ingots
* Changed and unified a couple of tooltips
* Changed tooltip on jetpacks and jet boots to say "Crouch" instead of "Hold Shift"
@ -317,7 +353,7 @@ https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#12
* Fixed #1834
* Fixed #1843
* Fixed #1873
* Fixed Electric Smeltery not prioritisting recipes
* Fixed Electric Smeltery not prioritising recipes
* Fixed #1851
* Fixed #1891
* Fixed #1893
@ -417,7 +453,7 @@ https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#10
* Internal clean up and further documentation
* Changed Automatic Ignition Chamber to be a Dropper
* Teleporters are now significantly faster
* Item permissions have been moved to a seperate permissions.yml file
* Item permissions have been moved to a separate permissions.yml file
* Salt now only requires 2 blocks of Sand
* Fireworks from researching no longer damages entities
* Very slight performance improvements for Cargo networks
@ -502,7 +538,7 @@ https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#6
https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#5
#### Additions
* Aded preset messages.yml files
* Added preset messages.yml files
* Added user-configurable localization
* Added many more options to the messages.yml
* Added custom model data support for Languages
@ -515,8 +551,8 @@ https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#5
* Added ability to translate messages for Players
* Added the ability to translate Researches
* Added StatusEffect API
* Added translatibility to categories
* Added translatibility to geo-resources
* Added translatability to categories
* Added translatability to geo-resources
#### Changes
* Removed Solar Array

View File

@ -3,7 +3,7 @@ This document outlines various ways how you can help contribute to Slimefun and
All contributions must be inline with our [Code of Conduct](https://github.com/Slimefun/Slimefun4/blob/master/.github/CODE_OF_CONDUCT.md) and [License](https://github.com/Slimefun/Slimefun4/blob/master/LICENSE).
Please also follow the templates for Issues and Pull Requests we provide.
## 1. Issues: Bug Reports
## :beetle: 1. Issues: Bug Reports
One of the foundations for good software is reliability. To facilitate this reliability, our community must work together to crush bugs that arise.
This of course requires good information and knowledge about ongoing bugs and issues though.
@ -15,7 +15,7 @@ If you encounter an issue which has already been reported, please don't open a n
It would be awesome though if you could post a comment on the existing issue which explains how you were able to reproduce this yourself.
The more context and information we get, the easier we can fix it.
## 2. Pull Requests: Bug Fixes
## :hammer_and_wrench: 2. Pull Requests: Bug Fixes
Bugs that have been reported need to be fixed of course.<br>
Any open Issue on our [Issues Tracker](https://github.com/Slimefun/Slimefun4/issues) is waiting to be fixed.
@ -23,10 +23,10 @@ This is an Open-Source project and we love Pull Requests.
So if you have an idea on how to approach a known issue, feel free to make a [Pull Request](https://github.com/Slimefun/Slimefun4/pulls) which fixes this bug.
You can also comment on the existing Issue, proposing your idea or communicating that you wanna work on this.
## 3. Pull Requests: Additions/Changes
## :wrench: 3. Pull Requests: Additions/Changes
Slimefun is an Open-Source project and anyone is allowed to make changes or add content to this plugin!
Please visit our [Discord Server](https://github.com/Slimefun/Slimefun4#discord) and share your ideas first, we hate to reject changes because the community disagrees.<br>
Please visit our [Discord Server](https://discord.gg/slimefun) and share your ideas first, we hate to reject changes because the community disagrees.<br>
So communicating your intended changes before-hand will ensure that you don't put too much work into something that might get rejected.
We also have a suggestions section in our Discord Server too. Suggestions can be placed in the `#suggestions` channel and community members can vote on a suggestion.
@ -36,7 +36,7 @@ Therefore our `#approved` is a great place to start looking for ideas on what to
Also consider making an addon for your additions when they get too large, too abstract or too "niche".
You can check out our [Developer Guide](https://github.com/Slimefun/Slimefun4/wiki/Developer-Guide) for a guide on how to create a Slimefun addon..
## 4. Pull Requests: Translations
## :earth_africa: 4. Pull Requests: Translations
Another great way to contribute to Slimefun is by working on translations for the project.
Slimefun's translation is available on [gitlocalize.com](https://gitlocalize.com/repo/3841).
Just find a language you are fluent in and translate away. But make sure to submit a "Review Request" when you are done.
@ -48,7 +48,7 @@ Language Moderators are responsible for proof-reading any new translations for t
For more info on how or what to translate, check out our article on [How to translate Slimefun](https://github.com/Slimefun/Slimefun4/wiki/Translating-Slimefun).
## 5. Pull Requests: Wiki contributions
## :scroll: 5. Pull Requests: Wiki contributions
Slimefun is a very large project and might be quite intimidating for new players.
That's why good documentation is always nice and helpful.
If you have played with Slimefun for a while and gotten yourself familiar with how things work, please consider contributing your experiences and knowledge to others via the wiki!
@ -57,17 +57,18 @@ It would help out a lot :heart:
You can find a tutorial on how to contribute to our wiki right here:<br>
https://github.com/Slimefun/Slimefun4/wiki/Expanding-the-Wiki
## 6. Pull Requests: Code Quality
Slimefun uses [sonarcloud.io](https://sonarcloud.io/dashboard?id=TheBusyBiscuit_Slimefun4) to monitor Code Quality.
## :star: 6. Pull Requests: Code Quality
Slimefun uses [sonarcloud.io](https://sonarcloud.io/dashboard?id=Slimefun_Slimefun4) to monitor Code Quality.
We always welcome quality improvements to the code and the "Code Smells" section on [sonarcloud.io](https://sonarcloud.io/dashboard?id=TheBusyBiscuit_Slimefun4) is a great place to start.
We always welcome quality improvements to the code and the "Code Smells" section on [sonarcloud.io](https://sonarcloud.io/dashboard?id=Slimefun_Slimefun4) is a great place to start.
But please keep in mind that some design patterns may not be changed too abruptly if an addon depends on them.
To prevent any accidents from happening, please contact us on our [Discord Server](https://github.com/Slimefun/Slimefun4#discord) before-hand and state your intended changes.
To prevent any accidents from happening, please contact us on our [Discord Server](https://discord.gg/slimefun) before-hand and state your intended changes.
#### Documentation
Code documentation is also a great way to improve the maintainability of the project.
Every class and every public method should have a Javadocs tag assigned to it.
Classes should also include an "author" tag to indicate who worked on that class.
1. Every class and every public method should have a Javadocs section assigned to it.
2. Classes should also include an `@author` tag to indicate who worked on that class.
3. Methods and parameters should be annotated with `@Nullable` or `@Nonnull` to indicate whether or not null values are accepted.
Feel free to visit our [Javadocs](https://slimefun.github.io/javadocs/Slimefun4/docs/overview-summary.html)
@ -76,4 +77,20 @@ Unit Tests help us test the project to work as intended in an automated manner.<
More or better Unit Tests are always good to have, so feel free to submit a Test and place it in our [src/test/java](https://github.com/Slimefun/Slimefun4/tree/master/src/test/java/io/github/thebusybiscuit/slimefun4/testing) directory
We are using [Junit 5 - Jupiter](https://github.com/junit-team/junit5/) and [MockBukkit](https://github.com/seeseemelk/MockBukkit) as our testing environment.<br>
Every new Unit Test should have a "DisplayName" annotation with a plain text description on what the Unit Test tests.
Every new Unit Test should have a `@DisplayName` annotation with a plain text description on what the Unit Test tests.
## :toolbox: How to compile Slimefun4
Slimefun is written in Java and uses [Maven](https://maven.apache.org/) for compilation.<br>
To compile Slimefun yourself, follow these steps:
1. Clone the project via git<br>
`$ git clone https://github.com/Slimefun/Slimefun4/`
2. Compile the project using Maven<br>
`$ mvn clean package`
3. Extract the compiled `Slimefun-v4.X-UNOFFICIAL.jar` from your `/target/` directory.
If you are already using an IDE, make sure to import the project via git and set it up as a *Maven project*.
Then you should be able build it via Maven using the goals `clean package`.
If you have any further questions, then please join our [Discord Support Server](https://discord.gg/slimefun) and ask your questions in the `#programming-help` channel.<br>
**Note that we will not accept any bug reports from custom-compiled versions of Slimefun**.

View File

@ -12,13 +12,14 @@ It currently adds over **500 new items and recipes** to Minecraft ([Read more ab
But it also comes with a lot of Addons too!<br>
Check out our [Addons](https://github.com/Slimefun/Slimefun4/wiki/Addons), you may find exactly what you were looking for.
### Quick navigation
### :compass: Quick navigation
* **[Download Slimefun4](#download-slimefun-4)**
* **[Screenshots](#screenshots)**
* **[Discord Support Server](#discord)**
* **[Bug Tracker](https://github.com/Slimefun/Slimefun4/issues)**
* **[Wiki](https://github.com/Slimefun/Slimefun4/wiki)**
* **[FAQ](https://github.com/Slimefun/Slimefun4/wiki/FAQ)**
* **[How to contribute](https://github.com/Slimefun/Slimefun4/blob/master/CONTRIBUTING.md)**
## Download Slimefun 4
(See also: [How to install Slimefun](https://github.com/Slimefun/Slimefun4/wiki/Installing-Slimefun))
@ -66,7 +67,7 @@ Well, we asked some users on our [Discord server](#discord) to send us some scre
| *Screenshot provided by GalaxyKat11#3816* | *Screenshot provided by TamThan#7987* | *Screenshot provided by Kilaruna#4981* |
## Discord
You can find Slimefun's community on Discord and connect with **over 2000** users of this plugin from all over the world.<br>
You can find Slimefun's community on Discord and connect with **over 2500** users of this plugin from all over the world.<br>
Click the badge down below to join the server for suggestions/questions or other discussions about this plugin.<br>
We are also hosting a community event every so often, join us to find out more.<br>
**Important**: We do **not** accept bug reports on discord, please use our [Issue Tracker](https://github.com/Slimefun/Slimefun4/issues) to submit bug reports!
@ -75,10 +76,9 @@ Due to the sheer size of this discord server, we need to enforce some [important
Not following these rules can lead to a kick or even a ban from the server.
<p align="center">
<a href="https://discord.gg/fsD4Bkh">
<img src="https://img.shields.io/discord/565557184348422174?color=7289DA&label=Discord&style=for-the-badge" alt="Discord Invite"/>
</a><br>
(Click the badge to join)
<a href="https://discord.gg/slimefun">
<img src="https://discordapp.com/api/guilds/565557184348422174/widget.png?style=banner3" alt="Discord Invite"/>
</a>
</p>
## Wiki
@ -102,49 +102,10 @@ The wiki is entirely community-run, so if you find an article missing, feel free
## Contributing to this project
Slimefun 4 is an Open-Source project and licensed under
[GNU GPLv3](https://github.com/Slimefun/Slimefun4/blob/master/LICENSE).<br>
Over 100 people have already contributed to this amazing project. You guys are awesome.<br>
Over 150+ people have already contributed to this amazing project. You guys are awesome.<br>
Please consider helping us maintain this project too, your engagement keeps the project alive <3.
### Translations
Slimefun4 has recently added suport for translations, note that translations are still _work in progress_.<br>
So not everything may be available for translation yet.<br>
[Read more...](https://github.com/Slimefun/Slimefun4/wiki/Translating-Slimefun)
### Pull requests
This is an open-source community project, so **your contributions keep this plugin alive!**<br>
Pull Requests can be fixes, changes or even additions, but please keep in mind that if you add too much content to Slimefun 4, you should maybe consider making an Addon for it instead ([Developer Guide](https://github.com/Slimefun/Slimefun4/wiki/Developer-Guide)).
#### Compiling
Slimefun is written in Java and uses [Maven](https://maven.apache.org/) for compilation.<br>
To compile Slimefun yourself, follow these steps:
1. Clone the project via git<br>
`$ git clone https://github.com/Slimefun/Slimefun4/`
2. Compile the project using Maven<br>
`$ mvn clean package`
If you are already using an IDE, make sure to import the project via git and set it as a *Maven project*. Then you should be able build it via Maven using the goals `clean package`.
If you have any further questions, then please join our [Discord Support Server](#discord) and ask your questions in the `#programming-help` channel. Note that we will not accept any bug reports from custom-compiled versions of Slimefun.
### Code Quality
Slimefun uses [Sonarcloud.io](https://sonarcloud.io/dashboard?id=TheBusyBiscuit_Slimefun4) to monitor Code Quality.
| [Overall Maintainability](https://sonarcloud.io/documentation/user-guide/metric-definitions/#maintainability) | "Code Smells" | "Technical Debt" | Test Coverage |
| ---- | ---- | ---- | ---- |
| [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=TheBusyBiscuit_Slimefun4&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=TheBusyBiscuit_Slimefun4) | [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=TheBusyBiscuit_Slimefun4&metric=code_smells)](https://sonarcloud.io/dashboard?id=TheBusyBiscuit_Slimefun4) | [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=TheBusyBiscuit_Slimefun4&metric=sqale_index)](https://sonarcloud.io/dashboard?id=TheBusyBiscuit_Slimefun4) | [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=TheBusyBiscuit_Slimefun4&metric=coverage)](https://sonarcloud.io/dashboard?id=TheBusyBiscuit_Slimefun4) |
##### "Code Smells"
Code Smells are portions of the source code that are confusing, lack documentation or are just done very badly in general. These code smells should be held to a bare minimum.
_Please contact us on [Discord](#discord) before working on any code smells. Some design patterns may not be changed abruptly because an addon might depend on them._
##### "Technical Debt"
Technical Debt is basically an estimate for how long it would take to fix all issues and code smells.
##### Test Coverage
Slimefun now also uses Automated Tests to determine whether an update could break something. The coverage shows how much these tests cover. Higher coverage means less breaking changes and as a result also better and more reliable builds.
Due to this being a very huge project though, getting to `100% coverage` is probably close to impossible. But increasing that number even slightly still helps. So feel free to write Unit Tests for Slimefun and place them in the [/src/test/java/](https://github.com/Slimefun/Slimefun4/tree/master/src/test/java) folder.
You can find more info on how to contribute to this project in our [CONTRIBUTING.md](https://github.com/Slimefun/Slimefun4/blob/master/CONTRIBUTING.md).
## Disclaimers
Slimefun4 uses various systems that collect usage information or download automatic updates as well as the latest information about the project.

51
pom.xml
View File

@ -4,12 +4,12 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.thebusybiscuit</groupId>
<groupId>com.github.slimefun</groupId>
<artifactId>Slimefun</artifactId>
<!-- Our default version will be UNOFFICIAL, this will prevent auto updates -->
<!-- from overriding our local test file -->
<version>4.3-UNOFFICIAL</version>
<version>4.8-UNOFFICIAL</version>
<inceptionYear>2013</inceptionYear>
<packaging>jar</packaging>
@ -22,14 +22,15 @@
<maven.compiler.target>1.8</maven.compiler.target>
<!-- Spigot properties -->
<spigot.version>1.16.2</spigot.version>
<spigot.version>1.16.3</spigot.version>
<spigot.javadocs>https://hub.spigotmc.org/javadocs/spigot/</spigot.javadocs>
<!-- Default settings for sonarcloud.io -->
<sonar.projectKey>TheBusyBiscuit_Slimefun4</sonar.projectKey>
<sonar.organization>thebusybiscuit-github</sonar.organization>
<sonar.projectKey>Slimefun_Slimefun4</sonar.projectKey>
<sonar.organization>slimefun</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<sonar.log.level>DEBUG</sonar.log.level>
<sonar.exclusions>src/main/java/me/mrCookieSlime/Slimefun/bstats/bukkit/Metrics.java</sonar.exclusions>
<sonar.coverage.jacoco.xmlReportPaths>target/site/jacoco/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
</properties>
@ -47,10 +48,6 @@
</licenses>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
@ -60,12 +57,12 @@
<url>https://papermc.io/repo/repository/maven-public/</url>
</repository>
<repository>
<id>worldedit-repo</id>
<url>https://maven.sk89q.com/repo/</url>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
<repository>
<id>bStats-repo</id>
<url>https://repo.codemc.org/repository/maven-public</url>
<id>worldedit-repo</id>
<url>https://maven.sk89q.com/repo/</url>
</repository>
<repository>
<id>placeholderapi-repo</id>
@ -131,7 +128,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.5</version>
<version>0.8.6</version>
<executions>
<execution>
@ -161,10 +158,6 @@
<!-- Shade dependencies into the output jar -->
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>me.mrCookieSlime.Slimefun.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>io.github.thebusybiscuit.cscorelib2</pattern>
<shadedPattern>me.mrCookieSlime.Slimefun.cscorelib2</shadedPattern>
@ -173,6 +166,10 @@
<pattern>io.papermc.lib</pattern>
<shadedPattern>io.github.thebusybiscuit.slimefun4.libraries.paperlib</shadedPattern>
</relocation>
<relocation>
<pattern>kong.unirest</pattern>
<shadedPattern>io.github.thebusybiscuit.slimefun4.libraries.unirest</shadedPattern>
</relocation>
</relocations>
<!-- Exclude unneeded metadata files from shaded dependencies -->
@ -290,7 +287,7 @@
<dependency>
<groupId>com.github.TheBusyBiscuit</groupId>
<artifactId>CS-CoreLib</artifactId>
<version>31390302cf</version>
<version>1.7</version>
<scope>provided</scope>
</dependency>
@ -306,13 +303,13 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.6.2</version>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.seeseemelk</groupId>
<artifactId>MockBukkit-v1.16</artifactId>
<version>0.5.0</version>
<version>0.6.0</version>
<scope>test</scope>
<exclusions>
<exclusion>
@ -326,7 +323,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.5.10</version>
<version>3.5.13</version>
<scope>test</scope>
</dependency>
@ -334,13 +331,7 @@
<dependency>
<groupId>com.github.TheBusyBiscuit</groupId>
<artifactId>CS-CoreLib2</artifactId>
<version>0.25.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>1.7</version>
<version>0.26</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -352,7 +343,7 @@
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>3.10.00</version>
<version>3.11.00</version>
<scope>compile</scope>
<exclusions>
<exclusion>

View File

@ -8,6 +8,7 @@ import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.logging.Level;
@ -26,7 +27,6 @@ import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This class represents an {@link ErrorReport}.
@ -41,7 +41,7 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
public class ErrorReport<T extends Throwable> {
private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm", Locale.ROOT);
private static int count;
private static final AtomicInteger count = new AtomicInteger(0);
private SlimefunAddon addon;
private T throwable;
@ -52,7 +52,7 @@ public class ErrorReport<T extends Throwable> {
this.throwable = throwable;
this.addon = addon;
Slimefun.runSync(() -> print(printer));
SlimefunPlugin.runSync(() -> print(printer));
}
@ParametersAreNonnullByDefault
@ -124,12 +124,12 @@ public class ErrorReport<T extends Throwable> {
* @return The amount of {@link ErrorReport ErrorReports} created.
*/
public static int count() {
return count;
return count.get();
}
private void print(@Nonnull Consumer<PrintStream> printer) {
this.file = getNewFile();
count++;
count.incrementAndGet();
try (PrintStream stream = new PrintStream(file, StandardCharsets.UTF_8.name())) {
stream.println();

View File

@ -50,6 +50,8 @@ public enum MinecraftVersion {
*/
UNIT_TEST("Unit Test Environment");
public static final MinecraftVersion[] values = values();
private final String name;
private final String prefix;

View File

@ -0,0 +1,65 @@
package io.github.thebusybiscuit.slimefun4.api.events;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AGenerator;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
/**
* This {@link Event} is fired whenever an {@link AGenerator} has completed its process.
*
* @author poma123
*
*/
public class AsyncGeneratorProcessCompleteEvent extends AsyncMachineProcessCompleteEvent {
private static final HandlerList handlers = new HandlerList();
private final AGenerator generator;
private final MachineFuel machineFuel;
@ParametersAreNonnullByDefault
public AsyncGeneratorProcessCompleteEvent(Location l, AGenerator generator, MachineFuel machineFuel) {
super(l, null, null);
this.generator = generator;
this.machineFuel = machineFuel;
}
/**
* The {@link SlimefunItem} instance of the generator.
*
* @return The {@link SlimefunItem} instance of the generator
*/
@Nonnull
public AGenerator getGenerator() {
return generator;
}
/**
* This returns the used {@link MachineFuel} in the process.
*
* @return The {@link MachineFuel} of the process
*/
@Nonnull
public MachineFuel getMachineFuel() {
return machineFuel;
}
@Nonnull
public static HandlerList getHandlerList() {
return handlers;
}
@Nonnull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
}

View File

@ -0,0 +1,76 @@
package io.github.thebusybiscuit.slimefun4.api.events;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.bukkit.Location;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
/**
* This {@link Event} is fired whenever an {@link AContainer} has completed its process.
*
* @author poma123
*
*/
public class AsyncMachineProcessCompleteEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private final Location location;
private final AContainer container;
private final MachineRecipe machineRecipe;
public AsyncMachineProcessCompleteEvent(@Nonnull Location l, @Nullable AContainer container, @Nullable MachineRecipe machineRecipe) {
super(true);
this.location = l;
this.container = container;
this.machineRecipe = machineRecipe;
}
/**
* This returns the {@link Location} of the machine.
*
* @return The {@link Location} of the machine
*/
@Nonnull
public Location getLocation() {
return location;
}
/**
* The {@link SlimefunItem} instance of the machine.
*
* @return The {@link SlimefunItem} instance of the machine
*/
@Nullable
public AContainer getMachine() {
return container;
}
/**
* This returns the used {@link MachineRecipe} in the process.
*
* @return The {@link MachineRecipe} of the process
*/
@Nullable
public MachineRecipe getMachineRecipe() {
return machineRecipe;
}
@Nonnull
public static HandlerList getHandlerList() {
return handlers;
}
@Nonnull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
}

View File

@ -0,0 +1,65 @@
package io.github.thebusybiscuit.slimefun4.api.events;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.Reactor;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
/**
* This {@link Event} is fired whenever a {@link Reactor} has completed its process.
*
* @author poma123
*
*/
public class AsyncReactorProcessCompleteEvent extends AsyncMachineProcessCompleteEvent {
private static final HandlerList handlers = new HandlerList();
private final Reactor reactor;
private final MachineFuel machineFuel;
@ParametersAreNonnullByDefault
public AsyncReactorProcessCompleteEvent(Location l, Reactor reactor, MachineFuel machineFuel) {
super(l, null, null);
this.reactor = reactor;
this.machineFuel = machineFuel;
}
/**
* The {@link SlimefunItem} instance of the reactor.
*
* @return The {@link SlimefunItem} instance of the reactor
*/
@Nonnull
public Reactor getReactor() {
return reactor;
}
/**
* This returns the used {@link MachineFuel} in the process.
*
* @return The {@link MachineFuel} of the process
*/
@Nonnull
public MachineFuel getMachineFuel() {
return machineFuel;
}
@Nonnull
public static HandlerList getHandlerList() {
return handlers;
}
@Nonnull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
}

View File

@ -17,7 +17,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.geo.GEOScanner;
/**
* This {@link Event} is fired whenever a {@link GEOResource} is being freshly generated.
* This only ocurs when a {@link GEOScanner} queries the {@link Chunk} for a {@link GEOResource}
* This only occurs when a {@link GEOScanner} queries the {@link Chunk} for a {@link GEOResource}
* but cannot find it.
*
* You can modify this {@link Event} by listening to it.

View File

@ -1,7 +1,7 @@
package io.github.thebusybiscuit.slimefun4.api.geo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.OptionalInt;
@ -89,9 +89,9 @@ public class ResourceManager {
* @param world
* The {@link World} of this {@link Location}
* @param x
* The {@link Chunk} x cordinate
* The {@link Chunk} x coordinate
* @param z
* The {@link Chunk} z cordinate
* The {@link Chunk} z coordinate
*
* @return An {@link OptionalInt}, either empty or containing the amount of the given {@link GEOResource}
*/
@ -175,7 +175,7 @@ public class ResourceManager {
menu.addItem(4, new CustomItem(HeadTexture.MINECRAFT_CHUNK.getAsItemStack(), ChatColor.YELLOW + SlimefunPlugin.getLocalization().getResourceString(p, "tooltips.chunk"), "", "&8\u21E8 &7" + SlimefunPlugin.getLocalization().getResourceString(p, "tooltips.world") + ": " + block.getWorld().getName(), "&8\u21E8 &7X: " + x + " Z: " + z), ChestMenuUtils.getEmptyClickHandler());
List<GEOResource> resources = new ArrayList<>(SlimefunPlugin.getRegistry().getGEOResources().values());
Collections.sort(resources, (a, b) -> a.getName(p).toLowerCase(Locale.ROOT).compareTo(b.getName(p).toLowerCase(Locale.ROOT)));
resources.sort(Comparator.comparing(a -> a.getName(p).toLowerCase(Locale.ROOT)));
int index = 10;
int pages = (resources.size() - 1) / 36 + 1;

View File

@ -37,7 +37,6 @@ import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* The {@link GPSNetwork} is a manager class for all {@link GPSTransmitter Transmitters} and waypoints.
@ -288,7 +287,7 @@ public class GPSNetwork {
return;
}
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
WaypointCreateEvent event = new WaypointCreateEvent(p, name, l);
Bukkit.getPluginManager().callEvent(event);

View File

@ -27,7 +27,6 @@ import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
import me.mrCookieSlime.Slimefun.api.Slimefun;
public final class TeleportationManager {
@ -79,7 +78,7 @@ public final class TeleportationManager {
index++;
}
Slimefun.runSync(() -> menu.open(p));
SlimefunPlugin.runSync(() -> menu.open(p));
});
}
@ -137,7 +136,7 @@ public final class TeleportationManager {
source.getWorld().spawnParticle(Particle.PORTAL, source, progress * 2, 0.2F, 0.8F, 0.2F);
source.getWorld().playSound(source, Sound.BLOCK_BEACON_AMBIENT, 1F, 0.6F);
Slimefun.runSync(() -> updateProgress(uuid, speed, progress + speed, source, destination, resistance), 10L);
SlimefunPlugin.runSync(() -> updateProgress(uuid, speed, progress + speed, source, destination, resistance), 10L);
}
}
else {
@ -148,8 +147,8 @@ public final class TeleportationManager {
@ParametersAreNonnullByDefault
private void onTeleport(Player p, Location destination, boolean success, boolean resistance) {
// This needs to run on the main Thread so we force it, as the
// async teleportation might happen on a seperate Thread.
Slimefun.runSync(() -> {
// async teleportation might happen on a separate Thread.
SlimefunPlugin.runSync(() -> {
if (success) {
// Apply Resistance Effect, if enabled
if (resistance) {

View File

@ -16,8 +16,8 @@ import org.bukkit.Particle;
import org.bukkit.Particle.DustOptions;
import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* An abstract Network class to manage networks in a stateful way
@ -217,7 +217,7 @@ public abstract class Network {
* every {@link Location} that this {@link Network} is connected to.
*/
public void display() {
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
DustOptions options = new DustOptions(Color.BLUE, 3F);
for (Location l : connectedLocations) {

View File

@ -10,9 +10,9 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BackpackListener;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This class represents the instance of a {@link SlimefunBackpack} that is ready to
@ -123,7 +123,7 @@ public class PlayerBackpack {
* The players who this Backpack will be shown to
*/
public void open(Player... players) {
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
for (Player p : players) {
p.openInventory(inventory);
}

View File

@ -404,6 +404,8 @@ public final class PlayerProfile {
* @return Whether the {@link PlayerProfile} was already loaded
*/
public static boolean request(@Nonnull OfflinePlayer p) {
Validate.notNull(p, "Cannot request a Profile for null");
if (!SlimefunPlugin.getRegistry().getPlayerProfiles().containsKey(p.getUniqueId())) {
// Should probably prevent multiple requests for the same profile in the future
Bukkit.getScheduler().runTaskAsynchronously(SlimefunPlugin.instance(), () -> {

View File

@ -11,7 +11,6 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
@ -70,7 +69,6 @@ public class SlimefunRegistry {
private final Set<String> tickers = new HashSet<>();
private final Set<SlimefunItem> radioactive = new HashSet<>();
private final Set<String> activeChunks = ConcurrentHashMap.newKeySet();
private final Set<ItemStack> barterDrops = new HashSet<>();
private final KeyMap<GEOResource> geoResources = new KeyMap<>();
@ -86,8 +84,6 @@ public class SlimefunRegistry {
private final Map<Class<? extends ItemHandler>, Set<ItemHandler>> globalItemHandlers = new HashMap<>();
private final Map<String, SlimefunBlockHandler> blockHandlers = new HashMap<>();
private final Map<String, Set<Location>> activeTickers = new ConcurrentHashMap<>();
private final Map<String, ItemStack> automatedCraftingChamberRecipes = new HashMap<>();
public void load(Config cfg) {
@ -226,10 +222,6 @@ public class SlimefunRegistry {
return tickers;
}
public Set<String> getActiveChunks() {
return activeChunks;
}
public Map<String, SlimefunItem> getSlimefunItemIds() {
return slimefunIds;
}
@ -262,10 +254,6 @@ public class SlimefunRegistry {
return chunks;
}
public Map<String, Set<Location>> getActiveTickers() {
return activeTickers;
}
public KeyMap<GEOResource> getGEOResources() {
return geoResources;
}

View File

@ -28,6 +28,7 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AGenerator;
public interface EnergyNetProvider extends EnergyNetComponent {
@Override
@Nonnull
default EnergyNetComponentType getEnergyComponentType() {
return EnergyNetComponentType.GENERATOR;
}

View File

@ -2,6 +2,8 @@ package io.github.thebusybiscuit.slimefun4.core.attributes;
import java.util.Collection;
import javax.annotation.Nonnull;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -18,9 +20,11 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
*/
public interface Placeable {
@Nonnull
Collection<ItemStack> getDrops();
Collection<ItemStack> getDrops(Player p);
@Nonnull
Collection<ItemStack> getDrops(@Nonnull Player p);
/**
* This method determines how to treat this {@link Block} when it is broken.

View File

@ -1,5 +1,8 @@
package io.github.thebusybiscuit.slimefun4.core.attributes;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
@ -29,6 +32,7 @@ public interface ProtectiveArmor extends ItemAttribute {
*
* @return The {@link ProtectionType}s.
*/
@Nonnull
ProtectionType[] getProtectionTypes();
/**
@ -44,5 +48,6 @@ public interface ProtectiveArmor extends ItemAttribute {
*
* @return The set {@link NamespacedKey}, <code>null</code> if none is found.
*/
@Nullable
NamespacedKey getArmorSetId();
}

View File

@ -1,4 +1,4 @@
/**
* This package contains everything related to slimefun's ingame command.
* This package contains everything related to Slimefun's ingame command.
*/
package io.github.thebusybiscuit.slimefun4.core.commands;

View File

@ -12,7 +12,6 @@ import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
import me.mrCookieSlime.Slimefun.api.Slimefun;
class BackpackCommand extends SubCommand {
@ -27,43 +26,48 @@ class BackpackCommand extends SubCommand {
@Override
public void onExecute(CommandSender sender, String[] args) {
if (!(sender instanceof Player) || !sender.hasPermission("slimefun.command.backpack")) {
SlimefunPlugin.getLocalization().sendMessage(sender, "messages.no-permission", true);
return;
}
if (sender instanceof Player) {
if (sender.hasPermission("slimefun.command.backpack")) {
if (args.length != 3) {
SlimefunPlugin.getLocalization().sendMessage(sender, "messages.usage", true, msg -> msg.replace("%usage%", "/sf backpack <Player> <ID>"));
return;
}
if (args.length != 3) {
SlimefunPlugin.getLocalization().sendMessage(sender, "messages.usage", true, msg -> msg.replace("%usage%", "/sf backpack <Player> <ID>"));
return;
}
if (!PatternUtils.NUMERIC.matcher(args[2]).matches()) {
SlimefunPlugin.getLocalization().sendMessage(sender, "commands.backpack.invalid-id");
return;
}
if (!PatternUtils.NUMERIC.matcher(args[2]).matches()) {
SlimefunPlugin.getLocalization().sendMessage(sender, "commands.backpack.invalid-id");
return;
}
@SuppressWarnings("deprecation")
OfflinePlayer backpackOwner = Bukkit.getOfflinePlayer(args[1]);
@SuppressWarnings("deprecation")
OfflinePlayer backpackOwner = Bukkit.getOfflinePlayer(args[1]);
if (!(backpackOwner instanceof Player) && !backpackOwner.hasPlayedBefore()) {
SlimefunPlugin.getLocalization().sendMessage(sender, "commands.backpack.player-never-joined");
return;
}
if (!(backpackOwner instanceof Player) && !backpackOwner.hasPlayedBefore()) {
SlimefunPlugin.getLocalization().sendMessage(sender, "commands.backpack.player-never-joined");
return;
}
int id = Integer.parseInt(args[2]);
int id = Integer.parseInt(args[2]);
PlayerProfile.get(backpackOwner, profile -> {
if (!profile.getBackpack(id).isPresent()) {
SlimefunPlugin.getLocalization().sendMessage(sender, "commands.backpack.backpack-does-not-exist");
return;
}
PlayerProfile.get(backpackOwner, profile -> {
if (!profile.getBackpack(id).isPresent()) {
SlimefunPlugin.getLocalization().sendMessage(sender, "commands.backpack.backpack-does-not-exist");
return;
SlimefunPlugin.runSync(() -> {
ItemStack item = SlimefunItems.RESTORED_BACKPACK.clone();
SlimefunPlugin.getBackpackListener().setBackpackId(backpackOwner, item, 2, id);
((Player) sender).getInventory().addItem(item);
SlimefunPlugin.getLocalization().sendMessage(sender, "commands.backpack.restored-backpack-given");
});
});
}
Slimefun.runSync(() -> {
ItemStack item = SlimefunItems.RESTORED_BACKPACK.clone();
SlimefunPlugin.getBackpackListener().setBackpackId(backpackOwner, item, 2, id);
((Player) sender).getInventory().addItem(item);
SlimefunPlugin.getLocalization().sendMessage(sender, "commands.backpack.restored-backpack-given");
});
});
else {
SlimefunPlugin.getLocalization().sendMessage(sender, "messages.no-permission", true);
}
}
else {
SlimefunPlugin.getLocalization().sendMessage(sender, "messages.only-players", true);
}
}
}

View File

@ -0,0 +1,55 @@
package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.attributes.Rechargeable;
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
/**
* {@link ChargeCommand} adds an in game command which charges any {@link Rechargeable}
* item to maximum charge, defined by {@link Rechargeable#getMaxItemCharge(ItemStack)}.
*
* @author FluffyBear
*
*/
class ChargeCommand extends SubCommand {
ChargeCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "charge", false);
}
@Override
protected String getDescription() {
return "commands.charge.description";
}
@Override
public void onExecute(CommandSender sender, String[] args) {
if (sender instanceof Player) {
if (sender.hasPermission("slimefun.charge.command")) {
Player p = (Player) sender;
ItemStack item = p.getInventory().getItemInMainHand();
SlimefunItem slimefunItem = SlimefunItem.getByItem(item);
if (slimefunItem instanceof Rechargeable) {
Rechargeable rechargeableItem = (Rechargeable) slimefunItem;
rechargeableItem.setItemCharge(item, rechargeableItem.getMaxItemCharge(item));
SlimefunPlugin.getLocalization().sendMessage(sender, "commands.charge.charge-success", true);
}
else {
SlimefunPlugin.getLocalization().sendMessage(sender, "commands.charge.not-rechargeable", true);
}
}
else {
SlimefunPlugin.getLocalization().sendMessage(sender, "messages.no-permission", true);
}
}
else {
SlimefunPlugin.getLocalization().sendMessage(sender, "messages.only-players", true);
}
}
}

View File

@ -37,6 +37,7 @@ public final class SlimefunSubCommands {
commands.add(new SearchCommand(plugin, cmd));
commands.add(new DebugFishCommand(plugin, cmd));
commands.add(new BackpackCommand(plugin, cmd));
commands.add(new ChargeCommand(plugin, cmd));
return commands;
}

View File

@ -14,7 +14,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.guide.ChestSlimefunGuid
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This is a static utility class that provides convenient access to the methods
@ -73,7 +72,7 @@ public final class SlimefunGuide {
}
private static void openMainMenuAsync(Player player, SlimefunGuideLayout layout, int selectedPage) {
if (!PlayerProfile.get(player, profile -> Slimefun.runSync(() -> openMainMenu(profile, layout, selectedPage)))) {
if (!PlayerProfile.get(player, profile -> SlimefunPlugin.runSync(() -> openMainMenu(profile, layout, selectedPage)))) {
SlimefunPlugin.getLocalization().sendMessage(player, "messages.opening-guide");
}
}

View File

@ -31,4 +31,6 @@ public enum SlimefunGuideLayout {
*/
CHEAT_SHEET;
public static final SlimefunGuideLayout[] values = values();
}

View File

@ -101,7 +101,7 @@ class GuideLayoutOption implements SlimefunGuideOption<SlimefunGuideLayout> {
@Override
public Optional<SlimefunGuideLayout> getSelectedOption(Player p, ItemStack guide) {
for (SlimefunGuideLayout layout : SlimefunGuideLayout.values()) {
for (SlimefunGuideLayout layout : SlimefunGuideLayout.values) {
if (SlimefunUtils.isItemSimilar(guide, SlimefunGuide.getItem(layout), true, false)) {
return Optional.of(layout);
}

View File

@ -1,5 +1,5 @@
/**
* This package contains the Settings menu forthe {@link io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide} as
* This package contains the Settings menu for the {@link io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide} as
* well as the interface {@link io.github.thebusybiscuit.slimefun4.core.guide.options.SlimefunGuideOption} for adding
* your own options
*/

View File

@ -45,6 +45,9 @@ public class MultiBlock {
if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) {
SUPPORTED_TAGS.add(Tag.WOODEN_FENCES);
}
if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_16)) {
SUPPORTED_TAGS.add(Tag.FIRE);
}
}
@Nonnull

View File

@ -180,7 +180,7 @@ public class CargoNet extends ChestTerminalNetwork {
SlimefunPlugin.getProfiler().scheduleEntries((terminals.isEmpty() ? 1 : 2) + inputs.size());
CargoNetworkTask runnable = new CargoNetworkTask(this, inputs, outputs, chestTerminalInputs, chestTerminalOutputs);
Slimefun.runSync(runnable);
SlimefunPlugin.runSync(runnable);
}
}

View File

@ -108,11 +108,18 @@ class CargoNetworkTask implements Runnable {
Inventory inv = inventories.get(inputTarget.getLocation());
if (inv != null) {
// Check if the original slot hasn't been occupied in the meantime
if (inv.getItem(previousSlot) == null) {
inv.setItem(previousSlot, stack);
}
else {
inputTarget.getWorld().dropItem(inputTarget.getLocation().add(0, 1, 0), stack);
// Try to add the item into another available slot then
ItemStack rest = inv.addItem(stack).get(0);
if (rest != null) {
// If the item still couldn't be inserted, simply drop it on the ground
inputTarget.getWorld().dropItem(inputTarget.getLocation().add(0, 1, 0), rest);
}
}
}
else {

View File

@ -15,6 +15,8 @@ import java.util.Set;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location;
import org.bukkit.Material;
@ -296,7 +298,8 @@ abstract class ChestTerminalNetwork extends Network {
try {
for (Location l : terminals) {
BlockMenu terminal = BlockStorage.getInventory(l);
int page = Integer.parseInt(BlockStorage.getLocationInfo(l, "page"));
String data = BlockStorage.getLocationInfo(l, "page");
int page = data == null ? 1 : Integer.parseInt(data);
if (!items.isEmpty() && items.size() < (page - 1) * TERMINAL_SLOTS.length + 1) {
page = 1;
@ -326,6 +329,13 @@ abstract class ChestTerminalNetwork extends Network {
}
}
@Override
public void markDirty(@Nonnull Location l) {
connectorCache.remove(l);
super.markDirty(l);
}
@ParametersAreNonnullByDefault
private void updateTerminal(Location l, BlockMenu terminal, int slot, int index, List<ItemStackAndInteger> items) {
if (items.size() > index) {
ItemStackAndInteger item = items.get(index);
@ -384,6 +394,7 @@ abstract class ChestTerminalNetwork extends Network {
return items;
}
@ParametersAreNonnullByDefault
private void findAllItems(List<ItemStackAndInteger> items, Location l, Block target) {
UniversalBlockMenu menu = BlockStorage.getUniversalInventory(target);
@ -416,6 +427,7 @@ abstract class ChestTerminalNetwork extends Network {
}
}
@ParametersAreNonnullByDefault
private void gatherItemsFromBarrel(Location l, BlockMenu blockMenu, List<ItemStackAndInteger> items) {
try {
Config cfg = BlockStorage.getLocationInfo(blockMenu.getLocation());
@ -447,17 +459,19 @@ abstract class ChestTerminalNetwork extends Network {
}
}
catch (Exception x) {
Slimefun.getLogger().log(Level.SEVERE, "An Exception occured while trying to read data from a Barrel", x);
Slimefun.getLogger().log(Level.SEVERE, "An Exception occurred while trying to read data from a Barrel", x);
}
}
@ParametersAreNonnullByDefault
private void handleWithdraw(DirtyChestMenu menu, List<ItemStackAndInteger> items, Location l) {
for (int slot : menu.getPreset().getSlotsAccessedByItemTransport(menu, ItemTransportFlow.WITHDRAW, null)) {
filter(menu.getItemInSlot(slot), items, l);
}
}
private void filter(ItemStack stack, List<ItemStackAndInteger> items, Location node) {
@ParametersAreNonnullByDefault
private void filter(@Nullable ItemStack stack, List<ItemStackAndInteger> items, Location node) {
if (stack != null && CargoUtils.matchesFilter(node.getBlock(), stack)) {
boolean add = true;

View File

@ -27,7 +27,6 @@ import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* The {@link EnergyNet} is an implementation of {@link Network} that deals with
@ -229,7 +228,7 @@ public class EnergyNet extends Network {
explodedBlocks.add(loc);
BlockStorage.clearBlockInfo(loc);
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
loc.getBlock().setType(Material.LAVA);
loc.getWorld().createExplosion(loc, 0F, false);
});

View File

@ -1,5 +1,5 @@
/**
* This package holds the core systems of Slimefun, these are not neccessarily used as an API
* but ratherprovide the core functionality of this {@link org.bukkit.plugin.Plugin}.
* This package holds the core systems of Slimefun, these are not necessarily used as an API
* but rather provide the core functionality of this {@link org.bukkit.plugin.Plugin}.
*/
package io.github.thebusybiscuit.slimefun4.core;

View File

@ -26,7 +26,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.setup.ResearchSetup;
import io.github.thebusybiscuit.slimefun4.utils.FireworkUtils;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* Represents a research, which is bound to one
@ -86,7 +85,7 @@ public class Research implements Keyed {
/**
* This method returns whether this {@link Research} is enabled.
* {@code false} can mean that this particular {@link Research} was disabled or that
* researches alltogether have been disabled.
* researches altogether have been disabled.
*
* @return Whether this {@link Research} is enabled or not
*/
@ -230,7 +229,7 @@ public class Research implements Keyed {
*/
public void unlock(@Nonnull Player p, boolean instant, @Nonnull Consumer<Player> callback) {
if (!instant) {
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F);
SlimefunPlugin.getLocalization().sendMessage(p, "messages.research.progress", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p)).replace("%progress%", "0%"));
}, 10L);
@ -238,7 +237,7 @@ public class Research implements Keyed {
PlayerProfile.get(p, profile -> {
if (!profile.hasUnlocked(this)) {
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
ResearchUnlockEvent event = new ResearchUnlockEvent(p, this);
Bukkit.getPluginManager().callEvent(event);
@ -250,7 +249,7 @@ public class Research implements Keyed {
SlimefunPlugin.getLocalization().sendMessage(p, "messages.research.start", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p)));
playResearchAnimation(p);
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
finishResearch(p, profile, callback);
SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().remove(p.getUniqueId());
}, (RESEARCH_PROGRESS.length + 1) * 20L);
@ -275,7 +274,7 @@ public class Research implements Keyed {
for (int i = 1; i < RESEARCH_PROGRESS.length + 1; i++) {
int j = i;
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F);
SlimefunPlugin.getLocalization().sendMessage(p, "messages.research.progress", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p)).replace("%progress%", RESEARCH_PROGRESS[j - 1] + "%"));
}, i * 20L);

View File

@ -46,7 +46,7 @@ public class AutoSavingService {
/**
* This method saves every {@link PlayerProfile} in memory and removes profiles
* that were markes for deletion.
* that were marked for deletion.
*/
private void saveAllPlayers() {
Iterator<PlayerProfile> iterator = PlayerProfile.iterator();

View File

@ -51,6 +51,8 @@ public class CustomTextureService {
config.setDefaultValue("SLIMEFUN_GUIDE", 0);
config.setDefaultValue("_UI_BACKGROUND", 0);
config.setDefaultValue("_UI_INPUT_SLOT", 0);
config.setDefaultValue("_UI_OUTPUT_SLOT", 0);
config.setDefaultValue("_UI_BACK", 0);
config.setDefaultValue("_UI_MENU", 0);
config.setDefaultValue("_UI_SEARCH", 0);

View File

@ -22,7 +22,6 @@ import kong.unirest.HttpResponse;
import kong.unirest.JsonNode;
import kong.unirest.Unirest;
import kong.unirest.UnirestException;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This Class represents a Metrics Service that sends data to https://bstats.org/
@ -102,7 +101,7 @@ public class MetricsService {
String version = metricsClass.getPackage().getImplementationVersion();
// This is required to be sync due to bStats.
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
try {
start.invoke(null);
plugin.getLogger().info("Metrics build #" + version + " started.");

View File

@ -1,8 +1,6 @@
package io.github.thebusybiscuit.slimefun4.core.services;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@ -12,8 +10,10 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import org.apache.commons.lang.Validate;
import org.bukkit.Server;
import org.bukkit.World;
@ -38,7 +38,7 @@ public class PerWorldSettingsService {
private final Map<SlimefunAddon, Set<String>> disabledAddons = new HashMap<>();
private final Set<UUID> disabledWorlds = new HashSet<>();
public PerWorldSettingsService(SlimefunPlugin plugin) {
public PerWorldSettingsService(@Nonnull SlimefunPlugin plugin) {
this.plugin = plugin;
}
@ -48,14 +48,7 @@ public class PerWorldSettingsService {
* @param worlds
* An {@link Iterable} of {@link World Worlds} to load
*/
public void load(Iterable<World> worlds) {
try {
migrate();
}
catch (IOException e) {
plugin.getLogger().log(Level.WARNING, "An error occurred while migrating old world settings", e);
}
public void load(@Nonnull Iterable<World> worlds) {
for (World world : worlds) {
load(world);
}
@ -67,41 +60,11 @@ public class PerWorldSettingsService {
* @param world
* The {@link World} to load
*/
public void load(World world) {
public void load(@Nonnull World world) {
Validate.notNull(world, "Cannot load a world that is null");
disabledItems.putIfAbsent(world.getUID(), loadWorldFromConfig(world));
}
/**
* Temporary migration method for the old system
*
* @throws IOException
* This will be thrown if we failed to delete the old {@link File}
*/
private void migrate() throws IOException {
Config oldConfig = new Config(plugin, "whitelist.yml");
if (oldConfig.getFile().exists()) {
for (String world : oldConfig.getKeys()) {
Config newConfig = new Config(plugin, "world-settings/" + world + ".yml");
newConfig.setDefaultValue("enabled", oldConfig.getBoolean(world + ".enabled"));
for (String id : oldConfig.getKeys(world + ".enabled-items")) {
SlimefunItem item = SlimefunItem.getByID(id);
if (item != null) {
String addon = item.getAddon().getName().toLowerCase(Locale.ROOT);
newConfig.setDefaultValue(addon + ".enabled", true);
newConfig.setDefaultValue(addon + '.' + id, oldConfig.getBoolean(world + ".enabled-items." + id));
}
}
newConfig.save();
}
Files.delete(oldConfig.getFile().toPath());
}
}
/**
* This method checks whether the given {@link SlimefunItem} is enabled in the given {@link World}.
*
@ -112,7 +75,10 @@ public class PerWorldSettingsService {
*
* @return Whether the given {@link SlimefunItem} is enabled in that {@link World}
*/
public boolean isEnabled(World world, SlimefunItem item) {
public boolean isEnabled(@Nonnull World world, @Nonnull SlimefunItem item) {
Validate.notNull(world, "The world cannot be null");
Validate.notNull(item, "The SlimefunItem cannot be null");
Set<String> items = disabledItems.computeIfAbsent(world.getUID(), id -> loadWorldFromConfig(world));
if (disabledWorlds.contains(world.getUID())) {
@ -132,7 +98,10 @@ public class PerWorldSettingsService {
* @param enabled
* Whether the given {@link SlimefunItem} should be enabled in that world
*/
public void setEnabled(World world, SlimefunItem item, boolean enabled) {
public void setEnabled(@Nonnull World world, @Nonnull SlimefunItem item, boolean enabled) {
Validate.notNull(world, "The world cannot be null");
Validate.notNull(item, "The SlimefunItem cannot be null");
Set<String> items = disabledItems.computeIfAbsent(world.getUID(), id -> loadWorldFromConfig(world));
if (enabled) {
@ -151,7 +120,8 @@ public class PerWorldSettingsService {
* @param enabled
* Whether this {@link World} should be enabled or not
*/
public void setEnabled(World world, boolean enabled) {
public void setEnabled(@Nonnull World world, boolean enabled) {
Validate.notNull(world, "null is not a valid World");
load(world);
if (enabled) {
@ -170,7 +140,8 @@ public class PerWorldSettingsService {
*
* @return Whether this {@link World} is enabled
*/
public boolean isWorldEnabled(World world) {
public boolean isWorldEnabled(@Nonnull World world) {
Validate.notNull(world, "null is not a valid World");
load(world);
return !disabledWorlds.contains(world.getUID());
@ -186,7 +157,9 @@ public class PerWorldSettingsService {
*
* @return Whether this addon is enabled in that {@link World}
*/
public boolean isAddonEnabled(World world, SlimefunAddon addon) {
public boolean isAddonEnabled(@Nonnull World world, @Nonnull SlimefunAddon addon) {
Validate.notNull(world, "World cannot be null");
Validate.notNull(addon, "Addon cannot be null");
return isWorldEnabled(world) && disabledAddons.getOrDefault(addon, Collections.emptySet()).contains(world.getName());
}
@ -198,7 +171,8 @@ public class PerWorldSettingsService {
* @param world
* The {@link World} to save
*/
public void save(World world) {
public void save(@Nonnull World world) {
Validate.notNull(world, "Cannot save a World that does not exist");
Set<String> items = disabledItems.computeIfAbsent(world.getUID(), id -> loadWorldFromConfig(world));
Config config = getConfig(world);
@ -213,7 +187,10 @@ public class PerWorldSettingsService {
config.save();
}
private Set<String> loadWorldFromConfig(World world) {
@Nonnull
private Set<String> loadWorldFromConfig(@Nonnull World world) {
Validate.notNull(world, "Cannot load a World that does not exist");
String name = world.getName();
Optional<Set<String>> optional = disabledItems.get(world.getUID());
@ -231,6 +208,7 @@ public class PerWorldSettingsService {
if (config.getBoolean("enabled")) {
loadItemsFromWorldConfig(name, config, items);
// We don't actually wanna write to disk during a Unit test
if (SlimefunPlugin.getMinecraftVersion() != MinecraftVersion.UNIT_TEST) {
config.save();
}
@ -243,13 +221,14 @@ public class PerWorldSettingsService {
}
}
private void loadItemsFromWorldConfig(String worldName, Config config, Set<String> items) {
private void loadItemsFromWorldConfig(@Nonnull String worldName, @Nonnull Config config, @Nonnull Set<String> items) {
for (SlimefunItem item : SlimefunPlugin.getRegistry().getEnabledSlimefunItems()) {
if (item != null) {
String addon = item.getAddon().getName().toLowerCase(Locale.ROOT);
config.setDefaultValue(addon + ".enabled", true);
config.setDefaultValue(addon + '.' + item.getID(), true);
// Whether the entire addon has been disabled
boolean isAddonDisabled = config.getBoolean(addon + ".enabled");
if (isAddonDisabled) {
@ -264,7 +243,17 @@ public class PerWorldSettingsService {
}
}
private Config getConfig(World world) {
/**
* This method returns the relevant {@link Config} for the given {@link World}
*
* @param world
* Our {@link World}
*
* @return The corresponding {@link Config}
*/
@Nonnull
private Config getConfig(@Nonnull World world) {
Validate.notNull(world, "World cannot be null");
return new Config(plugin, "world-settings/" + world.getName() + ".yml");
}

View File

@ -0,0 +1,22 @@
package io.github.thebusybiscuit.slimefun4.core.services.github;
import java.time.LocalDateTime;
import javax.annotation.Nonnull;
@FunctionalInterface
interface ActivityCallback {
/**
* This method is called when the {@link GitHubActivityConnector} finished loading.
*
* @param forks
* The amount of forks
* @param stars
* The amount of stars
* @param date
* The {@link LocalDateTime} of the last activity
*/
void accept(int forks, int stars, @Nonnull LocalDateTime date);
}

View File

@ -33,6 +33,7 @@ class ContributionsConnector extends GitHubConnector {
aliases.put("BurningBrimstone", "Bluedevil74");
aliases.put("bverhoeven", "soczol");
aliases.put("ramdon-person", "ramdon_person");
aliases.put("NCBPFluffyBear", "FluffyBear_");
}
private final String prefix;
@ -60,14 +61,14 @@ class ContributionsConnector extends GitHubConnector {
}
@Override
public void onSuccess(JsonNode element) {
public void onSuccess(@Nonnull JsonNode response) {
finished = true;
if (element.isArray()) {
computeContributors(element.getArray());
if (response.isArray()) {
computeContributors(response.getArray());
}
else {
Slimefun.getLogger().log(Level.WARNING, "Received an unusual answer from GitHub, possibly a timeout? ({0})", element);
Slimefun.getLogger().log(Level.WARNING, "Received an unusual answer from GitHub, possibly a timeout? ({0})", response);
}
}
@ -95,7 +96,8 @@ class ContributionsConnector extends GitHubConnector {
String profile = object.getString("html_url");
if (!blacklist.contains(name)) {
github.addContributor(aliases.getOrDefault(name, name), profile, role, commits);
String username = aliases.getOrDefault(name, name);
github.addContributor(username, profile, role, commits);
}
}
}

View File

@ -40,15 +40,29 @@ public class Contributor {
private Optional<UUID> uuid = Optional.empty();
private boolean locked = false;
public Contributor(@Nonnull String username, @Nonnull String profile) {
Validate.notNull(username, "Username must never be null!");
/**
* This creates a new {@link Contributor} with the given ingame name and GitHub profile.
*
* @param minecraftName
* The ingame name in Minecraft for this {@link Contributor}
* @param profile
* A link to their GitHub profile
*/
public Contributor(@Nonnull String minecraftName, @Nonnull String profile) {
Validate.notNull(minecraftName, "Username must never be null!");
Validate.notNull(profile, "The profile cannot be null!");
githubUsername = profile.substring(profile.lastIndexOf('/') + 1);
minecraftUsername = username;
minecraftUsername = minecraftName;
profileLink = profile;
}
/**
* This creates a new {@link Contributor} with the given username.
*
* @param username
* The username of this {@link Contributor}
*/
public Contributor(@Nonnull String username) {
Validate.notNull(username, "Username must never be null!");
@ -57,8 +71,18 @@ public class Contributor {
profileLink = null;
}
public void setContribution(@Nonnull String role, int commits) {
/**
* This sets the amount of contributions of this {@link Contributor} for the
* specified role.
*
* @param role
* The role
* @param commits
* The amount of contributions made as that role
*/
public void setContributions(@Nonnull String role, int commits) {
Validate.notNull(role, "The role cannot be null!");
Validate.isTrue(commits >= 0, "Contributions cannot be negative");
if (!locked || role.startsWith("translator,")) {
contributions.put(role, commits);
@ -66,9 +90,9 @@ public class Contributor {
}
/**
* Returns the name of this contributor.
* Returns the name of this {@link Contributor}.
*
* @return the name of this contributor
* @return the name of this {@link Contributor}
*/
@Nonnull
public String getName() {
@ -76,10 +100,10 @@ public class Contributor {
}
/**
* Returns the MC name of the contributor.
* This may be the same as {@link #getName()}.
* Returns the Minecraft username of the {@link Contributor}.
* This can be the same as {@link #getName()}.
*
* @return The MC username of this contributor.
* @return The Minecraft username of this {@link Contributor}.
*/
@Nonnull
public String getMinecraftName() {
@ -109,6 +133,7 @@ public class Contributor {
*
* @param role
* The role for which to count the contributions.
*
* @return The amount of contributions this {@link Contributor} submitted as the given role
*/
public int getContributions(@Nonnull String role) {
@ -137,7 +162,7 @@ public class Contributor {
}
/**
* Returns this Creator's head texture.
* Returns this contributor's head texture.
* If no texture could be found, or it hasn't been pulled yet,
* then it will return a placeholder texture.
*
@ -171,10 +196,22 @@ public class Contributor {
return headTexture.isComputed();
}
/**
* This sets the skin texture of this {@link Contributor} or clears it.
*
* @param skin
* The base64 skin texture or null
*/
public void setTexture(@Nullable String skin) {
headTexture.compute(skin);
}
/**
* This returns the total amount of contributions towards this project for this
* {@link Contributor}.
*
* @return The total amount of contributions
*/
public int getTotalContributions() {
return contributions.values().stream().mapToInt(Integer::intValue).sum();
}

View File

@ -0,0 +1,42 @@
package io.github.thebusybiscuit.slimefun4.core.services.github;
import java.time.LocalDateTime;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import kong.unirest.JsonNode;
import kong.unirest.json.JSONObject;
class GitHubActivityConnector extends GitHubConnector {
private final ActivityCallback callback;
@ParametersAreNonnullByDefault
GitHubActivityConnector(GitHubService github, String repository, ActivityCallback callback) {
super(github, repository);
this.callback = callback;
}
@Override
public void onSuccess(@Nonnull JsonNode response) {
JSONObject object = response.getObject();
int forks = object.getInt("forks");
int stars = object.getInt("stargazers_count");
LocalDateTime lastPush = NumberUtils.parseGitHubDate(object.getString("pushed_at"));
callback.accept(forks, stars, lastPush);
}
@Override
public String getFileName() {
return "repo";
}
@Override
public String getURLSuffix() {
return "";
}
}

View File

@ -10,6 +10,7 @@ import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import kong.unirest.HttpResponse;
@ -19,8 +20,16 @@ import kong.unirest.UnirestException;
import kong.unirest.json.JSONException;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* The {@link GitHubConnector} is used to connect to the GitHub API service.
* It can be extended by subclasses, this just serves as an abstract super class for
* other connectors.
*
* @author TheBusyBiscuit
* @author Walshy
*/
abstract class GitHubConnector {
private static final String API_URL = "https://api.github.com/";
protected File file;
@ -33,12 +42,23 @@ abstract class GitHubConnector {
this.repository = repository;
}
@Nonnull
public abstract String getFileName();
@Nonnull
public abstract String getURLSuffix();
public abstract void onSuccess(JsonNode element);
/**
* This method is called when the connection finished successfully.
*
* @param response
* The response
*/
public abstract void onSuccess(@Nonnull JsonNode response);
/**
* This method is called when the connection has failed.
*/
public void onFailure() {
// Don't do anything by default
}
@ -61,7 +81,7 @@ abstract class GitHubConnector {
}
else {
if (github.isLoggingEnabled()) {
Slimefun.getLogger().log(Level.WARNING, "Failed to fetch {0}: {1} - {2}", new Object[] {repository + getURLSuffix(), resp.getStatus(), resp.getBody()});
Slimefun.getLogger().log(Level.WARNING, "Failed to fetch {0}: {1} - {2}", new Object[] { repository + getURLSuffix(), resp.getStatus(), resp.getBody() });
}
// It has the cached file, let's just read that then
@ -94,12 +114,13 @@ abstract class GitHubConnector {
}
}
@Nullable
private JsonNode readCacheFile() {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
return new JsonNode(reader.readLine());
}
catch (IOException | JSONException e) {
Slimefun.getLogger().log(Level.WARNING, "Failed to read Github cache file: {0} - {1}: {2}", new Object[] {file.getName(), e.getClass().getSimpleName(), e.getMessage()});
Slimefun.getLogger().log(Level.WARNING, "Failed to read Github cache file: {0} - {1}: {2}", new Object[] { file.getName(), e.getClass().getSimpleName(), e.getMessage() });
return null;
}
}
@ -109,7 +130,7 @@ abstract class GitHubConnector {
output.write(node.toString().getBytes(StandardCharsets.UTF_8));
}
catch (IOException e) {
Slimefun.getLogger().log(Level.WARNING, "Failed to populate GitHub cache: {0} - {1}", new Object[] {e.getClass().getSimpleName(), e.getMessage()});
Slimefun.getLogger().log(Level.WARNING, "Failed to populate GitHub cache: {0} - {1}", new Object[] { e.getClass().getSimpleName(), e.getMessage() });
}
}
}

View File

@ -2,6 +2,7 @@ package io.github.thebusybiscuit.slimefun4.core.services.github;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import kong.unirest.JsonNode;
@ -9,20 +10,20 @@ import kong.unirest.json.JSONArray;
import kong.unirest.json.JSONObject;
import me.mrCookieSlime.Slimefun.api.Slimefun;
class GitHubIssuesTracker extends GitHubConnector {
class GitHubIssuesConnector extends GitHubConnector {
private final IssuesTrackerConsumer callback;
private final IssuesCallback callback;
@ParametersAreNonnullByDefault
GitHubIssuesTracker(GitHubService github, String repository, IssuesTrackerConsumer callback) {
GitHubIssuesConnector(GitHubService github, String repository, IssuesCallback callback) {
super(github, repository);
this.callback = callback;
}
@Override
public void onSuccess(JsonNode element) {
if (element.isArray()) {
JSONArray array = element.getArray();
public void onSuccess(@Nonnull JsonNode response) {
if (response.isArray()) {
JSONArray array = response.getArray();
int issues = 0;
int pullRequests = 0;
@ -41,7 +42,7 @@ class GitHubIssuesTracker extends GitHubConnector {
callback.accept(issues, pullRequests);
}
else {
Slimefun.getLogger().log(Level.WARNING, "Received an unusual answer from GitHub, possibly a timeout? ({0})", element);
Slimefun.getLogger().log(Level.WARNING, "Received an unusual answer from GitHub, possibly a timeout? ({0})", response);
}
}

View File

@ -16,9 +16,6 @@ import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.slimefun4.core.services.localization.Translators;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import kong.unirest.JsonNode;
import kong.unirest.json.JSONObject;
/**
* This Service is responsible for grabbing every {@link Contributor} to this project
@ -39,11 +36,11 @@ public class GitHubService {
private boolean logging = false;
private int issues = 0;
private int pullRequests = 0;
private int forks = 0;
private int stars = 0;
private LocalDateTime lastUpdate = LocalDateTime.now();
private int openIssues = 0;
private int pendingPullRequests = 0;
private int publicForks = 0;
private int stargazers = 0;
/**
* This creates a new {@link GitHubService} for the given repository.
@ -63,6 +60,11 @@ public class GitHubService {
plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new GitHubTask(this), 80L, 60 * 60 * 20L);
}
/**
* This method adds a few default {@link Contributor Contributors}.
* Think of them like honorable mentions that aren't listed through
* the usual methods.
*/
private void addDefaultContributors() {
addContributor("Fuffles_", "&dArtist");
addContributor("IMS_Art", "&dArtist");
@ -73,7 +75,7 @@ public class GitHubService {
private void addContributor(@Nonnull String name, @Nonnull String role) {
Contributor contributor = new Contributor(name);
contributor.setContribution(role, 0);
contributor.setContributions(role, 0);
contributor.setUniqueId(uuidCache.getUUID(name));
contributors.put(name, contributor);
}
@ -83,7 +85,7 @@ public class GitHubService {
String username = profileURL.substring(profileURL.lastIndexOf('/') + 1);
Contributor contributor = contributors.computeIfAbsent(username, key -> new Contributor(minecraftName, profileURL));
contributor.setContribution(role, commits);
contributor.setContributions(role, commits);
contributor.setUniqueId(uuidCache.getUUID(minecraftName));
return contributor;
}
@ -97,37 +99,22 @@ public class GitHubService {
connectors.add(new ContributionsConnector(this, "code2", 2, repository, "developer"));
// TheBusyBiscuit/Slimefun4-Wiki
connectors.add(new ContributionsConnector(this, "wiki", 1, "Slimefun/Slimefun-wiki", "wiki"));
connectors.add(new ContributionsConnector(this, "wiki", 1, "Slimefun/Wiki", "wiki"));
// TheBusyBiscuit/Slimefun4-Resourcepack
connectors.add(new ContributionsConnector(this, "resourcepack", 1, "Slimefun/Resourcepack", "resourcepack"));
// Issues and Pull Requests
connectors.add(new GitHubIssuesTracker(this, repository, (openIssues, openPullRequests) -> {
this.issues = openIssues;
this.pullRequests = openPullRequests;
connectors.add(new GitHubIssuesConnector(this, repository, (issues, pullRequests) -> {
this.openIssues = issues;
this.pendingPullRequests = pullRequests;
}));
connectors.add(new GitHubConnector(this, repository) {
@Override
public void onSuccess(JsonNode element) {
JSONObject object = element.getObject();
forks = object.getInt("forks");
stars = object.getInt("stargazers_count");
lastUpdate = NumberUtils.parseGitHubDate(object.getString("pushed_at"));
}
@Override
public String getFileName() {
return "repo";
}
@Override
public String getURLSuffix() {
return "";
}
});
connectors.add(new GitHubActivityConnector(this, repository, (forks, stars, date) -> {
this.publicForks = forks;
this.stargazers = stars;
this.lastUpdate = date;
}));
}
@Nonnull
@ -155,7 +142,7 @@ public class GitHubService {
* @return The amount of forks
*/
public int getForks() {
return forks;
return publicForks;
}
/**
@ -164,7 +151,7 @@ public class GitHubService {
* @return The amount of people who starred the repository
*/
public int getStars() {
return stars;
return stargazers;
}
/**
@ -173,7 +160,7 @@ public class GitHubService {
* @return The amount of open issues
*/
public int getOpenIssues() {
return issues;
return openIssues;
}
/**
@ -192,7 +179,7 @@ public class GitHubService {
* @return The amount of pending pull requests
*/
public int getPendingPullRequests() {
return pullRequests;
return pendingPullRequests;
}
/**
@ -212,7 +199,6 @@ public class GitHubService {
protected void saveCache() {
for (Contributor contributor : contributors.values()) {
Optional<UUID> uuid = contributor.getUniqueId();
uuid.ifPresent(value -> uuidCache.setValue(contributor.getName(), value));
if (contributor.hasTexture()) {

View File

@ -8,6 +8,7 @@ import java.util.UUID;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.bukkit.Bukkit;
@ -29,7 +30,6 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
class GitHubTask implements Runnable {
private static final int MAX_REQUESTS_PER_MINUTE = 16;
private final GitHubService gitHubService;
GitHubTask(@Nonnull GitHubService github) {
@ -39,7 +39,6 @@ class GitHubTask implements Runnable {
@Override
public void run() {
gitHubService.getConnectors().forEach(GitHubConnector::pullFile);
grabTextures();
}
@ -112,12 +111,12 @@ class GitHubTask implements Runnable {
return 0;
}
@Nullable
private String pullTexture(@Nonnull Contributor contributor, @Nonnull Map<String, String> skins) throws TooManyRequestsException, IOException {
Optional<UUID> uuid = contributor.getUniqueId();
if (!uuid.isPresent()) {
uuid = MinecraftAccount.getUUID(contributor.getMinecraftName());
uuid.ifPresent(contributor::setUniqueId);
}

View File

@ -1,10 +1,10 @@
package io.github.thebusybiscuit.slimefun4.core.services.github;
@FunctionalInterface
interface IssuesTrackerConsumer {
interface IssuesCallback {
/**
* This method is called when the {@link GitHubIssuesTracker} finished loading.
* This method is called when the {@link GitHubIssuesConnector} finished loading.
*
* @param issues
* The amount of open Issues

View File

@ -85,7 +85,7 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
protected abstract void addLanguage(@Nonnull String id, @Nonnull String texture);
protected void loadEmbeddedLanguages() {
for (SupportedLanguage lang : SupportedLanguage.values()) {
for (SupportedLanguage lang : SupportedLanguage.values) {
if (lang.isReadyForRelease() || SlimefunPlugin.getUpdater().getBranch() != SlimefunBranch.STABLE) {
addLanguage(lang.getLanguageId(), lang.getTexture());
}

View File

@ -58,6 +58,8 @@ enum SupportedLanguage {
MACEDONIAN("mk", false, "a0e0b0b5d87a855466980a101a757bcdb5f77d9f7287889f3efa998ee0472fc0"),
TAGALOG("tl", true, "9306c0c1ce6a9c61bb42a572c49e6d0ed20e0e6b3d122cc64c339cbf78e9e937");
public static final SupportedLanguage[] values = values();
private final String id;
private final boolean releaseReady;
private final String textureHash;

View File

@ -5,6 +5,7 @@ import java.util.Set;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
@ -24,16 +25,19 @@ class PlaceholderAPIHook extends PlaceholderExpansion {
this.author = plugin.getDescription().getAuthors().toString();
}
@Nonnull
@Override
public String getIdentifier() {
return "slimefun";
}
@Nonnull
@Override
public String getVersion() {
return version;
}
@Nonnull
@Override
public String getAuthor() {
return author;
@ -49,9 +53,18 @@ class PlaceholderAPIHook extends PlaceholderExpansion {
return true;
}
private boolean isPlaceholder(@Nullable OfflinePlayer p, boolean requiresProfile, @Nonnull String params, @Nonnull String placeholder) {
if (requiresProfile) {
return p != null && placeholder.equals(params) && PlayerProfile.request(p);
}
else {
return placeholder.equals(params);
}
}
@Override
public String onRequest(OfflinePlayer p, String params) {
if (params.equals("researches_total_xp_levels_spent") && PlayerProfile.request(p)) {
public String onRequest(@Nullable OfflinePlayer p, @Nonnull String params) {
if (isPlaceholder(p, true, params, "researches_total_xp_levels_spent")) {
Optional<PlayerProfile> profile = PlayerProfile.find(p);
if (profile.isPresent()) {
@ -60,7 +73,7 @@ class PlaceholderAPIHook extends PlaceholderExpansion {
}
}
if (params.equals("researches_total_researches_unlocked") && PlayerProfile.request(p)) {
if (isPlaceholder(p, true, params, "researches_total_researches_unlocked")) {
Optional<PlayerProfile> profile = PlayerProfile.find(p);
if (profile.isPresent()) {
@ -69,11 +82,11 @@ class PlaceholderAPIHook extends PlaceholderExpansion {
}
}
if (params.equals("researches_total_researches")) {
if (isPlaceholder(p, false, params, "researches_total_researches")) {
return String.valueOf(SlimefunPlugin.getRegistry().getResearches().size());
}
if (params.equals("researches_percentage_researches_unlocked") && PlayerProfile.request(p)) {
if (isPlaceholder(p, true, params, "researches_percentage_researches_unlocked")) {
Optional<PlayerProfile> profile = PlayerProfile.find(p);
if (profile.isPresent()) {
@ -82,7 +95,7 @@ class PlaceholderAPIHook extends PlaceholderExpansion {
}
}
if (params.equals("researches_title") && PlayerProfile.request(p)) {
if (isPlaceholder(p, true, params, "researches_title")) {
Optional<PlayerProfile> profile = PlayerProfile.find(p);
if (profile.isPresent()) {
@ -90,20 +103,17 @@ class PlaceholderAPIHook extends PlaceholderExpansion {
}
}
if (params.equals("gps_complexity")) {
if (isPlaceholder(p, false, params, "gps_complexity") && p != null) {
return String.valueOf(SlimefunPlugin.getGPSNetwork().getNetworkComplexity(p.getUniqueId()));
}
if (params.equals("timings_lag")) {
if (isPlaceholder(p, false, params, "timings_lag")) {
return SlimefunPlugin.getProfiler().getTime();
}
if (params.equals("language")) {
if (!(p instanceof Player)) {
return "Unknown";
}
return SlimefunPlugin.getLocalization().getLanguage((Player) p).getName((Player) p);
if (isPlaceholder(p, false, params, "language") && p instanceof Player) {
Player player = (Player) p;
return SlimefunPlugin.getLocalization().getLanguage(player).getName(player);
}
return null;

View File

@ -31,6 +31,8 @@ public enum PerformanceRating implements Predicate<Float> {
HURTFUL(ChatColor.DARK_RED, 500),
BAD(ChatColor.DARK_RED, Float.MAX_VALUE);
public static final PerformanceRating[] values = values();
private final ChatColor color;
private final float threshold;

View File

@ -81,7 +81,7 @@ public class SlimefunProfiler {
/**
* This method schedules a given amount of entries for the future.
* Be careful to {@link #closeEntry(Location, SlimefunItem, long)} all of them again!
* No {@link PerformanceSummary} will be sent until all entires were closed.
* No {@link PerformanceSummary} will be sent until all entries were closed.
*
* If the specified amount is negative, scheduled entries will be removed
*
@ -297,7 +297,7 @@ public class SlimefunProfiler {
public PerformanceRating getPerformance() {
float percentage = getPercentageOfTick();
for (PerformanceRating rating : PerformanceRating.values()) {
for (PerformanceRating rating : PerformanceRating.values) {
if (rating.test(percentage)) {
return rating;
}

View File

@ -546,6 +546,7 @@ public final class SlimefunItems {
public static final SlimefunItemStack TALISMAN_KNIGHT = new SlimefunItemStack("KNIGHT_TALISMAN", Material.EMERALD, "&aTalisman of the Knight", "", "&fWhile you have this Talisman", "&fin your Inventory it gives", "&fyou a 30% Chance for 5 Seconds of Regeneration", "&fwhenever You get hit", "&fbut will then be consumed");
public static final SlimefunItemStack TALISMAN_WHIRLWIND = new SlimefunItemStack("WHIRLWIND_TALISMAN", Material.EMERALD, "&aTalisman of the Whirlwind", "", "&fHaving this Talisman", "&fin your Inventory will reflect", "&f60% of any projectiles fired at you.", "&e&oOnly a thrown Trident can pierce", "&e&othrough this layer of protection");
public static final SlimefunItemStack TALISMAN_WIZARD = new SlimefunItemStack("WIZARD_TALISMAN", Material.EMERALD, "&aTalisman of the Wizard", "", "&fWhile you have this Talisman", "&fin your Inventory it allows you to", "&fobtain Fortune Level 4/5 however", "&fit also has a chance to lower the", "&fLevel of some Enchantments on your Item");
public static final SlimefunItemStack TALISMAN_CAVEMAN = new SlimefunItemStack("CAVEMAN_TALISMAN", Material.EMERALD, "&aTalisman of the Caveman", "", "&fWhile you have this Talisman", "&fin your inventory it gives", "&fyou a 50% chance for a decent", "&fHaste buff when you mine any ore");
/* Staves */
public static final SlimefunItemStack STAFF_ELEMENTAL = new SlimefunItemStack("STAFF_ELEMENTAL", Material.STICK, "&6Elemental Staff");
@ -675,6 +676,8 @@ public final class SlimefunItems {
public static final SlimefunItemStack BIG_CAPACITOR = new SlimefunItemStack("BIG_CAPACITOR", HeadTexture.CAPACITOR_25, "&aBig Energy Capacitor", "", LoreBuilder.machine(MachineTier.MEDIUM, MachineType.CAPACITOR), "&8\u21E8 &e\u26A1 &71024 J Capacity");
public static final SlimefunItemStack LARGE_CAPACITOR = new SlimefunItemStack("LARGE_CAPACITOR", HeadTexture.CAPACITOR_25, "&aLarge Energy Capacitor", "", LoreBuilder.machine(MachineTier.GOOD, MachineType.CAPACITOR), "&8\u21E8 &e\u26A1 &78192 J Capacity");
public static final SlimefunItemStack CARBONADO_EDGED_CAPACITOR = new SlimefunItemStack("CARBONADO_EDGED_CAPACITOR", HeadTexture.CAPACITOR_25, "&aCarbonado Edged Energy Capacitor", "", LoreBuilder.machine(MachineTier.END_GAME, MachineType.CAPACITOR), "&8\u21E8 &e\u26A1 &765536 J Capacity");
public static final SlimefunItemStack ENERGIZED_CAPACITOR = new SlimefunItemStack("ENERGIZED_CAPACITOR", HeadTexture.CAPACITOR_25, "&aEnergized Energy Capacitor", "", LoreBuilder.machine(MachineTier.END_GAME, MachineType.CAPACITOR), "&8\u21E8 &e\u26A1 &7524288 J Capacity");
/* Robots */
public static final SlimefunItemStack PROGRAMMABLE_ANDROID = new SlimefunItemStack("PROGRAMMABLE_ANDROID", HeadTexture.PROGRAMMABLE_ANDROID, "&cProgrammable Android &7(Normal)", "", "&8\u21E8 &7Function: None", "&8\u21E8 &7Fuel Efficiency: 1.0x");

View File

@ -13,6 +13,7 @@ import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.command.Command;
@ -21,6 +22,7 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader;
import org.bukkit.scheduler.BukkitTask;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
@ -101,7 +103,6 @@ import me.mrCookieSlime.CSCoreLibPlugin.CSCoreLib;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AGenerator;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.inventory.UniversalBlockMenu;
/**
@ -241,7 +242,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
registerListeners();
// Initiating various Stuff and all items with a slight delay (0ms after the Server finished loading)
Slimefun.runSync(new SlimefunStartupTask(this, () -> {
runSync(new SlimefunStartupTask(this, () -> {
protections = new ProtectionManager(getServer());
textureService.register(registry.getAllSlimefunItems(), true);
permissionsService.register(registry.getAllSlimefunItems(), true);
@ -251,7 +252,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
recipeService.refresh();
}
catch (Exception | LinkageError x) {
getLogger().log(Level.SEVERE, x, () -> "An Exception occured while iterating through the Recipe list on Minecraft Version " + minecraftVersion.getName() + " (Slimefun v" + getVersion() + ")");
getLogger().log(Level.SEVERE, x, () -> "An Exception occurred while iterating through the Recipe list on Minecraft Version " + minecraftVersion.getName() + " (Slimefun v" + getVersion() + ")");
}
}), 0);
@ -313,7 +314,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
String currentVersion = ReflectionUtils.getVersion();
if (currentVersion.startsWith("v")) {
for (MinecraftVersion version : MinecraftVersion.values()) {
for (MinecraftVersion version : MinecraftVersion.values) {
if (version.matches(currentVersion)) {
minecraftVersion = version;
return false;
@ -340,7 +341,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
private Collection<String> getSupportedVersions() {
List<String> list = new ArrayList<>();
for (MinecraftVersion version : MinecraftVersion.values()) {
for (MinecraftVersion version : MinecraftVersion.values) {
if (version != MinecraftVersion.UNKNOWN) {
list.add(version.getName());
}
@ -706,4 +707,63 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
return "https://github.com/Slimefun/Slimefun4/issues";
}
/**
* This method schedules a delayed synchronous task for Slimefun.
* <strong>For Slimefun only, not for addons.</strong>
*
* This method should only be invoked by Slimefun itself.
* Addons must schedule their own tasks using their own {@link Plugin} instance.
*
* @param runnable
* The {@link Runnable} to run
* @param delay
* The delay for this task
*
* @return The resulting {@link BukkitTask} or null if Slimefun was disabled
*/
@Nullable
public static BukkitTask runSync(@Nonnull Runnable runnable, long delay) {
Validate.notNull(runnable, "Cannot run null");
Validate.isTrue(delay >= 0, "The delay cannot be negative");
if (getMinecraftVersion() == MinecraftVersion.UNIT_TEST) {
runnable.run();
return null;
}
if (instance == null || !instance.isEnabled()) {
return null;
}
return instance.getServer().getScheduler().runTaskLater(instance, runnable, delay);
}
/**
* This method schedules a synchronous task for Slimefun.
* <strong>For Slimefun only, not for addons.</strong>
*
* This method should only be invoked by Slimefun itself.
* Addons must schedule their own tasks using their own {@link Plugin} instance.
*
* @param runnable
* The {@link Runnable} to run
*
* @return The resulting {@link BukkitTask} or null if Slimefun was disabled
*/
@Nullable
public static BukkitTask runSync(@Nonnull Runnable runnable) {
Validate.notNull(runnable, "Cannot run null");
if (getMinecraftVersion() == MinecraftVersion.UNIT_TEST) {
runnable.run();
return null;
}
if (instance == null || !instance.isEnabled()) {
return null;
}
return instance.getServer().getScheduler().runTask(instance, runnable);
}
}

View File

@ -80,7 +80,7 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
ChatComponent header = new ChatComponent(ChatColors.color("&b&l- " + SlimefunPlugin.getLocalization().getMessage(p, "guide.title.main") + " -\n\n"));
header.setHoverEvent(new HoverEvent(ChestMenuUtils.getSearchButton(p)));
header.setClickEvent(new ClickEvent(guideSearch, player -> Slimefun.runSync(() -> {
header.setClickEvent(new ClickEvent(guideSearch, player -> SlimefunPlugin.runSync(() -> {
SlimefunPlugin.getLocalization().sendMessage(player, "guide.search.message");
ChatInput.waitForPlayer(SlimefunPlugin.instance(), player, msg -> SlimefunGuide.openSearch(profile, msg, true, true));
}, 1)));
@ -234,13 +234,13 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
}
component.setHoverEvent(new HoverEvent(lore));
component.setClickEvent(new ClickEvent(key, player -> Slimefun.runSync(() -> displayItem(profile, item, true))));
component.setClickEvent(new ClickEvent(key, player -> SlimefunPlugin.runSync(() -> displayItem(profile, item, true))));
items.add(component);
}
}
private void research(Player p, PlayerProfile profile, SlimefunItem item, Research research, Category category, int page) {
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
if (!SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().contains(p.getUniqueId())) {
if (research.canUnlock(p)) {
if (profile.hasUnlocked(research)) {

View File

@ -1,14 +1,23 @@
package io.github.thebusybiscuit.slimefun4.implementation.guide;
import javax.annotation.Nonnull;
import java.util.LinkedList;
import java.util.List;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.SlimefunGuideItem;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
/**
@ -33,6 +42,29 @@ public class CheatSheetSlimefunGuide extends ChestSlimefunGuide {
return false;
}
/**
* Returns a {@link List} of visible {@link Category} instances that the {@link SlimefunGuide} would display.
*
* @param p
* The {@link Player} who opened his {@link SlimefunGuide}
* @param profile
* The {@link PlayerProfile} of the {@link Player}
* @return a {@link List} of visible {@link Category} instances
*/
@Nonnull
@Override
protected List<Category> getVisibleCategories(@Nonnull Player p, @Nonnull PlayerProfile profile) {
List<Category> categories = new LinkedList<>();
for (Category category : SlimefunPlugin.getRegistry().getCategories()) {
if (!(category instanceof FlexCategory)) {
categories.add(category);
}
}
return categories;
}
@Override
public SlimefunGuideLayout getLayout() {
return SlimefunGuideLayout.CHEAT_SHEET;

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.implementation.guide;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
@ -96,7 +98,17 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
return true;
}
private List<Category> getVisibleCategories(Player p, PlayerProfile profile) {
/**
* Returns a {@link List} of visible {@link Category} instances that the {@link SlimefunGuide} would display.
*
* @param p
* The {@link Player} who opened his {@link SlimefunGuide}
* @param profile
* The {@link PlayerProfile} of the {@link Player}
* @return a {@link List} of visible {@link Category} instances
*/
@Nonnull
protected List<Category> getVisibleCategories(@Nonnull Player p, @Nonnull PlayerProfile profile) {
List<Category> categories = new LinkedList<>();
for (Category category : SlimefunPlugin.getRegistry().getCategories()) {

View File

@ -1,9 +1,11 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
import javax.annotation.Nonnull;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
/**
* This enum covers all different fuel sources a {@link ProgrammableAndroid} can have.
@ -30,7 +32,7 @@ public enum AndroidFuelSource {
private final String[] lore;
AndroidFuelSource(String... lore) {
AndroidFuelSource(@Nonnull String... lore) {
this.lore = lore;
}
@ -39,8 +41,9 @@ public enum AndroidFuelSource {
*
* @return An {@link ItemStack} to display
*/
@Nonnull
public ItemStack getItem() {
return new CustomItem(SlimefunItems.COAL_GENERATOR, "&8\u21E9 &cFuel Input &8\u21E9", lore);
return new CustomItem(HeadTexture.GENERATOR.getAsItemStack(), "&8\u21E9 &cFuel Input &8\u21E9", lore);
}
}

View File

@ -1,5 +1,10 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
import org.apache.commons.lang.Validate;
@ -140,31 +145,61 @@ enum Instruction {
android.refuel(inv, target);
});
private static final Map<String, Instruction> nameLookup = new HashMap<>();
public static final Instruction[] values = values();
private final ItemStack item;
private final AndroidType type;
private final AndroidAction method;
Instruction(AndroidType type, HeadTexture head, AndroidAction method) {
static {
for (Instruction instruction : values) {
nameLookup.put(instruction.name(), instruction);
}
}
@ParametersAreNonnullByDefault
Instruction(AndroidType type, HeadTexture head, @Nullable AndroidAction method) {
this.type = type;
this.item = SlimefunUtils.getCustomHead(head.getTexture());
this.method = method;
}
@ParametersAreNonnullByDefault
Instruction(AndroidType type, HeadTexture head) {
this(type, head, null);
}
@Nonnull
public ItemStack getItem() {
return item;
}
@Nonnull
public AndroidType getRequiredType() {
return type;
}
@ParametersAreNonnullByDefault
public void execute(ProgrammableAndroid android, Block b, BlockMenu inventory, BlockFace face) {
Validate.notNull(method, "Instruction '" + name() + "' must be executed manually!");
method.perform(android, b, inventory, face);
}
/**
* Get a value from the cache map rather than calling {@link Enum#valueOf(Class, String)}.
* This is 25-40% quicker than the standard {@link Enum#valueOf(Class, String)} depending on
* your Java version. It also means that you can avoid an IllegalArgumentException which let's
* face it is always good.
*
* @param value
* The value which you would like to look up.
*
* @return The {@link Instruction} or null if it does not exist.
*/
@Nullable
public static Instruction getFromCache(@Nonnull String value) {
Validate.notNull(value, "An Instruction cannot be null!");
return nameLookup.get(value);
}
}

View File

@ -5,6 +5,10 @@ import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
@ -54,7 +58,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
@ -220,6 +223,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
});
}
@ParametersAreNonnullByDefault
public void openScript(Player p, Block b, String sourceCode) {
ChestMenu menu = new ChestMenu(ChatColor.DARK_AQUA + SlimefunPlugin.getLocalization().getMessage(p, "android.scripts.editor"));
menu.setEmptySlotsClickable(false);
@ -254,8 +258,15 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
});
}
else {
ItemStack stack = Instruction.valueOf(script[i]).getItem();
menu.addItem(i, new CustomItem(stack, SlimefunPlugin.getLocalization().getMessage(p, "android.scripts.instructions." + Instruction.valueOf(script[i]).name()), "", "&7\u21E8 &eLeft Click &7to edit", "&7\u21E8 &eRight Click &7to delete", "&7\u21E8 &eShift + Right Click &7to duplicate"));
Instruction instruction = Instruction.getFromCache(script[i]);
if (instruction == null) {
SlimefunPlugin.instance().getLogger().log(Level.WARNING, "Failed to parse Android instruction: {0}, maybe your server is out of date?", script[i]);
return;
}
ItemStack stack = instruction.getItem();
menu.addItem(i, new CustomItem(stack, SlimefunPlugin.getLocalization().getMessage(p, "android.scripts.instructions." + instruction.name()), "", "&7\u21E8 &eLeft Click &7to edit", "&7\u21E8 &eRight Click &7to delete", "&7\u21E8 &eShift + Right Click &7to duplicate"));
menu.addMenuClickHandler(i, (pl, slot, item, action) -> {
if (action.isRightClicked() && action.isShiftClicked()) {
if (script.length == 54) {
@ -283,9 +294,10 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
menu.open(p);
}
@ParametersAreNonnullByDefault
private String addInstruction(String[] script, int index, Instruction instruction) {
int i = 0;
StringBuilder builder = new StringBuilder(Instruction.START + "-");
StringBuilder builder = new StringBuilder(Instruction.START.name() + '-');
for (String current : script) {
if (i > 0) {
@ -303,7 +315,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
return builder.toString();
}
private String duplicateInstruction(String[] script, int index) {
private String duplicateInstruction(@Nonnull String[] script, int index) {
int i = 0;
StringBuilder builder = new StringBuilder(Instruction.START + "-");
@ -429,13 +441,9 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
menu.open(p);
}
@ParametersAreNonnullByDefault
private void uploadScript(Player p, Block b, int page) {
String code = getScript(b.getLocation());
if (code == null) {
return;
}
int nextId = 1;
for (Script script : Script.getUploadedScripts(getAndroidType())) {
@ -494,7 +502,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
protected List<Instruction> getValidScriptInstructions() {
List<Instruction> list = new ArrayList<>();
for (Instruction part : Instruction.values()) {
for (Instruction part : Instruction.values) {
if (part == Instruction.START || part == Instruction.REPEAT) {
continue;
}
@ -534,12 +542,13 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
menu.open(p);
}
protected String getScript(Location l) {
@Nonnull
protected String getScript(@Nonnull Location l) {
String script = BlockStorage.getLocationInfo(l, "script");
return script != null ? script : DEFAULT_SCRIPT;
}
protected void setScript(Location l, String script) {
protected void setScript(@Nonnull Location l, @Nonnull String script) {
BlockStorage.addBlockInfo(l, "script", script);
}
@ -647,7 +656,13 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
}
BlockStorage.addBlockInfo(b, "fuel", String.valueOf(fuel - 1));
Instruction instruction = Instruction.valueOf(script[index]);
Instruction instruction = Instruction.getFromCache(script[index]);
if (instruction == null) {
SlimefunPlugin.instance().getLogger().log(Level.WARNING, "Failed to parse Android instruction: {0}, maybe your server is out of date?", script[index]);
return;
}
executeInstruction(instruction, b, menu, data, index);
}
}
@ -770,10 +785,11 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
return false;
}
@ParametersAreNonnullByDefault
private void consumeFuel(Block b, BlockMenu menu) {
ItemStack item = menu.getItemInSlot(43);
if (item != null) {
if (item != null && item.getType() != Material.AIR) {
for (MachineFuel fuel : fuelTypes) {
if (fuel.test(item)) {
menu.consumeItem(43);
@ -790,12 +806,12 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
}
}
private void constructMenu(BlockMenuPreset preset) {
private void constructMenu(@Nonnull BlockMenuPreset preset) {
for (int i : BORDER) {
preset.addItem(i, new CustomItem(new ItemStack(Material.GRAY_STAINED_GLASS_PANE), " "), ChestMenuUtils.getEmptyClickHandler());
preset.addItem(i, ChestMenuUtils.getBackground(), ChestMenuUtils.getEmptyClickHandler());
}
for (int i : OUTPUT_BORDER) {
preset.addItem(i, new CustomItem(new ItemStack(Material.ORANGE_STAINED_GLASS_PANE), " "), ChestMenuUtils.getEmptyClickHandler());
preset.addItem(i, ChestMenuUtils.getOutputSlotTexture(), ChestMenuUtils.getEmptyClickHandler());
}
for (int i : getOutputSlots()) {
@ -834,7 +850,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
});
block.setBlockData(blockData);
Slimefun.runSync(() -> SkullBlock.setFromBase64(block, texture));
SlimefunPlugin.runSync(() -> SkullBlock.setFromBase64(block, texture));
b.setType(Material.AIR);
BlockStorage.moveBlockInfo(b.getLocation(), block.getLocation());

View File

@ -32,7 +32,6 @@ import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
@ -156,7 +155,7 @@ public class BlockPlacer extends SlimefunItem {
dispenser.getInventory().removeItem(new CustomItem(item, 1));
}
else {
Slimefun.runSync(() -> dispenser.getInventory().removeItem(item), 2L);
SlimefunPlugin.runSync(() -> dispenser.getInventory().removeItem(item), 2L);
}
}
});
@ -171,7 +170,7 @@ public class BlockPlacer extends SlimefunItem {
dispenser.getInventory().removeItem(new CustomItem(item, 1));
}
else {
Slimefun.runSync(() -> dispenser.getInventory().removeItem(item), 2L);
SlimefunPlugin.runSync(() -> dispenser.getInventory().removeItem(item), 2L);
}
}
}
@ -209,7 +208,7 @@ public class BlockPlacer extends SlimefunItem {
dispenser.getInventory().removeItem(new CustomItem(item, 1));
}
else {
Slimefun.runSync(() -> dispenser.getInventory().removeItem(item), 2L);
SlimefunPlugin.runSync(() -> dispenser.getInventory().removeItem(item), 2L);
}
}
}

View File

@ -8,6 +8,7 @@ import org.bukkit.Effect;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
@ -17,7 +18,6 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils;
import io.github.thebusybiscuit.cscorelib2.materials.MaterialCollections;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.cscorelib2.scheduling.TaskQueue;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
@ -50,12 +50,12 @@ public class Composter extends SimpleSlimefunItem<BlockUseHandler> implements Re
private List<ItemStack> getMachineRecipes() {
List<ItemStack> items = new LinkedList<>();
for (Material leave : MaterialCollections.getAllLeaves()) {
for (Material leave : Tag.LEAVES.getValues()) {
items.add(new ItemStack(leave, 8));
items.add(new ItemStack(Material.DIRT));
}
for (Material sapling : MaterialCollections.getAllSaplings()) {
for (Material sapling : Tag.SAPLINGS.getValues()) {
items.add(new ItemStack(sapling, 8));
items.add(new ItemStack(Material.DIRT));
}

View File

@ -4,6 +4,9 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.Tag;
@ -24,7 +27,6 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements RecipeDisplayItem {
@ -60,7 +62,7 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
items.add(new ItemStack(Material.TERRACOTTA, 12));
items.add(new ItemStack(Material.LAVA_BUCKET));
for (Material leave : MaterialCollections.getAllLeaves()) {
for (Material leave : Tag.LEAVES.getValues()) {
items.add(new ItemStack(leave, 16));
items.add(new ItemStack(Material.WATER_BUCKET));
}
@ -100,6 +102,7 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
};
}
@ParametersAreNonnullByDefault
private boolean craft(Player p, ItemStack input) {
for (int i = 0; i < recipes.size(); i += 2) {
ItemStack convert = recipes.get(i);
@ -116,7 +119,7 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
return false;
}
private void generateLiquid(Block block, boolean water) {
private void generateLiquid(@Nonnull Block block, boolean water) {
if (block.getType() == (water ? Material.WATER : Material.LAVA)) {
addLiquidLevel(block, water);
}
@ -126,11 +129,11 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
block.getWorld().playSound(block.getLocation(), Sound.BLOCK_LAVA_EXTINGUISH, 1F, 1F);
}
else {
Slimefun.runSync(() -> placeLiquid(block, water), 50L);
SlimefunPlugin.runSync(() -> placeLiquid(block, water), 50L);
}
}
private void addLiquidLevel(Block block, boolean water) {
private void addLiquidLevel(@Nonnull Block block, boolean water) {
int level = ((Levelled) block.getBlockData()).getLevel();
if (level > 7) {
@ -142,11 +145,11 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
}
else {
int finalLevel = 7 - level;
Slimefun.runSync(() -> runPostTask(block, water ? Sound.ENTITY_PLAYER_SPLASH : Sound.BLOCK_LAVA_POP, finalLevel), 50L);
SlimefunPlugin.runSync(() -> runPostTask(block, water ? Sound.ENTITY_PLAYER_SPLASH : Sound.BLOCK_LAVA_POP, finalLevel), 50L);
}
}
private void placeLiquid(Block block, boolean water) {
private void placeLiquid(@Nonnull Block block, boolean water) {
if (block.getType() == Material.AIR || block.getType() == Material.CAVE_AIR || block.getType() == Material.VOID_AIR) {
block.setType(water ? Material.WATER : Material.LAVA);
}
@ -167,6 +170,7 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
runPostTask(block, water ? Sound.ENTITY_PLAYER_SPLASH : Sound.BLOCK_LAVA_POP, 1);
}
@ParametersAreNonnullByDefault
private void runPostTask(Block block, Sound sound, int times) {
if (!(block.getBlockData() instanceof Levelled)) {
block.getWorld().playSound(block.getLocation(), Sound.BLOCK_METAL_BREAK, 1F, 1F);
@ -180,7 +184,7 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
block.setBlockData(le, false);
if (times < 8) {
Slimefun.runSync(() -> runPostTask(block, sound, times + 1), 50L);
SlimefunPlugin.runSync(() -> runPostTask(block, sound, times + 1), 50L);
}
else {
block.getWorld().playSound(block.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F);

View File

@ -3,6 +3,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.blocks;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
@ -54,7 +55,7 @@ public class InfusedHopper extends SimpleSlimefunItem<BlockTicker> {
}
if (sound && !silent.getValue().booleanValue()) {
b.getWorld().playSound(b.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1F, 2F);
b.getWorld().playSound(b.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, SoundCategory.BLOCKS, 1F, 2F);
}
}

View File

@ -83,7 +83,7 @@ abstract class AbstractCargoNode extends SlimefunItem {
menu.addMenuClickHandler(slotPrev, (p, slot, item, action) -> {
int newChannel = channel - 1;
if (channel < 0) {
if (newChannel < 0) {
if (isChestTerminalInstalled) {
newChannel = 16;
}

View File

@ -10,6 +10,8 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AGenerator;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import javax.annotation.Nonnull;
public abstract class CoalGenerator extends AGenerator {
public CoalGenerator(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
@ -22,21 +24,62 @@ public abstract class CoalGenerator extends AGenerator {
registerFuel(new MachineFuel(12, new ItemStack(Material.BLAZE_ROD)));
registerFuel(new MachineFuel(20, new ItemStack(Material.DRIED_KELP_BLOCK)));
// Boats
for (Material mat : Tag.ITEMS_BOATS.getValues()) {
registerFuel(new MachineFuel(5, new ItemStack(mat)));
}
// Coal & Charcoal
registerFuel(new MachineFuel(8, new ItemStack(Material.COAL)));
registerFuel(new MachineFuel(8, new ItemStack(Material.CHARCOAL)));
// Logs
for (Material mat : Tag.LOGS.getValues()) {
registerFuel(new MachineFuel(2, new ItemStack(mat)));
registerFuel(new MachineFuel(4, new ItemStack(mat)));
}
// Wooden Planks
for (Material mat : Tag.PLANKS.getValues()) {
registerFuel(new MachineFuel(1, new ItemStack(mat)));
}
// Wooden Slabs
for (Material mat : Tag.WOODEN_SLABS.getValues()) {
registerFuel(new MachineFuel(1, new ItemStack(mat)));
}
// Wooden Buttons
for (Material mat : Tag.WOODEN_BUTTONS.getValues()) {
registerFuel(new MachineFuel(1, new ItemStack(mat)));
}
// Wooden Fences
for (Material mat : Tag.WOODEN_FENCES.getValues()) {
registerFuel(new MachineFuel(1, new ItemStack(mat)));
}
// wooden Trapdoors
for (Material mat : Tag.WOODEN_TRAPDOORS.getValues()) {
registerFuel(new MachineFuel(3, new ItemStack(mat)));
}
// Wooden Pressure Plates
for (Material mat : Tag.WOODEN_PRESSURE_PLATES.getValues()) {
registerFuel(new MachineFuel(2, new ItemStack(mat)));
}
// Wooden Doors
for (Material mat : Tag.WOODEN_DOORS.getValues()) {
registerFuel(new MachineFuel(2, new ItemStack(mat)));
}
// Signs
for (Material mat : Tag.SIGNS.getValues()) {
registerFuel(new MachineFuel(2, new ItemStack(mat)));
}
}
@Nonnull
@Override
public ItemStack getProgressBar() {
return new ItemStack(Material.FLINT_AND_STEEL);

View File

@ -28,7 +28,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
@ -206,7 +205,7 @@ public abstract class AbstractEntityAssembler<T extends Entity> extends SimpleSl
removeCharge(b.getLocation(), getEnergyConsumption());
double offset = Double.parseDouble(BlockStorage.getLocationInfo(b.getLocation(), KEY_OFFSET));
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
Location loc = new Location(b.getWorld(), b.getX() + 0.5D, b.getY() + offset, b.getZ() + 0.5D);
spawnEntity(loc);

View File

@ -13,11 +13,11 @@ import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.holograms.ReactorHologram;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
@ -43,7 +43,7 @@ public abstract class NetherStarReactor extends Reactor {
@Override
public void extraTick(@Nonnull Location l) {
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
ArmorStand hologram = ReactorHologram.getArmorStand(l, true);
for (Entity entity : hologram.getNearbyEntities(5, 5, 5)) {
if (entity instanceof LivingEntity && entity.isValid()) {

View File

@ -21,6 +21,7 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.api.events.AsyncReactorProcessCompleteEvent;
import io.github.thebusybiscuit.slimefun4.api.events.ReactorExplodeEvent;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@ -37,7 +38,6 @@ import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AGenerator;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
@ -332,7 +332,7 @@ public abstract class Reactor extends AbstractEnergyProvider {
boolean explosion = explosionsQueue.contains(l);
if (explosion) {
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
ReactorExplodeEvent event = new ReactorExplodeEvent(l, Reactor.this);
Bukkit.getPluginManager().callEvent(event);
@ -349,7 +349,7 @@ public abstract class Reactor extends AbstractEnergyProvider {
}
private void checkForWaterBlocks(Location l) {
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
// We will pick a surrounding block at random and see if this is water.
// If it isn't, then we will make it explode.
int index = ThreadLocalRandom.current().nextInt(WATER_BLOCKS.length);
@ -376,6 +376,8 @@ public abstract class Reactor extends AbstractEnergyProvider {
}
}
Bukkit.getPluginManager().callEvent(new AsyncReactorProcessCompleteEvent(l, Reactor.this, getProcessing(l)));
progress.remove(l);
processing.remove(l);
}

View File

@ -12,6 +12,7 @@ import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemConsumptionHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.Cooler;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.CoolerListener;
@ -19,7 +20,6 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
@ -81,18 +81,18 @@ public class Juice extends SimpleSlimefunItem<ItemConsumptionHandler> {
private void removeGlassBottle(Player p, ItemStack item) {
if (SlimefunUtils.isItemSimilar(item, p.getInventory().getItemInMainHand(), true)) {
if (p.getInventory().getItemInMainHand().getAmount() == 1) {
Slimefun.runSync(() -> p.getEquipment().getItemInMainHand().setAmount(0));
SlimefunPlugin.runSync(() -> p.getEquipment().getItemInMainHand().setAmount(0));
}
else {
Slimefun.runSync(() -> p.getInventory().removeItem(new ItemStack(Material.GLASS_BOTTLE, 1)));
SlimefunPlugin.runSync(() -> p.getInventory().removeItem(new ItemStack(Material.GLASS_BOTTLE, 1)));
}
}
else if (SlimefunUtils.isItemSimilar(item, p.getInventory().getItemInOffHand(), true)) {
if (p.getInventory().getItemInOffHand().getAmount() == 1) {
Slimefun.runSync(() -> p.getEquipment().getItemInOffHand().setAmount(0));
SlimefunPlugin.runSync(() -> p.getEquipment().getItemInOffHand().setAmount(0));
}
else {
Slimefun.runSync(() -> p.getInventory().removeItem(new ItemStack(Material.GLASS_BOTTLE, 1)));
SlimefunPlugin.runSync(() -> p.getInventory().removeItem(new ItemStack(Material.GLASS_BOTTLE, 1)));
}
}
}

View File

@ -5,10 +5,10 @@ import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemConsumptionHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
@ -27,7 +27,7 @@ public class MonsterJerky extends SimpleSlimefunItem<ItemConsumptionHandler> {
@Override
public ItemConsumptionHandler getItemHandler() {
return (e, p, item) -> Slimefun.runSync(() -> {
return (e, p, item) -> SlimefunPlugin.runSync(() -> {
if (p.hasPotionEffect(PotionEffectType.HUNGER)) {
p.removePotionEffect(PotionEffectType.HUNGER);
}

View File

@ -34,7 +34,6 @@ import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class ElevatorPlate extends SimpleSlimefunItem<BlockUseHandler> {
@ -152,7 +151,7 @@ public class ElevatorPlate extends SimpleSlimefunItem<BlockUseHandler> {
@ParametersAreNonnullByDefault
private void teleport(Player player, String floorName, Block target) {
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
users.add(player.getUniqueId());
float yaw = player.getEyeLocation().getYaw() + 180;

View File

@ -67,12 +67,12 @@ public class EnchantmentRune extends SimpleSlimefunItem<ItemDropHandler> {
return (e, p, item) -> {
if (isItem(item.getItemStack())) {
if (Slimefun.hasUnlocked(p, this, true)) {
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
try {
addRandomEnchantment(p, item);
}
catch (Exception x) {
error("An Exception occured while trying to apply an Enchantment Rune", x);
error("An Exception occurred while trying to apply an Enchantment Rune", x);
}
}, 20L);
}
@ -124,7 +124,7 @@ public class EnchantmentRune extends SimpleSlimefunItem<ItemDropHandler> {
// This lightning is just an effect, it deals no damage.
l.getWorld().strikeLightningEffect(l);
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
// Being sure entities are still valid and not picked up or whatsoever.
if (rune.isValid() && item.isValid() && itemStack.getAmount() == 1) {

View File

@ -11,7 +11,10 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
import io.github.thebusybiscuit.slimefun4.core.handlers.EntityInteractHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
@ -31,10 +34,12 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
* @see EntityInteractHandler
*
*/
public class MagicalZombiePills extends SimpleSlimefunItem<EntityInteractHandler> {
public class MagicalZombiePills extends SimpleSlimefunItem<EntityInteractHandler> implements NotPlaceable {
public MagicalZombiePills(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
super(category, item, recipeType, recipe, recipeOutput);
addItemHandler(onRightClick());
}
@Override
@ -61,4 +66,12 @@ public class MagicalZombiePills extends SimpleSlimefunItem<EntityInteractHandler
};
}
/**
* This method cancels {@link PlayerRightClickEvent} to prevent placing {@link MagicalZombiePills}.
*
* @return the {@link ItemUseHandler} of this {@link SlimefunItem}
*/
public ItemUseHandler onRightClick() {
return PlayerRightClickEvent::cancel;
}
}

View File

@ -50,7 +50,7 @@ public class SoulboundRune extends SimpleSlimefunItem<ItemDropHandler> {
return true;
}
Slimefun.runSync(() -> activate(p, item), 20L);
SlimefunPlugin.runSync(() -> activate(p, item), 20L);
return true;
}
@ -76,7 +76,7 @@ public class SoulboundRune extends SimpleSlimefunItem<ItemDropHandler> {
// This lightning is just an effect, it deals no damage.
l.getWorld().strikeLightningEffect(l);
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
// Being sure entities are still valid and not picked up or whatsoever.
if (rune.isValid() && item.isValid() && itemStack.getAmount() == 1) {

View File

@ -2,6 +2,9 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.magical;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
@ -40,10 +43,12 @@ public class StormStaff extends SimpleSlimefunItem<ItemUseHandler> {
private static final NamespacedKey usageKey = new NamespacedKey(SlimefunPlugin.instance(), "stormstaff_usage");
public static final int MAX_USES = 8;
@ParametersAreNonnullByDefault
public StormStaff(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe, getCraftedOutput());
}
@Nonnull
private static ItemStack getCraftedOutput() {
ItemStack item = SlimefunItems.STAFF_STORM.clone();
ItemMeta im = item.getItemMeta();
@ -82,10 +87,11 @@ public class StormStaff extends SimpleSlimefunItem<ItemUseHandler> {
};
}
@ParametersAreNonnullByDefault
private void useItem(Player p, ItemStack item, Location loc) {
loc.getWorld().strikeLightning(loc);
if (p.getInventory().getItemInMainHand().getType() == Material.SHEARS) {
if (item.getType() == Material.SHEARS) {
return;
}
@ -98,22 +104,43 @@ public class StormStaff extends SimpleSlimefunItem<ItemUseHandler> {
}
}
ItemMeta meta = item.getItemMeta();
int usesLeft = meta.getPersistentDataContainer().getOrDefault(usageKey, PersistentDataType.INTEGER, MAX_USES);
damageItem(p, item);
}
if (usesLeft == 1) {
p.playSound(p.getLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
item.setAmount(0);
@ParametersAreNonnullByDefault
private void damageItem(Player p, ItemStack item) {
if (item.getAmount() > 1) {
item.setAmount(item.getAmount() - 1);
// Seperate one item from the stack and damage it
ItemStack seperateItem = item.clone();
seperateItem.setAmount(1);
damageItem(p, seperateItem);
// Try to give the Player the new item
if (!p.getInventory().addItem(seperateItem).isEmpty()) {
// or throw it on the ground
p.getWorld().dropItemNaturally(p.getLocation(), seperateItem);
}
}
else {
usesLeft--;
meta.getPersistentDataContainer().set(usageKey, PersistentDataType.INTEGER, usesLeft);
ItemMeta meta = item.getItemMeta();
int usesLeft = meta.getPersistentDataContainer().getOrDefault(usageKey, PersistentDataType.INTEGER, MAX_USES);
List<String> lore = meta.getLore();
lore.set(4, ChatColors.color("&e" + usesLeft + ' ' + (usesLeft > 1 ? "Uses" : "Use") + " &7left"));
meta.setLore(lore);
if (usesLeft == 1) {
p.playSound(p.getLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
item.setAmount(0);
}
else {
usesLeft--;
meta.getPersistentDataContainer().set(usageKey, PersistentDataType.INTEGER, usesLeft);
item.setItemMeta(meta);
List<String> lore = meta.getLore();
lore.set(4, ChatColors.color("&e" + usesLeft + ' ' + (usesLeft > 1 ? "Uses" : "Use") + " &7left"));
meta.setLore(lore);
item.setItemMeta(meta);
}
}
}

View File

@ -38,7 +38,7 @@ public abstract class MedicalSupply<T extends ItemHandler> extends SimpleSlimefu
if (n.hasPotionEffect(PotionEffectType.WEAKNESS)) n.removePotionEffect(PotionEffectType.WEAKNESS);
if (n.hasPotionEffect(PotionEffectType.CONFUSION)) n.removePotionEffect(PotionEffectType.CONFUSION);
if (n.hasPotionEffect(PotionEffectType.BLINDNESS)) n.removePotionEffect(PotionEffectType.BLINDNESS);
if (n.hasPotionEffect(PotionEffectType.BAD_OMEN)) n.removePotionEffect(PotionEffectType.BLINDNESS);
if (n.hasPotionEffect(PotionEffectType.BAD_OMEN)) n.removePotionEffect(PotionEffectType.BAD_OMEN);
}
/**

View File

@ -84,7 +84,7 @@ public class ArmorForge extends MultiBlockMachine {
for (int j = 0; j < 4; j++) {
int current = j;
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
if (current < 3) {
p.getWorld().playSound(p.getLocation(), Sound.BLOCK_ANVIL_USE, 1F, 2F);
}

View File

@ -21,7 +21,6 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class Compressor extends MultiBlockMachine {
@ -83,7 +82,7 @@ public class Compressor extends MultiBlockMachine {
for (int i = 0; i < 4; i++) {
int j = i;
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
if (j < 3) {
p.getWorld().playSound(p.getLocation(), j == 1 ? Sound.BLOCK_PISTON_CONTRACT : Sound.BLOCK_PISTON_EXTEND, 1F, j == 0 ? 1F : 2F);
}

View File

@ -94,7 +94,7 @@ public class MagicWorkbench extends BackpackCrafter {
private void startAnimation(Player p, Block b, Inventory inv, ItemStack output) {
for (int j = 0; j < 4; j++) {
int current = j;
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
p.getWorld().playEffect(b.getLocation(), Effect.MOBSPAWNER_FLAMES, 1);
p.getWorld().playEffect(b.getLocation(), Effect.ENDER_SIGNAL, 1);

View File

@ -53,6 +53,36 @@ public class OreCrusher extends MultiBlockMachine {
recipes.add(SlimefunItems.GOLD_4K);
recipes.add(SlimefunItems.GOLD_DUST);
recipes.add(SlimefunItems.GOLD_6K);
recipes.add(new SlimefunItemStack(SlimefunItems.GOLD_DUST, 2));
recipes.add(SlimefunItems.GOLD_8K);
recipes.add(new SlimefunItemStack(SlimefunItems.GOLD_DUST, 2));
recipes.add(SlimefunItems.GOLD_10K);
recipes.add(new SlimefunItemStack(SlimefunItems.GOLD_DUST, 3));
recipes.add(SlimefunItems.GOLD_12K);
recipes.add(new SlimefunItemStack(SlimefunItems.GOLD_DUST, 3));
recipes.add(SlimefunItems.GOLD_14K);
recipes.add(new SlimefunItemStack(SlimefunItems.GOLD_DUST, 4));
recipes.add(SlimefunItems.GOLD_16K);
recipes.add(new SlimefunItemStack(SlimefunItems.GOLD_DUST, 4));
recipes.add(SlimefunItems.GOLD_18K);
recipes.add(new SlimefunItemStack(SlimefunItems.GOLD_DUST, 5));
recipes.add(SlimefunItems.GOLD_20K);
recipes.add(new SlimefunItemStack(SlimefunItems.GOLD_DUST, 5));
recipes.add(SlimefunItems.GOLD_22K);
recipes.add(new SlimefunItemStack(SlimefunItems.GOLD_DUST, 6));
recipes.add(SlimefunItems.GOLD_24K);
recipes.add(new SlimefunItemStack(SlimefunItems.GOLD_DUST, 6));
recipes.add(new ItemStack(Material.GRAVEL));
recipes.add(new ItemStack(Material.SAND));

View File

@ -38,7 +38,7 @@ public class OreWasher extends MultiBlockMachine {
@Override
protected void registerDefaultRecipes(List<ItemStack> recipes) {
// Iron and Gold are displayed as Ore Crusher recipes, as that is their primary
// way of obtainining them. But we also wanna display them here, so we just
// way of obtaining them. But we also wanna display them here, so we just
// add these two recipes manually
recipes.add(SlimefunItems.SIFTED_ORE);
recipes.add(SlimefunItems.IRON_DUST);

View File

@ -22,7 +22,6 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class PressureChamber extends MultiBlockMachine {
@ -75,7 +74,7 @@ public class PressureChamber extends MultiBlockMachine {
for (int i = 0; i < 4; i++) {
int j = i;
Slimefun.runSync(() -> {
SlimefunPlugin.runSync(() -> {
p.getWorld().playSound(b.getLocation(), Sound.ENTITY_TNT_PRIMED, 1, 1);
p.getWorld().playEffect(b.getRelative(BlockFace.UP).getLocation(), Effect.SMOKE, 4);
p.getWorld().playEffect(b.getRelative(BlockFace.UP).getLocation(), Effect.SMOKE, 4);

View File

@ -191,7 +191,7 @@ class ActiveMiner implements Runnable {
ores++;
// Repeat the same column when we hit an ore.
Slimefun.runSync(this, 4);
SlimefunPlugin.runSync(this, 4);
return;
}
}
@ -232,7 +232,7 @@ class ActiveMiner implements Runnable {
return;
}
Slimefun.runSync(this, 5);
SlimefunPlugin.runSync(this, 5);
}
/**
@ -317,7 +317,7 @@ class ActiveMiner implements Runnable {
}
}
}
return 0;
}

View File

@ -9,6 +9,9 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit;
import org.bukkit.Effect;
import org.bukkit.GameMode;
@ -33,7 +36,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
@ -55,6 +57,7 @@ public class ClimbingPick extends SimpleSlimefunItem<ItemUseHandler> implements
private final Map<Material, Double> materialSpeeds;
private final Set<UUID> users = new HashSet<>();
@ParametersAreNonnullByDefault
public ClimbingPick(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
addItemSetting(dualWielding, damageOnUse);
@ -123,6 +126,8 @@ public class ClimbingPick extends SimpleSlimefunItem<ItemUseHandler> implements
};
}
@Nonnull
@ParametersAreNonnullByDefault
private ItemStack getOtherHandItem(Player p, EquipmentSlot hand) {
if (hand == EquipmentSlot.HAND) {
return p.getInventory().getItemInOffHand();
@ -132,6 +137,7 @@ public class ClimbingPick extends SimpleSlimefunItem<ItemUseHandler> implements
}
}
@ParametersAreNonnullByDefault
private void climb(Player p, EquipmentSlot hand, ItemStack item, Block block) {
double power = materialSpeeds.getOrDefault(block.getType(), 0.0);
@ -144,7 +150,7 @@ public class ClimbingPick extends SimpleSlimefunItem<ItemUseHandler> implements
power += efficiencyLevel * 0.1;
}
Slimefun.runSync(() -> users.remove(p.getUniqueId()), 3L);
SlimefunPlugin.runSync(() -> users.remove(p.getUniqueId()), 4L);
Vector velocity = new Vector(0, power * BASE_POWER, 0);
ClimbingPickLaunchEvent event = new ClimbingPickLaunchEvent(p, velocity, this, item, block);
Bukkit.getPluginManager().callEvent(event);
@ -162,25 +168,37 @@ public class ClimbingPick extends SimpleSlimefunItem<ItemUseHandler> implements
}
}
@ParametersAreNonnullByDefault
private void swing(Player p, Block b, EquipmentSlot hand, ItemStack item) {
if (p.getGameMode() != GameMode.CREATIVE) {
if (isDualWieldingEnabled()) {
if (ThreadLocalRandom.current().nextBoolean()) {
damageItem(p, p.getInventory().getItemInMainHand());
playAnimation(p, b, EquipmentSlot.HAND);
}
else {
damageItem(p, p.getInventory().getItemInOffHand());
playAnimation(p, b, EquipmentSlot.OFF_HAND);
}
if (isDualWieldingEnabled()) {
if (ThreadLocalRandom.current().nextBoolean()) {
damageItem(p, p.getInventory().getItemInMainHand());
playAnimation(p, b, EquipmentSlot.HAND);
}
else {
damageItem(p, item);
playAnimation(p, b, hand);
damageItem(p, p.getInventory().getItemInOffHand());
playAnimation(p, b, EquipmentSlot.OFF_HAND);
}
}
else {
damageItem(p, item);
playAnimation(p, b, hand);
}
}
@Override
public void damageItem(Player p, ItemStack item) {
if (p.getGameMode() != GameMode.CREATIVE) {
DamageableItem.super.damageItem(p, item);
}
}
@Override
public boolean isDamageable() {
return damageOnUse.getValue();
}
@ParametersAreNonnullByDefault
private void playAnimation(Player p, Block b, EquipmentSlot hand) {
MinecraftVersion version = SlimefunPlugin.getMinecraftVersion();
@ -198,11 +216,6 @@ public class ClimbingPick extends SimpleSlimefunItem<ItemUseHandler> implements
}
}
@Override
public boolean isDamageable() {
return damageOnUse.getValue();
}
@Override
public List<ItemStack> getDisplayRecipes() {
List<ItemStack> display = new ArrayList<>();

View File

@ -15,6 +15,7 @@ import io.github.thebusybiscuit.cscorelib2.collections.RandomizedSet;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.core.handlers.EntityInteractHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@ -47,6 +48,7 @@ public class GoldPan extends SimpleSlimefunItem<ItemUseHandler> implements Recip
drops.addAll(getGoldPanDrops());
addItemSetting(drops.toArray(new GoldPanDrop[0]));
addItemHandler(onEntityInteract());
}
protected Material getInput() {
@ -115,6 +117,16 @@ public class GoldPan extends SimpleSlimefunItem<ItemUseHandler> implements Recip
};
}
/**
* This method cancels {@link EntityInteractHandler} to prevent interacting {@link GoldPan}
* with entities.
*
* @return the {@link EntityInteractHandler} of this {@link SlimefunItem}
*/
public EntityInteractHandler onEntityInteract() {
return (e, item, offHand) -> e.setCancelled(true);
}
@Override
public List<ItemStack> getDisplayRecipes() {
List<ItemStack> recipes = new LinkedList<>();

View File

@ -22,12 +22,14 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class GrapplingHook extends SimpleSlimefunItem<ItemUseHandler> {
private final ItemSetting<Boolean> consumeOnUse = new ItemSetting<>("consume-on-use", true);
private final ItemSetting<Integer> despawnTicks = new ItemSetting<>("despawn-seconds", 60);
public GrapplingHook(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
addItemSetting(despawnTicks);
addItemSetting(consumeOnUse);
}
@Override
@ -35,6 +37,7 @@ public class GrapplingHook extends SimpleSlimefunItem<ItemUseHandler> {
return e -> {
Player p = e.getPlayer();
UUID uuid = p.getUniqueId();
boolean consumeOnUseValue = consumeOnUse.getValue();
if (!e.getClickedBlock().isPresent() && !SlimefunPlugin.getGrapplingHookListener().isGrappling(uuid)) {
e.cancel();
@ -47,7 +50,10 @@ public class GrapplingHook extends SimpleSlimefunItem<ItemUseHandler> {
ItemStack item = e.getItem();
if (item.getType() == Material.LEAD) {
item.setAmount(item.getAmount() - 1);
//If consume on use is enabled, the if statement below will take 1 grappling hook out of player's hand
if (consumeOnUseValue) {
item.setAmount(item.getAmount() - 1);
}
}
Vector direction = p.getEyeLocation().getDirection().multiply(2.0);
@ -63,7 +69,7 @@ public class GrapplingHook extends SimpleSlimefunItem<ItemUseHandler> {
bat.setLeashHolder(arrow);
boolean state = item.getType() != Material.SHEARS;
SlimefunPlugin.getGrapplingHookListener().addGrapplingHook(p, arrow, bat, state, despawnTicks.getValue());
SlimefunPlugin.getGrapplingHookListener().addGrapplingHook(p, arrow, bat, state, despawnTicks.getValue(), consumeOnUseValue);
}
};
}

View File

@ -1,7 +1,10 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.tools;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.inventory.CraftingInventory;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
@ -11,8 +14,16 @@ import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* The {@link PortableCrafter} is one of the oldest items in Slimefun.
* It allows a {@link Player} to open up the {@link CraftingInventory} via right click.
*
* @author TheBusyBiscuit
*
*/
public class PortableCrafter extends SimpleSlimefunItem<ItemUseHandler> implements NotPlaceable {
@ParametersAreNonnullByDefault
public PortableCrafter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
}

View File

@ -4,6 +4,9 @@ import java.text.DecimalFormat;
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
@ -34,6 +37,7 @@ public class TapeMeasure extends SimpleSlimefunItem<ItemUseHandler> implements N
private final NamespacedKey key = new NamespacedKey(SlimefunPlugin.instance(), "anchor");
private final DecimalFormat format = new DecimalFormat("##.###");
@ParametersAreNonnullByDefault
public TapeMeasure(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
}
@ -56,6 +60,7 @@ public class TapeMeasure extends SimpleSlimefunItem<ItemUseHandler> implements N
};
}
@ParametersAreNonnullByDefault
private void setAnchor(Player p, ItemStack item, Block block) {
ItemMeta meta = item.getItemMeta();
@ -74,6 +79,8 @@ public class TapeMeasure extends SimpleSlimefunItem<ItemUseHandler> implements N
}
@Nonnull
@ParametersAreNonnullByDefault
private Optional<Location> getAnchor(Player p, ItemStack item) {
ItemMeta meta = item.getItemMeta();
@ -102,6 +109,7 @@ public class TapeMeasure extends SimpleSlimefunItem<ItemUseHandler> implements N
}
}
@ParametersAreNonnullByDefault
private void measure(Player p, ItemStack item, Block block) {
Optional<Location> anchor = getAnchor(p, item);

Some files were not shown because too many files have changed in this diff Show More