Compare commits

..

14 Commits

Author SHA1 Message Date
Funnycube
09d3c06698 Add files via upload 2026-02-02 22:44:01 +11:00
Funnycube
5048328e82 Add files via upload 2026-02-02 22:42:51 +11:00
Funnycube
2e75ec023f Delete dark_mode/test 2026-02-02 22:41:09 +11:00
Funnycube
f43274c03e Add files via upload 2026-02-02 22:40:19 +11:00
Funnycube
86c98df5d2 Create test 2026-02-02 22:40:05 +11:00
PiggyPiglet
d62b6af129 yes 2026-02-02 19:37:25 +08:00
Funnycube
4ee2840a0a Update download and server usage statistics in README 2026-02-02 22:24:12 +11:00
PiggyPiglet
c52d117f12 2.12.1 dev 2026-02-02 18:28:07 +08:00
PiggyPiglet
e307aba414 2.12.0 release 2026-02-02 17:58:26 +08:00
PiggyPiglet
5ea5a18fe8 fix config option path 2026-02-02 17:43:41 +08:00
PiggyPiglet
9c1db4b48a fix newlines in ecloud command error & restrict api to bukkit platform 2026-02-02 17:29:15 +08:00
PiggyPiglet
b233c92ca1 Add warning message to failed ecloud download 2026-02-02 17:10:50 +08:00
PiggyPiglet
1b1d2e61b9 Add config option to use adventure replacer, add bracket {} support 2026-02-02 16:35:13 +08:00
PiggyPiglet
2dc5b93133 WIP custom component replacer no regex!! 2026-01-21 22:14:46 +08:00
85 changed files with 1 additions and 8251 deletions

9
.github/CODEOWNERS vendored
View File

@@ -1,9 +0,0 @@
#
# Assigns extendedclip and PiggyPiglet for any PR unless a check below matches.
#
* @PiggyPiglet @darbyjack
#
# Assigns Andre601 to any PR that targets the wiki folder.
#
*.md @Andre601

View File

@@ -1,67 +0,0 @@
[issue]: https://github.com/PlaceholderAPI/PlaceholderAPI/issues/new
[discord]: https://helpch.at/discord
[code of conduct]: https://github.com/PlaceholderAPI/PlaceholderAPI/blob/master/CODE_OF_CONDUCT.md
[wiki]: https://github.com/PlaceholderAPI/PlaceholderAPI/blob/wiki
[master]: https://github.com/PlaceholderAPI/PlaceholderAPI/tree/master
[docs-wiki]: https://github.com/PlaceholderAPI/PlaceholderAPI/tree/docs/wiki
[style]: https://github.com/PlaceholderAPI/PlaceholderAPI/tree/master/config/style
# Contributing Guidelines
We welcome everyone to contribute towards the PlaceholderAPI Project, but doing so will require you to follow specific rules to keep a consistent and welcoming way of contributing.
If you have any questions about contributions towards the project, feel free to contact us on our [Discord Server][discord].
## Issues
Like any other project can you encounter bugs or a feature is missing for you in the plugin.
For that, you can open an [issue] to report a bug, or suggest a new feature to be added.
When doing so, make sure you follow rules below:
### Follow the template
We have issue templates to help us get the required information more easily. Please follow the provided template when either filing a bug report or feature request.
Your issue may be closed without warning for not following the template.
### Use the latest version
When it comes to bug reports should you always check first, that you're using the latest release of PlaceholderAPI.
Often the bug you've encountered, is fixed in a newer version.
The same rules apply when making a feature request.
### No duplicate issue
Make sure that there aren't any existing issues relating to the problem, which are still open, or are closed with a solution/explanation.
Opening a separate issue for a bug report or feature request, that already exists on the issue tracker only slows down the process of fixing the bug or implementing the feature.
If an issue with the bug or feature you want to report/suggest exists, comment on it with your info (bug reports) or give it a :thumbsup: (Feature Request) to show that this is important for you.
### Issue isn't caused by external source
PlaceholderAPI provides a feature to have expansions (separate jar files) for placeholders. This gives it a possability that an issue you encounter is caused by said expansions or a separate plugin that uses those expansions.
In those cases should you report the issue to the issue tracker of the expansion or plugin.
## Pull requests
As an open source project we are welcoming all contributions to improve PlaceholderAPI, being it changes to its code, or contributions to its documentation such as the [Wiki] or the Javadocs.
> [!IMPORTANT]
> When contributing, make sure to both base of and target the mentioned branch. Pull requests targeting the wrong branch may get closed without a warning.
### Code contributions
> **Source and Target Branch:** [`master`][master]
When contributing towards the code of PlaceholderAPI, be it new features or just bug fixes, your changes should follow the general code styling used in the project.
You can find the necessary files in the [`config/style`][style] directory of this repository.
### Javadocs contributions
> **Source and Target Branch:** [`master`][master]*
Javadocs changes should usually be combined with [code contributions](#code-contributions) when possible, but if not, make sure the changes are significant enough to warrant a new build on our CI server.
\*This branch may change in the future.
### Wiki contributions
> **Source and Target Branch:** [`wiki`][docs-wiki]
The Wiki of PlaceholderAPI is located on its own dedicated branch, hosting all the assets and files that get used to create it through the usage of GitHub Actions and GitHub Pages.
We welcome contributions that update outdated information, add new expansions/plugins supporting PlaceholderAPI or even correct spelling mistakes and typos.
## Code of Conduct
We have a [Code of Conduct] to maintain a welcoming atmosphere in this project.
If your contributions go against the Code of Conduct, linked above, we reserve the right to deny or revert your contributions.

View File

@@ -1,103 +0,0 @@
name: Bug Report
description: Found a Bug about PlaceholderAPI? Use this template to report it!
labels:
- "Type: Issue (Unconfirmed)"
body:
- type: markdown
attributes:
value: |-
Thank you for taking your time and opening a Bug Report.
In order for us to process this Bug Report as fast and efficient as possible do we ask you to read the form carefully and provide any requested information.
Required fields are marked with an asterisk symbol (`*`)
Also, always make sure to use the latest Release from [Spigot](https://www.spigotmc.org/resources/6245/) or the latest Development Build from our [Jenkins Server](http://ci.extendedclip.com/job/PlaceholderAPI/) to make sure that your issue isn't already fixed.
**DO NOT REPORT ISSUES WITH EXPANSIONS AND/OR PLACEHOLDERS. USE THE APPROPRIATE ISSUE TRACKER FOR THOSE!**
- type: checkboxes
attributes:
label: Confirmation
description: Please make sure to have followed the following checks.
options:
- label: My issue isn't already found on the Issue tracker.
required: true
- label: My issue is about **PlaceholderAPI** and not any expansion or external plugin
required: true
- label: The issue isn't already fixed in a Spigot Release or Development Build.
required: true
- label: The [Common Issues](https://github.com/PlaceholderAPI/PlaceholderAPI/wiki/Common-Issues) page doesn't mention this issue.
required: true
- type: dropdown
attributes:
label: "Type"
description: |-
What kind of Bug do you encounter?
- `Plugin Bug`: PlaceholderAPI doesn't startup properly.
- `API Bug`: A method you use didn't work or has an unexpected result.
- `Plugin/Server Incompatability`: PlaceholderAPI either doesn't support a specific Server Type/Version or has conflicts with another plugin.
multiple: false
options:
- "Plugin Bug"
- "API Bug"
- "Plugin/Server Incompatability"
validations:
required: true
- type: textarea
attributes:
label: "What happens?"
description: "What bug are you encountering? Try to explain it as detailed as possible."
placeholder: "PlaceholderAPI does this when I do that..."
validations:
required: true
- type: textarea
attributes:
label: "Expected Behaviour"
description: "What behaviour did you expect from PlaceholderAPI?"
placeholder: "PlaceholderAPI should actually do..."
validations:
required: true
- type: textarea
attributes:
label: "How to Reproduce"
description: |-
List the steps on how to reproduce this Bug.
Post any Code-examples in the `Additional Information` field below when you selected `API Bug`.
placeholder: |-
1. Do this
2. ...
3. Profit!
validations:
required: true
- type: input
id: "dump"
attributes:
label: "`/papi dump` Output"
description: |-
Please execute the `/papi dump` command and provide the generated URL from it.
If you can't execute the command (i.e. PlaceholderAPI doesn't start up) can you put N/A here and mention the issue in the `Additional Information` field.
placeholder: "https://paste.helpch.at/dump.log"
validations:
required: true
- type: input
id: "console"
attributes:
label: "Console Log"
description: |-
Get the latest content of your `latest.log` file an upload it to https://paste.helpch.at
Take the generated URL and paste it into this field.
placeholder: "https://paste.helpch.at/latest.log"
- type: input
id: "error"
attributes:
label: "Errors"
description: |-
Upload any errors you find to https://paste.helpch.at and post the link in the field below.
placeholder: "https://paste.helpch.at/error.log"
- type: textarea
attributes:
label: "Additional Info"
description: |-
Add any extra info you think is nessesary for this Bug report.
- If you selected `API Bug` will you need to include code-examples here to reproduce the issue.
- If you selected `Plugin/Server Incompatability` should you include extra Server info such as a Timings or Spark-Report or info about the plugin in question.
placeholder: "Put any extra info you like into this field..."

View File

@@ -1,17 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: HelpChat Discord
url: https://discordapp.com/invite/0utOOIYX82aImw7h
about: Please join our Discord for faster support.
- name: Wiki
url: https://github.com/PlaceholderAPI/PlaceholderAPI/wiki
about: The Wiki of PlaceholderAPI.
- name: Hastebin
url: https://paste.helpch.at
about: Use our Hastebin-site for sharing errors and configuration files.
- name: Update Wiki
url: https://github.com/PlaceholderAPI/PlaceholderAPI/pulls
about: Please make a Pull request towards the "wiki" folder to update the wiki.
- name: Questions
url: https://github.com/PlaceholderAPI/PlaceholderAPI/discussions
about: If you have any questions, ask them in our Discussions Page.

View File

@@ -1,62 +0,0 @@
name: Feature Request
description: Suggest a new Feature for PlaceholderAPI
labels:
- "Type: Enhancement"
body:
- type: markdown
attributes:
value: |-
Thank you for taking the time in creating this Feature Request.
In order to process your feature request as fast and efficiently as possible do we ask you to fill out any required fields (Indicated with a red asterisk (`*`)) with the requested information.
If you have any further questions should you either [join our Discord Server](https://helpch.at/discord) or [ask in our Discussions](https://github.com/PlaceholderAPI/PlaceholderAPI/discussions).
- type: checkboxes
attributes:
label: Confirmation
description: Please make sure to have followed the following checks.
options:
- label: I checked the Issues and Pull request tab for any existing issues or PRs.
required: true
- label: My Feature Request is for **PlaceholderAPI** and not any expansion or other plugin.
required: true
- type: dropdown
attributes:
label: "Type"
description: "What type is your Suggestion? Select all that match."
multiple: true
options:
- "New API feature"
- "New config option"
- "Minor Code improvement (Won't affect Servers)"
- "Major Code improvement (Will affect Servers)"
validations:
required: true
- type: textarea
attributes:
label: "Description"
description: |-
Give a detailed explanation about your Feature request and why it would be beneficial for PlaceholderAPI.
Just saying "It's cool!" or "I need it" don't count as valid reasons. It needs to have a clear benefit for **other** players too.
validations:
required: true
- type: textarea
attributes:
label: "Code Example"
description: |-
Do you have any Code Snippets that you want to share with us? Paste it here!
Note that the input will automatically be rendered as Java code, so you won't need to put it into a code block yourself.
render: java
- type: input
attributes:
label: "Jar file"
description: |-
If you already have a PlaceholderAPI Jar with the requested changes would we love to get a download link for it.
If you don't have a download link can you leave this field empty or provide "N/A" as a response.
placeholder: "https://cdn.discordapp.com/..."
- type: textarea
attributes:
label: "Additional Information"
description: |-
Add any extra info you think is nessesary for this Feature request.
- When you selected `Major Code improvement (Will affect Servers)` should you mention what will break when people update.
placeholder: "Put any extra info you like into this field..."

View File

@@ -1,28 +0,0 @@
<!--
### Please read ###
Please make sure you checked the following:
- You checked the Pull requests page for any upcoming changes.
- You documented any public code that the end-user might use.
- You followed the contributing file (https://github.com/PlaceholderAPI/PlaceholderAPI/tree/master/.github/CONTRIBUTING.md).
-->
## Pull Request
### Type
<!--
Please select the right one, by changing the [ ] to [x]
-->
- [ ] Internal change (Doesn't affect end-user).
- [ ] External change (Does affect end-user).
- [ ] Wiki (Changes towards the [Wiki]).
- [ ] Other: __________ <!-- Use this if none of the above matches your request -->
### Description
<!-- What does your Pull request change? -->
Closes N/A <!-- If your PR is based on an issue, change "N/A" to the issue ID (#id) -->
<!-- DO NOT ALTER ANYTHING BELOW THIS LINE! -->
[Wiki]: https://wiki.placeholderapi.com

View File

@@ -1,145 +0,0 @@
comment:
footer: "\
----\n\n
> [!NOTE]\n
> *This is an automated response created by a **GitHub Action***<br>
> *Mentioning the bot won't have any effect!*
"
labels:
- name: 'Type: Issue (Expansion)'
labeled:
issue:
body: |-
Hello @{{ issue.user.login }},
The issue you encountered is caused by an Expansion and not PlaceholderAPI itself.
This issue-tracker is reserved for Bug reports and feature requests towards PlaceholderAPI.
Please report this issue to the Expansion's main issue-tracker.
A list of known Expansion repositories and their issue trackers can be found [here](https://github.com/PlaceholderAPI/PlaceholderAPI/discussions/510#discussion-63812).
action: close
- name: 'Type: Duplicate'
labeled:
issue:
body: |-
Your issue is already known and a separate issue with the exact same report/feature request already exist.
Please comment on the already existing issue with your information instead of opening your own.
action: close
- name: 'Problem: More info required'
labeled:
issue:
body: |-
Hello @{{ issue.user.login }},
Your issue unfortunately lacks certain information that we require in order to help you with your issue.
Please make sure you provide the following information:
- Currently used Versions of your server (`/version`) and PlaceholderAPI (`/version PlaceholderAPI`)
- Currently installed Expansions (`/papi list`)
- Currently installed Plugins (`/pl`)
- Any additional information requested by users in this issue.
The easiest way to provide those information is through the `/papi dump` command which posts the required information to https://paste.helpch.at and gives a URL to share.
unlabeled:
issue:
body: |-
Thank you for providing additional information.
We will take a look at the issue you encounter and come back to you with a possible solution.
- name: 'Type: Invalid'
labeled:
issue:
body: |-
Your issue has beeen marked as invalid.
This means that it either doesn't follow any provided template, or isn't related to PlaceholderAPI.
Please make sure to use one of the issue templates and provide the requested information.
Currently available Templates are:
- [Bug Report](https://github.com/PlaceholderAPI/PlaceholderAPI/issues/new?labels=Type%3A+Issue+%28Unconfirmed%29&template=bug_report.yml)
- [Feature Request](https://github.com/PlaceholderAPI/PlaceholderAPI/issues/new?labels=Type%3A+Enhancement&template=feature_request.yml)
If you want changes to be made towards the Wiki, would we encourage you to [Make a Pull request](https://github.com/PlaceholderAPI/PlaceholderAPI/pulls).
You can find more information about this process on the [Wiki's Readme](https://github.com/PlaceholderAPI/PlaceholderAPI/blob/wiki/README.md).
It is recommended to [join our Discord Server](https://helpch.at/discord) as you often receive a faster response compared to the issue tracker here.
Questions about PlaceholderAPI should be asked in our [Discussions](https://github.com/PlaceholderAPI/PlaceholderAPI/discussions).
action: close
pr:
body: |-
Your Pull request has been marked as **invalid**.
This means that it doesn't follow our [Contributing Guidelines](https://github.com/PlaceholderAPI/PlaceholderAPI/blob/master/.github/CONTRIBUTING.md).
Here is a small summary of what you should know:
- Pull requests for PlaceholderAPI should target the `master` branch.
- Pull requests for the Wiki should target the `wiki` branch.
Don't hesitate to ask us any questions.
action: close
- name: 'Type: Invalid (Wiki)'
labeled:
pr:
body: |-
Your Wiki Pull request has been marked as **invalid**.
Pull requests targeting the Wiki need to target the `wiki` branch.
More information can be found on the [Wiki README](https://github.com/PlaceholderAPI/PlaceholderAPI/blob/wiki/README.md).
action: close
- name: 'Target: Wiki'
labeled:
issue:
body: |-
Hello @{{ issue.user.login }},
Thank you for reaching out to us about the wiki.
We would like to inform you, that you are able to directly commit your changes to the wiki through a Pull request.
When doing so, make sure you follow these steps:
- The Pull request is based on AND targets the [`wiki`](https://github.com/PlaceholderAPI/PlaceholderAPI/tree/wiki) branch of the Repository.
- You followed the general Styling Guidelines mentioned in the wiki's [README](https://github.com/PlaceholderAPI/PlaceholderAPI/blob/wiki/README.md) file.
If you have any questions about submitting a PR for the wiki or have any other questions don't hesitate to ask us about it.
- name: 'Type: Not a bug'
labeled:
issue:
body: |-
The issue you encounter is not considered a bug and rather an intentional behaviour of PlaceholderAPI and/or one of its expansions.
If you still believe that it is a bug, provide more information and a maintainer of this repository may look at it more closely.
Before providing more info, always make sure to use the latest version of PlaceholderAPI, as the issue you encounter might already be fixed in a newer version.
Optionally can you also try out [development builds](https://ci.extendedclip.com/job/PlaceholderAPI/) and see if the issue was fixed there.
action: close
unlabeled:
issue:
body: After further investigation is the issue you encounter indeed considered a bug and we will try to fix it as soon as possible.
action: open
- name: 'Status: Inactive'
labeled:
issue:
body: |-
The issue has been marked as **inactive** which means it didn't recieve any responses from the Author ({{ issue.user.login }}) for a long period of time.
To keep the issue-tracker clean and up to date do we close issues that haven't received any responses for a long time.
If you're the Author of this issue and the reported problem is still present, make sure to respond with additional info to this issue, so that we can reopen it.
**Do not create a new issue for the same problem!**
action: close
unlabeled:
issue:
body: The issue received a response from the Author who confirms this to still be prominent and has therefore been reopened.
action: open
- name: 'Type: Question'
labeled:
issue:
body: |-
Hello @{{ issue.user.login }},
Thank you for reaching out to us for getting Support with PlaceholderAPI.
We would like to inform you, that we have [Discussions](https://github.com/PlaceholderAPI/PlaceholderAPI/discussions) that you can use for asking questions.
Just head over there and click the "New discussion" button to create a new post.
Remember to first read the [READ ME](https://github.com/PlaceholderAPI/PlaceholderAPI/discussions/507) post to not face any issues.
For questions do we recommend to use the [(2) Support](https://github.com/PlaceholderAPI/PlaceholderAPI/discussions/categories/-2-support) category.
You can also use the Discussion to submit Feature requests (Feature requests through issues are still accepted tho).

24
.github/release.yml vendored
View File

@@ -1,24 +0,0 @@
#
# This file is used to automatically draft new release changelogs in GitHub.
# Read more: https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes
#
changelog:
exclude:
labels:
- 'Action: No Changelog'
categories:
- title: 'Breaking Changes'
labels:
- 'Type: Breaking'
- title: 'Additions'
labels:
- 'Type: New Feature'
- title: 'Changes'
labels:
- 'Type: Enhancement'
- title: 'Fixes'
labels:
- 'Type: Bugfix'
- title: 'Other changes'
labels:
- '*' # Catch every other PR not labeled with an "exclude" label.

View File

@@ -1,25 +0,0 @@
name: Comment
on:
issues:
types:
- labeled
- unlabeled
pull_request_target:
types:
- labeled
- unlabeled
jobs:
give_comment:
if: github.event.issue.state == 'open' || github.event.pull_request.state == 'open'
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
with:
ref: master
- name: Send Issue/Pull request comment
uses: peaceiris/actions-label-commenter@v1.8.2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,33 +0,0 @@
name: "Test compiling against Java 8, 11 and 16"
on:
pull_request:
branches:
- development
paths:
- "../../spigot/**"
- "../../paper/**"
- "build.gradle.kts"
- "settings.gradle.kts"
jobs:
testBuilds:
strategy:
fail-fast: false
max-parallel: 4
matrix:
java-version: [8, 11, 16]
name: "Compile jar against ${{ matrix.java-version }}"
runs-on: ubuntu-latest
steps:
- name: "Checkout Code"
uses: actions/checkout@v2
- name: "Prepare Java ${{ matrix.java-version }}"
uses: actions/setup-java@v2
with:
distribution: "adopt"
java-version: "${{ matrix.java-version }}"
- name: "Make build.gradle executable"
run: "chmod +x gradlew"
- name: "Build jar with Java ${{ matrix.java-version }}"
run: "./gradlew shadowJar"

4
.gitignore vendored
View File

@@ -1,8 +1,6 @@
.idea/ .idea/
.gradle/ .gradle/
.vscode/
server/ server/
build/ build/
out/ out/
*.iml *.iml
libs/

View File

@@ -1,51 +0,0 @@
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
[discord]: https://helpch.at/discord
## Code of Conduct
### Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
### Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
### Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
### Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
### Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team on their [discord server][discord]. All
complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
### Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]

674
LICENSE
View File

@@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@@ -1,54 +0,0 @@
[issues]: https://github.com/PlaceholderAPI/PlaceholderAPI/issues
[licenseImg]: https://img.shields.io/github/license/PlaceholderAPI/PlaceholderAPI.svg
[license]: https://github.com/PlaceholderAPI/PlaceholderAPI/blob/master/LICENSE
[releaseImg]: https://img.shields.io/github/release/PlaceholderAPI/PlaceholderAPI.svg?label=github%20release
[release]: https://github.com/PlaceholderAPI/PlaceholderAPI/releases/latest
[discord]: https://helpch.at/discord
[spigot]: https://www.spigotmc.org/resources/6245/
[hangar]: https://hangar.papermc.io/HelpChat/PlaceholderAPI
[modrinth]: https://modrinth.com/plugin/placeholderapi
[Expansions cloud]: https://ecloud.placeholderapi.com
[placeholder list]: https://helpch.at/placeholders
[statistics]: https://bstats.org/plugin/bukkit/PlaceholderAPI
[ci]: http://ci.extendedclip.com/job/PlaceholderAPI/
[ciImg]: http://ci.extendedclip.com/buildStatus/icon?job=PlaceholderAPI
[APIversionImg]: https://repo.extendedclip.com/api/badge/latest/releases/me/clip/placeholderapi?name=API%20Version
[logo]: https://wiki.placeholderapi.com/assets/img/papi-logo.png
[contributing]: https://github.com/PlaceholderAPI/PlaceholderAPI/blob/master/.github/CONTRIBUTING.md
[placeholderexpansion]: https://wiki.placeholderapi.com/developers/creating-a-placeholderexpansion/
<!-- The stuff above isn't visible in the readme -->
[![logo]][spigot]
[![ciImg]][ci] [![releaseImg]][release] ![APIversionImg] [![licenseImg]][license]
# Information
[PlaceholderAPI][spigot] is a plugin for Spigot servers that allows server owners to display information from various plugins with a uniform format.
Support for specific plugins are provided either by the plugin itself or through expansions. The expansions may be downloaded in-game through the PAPI Expansion Cloud. There are currently over 240+ expansions that support a wide variety of plugins, such as Essentials, Factions, LuckPerms, and Vault.
PlaceholderAPI has been downloaded over 1,700,000 times on Spigot and has been used concurrently on over 45,000 servers, which makes it a must-have for a server of any type or scale.
## Contribute
If you would like to contribute towards PlaceholderAPI should you take a look at our [Contributing file][contributing] for the ins and outs on how you can do that and what you need to keep in mind.
## Create an Expansion
If you would like to create your own Placeholder Expansion for PlaceholderAPI, take a look at our [Wiki][placeholderexpansion] which contains a detailed tutorial on how you can achieve this.
## Support
- [Issue Tracker][issues]
- [Discord Support][discord]
## Quick Links
- [CI Server][ci]
- [Expansions Cloud]
- [Placeholder List]
- [Spigot Page][spigot]
- [Hangar Page][hangar]
- [Modrinth Page][modrinth]
- [Plugin Statistics][statistics]

View File

@@ -1,80 +0,0 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins {
`java-library`
`maven-publish`
id("com.gradleup.shadow") version "9.3.1"
}
group = "at.helpch"
version = "1.0.5-DEV-${System.getProperty("BUILD_NUMBER")}"
description = "An awesome placeholder provider!"
repositories {
mavenCentral()
mavenLocal()
maven {
url = uri("https://repo.codemc.io/repository/hytale/")
}
}
dependencies {
implementation("org.yaml:snakeyaml:2.5")
compileOnly("com.hypixel.hytale:Server:2026.01.17-4b0f30090")
compileOnlyApi("org.jetbrains:annotations:23.0.0")
}
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
withJavadocJar()
withSourcesJar()
disableAutoTargetJvm()
}
val javaComponent: SoftwareComponent = components["java"]
tasks {
processResources {
eachFile { expand("version" to project.version) }
}
withType<ShadowJar> {
archiveClassifier.set("hytale")
relocate("org.yaml.snakeyaml", "at.helpch.placeholderapi.libs.yaml")
exclude("META-INF/versions/**")
}
publishing {
publications {
create<MavenPublication>("maven") {
artifactId = "placeholderapi-hytale"
from(javaComponent)
}
}
repositories {
maven {
if ("-DEV" in version.toString()) {
url = uri("https://repo.extendedclip.com/snapshots")
} else {
url = uri("https://repo.extendedclip.com/releases")
}
credentials {
username = System.getenv("JENKINS_USER")
password = System.getenv("JENKINS_PASS")
}
}
}
}
publish.get().setDependsOn(listOf(build.get()))
}

View File

@@ -1,7 +0,0 @@
Copyright (c) 2018-2026 Peter Blood
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,17 +0,0 @@
This file is part of PlaceholderAPI
PlaceholderAPI
Copyright (c) 2015 - ${year} PlaceholderAPI Team
PlaceholderAPI free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PlaceholderAPI is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

View File

@@ -1,569 +0,0 @@
<code_scheme name="DaddyStyle" version="173">
<option name="OTHER_INDENT_OPTIONS">
<value>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</value>
</option>
<option name="RIGHT_MARGIN" value="100" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
<option name="LAYOUT_SETTINGS">
<value>
<option name="INSERT_BLANK_LINE_BEFORE_TAG" value="false" />
</value>
</option>
</AndroidXmlCodeStyleSettings>
<JSCodeStyleSettings version="0">
<option name="INDENT_CHAINED_CALLS" value="false" />
</JSCodeStyleSettings>
<JavaCodeStyleSettings>
<option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
</value>
</option>
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
<option name="JD_P_AT_EMPTY_LINES" value="false" />
<option name="JD_KEEP_EMPTY_PARAMETER" value="false" />
<option name="JD_KEEP_EMPTY_EXCEPTION" value="false" />
<option name="JD_KEEP_EMPTY_RETURN" value="false" />
</JavaCodeStyleSettings>
<Objective-C>
<option name="INDENT_NAMESPACE_MEMBERS" value="0" />
<option name="INDENT_C_STRUCT_MEMBERS" value="2" />
<option name="INDENT_CLASS_MEMBERS" value="2" />
<option name="INDENT_VISIBILITY_KEYWORDS" value="1" />
<option name="INDENT_INSIDE_CODE_BLOCK" value="2" />
<option name="KEEP_STRUCTURES_IN_ONE_LINE" value="true" />
<option name="FUNCTION_PARAMETERS_WRAP" value="5" />
<option name="FUNCTION_CALL_ARGUMENTS_WRAP" value="5" />
<option name="TEMPLATE_CALL_ARGUMENTS_WRAP" value="5" />
<option name="TEMPLATE_CALL_ARGUMENTS_ALIGN_MULTILINE" value="true" />
<option name="ALIGN_INIT_LIST_IN_COLUMNS" value="false" />
<option name="SPACE_BEFORE_SUPERCLASS_COLON" value="false" />
</Objective-C>
<Objective-C-extensions>
<option name="GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES" value="ASK" />
<option name="RELEASE_STYLE" value="IVAR" />
<option name="TYPE_QUALIFIERS_PLACEMENT" value="BEFORE" />
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cc" header="h" />
<pair source="c" header="h" />
</extensions>
</Objective-C-extensions>
<Python>
<option name="USE_CONTINUATION_INDENT_FOR_ARGUMENTS" value="true" />
</Python>
<TypeScriptCodeStyleSettings version="0">
<option name="INDENT_CHAINED_CALLS" value="false" />
</TypeScriptCodeStyleSettings>
<XML>
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="CSS">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="ECMA Script Level 4">
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
</codeStyleSettings>
<codeStyleSettings language="HTML">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_RESOURCES" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
<option name="KEEP_SIMPLE_LAMBDAS_IN_ONE_LINE" value="true" />
<option name="KEEP_SIMPLE_CLASSES_IN_ONE_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="WRAP_COMMENTS" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JSON">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="RIGHT_MARGIN" value="80" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="ObjectiveC">
<option name="RIGHT_MARGIN" value="80" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
<option name="BLANK_LINES_BEFORE_IMPORTS" value="0" />
<option name="BLANK_LINES_AFTER_IMPORTS" value="0" />
<option name="BLANK_LINES_AROUND_CLASS" value="0" />
<option name="BLANK_LINES_AROUND_METHOD" value="0" />
<option name="BLANK_LINES_AROUND_METHOD_IN_INTERFACE" value="0" />
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="false" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="PROTO">
<option name="RIGHT_MARGIN" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="Python">
<option name="RIGHT_MARGIN" value="80" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="SASS">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="SCSS">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:.*Style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_weight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_margin</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginTop</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginBottom</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginStart</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginEnd</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginLeft</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginRight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:padding</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingTop</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingBottom</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingStart</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingEnd</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingLeft</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingRight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res-auto</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/tools</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="protobuf">
<option name="RIGHT_MARGIN" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>

BIN
dark_mode/ABOUT.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
dark_mode/COMMANDS.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
dark_mode/CONFIG.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
dark_mode/HEADER.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
dark_mode/PERMISSIONS.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
dark_mode/Placeholders.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
dark_mode/Placeholders2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
dark_mode/STEPS.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
dark_mode/eCloud.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
dark_mode/wiki.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

View File

@@ -1,6 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

244
gradlew vendored
View File

@@ -1,244 +0,0 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

92
gradlew.bat vendored
View File

@@ -1,92 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -1 +0,0 @@
rootProject.name = "PlaceholderAPI"

View File

@@ -1,330 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import at.helpch.placeholderapi.expansion.Relational;
import at.helpch.placeholderapi.replacer.CharsReplacer;
import at.helpch.placeholderapi.replacer.MessageReplacer;
import at.helpch.placeholderapi.replacer.Replacer;
import at.helpch.placeholderapi.replacer.Replacer.Closure;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import org.jetbrains.annotations.NotNull;
public final class PlaceholderAPI {
private static final Replacer REPLACER_PERCENT = new CharsReplacer(Closure.PERCENT);
private static final Replacer REPLACER_BRACKET = new CharsReplacer(Closure.BRACKET);
static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("[%]([^%]+)[%]");
static final Pattern BRACKET_PLACEHOLDER_PATTERN = Pattern.compile("[{]([^{}]+)[}]");
static final Pattern RELATIONAL_PLACEHOLDER_PATTERN = Pattern
.compile("[%](rel_)([^%]+)[%]");
private PlaceholderAPI() {
}
// === Current API ===
/**
* Translates all placeholders into their corresponding values.
* <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}.
*
* @param player Player to parse the placeholders against
* @param text Text to set the placeholder values in
* @return String containing all translated placeholders
*/
@NotNull
public static String setPlaceholders(final PlayerRef player,
@NotNull final String text) {
return REPLACER_PERCENT.apply(text, player,
PlaceholderAPIPlugin.instance().localExpansionManager()::getExpansion);
}
/**
* Translates all placeholders into their corresponding values.
* <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}.
*
* @param player Player to parse the placeholders against
* @param original Message to set the placeholder values in
* @return Message containing all translated placeholders
*/
@NotNull
public static Message setPlaceholders(final PlayerRef player,
@NotNull final Message original) {
return MessageReplacer.replace(original, str -> setPlaceholders(player, str));
}
/**
* Translates all placeholders into their corresponding values.
* <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}.
*
* @param player Player to parse the placeholders against
* @param text List of Strings to set the placeholder values in
* @return String containing all translated placeholders
*/
@NotNull
public static List<String> setPlaceholders(final PlayerRef player,
@NotNull final List<String> text) {
return text.stream().map(line -> setPlaceholders(player, line)).collect(Collectors.toList());
}
// /**
// * Translates all placeholders into their corresponding values.
// * <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}.
// *
// * @param player Player to parse the placeholders against
// * @param original List of Messages to set the placeholder values in
// * @return List of Message containing all translated placeholders
// */
// @NotNull
// public static List<Message> setPlaceholders(final Player player,
// @NotNull final List<Message> original) {
// return original.stream().map(msg -> setPlaceholders(player, msg)).collect(Collectors.toList());
// }
// /**
// * Translates all placeholders into their corresponding values.
// * <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}.
// *
// * @param player Player to parse the placeholders against
// * @param text Text to set the placeholder values in
// * @return String containing all translated placeholders
// */
// @NotNull
// public static String setPlaceholders(final Player player, @NotNull String text) {
// return setPlaceholders(((OfflinePlayer) player), text);
// }
// /**
// * Translates all placeholders into their corresponding values.
// * <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}.
// *
// * @param player Player to parse the placeholders against
// * @param text List of Strings to set the placeholder values in
// * @return String containing all translated placeholders
// */
// @NotNull
// public static List<String> setPlaceholders(final Player player, @NotNull List<@NotNull String> text) {
// return setPlaceholders(((OfflinePlayer) player), text);
// }
/**
* Translates all placeholders into their corresponding values.
* <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}.
*
* @param player Player to parse the placeholders against
* @param text Text to set the placeholder values in
* @return String containing all translated placeholders
*/
@NotNull
public static String setBracketPlaceholders(final PlayerRef player,
@NotNull final String text) {
return REPLACER_BRACKET.apply(text, player,
PlaceholderAPIPlugin.instance().localExpansionManager()::getExpansion);
}
@NotNull
public static Message setBracketPlaceholders(final PlayerRef player,
@NotNull final Message original) {
return MessageReplacer.replace(original, str -> setBracketPlaceholders(player, str));
}
/**
* Translates all placeholders into their corresponding values.
* <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}.
*
* @param player Player to parse the placeholders against
* @param text List of Strings to set the placeholder values in
* @return String containing all translated placeholders
*/
@NotNull
public static List<@NotNull String> setBracketPlaceholders(final PlayerRef player,
@NotNull final List<@NotNull String> text) {
return text.stream().map(line -> setBracketPlaceholders(player, line))
.collect(Collectors.toList());
}
// /**
// * Translates all placeholders into their corresponding values.
// * <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}.
// *
// * @param player Player to parse the placeholders against
// * @param text Text to set the placeholder values in
// * @return String containing all translated placeholders
// */
// @NotNull
// public static String setBracketPlaceholders(Player player, @NotNull String text) {
// return setBracketPlaceholders((OfflinePlayer) player, text);
// }
//
// /**
// * Translates all placeholders into their corresponding values.
// * <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}.
// *
// * @param player Player to parse the placeholders against
// * @param text List of Strings to set the placeholder values in
// * @return String containing all translated placeholders
// */
// @NotNull
// public static List<String> setBracketPlaceholders(Player player, @NotNull List<String> text) {
// return setBracketPlaceholders((OfflinePlayer) player, text);
// }
/**
* set relational placeholders in the text specified placeholders are matched with the pattern
* {@literal %<rel_(identifier)_(params)>%} when set with this method
*
* @param one First player to compare
* @param two Second player to compare
* @param text Text to parse the placeholders in
* @return The text containing the parsed relational placeholders
*/
public static String setRelationalPlaceholders(PlayerRef one, PlayerRef two, String text) {
final Matcher matcher = RELATIONAL_PLACEHOLDER_PATTERN.matcher(text);
while (matcher.find()) {
final String format = matcher.group(2);
final int index = format.indexOf("_");
if (index <= 0 || index >= format.length()) {
continue;
}
String identifier = format.substring(0, index).toLowerCase(Locale.ROOT);
String params = format.substring(index + 1);
final PlaceholderExpansion expansion = PlaceholderAPIPlugin.instance()
.localExpansionManager().getExpansion(identifier);
if (!(expansion instanceof Relational)) {
continue;
}
final String value = ((Relational) expansion).onPlaceholderRequest(one, two, params);
if (value != null) {
text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value));
}
}
return text;
}
/**
* Translate placeholders in the provided List based on the relation of the two provided players.
* <br>The pattern of a valid placeholder is {@literal %rel_<identifier>_<param>%}.
*
* @param one Player to compare
* @param two Player to compare
* @param text text to parse the placeholder values to
* @return The text containing the parsed relational placeholders
*/
public static List<String> setRelationalPlaceholders(PlayerRef one, PlayerRef two, List<String> text) {
return text.stream().map(line -> setRelationalPlaceholders(one, two, line))
.collect(Collectors.toList());
}
/**
* Check if a specific placeholder identifier is currently registered
*
* @param identifier The identifier to check
* @return true if identifier is already registered
*/
public static boolean isRegistered(@NotNull final String identifier) {
return PlaceholderAPIPlugin.instance().localExpansionManager()
.findExpansionByIdentifier(identifier).isPresent();
}
/**
* Get all registered placeholder identifiers
*
* @return A Set of type String containing the identifiers of all registered expansions.
*/
@NotNull
public static Set<String> getRegisteredIdentifiers() {
return Set
.copyOf(PlaceholderAPIPlugin.instance().localExpansionManager().getIdentifiers());
}
/**
* Get the normal placeholder pattern.
*
* @return Regex Pattern of {@literal [%]([^%]+)[%]}
*/
public static Pattern getPlaceholderPattern() {
return PLACEHOLDER_PATTERN;
}
/**
* Get the bracket placeholder pattern.
*
* @return Regex Pattern of {@literal [{]([^{}]+)[}]}
*/
public static Pattern getBracketPlaceholderPattern() {
return BRACKET_PLACEHOLDER_PATTERN;
}
/**
* Get the relational placeholder pattern.
*
* @return Regex Pattern of {@literal [%](rel_)([^%]+)[%]}
*/
public static Pattern getRelationalPlaceholderPattern() {
return RELATIONAL_PLACEHOLDER_PATTERN;
}
/**
* Check if a String contains any PlaceholderAPI placeholders ({@literal
* %<identifier>_<params>%}).
*
* @param text String to check
* @return true if String contains any matches to the normal placeholder pattern, false otherwise
*/
public static boolean containsPlaceholders(String text) {
return text != null && PLACEHOLDER_PATTERN.matcher(text).find();
}
/**
* Check if a String contains any PlaceholderAPI bracket placeholders ({@literal
* {<identifier>_<params>}}).
*
* @param text String to check
* @return true if String contains any matches to the bracket placeholder pattern, false otherwise
*/
public static boolean containsBracketPlaceholders(String text) {
return text != null && BRACKET_PLACEHOLDER_PATTERN.matcher(text).find();
}
public static String booleanValue(final boolean value) {
return value ? PlaceholderAPIPlugin.instance().configManager().config().booleanValue().trueValue() : PlaceholderAPIPlugin.instance().configManager().config().booleanValue().falseValue();
}
}

View File

@@ -1,88 +0,0 @@
package at.helpch.placeholderapi;
import at.helpch.placeholderapi.commands.PlaceholderCommandRouter;
import at.helpch.placeholderapi.configuration.ConfigManager;
import at.helpch.placeholderapi.expansion.manager.CloudExpansionManager;
import at.helpch.placeholderapi.expansion.manager.LocalExpansionManager;
import com.hypixel.hytale.event.EventPriority;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import com.hypixel.hytale.server.core.console.ConsoleSender;
import com.hypixel.hytale.server.core.event.events.BootEvent;
import com.hypixel.hytale.server.core.event.events.PrepareUniverseEvent;
import com.hypixel.hytale.server.core.event.events.player.PlayerDisconnectEvent;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import org.jetbrains.annotations.NotNull;
public class PlaceholderAPIPlugin extends JavaPlugin {
private final ConfigManager configManager = new ConfigManager(this);
private final LocalExpansionManager localExpansionManager = new LocalExpansionManager(this);
private final CloudExpansionManager cloudExpansionManager = new CloudExpansionManager(this);
private static PlaceholderAPIPlugin instance;
public static PlaceholderAPIPlugin instance() {
return instance;
}
public PlaceholderAPIPlugin(@NotNull final JavaPluginInit init) {
super(init);
instance = this;
}
@Override
protected void setup() {
configManager.setup();
getEventRegistry().register(PlayerDisconnectEvent.class, localExpansionManager::onQuit);
getEventRegistry().register(EventPriority.LAST, BootEvent.class, this::onServerLoad);
if (configManager.config().cloudEnabled()) {
cloudExpansionManager.load();
}
}
@Override
protected void start() {
getCommandRegistry().registerCommand(new PlaceholderCommandRouter(this));
// localExpansionManager().load(ConsoleSender.INSTANCE);
super.start();
}
@Override
protected void shutdown() {
super.shutdown();
}
public void reloadPlugin(@NotNull final CommandSender sender) {
localExpansionManager.kill();
// configManager.save();
configManager.setup();
localExpansionManager.load(sender);
if (configManager.config().cloudEnabled()) {
cloudExpansionManager.load();
} else {
cloudExpansionManager.kill();
}
}
public LocalExpansionManager localExpansionManager() {
return localExpansionManager;
}
public ConfigManager configManager() {
return configManager;
}
public CloudExpansionManager cloudExpansionManager() {
return cloudExpansionManager;
}
private void onServerLoad(BootEvent event) {
localExpansionManager.load(ConsoleSender.INSTANCE);
}
}

View File

@@ -1,31 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface PlaceholderHook {
@Nullable
String onPlaceholderRequest(final PlayerRef player, @NotNull final String params);
}

View File

@@ -1,105 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands;
import java.util.*;
import java.util.stream.Stream;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
public abstract class PlaceholderCommand {
@NotNull
private final String label;
@NotNull
private final Set<String> alias;
private Set<String> permissions = new HashSet<>();
protected PlaceholderCommand(@NotNull final String label, @NotNull final String... alias) {
this.label = label;
this.alias = Set.of(alias);
setPermissions("placeholderapi.*");
}
@NotNull
public static Stream<PlaceholderCommand> filterByPermission(@NotNull final CommandSender sender,
@NotNull final Stream<PlaceholderCommand> commands) {
return commands.filter(target -> target.getPermissions().stream().anyMatch(sender::hasPermission));
}
public static void suggestByParameter(@NotNull final Stream<String> possible,
@NotNull final List<String> suggestions, @Nullable final String parameter) {
if (parameter == null) {
possible.forEach(suggestions::add);
} else {
possible.filter(suggestion -> suggestion.toLowerCase(Locale.ROOT).startsWith(parameter.toLowerCase(Locale.ROOT)))
.forEach(suggestions::add);
}
}
@NotNull
public final String getLabel() {
return label;
}
@NotNull
@Unmodifiable
public final Set<String> getAlias() {
return Set.copyOf(alias);
}
@NotNull
@Unmodifiable
public final Set<String> getLabels() {
final Set<String> set = new HashSet<>();
set.add(label);
set.addAll(alias);
return set;
}
@NotNull
public final Set<String> getPermissions() {
return permissions;
}
public void setPermissions(@NotNull final String @NotNull ... permissions) {
this.permissions.addAll(Arrays.asList(permissions));
}
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
}
public void complete(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
}
}

View File

@@ -1,122 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.impl.cloud.CommandECloud;
import at.helpch.placeholderapi.commands.impl.local.*;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.*;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
public final class PlaceholderCommandRouter extends AbstractCommand {
@Unmodifiable
private static final List<PlaceholderCommand> COMMANDS = List.of(new CommandHelp(),
new CommandInfo(),
new CommandList(),
new CommandDump(),
new CommandECloud(),
new CommandParse(),
new CommandReload(),
new CommandVersion(),
new CommandExpansionRegister(),
new CommandExpansionUnregister());
@NotNull
private final PlaceholderAPIPlugin plugin;
@NotNull
@Unmodifiable
private final Map<String, PlaceholderCommand> commands;
@Override
public String getName() {
return "papi";
}
public PlaceholderCommandRouter(@NotNull final PlaceholderAPIPlugin plugin) {
super("papi", "papi");
addAliases("placeholderapi");
setAllowsExtraArguments(true);
this.plugin = plugin;
final Map<String, PlaceholderCommand> commands = new HashMap<>();
for (final PlaceholderCommand command : COMMANDS) {
command.getLabels().forEach(label -> commands.put(label, command));
}
this.commands = commands;
}
@Override
protected boolean canGeneratePermission() {
return false;
}
@Override
protected @Nullable CompletableFuture<Void> execute(@NotNull final CommandContext context) {
final String[] args = context.getInputString().replace("papi", "").replace("placeholderapi", "").trim().split(" ");
final CommandSender sender = context.sender();
if (args.length == 0 || args[0].isBlank()) {
final PlaceholderCommand fallback = commands.get("version");
if (fallback != null) {
fallback.evaluate(plugin, sender, "", Collections.emptyList());
}
return CompletableFuture.completedFuture(null);
}
final String search = args[0].toLowerCase(Locale.ROOT);
final PlaceholderCommand target = commands.get(search);
if (target == null) {
sender.sendMessage(Message.raw("Unknown command ").color(Color.RED).insert(Message.raw(search).color(Color.GRAY)));
return CompletableFuture.completedFuture(null);
}
final Set<String> permissions = target.getPermissions();
if (permissions.stream().noneMatch(sender::hasPermission)) {
sender.sendMessage(Message.raw("You do not have permission to do this!").color(Color.RED));
return CompletableFuture.completedFuture(null);
}
target
.evaluate(plugin, sender, search, Arrays.asList(Arrays.copyOfRange(args, 1, args.length)));
return CompletableFuture.completedFuture(null);
}
}

View File

@@ -1,184 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.cloud;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
public final class CommandECloud extends PlaceholderCommand {
@Unmodifiable
private static final List<PlaceholderCommand> COMMANDS = List
.of(new CommandECloudClear(),
new CommandECloudStatus(),
new CommandECloudUpdate(),
new CommandECloudRefresh(),
new CommandECloudDownload(),
new CommandECloudExpansionInfo(),
new CommandECloudExpansionList(),
new CommandECloudExpansionPlaceholders());
static {
COMMANDS
.forEach(command -> command.setPermissions("placeholderapi.ecloud." + command.getLabel()));
}
@NotNull
@Unmodifiable
private final Map<String, PlaceholderCommand> commands;
public CommandECloud() {
super("ecloud");
final Map<String, PlaceholderCommand> commands = new HashMap<>();
for (final PlaceholderCommand command : COMMANDS) {
command.getLabels().forEach(label -> commands.put(label, command));
}
this.commands = commands;
setPermissions("placeholderapi.ecloud.*", "placeholderapi.ecloud");
COMMANDS.stream().map(PlaceholderCommand::getPermissions).flatMap(Set::stream).forEach(this::setPermissions);
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
if (params.isEmpty()) {
Message message = Message.empty()
.insert(Message.raw("PlaceholderAPI ").color(Color.CYAN).bold(true))
.insert(Message.raw("- ").color(Color.DARK_GRAY))
.insert(Message.raw("eCloud Help Menu ").color(Color.GRAY))
.insert(Message.raw("-\n").color(Color.DARK_GRAY));
final List<String[]> commands = List.of(
new String[]{"ecloud status", "View status of the eCloud"},
new String[]{"ecloud list <all/{author}/installed> {page}", "List all/author specific available expansions"},
new String[]{"ecloud info <expansion name> {version}", "View information about a specific expansion available on the eCloud"},
new String[]{"ecloud placeholders <expansion name>", "View placeholders for an expansion"},
new String[]{"ecloud download <expansion name> {version}", "Download an expansion from the eCloud"},
new String[]{"ecloud update <expansion name/all>", "Update a specific/all installed expansions"},
new String[]{"ecloud refresh", "Fetch the most up to date list of expansions available."},
new String[]{"ecloud clear", "Clear the expansion cloud cache."}
);
for (String[] command : commands) {
message = message.insert(Message.raw("\n/papi ").color(Color.CYAN))
.insert(Message.raw(command[0]).color(Color.WHITE))
.insert(Message.raw("\n " + command[1]).color(Color.GRAY));
}
sender.sendMessage(message);
// Msg.msg(sender,
// "&b&lPlaceholderAPI &8- &7eCloud Help Menu &8- ",
// " ",
// "&b/papi &fecloud status",
// " &7&oView status of the eCloud",
// "&b/papi &fecloud list <all/{author}/installed> {page}",
// " &7&oList all/author specific available expansions",
// "&b/papi &fecloud info <expansion name> {version}",
// " &7&oView information about a specific expansion available on the eCloud",
// "&b/papi &fecloud placeholders <expansion name>",
// " &7&oView placeholders for an expansion",
// "&b/papi &fecloud download <expansion name> {version}",
// " &7&oDownload an expansion from the eCloud",
// "&b/papi &fecloud update <expansion name/all>",
// " &7&oUpdate a specific/all installed expansions",
// "&b/papi &fecloud refresh",
// " &7&oFetch the most up to date list of expansions available.",
// "&b/papi &fecloud clear",
// " &7&oClear the expansion cloud cache.");
return;
}
final String search = params.get(0).toLowerCase(Locale.ROOT);
final PlaceholderCommand target = commands.get(search);
if (target == null) {
sender.sendMessage(Message.raw("Unknown command ").color(Color.RED).insert(Message.raw("ecloud " + search).color(Color.GRAY)));
// Msg.msg(sender, "&cUnknown command &7ecloud " + search);
return;
}
final Set<String> permissions = target.getPermissions();
if (permissions.stream().noneMatch(sender::hasPermission)) {
sender.sendMessage(Message.raw("You do not have permission to do this!").color(Color.RED));
// Msg.msg(sender, "&cYou do not have permission to do this!");
return;
}
if (!plugin.configManager().config().cloudEnabled()) {
sender.sendMessage(Message.raw("The eCloud Manager is not enabled! To enable it, set 'cloud_enabled' to true and reload the plugin."));
// Msg.msg(sender, "&cThe eCloud Manager is not enabled! To enable it, set 'cloud_enabled' to true and reload the plugin.");
return;
}
if (!target.getLabel().equalsIgnoreCase("refresh") && plugin.cloudExpansionManager().isEmpty()) {
sender.sendMessage(Message.raw("There is no available data from the eCloud. Please try running ").color(Color.RED)
.insert(Message.raw("/papi ecloud refresh").color(Color.WHITE))
.insert(Message.raw(" If this does not resolve the issue, the eCloud may be blocked by your firewall, server host or service provider.\n\n").color(Color.RED))
.insert(Message.raw("More information: ").color(Color.RED))
.insert(Message.raw("https://placeholderapi.com/ecloud-blocked").color(Color.WHITE).bold(true).italic(true).link("https://placeholderapi.com/ecloud-blocked")));
// Msg.msg(sender, "&cThere is no available data from the eCloud. Please try running &f/papi ecloud refresh&c. If this does not resolve the issue, the eCloud may be blocked by your firewall, server host, or service provider.\n\nMore information: &fhttps://placeholderapi.com/ecloud-blocked");
return;
}
target.evaluate(plugin, sender, search, params.subList(1, params.size()));
}
// @Override
// public void complete(@NotNull final PlaceholderAPIPlugin plugin,
// @NotNull final CommandSender sender, @NotNull final String alias,
// @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
// if (params.size() <= 1) {
// final Stream<String> targets = filterByPermission(sender, commands.values().stream())
// .map(PlaceholderCommand::getLabels).flatMap(Collection::stream);
// suggestByParameter(targets, suggestions, params.isEmpty() ? null : params.get(0));
//
// return; // send sub commands
// }
//
// final String search = params.get(0).toLowerCase(Locale.ROOT);
// final PlaceholderCommand target = commands.get(search);
//
// if (target == null) {
// return;
// }
//
// target.complete(plugin, sender, search, params.subList(1, params.size()), suggestions);
// }
}

View File

@@ -1,50 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.cloud;
import java.awt.*;
import java.util.List;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandECloudClear extends PlaceholderCommand {
public CommandECloudClear() {
super("clear");
setPermissions("placeholderapi.ecloud.*", "placeholderapi.ecloud.clear");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
plugin.cloudExpansionManager().clean();
sender.sendMessage(Message.raw("The eCloud cache has been cleared!").color(Color.GREEN));
// Msg.msg(sender,
// "&aThe eCloud cache has been cleared!");
}
}

View File

@@ -1,68 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.cloud;
import java.awt.*;
import java.util.Arrays;
import java.util.List;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import at.helpch.placeholderapi.expansion.cloud.CloudExpansion;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandECloudDownload extends PlaceholderCommand {
public CommandECloudDownload() {
super("download");
setPermissions("placeholderapi.ecloud.*", "placeholderapi.ecloud.download");
}
private boolean isBlockedExpansion(String name) {
String env = System.getenv("PAPI_BLOCKED_EXPANSIONS");
if (env == null) {
return false;
}
return Arrays.stream(env.split(","))
.anyMatch(s -> s.equalsIgnoreCase(name));
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
final Message message = Message.raw("""
Expansion downloads have been disabled to meet CurseForge's policy requirements.
This limitation is imposed by the platform, not PlaceholderAPI.
""").color(Color.RED)
.insert(Message.raw("Please download expansions manually from ").color(Color.RED).insert(Message.raw("ecloud.placeholderapi.com").link("https://ecloud.placeholderapi.com").bold(true).italic(true).color(Color.WHITE)))
.insert(Message.raw(" or install the full version of PlaceholderAPI from ").color(Color.RED))
.insert(Message.raw("placeholderapi.com/downloads").link("https://placeholderapi.com/downloads").bold(true).italic(true).color(Color.WHITE));
sender.sendMessage(message);
}
}

View File

@@ -1,134 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.cloud;
import java.awt.*;
import java.util.List;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import at.helpch.placeholderapi.expansion.cloud.CloudExpansion;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandECloudExpansionInfo extends PlaceholderCommand {
public CommandECloudExpansionInfo() {
super("info");
setPermissions("placeholderapi.ecloud.*", "placeholderapi.ecloud.info");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
if (params.isEmpty()) {
sender.sendMessage(Message.raw("You must specify the name of the expansion.").color(Color.RED));
// Msg.msg(sender,
// "&cYou must specify the name of the expansion.");
return;
}
final CloudExpansion expansion = plugin.cloudExpansionManager()
.findCloudExpansionByName(params.get(0)).orElse(null);
if (expansion == null) {
sender.sendMessage(Message.raw("There is no expansion with the name: ").color(Color.RED).insert(Message.raw(params.get(0)).color(Color.WHITE)));
// Msg.msg(sender,
// "&cThere is no expansion with the name: &f" + params.get(0));
return;
}
Message message = Message.raw("Expansion: ").color(Color.CYAN)
.insert(Message.raw(expansion.getName()).color(expansion.shouldUpdate() ? Color.YELLOW : Color.GREEN))
.insert(Message.raw("\nAuthor: ").color(Color.CYAN))
.insert(Message.raw(expansion.getAuthor()).color(Color.WHITE))
.insert(Message.raw("\n"));
if (params.size() < 2) {
message = message
.insert(Message.raw("Latest Version: ").color(Color.CYAN))
.insert(Message.raw(expansion.getLatestVersion()).color(Color.WHITE))
.insert(Message.raw("\nReleased: ").color(Color.CYAN))
.insert(Message.raw(expansion.getTimeSinceLastUpdate() + " ago").color(Color.WHITE))
.insert(Message.raw("\nVerified: ").color(Color.CYAN))
.insert(Message.raw(expansion.getVersion().isVerified() ? "YES" : "NO")
.color(expansion.getVersion().isVerified() ? Color.GREEN : Color.RED)
.bold(true))
.insert(Message.raw("\nRelease Notes: ").color(Color.CYAN))
.insert(Message.raw(expansion.getVersion().getReleaseNotes()).color(Color.WHITE))
.insert(Message.raw("\n"));
} else {
final CloudExpansion.Version version = expansion.getVersion(params.get(1));
if (version == null) {
sender.sendMessage(Message.raw("Could not find specified version: ").color(Color.RED)
.insert(Message.raw(params.get(1)).color(Color.WHITE))
.insert(Message.raw("\nVersions: ").color(Color.GREEN))
.insert(Message.raw(expansion.getAvailableVersions().toString()).color(Color.WHITE)));
// Msg.msg(sender,
// "&cCould not find specified version: &f" + params.get(1),
// "&aVersions: &f" + expansion.getAvailableVersions());
return;
}
message = message
.insert(Message.raw("Version: ").color(Color.CYAN))
.insert(Message.raw(version.getVersion()).color(Color.WHITE))
.insert(Message.raw("\nVerified: ").color(Color.CYAN))
.insert(Message.raw(version.isVerified() ? "YES" : "NO")
.color(version.isVerified() ? Color.GREEN : Color.RED)
.bold(true))
.insert(Message.raw("\nRelease Notes: ").color(Color.CYAN))
.insert(Message.raw(version.getReleaseNotes()).color(Color.WHITE))
.insert(Message.raw("\nDownload URL: ").color(Color.CYAN))
.insert(Message.raw(version.getUrl()).color(Color.WHITE))
.insert(Message.raw("\n"));
}
sender.sendMessage(message);
}
// @Override
// public void complete(@NotNull final PlaceholderAPIPlugin plugin,
// @NotNull final CommandSender sender, @NotNull final String alias,
// @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
// if (params.size() > 2) {
// return;
// }
//
// if (params.size() <= 1) {
// final Stream<String> names = plugin.getCloudExpansionManager().getCloudExpansions().values()
// .stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_'));
// suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0));
// return;
// }
//
// final Optional<CloudExpansion> expansion = plugin.getCloudExpansionManager()
// .findCloudExpansionByName(params.get(0));
// if (!expansion.isPresent()) {
// return;
// }
//
// suggestByParameter(expansion.get().getAvailableVersions().stream(), suggestions, params.get(1));
// }
}

View File

@@ -1,392 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.cloud;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.function.Function;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import at.helpch.placeholderapi.expansion.cloud.CloudExpansion;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import com.hypixel.hytale.server.core.entity.entities.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandECloudExpansionList extends PlaceholderCommand {
private static final int PAGE_SIZE = 10;
@NotNull
private static final Function<CloudExpansion, String> EXPANSION_LATEST_VERSION =
CloudExpansion::getLatestVersion;
@NotNull
private static final Function<CloudExpansion, String> EXPANSION_CURRENT_VERSION =
expansion -> PlaceholderAPIPlugin.instance().localExpansionManager()
.findExpansionByName(expansion.getName()).map(PlaceholderExpansion::getVersion)
.orElse("Unknown");
@Unmodifiable
private static final Set<String> OPTIONS = Set.of("all", "installed");
public CommandECloudExpansionList() {
super("list");
setPermissions("placeholderapi.ecloud.*", "placeholderapi.ecloud.list");
}
@NotNull
private static Collection<CloudExpansion> getExpansions(@NotNull final String target,
@NotNull final PlaceholderAPIPlugin plugin) {
switch (target.toLowerCase(Locale.ROOT)) {
case "all":
return plugin.cloudExpansionManager().getCloudExpansions().values();
case "installed":
return plugin.cloudExpansionManager().getCloudExpansionsInstalled().values();
default:
return plugin.cloudExpansionManager().getCloudExpansionsByAuthor(target).values();
}
}
@NotNull
private static List<CloudExpansion> getPage(@NotNull final List<CloudExpansion> expansions,
final int page) {
final int head = (page * PAGE_SIZE);
final int tail = Math.min(expansions.size(), head + PAGE_SIZE);
if (expansions.size() < head) {
return Collections.emptyList();
}
return expansions.subList(head, tail);
}
public static Message buildExpansionTitle(@NotNull final String target, final int page) {
Message title;
switch (target.toLowerCase(Locale.ROOT)) {
case "all":
title = Message.raw("All Expansions").color(Color.CYAN);
break;
case "installed":
title = Message.raw("Installed Expansions").color(Color.CYAN);
break;
default:
title = Message.raw("Expansions by ").color(Color.CYAN)
.insert(Message.raw(target).color(Color.WHITE));
break;
}
if (page == -1) {
return title.insert(Message.raw("\n"));
}
return title
.insert(Message.raw(" Page").color(Color.CYAN))
.insert(Message.raw(": ").color(Color.GRAY))
.insert(Message.raw(String.valueOf(page)).color(Color.GREEN));
}
private static Message getMessage(@NotNull final List<CloudExpansion> expansions,
final int page, final int limit, @NotNull final String target) {
Message message = Message.empty();
for (int index = 0; index < expansions.size(); index++) {
final CloudExpansion expansion = expansions.get(index);
Message line = Message.empty();
final int expansionNumber = index + ((page - 1) * PAGE_SIZE) + 1;
line = line.insert(Message.raw(expansionNumber + ". ").color(Color.DARK_GRAY));
final Color expansionColour;
if (expansion.shouldUpdate()) {
expansionColour = Color.YELLOW;
} else {
if (expansion.hasExpansion()) {
expansionColour = Color.GREEN;
} else {
expansionColour = Color.GRAY;
}
}
line = line.insert(Message.raw(expansion.getName()).color(expansionColour));
// line = line.click(ClickEvent.suggestCommand("/papi ecloud download " + expansion.getName()));
//
// final TextComponent.Builder hoverText = text("Click to download this expansion!", AQUA)
// .append(newline()).append(newline())
// .append(text("Author: ", AQUA)).append(text(expansion.getAuthor(), WHITE))
// .append(newline())
// .append(text("Verified: ", AQUA)).append(text(expansion.getVersion().isVerified() ? "✔" : "❌", expansion.getVersion().isVerified() ? GREEN : RED, TextDecoration.BOLD))
// .append(newline())
// .append(text("Released: ", AQUA)).append(text(format.format(expansion.getLastUpdate()), WHITE))
// .toBuilder();
//
// Optional.ofNullable(expansion.getDescription())
// .filter(description -> !description.isEmpty())
// .ifPresent(description -> hoverText.append(newline()).append(newline())
// .append(text(description.replace("\r", "").trim(), WHITE))
// );
// line.hoverEvent(HoverEvent.showText(hoverText.build()));
if (index != expansions.size() - 1) {
line.insert(Message.raw("\n"));
}
message = message.insert(line);
}
if (limit > 1) {
message = message.insert("\n");
// Message left = Message.raw("â—€", page > 1 ? GRAY : DARK_GRAY).toBuilder();
// if (page > 1) {
// left.clickEvent(ClickEvent.runCommand("/papi ecloud list " + target + " " + (page - 1)));
// }
//
// final TextComponent.Builder right = text("â–¶", page < limit ? GRAY : DARK_GRAY).toBuilder();
// if (page < limit) {
// right.clickEvent(ClickEvent.runCommand("/papi ecloud list " + target + " " + (page + 1)));
// }
message = message.insert(Message.raw(" - " + page + " - ").color(Color.GREEN));
}
return message;
}
private static Message buildExpansionTable(@NotNull final List<CloudExpansion> expansions,
final int startIndex,
@NotNull final String versionTitle,
@NotNull final Function<CloudExpansion, String> versionFunction) {
final List<List<String>> rows = new ArrayList<>();
rows.add(List.of("#", "Name", "Author", "Verified", versionTitle));
int counter = startIndex;
for (final CloudExpansion expansion : expansions) {
rows.add(List.of(
counter++ + ".",
expansion.getName(),
expansion.getAuthor(),
expansion.getVersion().isVerified() ? "Y" : "N",
versionFunction.apply(expansion)
));
}
final int columnCount = rows.getFirst().size();
final int[] widths = new int[columnCount];
for (final List<String> row : rows) {
for (int i = 0; i < columnCount; i++) {
widths[i] = Math.max(widths[i], row.get(i).length());
}
}
final List<Color> headerColors = List.of(
Color.WHITE,
new Color(85, 85, 255),
new Color(85, 85, 255),
new Color(85, 85, 255),
new Color(85, 85, 255)
);
Message message = Message.empty();
message = message.insert(buildTableRow(rows.getFirst(), headerColors, widths));
message = message.insert(Message.raw("\n"));
final int separatorLength = Arrays.stream(widths).sum() + (columnCount * 2);
message = message.insert(Message.raw("-".repeat(separatorLength)).color(Color.DARK_GRAY));
if (rows.size() > 1) {
message = message.insert(Message.raw("\n"));
}
for (int rowIndex = 1; rowIndex < rows.size(); rowIndex++) {
final List<String> row = rows.get(rowIndex);
final CloudExpansion expansion = expansions.get(rowIndex - 1);
final Color nameColor = expansion.shouldUpdate()
? Color.YELLOW
: (expansion.hasExpansion() ? Color.GREEN : Color.GRAY);
final List<Color> rowColors = List.of(
Color.DARK_GRAY,
nameColor,
Color.WHITE,
expansion.getVersion().isVerified() ? Color.GREEN : Color.RED,
Color.WHITE
);
message = message.insert(buildTableRow(row, rowColors, widths));
if (rowIndex < rows.size() - 1) {
message = message.insert(Message.raw("\n"));
}
}
return message;
}
private static Message buildTableRow(@NotNull final List<String> columns,
@NotNull final List<Color> colors,
@NotNull final int[] widths) {
Message row = Message.empty();
for (int i = 0; i < columns.size(); i++) {
final String padded = padRight(columns.get(i), widths[i] + 2);
row = row.insert(Message.raw(padded).color(colors.get(i)));
}
return row;
}
@NotNull
private static String padRight(@NotNull final String text, final int length) {
if (text.length() >= length) {
return text;
}
return text + " ".repeat(length - text.length());
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
if (params.isEmpty()) {
sender.sendMessage(Message.raw("You must specify an option. [all, {author}, installed]").color(Color.RED));
// Msg.msg(sender,
// "&cYou must specify an option. [all, {author}, installed]");
return;
}
final boolean installed = params.get(0).equalsIgnoreCase("installed");
final List<CloudExpansion> expansions = new ArrayList<>(getExpansions(params.get(0), plugin));
if (expansions.isEmpty()) {
sender.sendMessage(Message.raw("No expansions available to list.").color(Color.RED));
// Msg.msg(sender,
// "&cNo expansions available to list.");
return;
}
expansions
.sort(plugin.configManager().config().cloudSorting());
if (!(sender instanceof Player) && params.size() < 2) {
final Message message = buildExpansionTitle(params.get(0), -1)
.insert(buildExpansionTable(
expansions,
1,
installed ? "Version" : "Latest Version",
installed ? EXPANSION_CURRENT_VERSION : EXPANSION_LATEST_VERSION));
sender.sendMessage(message);
// Msg.msg(sender, builder.toString());
return;
}
final int page;
if (params.size() < 2) {
page = 1;
} else {
//noinspection UnstableApiUsage
Integer parsed/* = Ints.tryParse(params.get(1))*/;
try {
parsed = Integer.parseInt(params.get(1));
} catch (Exception e) {
parsed = null;
}
if (parsed == null) {
sender.sendMessage(Message.raw("Page number must be an integer.").color(Color.RED));
// Msg.msg(sender,
// "&cPage number must be an integer.");
return;
}
final int limit = (int) Math.ceil((double) expansions.size() / PAGE_SIZE);
if (parsed < 1 || parsed > limit) {
sender.sendMessage(Message.raw("Page number must be in the range [1.." + limit + "]").color(Color.RED)); //todo: not exact
// Msg.msg(sender,
// "&cPage number must be in the range &8[&a1&7..&a" + limit + "&8]");
return;
}
page = parsed;
}
final List<CloudExpansion> values = getPage(expansions, page - 1);
final Message title = buildExpansionTitle(params.get(0), page);
if (!(sender instanceof Player)) {
final Message message = title.insert(buildExpansionTable(
values,
((page - 1) * PAGE_SIZE) + 1,
installed ? "Version" : "Latest Version",
installed ? EXPANSION_CURRENT_VERSION : EXPANSION_LATEST_VERSION));
sender.sendMessage(message);
// Msg.msg(sender, builder.toString());
return;
}
sender.sendMessage(title);
// Msg.msg(sender, builder.toString());
final int limit = (int) Math.ceil((double) expansions.size() / PAGE_SIZE);
final Message message = getMessage(values, page, limit, params.get(0));
sender.sendMessage(message);
}
// @Override
// public void complete(@NotNull final PlaceholderAPIPlugin plugin,
// @NotNull final CommandSender sender, @NotNull final String alias,
// @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
// if (params.size() > 2) {
// return;
// }
//
// if (params.size() <= 1) {
// suggestByParameter(
// Sets.union(OPTIONS, plugin.getCloudExpansionManager().getCloudExpansionAuthors())
// .stream(), suggestions, params.isEmpty() ? null : params.get(0));
// return;
// }
//
// suggestByParameter(IntStream.rangeClosed(1,
// (int) Math.ceil((double) getExpansions(params.get(0), plugin).size() / PAGE_SIZE))
// .mapToObj(Objects::toString), suggestions, params.get(1));
// }
}

View File

@@ -1,124 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.cloud;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import at.helpch.placeholderapi.expansion.cloud.CloudExpansion;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandECloudExpansionPlaceholders extends PlaceholderCommand {
public CommandECloudExpansionPlaceholders() {
super("placeholders");
setPermissions("placeholderapi.ecloud.*", "placeholderapi.ecloud.placeholders");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
if (params.isEmpty()) {
sender.sendMessage(Message.raw("You must specify the name of the expansion.").color(Color.RED));
// Msg.msg(sender,
// "&cYou must specify the name of the expansion.");
return;
}
final CloudExpansion expansion = plugin.cloudExpansionManager()
.findCloudExpansionByName(params.get(0)).orElse(null);
if (expansion == null) {
sender.sendMessage(Message.raw("There is no expansion with the name: ").color(Color.RED).insert(Message.raw(params.getFirst()).color(Color.WHITE)));
// Msg.msg(sender,
// "&cThere is no expansion with the name: &f" + params.get(0));
return;
}
final List<String> placeholders = expansion.getPlaceholders();
if (placeholders == null || placeholders.isEmpty()) {
sender.sendMessage(Message.raw("The expansion specified does not have placeholders listed.").color(Color.RED));
// Msg.msg(sender,
// "&cThe expansion specified does not have placeholders listed.");
return;
}
// final List<List<String>> partitions = Lists
// .partition(placeholders.stream().sorted().collect(Collectors.toList()), 10);
final List<List<String>> partitions = new ArrayList<>(IntStream.range(0, placeholders.size()).boxed().collect(Collectors.groupingBy(i -> i/10, Collectors.mapping(placeholders::get, Collectors.toList()))).values());
Message message = Message.raw(" ").color(Color.ORANGE)
.insert(Message.raw(String.valueOf(placeholders.size())).color(Color.ORANGE))
.insert(Message.raw(" placeholders: ").color(Color.GRAY));
for (int i = 0; i < partitions.size(); i++) {
if (i == 0) {
message = message.insert(Message.raw("\n"));
}
final List<String> partition = partitions.get(i);
for (int j = 0; j < partition.size(); j++) {
message = message.insert(Message.raw(partition.get(j)).color(Color.GREEN));
if (j < partition.size() - 1) {
message = message.insert(Message.raw(", ").color(Color.GRAY));
}
}
if (i < partitions.size() - 1) {
message = message.insert(Message.raw("\n"));
}
}
sender.sendMessage(message);
// Msg.msg(sender,
// "&6" + placeholders.size() + "&7 placeholders: &a",
// partitions.stream().map(partition -> String.join(", ", partition))
// .collect(Collectors.joining("\n")));
}
// @Override
// public void complete(@NotNull final PlaceholderAPIPlugin plugin,
// @NotNull final CommandSender sender, @NotNull final String alias,
// @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
// if (params.size() > 1) {
// return;
// }
//
// final Stream<String> names = plugin.getCloudExpansionManager()
// .getCloudExpansions()
// .values()
// .stream()
// .map(CloudExpansion::getName)
// .map(name -> name.replace(' ', '_'));
//
// suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0));
// }
}

View File

@@ -1,51 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.cloud;
import java.awt.*;
import java.util.List;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandECloudRefresh extends PlaceholderCommand {
public CommandECloudRefresh() {
super("refresh");
setPermissions("placeholderapi.ecloud.*", "placeholderapi.ecloud.refresh");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
plugin.cloudExpansionManager().load();
sender.sendMessage(Message.raw("The eCloud manager has been refreshed!").color(Color.GREEN));
// Msg.msg(sender,
// "&aThe eCloud manager has been refreshed!");
}
}

View File

@@ -1,72 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.cloud;
import java.awt.*;
import java.util.List;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import at.helpch.placeholderapi.expansion.manager.CloudExpansionManager;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandECloudStatus extends PlaceholderCommand {
public CommandECloudStatus() {
super("status");
setPermissions("placeholderapi.ecloud.*", "placeholderapi.ecloud.status");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
final CloudExpansionManager manager = plugin.cloudExpansionManager();
final int updateCount = manager.getCloudUpdateCount();
final int authorCount = manager.getCloudExpansionAuthorCount();
final int expansionCount = manager.getCloudExpansions().size();
Message message = Message.raw("There are ").color(Color.CYAN)
.insert(Message.raw(String.valueOf(expansionCount)).color(Color.GREEN))
.insert(Message.raw(" expansions available on the eCloud.\n").color(Color.CYAN))
.insert(Message.raw("A total of ").color(Color.GRAY))
.insert(Message.raw(String.valueOf(authorCount)).color(Color.WHITE))
.insert(Message.raw(" authors have contributed Hytale expansions to the eCloud.\n").color(Color.GRAY));
if (updateCount > 0) {
message = message
.insert(Message.raw("You have ").color(Color.YELLOW))
.insert(Message.raw(String.valueOf(updateCount)).color(Color.WHITE))
.insert(Message.raw(updateCount > 1 ? " expansions" : " expansion").color(Color.YELLOW))
.insert(Message.raw(" installed that ").color(Color.YELLOW))
.insert(Message.raw(updateCount > 1 ? "have an" : "has an").color(Color.YELLOW))
.insert(Message.raw(" update available.").color(Color.YELLOW));
}
sender.sendMessage(message);
// Msg.msg(sender, builder.toString());
}
}

View File

@@ -1,67 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.cloud;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import at.helpch.placeholderapi.expansion.cloud.CloudExpansion;
import at.helpch.placeholderapi.util.Futures;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
/**
* please don't flame me for this code, I will fix this shit later.
*/
public final class CommandECloudUpdate extends PlaceholderCommand {
public CommandECloudUpdate() {
super("update");
setPermissions("placeholderapi.ecloud.*", "placeholderapi.ecloud.update");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
final Message message = Message.raw("""
Expansion downloads have been disabled to meet CurseForge's policy requirements.
This limitation is imposed by the platform, not PlaceholderAPI.
""").color(Color.RED)
.insert(Message.raw("Please download expansions manually from ").color(Color.RED).insert(Message.raw("ecloud.placeholderapi.com").link("https://ecloud.placeholderapi.com").bold(true).italic(true).color(Color.WHITE)))
.insert(Message.raw(" or install the full version of PlaceholderAPI from ").color(Color.RED))
.insert(Message.raw("placeholderapi.com/downloads").link("https://placeholderapi.com/downloads").bold(true).italic(true).color(Color.WHITE));
sender.sendMessage(message);
}
}

View File

@@ -1,214 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.local;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import com.hypixel.hytale.common.plugin.AuthorInfo;
import com.hypixel.hytale.common.util.java.ManifestUtil;
import com.hypixel.hytale.server.core.HytaleServer;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import com.hypixel.hytale.server.core.plugin.PluginBase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
import java.awt.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.stream.Collectors;
public final class CommandDump extends PlaceholderCommand {
@NotNull
private static final String URL = "https://paste.helpch.at/";
@NotNull
private static final Gson gson = new Gson();
@NotNull
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter
.ofLocalizedDateTime(FormatStyle.LONG)
.withLocale(Locale.US)
.withZone(ZoneId.of("UTC"));
public CommandDump() {
super("dump");
setPermissions("placeholderapi.admin", "placeholderapi.dump");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
postDump(makeDump(plugin)).whenComplete((key, exception) -> {
if (exception != null) {
plugin.getLogger().atWarning().log("failed to post dump details ", exception);
sender.sendMessage(Message.raw("Failed to post dump details, check console.").color(Color.RED));
// Msg.msg(sender,
// "&cFailed to post dump details, check console.");
return;
}
sender.sendMessage(Message.raw("Successfully posted dump: ").color(Color.GREEN).insert(Message.raw(URL + key).color(Color.WHITE).bold(true).italic(true).link(URL + key)));
// Msg.msg(sender,
// "&aSuccessfully posted dump: " + URL + key);
});
}
@NotNull
private CompletableFuture<String> postDump(@NotNull final String dump) {
return CompletableFuture.supplyAsync(() -> {
try {
final HttpURLConnection connection = ((HttpURLConnection) new URL(URL + "documents")
.openConnection());
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "text/plain; charset=utf-8");
connection.setDoOutput(true);
connection.connect();
try (final OutputStream stream = connection.getOutputStream()) {
stream.write(dump.getBytes(StandardCharsets.UTF_8));
}
try (final InputStream stream = connection.getInputStream()) {
final String json = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8)).lines().collect(Collectors.joining(System.lineSeparator()));
return gson.fromJson(json, JsonObject.class).get("key").getAsString();
}
} catch (final IOException ex) {
throw new CompletionException(ex);
}
});
}
@NotNull
private String makeDump(@NotNull final PlaceholderAPIPlugin plugin) {
final StringBuilder builder = new StringBuilder();
builder.append("Generated: ")
.append(DATE_FORMAT.format(Instant.now()))
.append("\n\n");
builder.append("PlaceholderAPI: ")
.append(plugin.getManifest().getVersion())
.append("\n\n");
builder.append("Expansions Registered:")
.append('\n');
final List<PlaceholderExpansion> expansions = plugin.localExpansionManager()
.getExpansions()
.stream()
.sorted(
Comparator.comparing(PlaceholderExpansion::getIdentifier)
.thenComparing(PlaceholderExpansion::getAuthor)
)
.toList();
int size = expansions.stream().map(e -> e.getIdentifier().length())
.max(Integer::compareTo)
.orElse(0);
for (final PlaceholderExpansion expansion : expansions) {
builder.append(" ")
.append(String.format("%-" + size + "s", expansion.getIdentifier()))
.append(" [Author: ")
.append(expansion.getAuthor())
.append(", Version: ")
.append(expansion.getVersion())
.append("]\n");
}
builder.append('\n');
builder.append("Expansions Directory:")
.append('\n');
final String[] jars = plugin.localExpansionManager()
.getExpansionsFolder()
.list((dir, name) -> name.toLowerCase(Locale.ROOT).endsWith(".jar"));
if (jars == null) {
builder.append(" ¨[Warning]: Could not load jar files from expansions folder.");
} else {
for (final String jar : jars) {
builder.append(" ")
.append(jar)
.append('\n');
}
}
builder.append('\n');
builder.append("Server Info: ")
.append(ManifestUtil.getImplementationVersion()) // hytale version
.append("\n");
builder.append("Java Version: ")
.append(System.getProperty("java.version"))
.append("\n\n");
builder.append("Plugin Info:")
.append('\n');
List<PluginBase> plugins = HytaleServer.get().getPluginManager().getPlugins().stream()
.sorted(Comparator.comparing(PluginBase::getName))
.toList();
size = plugins.stream().map(pl -> pl.getName().length())
.max(Integer::compareTo)
.orElse(0);
for (final PluginBase other : plugins) {
builder.append(" ")
.append(String.format("%-" + size + "s", other.getName()))
.append(" [Authors: [")
.append(other.getManifest().getAuthors().stream()
.map(AuthorInfo::getName)
.collect(Collectors.joining(", ")))
.append("], Version: ")
.append(other.getManifest().getVersion())
.append("]")
.append("\n");
}
return builder.toString();
}
}

View File

@@ -1,117 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.local;
import java.awt.*;
import java.io.File;
import java.util.List;
import java.util.Optional;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import at.helpch.placeholderapi.expansion.manager.LocalExpansionManager;
import at.helpch.placeholderapi.util.Futures;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandExpansionRegister extends PlaceholderCommand {
public CommandExpansionRegister() {
super("register");
setPermissions("placeholderapi.admin", "placeholderapi.register");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
if (params.isEmpty()) {
sender.sendMessage(Message.raw("You must specify the name of an expansion file.").color(Color.RED));
// Msg.msg(sender,
// "&cYou must specify the name of an expansion file.");
return;
}
final LocalExpansionManager manager = plugin.localExpansionManager();
final File file = new File(manager.getExpansionsFolder(), params.getFirst());
if (!file.exists() || !file.getParentFile().equals(manager.getExpansionsFolder())) {
sender.sendMessage(Message.raw("The file ").color(Color.RED).insert(Message.raw(file.getName()).color(Color.WHITE)).insert(Message.raw(" doesn't exist!").color(Color.RED)));
// Msg.msg(sender,
// "&cThe file &f" + file.getName() + "&c doesn't exist!");
return;
}
Futures.onMainThread(plugin, manager.findExpansionInFile(file), (clazz, exception) -> {
if (exception != null) {
sender.sendMessage(Message.raw("Failed to find expansion in file: ").color(Color.RED).insert(Message.raw(file.toString()).color(Color.WHITE)));
// Msg.msg(sender,
// "&cFailed to find expansion in file: &f" + file);
plugin.getLogger()
.atWarning().log("failed to find expansion in file: " + file, exception);
return;
}
if (clazz == null) {
sender.sendMessage(Message.raw("No expansion class found in file: ").color(Color.RED).insert(Message.raw(file.toString()).color(Color.WHITE)));
// Msg.msg(sender,
// "&cNo expansion class found in file: &f" + file);
return;
}
final Optional<PlaceholderExpansion> expansion = manager.register(clazz);
if (!expansion.isPresent()) {
sender.sendMessage(Message.raw("Failed to register expansion from ").color(Color.RED).insert(Message.raw(params.getFirst()).color(Color.WHITE)));
// Msg.msg(sender,
// "&cFailed to register expansion from &f" + params.get(0));
return;
}
sender.sendMessage(Message.raw("Sucessfully registered expansion: ").color(Color.GREEN).insert(Message.raw(expansion.get().getName()).color(Color.WHITE)));
// Msg.msg(sender,
// "&aSuccessfully registered expansion: &f" + expansion.get().getName());
});
}
// @Override
// public void complete(@NotNull final PlaceholderAPIPlugin plugin,
// @NotNull final CommandSender sender, @NotNull final String alias,
// @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
// if (params.size() > 1) {
// return;
// }
//
// final String[] fileNames = plugin.getLocalExpansionManager().getExpansionsFolder()
// .list((dir, name) -> name.endsWith(".jar"));
// if (fileNames == null || fileNames.length == 0) {
// return;
// }
//
// suggestByParameter(Arrays.stream(fileNames), suggestions,
// params.isEmpty() ? null : params.get(0));
// }
}

View File

@@ -1,86 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.local;
import java.awt.*;
import java.util.List;
import java.util.Optional;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandExpansionUnregister extends PlaceholderCommand {
public CommandExpansionUnregister() {
super("unregister");
setPermissions("placeholderapi.admin", "placeholderapi.unregister");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
if (params.isEmpty()) {
sender.sendMessage(Message.raw("You must specify the name of the expansion.").color(Color.RED));
// Msg.msg(sender,
// "&cYou must specify the name of the expansion.");
return;
}
final Optional<PlaceholderExpansion> expansion = plugin.localExpansionManager()
.findExpansionByName(params.get(0));
if (!expansion.isPresent()) {
sender.sendMessage(Message.raw("There is no expansion loaded with the identifier: ").color(Color.RED).insert(Message.raw(params.getFirst()).color(Color.WHITE)));
// Msg.msg(sender,
// "&cThere is no expansion loaded with the identifier: &f" + params.get(0));
return;
}
// final String message = !expansion.get().unregister() ?
// "&cFailed to unregister expansion: &f" :
// "&aSuccessfully unregistered expansion: &f";
final Message message = !expansion.get().unregister() ?
Message.raw("Failed to unregister expansion: ").color(Color.RED) :
Message.raw("Successfully unregistered expansion: ").color(Color.GREEN);
sender.sendMessage(message.insert(Message.raw(expansion.get().getName()).color(Color.WHITE)));
// sender.sendMessage(Message.raw(message + exp));
// Msg.msg(sender, message + expansion.get().getName());
}
// @Override
// public void complete(@NotNull final PlaceholderAPIPlugin plugin,
// @NotNull final CommandSender sender, @NotNull final String alias,
// @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
// if (params.size() > 1) {
// return;
// }
//
// suggestByParameter(PlaceholderAPI.getRegisteredIdentifiers().stream(), suggestions,
// params.isEmpty() ? null : params.get(0));
// }
}

View File

@@ -1,112 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.local;
import java.awt.*;
import java.util.List;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import com.hypixel.hytale.common.plugin.PluginManifest;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandHelp extends PlaceholderCommand {
public CommandHelp() {
super("help");
setPermissions("placeholderapi.admin", "placeholderapi.help");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
final PluginManifest description = plugin.getManifest();
// final PluginDescriptionFile description = plugin.getDescription();
final Message message = Message.raw("PlaceholderAPI ").color(Color.CYAN).bold(true)
.insert(Message.raw("- ").color(Color.DARK_GRAY).bold(false))
.insert(Message.raw("Help Menu ").color(Color.WHITE).bold(false))
.insert(Message.raw("- ").color(Color.DARK_GRAY).bold(false))
.insert(Message.raw("(").color(Color.GRAY).bold(false))
.insert(Message.raw(description.getVersion().toString()).color(Color.WHITE).bold(false))
.insert(Message.raw(")").color(Color.GRAY).bold(false))
.insert(Message.raw("\n"))
.insert(genCommandMsg("bcparse", "<me|--null|player name> <message>", "Parse a message with placeholders and broadcast it"))
.insert(genCommandMsg("cmdparse", "<me|player> <command with placeholders>", "Parse a message with relational placeholders"))
.insert(genCommandMsg("dump", null, "Dump all relevant information needed to help debug issues into a paste link."))
.insert(genCommandMsg("info", "<placeholder name>", "View information for a specific expansion"))
.insert(genCommandMsg("list", null, "List active expansions"))
.insert(genCommandMsg("parse", "<me|--null|player name> <message>", "Parse a message with placeholders"))
.insert(genCommandMsg("parserel", "<player one> <player two> <message>", "Parse a message with relational placeholders"))
.insert(genCommandMsg("register", "<file name>", "Register an expansion by the name of the file"))
.insert(genCommandMsg("reload", null, "Reload the config of PAPI"))
.insert(genCommandMsg("unregister", "<expansion name>", "Unregister an expansion by name"))
.insert(genCommandMsg("version", null, "View plugin info/version"));
sender.sendMessage(message);
// Msg.msg(sender,
// "&b&lPlaceholderAPI &8- &7Help Menu &8- &7(&f" + description.getVersion() + "&7)",
// " ",
// "&b/papi &fbcparse &9<me|--null|player name> <message>",
// " &7&oParse a message with placeholders and broadcast it",
// "&b/papi &fcmdparse &9<me|player> <command with placeholders>",
// " &7&oParse a message with relational placeholders",
// "&b/papi &fdump",
// " &7&oDump all relevant information needed to help debug issues into a paste link.",
// "&b/papi &finfo &9<placeholder name>",
// " &7&oView information for a specific expansion",
// "&b/papi &flist",
// " &7&oList active expansions",
// "&b/papi &fparse &9<me|--null|player name> <message>",
// " &7&oParse a message with placeholders",
// "&b/papi &fparserel &9<player one> <player two> <message>",
// " &7&oParse a message with relational placeholders",
// "&b/papi &fregister &9<file name>",
// " &7&oRegister an expansion by the name of the file",
// "&b/papi &freload",
// " &7&oReload the config of PAPI",
// "&b/papi &funregister &9<expansion name>",
// " &7&oUnregister an expansion by name",
// "&b/papi &fversion",
// " &7&oView plugin info/version");
}
private Message genCommandMsg(@NotNull final String command, @Nullable final String arguments,
@NotNull final String description) {
Message message = Message.raw("\n/papi ").color(Color.CYAN)
.insert(Message.raw(command).color(Color.WHITE));
if (arguments != null) {
message = message.insert(" " + arguments).color(Color.CYAN);
}
return message
.insert(Message.raw("\n " + description).color(Color.gray).bold(false));
}
}

View File

@@ -1,130 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.local;
import java.awt.*;
import java.util.List;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandInfo extends PlaceholderCommand {
public CommandInfo() {
super("info");
setPermissions("placeholderapi.admin", "placeholderapi.info");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
if (params.isEmpty()) {
sender.sendMessage(Message.raw("You must specify the name of the expansion.").color(Color.RED));
// Msg.msg(sender,
// "&cYou must specify the name of the expansion.");
return;
}
final PlaceholderExpansion expansion = plugin.localExpansionManager()
.findExpansionByIdentifier(params.get(0)).orElse(null);
if (expansion == null) {
sender.sendMessage(Message.raw("There is no expansion loaded with the identifier: ").color(Color.RED).insert(Message.raw(params.getFirst()).color(Color.WHITE)));
// Msg.msg(sender,
// "&cThere is no expansion loaded with the identifier: &f" + params.get(0));
return;
}
Message message = Message.empty()
.insert(Message.raw("Placeholder expansion info for:").color(Color.GRAY))
.insert(Message.raw(expansion.getName() + "\n").color(Color.WHITE))
.insert(Message.raw("Status: ").color(Color.GRAY))
.insert(Message.raw(expansion.isRegistered() ? "Registered" : "Not Registered").color(expansion.isRegistered() ? Color.GREEN : Color.RED))
.insert("\n");
final String author = expansion.getAuthor();
if (author != null) {
message = message.insert(Message.raw("Author: ").color(Color.GRAY))
.insert(Message.raw(author + "\n").color(Color.WHITE));
// builder.append("&7Author: &r")
// .append(author)
// .append('\n');
}
final String version = expansion.getVersion();
if (version != null) {
message = message.insert(Message.raw("Version: ").color(Color.GRAY))
.insert(Message.raw(version + "\n").color(Color.WHITE));
// builder.append("&7Version: &r")
// .append(version)
// .append('\n');
}
final String requiredPlugin = expansion.getRequiredPlugin();
if (requiredPlugin != null) {
message = message.insert(Message.raw("Requires plugin: ").color(Color.GRAY))
.insert(Message.raw(requiredPlugin + '\n').color(Color.WHITE));
// builder.append("&7Requires plugin: &r")
// .append(requiredPlugin)
// .append('\n');
}
final List<String> placeholders = expansion.getPlaceholders();
if (placeholders != null && !placeholders.isEmpty()) {
message = message.insert(Message.raw("-- ").color(Color.DARK_GRAY))
.insert(Message.raw("Placeholders ").color(Color.GRAY))
.insert(Message.raw("--\n").color(Color.DARK_GRAY));
// builder.append("&8&m-- &7Placeholders &8&m--&r")
// .append('\n');
for (final String placeholder : placeholders) {
message = message.insert(Message.raw(placeholder + "\n").color(Color.WHITE));
// builder.append(placeholder)
// .append('\n');
}
}
sender.sendMessage(message);
// Msg.msg(sender, builder.toString());
}
// @Override
// public void complete(@NotNull final PlaceholderAPIPlugin plugin,
// @NotNull final CommandSender sender, @NotNull final String alias,
// @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
// if (params.size() > 1) {
// return;
// }
//
// suggestByParameter(PlaceholderAPI.getRegisteredIdentifiers().stream(), suggestions,
// params.isEmpty() ? null : params.get(0));
// }
}

View File

@@ -1,89 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.local;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import at.helpch.placeholderapi.PlaceholderAPI;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandList extends PlaceholderCommand {
public CommandList() {
super("list");
setPermissions("placeholderapi.admin", "placeholderapi.list");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
final List<String> identifiers = new ArrayList<>(PlaceholderAPI.getRegisteredIdentifiers());
if (identifiers.isEmpty()) {
sender.sendMessage(Message.raw("There are no placeholder hooks active!").color(Color.RED));
// Msg.msg(sender, "&cThere are no placeholder hooks active!");
return;
}
final List<List<String>> partitions = new ArrayList<>(IntStream.range(0, identifiers.size()).boxed().collect(Collectors.groupingBy(i -> i/10, Collectors.mapping(identifiers::get, Collectors.toList()))).values());
// final List<List<String>> partitions = Lists
// .partition(identifiers.stream().sorted().collect(Collectors.toList()), 10);
Message message = Message.raw("A total of ").color(Color.GRAY)
.insert(Message.raw(identifiers.size() + " ").color(Color.WHITE))
.insert(Message.raw("placeholder hook(s) are active: ").color(Color.GRAY));
for (int i = 0; i < partitions.size(); ++i) {
final List<String> partition = partitions.get(i);
for (int j = 0; j < partition.size(); ++j) {
message = message.insert(Message.raw(partition.get(j)).color(Color.GREEN));
if (j != partition.size() - 1) {
message = message.insert(Message.raw(", ").color(Color.GRAY));
}
}
if (i != partitions.size() - 1) {
message = message.insert(Message.raw("\n"));
}
}
sender.sendMessage(message);
// Msg.msg(sender,
// "&7A total of &f" + identifiers.size() + "&7 placeholder hook(s) are active: &a",
// partitions.stream().map(partition -> String.join("&7, &a", partition))
// .collect(Collectors.joining("\n")));
}
}

View File

@@ -1,279 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.local;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.stream.Stream;
import at.helpch.placeholderapi.PlaceholderAPI;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.NameMatching;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.Universe;
import com.hypixel.hytale.server.core.universe.world.World;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandParse extends PlaceholderCommand {
public CommandParse() {
super("parse", "bcparse", "parserel", "cmdparse");
setPermissions("placeholderapi.admin", "placeholderapi.parse");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
final Runnable logic = () -> {
switch (alias.toLowerCase(Locale.ROOT)) {
case "parserel":
evaluateParseRelation(sender, params);
break;
case "parse":
evaluateParseSingular(sender, params, false, false);
break;
case "bcparse":
evaluateParseSingular(sender, params, true, false);
break;
case "cmdparse":
evaluateParseSingular(sender, params, false, true);
break;
};
};
final World world;
if (sender instanceof Player) {
world = ((Player) sender).getWorld();
} else if (sender instanceof PlayerRef) {
UUID uuid = ((PlayerRef) sender).getWorldUuid();
world = uuid == null ? Universe.get().getDefaultWorld() : Universe.get().getWorld(uuid);
} else {
world = Universe.get().getDefaultWorld();
}
if (world != null) {
world.execute(logic);
} else {
logic.run();
}
}
private void evaluateParseSingular(@NotNull final CommandSender sender,
@NotNull @Unmodifiable final List<String> params, final boolean broadcast,
final boolean command) {
if (params.size() < 2) {
sender.sendMessage(Message.raw("You must provide a target and a message: ").color(Color.RED)
.insert(Message.raw("/papi ").color(Color.CYAN))
.insert(Message.raw(command ? "cmdparse" : (broadcast ? "bcparse" : "parse")).color(Color.CYAN))
.insert(Message.raw(" {target}").color(Color.GRAY))
.insert(Message.raw(" {message}").color(Color.GREEN)));
return;
}
PlayerRef player;
if ("me".equalsIgnoreCase(params.getFirst())) {
if (!(sender instanceof Player) && !(sender instanceof PlayerRef)) {
sender.sendMessage(Message.raw("You must be a player to use ").color(Color.RED).insert(Message.raw("me").color(Color.GRAY)).insert(Message.raw(" as a target!").color(Color.RED)));
return;
}
if (sender instanceof Player) {
player = ((Player) sender).getPlayerRef();
} else {
player = (PlayerRef) sender;
}
} else if ("--null".equalsIgnoreCase(params.get(0))) {
player = null;
} else {
final PlayerRef target = resolvePlayer(params.get(0));
if (target == null) {
sender.sendMessage(Message.raw("Failed to find player: ").color(Color.RED).insert(Message.raw(params.get(0)).color(Color.WHITE)));
return;
}
player = target;
}
final String message = PlaceholderAPI
.setPlaceholders(player, String.join(" ", params.subList(1, params.size())));
if (command) {
sender.sendMessage(Message.raw("To be implemented")); // todo: implement
return;
}
if (broadcast) {
Universe.get().sendMessage(Message.raw(message));
} else {
sender.sendMessage(Message.raw(message));
}
}
private void evaluateParseRelation(@NotNull final CommandSender sender,
@NotNull @Unmodifiable final List<String> params) {
if (params.size() < 3) {
sender.sendMessage(Message.raw("You must supply two targets, and a message: ").color(Color.RED)
.insert(Message.raw("/papi parserel ").color(Color.CYAN))
.insert(Message.raw("{target one} {target two} ").color(Color.GRAY))
.insert(Message.raw("{message}").color(Color.GREEN)));
return;
}
PlayerRef playerOne;
if ("me".equalsIgnoreCase(params.get(0))) {
if (!(sender instanceof Player) && !(sender instanceof PlayerRef)) {
sender.sendMessage(Message.raw("You must be a player to use ").color(Color.RED)
.insert(Message.raw("me").color(Color.GRAY))
.insert(Message.raw(" as a target!").color(Color.RED)));
return;
}
if (sender instanceof Player) {
playerOne = ((Player) sender).getPlayerRef();
} else {
playerOne = (PlayerRef) sender;
}
} else {
playerOne = resolvePlayer(params.get(0));
}
if (playerOne == null) {
sender.sendMessage(Message.raw("Failed to find player: ").color(Color.RED).insert(Message.raw(params.get(0)).color(Color.WHITE)));
return;
}
PlayerRef playerTwo;
if ("me".equalsIgnoreCase(params.get(1))) {
if (!(sender instanceof Player) && !(sender instanceof PlayerRef)) {
sender.sendMessage(Message.raw("You must be a player to use ").color(Color.RED).insert(Message.raw("me").color(Color.GRAY)).insert(Message.raw(" as a target!").color(Color.RED)));
return;
}
if (sender instanceof Player) {
playerTwo = ((Player) sender).getPlayerRef();
} else {
playerTwo = (PlayerRef) sender;
}
} else {
playerTwo = resolvePlayer(params.get(1));
}
if (playerTwo == null) {
sender.sendMessage(Message.raw("Failed to find player: ").color(Color.RED).insert(Message.raw(params.get(1)).color(Color.WHITE)));
return;
}
final String message = PlaceholderAPI
.setRelationalPlaceholders(playerOne, playerTwo,
String.join(" ", params.subList(2, params.size())));
sender.sendMessage(Message.raw(message));
}
private void completeParseSingular(@NotNull final CommandSender sender,
@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
if (params.size() <= 1) {
if (sender instanceof Player && (params.isEmpty() || "me"
.startsWith(params.get(0).toLowerCase(Locale.ROOT)))) {
suggestions.add("me");
}
if ("--null".startsWith(params.get(0).toLowerCase(Locale.ROOT))) {
suggestions.add("--null");
}
final Stream<String> names = Universe.get().getPlayers().stream().map(PlayerRef::getUsername);
suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0));
return;
}
final String name = params.get(params.size() - 1);
if (!name.startsWith("%") || name.endsWith("%")) {
return;
}
final int index = name.indexOf('_');
if (index == -1) {
return; // no arguments supplied yet
}
final PlaceholderExpansion expansion = PlaceholderAPIPlugin.instance()
.localExpansionManager().findExpansionByIdentifier(name.substring(1, index))
.orElse(null);
if (expansion == null) {
return;
}
final Set<String> possible = new HashSet<>(expansion.getPlaceholders());
PlaceholderAPIPlugin.instance()
.cloudExpansionManager()
.findCloudExpansionByName(expansion.getName())
.ifPresent(cloud -> possible.addAll(cloud.getPlaceholders()));
suggestByParameter(possible.stream(), suggestions, params.get(params.size() - 1));
}
// private void completeParseRelation(@NotNull @Unmodifiable final List<String> params,
// @NotNull final List<String> suggestions) {
// if (params.size() > 2) {
// return;
// }
//
// final Stream<String> names = Bukkit.getOnlinePlayers().stream().map(Player::getName);
// suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(params.size() - 1));
// }
@Nullable
private PlayerRef resolvePlayer(@NotNull final String name) {
// Player target = Universe.get().getPlayerByUsername(name, NameMatching.EXACT);
// final Optional<Player> target = world.getPlayers().stream().filter(player -> player.getDisplayName().equals(name)).findAny();
//
// if (target.isEmpty()) {
// // Not the best option, but Spigot doesn't offer a good replacement (as usual)
//// target = Bukkit.getOfflinePlayer(name);
////
//// return target.hasPlayedBefore() ? target : null;
// return null;
// }
//
// return target.get();
return Universe.get().getPlayerByUsername(name, NameMatching.EXACT);
}
}

View File

@@ -1,45 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.local;
import java.util.List;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandReload extends PlaceholderCommand {
public CommandReload() {
super("reload");
setPermissions("placeholderapi.admin", "placeholderapi.reload");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
plugin.reloadPlugin(sender);
}
}

View File

@@ -1,71 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.commands.impl.local;
import java.awt.*;
import java.util.List;
import java.util.stream.Collectors;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.commands.PlaceholderCommand;
import com.hypixel.hytale.common.plugin.AuthorInfo;
import com.hypixel.hytale.common.plugin.PluginManifest;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandVersion extends PlaceholderCommand {
public CommandVersion() {
super("version");
setPermissions("placeholderapi.admin", "placeholderapi.version");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
final PluginManifest description = plugin.getManifest();
sender.sendMessage(Message.empty()
.insert(Message.raw("PlaceholderAPI ").color(Color.CYAN).bold(true))
.insert(Message.raw("(").color(Color.GRAY))
.insert(Message.raw(description.getVersion().toString()).color(Color.WHITE))
.insert(Message.raw(")").color(Color.GRAY))
.insert(Message.raw("\nAuthor: ").color(Color.GRAY))
.insert(Message.raw(description.getAuthors().stream().map(AuthorInfo::getName).collect(Collectors.joining(", "))).color(Color.WHITE))
.insert(Message.raw("\nPAPI Commands: ").color(Color.GRAY))
.insert(Message.raw("/papi ").color(Color.CYAN))
.insert(Message.raw("help").color(Color.WHITE))
.insert(Message.raw("\neCloud Commands: ").color(Color.GRAY))
.insert(Message.raw("/papi ").color(Color.CYAN))
.insert(Message.raw("ecloud").color(Color.WHITE)));
// Msg.msg(sender,
// "&b&lPlaceholderAPI &7(&f" + description.getVersion() + "&7)",
// "&7Author: &f" + description.getAuthors().stream().map(AuthorInfo::getName).collect(Collectors.joining(", ")),
// "&7PAPI Commands: &b/papi &fhelp",
// "&7eCloud Commands&8: &b/papi &fecloud");
}
}

View File

@@ -1,6 +0,0 @@
package at.helpch.placeholderapi.configuration;
import org.jetbrains.annotations.NotNull;
public record BooleanValue(@NotNull String trueValue, @NotNull String falseValue) {
}

View File

@@ -1,128 +0,0 @@
package at.helpch.placeholderapi.configuration;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;
public final class ConfigManager {
private static final Yaml YAML;
private static final Gson GSON = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create();
// .registerTypeAdapter()
private static final Pattern LINE_DELIMITER = Pattern.compile("\n");
static {
final DumperOptions options = new DumperOptions();
options.setPrettyFlow(true);
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
YAML = new Yaml(options);
}
private final JavaPlugin main;
private final HytaleLogger logger;
private PlaceholderAPIConfig config;
public ConfigManager(@NotNull final JavaPlugin main) {
this.main = main;
this.logger = main.getLogger();
}
public void setup() {
final String content;
try {
final Path file = createFile("/config.yml", main.getDataDirectory().toString() + "/config.yml");
if (file != null) {
content = Files.readString(file);
} else {
return;
}
} catch (Exception e) {
e.printStackTrace();
return;
}
final Map<String, Object> data = YAML.load(content);
config = GSON.fromJson(GSON.toJsonTree(data), PlaceholderAPIConfig.class);
}
public PlaceholderAPIConfig config() {
return config;
}
public void save() {
try {
final Map<String, Object> map = GSON.fromJson(GSON.toJsonTree(config), new TypeToken<Map<String, Object>>(){}.getType());
final String yaml = YAML.dump(map);
final Path path = Paths.get(main.getDataDirectory().toString() + "/config.yml");
Files.write(path, Arrays.asList(LINE_DELIMITER.split(yaml)), StandardCharsets.UTF_8, StandardOpenOption.TRUNCATE_EXISTING);
} catch (Exception e) {
logger.atSevere().log("Something went wrong when saving config.yml: ", e);
}
}
@NotNull
public <T> T convertExpansion(@NotNull final Map<String, Object> expansionConfig, @NotNull final Class<T> type) {
return GSON.fromJson(GSON.toJsonTree(expansionConfig), type);
}
@Nullable
private Path createFile(@NotNull final String internalPath, @NotNull final String externalPath) {
final Path file = Paths.get(externalPath);
if (Files.exists(file)) {
return file;
}
final Optional<Path> parent = Optional.ofNullable(file.getParent());
try {
if (parent.isPresent()) {
Files.createDirectories(parent.get());
}
Files.createFile(file);
} catch (IOException e) {
logger.atSevere().log("Something went wrong when trying to create ", file);
return null;
}
if (exportResource(internalPath, externalPath)) {
return file;
}
return null;
}
private boolean exportResource(@NotNull final String internalPath, @NotNull final String externalPath) {
try {
Files.copy(PlaceholderAPIPlugin.class.getResourceAsStream(internalPath), Paths.get(externalPath),
StandardCopyOption.REPLACE_EXISTING);
return true;
} catch (Exception e) {
logger.atSevere().log("Something went wrong when moving internal: ", internalPath, " to ", externalPath);
}
return false;
}
}

View File

@@ -1,48 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.configuration;
import java.util.Comparator;
import at.helpch.placeholderapi.expansion.cloud.CloudExpansion;
import org.jetbrains.annotations.NotNull;
public enum ExpansionSort implements Comparator<CloudExpansion> {
NAME(Comparator.comparing(CloudExpansion::getName)),
AUTHOR(Comparator.comparing(CloudExpansion::getAuthor)),
LATEST(Comparator.comparing(CloudExpansion::getLastUpdate).reversed());
@NotNull
private final Comparator<CloudExpansion> comparator;
ExpansionSort(@NotNull final Comparator<CloudExpansion> comparator) {
this.comparator = comparator;
}
@Override
public final int compare(final CloudExpansion expansion1, final CloudExpansion expansion2) {
return comparator.compare(expansion1, expansion2);
}
}

View File

@@ -1,107 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.configuration;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
public final class PlaceholderAPIConfig {
private boolean cloudEnabled;
private boolean debugMode;
private ExpansionSort cloudSorting;
private BooleanValue booleanValue;
private String dateFormat;
private Map<String, Object> expansions;
public PlaceholderAPIConfig(boolean cloudEnabled, boolean debugMode, @NotNull ExpansionSort cloudSorting,
@NotNull BooleanValue booleanValue, @NotNull String dateFormat) {
this.cloudEnabled = cloudEnabled;
this.debugMode = debugMode;
this.cloudSorting = cloudSorting;
this.booleanValue = booleanValue;
this.dateFormat = dateFormat;
this.expansions = new HashMap<>();
}
public PlaceholderAPIConfig(boolean cloudEnabled, boolean debugMode, @NotNull ExpansionSort cloudSorting,
@NotNull BooleanValue booleanValue, @NotNull String dateFormat, Map<String, Object> expansions) {
this.cloudEnabled = cloudEnabled;
this.debugMode = debugMode;
this.cloudSorting = cloudSorting;
this.booleanValue = booleanValue;
this.dateFormat = dateFormat;
this.expansions = expansions;
}
public boolean cloudEnabled() {
return cloudEnabled;
}
public void cloudEnabled(final boolean value) {
cloudEnabled = value;
}
public boolean debugMode() {
return debugMode;
}
public void debugMode(final boolean value) {
debugMode = value;
}
@NotNull
public ExpansionSort cloudSorting() {
return cloudSorting;
}
public void cloudSorting(@NotNull final ExpansionSort value) {
cloudSorting = value;
}
@NotNull
public BooleanValue booleanValue() {
return booleanValue;
}
public void booleanValue(@NotNull final BooleanValue value) {
booleanValue = value;
}
@NotNull
public String dateFormat() {
return dateFormat;
}
public void dateFormat(@NotNull final String value) {
dateFormat = value;
}
@NotNull
public Map<String, Object> expansions() {
return expansions;
}
public void expansions(@NotNull final Map<String, Object> value) {
expansions = value;
}
}

View File

@@ -1,74 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.events;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import com.hypixel.hytale.event.ICancellable;
import com.hypixel.hytale.event.IEvent;
import org.jetbrains.annotations.NotNull;
/**
* This event indicates that a <b>single</b> {@link PlaceholderExpansion PlaceholderExpansion} has
* been registered in PlaceholderAPI.
*
* <p>To know when <b>all</b> Expansions have been registered, use the
* {@link at.helpch.placeholderapi.events.ExpansionsLoadedEvent ExpansionsLoadedEvent} instead.
*/
public final class ExpansionRegisterEvent implements IEvent<Void>, ICancellable {
@NotNull
private final PlaceholderExpansion expansion;
private boolean cancelled;
public ExpansionRegisterEvent(@NotNull final PlaceholderExpansion expansion) {
this.expansion = expansion;
}
/**
* The {@link PlaceholderExpansion PlaceholderExpansion} that was registered in PlaceholderAPI.
* <br>The PlaceholderExpansion will be available for use when the event
* {@link #isCancelled() was not cancelled}!
*
* @return Current instance of the registered {@link PlaceholderExpansion PlaceholderExpansion}
*/
@NotNull
public PlaceholderExpansion getExpansion() {
return expansion;
}
/**
* Indicates if this event was cancelled or not.
* <br>A cancelled Event will result in the {@link #getExpansion() PlaceholderExpansion} NOT
* being added to PlaceholderAPI's internal list and will therefore be considered not registered
* anymore.
*
* @return Whether the event has been cancelled or not.
*/
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@@ -1,54 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.events;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import com.hypixel.hytale.event.IEvent;
import org.jetbrains.annotations.NotNull;
/**
* This event indicates that a {@link PlaceholderExpansion PlaceholderExpansion} has been
* unregistered by PlaceholderAPI.
*
* <p>Note that this event is triggered <b>before</b> the PlaceholderExpansion is completely
* removed.
* <br>This includes removing any Listeners, stopping active tasks and clearing the cache of
* the PlaceholderExpansion.
*/
public final class ExpansionUnregisterEvent implements IEvent<ExpansionUnregisterEvent> {
@NotNull
private final PlaceholderExpansion expansion;
public ExpansionUnregisterEvent(@NotNull final PlaceholderExpansion expansion) {
this.expansion = expansion;
}
/**
* The {@link PlaceholderExpansion PlaceholderExpansion} that was unregistered.
*
* @return The {@link PlaceholderExpansion PlaceholderExpansion} instance.
*/
@NotNull
public PlaceholderExpansion getExpansion() {
return expansion;
}
}

View File

@@ -1,59 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.events;
import java.util.Collections;
import java.util.List;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import com.hypixel.hytale.event.IEvent;
import org.jetbrains.annotations.NotNull;
/**
* This event indicated that <b>all</b> {@link PlaceholderExpansion PlaceholderExpansions} have
* been registered in PlaceholderAPI and can now be used.
* <br>This even will also be triggered whenever PlaceholderAPI gets reloaded.
*
* <p>All PlaceholderExpansions, except for those loaded by plugins, are loaded
* after Spigot triggered its ServerLoadEvent (1.13+), or after PlaceholderAPI has been enabled.
*/
public class ExpansionsLoadedEvent implements IEvent<ExpansionsLoadedEvent> {
private final List<PlaceholderExpansion> expansions;
public ExpansionsLoadedEvent(List<PlaceholderExpansion> expansions) {
this.expansions = Collections.unmodifiableList(expansions);
}
/**
* Returns a unmodifiable list of {@link PlaceholderExpansion PlaceholderExpansions} that
* have been registered by PlaceholderAPI.
*
* <p><b>This list does not include manually registered PlaceholderExpansions.</b>
*
* @return List of {@link PlaceholderExpansion registered PlaceholderExpansions}.
*/
@NotNull
public final List<PlaceholderExpansion> getExpansions() {
return expansions;
}
}

View File

@@ -1,29 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.exceptions;
public final class NoDefaultCommandException extends RuntimeException {
public NoDefaultCommandException(final String message) {
super(message);
}
}

View File

@@ -1,38 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.expansion;
/**
* Classes implementing this interface will have a {@link #clear() clear void} that is called
* by PlaceholderAPI whenever the {@link at.helpch.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansion}
* is unregistered.
*
* <p>This allows you to execute things such as clearing internal caches, saving data to files, etc.
*
* @author Ryan McCarthy
*/
public interface Cacheable {
/**
* Called when the implementing class is unregistered from PlaceholderAPI
*/
void clear();
}

View File

@@ -1,42 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.expansion;
import com.hypixel.hytale.server.core.universe.PlayerRef;
/**
* Classes implementing this interface will have a {@link #cleanup(PlayerRef) cleanup void} that is
* called by PlaceholderAPI whenever a Player leaves the server.
*
* <p>This can be useful for cases where you keep data of the player in a cache or similar
* and want to free up space whenever they leave.
*
* @author Ryan McCarthy
*/
public interface Cleanable {
/**
* Called when a player leaves the server
*
* @param p (@link Player} who left the server
*/
void cleanup(PlayerRef p);
}

View File

@@ -1,63 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.expansion;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
/**
* Implementing this interface allows {@link at.helpch.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansions}
* allows you to map an object to a section of yaml in the main config.yml.
*
* <p>The entries will be added under {@code expansions} as their own section.
* <h2>Example:</h2>
*
* <pre><code>
* expansions:
* myexpansion:
* foo: "bar"
* </code></pre>
*
* <p><b>The configuration is set before the PlaceholderExpansion is registered!</b>
*
* @author Ryan McCarthy
*/
public interface Configurable<T> {
@NotNull
Class<T> provideConfigType();
@NotNull
T provideDefault();
// /**
// * The map returned by this method will be used to set config options in PlaceholderAPI's config.yml.
// *
// * <p>The key and value pairs are set under a section named after your
// * {@link at.helpch.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansion} in the
// * {@code expansions} section of the config.
// *
// * @return Map of config path / values which need to be added / removed from the PlaceholderAPI
// * config.yml file
// */
// Map<String, Object> getDefaults();
}

View File

@@ -1,546 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.expansion;
import java.util.*;
import java.util.logging.Level;
import java.util.regex.Pattern;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import at.helpch.placeholderapi.PlaceholderHook;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.HytaleServer;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.plugin.PluginBase;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Any class extending this will be able to get registered as a PlaceholderExpansion.
* <br>The registration either happens automatically when the jar file containing a
* class extending this one is located under the {@code PlaceholderAPI/expansions}
* directory or when the {@link #register()} method is called by said class.
*/
public abstract class PlaceholderExpansion implements PlaceholderHook {
private static final Pattern PATH_DELIMITER = Pattern.compile(".");
/**
* The type is {@link Type#INTERNAL} by default.
* For external expansions, the type is updated on {@link at.helpch.placeholderapi.expansion.manager.LocalExpansionManager#register(Class) register}.
*
* @since 2.11.4
*/
@ApiStatus.Internal
protected Type expansionType = Type.INTERNAL;
/**
* The placeholder identifier of this expansion. May not contain {@literal %},
* {@literal {}} or _
*
* @return placeholder identifier that is associated with this expansion
*/
@NotNull
public abstract String getIdentifier();
/**
* The author of this expansion
*
* @return name of the author for this expansion
*/
@NotNull
public abstract String getAuthor();
/**
* The version of this expansion
*
* @return current version of this expansion
*/
@NotNull
public abstract String getVersion();
/**
* The name of this expansion
*
* @return {@link #getIdentifier()} by default, name of this expansion if specified
*/
@NotNull
public String getName() {
return getIdentifier();
}
/**
* The name of the plugin that this expansion hooks into. by default will null
*
* @return plugin name that this expansion requires to function
*/
@Nullable
public String getRequiredPlugin() {
return getPlugin();
}
/**
* The placeholders associated with this expansion
*
* @return placeholder list that this expansion provides
*/
@NotNull
public List<String> getPlaceholders() {
return Collections.emptyList();
}
/**
* Expansions that do not use the ecloud and instead register from the dependency should set this
* to true to ensure that your placeholder expansion is not unregistered when the papi reload
* command is used
*
* @return if this expansion should persist through placeholder reloads
*/
public boolean persist() {
return false;
}
/**
* Check if this placeholder identifier has already been registered
*
* @return true if the identifier for this expansion is already registered
*/
public final boolean isRegistered() {
return getPlaceholderAPI().localExpansionManager().findExpansionByIdentifier(getIdentifier())
.map(it -> it.equals(this)).orElse(false);
}
/**
* If any requirements need to be checked before this expansion should register, you can check
* them here
*
* @return true if this hook meets all the requirements to register
*/
public boolean canRegister() {
return getRequiredPlugin() == null
|| HytaleServer.get().getPluginManager().getPlugins().stream().map(PluginBase::getName).anyMatch(getRequiredPlugin()::equals);
}
/**
* Attempt to register this PlaceholderExpansion
*
* @return true if this expansion is now registered with PlaceholderAPI
*/
public boolean register() {
return getPlaceholderAPI().localExpansionManager().register(this);
}
/**
* Attempt to unregister this PlaceholderExpansion
*
* @return true if this expansion is now unregistered with PlaceholderAPI
*/
public final boolean unregister() {
return getPlaceholderAPI().localExpansionManager().unregister(this);
}
/**
* Quick getter for the {@link PlaceholderAPIPlugin} instance
*
* @return {@link PlaceholderAPIPlugin} instance
*/
@NotNull
public final PlaceholderAPIPlugin getPlaceholderAPI() {
return PlaceholderAPIPlugin.instance();
}
/**
* Get the type of the expansion
*
* @return the type of the expansion
* @since 2.11.4
*/
@ApiStatus.Internal
public Type getExpansionType() {
return expansionType;
}
/**
* Set the type of the expansion
*
* @param expansionType the new type
* @since 2.11.4
*/
@ApiStatus.Internal
public void setExpansionType(Type expansionType) {
this.expansionType = expansionType;
}
// === Configuration ===
// /**
// * Gets the ConfigurationSection of the expansion located in the config.yml of PlaceholderAPI or
// * null when not specified.
// * <br>You may use the {@link Configurable} interface to define default values set
// *
// * @return ConfigurationSection that this expansion has.
// */
// @NotNull
// public final Map<String, Object> getExpansionConfig() {
// return (Map<String, Object>) getPlaceholderAPI().configManager().config().expansions().getOrDefault(getIdentifier(), new HashMap<>());
// }
@Nullable
public final <T> T getExpansionConfig(@NotNull final Class<? extends Configurable<T>> configurableType) {
return (T) getPlaceholderAPI().configManager().config().expansions().getOrDefault(getIdentifier(), null);
}
// /**
// * Gets the ConfigurationSection relative to the {@link #getConfigSection() default one} set
// * by the expansion or null when the default ConfigurationSection is null
// *
// * @param path The path to get the ConfigurationSection from. This is relative to the default section
// * @return ConfigurationSection relative to the default section
// */
// @Nullable
// public final ConfigurationSection getConfigSection(@NotNull final String path) {
// final ConfigurationSection section = getConfigSection();
// return section == null ? null : section.getConfigurationSection(path);
// }
// /**
// * Gets the Object relative to the config section set
// * by the expansion or the provided Default Object, when the default ConfigurationSection is null
// *
// * @param path The path to get the Object from. This is relative to the default section
// * @param def The default Object to return when the ConfigurationSection returns null
// * @return Object from the provided path or the default one provided
// */
// @Nullable
// @Contract("_, !null -> !null")
// public final Object get(@NotNull final String path, final Object def) {
// return get(new ArrayDeque<>(Arrays.asList(PATH_DELIMITER.split(path))), def, getExpansionConfig());
// }
//
// private Object get(@NotNull final Queue<String> path, final Object def, @NotNull final Map<String, Object> map) {
// if (path.size() == 1) {
// return map.getOrDefault(path.poll(), def);
// }
//
// Object obj = map.get(path.poll());
//
// if (!(obj instanceof Map<?, ?>)) {
// return def;
// }
//
// return get(path, def, (Map<String, Object>) obj);
// }
//
// /**
// * Gets the int relative to the config section set
// * by the expansion or the provided Default int, when the default ConfigurationSection is null
// *
// * @param path The path to get the int from. This is relative to the default section
// * @param def The default int to return when the ConfigurationSection returns null
// * @return int from the provided path or the default one provided
// */
// public final int getInt(@NotNull final String path, final int def) {
// final Object obj = get(path, def);
//
// if (!(obj instanceof Integer)) {
// return def;
// }
//
// return (Integer) obj;
// }
//
// /**
// * Gets the long relative to the config section set
// * by the expansion or the provided Default long, when the default ConfigurationSection is null
// *
// * @param path The path to get the long from. This is relative to the default section
// * @param def The default long to return when the ConfigurationSection returns null
// * @return long from the provided path or the default one provided
// */
// public final long getLong(@NotNull final String path, final long def) {
// final Object obj = get(path, def);
//
// if (!(obj instanceof Long) ) {
// return def;
// }
//
// return (Long) obj;
// }
//
// /**
// * Gets the double relative to the config section set
// * by the expansion or the provided Default double, when the default ConfigurationSection is null
// *
// * @param path The path to get the double from. This is relative to the default section
// * @param def The default double to return when the ConfigurationSection returns null
// * @return double from the provided path or the default one provided
// */
// public final double getDouble(@NotNull final String path, final double def) {
// final Object obj = get(path, def);
//
// if (!(obj instanceof Double) ) {
// return def;
// }
//
// return (Double) obj;
// }
//
// /**
// * Gets the String relative to the config section set
// * by the expansion or the provided Default String, when the default ConfigurationSection is null
// *
// * @param path The path to get the String from. This is relative to the default section
// * @param def The default String to return when the ConfigurationSection returns null. Can be null
// * @return String from the provided path or the default one provided
// */
// @Nullable
// @Contract("_, !null -> !null")
// public final String getString(@NotNull final String path, @Nullable final String def) {
// final Object obj = get(path, def);
//
// if (!(obj instanceof String)) {
// return def;
// }
//
// return (String) obj;
// }
//
// /**
// * Gets a String List relative to the config section set
// * by the expansion or an empty List, when the default ConfigurationSection is null
// *
// * @param path The path to get the String list from. This is relative to the default section
// * @return String list from the provided path or an empty list
// */
// @NotNull
// public final List<String> getStringList(@NotNull final String path) {
// final Object obj = get(path, new ArrayList<>());
//
// if (!(obj instanceof List<?>)) {
// return new ArrayList<>();
// }
//
// return (List<String>) obj;
// }
//
// /**
// * Gets the boolean relative to the config section set
// * by the expansion or the default boolean, when the default ConfigurationSection is null
// *
// * @param path The path to get the boolean from. This is relative to the default section
// * @param def The default boolean to return when the ConfigurationSection is null
// * @return boolean from the provided path or the default one provided
// */
// public final boolean getBoolean(@NotNull final String path, final boolean def) {
// final Object obj = get(path, def);
//
// if (!(obj instanceof Boolean)) {
// return def;
// }
//
// return (Boolean) obj;
// }
//
// /**
// * Whether the config section contains the provided path
// * or not. This will return {@code false} when either the default section is null, or doesn't
// * contain the provided path
// *
// * @param path The path to check
// * @return true when the default ConfigurationSection is not null and contains the path, false otherwise
// */
// public final boolean configurationContains(@NotNull final String path) {
// final Object obj = get(path, null);
//
// return obj == null;
// }
/**
* Logs the provided message with the provided Level in the console.
* <br>The message will be prefixed with {@link #getName() <code>[&lt;expansion name&gt;]</code>}
*
* @param level The Level at which the message should be logged with
* @param msg The message to log
*/
public void log(Level level, String msg) {
getPlaceholderAPI().getLogger().at(level).log("[" + getName() + "] " + msg);
}
/**
* Logs the provided message and Throwable with the provided Level in the console.
* <br>The message will be prefixed with {@link #getName() <code>[&lt;expansion name&gt;]</code>}
*
* @param level The Level at which the message should be logged with
* @param msg The message to log
* @param throwable The Throwable to log
*/
public void log(Level level, String msg, Throwable throwable) {
getPlaceholderAPI().getLogger().at(level).log("[" + getName() + "] " + msg, throwable);
}
/**
* Logs the provided message with Level "info".
* <br>The message will be prefixed with {@link #getName() <code>[&lt;expansion name&gt;]</code>}
*
* @param msg The message to log
*/
public void info(String msg) {
log(Level.INFO, msg);
}
/**
* Logs the provided message with Level "warning".
* <br>The message will be prefixed with {@link #getName() <code>[&lt;expansion name&gt;]</code>}
*
* @param msg The message to log
*/
public void warning(String msg) {
log(Level.WARNING, msg);
}
/**
* Logs the provided message with Level "severe" (error).
* <br>The message will be prefixed with {@link #getName() <code>[&lt;expansion name&gt;]</code>}
*
* @param msg The message to log
*/
public void severe(String msg) {
log(Level.SEVERE, msg);
}
/**
* Logs the provided message and Throwable with Level "severe" (error).
* <br>The message will be prefixed with {@link #getName() <code>[&lt;expansion name&gt;]</code>}
*
* @param msg The message to log
* @param throwable The Throwable to log
*/
public void severe(String msg, Throwable throwable) {
log(Level.SEVERE, msg, throwable);
}
/**
* Whether the provided Object is an instance of this PlaceholderExpansion.
* <br>This method will perform the following checks in order:
* <br><ul>
* <li>Checks if Object equals the class. Returns true when equal and continues otherwise</li>
* <li>Checks if the Object is an instance of a PlaceholderExpansion. Returns false if not</li>
* <li>Checks if the Object's Identifier, Author and version equal the one of this class</li>
* </ul>
*
* @param o The Object to check
* @return true or false depending on the above mentioned checks
*/
@Override
public final boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof PlaceholderExpansion)) {
return false;
}
final PlaceholderExpansion expansion = (PlaceholderExpansion) o;
return getIdentifier().equals(expansion.getIdentifier()) &&
getAuthor().equals(expansion.getAuthor()) &&
getVersion().equals(expansion.getVersion());
}
/**
* Returns a String containing the Expansion's name, author and version
*
* @return String containing name, author and version of the expansion
*/
@Override
public final String toString() {
return String.format("PlaceholderExpansion[name: '%s', author: '%s', version: '%s', type: '%s']", getName(),
getAuthor(), getVersion(), getExpansionType());
}
// === Deprecated API ===
/**
* @return The plugin name.
* @deprecated As of versions greater than 2.8.7, use {@link #getRequiredPlugin()}
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public String getPlugin() {
return null;
}
/**
* @return The description of the expansion.
* @deprecated As of versions greater than 2.8.7, use the expansion cloud to show a description
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public String getDescription() {
return null;
}
/**
* @return The link for the expansion.
* @deprecated As of versions greater than 2.8.7, use the expansion cloud to display a link
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public String getLink() {
return null;
}
public enum Type {
/**
* An expansion provided by a plugin is considered internal
*/
INTERNAL,
/**
* An expansion loaded from the expansions folder is considered external
*/
EXTERNAL
}
@Nullable
public static Player player(@NotNull final PlayerRef target) {
final Ref<EntityStore> ref = target.getReference();
if (ref == null || !ref.isValid()) {
return null;
}
final Store<EntityStore> store = ref.getStore();
return store.isInThread() ? store.getComponent(ref, Player.getComponentType()) : null;
}
}

View File

@@ -1,44 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.expansion;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.universe.PlayerRef;
/**
* Implementing this interface allows your {@link at.helpch.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansion}
* to be used as a relational placeholder expansion.
*
* <p>Relational placeholders take two Players as input and are always prefixed with {@code rel_},
* so {@code %foo_bar%} becomes {@code %rel_foo_bar%}
*/
public interface Relational {
/**
* This method is called whenever a placeholder starting with {@code rel_} is called.
*
* @param one The first player used for the placeholder.
* @param two The second player used for the placeholder.
* @param identifier The text right after the expansion's name (%expansion_<b>identifier</b>%)
* @return Parsed String from the expansion.
*/
String onPlaceholderRequest(PlayerRef one, PlayerRef two, String identifier);
}

View File

@@ -1,43 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.expansion;
/**
* Implementing this interface adds the {@link #start() start} and {@link #stop() stop} void
* methods to your {@link at.helpch.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansion}.
*
* <p>This can be used to execute methods and tasks whenever the PlaceholderExpansion has been
* successfully (un)registered.
*/
public interface Taskable {
/**
* Called when the implementing class has successfully been registered to the placeholder map.
* <br>Tasks that need to be performed when this expansion is registered should go here
*/
void start();
/**
* Called when the implementing class has been unregistered from PlaceholderAPI.
* <br>Tasks that need to be performed when this expansion has unregistered should go here
*/
void stop();
}

View File

@@ -1,207 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.expansion.cloud;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import at.helpch.placeholderapi.util.TimeUtil;
public class CloudExpansion {
private String name,
author,
latest_version,
description,
source_url,
dependency_url;
private boolean hasExpansion,
shouldUpdate;
private long last_update,
ratings_count;
private double average_rating;
private List<String> placeholders;
private List<Version> versions;
public CloudExpansion() {
}
public String getTimeSinceLastUpdate() {
int time = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - getLastUpdate());
return TimeUtil.getTime(time);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Version getVersion() {
return getLatestVersion() == null ? null : getVersion(getLatestVersion());
}
public Version getVersion(String version) {
return versions == null ? null : versions.stream()
.filter(v -> v.getVersion().equals(version))
.findFirst()
.orElse(null);
}
public List<String> getAvailableVersions() {
return versions.stream().map(Version::getVersion).collect(Collectors.toList());
}
public String getLatestVersion() {
return latest_version;
}
public void setLatestVersion(String latest_version) {
this.latest_version = latest_version;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getSourceUrl() {
return source_url;
}
public void setSourceUrl(String source_url) {
this.source_url = source_url;
}
public String getDependencyUrl() {
return dependency_url;
}
public void setDependencyUrl(String dependency_url) {
this.dependency_url = dependency_url;
}
public boolean hasExpansion() {
return hasExpansion;
}
public void setHasExpansion(boolean hasExpansion) {
this.hasExpansion = hasExpansion;
}
public boolean shouldUpdate() {
return shouldUpdate;
}
public void setShouldUpdate(boolean shouldUpdate) {
this.shouldUpdate = shouldUpdate;
}
public long getLastUpdate() {
return last_update;
}
public void setLastUpdate(long last_update) {
this.last_update = last_update;
}
public long getRatingsCount() {
return ratings_count;
}
public double getAverage_rating() {
return average_rating;
}
public List<String> getPlaceholders() {
return placeholders;
}
public void setPlaceholders(List<String> placeholders) {
this.placeholders = placeholders;
}
public List<Version> getVersions() {
return versions;
}
public void setVersions(List<Version> versions) {
this.versions = versions;
}
public static class Version {
private String url, version, release_notes;
private boolean verified;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getReleaseNotes() {
return release_notes;
}
public void setReleaseNotes(String release_notes) {
this.release_notes = release_notes;
}
public boolean isVerified() {
return verified;
}
public void setVerified(boolean verified) {
this.verified = verified;
}
}
}

View File

@@ -1,305 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.expansion.manager;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.*;
import java.lang.reflect.Type;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import at.helpch.placeholderapi.expansion.cloud.CloudExpansion;
import com.hypixel.hytale.logger.HytaleLogger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CloudExpansionManager {
@NotNull
private static final String API_URL = "https://ecloud.placeholderapi.com/api/v3/?platform=hytale";
@NotNull
private static final Gson GSON = new Gson();
@NotNull
private static final Type TYPE = new TypeToken<Map<String, CloudExpansion>>() {}.getType();
@NotNull
private final Collector<CloudExpansion, ?, Map<String, CloudExpansion>> INDEXED_NAME_COLLECTOR = Collectors
.toMap(CloudExpansionManager::toIndexName, Function.identity());
@NotNull
private final PlaceholderAPIPlugin plugin;
private final HytaleLogger logger;
@NotNull
private final Map<String, CloudExpansion> cache = new HashMap<>();
@NotNull
private final Map<String, CompletableFuture<File>> await = new ConcurrentHashMap<>();
private final ExecutorService ASYNC_EXECUTOR =
Executors.newCachedThreadPool(new LoggingThreadFactory("placeholderapi-io-#%1$d"));
public CloudExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) {
this.plugin = plugin;
this.logger = plugin.getLogger();
}
@NotNull
private static String toIndexName(@NotNull final String name) {
return name.toLowerCase(Locale.ROOT).replace(' ', '_');
}
@NotNull
private static String toIndexName(@NotNull final CloudExpansion expansion) {
return toIndexName(expansion.getName());
}
public void load() {
clean();
fetch();
}
public void kill() {
clean();
}
@NotNull
@Unmodifiable
public Map<String, CloudExpansion> getCloudExpansions() {
return Map.copyOf(cache);
}
public boolean isEmpty() {
return cache.isEmpty();
}
@NotNull
@Unmodifiable
public Map<String, CloudExpansion> getCloudExpansionsInstalled() {
if (cache.isEmpty()) {
return Collections.emptyMap();
}
return cache.values()
.stream()
.filter(CloudExpansion::hasExpansion)
.collect(INDEXED_NAME_COLLECTOR);
}
@NotNull
@Unmodifiable
public Map<String, CloudExpansion> getCloudExpansionsByAuthor(@NotNull final String author) {
if (cache.isEmpty()) {
return Collections.emptyMap();
}
return cache.values()
.stream()
.filter(expansion -> author.equalsIgnoreCase(expansion.getAuthor()))
.collect(INDEXED_NAME_COLLECTOR);
}
@NotNull
@Unmodifiable
public Set<String> getCloudExpansionAuthors() {
return cache.values().stream().map(CloudExpansion::getAuthor).collect(Collectors.toSet());
}
public int getCloudExpansionAuthorCount() {
return getCloudExpansionAuthors().size();
}
public int getCloudUpdateCount() {
return ((int) plugin.localExpansionManager()
.getExpansions()
.stream()
.filter(expansion -> findCloudExpansionByName(expansion.getName())
.map(CloudExpansion::shouldUpdate).orElse(false))
.count());
}
@NotNull
public Optional<CloudExpansion> findCloudExpansionByName(@NotNull final String name) {
return Optional.ofNullable(cache.get(toIndexName(name)));
}
public void clean() {
cache.clear();
await.values().forEach(future -> future.cancel(true));
await.clear();
}
public void fetch() {
logger.at(Level.INFO).log("Fetching available expansion information...");
ASYNC_EXECUTOR.submit(
() -> {
// a defence tactic! use ConcurrentHashMap instead of normal HashMap
Map<String, CloudExpansion> values = new ConcurrentHashMap<>();
try {
final URI uri = new URI(API_URL);
final URLConnection connection = uri.toURL().openConnection();
final String json;
try (final InputStream input = connection.getInputStream()) {
final BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
json = reader.lines().collect(Collectors.joining(System.lineSeparator()));
}
//noinspection UnstableApiUsage
// String json = Resources.toString(new URL(API_URL), StandardCharsets.UTF_8);
values.putAll(GSON.fromJson(json, TYPE));
List<String> toRemove = new ArrayList<>();
for (Map.Entry<String, CloudExpansion> entry : values.entrySet()) {
CloudExpansion expansion = entry.getValue();
if (expansion.getLatestVersion() == null
|| expansion.getVersion(expansion.getLatestVersion()) == null) {
toRemove.add(entry.getKey());
}
}
for (String name : toRemove) {
values.remove(name);
}
} catch (UnknownHostException e) {
logger.atWarning().log("There is no data available from the eCloud. Please try running /papi refresh. If this does not resolve the issue, the eCloud may be blocked by your firewall, server host, or service provider.\n\nMore information: https://placeholderapi.com/ecloud-blocked", e);
} catch (Throwable e) {
// ugly swallowing of every throwable, but we have to be defensive
logger.atWarning().log("Failed to download expansion information", e);
}
// loop through what's left on the main thread
plugin
.getTaskRegistry()
.registerTask(CompletableFuture.runAsync(
() -> {
try {
for (Map.Entry<String, CloudExpansion> entry : values.entrySet()) {
String name = entry.getKey();
CloudExpansion expansion = entry.getValue();
expansion.setName(name);
Optional<PlaceholderExpansion> localOpt =
plugin.localExpansionManager().findExpansionByName(name);
if (localOpt.isPresent()) {
PlaceholderExpansion local = localOpt.get();
if (local.isRegistered()) {
expansion.setHasExpansion(true);
expansion.setShouldUpdate(
!local.getVersion().equalsIgnoreCase(expansion.getLatestVersion()));
}
}
cache.put(toIndexName(expansion), expansion);
}
} catch (Throwable e) {
// ugly swallowing of every throwable, but we have to be defensive
logger.atWarning().log("Failed to download expansion information", e);
}
}));
});
}
/*
public boolean isDownloading(@NotNull final CloudExpansion expansion) {
return await.containsKey(toIndexName(expansion));
}
@NotNull
public CompletableFuture<File> downloadExpansion(@NotNull final CloudExpansion expansion,
@NotNull final CloudExpansion.Version version) {
final CompletableFuture<File> previous = await.get(toIndexName(expansion));
if (previous != null) {
return previous;
}
final File file = new File(plugin.localExpansionManager().getExpansionsFolder(),
"Expansion-" + toIndexName(expansion) + ".jar");
final CompletableFuture<File> download = CompletableFuture.supplyAsync(() -> {
try (final ReadableByteChannel source = Channels.newChannel(new URL(version.getUrl())
.openStream()); final FileOutputStream target = new FileOutputStream(file)) {
target.getChannel().transferFrom(source, 0, Long.MAX_VALUE);
} catch (final IOException ex) {
throw new CompletionException(ex);
}
return file;
}, ASYNC_EXECUTOR);
download.whenCompleteAsync((value, exception) -> {
await.remove(toIndexName(expansion));
if (exception != null) {
logger.atSevere().log("Failed to download %s:%s %s", expansion.getName(), expansion.getVersion(), exception);
}
}, ASYNC_EXECUTOR);
await.put(toIndexName(expansion), download);
return download;
} */
private static final class LoggingThreadFactory implements ThreadFactory {
private final ThreadFactory backing = Executors.defaultThreadFactory();
private final String format;
private final AtomicLong count = new AtomicLong(0);
private LoggingThreadFactory(@NotNull final String format) {
this.format = format;
}
@Override
public Thread newThread(@NotNull final Runnable r) {
final Thread thread = backing.newThread(r);
thread.setName(String.format(format, count.getAndIncrement()));
return thread;
}
}
}

View File

@@ -1,511 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.expansion.manager;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import java.awt.*;
import java.io.File;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.stream.Collectors;
import at.helpch.placeholderapi.configuration.ConfigManager;
import at.helpch.placeholderapi.configuration.PlaceholderAPIConfig;
import at.helpch.placeholderapi.events.ExpansionRegisterEvent;
import at.helpch.placeholderapi.events.ExpansionUnregisterEvent;
import at.helpch.placeholderapi.events.ExpansionsLoadedEvent;
import at.helpch.placeholderapi.expansion.Cacheable;
import at.helpch.placeholderapi.expansion.Cleanable;
import at.helpch.placeholderapi.expansion.Configurable;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import at.helpch.placeholderapi.expansion.Taskable;
import at.helpch.placeholderapi.expansion.cloud.CloudExpansion;
import at.helpch.placeholderapi.util.FileUtil;
import at.helpch.placeholderapi.util.Futures;
import com.hypixel.hytale.common.plugin.PluginIdentifier;
import com.hypixel.hytale.event.IEventDispatcher;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.server.core.HytaleServer;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import com.hypixel.hytale.server.core.event.events.player.PlayerDisconnectEvent;
import com.hypixel.hytale.server.core.plugin.PluginBase;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
public final class LocalExpansionManager /*implements Listener*/ {
@NotNull
private static final String EXPANSIONS_FOLDER_NAME = "expansions";
@NotNull
private static final Set<MethodSignature> ABSTRACT_EXPANSION_METHODS = Arrays.stream(PlaceholderExpansion.class.getDeclaredMethods())
.filter(method -> Modifier.isAbstract(method.getModifiers()))
.map(method -> new MethodSignature(method.getName(), method.getParameterTypes()))
.collect(Collectors.toSet());
@NotNull
private final File folder;
@NotNull
private final PlaceholderAPIPlugin plugin;
private final HytaleLogger logger;
private final ConfigManager configManager;
@NotNull
private final Map<String, PlaceholderExpansion> expansions = new ConcurrentHashMap<>();
private final ReentrantLock expansionsLock = new ReentrantLock();
public LocalExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) {
this.plugin = plugin;
this.folder = new File(plugin.getDataDirectory().toString(), EXPANSIONS_FOLDER_NAME);
this.logger = plugin.getLogger();
this.configManager = plugin.configManager();
if (!this.folder.exists() && !folder.mkdirs()) {
logger.atWarning().log("Failed to create expansions folder!");
}
}
public void load(@NotNull final CommandSender sender) {
registerAll(sender);
}
public void kill() {
unregisterAll();
}
@NotNull
public File getExpansionsFolder() {
return folder;
}
@NotNull
@Unmodifiable
public Collection<String> getIdentifiers() {
expansionsLock.lock();
try {
return Set.copyOf(expansions.keySet());
} finally {
expansionsLock.unlock();
}
}
@NotNull
@Unmodifiable
public Collection<PlaceholderExpansion> getExpansions() {
expansionsLock.lock();
try {
return Set.copyOf(expansions.values());
} finally {
expansionsLock.unlock();
}
}
@Nullable
public PlaceholderExpansion getExpansion(@NotNull final String identifier) {
expansionsLock.lock();
try {
return expansions.get(identifier.toLowerCase(Locale.ROOT));
} finally {
expansionsLock.unlock();
}
}
@NotNull
public Optional<PlaceholderExpansion> findExpansionByName(@NotNull final String name) {
expansionsLock.lock();
try {
PlaceholderExpansion bestMatch = null;
for (Map.Entry<String, PlaceholderExpansion> entry : expansions.entrySet()) {
PlaceholderExpansion expansion = entry.getValue();
if (expansion.getName().equalsIgnoreCase(name)) {
bestMatch = expansion;
break;
}
}
return Optional.ofNullable(bestMatch);
} finally {
expansionsLock.unlock();
}
}
@NotNull
public Optional<PlaceholderExpansion> findExpansionByIdentifier(
@NotNull final String identifier) {
return Optional.ofNullable(getExpansion(identifier));
}
public Optional<PlaceholderExpansion> register(
@NotNull final Class<? extends PlaceholderExpansion> clazz) {
try {
final PlaceholderExpansion expansion = createExpansionInstance(clazz);
if (expansion == null) {
return Optional.empty();
}
Objects.requireNonNull(expansion.getAuthor(), "The expansion author is null!");
Objects.requireNonNull(expansion.getIdentifier(), "The expansion identifier is null!");
Objects.requireNonNull(expansion.getVersion(), "The expansion version is null!");
if (expansion.getRequiredPlugin() != null && !expansion.getRequiredPlugin().isEmpty()) {
if (HytaleServer.get().getPluginManager().getPlugin(PluginIdentifier.fromString(expansion.getRequiredPlugin())) == null) {
logger.atWarning().log("Cannot load expansion %s due to a missing plugin: %s", expansion.getIdentifier(),
expansion.getRequiredPlugin());
return Optional.empty();
}
}
expansion.setExpansionType(PlaceholderExpansion.Type.EXTERNAL);
if (!expansion.register()) {
logger.atWarning().log("Cannot load expansion %s due to an unknown issue.", expansion.getIdentifier());
return Optional.empty();
}
return Optional.of(expansion);
} catch (LinkageError | NullPointerException ex) {
final String reason;
if (ex instanceof LinkageError) {
reason = " (Is a dependency missing?)";
} else {
reason = " - One of its properties is null which is not allowed!";
}
logger.atSevere().log("Failed to load expansion class %s%s", ex, clazz.getSimpleName(), reason);
}
return Optional.empty();
}
/**
* Attempt to register a {@link PlaceholderExpansion}
*
* @param expansion the expansion to register
* @return if the expansion was registered
*/
@ApiStatus.Internal
public boolean register(@NotNull final PlaceholderExpansion expansion) {
final String identifier = expansion.getIdentifier().toLowerCase(Locale.ROOT);
if (!expansion.canRegister()) {
return false;
}
// Avoid loading two external expansions with the same identifier
if (expansion.getExpansionType() == PlaceholderExpansion.Type.EXTERNAL && expansions.containsKey(identifier)) {
logger.atWarning().log("Failed to load external expansion %s. Identifier is already in use.", expansion.getIdentifier());
return false;
}
if (expansion instanceof Configurable<?> configurable) {
final PlaceholderAPIConfig config = configManager.config();
if (config.expansions() == null) {
config.expansions(new HashMap<>());
}
if (!config.expansions().containsKey(expansion.getIdentifier())) {
config.expansions().put(expansion.getIdentifier(), configurable.provideDefault());
configManager.save();
} else {
final Object expansionConfig = configManager.convertExpansion((Map<String, Object>) config.expansions().get(expansion.getIdentifier()), configurable.provideConfigType());
config.expansions().put(expansion.getIdentifier(), expansionConfig);
}
// Map<String, Object> defaults = ((Configurable<?>) expansion).getDefaults();
// String pre = "expansions." + identifier + ".";
// boolean save = false;
//
// final PlaceholderAPIConfig config = this.config.config();
//
// if (defaults != null) {
// for (Map.Entry<String, Object> entries : defaults.entrySet()) {
// if (entries.getKey() == null || entries.getKey().isEmpty()) {
// continue;
// }
//
// if (entries.getValue() == null) {
// if (cfg.contains(pre + entries.getKey())) {
// save = true;
// cfg.set(pre + entries.getKey(), null);
// }
// } else {
// if (!cfg.contains(pre + entries.getKey())) {
// save = true;
// cfg.set(pre + entries.getKey(), entries.getValue());
// }
// }
// }
// }
//
// if (save) {
// plugin.saveConfig();
// plugin.reloadConfig();
// }
}
// if (expansion instanceof VersionSpecific) {
// VersionSpecific nms = (VersionSpecific) expansion;
// if (!nms.isCompatibleWith(PlaceholderAPIPlugin.getServerVersion())) {
// Msg.warn("Your server version is incompatible with expansion %s %s",
// expansion.getIdentifier(), expansion.getVersion());
// return false;
// }
// }
final PlaceholderExpansion removed = getExpansion(identifier);
if (removed != null && !removed.unregister()) {
return false;
}
final ExpansionRegisterEvent event = new ExpansionRegisterEvent(expansion);
final IEventDispatcher<ExpansionRegisterEvent, ExpansionRegisterEvent> eventDispatcher = HytaleServer.get().getEventBus().dispatchFor(ExpansionRegisterEvent.class);
if (eventDispatcher.hasListener()) {
eventDispatcher.dispatch(event);
}
// Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return false;
}
expansionsLock.lock();
try {
expansions.put(identifier, expansion);
} finally {
expansionsLock.unlock();
}
// if (expansion instanceof Listener) {
// Bukkit.getPluginManager().registerEvents(((Listener) expansion), plugin);
// }
logger.at(Level.INFO).log(
"Successfully registered %s expansion: %s [%s]",
expansion.getExpansionType().name().toLowerCase(),
expansion.getIdentifier(),
expansion.getVersion()
);
if (expansion instanceof Taskable) {
((Taskable) expansion).start();
}
// Check eCloud for updates only if the expansion is external
if (configManager.config().cloudEnabled() && expansion.getExpansionType() == PlaceholderExpansion.Type.EXTERNAL) {
final Optional<CloudExpansion> cloudExpansionOptional = plugin.cloudExpansionManager().findCloudExpansionByName(identifier);
if (cloudExpansionOptional.isPresent()) {
CloudExpansion cloudExpansion = cloudExpansionOptional.get();
cloudExpansion.setHasExpansion(true);
cloudExpansion.setShouldUpdate(!cloudExpansion.getLatestVersion().equals(expansion.getVersion()));
}
}
return true;
}
@ApiStatus.Internal
public boolean unregister(@NotNull final PlaceholderExpansion expansion) {
if (expansions.remove(expansion.getIdentifier().toLowerCase(Locale.ROOT)) == null) {
return false;
}
final IEventDispatcher<ExpansionUnregisterEvent, ExpansionUnregisterEvent> eventDispatcher = HytaleServer.get().getEventBus().dispatchFor(ExpansionUnregisterEvent.class);
if (eventDispatcher.hasListener()) {
eventDispatcher.dispatch(new ExpansionUnregisterEvent(expansion));
}
// if (expansion instanceof Listener) {
// HandlerList.unregisterAll((Listener) expansion);
// }
if (expansion instanceof Taskable) {
((Taskable) expansion).stop();
}
if (expansion instanceof Cacheable) {
((Cacheable) expansion).clear();
}
if (configManager.config().cloudEnabled()) {
plugin.cloudExpansionManager().findCloudExpansionByName(expansion.getName())
.ifPresent(cloud -> {
cloud.setHasExpansion(false);
cloud.setShouldUpdate(false);
});
}
return true;
}
private void registerAll(@NotNull final CommandSender sender) {
logger.at(Level.INFO).log("Placeholder expansion registration initializing...");
Futures.onMainThread(plugin, findExpansionsOnDisk(), (classes, exception) -> {
if (exception != null) {
logger.atSevere().log("Failed to load class files of expansion.", exception);
return;
}
final List<PlaceholderExpansion> registered = classes.stream()
.filter(Objects::nonNull)
.map(this::register)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
final long needsUpdate = registered.stream()
.map(expansion -> plugin.cloudExpansionManager().findCloudExpansionByName(expansion.getName()).orElse(null))
.filter(Objects::nonNull)
.filter(CloudExpansion::shouldUpdate)
.count();
Message message = Message.raw(registered.size() + "").color(registered.isEmpty() ? Color.YELLOW : Color.GREEN)
.insert(" placeholder hook(s) registered!");
if (needsUpdate > 0) {
message = message.insert(" ")
.insert(Message.raw(needsUpdate + " placeholder hook(s) have an update available.").color(Color.YELLOW));
}
// logger.at(Level.INFO).log(message.toString());
sender.sendMessage(message);
final IEventDispatcher<ExpansionsLoadedEvent, ExpansionsLoadedEvent> eventDispatcher = HytaleServer.get().getEventBus().dispatchFor(ExpansionsLoadedEvent.class);
if (eventDispatcher.hasListener()) {
eventDispatcher.dispatch(new ExpansionsLoadedEvent(registered));
}
});
}
private void unregisterAll() {
for (final PlaceholderExpansion expansion : new HashSet<>(expansions.values())) {
if (expansion.persist()) {
continue;
}
expansion.unregister();
}
}
@NotNull
public CompletableFuture<@NotNull List<@Nullable Class<? extends PlaceholderExpansion>>> findExpansionsOnDisk() {
File[] files = folder.listFiles((dir, name) -> name.endsWith(".jar"));
if (files == null) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
return Arrays.stream(files)
.map(this::findExpansionInFile)
.collect(Futures.collector());
}
@NotNull
public CompletableFuture<@Nullable Class<? extends PlaceholderExpansion>> findExpansionInFile(
@NotNull final File file) {
return CompletableFuture.supplyAsync(() -> {
try {
final Class<? extends PlaceholderExpansion> expansionClass = FileUtil.findClass(file, PlaceholderExpansion.class);
if (expansionClass == null) {
logger.atSevere().log("Failed to load expansion %s, as it does not have a class which"
+ " extends PlaceholderExpansion", file.getName());
return null;
}
Set<MethodSignature> expansionMethods = Arrays.stream(expansionClass.getDeclaredMethods())
.map(method -> new MethodSignature(method.getName(), method.getParameterTypes()))
.collect(Collectors.toSet());
if (!expansionMethods.containsAll(ABSTRACT_EXPANSION_METHODS)) {
logger.atSevere().log("Failed to load expansion %s, as it does not have the required"
+ " methods declared for a PlaceholderExpansion.", file.getName());
return null;
}
return expansionClass;
} catch (VerifyError | NoClassDefFoundError e) {
logger.atSevere().log("Failed to load expansion %s (is a dependency missing?)", e, file.getName());
return null;
} catch (Exception e) {
logger.atSevere().log("Failed to load expansion file: " + file.getAbsolutePath(), e);
return null;
}
});
}
@Nullable
public PlaceholderExpansion createExpansionInstance(
@NotNull final Class<? extends PlaceholderExpansion> clazz) throws LinkageError {
try {
return clazz.getDeclaredConstructor().newInstance();
} catch (final Exception ex) {
if (ex.getCause() instanceof LinkageError) {
throw ((LinkageError) ex.getCause());
}
logger.atWarning().log("There was an issue with loading an expansion.");
return null;
}
}
public void onQuit(@NotNull final PlayerDisconnectEvent event) {
for (final PlaceholderExpansion expansion : getExpansions()) {
if (!(expansion instanceof Cleanable)) {
continue;
}
((Cleanable) expansion).cleanup(event.getPlayerRef());
}
}
// @EventHandler(priority = EventPriority.HIGH)
//todo: hytale has no plugin disable event as of yet :(
// public void onPluginDisable() {
// final String name = event.getPlugin().getName();
// if (name.equals(plugin.getName())) {
// return;
// }
//
// for (final PlaceholderExpansion expansion : getExpansions()) {
// if (!name.equalsIgnoreCase(expansion.getRequiredPlugin())) {
// continue;
// }
//
// expansion.unregister();
// Msg.info("Unregistered placeholder expansion %s", expansion.getIdentifier());
// Msg.info("Reason: required plugin %s was disabled.", name);
// }
// }
}

View File

@@ -1,57 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.expansion.manager;
import java.util.Arrays;
import java.util.Objects;
public final class MethodSignature {
private final String name;
private final Class<?>[] params;
protected MethodSignature(String name, Class<?>[] params) {
this.name = name;
this.params = params;
}
public String getName() {
return name;
}
public Class<?>[] getParams() {
return params;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MethodSignature that = (MethodSignature) o;
return Objects.equals(name, that.name) && Arrays.equals(params, that.params);
}
@Override
public int hashCode() {
int result = Objects.hash(name);
result = 31 * result + Arrays.hashCode(params);
return result;
}
}

View File

@@ -1,138 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.replacer;
import java.util.Locale;
import java.util.function.Function;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class CharsReplacer implements Replacer {
@NotNull
private final Closure closure;
public CharsReplacer(@NotNull final Closure closure) {
this.closure = closure;
}
@NotNull
@Override
public String apply(@NotNull final String text, @Nullable final PlayerRef player,
@NotNull final Function<String, @Nullable PlaceholderExpansion> lookup) {
final char[] chars = text.toCharArray();
final StringBuilder builder = new StringBuilder(text.length());
final StringBuilder identifier = new StringBuilder();
final StringBuilder parameters = new StringBuilder();
for (int i = 0; i < chars.length; i++) {
final char l = chars[i];
if (l != closure.head || i + 1 >= chars.length) {
builder.append(l);
continue;
}
boolean identified = false;
boolean invalid = true;
boolean hadSpace = false;
while (++i < chars.length) {
final char p = chars[i];
if (p == ' ' && !identified) {
hadSpace = true;
break;
}
if (p == closure.tail) {
invalid = false;
break;
}
if (p == '_' && !identified) {
identified = true;
continue;
}
if (identified) {
parameters.append(p);
} else {
identifier.append(p);
}
}
final String identifierString = identifier.toString();
final String lowercaseIdentifierString = identifierString.toLowerCase(Locale.ROOT);
final String parametersString = parameters.toString();
identifier.setLength(0);
parameters.setLength(0);
if (invalid) {
builder.append(closure.head).append(identifierString);
if (identified) {
builder.append('_').append(parametersString);
}
if (hadSpace) {
builder.append(' ');
}
continue;
}
final PlaceholderExpansion placeholder = lookup.apply(lowercaseIdentifierString);
if (placeholder == null) {
builder.append(closure.head).append(identifierString);
if (identified) {
builder.append('_');
}
builder.append(parametersString).append(closure.tail);
continue;
}
final String replacement = placeholder.onPlaceholderRequest(player, parametersString);
if (replacement == null) {
builder.append(closure.head).append(identifierString);
if (identified) {
builder.append('_');
}
builder.append(parametersString).append(closure.tail);
continue;
}
builder.append(replacement);
}
return builder.toString();
}
}

View File

@@ -1,50 +0,0 @@
package at.helpch.placeholderapi.replacer;
import at.helpch.placeholderapi.PlaceholderAPI;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.entity.entities.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
public final class MessageReplacer {
@NotNull
public static Message replace(@NotNull final Message original, @NotNull final Function<String, String> setPlaceholders) {
if (original.getFormattedMessage().rawText == null) {
return original;
}
String replaced = setPlaceholders.apply(original.getFormattedMessage().rawText);
String link = original.getFormattedMessage().link == null ? null : setPlaceholders.apply(original.getFormattedMessage().link);
List<Message> newChildren = original.getChildren().stream()
.filter(Objects::nonNull)
.map(child -> replace(child, setPlaceholders))
.toList();
Message message = Message.raw(replaced);
if (original.getColor() != null) {
message = message.color(original.getColor());
}
if (link != null) {
message = message.link(link);
}
int bold = original.getFormattedMessage().bold.getValue();
if (bold != 0) {
message = message.bold(bold != 1);
}
int italic = original.getFormattedMessage().italic.getValue();
if (italic != 0) {
message = message.italic(italic != 1);
}
return message.insertAll(newChildren);
}
}

View File

@@ -1,51 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.replacer;
import java.util.function.Function;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface Replacer {
@NotNull
String apply(@NotNull final String text, @Nullable final PlayerRef player,
@NotNull final Function<String, @Nullable PlaceholderExpansion> lookup);
enum Closure {
BRACKET('{', '}'),
PERCENT('%', '%');
public final char head, tail;
Closure(final char head, final char tail) {
this.head = head;
this.tail = tail;
}
}
}

View File

@@ -1,77 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.util;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
public class FileUtil {
@Nullable
public static <T> Class<? extends T> findClass(@NotNull final File file,
@NotNull final Class<T> clazz) throws IOException, ClassNotFoundException {
if (!file.exists()) {
return null;
}
final URL jar = file.toURI().toURL();
final URLClassLoader loader = new URLClassLoader(new URL[]{jar}, clazz.getClassLoader());
final List<String> matches = new ArrayList<>();
final List<Class<? extends T>> classes = new ArrayList<>();
try (final JarInputStream stream = new JarInputStream(jar.openStream())) {
JarEntry entry;
while ((entry = stream.getNextJarEntry()) != null) {
final String name = entry.getName();
if (name.isEmpty() || !name.endsWith(".class")) {
continue;
}
matches.add(name.substring(0, name.lastIndexOf('.')).replace('/', '.'));
}
for (final String match : matches) {
try {
final Class<?> loaded = loader.loadClass(match);
if (clazz.isAssignableFrom(loaded)) {
classes.add(loaded.asSubclass(clazz));
}
} catch (final NoClassDefFoundError ignored) {
}
}
}
if (classes.isEmpty()) {
loader.close();
return null;
}
return classes.get(0);
}
}

View File

@@ -1,71 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.util;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static java.util.stream.IntStream.range;
import java.util.List;
import java.util.Optional;
import org.jetbrains.annotations.NotNull;
/**
* For the record, I am not sorry.
*/
public final class Format {
private Format() {}
@NotNull
public static Optional<List<String>> tablify(@NotNull final Align align,
@NotNull final List<List<String>> rows) {
return findSpacing(rows)
.map(spacing -> buildFormat(align, spacing))
.map(format -> rows.stream()
.map(
row -> String.format(format, row.toArray()).substring(align == Align.RIGHT ? 2 : 0))
.collect(toList()));
}
@NotNull
private static String buildFormat(@NotNull final Align align, final int[] spacing) {
return stream(spacing)
.mapToObj(space -> "%" + (align == Align.LEFT ? "-" : "") + (space + 2) + "s")
.collect(joining());
}
@NotNull
private static Optional<int[]> findSpacing(@NotNull final List<List<String>> rows) {
return rows.stream()
.map(row -> row.stream().mapToInt(String::length).toArray())
.reduce((l, r) -> range(0, min(l.length, r.length)).map(i -> max(l[i], r[i])).toArray());
}
public enum Align {
LEFT, RIGHT
}
}

View File

@@ -1,75 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.util;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import com.hypixel.hytale.server.core.HytaleServer;
import com.hypixel.hytale.server.core.universe.Universe;
import org.jetbrains.annotations.NotNull;
public final class Futures {
private Futures() {}
public static <T> void onMainThread(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CompletableFuture<T> future,
@NotNull final BiConsumer<T, Throwable> consumer) {
future.whenComplete((value, exception) -> {
HytaleServer.SCHEDULED_EXECUTOR.execute(() -> consumer.accept(value, exception));
});
}
@NotNull
public static <T> Collector<CompletableFuture<T>, ?, CompletableFuture<List<T>>> collector() {
return Collectors.collectingAndThen(Collectors.toList(), Futures::of);
}
@NotNull
public static <T> CompletableFuture<List<T>> of(
@NotNull final Stream<CompletableFuture<T>> futures) {
return of(futures.collect(Collectors.toList()));
}
@NotNull
public static <T> CompletableFuture<List<T>> of(
@NotNull final Collection<CompletableFuture<T>> futures) {
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenApplyAsync($ -> awaitCompletion(futures));
}
@NotNull
private static <T> List<T> awaitCompletion(
@NotNull final Collection<CompletableFuture<T>> futures) {
return futures.stream().map(CompletableFuture::join).collect(Collectors.toList());
}
}

View File

@@ -1,28 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.util;
public enum TimeFormat {
DAYS,
HOURS,
MINUTES,
SECONDS
}

View File

@@ -1,96 +0,0 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
*
* PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlaceholderAPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.helpch.placeholderapi.util;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.StringJoiner;
public class TimeUtil {
public static String getRemaining(final int seconds, final TimeFormat type) {
return getRemaining((long) seconds, type);
}
public static String getRemaining(final long seconds, final TimeFormat type) {
switch (type) {
default:
return String.valueOf(seconds);
case SECONDS:
return String.valueOf(seconds % 60);
case MINUTES:
return String.valueOf((seconds / 60) % 60);
case HOURS:
return String.valueOf((seconds / 3600) % 24);
case DAYS:
return String.valueOf(seconds / 86400);
}
}
/**
* Format the given value with s, m, h and d (seconds, minutes, hours and days)
*
* @param duration {@link Duration} (eg, Duration.of(20, {@link ChronoUnit#SECONDS}) for 20
* seconds)
* @return formatted time
*/
public static String getTime(final Duration duration) {
return getTime(duration.getSeconds());
}
public static String getTime(final int seconds) {
return getTime((long) seconds);
}
public static String getTime(long seconds) {
final StringJoiner joiner = new StringJoiner(" ");
long minutes = seconds / 60;
long hours = minutes / 60;
final long days = hours / 24;
seconds %= 60;
minutes %= 60;
hours %= 24;
if (days > 0) {
joiner.add(days + "d");
}
if (hours > 0) {
joiner.add(hours + "h");
}
if (minutes > 0) {
joiner.add(minutes + "m");
}
if (seconds > 0) {
joiner.add(seconds + "s");
}
return joiner.toString();
}
}

View File

@@ -1,18 +0,0 @@
# PlaceholderAPI
# Version: ${version}
# Created by: extended_clip
# Contributors: https://github.com/PlaceholderAPI/PlaceholderAPI/graphs/contributors
# Issues: https://github.com/PlaceholderAPI/PlaceholderAPI/issues
# Expansions: https://placeholderapi.com/ecloud
# Wiki: https://wiki.placeholderapi.com/
# Discord: https://helpch.at/discord
# No placeholders are provided with this plugin by default.
# Download placeholders: /papi ecloud
check_updates: true
cloud_enabled: true
cloud_sorting: "NAME"
boolean_value:
true_value: 'yes'
false_value: 'no'
date_format: MM/dd/yy HH:mm:ss
debug: false

View File

@@ -1,14 +0,0 @@
{
"Group": "HelpChat",
"Name": "PlaceholderAPI",
"Version": "${version}",
"Description": "An awesome placeholder provider",
"Authors": [{"Name": "HelpChat"}],
"Website": "https://placeholderapi.com",
"ServerVersion": "*",
"Dependencies": {},
"OptionalDependencies": {},
"DisabledByDefault": false,
"Main": "at.helpch.placeholderapi.PlaceholderAPIPlugin",
"IncludesAssetPack": false
}