Compare commits

...

957 Commits

Author SHA1 Message Date
PiggyPiglet ac771207c3
bump to dev version 2024-05-21 18:51:05 +08:00
PiggyPiglet 8b031576aa
bump version for release 2024-05-21 18:31:02 +08:00
PiggyPiglet 2d1a0ee157
Merge pull request #1060 from PlaceholderAPI/fix/parse-command-improvements
Parse command improvements
2024-05-21 18:08:19 +08:00
PiggyPiglet b9e2bf9429
Merge pull request #1061 from PlaceholderAPI/feature/update-adventure-platform-bukkit
Update Adventure-platform-bukkit to 4.3.2
2024-05-21 18:05:13 +08:00
PiggyPiglet a35923a117
cast instead of #getplayer 2024-05-21 17:59:57 +08:00
PiggyPiglet d5e96bd6a6
exclude module-info fix #894 2024-05-20 22:44:44 +08:00
Andre601 2523b6c094
Update Adventure-platform-bukkit to 4.3.2 2024-05-10 14:41:51 +02:00
Andre601 7b230fc679
Fix output for parse command + "me" support in parserel 2024-05-06 16:42:24 +02:00
Andre_601 68f467ab29
Add 1.20.2 - 1.20.5 to NMSVersion.java (#1057) 2024-04-30 10:35:18 -05:00
PiggyPiglet 068b5a31b2
Fix #1034 & Deprecate VersionSpecific & update copyright (#1035)
Co-authored-by: Andre_601 <github@andre601.ch>
2024-04-30 10:34:43 -05:00
Gabriel Dumitru 882b7c5965
Merge pull request #1046 from PlaceholderAPI/feature/add-plugin-authors
Add Plugin Authors to /papi dump
2024-03-07 22:59:42 +02:00
Gabriel Dumitru 7a0be5edf8
Merge pull request #1040 from DevCyntrix/fix-class-cast-exception
Use the OfflinePlayer$getPlayer method instead of casting to Player class
2024-03-07 22:59:24 +02:00
Andre601 e94328935d
Add Plugin Authors to /papi dump 2024-02-25 14:42:48 +01:00
Andre_601 604fed36a4
Man, this file is outdated... 2024-02-25 00:14:41 +01:00
Ricardo Borutta 403622d205 Use the OfflinePlayer$getPlayer method instead of casting to Player class
You should use this to avoid a class cast exception if some other plugins uses an own Implementation of the offline player.
2024-01-29 10:21:24 +01:00
Funnycube 1cd4d93f7f
Merge pull request #1038 from Funny-cube/master
Update config.yml with papi domain for wiki and ecloud
2024-01-27 21:57:48 +11:00
Funnycube a83ef75bf9
Update config.yml 2024-01-27 20:45:10 +11:00
Andre_601 b96e535aaa
Update wiki link in PR template 2024-01-27 00:58:11 +01:00
Andre_601 2e67272aea
Fix logo and update link in README 2024-01-26 23:05:04 +01:00
Andre_601 2c7767e77d
fix github admonition blocks 2024-01-22 20:12:39 +01:00
Andre_601 c4a046ff24
Merge pull request #1006 from PlaceholderAPI/feature/add-new-download-pages
Add Hangar and BuiltByBit pages to readme
2023-11-26 16:58:08 +01:00
PiggyPiglet 57fa68c896
change version to .6-dev 2023-10-28 21:50:05 +08:00
PiggyPiglet b64f024eb2
fix config version variable and set release version 2023-10-28 21:49:39 +08:00
PiggyPiglet c7a4900aa3
remove ability to download unverified expansions 2023-10-28 21:42:18 +08:00
Andre_601 491abd6238
BuilT not BuilD 2023-09-25 15:11:49 +02:00
Andre_601 d3646a9874
Change Built By Bit to BuiltByBit Page 2023-09-25 15:07:13 +02:00
Andre_601 af0b475330
Add Hangar and BuiltByBit pages to readme 2023-09-25 14:58:30 +02:00
Funnycube d35a499e31
Update plugin.yml
remove unused toggle permissions
2023-09-24 13:49:40 +10:00
Funnycube c0f824450e
Update build.gradle.kts
start 2.11.5-DEV
2023-09-24 12:59:01 +10:00
Funnycube 5b1a8ef4ba
2.11.4 release 2023-09-24 12:40:46 +10:00
PiggyPiglet 5623a00f9b
Merge pull request #978 from JulianVennen/block-unverified-expansions
Add environment variable to override cloud_allowunverified_expansions
2023-09-21 17:38:54 +08:00
PiggyPiglet 4926907b47
Merge pull request #969 from PlaceholderAPI/feature/support-1.20
1.20 support
2023-09-04 17:26:11 +08:00
Andre_601 195158b18b
Use new format for note block [skip ci] 2023-08-01 03:27:15 +02:00
Gabriel Dumitru 36fa9ac96d
feat: distinguish expansions (external or internal) (fixes #945) (#953) 2023-07-24 11:48:29 +03:00
Julian 42cfe1dc80
simplify env values to true/false 2023-06-23 17:06:11 +02:00
Julian 92a7d54664
Add environment variable to override cloud_allowunverified_expansions
This adds the environment variable PAPI_ALLOW_UNVERIFIED_EXPANSIONS.
It allows overriding the option set in the config.yml.
2023-06-23 14:04:00 +02:00
Gabriel Dumitru f91b4e3752
feat: fetch all expansions (#952) 2023-06-21 21:26:52 +03:00
PiggyPiglet a497e05e55
Merge pull request #947 from JulianVennen/block-extensions-env
Add environment variable to block individual ecloud expansions.
2023-06-21 20:25:16 +08:00
Andre601 74d8fec6bd
Bump Spigot version 2023-06-10 18:13:10 +02:00
Andre601 28287c7fbd
1.20 NMS version support 2023-06-10 17:59:55 +02:00
Gabriel Dumitru 744cf6d8c0
Merge pull request #946 from JulianVennen/block-load-path-traversal
Prevent loading of extensions outside of the expansions folder using the register command
2023-04-04 17:28:00 +03:00
Julian ecd4c002c8
Add environment variable to block individual ecloud expansions.
This commit adds the environment variable "PAPI_BLOCKED_EXPANSIONS"
which can contain a case insensitive, comma separated list of blocked
expansions.
Expansions on this list can no longer be downloaded using commands.
2023-03-30 13:41:01 +02:00
Julian b4e60b7db5
Prevent loading of extensions outside of the expansions folder using the register command 2023-03-30 12:47:23 +02:00
darbyjack e862abe0b4
Start 2.11.4 DEV cycle 2023-03-17 20:07:24 -05:00
darbyjack 2d946646f0
Release 2.11.3 2023-03-17 20:03:47 -05:00
Glare 5ab61e0cd3
Update the NMS options up to the latest 1.19 R3 (#938) 2023-03-17 19:59:31 -05:00
Gabriel Dumitru 81ef464dad
fix: catch NoClassDefFoundError in order for the other expansions to be loaded (#936) 2023-03-17 15:44:41 -05:00
Gabriel Dumitru 0ae0ddc9cb
Merge pull request #935 from PlaceholderAPI/fix/kotlin-build-system 2023-03-17 22:16:10 +02:00
darbyjack 3d00d48106
Tell build to depend on shadowJar and publish for build 2023-03-17 14:13:49 -05:00
darbyjack 7e902cae66
Fixed variables in the plugin.yml not being created properly 2023-03-17 13:45:31 -05:00
Matt f4e4433b16
Feature/gradle kts (#934)
Co-authored-by: darbyjack <admin@glaremasters.me>
2023-03-17 13:25:47 -05:00
Andre_601 d5c371004c
Fix duplicate expansion loading (#866) 2023-03-17 12:47:27 -05:00
Glare e246473782
Merge pull request #933 from PlaceholderAPI/feature/update-adventure 2023-03-16 18:31:20 -05:00
Andre601 4afad7f7b0
Update Kyori Adventure to 4.3.0 2023-03-17 00:22:58 +01:00
PiggyPiglet a0b177bdd8
Merge pull request #869 from PlaceholderAPI/remove-ecloud-toggle-command
remove the eCloud toggle command
2023-02-23 21:29:06 +08:00
Gabriel Dumitru 40b1fe8d68
Merge pull request #901 from BlockyTheDev/fix-status-message 2023-02-23 13:36:05 +02:00
PiggyPiglet 9ee4afa1e9
Merge pull request #873 from PlaceholderAPI/fix/872-fix-inxonsisten-parsing
Fix inconsistent parsing command behaviour
2023-02-23 19:31:38 +08:00
BlockyTheDev 1cf66b130c
Add space to message 2022-12-25 21:31:55 +01:00
Andre601 c3cfc82eb3 Fix inconsistent parsing command behaviour 2022-08-14 16:30:22 +02:00
Gabriel Dumitru 3afb634e58
revert 4c228ca4fb 2022-08-10 16:01:41 +03:00
Gabriel Dumitru d888d9754b
remove from help 2022-08-09 01:20:04 +03:00
Gabriel Dumitru 4c228ca4fb make the eCloud disable by default 2022-08-09 01:08:45 +03:00
Gabriel Dumitru 6cf987586e remove the eCloud toggle command 2022-08-09 01:08:24 +03:00
Glare 46d9a69534
Merge pull request #862 from darbyjack/fix-ecloud-components
Updated Adventure
2022-07-26 18:49:45 -05:00
Glare af8cc09fca
Merge pull request #863 from darbyjack/bump-dev
Bump to 2.11.3-dev
2022-07-26 18:48:44 -05:00
darbyjack 452c8ccd42
Bump to 2.11.3-dev 2022-07-26 16:22:18 -05:00
darbyjack 054c780fd1
Updated Adventure 2022-07-26 12:57:11 -05:00
Andre_601 83261eee49
Update canned responses. 2022-07-03 20:12:45 +02:00
PiggyPiglet 3fca78626a
remove remaining colour shit and changed version so cube can release and we can be all happy and dandy 2022-07-03 20:34:12 +08:00
PiggyPiglet a2456c582d
Removed excess capitalisation 2022-07-02 21:45:53 +08:00
Andre_601 b987916328
Update Image link 2022-07-02 13:46:48 +02:00
Andre_601 23ef4ecb62
Remove wiki folder 2022-07-02 13:46:09 +02:00
PiggyPiglet 8b7a217796
Merge pull request #830 from montlikadani/improve-replacer-process
Remove regex replacer & associated tests
2022-07-01 23:33:35 +08:00
PiggyPiglet 74ebb0bec0
remove regex replacer & associated tests 2022-07-01 23:31:51 +08:00
Glare 794c8890e5
Merge pull request #801 from PlaceholderAPI/fix/papi-dump-expansion-order 2022-07-01 10:08:57 -05:00
Glare 013e566a85
Merge pull request #832 from PlaceholderAPI/feature/log-missing-plugin 2022-07-01 09:51:12 -05:00
Glare 5a4a8c2e7e
Merge pull request #793 from Rothes/master 2022-07-01 09:46:39 -05:00
Andre_601 0b068470ac
Update CODEOWNERS 2022-07-01 13:06:22 +02:00
Andre_601 f3cb7635c2
Update old links 2022-06-30 22:51:34 +02:00
Andre_601 8e21a76118
Update bug_report.yml 2022-06-30 22:26:13 +02:00
Andre_601 1dad2381e5
Delete wiki action (Not needed) 2022-06-30 22:16:06 +02:00
Andre_601 9767811cb9
Merge pull request #847 from JT122406/master
Gradle Bumps and stuff
2022-06-27 12:55:06 +02:00
J.T. McQuigg e6fb6d5ec6 Other small version bumps 2022-06-26 23:54:07 -04:00
J.T. McQuigg 1acc621f2e Bump Gradle from 7.3.1 to 7.4.2 2022-06-26 23:53:51 -04:00
Glare d9bab03e3b
Merge pull request #773 from PlaceholderAPI/feature/update-contributing 2022-06-25 15:47:54 -05:00
PiggyPiglet 9baf5f58ae
Merge pull request #844 from PlaceholderAPI/feature/1.19
1.19 support
2022-06-25 20:06:19 +08:00
Andre601 077d64dc68 Fix NMS version 2022-06-16 01:45:47 +02:00
Andre601 b8d5886cad 1.19 support 2022-06-16 01:31:33 +02:00
Andre_601 52119682f3
Use custom quote block in automatic replies 2022-05-20 17:04:38 +02:00
Andre601 651e14a797 Make plugin check before register to avoid possible exceptions 2022-05-19 02:46:40 +02:00
Andre601 0ac62d6b63 Log missing required plugin for expansion
+ some logger improvements
2022-05-18 21:11:09 +02:00
Andre601 0be6b721cf Use stream to get size padding 2022-05-04 18:36:46 +02:00
Andre601 0e0e36476a Change appended message for null jar array 2022-04-29 23:13:19 +02:00
Andre_601 a56b3b62b9
Update to v3 wiki action 2022-04-28 21:30:52 +02:00
Funnycube 883f1c1edf
One Million 🎉 2022-04-08 20:23:05 +10:00
Rothes bfc30a8703
`Locale.ROOT` param 2022-03-26 09:09:50 +08:00
Andre_601 37c39ab734
Update the flex 2022-03-26 01:36:07 +01:00
Glare 35c47a8745
Merge pull request #810 from PlaceholderAPI/feature/remove-escape-hex-test
Remove testCharsReplacerHandlesEscapedHex()
2022-03-13 05:48:30 -05:00
PiggyPiglet fadf14a316
Merge pull request #814 from PlaceholderAPI/fix/666-lowercasing
fix(replacer): Stop lowercasing replacements
2022-03-13 14:35:34 +08:00
Starmism 1388a5278f fix(replacer): Stop lowercasing replacements
This commit changes two lines but fixes the replacement of cased
    placeholders with non-cased ones that was accidentally happening.
    This was partially fixed in a few previous commits, but not fully as
    it was still replacing failed placeholder matches.
2022-03-12 12:42:56 -07:00
Andre_601 3bc6ad0f06
Also update label-commenter-config 2022-03-12 01:20:21 +01:00
Andre_601 bb149811d4
Update label-commenter-config.yml 2022-03-12 01:16:33 +01:00
Andre601 350a2be0ed Remove testCharsReplacerHandlesEscapedHex() 2022-02-22 11:48:51 +01:00
Gabriel Dumitru b73d72cec7
add missing java.util.Locale imports 2022-02-22 11:42:35 +02:00
Gabriel Dumitru 7afb8ee36d
Merge pull request #800 from PlaceholderAPI/feature/null-parse-option
Add --null argument for Parse command
2022-02-22 10:42:02 +02:00
Andre601 1241c33ba0 Add --null to command help 2022-02-05 20:55:48 +01:00
Andre601 631609af74 Improve expansion sorting in /papi dump 2022-02-05 14:08:43 +01:00
Andre601 fe8d865657 Add missing import 2022-02-05 13:57:30 +01:00
Andre601 50d4e14333 Add --null option for parse command 2022-02-05 13:57:05 +01:00
Andre_601 666ab468a1
Link to docs/wiki branch README 2022-01-30 12:03:42 +01:00
Rothes 151fb08db8
Fix PlaceholderExpansion may not unregistered 2022-01-28 13:40:39 +08:00
Andre_601 cd9074203c
Update label-commenter-config.yml 2022-01-03 00:19:58 +01:00
Andre_601 38d77ff4ca
Update label-commenter-config.yml 2022-01-03 00:17:23 +01:00
Glare 3ccbbe9c20
Bump to 2.11.2 DEV 2021-12-27 01:33:36 -08:00
Glare 358a3bcab3
Release 2.11.1 2021-12-27 01:32:00 -08:00
PiggyPiglet ca088227c3
Merge pull request #772 from PlaceholderAPI/fix/771-identifier-replacement
Fix #771
2021-12-27 15:21:30 +08:00
Andre_601 69fd180c9b
Update CONTRIBUTING.md 2021-12-25 16:55:05 +01:00
Andre_601 38e6e02e1b
Not sure how I missed that... 2021-12-25 15:53:07 +01:00
Andre_601 a71b8657f1
Update Contributing file 2021-12-25 15:50:17 +01:00
PiggyPiglet 850633e792
Fix #771 2021-12-24 12:34:36 +08:00
PiggyPiglet 348b075ac5
added glare's fancy pants dev string to ver 2021-12-24 12:32:01 +08:00
PiggyPiglet ce18d3b597
update licenses & bump deprecation ver 2021-12-24 12:26:22 +08:00
PiggyPiglet 9d66d9d9a1
bump ver 2021-12-24 12:24:40 +08:00
darbyjack 5fe9389dda
We're actually on 2.11.0 RELEASE 2021-12-19 18:59:38 -06:00
darbyjack e25a28b2a5
2.10.11 RELEASE 2021-12-19 18:53:25 -06:00
PiggyPiglet cfd289939e
Merge pull request #667 from PlaceholderAPI/fix/666-lowercase-issues
Fix issue with invalid placeholder pattern lowercasing text
2021-12-19 18:49:37 -06:00
PiggyPiglet d168be94b1
Merge pull request #752 from PlaceholderAPI/1.18
1.18 + Gradle Updates
2021-12-03 13:01:09 +08:00
PiggyPiglet 511717a8d6
Merge branch 'master' into 1.18 2021-12-03 13:01:02 +08:00
PiggyPiglet 18fb194ce6
Merge pull request #677 from PlaceholderAPI/feature/add-logging-options
Add logging options to PlaceholderExpansion
2021-12-03 13:00:15 +08:00
PiggyPiglet e11d551071
Merge pull request #717 from PlaceholderAPI/feature/log-expansio-version
Include version in registration message and other QOL changes
2021-12-03 12:59:20 +08:00
PiggyPiglet 020f14d82c
Merge branch 'master' into feature/log-expansio-version 2021-12-03 12:59:07 +08:00
darbyjack acb5728e65
1.18 + Gradle Updates 2021-12-02 21:55:12 -06:00
Andre_601 cc235cfc01
Merge Development into master (#758)
* Update development from master (#662)

* Add contributing and expansion section

* Start using new Issue template system

* Create bug_report.yml

* Rename feature_request.md to feature_request_old.md

* Create feature_request.yml

* fix unique name

* Update feature_request_old.md

* Add Checkboxes

* Add checkboxes

* disable default issue body

* Delete bug_report_old.md

* Delete feature_request_old.md

* Rename bug_report_new.yml to bug_report.yml

* Check if deleting this fixed the PR...

* Use description in favour of about

* improve feature_request.md

* Update bug_report.yml

* Assign "Type: Issue (Unconfirmed)" label

* Use lists and not comma-separated string

* Update feature_request.yml

* Use id option for error and dump fields

* Add field for logs

* Remove deprecated issue_body type

* Update feature_request.yml

* Improve description of bug_report.yml

* Initial 1.17 Changes

* add render

* Revert build.gradle dependencies change

* Fixed duplicate files

* Initial test on adventure

* started moving to pure adventure

* finished kyori impl

* added 1.17 to nmsversion (what does this even do)

* removed dev for release

* added dev back

Co-authored-by: PiggyPiglet <PiggyPiglet@users.noreply.github.com>
Co-authored-by: darbyjack <admin@glaremasters.me>
Co-authored-by: PiggyPiglet <noreply@piggypiglet.me>

* Update dependencies of PlaceholderAPI

* Add missing trailing /

Co-authored-by: PiggyPiglet <PiggyPiglet@users.noreply.github.com>
Co-authored-by: darbyjack <admin@glaremasters.me>
Co-authored-by: PiggyPiglet <noreply@piggypiglet.me>
2021-12-03 04:52:28 +01:00
PiggyPiglet 894dcd0a2f
Merge pull request #687 from PlaceholderAPI/java-version-dump
Add Java Version to /papi dump command
2021-12-03 11:40:11 +08:00
PiggyPiglet 41c9231664
Merge pull request #749 from itIsMaku/master
nullable annotation placeholderhook
2021-12-03 11:37:52 +08:00
Andre601 31deef2a62 Use completedFuture instead 2021-12-01 21:30:41 +01:00
Andre601 3ba29f1147 Fix possible NPE for findExpansionsOnDisk 2021-12-01 19:09:02 +01:00
Andre601 e969f37405 Improve StringBuilder and also fix possible NPE 2021-12-01 19:05:28 +01:00
Andre_601 b9a5f4445f
Merge pull request #731 from PlaceholderAPI/feature/automatic-release-drafting
Add release.yml for automatic release drafts
2021-11-29 01:36:03 +01:00
Adam Volkman (itIsMaku) 6f87955898
feat: nullable annotation placeholderhook 2021-11-17 14:10:19 +01:00
Andre_601 d68af58df5
Make name of job only show java version 2021-11-11 13:49:48 +01:00
Andre_601 6e1eb88585
Add release.yml for automatic release drafts 2021-10-09 18:39:13 +02:00
Andre_601 0798d94449
Update this flex too funnycube :) 2021-10-01 16:22:30 +02:00
Funnycube aa68a481ee
Update flex 2021-10-01 22:59:12 +10:00
Andre_601 6f5853746d
fix wiki action... again 2021-10-01 14:17:21 +02:00
Andre_601 416fbc0e3e
Merge branch 'docs/wiki' into master 2021-10-01 14:16:06 +02:00
Andre601 407714c13f Rename logo.png to wiki-logo.png 2021-10-01 14:14:41 +02:00
Andre_601 aa13ddf17e
Add files via upload 2021-10-01 14:10:19 +02:00
Andre_601 d9da5a706c
Update README.md 2021-10-01 14:01:59 +02:00
Andre_601 80446de15b
Merge pull request #718 from TheCashFire/patch-1
New Placeholder for %aach_total_commands%
2021-09-23 16:37:08 +02:00
Kris Stancy 0647f88de5
New Placeholder
Added %aach_total_commands% new placeholder to the total achievement placeholders section.
2021-09-19 22:06:01 -05:00
Andre601 38099198d6 Include version in registration message 2021-09-20 02:42:38 +02:00
Andre_601 6f2f1f1cf1
Update README.md 2021-09-12 02:17:58 +02:00
ThisKarolGajda 5e4d3f7135
Update Placeholders.md (#714) 2021-09-10 14:25:24 +02:00
Andre_601 327078d8dd
Update README.md 2021-09-10 03:30:03 +02:00
Andre_601 1b7fabf238
Update Wiki Readme... a lot 2021-09-10 03:23:11 +02:00
Andre_601 66025a6a1c
Update PlaceholderExpansion.md 2021-09-10 02:02:53 +02:00
Andre_601 04f2c85722
fix e-mail env 2021-09-10 01:58:46 +02:00
ThisKarolGajda 7b5ceb520f
Update Placeholders.md - OpEconomy (#713)
* Update Placeholders.md

* Add OpEconomy to "Plugins using PlaceholderAPI"

Co-authored-by: Andre_601 <11576465+Andre601@users.noreply.github.com>
2021-09-10 01:55:13 +02:00
Andre_601 f7dc184899
Update label-commenter-config.yml 2021-09-09 18:32:37 +02:00
Andre_601 4300bf7d1e
Pull latest changes from master into docs/wiki (#712)
* Update Javadoc documentation

* More comments... a lot more!

* Remove Gson

* Implemented working version for 1.8.8 - 1.16.3

* Improve ExpansionsLoadedEvent's docs

* 2021 🥳

* Add contributing and expansion section

* Fix invalid link tag

* Start using new Issue template system

* Create bug_report.yml

* Rename feature_request.md to feature_request_old.md

* Create feature_request.yml

* should it use setBracketPlaceholders??

* fix unique name

* Update feature_request_old.md

* Add Checkboxes

* Add checkboxes

* disable default issue body

* Delete bug_report_old.md

* Delete feature_request_old.md

* Rename bug_report_new.yml to bug_report.yml

* Check if deleting this fixed the PR...

* Use description in favour of about

* improve feature_request.md

* Update bug_report.yml

* Assign "Type: Issue (Unconfirmed)" label

* Use lists and not comma-separated string

* Update feature_request.yml

* Use id option for error and dump fields

* Add field for logs

* Update Copyright
~ Fixed a typo and updated missed files from #543

* Re-add removed code
That should actually NOT be here...

* Undo renaming of boolean

* Remove deprecated issue_body type

* Update feature_request.yml

* Improve description of bug_report.yml

* Build jars on PR (Compile and build validation)

* Initial 1.17 Changes

* Extracted URLClassLoader out of try-with-resources block

* Close URLClassLoader if Expansion class was not found

* Build against Java 8, 11 and 16

* adoPt

I always make that mistake...

* add render

* Cleanup build.gradle

(cherry picked from commit 7750ba7033)

* Remove the @NotNull's because they are overridden by expansion devs anyways, and it turns out people can make them null anyways. This adds a hashcode check and pretty error for it.

(cherry picked from commit f5386d4ca5)

* Fix version checker to compare the individual semver numbers instead of combining it together.

(cherry picked from commit ef5cd9d376)

* Update src/main/java/me/clip/placeholderapi/updatechecker/UpdateChecker.java

Co-authored-by: Andre_601 <11576465+Andre601@users.noreply.github.com>
(cherry picked from commit ccf4f59343)

* Re-add NotNull's

(cherry picked from commit 2bfd8e7e5e)

* Removed nullcheck from hashcode, and moved it up the chain.

* POJO to help with checking that expansions have all required methods implemented.

* Add method implementation checking and nullchecking for fields.

* Appease the Pigman

* Revert build.gradle dependencies change

* Fixed duplicate files

* Sync Dev with master (#659)

* Add contributing and expansion section

* Start using new Issue template system

* Create bug_report.yml

* Rename feature_request.md to feature_request_old.md

* Create feature_request.yml

* fix unique name

* Update feature_request_old.md

* Add Checkboxes

* Add checkboxes

* disable default issue body

* Delete bug_report_old.md

* Delete feature_request_old.md

* Rename bug_report_new.yml to bug_report.yml

* Check if deleting this fixed the PR...

* Use description in favour of about

* improve feature_request.md

* Update bug_report.yml

* Assign "Type: Issue (Unconfirmed)" label

* Use lists and not comma-separated string

* Update feature_request.yml

* Use id option for error and dump fields

* Add field for logs

* Remove deprecated issue_body type

* Update feature_request.yml

* Improve description of bug_report.yml

* Initial 1.17 Changes

* add render

* Revert build.gradle dependencies change

* Fixed duplicate files

Co-authored-by: PiggyPiglet <PiggyPiglet@users.noreply.github.com>
Co-authored-by: darbyjack <admin@glaremasters.me>

* Initial test on adventure

* started moving to pure adventure

* finished kyori impl

* added 1.17 to nmsversion (what does this even do)

* removed dev for release

* added dev back

* Switch to differen wiki action

Co-authored-by: darbyjack <admin@glaremasters.me>
Co-authored-by: ElijahRus250 <64851720+ElijahRus250@users.noreply.github.com>
Co-authored-by: PiggyPiglet <PiggyPiglet@users.noreply.github.com>
Co-authored-by: Huynh Tien <huynhqtienvtag@gmail.com>
Co-authored-by: Vaishnav Anil <vaishnavanil7th@gmail.com>
Co-authored-by: Starmism <iamstarmism@gmail.com>
Co-authored-by: PiggyPiglet <noreply@piggypiglet.me>
2021-09-09 18:31:29 +02:00
Andre_601 5412b484f8
Merge pull request #706 from NotMyFault/feature/wiki/update-plotsquared
Update PlotSquared placeholders
2021-09-03 02:05:39 +02:00
NotMyFault af2f625224
Update PlotSquared placeholders 2021-09-03 00:05:42 +02:00
Andre_601 d2a4f038d0
Merge pull request #705 from DailyStruggle/Add-RTP-Placeholders
add RTP placeholders
2021-09-01 13:39:13 +02:00
Andre_601 7e28dc0a41
Merge pull request #698 from PlaceholderAPI/feature/change-wiki-action
Switch to differen wiki action
2021-09-01 13:38:30 +02:00
Andre_601 b82948c87a
fix link 2021-09-01 13:38:15 +02:00
Andre_601 39c68e8f87
fix url and padding 2021-09-01 13:37:19 +02:00
Leaf26 5a24387f3d fix spacing 2021-08-31 22:39:02 -04:00
Leaf26 cd429bd7d7 adding a few more 2021-08-31 22:38:03 -04:00
Leaf26 a383a73b24 add RTP placeholders 2021-08-31 21:41:32 -04:00
Andre_601 7baaa5233d
Merge pull request #703 from PyvesB/patch-1
Update Advanced Achievements information
2021-08-30 13:06:35 +02:00
Pierre-Yves B b35035390e
Simplify link format
Co-authored-by: Andre_601 <11576465+Andre601@users.noreply.github.com>
2021-08-30 12:05:14 +01:00
Pierre-Yves B 1b0a3bc09d
Simplify link format
Co-authored-by: Andre_601 <11576465+Andre601@users.noreply.github.com>
2021-08-30 12:05:04 +01:00
Pierre-Yves B 3817f52158
Add Advanced Achievements placeholders 2021-08-30 11:44:47 +01:00
Pierre-Yves B 663f149d74
Add Advanced Achievements placeholders 2021-08-30 11:43:26 +01:00
Pierre-Yves B 3da8f00664
Update Advanced Achievements links 2021-08-30 11:18:11 +01:00
Andre_601 c24c75c8c0
Merge pull request #701 from LielAmar/docs/wiki
Added Two Factor Authentication to PlaceholderAPI's wiki
2021-08-27 16:19:13 +02:00
Liel c401adee86 Added Two Factor Authentication to PlaceholderAPI's wiki 2021-08-27 16:24:51 +03:00
Andre_601 1dd3e1fc0d
Switch to differen wiki action 2021-08-26 22:42:05 +02:00
Andre_601 1f53daf416
Some more corrections 2021-08-23 01:58:15 +02:00
Andre_601 8105beeee0
Improve grammar of PlaceholderExpansion.md 2021-08-23 01:52:10 +02:00
Andre_601 8c9a20c035
Merge pull request #696 from TeamVK/docs/wiki
added new placeholders for TokenEnchant
2021-08-22 12:17:49 +02:00
vk2gpz c1d2effe7e
added new placeholders for TokenEnchant
renamed rawcost to fullcost.
added costmax 
```%tokenenchant_<enchantment>_costmax% : cost to increment the enchantmnt level to its maax one from the current level 
%tokenenchant_<enchantment>_fullcostmax% : cost to enchant the max level from 0 level 
%tokenenchant_<enchantment>_fullcost_<X>% : cost to enchant the <X> level from 0 level
```
2021-08-22 09:42:02 +10:00
Andre_601 2eda4b1335
Add missing commands to wiki 2021-08-15 15:44:27 +02:00
Andre_601 ff72450d3f
Merge pull request #692 from BlitzOffline/docs/wiki
Added placeholders from the String expansion
2021-08-15 00:00:41 +02:00
BlitzOffline a654262196
Added placeholders frmo the String expansion 2021-08-15 00:04:17 +03:00
Andre_601 fa705e4572
Merge pull request #689 from TeamVK/docs/wiki
added missing baltop related placeholders and multiplier related placeholders.
2021-08-08 23:24:37 +02:00
vk2gpz e687a06d6e
added missing baltop related placeholders 2021-08-09 07:19:25 +10:00
darbyjack 08c43d25e7
Add Java Version to /papi dump command 2021-08-04 14:16:15 -05:00
Andre_601 48da25659d
Merge pull request #685 from AfkF24/docs/wiki
Update Placeholders.md
2021-07-31 16:46:22 +02:00
AfkF24 905c9e83ee
Apply suggestions from code review
Woop, thanks

Co-authored-by: Andre_601 <11576465+Andre601@users.noreply.github.com>
2021-07-31 16:44:46 +02:00
AfkF24 54ddc9fd4d
Update Placeholders.md
Swap Kingdoms+ for KingdomsX and add link to wiki
2021-07-31 16:23:25 +02:00
Andre601 fe0bb12d53 Add missing [<expansion>] prefix 2021-07-31 00:11:24 +02:00
Andre_601 e6da5f291e
Merge pull request #683 from TeamVK/docs/wiki
Update Placeholders.md
2021-07-29 00:36:40 +02:00
vk2gpz d674893312
Update Placeholders.md
added %levelup_pickaxe_block_count%, %levelup_bow_kill_count%, %levelup_sword_kill_count%
2021-07-29 07:27:27 +10:00
Andre_601 9da9e8c20f
Merge pull request #680 from BlitzOffline/docs/wiki
added changeoutput expansion placeholders
2021-07-24 14:01:29 +02:00
BlitzOffline 33c309ee8e
used inline code instead 2021-07-24 14:17:14 +03:00
BlitzOffline 62c3261a00
added changeoutput expansion placeholders 2021-07-24 14:00:42 +03:00
Funnycube c393392b85
Update Placeholders.md 2021-07-24 17:39:38 +10:00
Funnycube fbf91d6393
Merge pull request #679 from TeamVK/docs/wiki
added RandomNumber and LevelUp entries.
2021-07-24 17:30:49 +10:00
vk2gpz 8d30c4c99d
added RandomNumber and LevelUp entries. 2021-07-24 17:12:03 +10:00
Andre601 721904335d Add overload for Throwable 2021-07-22 23:56:29 +02:00
Andre601 d79f9725bd Add logging options to PlaceholderExpansion 2021-07-22 23:31:48 +02:00
Andre_601 eb2decb93d
Merge pull request #676 from M0diis/docs/wiki
Update Placeholders.md
2021-07-22 22:14:10 +02:00
M0dii d2192e3195
Update Plugins-using-PlaceholderAPI.md
Added VenturaCalendar.
2021-07-22 23:11:09 +03:00
M0dii c01acfba77
Update Placeholders.md
Change resource ID.
2021-07-22 21:54:44 +03:00
M0dii a494add04c
Update Placeholders.md 2021-07-22 21:48:38 +03:00
Andre_601 059047905f
Update formatter placeholders 2021-07-22 17:28:06 +02:00
Andre_601 fa717c34ef
fix code examples 2021-07-22 12:56:56 +02:00
Andre_601 e16287405b
Update nav entries (#674)
* Update nav entries

* Update Home.md
2021-07-22 01:36:43 +02:00
Andre_601 afdf80bf00
Rework PlaceholderExpansion page (#654)
* Rework PlaceholderExpansion page

* typo

* Implement suggestions of FunnyCube

* Apply suggestions from code review

Co-authored-by: Star <iamstarmism@gmail.com>

* Update wiki/PlaceholderExpansion.md

Co-authored-by: Star <iamstarmism@gmail.com>

* Rename "With a Plugin (Internal Jar)" to "With a Plugin (Internal Class)"

Co-authored-by: Star <iamstarmism@gmail.com>
2021-07-22 01:29:30 +02:00
Andre_601 ec7943fe0a
Fix formatting too 2021-07-17 22:23:28 +02:00
Andre_601 6493963d8a
Forgot the list-entry 2021-07-17 22:22:22 +02:00
Andre_601 c48e11bd70
Add OreMarket placeholders (#671)
* Add OreMarket placeholders

* Update Plugins-using-PlaceholderAPI.md

* Add URL
2021-07-17 22:18:53 +02:00
Andre_601 b4f6831e54
Update development from master (#662)
* Add contributing and expansion section

* Start using new Issue template system

* Create bug_report.yml

* Rename feature_request.md to feature_request_old.md

* Create feature_request.yml

* fix unique name

* Update feature_request_old.md

* Add Checkboxes

* Add checkboxes

* disable default issue body

* Delete bug_report_old.md

* Delete feature_request_old.md

* Rename bug_report_new.yml to bug_report.yml

* Check if deleting this fixed the PR...

* Use description in favour of about

* improve feature_request.md

* Update bug_report.yml

* Assign "Type: Issue (Unconfirmed)" label

* Use lists and not comma-separated string

* Update feature_request.yml

* Use id option for error and dump fields

* Add field for logs

* Remove deprecated issue_body type

* Update feature_request.yml

* Improve description of bug_report.yml

* Initial 1.17 Changes

* add render

* Revert build.gradle dependencies change

* Fixed duplicate files

* Initial test on adventure

* started moving to pure adventure

* finished kyori impl

* added 1.17 to nmsversion (what does this even do)

* removed dev for release

* added dev back

Co-authored-by: PiggyPiglet <PiggyPiglet@users.noreply.github.com>
Co-authored-by: darbyjack <admin@glaremasters.me>
Co-authored-by: PiggyPiglet <noreply@piggypiglet.me>
2021-07-11 01:37:09 +02:00
PiggyPiglet 6348c88c6f
added dev back 2021-07-10 12:17:08 +08:00
PiggyPiglet 5fb45d13da
removed dev for release 2021-07-10 12:16:37 +08:00
PiggyPiglet 5710972288
Merge remote-tracking branch 'origin/master' 2021-07-10 11:27:08 +08:00
PiggyPiglet 63955511a8
added 1.17 to nmsversion (what does this even do) 2021-07-10 11:26:56 +08:00
PiggyPiglet 9a7790c808
Merge pull request #661 from PlaceholderAPI/adventure
Adventure
2021-07-09 17:00:44 +08:00
PiggyPiglet 3abc78ff64
Merge pull request #660 from PlaceholderAPI/development
Sync Dev with master (#659)
2021-07-09 15:50:01 +08:00
PiggyPiglet c4789b7db0
finished kyori impl 2021-07-09 12:24:36 +08:00
PiggyPiglet d7a4acc2f5
started moving to pure adventure 2021-07-07 15:37:35 +08:00
darbyjack dd7751332f
Initial test on adventure 2021-07-06 11:59:17 -05:00
Andre_601 7b50453294
Add new Essentials placeholders 2021-07-03 17:56:32 +02:00
Andre_601 fa7c30df80
Sync Dev with master (#659)
* Add contributing and expansion section

* Start using new Issue template system

* Create bug_report.yml

* Rename feature_request.md to feature_request_old.md

* Create feature_request.yml

* fix unique name

* Update feature_request_old.md

* Add Checkboxes

* Add checkboxes

* disable default issue body

* Delete bug_report_old.md

* Delete feature_request_old.md

* Rename bug_report_new.yml to bug_report.yml

* Check if deleting this fixed the PR...

* Use description in favour of about

* improve feature_request.md

* Update bug_report.yml

* Assign "Type: Issue (Unconfirmed)" label

* Use lists and not comma-separated string

* Update feature_request.yml

* Use id option for error and dump fields

* Add field for logs

* Remove deprecated issue_body type

* Update feature_request.yml

* Improve description of bug_report.yml

* Initial 1.17 Changes

* add render

* Revert build.gradle dependencies change

* Fixed duplicate files

Co-authored-by: PiggyPiglet <PiggyPiglet@users.noreply.github.com>
Co-authored-by: darbyjack <admin@glaremasters.me>
2021-07-01 21:03:01 +02:00
darbyjack 89053354e9
Fixed duplicate files 2021-07-01 09:24:01 -05:00
Andre_601 ead63ca763
Revert build.gradle dependencies change 2021-07-01 16:21:49 +02:00
Andre_601 0fa592383f
Merge branch 'development' into master 2021-07-01 16:16:29 +02:00
PiggyPiglet 7df3a5c6e0
Merge pull request #657 from Starmism/development
Small changes on the correct branch!
2021-07-01 22:08:04 +08:00
Starmism c4a2256fff Appease the Pigman 2021-07-01 07:54:42 -06:00
Starmism 9b6b558002 Add method implementation checking and nullchecking for fields. 2021-06-30 10:13:47 -06:00
Starmism 94bf5fea57 POJO to help with checking that expansions have all required methods implemented. 2021-06-30 10:13:29 -06:00
Starmism 252802dcbe Removed nullcheck from hashcode, and moved it up the chain. 2021-06-30 10:13:12 -06:00
PiggyPiglet 8932a92049
Merge pull request #658 from PlaceholderAPI/1.17
Initial 1.17 Changes
2021-06-30 21:16:12 +08:00
Starmism 679ef90091 Re-add NotNull's
(cherry picked from commit 2bfd8e7e5e)
2021-06-30 05:59:57 -06:00
Star ac9b0c42b7 Update src/main/java/me/clip/placeholderapi/updatechecker/UpdateChecker.java
Co-authored-by: Andre_601 <11576465+Andre601@users.noreply.github.com>
(cherry picked from commit ccf4f59343)
2021-06-30 05:59:52 -06:00
Starmism 14d885392c Fix version checker to compare the individual semver numbers instead of combining it together.
(cherry picked from commit ef5cd9d376)
2021-06-30 05:59:45 -06:00
Starmism 0c102a1823 Remove the @NotNull's because they are overridden by expansion devs anyways, and it turns out people can make them null anyways. This adds a hashcode check and pretty error for it.
(cherry picked from commit f5386d4ca5)
2021-06-30 05:59:33 -06:00
Starmism 4c968f012d Cleanup build.gradle
(cherry picked from commit 7750ba7033)
2021-06-30 05:59:22 -06:00
Andre_601 ba71486151
Merge pull request #655 from LOOHP/docs/wiki
Update InteractionVisualizer placeholders
2021-06-30 11:35:46 +02:00
LOOHP e1269d6c86 Update InteractionVisualizer placeholders 2021-06-30 13:48:22 +08:00
Andre_601 438a665b74
add render 2021-06-27 14:31:15 +02:00
PiggyPiglet 247a5cde8f
Merge pull request #623 from PlaceholderAPI/feature/621-build-jars-on-pr
Build jars on PR (Compile and build validation)
2021-06-26 11:51:00 +08:00
Andre_601 aa9ac65d02
Merge pull request #650 from SaltyAimbOtter/patch-1
update BetonQuest docs link
2021-06-25 23:34:36 +02:00
SaltyAimbOtter ba983f7fb3
update BetonQuest docs link 2021-06-25 23:23:04 +02:00
Andre_601 af268c4941
adoPt
I always make that mistake...
2021-06-25 16:33:27 +02:00
Andre_601 4c4b1602d9
Build against Java 8, 11 and 16 2021-06-25 16:32:45 +02:00
PiggyPiglet 8c69a164b8
Merge pull request #649 from Vshnv/patch/expansion-classloader
Fixed issue with expansions not being able to access their resources
2021-06-25 22:11:58 +08:00
Vaishnav Anil df8583df57 Close URLClassLoader if Expansion class was not found 2021-06-25 05:08:14 +05:30
Vaishnav Anil 09e68e7510 Extracted URLClassLoader out of try-with-resources block 2021-06-25 05:07:14 +05:30
Andre_601 2c223ffc87
Merge pull request #647 from cj89898/docs/wiki
Added 2.3.0 Checkitem changes
2021-06-20 18:38:27 +02:00
cj89898 5571ba5d70
Added 2.3.0 Checkitem changes 2021-06-20 10:49:28 -05:00
Andre_601 b77b1b9649
Update Placeholders.md 2021-06-17 14:49:16 +02:00
Andre_601 bf9b34eb57
Merge pull request #645 from stumper66/docs/wiki
LevelledMobs Wiki Addition
2021-06-17 14:45:07 +02:00
Penal Buffalo 215fd7e3f0
Update wiki/Placeholders.md
Co-authored-by: Andre_601 <11576465+Andre601@users.noreply.github.com>
2021-06-17 07:44:14 -05:00
stumper66 aca624c2d3 LevelledMobs
Added LevelledMobs info to the wiki
2021-06-17 07:26:07 -05:00
Andre_601 5826390251
Merge pull request #642 from garagepoort/feature/add_staffplusplus_wiki
Add staff++ to the wiki
2021-06-15 21:59:55 +02:00
David Maes a91a5c85ba Better phrasing 2021-06-15 21:57:47 +02:00
David Maes 156243a549 Add staff++ to the wiki 2021-06-15 21:52:32 +02:00
Andre_601 eceb236121
Merge pull request #640 from cj89898/docs/wiki
Update Placeholders.md
2021-06-11 11:43:03 +02:00
darbyjack 71b5433326
Initial 1.17 Changes 2021-06-11 01:33:29 -05:00
cj89898 2c8314200f
Update Placeholders.md
Added 2.2.0 checkitem placeholder
2021-06-10 21:52:36 -05:00
Andre_601 0b70ea61aa
Merge pull request #639 from darbyjack/docs/wiki
Added in some missing placeholders for Player Expansion
2021-06-09 16:00:38 +02:00
darbyjack ac31e107ad
Added in some missing placeholders 2021-06-09 08:58:49 -05:00
Andre_601 b9230ef9c5
Merge pull request #631 from broken1arrow/docs/wiki
Docs/wiki
2021-05-13 14:58:20 +02:00
broken1arrow 06e6765870 Try for the 10 times to make it right
See if this work better
2021-05-13 14:45:46 +02:00
broken1arrow 5ac579e878 Revert "Has change and add descriptions"
This reverts commit a4d8009ce4.
2021-05-13 14:41:33 +02:00
broken1arrow a4d8009ce4 Has change and add descriptions
Try other way and see if this work better to pull uppdates.
2021-05-12 17:19:05 +02:00
Andre_601 0df265881a
Add CalculateNumbers 2021-05-12 00:03:34 +02:00
Andre_601 5dbd58076a
Add %rng_online_player% 2021-05-08 14:17:19 +02:00
Andre_601 c3922de323
Update Commands.md 2021-05-07 23:45:29 +02:00
Andre_601 0f118f12bc
Merge pull request #626 from Lorenzo0111/patch-1
Update RocketPlaceholders documentation url
2021-05-04 17:12:15 +02:00
Lorenzo edd3153acd
Update documentation url 2021-05-04 16:24:18 +02:00
Andre_601 748b9f33f7
Build jars on PR (Compile and build validation) 2021-04-26 18:05:42 +02:00
Andre601 230e36c55e [Wiki] Add Lands 2021-04-23 00:08:00 +02:00
Andre_601 0f7294972e
Merge pull request #618 from PlaceholderAPI/feature/improve-placeholders-page
Redesign Placeholders page and other pages
2021-04-22 23:53:37 +02:00
Andre_601 d14f319eb4
Improve description of bug_report.yml 2021-04-21 14:30:46 +02:00
Andre_601 0927760d76
Merge pull request #619 from PlaceholderAPI/feature/remove-issue-body-field
Remove deprecated issue_body type
2021-04-21 14:25:40 +02:00
Andre_601 91af12f575
Update feature_request.yml 2021-04-21 14:24:40 +02:00
Andre_601 5dbbe01b95
Remove deprecated issue_body type 2021-04-21 14:24:14 +02:00
Andre601 30b5abda19 Fix wrong links 2021-04-20 23:30:43 +02:00
Andre601 a8e996fa26 Redesign Placeholders page and other pages 2021-04-20 23:21:24 +02:00
Andre_601 3f83312454
Merge pull request #616 from Warriorrrr/update-towny-placeholders
Update Towny placeholders
2021-04-18 03:23:41 +02:00
Warrior 0b1bd1c265 Forgot the dot. 2021-04-18 02:40:30 +02:00
Warrior b747720f36 Update towny placeholders 2021-04-18 02:33:40 +02:00
Andre_601 be34f28fd3
Merge pull request #615 from Hempfest/docs/wiki
Docs/wiki
2021-04-17 11:45:31 +02:00
Hempfest 9843d84ac3
Updated Clans Pro Listing.
New placeholders.
2021-04-17 02:43:19 -07:00
Andre_601 37de42f4a7
Merge pull request #613 from MysteriousKyle/docs/wiki
Addition of a plugin using PalaceholderAPI
2021-04-14 18:01:05 +02:00
Kyle 5595bc144f Addition of a plugin using PalaceholderAPI 2021-04-14 10:56:27 -05:00
Andre_601 9b2e7bb3ca
Merge pull request #611 from thienbao860/patch-2
Update placeholders, clear Spectator expansion
2021-04-13 18:23:16 +02:00
thienbao860 8b5ead7a13
Update placeholders, clear Spectator expansion 2021-04-13 23:18:39 +07:00
Andre_601 0c6dd5466c
Merge pull request #610 from PlaceholderAPI/fix/update-missing-copyright
Update Copyright
2021-04-13 17:59:21 +02:00
Andre601 41275509b2 Undo renaming of boolean 2021-04-13 17:58:42 +02:00
Andre601 4e8b1b47d1 Re-add removed code
That should actually NOT be here...
2021-04-13 17:57:59 +02:00
Andre601 d0e62e6434 Update Copyright
~ Fixed a typo and updated missed files from #543
2021-04-13 17:54:57 +02:00
Andre_601 2086fcb299
Merge pull request #583 from HSGamer/patch-1
should it use setBracketPlaceholders??
2021-04-13 17:20:59 +02:00
Andre_601 b3ea920b41
Merge pull request #608 from CMPSCjg/patch-1
Add 2 New TokensPlus Placeholders
2021-04-12 17:52:22 +02:00
CMPSCjg 001fa6bcf2
Add 2 New TokensPlus Placeholders 2021-04-12 11:49:16 -04:00
PiggyPiglet 3a31c5cb78
Merge pull request #485 from PlaceholderAPI/fix/477-remove-gson
Remove Gson
2021-04-12 21:40:55 +08:00
PiggyPiglet 20b2a69b5e
Merge pull request #558 from PlaceholderAPI/development
Sync Master branch with Development (Possible Release)
2021-04-12 21:35:32 +08:00
PiggyPiglet 682717660f
Merge pull request #546 from PlaceholderAPI/feature/add-sections
Add contributing and expansion section
2021-04-12 21:16:18 +08:00
PiggyPiglet 7b7bfb7306
Merge pull request #543 from ElijahRus250/master
2021 🥳
2021-04-12 21:13:38 +08:00
Andre_601 09043c6aaf
Merge pull request #607 from RobinDeBaets/patch-1
Add %statistic_mob_kills%
2021-04-10 17:24:03 +02:00
RobinDeBaets f711500d80
Add %statistic_mob_kills% 2021-04-10 17:01:54 +02:00
Andre_601 8d6aa7c801
Merge pull request #606 from Lorenzo0111/patch-1
Edit RocketPlaceholders on the wiki
2021-04-02 19:36:09 +02:00
Lorenzo 04968cb437
Update Plugins-using-PlaceholderAPI.md 2021-04-02 17:01:52 +02:00
Andre_601 048c539fff
Merge pull request #604 from Paul19988/docs/wiki
Add entry for Expansion "TeamsExpansion"
2021-03-31 17:28:49 +02:00
Andre_601 501d1bbbdd
Add minor corrections 2021-03-31 17:28:14 +02:00
Paul Baird e4a6faa22a
Corrected ecloud link for name change 2021-03-31 16:09:15 +01:00
Paul Baird c3bdc90168
Corrected entry and added ecloud command 2021-03-31 15:59:44 +01:00
Paul Baird 79ec3c8f95
Added TeamExpansion in correct place 2021-03-31 15:29:46 +01:00
Paul Baird e9e4caf989
Add TeamsExpansion placeholder expansion 2021-03-31 15:24:25 +01:00
Andre_601 0b1a3ced9e
Merge pull request #602 from matahombres/patch-3
Update advancements placeholder
2021-03-27 17:14:34 +01:00
matahombres b55261a62f
Update advancements placeholder 2021-03-27 17:06:25 +01:00
Andre_601 8c633c8943
Merge pull request #600 from LOOHP/docs/wiki
Add %interactivechat_invdisplaylayout% placeholder
2021-03-26 14:58:56 +01:00
LOOHP 8757217fb6 Add %interactivechat_invdisplaylayout% placeholder 2021-03-26 21:53:43 +08:00
Andre_601 8f796e3940
Add field for logs 2021-03-26 14:53:02 +01:00
Andre_601 bf1527a40f
Use id option for error and dump fields 2021-03-26 14:42:20 +01:00
Andre_601 a65de95b16
Merge pull request #599 from Alpha018/wiki_update
modify: Change wiki to use new placeholder
2021-03-25 07:11:49 +01:00
Alpha018 fb8572313e modify: Change wiki to use new placeholder 2021-03-25 03:07:49 -03:00
vk2gpz 2fc28777b7
added %vkautopickup_autosmelt% and %vkautopickup_autoblock% to VKAutoPickup. 2021-03-25 12:56:26 +11:00
Andre_601 ffd493fea9
Merge pull request #597 from CMPSCjg/patch-2
Add TokensPlus Placeholder
2021-03-24 21:37:32 +01:00
Andre_601 b207cbf03e
Add plugin to Plugins using PlaceholderAPI page 2021-03-24 21:37:06 +01:00
CMPSCjg 72239801d8
Update Placeholders.md 2021-03-24 16:19:33 -04:00
CMPSCjg 33ff83d102
Update wiki/Placeholders.md
My bad, thought I updated the URL to reflect this format.

Co-authored-by: Andre_601 <11576465+Andre601@users.noreply.github.com>
2021-03-24 16:16:04 -04:00
CMPSCjg 031625e241
Add TokensPlus Placeholder 2021-03-24 15:58:13 -04:00
Andre_601 ec127dbeb1
Merge pull request #595 from PlaceholderAPI/docs/wiki
Sync Development and docs/wiki
2021-03-24 09:17:58 +01:00
Andre_601 5d80119fcd
Merge pull request #594 from PlaceholderAPI/feature/wiki-add-vkautopickup
Add VKAutoPickup
2021-03-24 09:14:56 +01:00
Andre_601 f6c972c9a2
Add VKAutoPickup 2021-03-24 09:12:31 +01:00
Andre_601 a0b256c17d
Merge pull request #593 from lucko/patch-1
Update LuckPerms placeholders
2021-03-21 14:58:22 +01:00
lucko a66cae9a6b
Update LuckPerms placeholders 2021-03-21 13:52:58 +00:00
Andre_601 7f6122f8b8
Merge pull request #591 from ajgeiss0702/docs/wiki
Update ajParkour + add ajLeaderboards placeholders
2021-03-19 16:53:14 +01:00
ajgeiss0702 ee7257208a Update ajParkour + add ajLeaderboards 2021-03-19 08:47:51 -07:00
Andre_601 87ea46a4dd
Merge pull request #585 from PlaceholderAPI/fix/change-to-stringlist
Use lists and not comma-separated string
2021-03-11 22:09:05 +01:00
Andre_601 d221a3f38a
Update feature_request.yml 2021-03-11 22:08:51 +01:00
Andre_601 f62980606a
Use lists and not comma-separated string 2021-03-11 22:07:48 +01:00
Andre_601 c2ab9f5b85
Assign "Type: Issue (Unconfirmed)" label 2021-03-08 18:08:35 +01:00
Andre_601 2c925983a8
Merge pull request #584 from PlaceholderAPI/fix/issue-form-about-deprecation
Use description in favour of about
2021-03-08 18:07:02 +01:00
Andre_601 375e743124
Update bug_report.yml 2021-03-08 18:06:10 +01:00
Andre_601 78f76c8343
improve feature_request.md 2021-03-08 17:51:42 +01:00
Andre_601 33e4743e89
Use description in favour of about 2021-03-08 17:36:34 +01:00
Andre_601 b9b7104f6b
Merge pull request #580 from PlaceholderAPI/feature/use-new-issue-system
Start using new Issue template system
2021-03-08 17:34:02 +01:00
Andre_601 a45f420069
Check if deleting this fixed the PR... 2021-03-08 17:26:21 +01:00
Andre_601 a7d92f569f
Rename bug_report_new.yml to bug_report.yml 2021-03-08 16:12:25 +01:00
Andre_601 73f55735b4
Delete feature_request_old.md 2021-03-08 16:10:43 +01:00
Andre_601 a15c6b4855
Delete bug_report_old.md 2021-03-08 16:10:34 +01:00
Andre_601 48f7ffe089
disable default issue body 2021-03-08 15:59:52 +01:00
Andre_601 c607338003
Add checkboxes 2021-03-08 15:56:26 +01:00
Andre_601 66a7a6d199
Add Checkboxes 2021-03-08 15:53:04 +01:00
Andre_601 1d7bf239ea
Update feature_request_old.md 2021-03-08 15:44:41 +01:00
Andre_601 43a5db7711
fix unique name 2021-03-08 15:44:10 +01:00
Huynh Tien 0e56ea9503
should it use setBracketPlaceholders?? 2021-03-06 20:37:43 +07:00
Andre_601 d640d801e6
Create feature_request.yml 2021-02-28 11:00:23 +01:00
Andre_601 b5c70dedcb
Rename feature_request.md to feature_request_old.md 2021-02-28 10:48:06 +01:00
Andre_601 a8bcf0e14d
Create bug_report.yml 2021-02-28 10:41:15 +01:00
Andre_601 0c13004040
Start using new Issue template system 2021-02-28 10:05:16 +01:00
Andre_601 cc05a3508b
Merge pull request #579 from LOOHP/docs/wiki
Adds and updates InteractiveChat, InteractionVisualizer and HoloMobHealth on the wiki
2021-02-28 07:56:43 +01:00
LOOHP 458030c575 Added HoloMobHealth 2021-02-28 14:50:38 +08:00
LOOHP 3b4641c26c Added InteractiveChat, Updated InteractionVisualizer 2021-02-28 14:41:13 +08:00
Andre_601 9b03af17b6
Merge pull request #576 from matahombres/patch-2
Added more placeholders to wiki
2021-02-18 19:25:00 +01:00
matahombres 72b2be4933
Added more placeholders to wiki
Add more advancements placeholders
2021-02-18 18:47:14 +01:00
Andre_601 2f0f717d44
Update formatter expansion list 2021-02-17 17:15:59 +01:00
Andre_601 e3bef564f2
Merge pull request #574 from Kqliber/patch-1
Added extra placeholders to wiki
2021-02-15 23:04:27 +01:00
Kqliber 319be0e043
Added extra placeholders
Added the RNG expansion 
Updated the chat reaction placeholders list
2021-02-15 21:54:44 +00:00
Andre_601 431483da89
Merge pull request #571 from Hempfest/master
PR to correct branch.
2021-02-14 17:57:04 +01:00
Hempfest d07376245c
minor edits 2021-02-14 08:37:00 -08:00
Hempfest 2aa6ac2b63
minor edit 2021-02-14 08:35:09 -08:00
Hempfest 03a362817c
Updated my plugin listings.
Updated listing for Clans [Free] and Clans [Pro] Listings. Both plugins are utilizing the API and are available on spigot as i type this.
2021-02-14 06:32:15 -08:00
Hempfest 2dc972423a
Updated listings for both of my plugins
Updated listing for Clans [Free] and Clans [Pro] Listings. Both plugins are utilizing the API and are available on spigot as i type this.
2021-02-14 06:30:38 -08:00
Andre_601 4b43d35bcc
Merge pull request #567 from ArVdC/docs/wiki
Add TimeManager placeholders
2021-02-13 21:36:54 +01:00
ArVdC 350ec10186
Update Plugins-using-PlaceholderAPI.md 2021-02-13 21:14:21 +01:00
ArVdC 0104e48b72
Update Placeholders.md 2021-02-13 21:13:43 +01:00
Andre_601 a88f7aab30
Merge pull request #562 from HappyRogelio7/patch-2
Update Placeholders.md
2021-02-10 22:48:51 +01:00
Andre_601 e91ed337cc
Merge pull request #563 from HappyRogelio7/patch-3
Update Plugins-using-PlaceholderAPI.md
2021-02-10 22:48:28 +01:00
HappyRogelio7 32d5b7697d
Update Plugins-using-PlaceholderAPI.md 2021-02-10 13:21:43 -03:00
HappyRogelio7 c23d35d219
Update Placeholders.md 2021-02-10 13:18:31 -03:00
Andre_601 6b04b6c39b
Use pull_request_target 2021-02-10 15:29:33 +01:00
Andre_601 021d5b1f47
Update label-commenter-config.yml 2021-02-10 15:29:03 +01:00
Andre_601 b0f14c6e4e
Merge pull request #559 from RoinujNosde/docs/wiki
Update Placeholders.md
2021-02-10 01:34:47 +01:00
Edson Passos cd3a0f52d5
Update Placeholders.md
Changes SimpleClans' resource page link
Adds link to wiki page listing placeholders
2021-02-09 19:41:36 -03:00
Andre_601 cc5835423f
Improve Wiki Readme 2021-02-09 04:46:18 +01:00
Andre_601 155fc0592a
Branch is actually called development 2021-02-09 04:01:29 +01:00
Andre_601 a163c72e93
Update Placeholders.md 2021-02-04 18:09:44 +01:00
Andre_601 562f6a852d
Add Shortcut expansion 2021-02-04 15:02:35 +01:00
Andre_601 bfb88781af
Improve placeholder pattern and info 2021-02-04 14:59:14 +01:00
Andre_601 ff4656bbe7
Update formatter placeholders 2021-02-02 22:17:32 +01:00
Andre_601 c44b08e2e9
Merge pull request #553 from SrBedrock/patch-1
Update GriefPrevention Expansion
2021-01-31 22:35:10 +01:00
ThiagoROX 4d14b583ff
Update GriefPrevention Expansion
Add %griefprevention_bonusclaims_formatted% from GriefPrevention Expansion version 1.5.2
2021-01-31 18:30:13 -03:00
Andre_601 892f0727e8
Fix invalid link tag 2021-01-29 03:29:35 +01:00
PiggyPiglet 3635ecb8b4
Merge pull request #528 from PlaceholderAPI/feature/add-faq-entry
Update FAQ
2021-01-29 10:11:19 +08:00
PiggyPiglet dd2981b13e
Merge pull request #443 from PlaceholderAPI/feature/update-documentation
Update Javadoc documentation
2021-01-29 10:10:12 +08:00
Andre_601 ff60343089
Add contributing and expansion section 2021-01-24 17:47:03 +01:00
Andre_601 fb77c42bba
Brag a bit more about this 2021-01-24 17:35:30 +01:00
Andre_601 a65b9ad49e
Merge pull request #545 from eggsy/master
🔧 update wrong (time_played) statistic types on wiki
2021-01-24 15:23:28 +01:00
EGGSY 0ed32c7ddd 🔧 update wrong statistic types 2021-01-24 15:15:44 +03:00
Andre601 f1350783fc Use repo links 2021-01-21 01:58:44 +01:00
Andre601 5ac2efd9c6 Trying out img folder in wiki 2021-01-21 01:54:34 +01:00
ElijahRus250 a7247acbb3 2021 🥳 2021-01-20 15:29:13 -05:00
Andre_601 0b3663ee87
Merge pull request #542 from cj89898/docs/wiki
Updated deluxemenus on wiki
2021-01-20 16:04:28 +01:00
cj89898 ba9b38dd0e
Update Plugins-using-PlaceholderAPI.md
Updated deluxemenus to providing placeholders
2021-01-20 08:58:59 -06:00
cj89898 62bb68ee94
Update Placeholders.md
Added deluxemenus
2021-01-20 08:57:39 -06:00
Andre_601 e96c6fb7ef
Merge pull request #540 from steve4744/docs/wiki
update parkour placeholders
2021-01-19 02:07:15 +01:00
BuildTools c04c101de5 update parkour placeholders 2021-01-19 00:19:36 +00:00
Andre_601 5ab2c05821
Merge pull request #539 from LeonMangler/patch-1
Update PremiumVanish placeholders
2021-01-18 22:25:42 +01:00
Leon Mangler 9b9e0e4b9e
Update PremiumVanish placeholders 2021-01-18 22:00:02 +01:00
Andre_601 c3ee5bbdc0
Actually was renamed too 2021-01-11 22:28:32 +01:00
Andre_601 fb70ba6403
Update invalid link 2021-01-11 22:22:34 +01:00
Andre_601 f605db479b
Improve message 2021-01-11 22:16:39 +01:00
Andre_601 175308ecf5
Merge pull request #533 from granny/docs/wiki
DiscordSRV placeholders are now integrated in DiscordSRV
2021-01-07 23:39:04 +01:00
granny 2adf2845fd DiscordSRV placeholders are now integrated in DiscordSRV 2021-01-07 14:04:27 -08:00
Andre_601 0438c67f7d
Markdown rendering 2021-01-06 17:33:24 +01:00
Andre_601 47d6928b9f
Mention headers 2021-01-06 17:30:14 +01:00
Andre_601 deee5a1c39
Use new message 2021-01-06 17:09:08 +01:00
Andre_601 c9492564e0
Mention Discussion entry 2021-01-06 16:42:32 +01:00
Andre_601 0c826a288e
Link to the wiki folder 2021-01-06 14:40:33 +01:00
PiggyPiglet 093ba4d68c
Merge pull request #530 from PlaceholderAPI/fix/515-proper-expansion-null-checks
Fix contract violations & add null checks which should close #515
2021-01-04 10:25:48 +08:00
PiggyPiglet 1478aabb5e
remove an from log message
Co-authored-by: Andre_601 <11576465+Andre601@users.noreply.github.com>
2021-01-04 10:25:38 +08:00
PiggyPiglet 07ac8e41c5 Fix contract violations & add null checks which should close #515 2021-01-03 23:42:23 +08:00
PiggyPiglet f0dccbd594 update gradle 2021-01-03 23:35:37 +08:00
PiggyPiglet 26fdedd989
Merge pull request #529 from PlaceholderAPI/fix/527-improve-parse-command
Fix resolvePlayer method
2021-01-03 23:28:52 +08:00
PiggyPiglet d342c73f24
Merge pull request #517 from PlaceholderAPI/fix/515-improve-logging
Fixing issues for logging when Expansion doesn't contain any classes.
2021-01-03 22:40:20 +08:00
Andre601 0a52ef7219 Use a generic log message for this 2021-01-03 15:38:10 +01:00
Andre601 6a69ec833f Use getPlayerExact 2021-01-01 18:19:07 +01:00
Andre_601 b540127651
Add a little © 2020-12-31 22:12:51 +01:00
Andre601 8fa0f73a46 Fix resolvePlayer method 2020-12-31 18:20:11 +01:00
Andre_601 077a221c3f
Update FAQ.md 2020-12-31 15:12:09 +01:00
Andre_601 301a1c9ac5
Merge pull request #526 from cj89898/docs/wiki
Update Placeholders.md
2020-12-30 11:51:36 +01:00
cj89898 0db15f96ae
Update Placeholders.md 2020-12-29 20:17:44 -06:00
Andre_601 9b2ea05875
Improve ExpansionsLoadedEvent's docs 2020-12-29 21:12:22 +01:00
Andre_601 27d8ae03e1
fix wrong var name 2020-12-29 18:54:39 +01:00
Andre_601 15e22ea115
Merge pull request #525 from Harieo/docs/wiki
Adds seasons plugin to Wiki
2020-12-29 18:31:54 +01:00
Harieo f398854c68 Added extra square brackets to match other links in Plugins-using-PlaceholderAPI.md 2020-12-29 16:57:12 +00:00
Harieo 29446c08b6 Reverted previous commit 2020-12-29 16:51:36 +00:00
Harieo 3d44f8ffdc Changed wiki.yml workflow to generate personal Wiki page 2020-12-29 16:48:29 +00:00
Harieo 61afb24d33 Added the Seasons plugin as a plugin using PlaceholderAPI 2020-12-29 16:42:32 +00:00
Andre_601 e8b5660eda
Use invalid on PR too 2020-12-28 22:17:01 +01:00
Andre_601 d4744838ee
Merge pull request #522 from PlaceholderAPI/master
Update docs/wiki from master
2020-12-28 22:12:50 +01:00
Andre_601 32f3e21ab7
Merge pull request #521 from weihao/docs/wiki
Added Ath wiki to docs branch
2020-12-28 22:11:48 +01:00
Weihao e6d57f81da
Update wiki/Placeholders.md
Co-authored-by: Andre_601 <11576465+Andre601@users.noreply.github.com>
2020-12-28 16:10:53 -05:00
Weihao 818bf91c93 Merge branch 'docs/wiki' of https://github.com/weihao/PlaceholderAPI into docs/wiki 2020-12-28 16:10:24 -05:00
Weihao ac2c2b324e Improvements 2020-12-28 16:10:10 -05:00
Weihao cf9d07a856
Update wiki/Plugins-using-PlaceholderAPI.md
Co-authored-by: Andre_601 <11576465+Andre601@users.noreply.github.com>
2020-12-28 16:08:19 -05:00
Weihao 860239fa2b Added Ath 2020-12-28 15:50:55 -05:00
Andre_601 69f0ede0c6
Also check for PRs 2020-12-28 21:45:54 +01:00
Andre_601 480f13a3ce
Now this should work 2020-12-28 15:46:06 +01:00
Andre601 b99335e5b2 First step at fixing #515 and for #516 2020-12-27 18:47:48 +01:00
Andre_601 e83eba9226
fix missing linebreak 2020-12-27 18:33:20 +01:00
Andre_601 278a5a4096
mention paste url 2020-12-27 14:12:01 +01:00
Andre_601 1cfa247f8c
Seems to not work as intended 2020-12-26 23:32:12 +01:00
Andre_601 a3b2777d16
Merge branch 'master' into feature/update-documentation 2020-12-26 23:01:03 +01:00
Andre_601 3c9f6ea520
Only work on non-closed issues 2020-12-25 15:09:25 +01:00
Andre_601 15d2452b19
Merge pull request #514 from steve4744/docs/wiki
update parkour and tntrun_reloaded placeholders
2020-12-23 00:19:01 +01:00
BuildTools f582474fb1 update parkour and tntrun_reloaded placeholders 2020-12-22 23:10:58 +00:00
BuildTools b1662676f1 update parkour and tntrun_reloaded placeholders 2020-12-22 23:01:45 +00:00
PiggyPiglet 23943f41ad
Merge pull request #513 from PlaceholderAPI/dont-fail-on-error
Javadoc Changes
2020-12-14 09:01:40 +08:00
darbyjack 3cd665a159
Javadoc Changes
- Don't fail on error
- Add license to new files that were merged
2020-12-13 18:58:55 -06:00
PiggyPiglet 4074192c0b
Merge pull request #512 from PlaceholderAPI/fix/javadoc-build-errors
Fix Javadoc build errors
2020-12-14 08:54:27 +08:00
Andre601 59cd5982ad Complete fix 2020-12-14 01:52:46 +01:00
Andre601 b3893c38db Hopefully fixing all the JD issues 2020-12-14 01:31:40 +01:00
PiggyPiglet a3d6426084
Merge pull request #473 from PlaceholderAPI/fix/469
Fix wrong expansion get in /papi info
2020-12-14 08:09:24 +08:00
Andre_601 30a194c75d
Update PlaceholderAPI.java 2020-12-14 01:08:40 +01:00
Glare 6431bcdeca
Merge pull request #460 from ignissak/444-add-expansionsLoadEvent 2020-12-13 18:07:24 -06:00
PiggyPiglet 0d1978cece
Merge pull request #454 from PlaceholderAPI/feature/add-getBoolean
Add missing getBoolean method
2020-12-14 08:04:49 +08:00
Andre_601 e7e9e81e85
Update VersionSpecific.java 2020-12-14 01:04:07 +01:00
Andre_601 ba22201311
Fix Javadoc build errors 2020-12-14 01:02:01 +01:00
PiggyPiglet f799835dd0
Merge pull request #429 from MrIvanPlays/patch/gradle-improvements
Attach sources and javadoc jar when deploying
2020-12-14 07:58:07 +08:00
PiggyPiglet 6f3dcf04fe
Merge pull request #407 from PlaceholderAPI/change/update-contributing
Update Contributing file
2020-12-14 07:56:36 +08:00
Andre_601 6b03c38e40
Update label commenter action 2020-12-13 17:21:52 +01:00
Andre_601 f756fbb43b
Update label-commenter-config.yml 2020-12-13 17:21:18 +01:00
Andre_601 f84702e3b2
Merge pull request #508 from PlaceholderAPI/feature/mention-github-discussions
Mention GitHub Discussions in Template chooser
2020-12-10 17:36:12 +01:00
Andre_601 9c750f50a2
Add Type:Question label 2020-12-09 18:10:19 +01:00
Andre_601 dcca454bad
Mention GitHub Discussions in Template chooser
Adds a link to the new [GitHub Discussions page](https://github.com/PlaceholderAPI/PlaceholderAPI/discussions) of this Repository.
2020-12-09 13:10:11 +01:00
BlitzGamer-88 ffef826c94
Merge pull request #503 from rbluer/patch-1
Adding Prison placeholders
2020-11-28 09:43:11 +02:00
RbR 15e0a293eb
Update Placeholders.md 2020-11-27 20:29:35 -05:00
RbR 11ed822845
Update Placeholders.md
Update the descriptions.
2020-11-27 20:25:37 -05:00
RbR 1e4af86172
Update Plugins-using-PlaceholderAPI.md
Added entry for Prison plugin.
2020-11-27 19:10:32 -05:00
RbR 5f9dffc3c7
Update Placeholders.md
Added the current placeholders for the Prison plugin.
2020-11-27 03:58:58 -05:00
Andre_601 93e83efb57
Rename label 2020-11-15 15:47:37 +01:00
Andre_601 0d9485ddec
Add action for inactive issues. 2020-11-15 15:45:49 +01:00
Andre_601 1248010566
Merge pull request #501 from Lauriichan/docs/wiki
Added RealisticWorldGenerator to Plugin Placeholders sections in wiki
2020-11-05 12:22:23 +01:00
Laura Endreß d68fe7067c
Update Plugins-using-PlaceholderAPI.md 2020-11-05 11:38:22 +01:00
Laura Endreß e16497618c
Update Placeholders.md 2020-11-05 11:36:38 +01:00
PiggyPiglet 4cfd419565
Merge pull request #500 from PlaceholderAPI/1.16.4
Compile under 1.16.4 + add new NMS support
2020-11-03 21:19:48 +08:00
darbyjack f52bdbc458
Compile under 1.16.4 + add new NMS support 2020-11-02 14:35:55 -06:00
Andre_601 433dd7020c
Merge pull request #499 from steve4744/docs/wiki
update tntrun_reloaded placeholders
2020-10-29 13:24:39 +01:00
BuildTools 4fef2dd82a update tntrun_reloaded placeholders 2020-10-29 12:21:19 +00:00
Andre_601 1e6fb502a6
Improve some text 2020-10-22 00:54:43 +02:00
Andre_601 b56ab1408e
Merge pull request #493 from N0tMyFaultOG/docs/wiki
Update PlotSquared placeholders
2020-10-15 19:39:01 +02:00
NotMyFault 5dae844181
Update PlotSquared placeholders 2020-10-15 19:27:46 +02:00
Andre_601 329b46c042
Merge pull request #491 from steve4744/docs/wiki
Update Placeholders.md for Parkour
2020-10-08 12:45:31 +02:00
steve4744 e2dd16cf1c
Update Placeholders.md 2020-10-08 10:56:35 +01:00
Andre_601 dc244849a1
Merge pull request #488 from PlaceholderAPI/change/improve-wiki-faq
Improve Wiki FAQ
2020-10-06 13:33:05 +02:00
Andre_601 736de5b633
Update FAQ.md 2020-10-02 11:58:38 +02:00
PiggyPiglet b31767ba4a
Merge pull request #487 from GiansCode/patch-1
Update README
2020-09-28 23:25:04 +08:00
Gianluca Falcomer ae06fcd807
Update README 2020-09-28 17:23:25 +02:00
Andre_601 7108ffbb31
Update Placeholders.md 2020-09-27 15:36:57 +02:00
Andre_601 7a6b6d7ce4
Merge pull request #486 from thienbao860/patch-1
Expansion name shorten request
2020-09-27 15:35:36 +02:00
thienbao860 549a30b502
Update Placeholders.md 2020-09-27 20:05:55 +07:00
darbyjack c64946173b
Implemented working version for 1.8.8 - 1.16.3 2020-09-25 19:08:56 -05:00
Andre_601 5bca9dc41f
Remove Gson 2020-09-24 22:31:26 +02:00
Andre_601 5c830d7102
Merge pull request #484 from PlaceholderAPI/feature/481-add-plugins
Add plugins to wiki
2020-09-24 17:15:21 +02:00
Andre_601 400c0d5b5d
Add plugins
- https://www.spigotmc.org/resources/83879/
- https://www.spigotmc.org/resources/67551/
- https://www.spigotmc.org/resources/68968/
- https://www.spigotmc.org/resources/21692/
2020-09-24 17:15:07 +02:00
Andre_601 c53d5b2abf
Add Boxing and TicketsGUI
- https://www.spigotmc.org/resources/83879/
- https://www.spigotmc.org/resources/68968/
2020-09-24 17:06:22 +02:00
Andre_601 a842095fff
Merge pull request #483 from PlaceholderAPI/fix/update-broken-links
Fix broken wiki links
2020-09-24 16:56:00 +02:00
Andre_601 c6e36fec2c
Fix broken wiki links 2020-09-24 16:55:22 +02:00
Andre_601 fa7eeb5852
Add AlonsoLevels 2020-09-24 16:51:24 +02:00
Andre_601 b6bfe3f3ef
Add AlonsoLevels 2020-09-24 16:49:10 +02:00
Andre_601 d6cfc8beae
Merge pull request #475 from stijnb1234/docs/wiki
Updated ThemePark
2020-09-13 21:58:26 +02:00
Stijn Bannink 83c35ced32
Moved to command 2020-09-13 21:57:11 +02:00
Andre_601 b9bdb3167a
Fix outdated Info 2020-09-13 21:48:02 +02:00
Stijn Bannink dfec6c4c8b
Updated ThemePark
v1.2 is live.
2020-09-13 19:19:04 +02:00
Andre_601 35838aa229
Fix wrong expansion get in /papi info 2020-09-13 00:30:27 +02:00
Andre_601 ee0df86f84
Merge pull request #472 from PlaceholderAPI/feature/470-add-BetonQuest
Add BetonQuest
2020-09-13 00:24:58 +02:00
Andre601 0650de95d6 Add BetonQuest 2020-09-13 00:22:51 +02:00
Andre_601 279f1d0c07
Merge pull request #471 from PlaceholderAPI/feature/468-add-SimpleCoins
Add SimpleCoins to wiki
2020-09-13 00:21:40 +02:00
Andre_601 5a8738e711
Remove useless empty line 2020-09-13 00:21:26 +02:00
Andre601 00b95461b6 Add SimpleCoins to the wiki 2020-09-13 00:11:52 +02:00
Andre_601 a74f78bd73
Update placeholders 2020-09-12 22:05:06 +02:00
Andre_601 9d35f4c3e6
Fix issue commenter 2020-09-12 22:02:25 +02:00
darbyjack 325cd2d284
Added support for 1.16.2 NMS changes 2020-09-06 16:39:15 -05:00
Andre_601 d4f0eb91ef
Merge pull request #466 from xknat/patch-1
Added SkinsRestorerPlaceholders
2020-09-06 22:37:15 +02:00
xknat 5ab228d1d8
Added SkinsRestorerPlaceholders 2020-09-06 21:30:12 +02:00
xknat 64e0f7e500
Added SkinsRestorerPlaceholders 2020-09-06 21:29:03 +02:00
xknat 7998d4d666
Add SkinsRestorerPlaceholders 2020-09-06 21:27:00 +02:00
xknat 2a91d34a65
Added SkinsRestorerPlaceholders 2020-09-06 21:25:06 +02:00
xknat ac717c7600
Added SkinsRestorerPlaceholsers 2020-09-06 21:18:26 +02:00
Andre_601 e13b91cb22
Merge pull request #465 from svenar-nl/docs/wiki
Docs/wiki
2020-09-05 00:53:33 +02:00
Sven Arends fdfca9da42
Update Plugins-using-PlaceholderAPI.md
Updated PowerRanks information
2020-09-05 00:49:21 +02:00
Sven Arends 1556e15a1a
Update Placeholders.md
Updated PowerRanks Placeholders
2020-09-05 00:48:42 +02:00
Andre_601 7691dd93ad
Add and improve responses 2020-09-02 12:08:50 +02:00
Jacob Bordas 2c13acfd30
Changes regarding review by Andre
Signed-off-by: Jacob Bordas <methalicity@gmail.com>
2020-09-01 01:31:52 +02:00
Andre_601 40f1fcbce2
Merge pull request #461 from Bimmr/docs/wiki
Updated McInfected Placeholders
2020-08-31 22:01:50 +02:00
Randy 456958d647
Updated McInfected Placeholders 2020-08-31 13:33:21 -04:00
Jacob Bordas 7c404db56b
Added event when all expansions are loaded for developers. 2020-08-31 13:32:11 +02:00
Andre_601 18cfd438b8
Update .github/CONTRIBUTING.md
Co-authored-by: PiggyPiglet <PiggyPiglet@users.noreply.github.com>
2020-08-31 03:00:24 +02:00
Andre_601 d5e27252cf
Fix wrong link 2020-08-31 02:52:16 +02:00
Andre_601 3fe0f0143c
Add note about wiki PRs 2020-08-31 02:50:30 +02:00
Andre_601 61a71b9e73
Add info about target branch. 2020-08-31 02:50:08 +02:00
Andre_601 e542dabd52
Merge pull request #459 from fredthedoggy/patch-1
Update BentoBox Placeholders
2020-08-31 02:46:10 +02:00
fredthedoggy 9cde086436
Update BentoBox Placeholders
Update the out of date BentoBox placeholders
2020-08-30 20:32:51 -04:00
Andre_601 fe02939466
Add missing getBoolean method 2020-08-28 15:16:03 +02:00
Andre_601 f1c2315055
Add missing line 2020-08-28 14:53:50 +02:00
Andre_601 9681c518fc
Merge pull request #453 from PlaceholderAPI/feature/451-add-streaming-drops
Add Streaming Drops (#451)
2020-08-28 14:51:02 +02:00
Andre_601 762bb409d3
Add Streaming Drop
https://www.spigotmc.org/resources/76996/
2020-08-28 14:50:48 +02:00
Andre_601 0394ba284b
Add Streaming Drops (#451) 2020-08-28 14:46:57 +02:00
Andre_601 3e9dcdb53c
Merge pull request #447 from steve4744/master
Update placeholders for tntrun_reloaded and parkour
2020-08-23 22:24:50 +02:00
BuildTools ddfaf4105d update placeholders for parkour 2020-08-23 17:44:23 +01:00
BuildTools 5b1df7c42a update placeholders for tntrun_reloaded 2020-08-23 17:27:55 +01:00
Andre_601 7555bb0f97
Update .github/CONTRIBUTING.md
Co-authored-by: PiggyPiglet <PiggyPiglet@users.noreply.github.com>
2020-08-19 16:27:48 +02:00
Andre601 ab96120911 More comments... a lot more! 2020-08-18 23:15:23 +02:00
Andre_601 7371a576d6
Update Javadoc documentation 2020-08-18 18:37:44 +02:00
Andre_601 5d5ceb5902
Merge pull request #439 from Lorenzo0111/patch-1
Added RocketPlaceholsers
2020-08-13 14:45:43 +02:00
Andre_601 125d02fecd
Add missing link 2020-08-13 14:45:02 +02:00
Andre_601 8c98a214f8
Add RocketPlaceholders
https://www.spigotmc.org/resources/82678/
2020-08-13 14:44:11 +02:00
Lorenzo 2a3e8dcec1
Added RocketPlaceholsers
Added RocketPlaceholsers which provides their own placeholders.  The placeholders are customizable from the config.
2020-08-13 10:10:17 +02:00
Andre_601 a996d9039e
Merge pull request #437 from PlaceholderAPI/feature/label-commenter
Adding Label commenter
2020-08-12 23:17:39 +02:00
Andre_601 cfba92bf14
Add missing info about automated response. 2020-08-12 15:26:40 +02:00
Andre_601 41f408226e
Update label-commenter-config.yml 2020-08-12 15:20:40 +02:00
Andre_601 58cfa92136
Add label-commenter-config.yml 2020-08-12 15:11:21 +02:00
Andre_601 f3309b76d1
Adding Label commenter 2020-08-12 14:58:04 +02:00
Andre_601 04bfa1e721
Update formatter placeholders 2020-08-12 13:48:31 +02:00
Andre_601 dc894c6212
Merge pull request #434 from PlaceholderAPI/master
Update docs/wiki from master
2020-08-10 22:30:00 +02:00
Andre_601 7c7025fdbb
Merge pull request #433 from RobinDeBaets/master
Fix Statistic download information
2020-08-10 22:27:42 +02:00
RobinDeBaets 97a4eca0a7
Add back Statistic link 2020-08-10 22:24:06 +02:00
RobinDeBaets 5e4110b1b3
Remove outdated Statistic information 2020-08-10 22:22:53 +02:00
Andre_601 d1e3047445
Update CONTRIBUTING.md 2020-08-10 21:29:42 +02:00
Andre_601 c72515912d
Add RocketJoin
https://www.spigotmc.org/resources/82520/
2020-08-10 21:21:48 +02:00
MrIvanPlays eb5a93dce2
Attach sources and javadoc jar when deploying 2020-08-09 10:22:21 +03:00
Andre_601 7cb3b3b7ec
Add missing expansions 2020-08-08 18:35:36 +02:00
Ivan Pekov c648d6a541
Fix trailing/leading space after placeholder once and for all (#427) 2020-08-06 14:45:27 -04:00
extendedclip 2d72e274e3 account for empty strings 2020-08-06 14:08:48 -04:00
extendedclip b73d00e169 bstats might have an issue? 2020-08-06 14:05:33 -04:00
Ivan Pekov 5065623ab0
Attempt at fixing 413 (#422)
* Attempt at fixing 413

This is my (miserable) attempt at fixing #413
These changes basically fix some potential threading issues and (probably) #413
Local tests went fine for me, but more tests are required.

* Remove delay, fixed -> cached thread pool
2020-08-06 13:54:35 -04:00
Federico López 8698449e5d
Refactorization of the TimeUtil utility class (#423)
* Refactored `TimeUtil` utility class.

* Minimized `TimeUtil#getRemaining`.
* Fixed a bug regarding how days and hours were calculated in `TimeUtil#getTime`.
* Ditched the use of `int`s and use `long`s instead.

* Implemented `int`-taking methods because my dumb ass didn't think it would break.
2020-08-06 13:43:14 -04:00
extendedclip 722e987b93 Dont trim 2020-08-06 13:27:58 -04:00
extendedclip a00cbf4be3 trim whitespaces 2020-08-06 11:44:34 -04:00
Andre_601 f235c60bef
Update World placeholders 2020-08-06 13:48:58 +02:00
extendedclip a1d69cd25f Remove hashcode method 2020-08-05 11:53:06 -04:00
extendedclip f7504b99ca Add registerExpansion and unregisterExpansion back 2020-08-05 11:45:58 -04:00
extendedclip 02669e2435 Set builds to 2.10.10-dev 2020-08-04 12:47:05 -04:00
extendedclip 3d2fca277f 2.10.9 RELEASE 2020-08-04 12:29:50 -04:00
Andre_601 3e6d10e203
Fix formatting 2020-08-04 16:10:51 +02:00
Andre_601 f828857ce3
Add BuyCraft
https://www.spigotmc.org/resources/82261/
2020-08-04 16:09:31 +02:00
extendedclip eeb9c8d5db Restore pre 2.10.7 API functionality for the most part. Only things actually being removed in 2.11.0 are deprecated. No breaking API changes until 3.0 2020-08-04 10:04:34 -04:00
extendedclip 6d38f411ba Include &n 2020-08-03 16:21:56 -04:00
extendedclip 542ffd6b7b Rename dependency variable 2020-08-03 15:38:53 -04:00
extendedclip 2a559fd240 Fix quotations 2020-08-03 15:23:48 -04:00
extendedclip 51844cd291 Always provide a copy of the placeholder map 2020-08-03 13:54:28 -04:00
Andre_601 ec9d6295fb
on their? Sounds better imo 2020-08-03 16:56:58 +02:00
Andre_601 19a80c2d26
Do some changes 2020-08-03 16:51:46 +02:00
extendedclip 12a358fbd0 Check if canRegister in LocalExpansionManager.register rather than in Expansion#register 2020-08-03 10:24:56 -04:00
extendedclip 0982505574 Maybe this will include the jetbrains annotations in the pom? 2020-08-03 10:00:59 -04:00
Andre_601 e3d71843ac
Fix typos and more info 2020-08-03 13:41:35 +02:00
Funnycube 364635cd06
Merge pull request #417 from PlaceholderAPI/change/update-templates
Change/update templates
2020-08-03 21:27:33 +10:00
Andre_601 d3844711bc
Update Feature Request template 2020-08-03 13:17:17 +02:00
Andre_601 81038dab80
Update PR template 2020-08-03 13:14:52 +02:00
Andre_601 514e25454d
Update Bug report template 2020-08-03 13:11:41 +02:00
Funnycube 203f02029c
Updated flex 2020-08-03 13:45:50 +10:00
Andre_601 eb20a80b37
Update API version badge 2020-08-01 20:51:48 +02:00
Andre_601 c2dc51c728
fix typo 2020-08-01 15:09:22 +02:00
extendedclip c38ecfc16c Bump to 2.10.9 dev builds 2020-08-01 00:06:41 -04:00
extendedclip 105b116529 2.10.8 2020-07-31 23:15:08 -04:00
extendedclip 6a78ff88d3 Include daddy codestyle in project 2020-07-31 23:04:06 -04:00
extendedclip dcc8dad4ea Format to Daddy code style 2020-07-31 22:52:07 -04:00
extendedclip cee6984818 Don't add license to config or plugin.yml 2020-07-31 22:37:00 -04:00
extendedclip 8a751cddd5 Use @name@ variable 2020-07-31 22:08:48 -04:00
extendedclip 91d370d883 Set artifact id to lower case 2020-07-31 22:07:58 -04:00
extendedclip 18854647bf Show help in alphabetical order 2020-07-31 21:35:38 -04:00
extendedclip 97fd3a3b5d Make the message differentiate between singular and plural updates avail 2020-07-31 21:30:00 -04:00
extendedclip 0f8ce0c6c3 Set Manager to lower case 2020-07-31 21:18:18 -04:00
extendedclip 9d43b743a2 Remove space before placeholders start 2020-07-31 21:17:41 -04:00
Andre_601 e43b7bf205
Improve dump command (#412) 2020-07-31 19:59:55 -04:00
extendedclip 9412fed9ad Merge remote-tracking branch 'origin/master' 2020-07-31 19:21:38 -04:00
extendedclip c7de89bebe Add back deprecated getPlaceholders method 2020-07-31 19:21:11 -04:00
Andre_601 cc02c126b5
Merge pull request #410 from PlaceholderAPI/master
Update wiki branch
2020-07-31 19:33:46 +02:00
Andre_601 aed0d288f7
Add CODEOWNERS file (#408) 2020-07-31 12:40:18 -04:00
Andre_601 b4a914314a
Update _Footer 2020-07-31 18:07:53 +02:00
Andre_601 f6ba24e46f
& instead of ? 2020-07-31 18:07:00 +02:00
Andre_601 745f7926a6
Fix label 2020-07-31 18:06:28 +02:00
Andre_601 62c93465f2
Update PlaceholderExpansion.md 2020-07-31 18:03:51 +02:00
extendedclip 0e733b6933 Force all identifiers to lower case 2020-07-31 12:01:27 -04:00
extendedclip 2e28647497 Force all identifiers to lower case 2020-07-31 11:40:44 -04:00
extendedclip 9b2b6992c7 Make author name white 2020-07-31 11:01:42 -04:00
extendedclip 81aa425616 Fix version and color 2020-07-31 10:52:43 -04:00
extendedclip e932fabe64 Don't set the name of the jar 2020-07-31 10:46:27 -04:00
extendedclip 9901e8bc24 Merge remote-tracking branch 'origin/master' 2020-07-31 10:43:43 -04:00
extendedclip 8c15cdf7cb remove JSONMessage repo, Update archive file name and license stuff 2020-07-31 10:42:24 -04:00
extendedclip fc453a9d7f Add license header 2020-07-31 10:40:37 -04:00
extendedclip a232294b11 remove register deprecation as it won't be final. Set removal for deprecated methods to 2.11.0 2020-07-31 10:40:03 -04:00
extendedclip 8c829417a7 Added missing commands to help commands, fixed some color / formatting 2020-07-31 10:37:47 -04:00
extendedclip 94ce9d6a6e Add license header 2020-07-31 10:37:01 -04:00
extendedclip a843369ebd Include JSONMessage with plugin instead of using maven repo to fetch 2020-07-31 10:36:31 -04:00
extendedclip 8e3c942282 Remove deprecation for useful methods, set removal of deprecated methods to 2.11.0, registerPlaceholderHook will fail gracefully 2020-07-31 10:35:47 -04:00
extendedclip d2945539b3 Deprecate PlaceholderHook but not onRequest 2020-07-31 10:34:11 -04:00
extendedclip 0281e5e346 Hardcode plugin name in plugin.yml 2020-07-31 10:33:04 -04:00
Andre_601 c76baeae1c
Update CONTRIBUTING.md 2020-07-31 16:02:20 +02:00
Andre_601 d12c746630
Improve content 2020-07-31 16:00:35 +02:00
Andre_601 3f9205d2df
Merge pull request #403 from PlaceholderAPI/change/remove-wiki-template
Remove request change (wiki) template
2020-07-31 15:29:00 +02:00
Andre_601 fbdd789dbe
Create CODE_OF_CONDUCT.md 2020-07-31 15:26:33 +02:00
Andre_601 b521fe4a1f
Update Contributing file 2020-07-31 15:24:07 +02:00
Andre_601 b24b127ad5
Merge pull request #406 from PlaceholderAPI/master
Trigger on docs/wiki branch
2020-07-31 14:51:15 +02:00
Andre_601 8a12d324e3
Trigger on docs/wiki branch 2020-07-31 14:50:30 +02:00
Andre_601 51975cbe40
Update Marcely's Bedwars 2020-07-31 14:33:00 +02:00
extendedclip f6e6394a74 dump on someone else 2020-07-30 18:18:37 -04:00
Andre_601 466509c578
Update config.yml 2020-07-31 00:18:19 +02:00
Andre_601 ee86fa7460
Rename to Feature Request 2020-07-31 00:17:16 +02:00
extendedclip 7f767cb222 dump on someone else 2020-07-30 18:14:09 -04:00
extendedclip c3499416f3 Add dump command to help 2020-07-30 18:07:46 -04:00
Andre_601 3bcffa0112
Move comments into <!-- --> block 2020-07-31 00:07:33 +02:00
Andre_601 529399e486
Remove request change (wiki) template 2020-07-31 00:00:16 +02:00
Andre_601 0ce8dd5096
Add comment about PAT 2020-07-30 23:56:24 +02:00
Andre_601 8b1227e6b7
Let's see if this won't trigger a build...
Update Wiki
2020-07-30 23:52:13 +02:00
Andre_601 a887aad9ac
Update Plugins-using-PlaceholderAPI.md 2020-07-30 21:52:06 +02:00
Andre_601 f5fc7f26b7
Add custom Items 2020-07-30 21:47:57 +02:00
Andre_601 620bc01620
Add RVP placeholders 2020-07-30 20:05:27 +02:00
extendedclip 6362c9618d Added deprecated registerPlaceholderHook and unregisterPlaceholderHook methods which will throw UnsupportedOperationException so end users can nag authors to update 2020-07-30 09:53:12 -04:00
extendedclip d053881549 Reset version to 2.10.8-dev 2020-07-30 09:35:11 -04:00
extendedclip 3605ba4262 Update deprecated methods to specify actual version of removal 2020-07-30 09:31:07 -04:00
extendedclip 499a46898e Update deprecated methods to specify actual version of removal 2020-07-30 09:30:11 -04:00
Andre_601 49595c641c
Update Hook-into-PlaceholderAPI.md 2020-07-30 13:45:03 +02:00
Sxtanna 98fbceeb1d added back packaging node 2020-07-29 18:20:39 -04:00
Sxtanna 592f093566 updated maven publication to remove transitive dependencies 2020-07-29 17:43:05 -04:00
Sxtanna 63134f4d74 changed project name to lowercase 2020-07-29 17:43:03 -04:00
Sxtanna 8b4a2517c0 updated char replacer to colorize returned replacements as well. 2020-07-29 17:19:30 -04:00
Sxtanna a78b5fe712 updated to use Player#spigot instead of CommandSender#spigot (I miss Kotlin) 2020-07-29 17:19:29 -04:00
Sxtanna 68402d244b bumped to 2.10.7 2020-07-28 17:36:39 -04:00
Sxtanna 81225dafbc updated parse command completer to suggest available placeholders 2020-07-28 16:09:30 -04:00
Sxtanna 74bd22eb0c updated char replacer to have spaces in placeholder parameters 2020-07-28 15:18:15 -04:00
Sxtanna a6ab3a2a03 updated to publish dev builds to the dev repo 2020-07-28 14:47:37 -04:00
Sxtanna 9ef5cedfd6 updated to use credentials from the environment 2020-07-28 14:06:51 -04:00
Sxtanna 8f9b999e5a updated to publish to clip nexus repo 2020-07-28 13:47:28 -04:00
Sxtanna f9156209e7 Merge remote-tracking branch 'origin/master' 2020-07-28 12:58:24 -04:00
Sxtanna 77d0654a29 updated build to use maven publish plugin 2020-07-28 12:58:06 -04:00
Sxtanna 300eb64d89 removed benchmarks for shitty replacer 2020-07-28 12:57:08 -04:00
Andre_601 ff01f83a09
Let's hope the wiki actions works this time
Update navigation
2020-07-28 18:52:11 +02:00
Andre_601 c28eab1697
Update Home.md navigation 2020-07-28 18:51:48 +02:00
Andre_601 7a322e0bb8
Update sidebar navigation 2020-07-28 18:50:17 +02:00
Andre_601 731e177859
Use short actions e-mail 2020-07-28 18:03:40 +02:00
Andre_601 1beb2ef3da
Use Personal/Private Access Token 2020-07-28 17:58:41 +02:00
Andre_601 5047b0cdee
Add Wiki update action (#373)
* First step to make automated wiki action

* Add wiki folder and files

* Only trigger on master branch

* Add dump command

* Update Plugins-using-PlaceholderAPI.md

* Create README.md

* Update README.md

* Ignore the readme file

* Update files from wiki

* Update wiki pages
2020-07-28 11:07:41 -04:00
Andre_601 5cc65c880a
Move links down in the templates (#379)
* Move links down in the templates

* Add wiki option to PR template
2020-07-28 11:07:08 -04:00
Sxtanna b73a6916cb updated classes with contract annotations 2020-07-27 11:40:58 -04:00
Sxtanna 134086f6a9 updated fileutil to load *vomit* all classes, closes #381 2020-07-27 11:39:11 -04:00
PiggyPiglet 1993b2cd82 replaced single quote from merge with double quote 2020-07-27 15:23:32 +08:00
PiggyPiglet 9291184534 Merge remote-tracking branch 'origin/master' 2020-07-27 15:23:11 +08:00
PiggyPiglet 6d502db694 Licensed all files
Added licensing plugin
2020-07-27 15:21:35 +08:00
Sxtanna f61b6acfa8 updated placeholderexpansion to define its own unregister method 2020-07-26 23:01:12 -04:00
Sxtanna 8360511c50 rewrote discovery and registration code to be composable and higher level 2020-07-26 21:02:55 -04:00
Sxtanna ee33de5ec8 removed final from deprecated methods, restored fallback for getRequiredPlugin 2020-07-26 21:01:12 -04:00
Sxtanna a160f3abc9 updated to further phase out PlaceholderHook, added contracts to expansion methods 2020-07-26 18:46:00 -04:00
Sxtanna b63f10f749 lets pretend no one saw this. 2020-07-26 18:36:50 -04:00
Sxtanna 86002f50e6 updated to phase out PlaceholderHook 2020-07-26 18:03:31 -04:00
Sxtanna c3e0c1fb64 updated gson 2.8.5 -> 2.8.6 2020-07-26 17:32:28 -04:00
Sxtanna b464590491 added dump command, closes #366 2020-07-26 16:26:42 -04:00
Sxtanna 65f04ba70e updated cloud expansion list to be sorted via a configuration option of values [name, author, latest]. closes #363 2020-07-26 13:39:33 -04:00
Andre_601 a7a4b46821
Merge pull request #328 from Andre601/patch-2
Added "Installed expansions" section
2020-07-26 13:12:06 +02:00
Sxtanna 07cd344123 updated local expansion to not catch potential linkage errors, and report them. closes #377 2020-07-25 23:57:19 -04:00
Sxtanna 30ead2ae4b fixed spacing 2020-07-25 23:54:09 -04:00
Sxtanna 9339192f88 updated ecloud list command to use new table utility, added message for when no expansions can be listed 2020-07-25 22:38:41 -04:00
Sxtanna 6eb1ecc212 Implemented general purpose table utility 2020-07-25 22:35:56 -04:00
Sxtanna 973484066a updated ecloud list command to not paginate by default in console, closes #375 2020-07-25 14:57:10 -04:00
Sxtanna f177da8ef7 updated parse tab completer to consider the "cmdparse" alias 2020-07-25 13:08:26 -04:00
Sxtanna d1b50c3db4 updated parse tab completer to call method inversely 2020-07-25 13:07:59 -04:00
Sxtanna fb7a3ec99d added tab completion to the update command 2020-07-25 12:55:44 -04:00
Sxtanna 6caed4c23c updated plugin.yml to include permission for update command 2020-07-25 12:55:44 -04:00
Sxtanna f7c2e72c1e added ecloud update command 2020-07-25 12:55:44 -04:00
Sxtanna 85b9fc36da updated local manager to allow for reregistering expansions 2020-07-25 12:55:44 -04:00
Sxtanna 5861f9fe6a updated register command to attempt registration on the main thread. (event bullshit I think) 2020-07-25 12:02:34 -04:00
Sxtanna b6ec478dd6 updated ecloud list command to print to console in a table format. 2020-07-25 10:24:19 -04:00
Sxtanna 89061e6437 fixed ordering of methods 2020-07-24 19:45:28 -04:00
Sxtanna 50cee40531 updated LocalExpansionManager to accept a command sender to notify of load completion details 2020-07-24 19:02:17 -04:00
Sxtanna 00ced0495d I don't know how this happened, please don't flame me. ty. 2020-07-24 18:51:19 -04:00
Sxtanna 4e37f9f52a Merge remote-tracking branch 'origin/master'
# Conflicts:
#	src/main/java/me/clip/placeholderapi/expansion/manager/CloudExpansionManager.java
2020-07-24 18:51:07 -04:00
Sxtanna e57a0600f1
Managers Update (#368)
* added google codestyle plugin

* updated managers to make more sense, removed old

* updated cloud expansion manager to cache with index name
2020-07-24 18:49:18 -04:00
Sxtanna f4466059ac Merge branch 'master' into managers 2020-07-24 15:54:00 -04:00
Sxtanna dd183b4031 Merge remote-tracking branch 'origin/master' 2020-07-24 14:47:46 -04:00
Sxtanna 5ef360e3fe updated build.gradle formatting, and added missing values 2020-07-24 14:47:30 -04:00
Andre_601 ffe7680795 Fix missing line break in expansion list command. 2020-07-24 14:40:58 -04:00
Sxtanna cbbb2f27e4 Merge branch 'master' into managers
# Conflicts:
#	build.gradle
#	src/main/java/me/clip/placeholderapi/commands/impl/cloud/CommandECloudExpansionList.java
#	src/main/java/me/clip/placeholderapi/expansion/cloud/ExpansionCloudManager.java
2020-07-24 14:34:54 -04:00
Sxtanna f3ba9d588e updated managers to make more sense, removed old 2020-07-24 14:30:57 -04:00
extendedclip 623fd68ccc eCloud list outputs expansion information on a single line instead of multiple. Fixes #367 2020-07-24 12:40:07 -04:00
Glare 5fec3b53d0
Merge pull request #365 from PlaceholderAPI/fix-gradle-resolve 2020-07-24 10:49:32 -05:00
darbyjack ffe2bb28ba
Fix gradle resolve 2020-07-24 10:48:37 -05:00
Sxtanna 651de80a01 updated expansion list command to send messages using json 2020-07-24 11:04:12 -04:00
Sxtanna 4c586d1803 updated cloud manager to not be weird 2020-07-24 11:04:12 -04:00
Sxtanna 60a74258ec added google codestyle plugin 2020-07-24 08:26:20 -04:00
PiggyPiglet 7d091f3cf4
Merge pull request #361 from PlaceholderAPI/casing
fixed ecloud casing
2020-07-24 17:54:42 +08:00
PiggyPiglet 34a0bff760 removed apostrophe, apparently that particular rule doesn't apply to "its". 2020-07-24 17:37:33 +08:00
PiggyPiglet 51abc00e51 added a missing apostrophe 2020-07-24 17:35:21 +08:00
PiggyPiglet 3429d69f9d Fixed more casings 2020-07-24 17:32:39 +08:00
PiggyPiglet 79b8dd73a5 Fixed missed casings 2020-07-24 17:25:34 +08:00
Sxtanna fccf0d5bb8 fixed ecloud casing 2020-07-24 05:21:43 -04:00
PiggyPiglet e0e02f38b6 convert gstring to string 2020-07-24 16:32:18 +08:00
PiggyPiglet d1bc2f598f fixed build number 2020-07-24 16:27:11 +08:00
PiggyPiglet 9d38d9b1a0
Merge pull request #359 from PlaceholderAPI/gradle
Gradle
2020-07-24 15:51:18 +08:00
PiggyPiglet 8b3f37b61e
Merge branch 'master' into gradle 2020-07-24 15:50:17 +08:00
Sxtanna 6fade3fb93 removed obsolete EZPlaceholderHook 2020-07-24 01:39:17 -04:00
Sxtanna b7d1c6969e
Commands rewrite (#357)
* began rewriting command system

* began rewriting command system

* updated formatting

* added new info command

* added new reload command

* updated new parse command to support all three parsing types

* added new commands to command router

* deleted old unused commands

* removed parserel

* added new expansion register and unregister commands

* deleted unused commands

* fixed annotation order

* added labels helper to command

* updated alias method to return an immutable view

* updated params param with unmodifiable annotation

* updated router to build an immutable map of the commands

* began rewriting command system

* updated formatting

* added new info command

* added new reload command

* updated new parse command to support all three parsing types

* added new commands to command router

* deleted old unused commands

* removed parserel

* added new expansion register and unregister commands

* deleted unused commands

* fixed annotation order

* added labels helper to command

* updated alias method to return an immutable view

* updated params param with unmodifiable annotation

* updated router to build an immutable map of the commands

* updated plugin class to use new command router

* updated switch to break on parse match

* updated register completions to suggest file names

* updated router to allow entering labels in any case

* updated parse command to send message to players as components

* added command dispatching parsing

* moved new commands into local package

* added helper functions for filtering and suggesting

* updated imports, updated tab completion to use helper functions

* added start of ecloud commands

* replace ecloud enable and disable commands with single toggle command evaluator

* deleted unused commands

* updated commands to use helper functions for suggesting

* updated downloading to use completablefuture, updated all methods to use streams exclusively

* updated to use the config instead of a null check

* deleted old commands system

* finished new command system

* updated to use new method from cloud manager

* fixed annotation ordering and added missing annotations

* updated ecloud subcommands to have a more specific permission

* updated plugin.yml with the new permissions, (and also fixed its formatting)

* fixed annotations intellij missed

* this should probably be there...
2020-07-24 01:29:11 -04:00
Sxtanna 21ca434e72 added unit test for hex code escaping 2020-07-23 12:02:04 -04:00
Sxtanna d63d7dc5f8 updated char replacer to support hex colors, and escaping &x 2020-07-22 23:59:39 -04:00
Sxtanna f47eef7442 updated plugin class to be less painful to look at, 2020-07-22 20:42:53 -04:00
Sxtanna 9631b087b3 updated server load listener to be final, and to automatically unregister itself when done 2020-07-22 20:41:27 -04:00
Sxtanna d7b947ddad finalized config, added nullability annotations 2020-07-22 20:40:47 -04:00
Sxtanna 656f9ad03c updated expansion manager to actually... manage expansions 2020-07-22 20:40:15 -04:00
Sxtanna 0a4150d63e updated fileutil to ignore NCDFEs, and to print exceptions 2020-07-21 16:04:24 -04:00
Sxtanna 377d091ae2 added back deprecated online player method 2020-07-21 12:25:38 -04:00
Sxtanna bdf8a1bcc1 reformatted event classes, added nullability annotations, made classes final. 2020-07-21 11:56:57 -04:00
Sxtanna ee78fc1775 updated char replacer to better handle malformed input 2020-07-21 01:48:59 -04:00
Sxtanna 9ddb21220f updated shadow, added test dependencies for jmh and junit 2020-07-20 20:13:32 -04:00
Sxtanna 47e336c1fe Merge branch 'master' into gradle
# Conflicts:
#	pom.xml
2020-07-20 20:07:38 -04:00
Sxtanna a2a736d909 undeprecated bracket placeholder methods, 2020-07-20 19:50:36 -04:00
Sxtanna 9217147827
Merge pull request #355 from Andre601/patch-3
Add missing @deprecated notes to methods
2020-07-20 19:26:56 -04:00
Andre_601 53736888a5
grammar 2020-07-21 01:26:21 +02:00
Andre601 75004f08d0 Add deprecation notice to all methods
Was it so hard to do a Ctrl+C, Ctrl+V?
2020-07-21 01:20:26 +02:00
Andre_601 51f61f61af
Add missing deprecation notices. 2020-07-21 01:06:37 +02:00
Sxtanna e7ce84e7fc cleaned up fileutil and expansion manager 2020-07-20 18:55:37 -04:00
Sxtanna 42992de312 updated with null contracts, immutability, and early returns. 2020-07-20 18:22:08 -04:00
Sxtanna 45b3ebfbc2 updated to use new char replacer, deprecated all older functions, defined null contracts, and immutability. 2020-07-20 18:16:46 -04:00
Sxtanna 3b3892e7d6 updated placeholder hook to define immutability and null contracts, deprecated online player function 2020-07-20 18:14:13 -04:00
Sxtanna 9060ea6bd3 updated to use new closure 2020-07-20 17:38:18 -04:00
extendedclip 49012dc6b2 here 2020-07-20 17:23:27 -04:00
Sxtanna 9d73893cc8
replacer api, unit tests, and benchmarks (#354)
* added abstracted replacer api, and both char and regex based implementations

* added test dependencies for jmh and junit

* added unit tests and benchmarks for the replacer implementations

* updated replacers to accept specific closure types, added test to verify malformed placeholder handling

* updated jmh to 1.23, updated junit to 5.6.2
2020-07-20 16:59:25 -04:00
extendedclip 4ce0b03852 Revert "Performance Improvements (#340)"
This reverts commit 54d5757d
2020-07-20 16:57:16 -04:00
Glare 8972f7cff4
Merge pull request #352 from Sxtanna/master
POM fixes.
2020-07-19 15:22:24 -05:00
Sxtanna d2223f83b8 removed server dependency, added provided dependency for log4j-core 2020-07-19 09:16:09 -04:00
Sxtanna b4d6b047af moved compiler source and target to properties 2020-07-19 09:12:58 -04:00
Crypto Morin 54d5757d0a
Performance Improvements (#340)
* Performance Improvements

* More Optimizations

* Even More Optimizations & Cleanups

* Almost a recode I guess
2020-07-16 12:32:22 -04:00
PiggyPiglet ca8fb3117f fixed resource processing variables 2020-07-15 01:00:01 +08:00
PiggyPiglet bc0535e2f4 Converted to gradle 2020-07-15 00:56:49 +08:00
extendedclip f9f59f1f96 Merge the multiple static blocks 2020-07-14 10:24:01 -04:00
extendedclip f205146c75 Rename ecloud commands to be prefixed with Ecloud to avoid confusion 2020-07-14 10:21:29 -04:00
darbyjack 0634a9cd9b
Switch back to the official JSONMessages 2020-07-14 08:18:06 -05:00
Frcsty 3e396a97b0
Changed command system (#304)
* Save Cacheable expansions data on shutdown

* Prepare for 1.16

* 1.16.1 is out apparently

* Further fixes, still not done

* Inline JSONMessages & fix for 1.16

* Done :O

* Done for real now, (hopefully)

* Changed to static instead of DI for plugin instance

* Cleanup

* Modified tab completions. Removed extra command.

* Apparently this is needed

* Started cleaning stuff up

basically just pushing so I can continue on laptop

* did more cleaning, probs like half way done

* more cleaning. reverted back to a min arg system somewhat similar to what frosty had, but less boilerplate.

* Started debugging and fixing runtime/compile errors

* Fixed bugs, still needs thorough testing

* Re-enable metrics

* relocated stuff again

* - Remove json message relocation
- uncomment other relocations
- reformat pom
- remove useless scope declaration
- Fix metrics constructor
- Switch commands to use inline json message

Co-authored-by: iGabyTM <contactgabytm@gmail.com>
Co-authored-by: darbyjack <admin@glaremasters.me>
Co-authored-by: PiggyPiglet <noreply@piggypiglet.me>
2020-07-13 15:27:59 -04:00
Andre_601 9316636939
Added "Installed expansions" section 2020-06-13 18:16:42 +02:00
extendedclip 82fa8d7393 Added 1.15 2020-05-02 23:16:46 -04:00
extendedclip 83abb8b728 Bump to 2.10.7 dev 2020-05-02 23:16:03 -04:00
extendedclip feed418ccf 2.10.6 release 2020-05-02 22:52:18 -04:00
Glare a2868cbc4f
Merge pull request #294 from PlaceholderAPI/fixes/first-time-parse
Fixes the super old issue of not being able to parse on first join
2020-04-26 12:19:09 -05:00
darbyjack 43d134cbe3
Fixes the super old issue of not being able to parse on first join 2020-04-25 21:57:40 -05:00
Ryan e023c4e789
Fixed Discord URL 2020-04-09 11:45:35 -04:00
aBooDyy 784d7dd273
Fixes ecloud placeholders command (#201)
* fix parsing placeholders on ecloud placeholders command

* try catch on registering expansions

Co-authored-by: aBo0oDyy <35378106+aBo0oDyy@users.noreply.github.com>
2020-04-09 11:43:21 -04:00
Andre_601 d26561eaeb
Add issue template config for custom template selection (#272)
* Fix typos

* Update change_request_placeholderapi.md

* Slighty better grammar

* Create config.yml

* Add about part

* Make wiki point to PAPI wiki
2020-04-09 11:38:14 -04:00
WCKDAWE 0666ac7b01
Minor spelling mistakes (#284)
Not a grammar nazi, just noticed them and though to commit dem changes.
2020-04-09 11:37:48 -04:00
Andre_601 2caf5f0232
Add missing setPlaceholder methods (#234)
* Add missing setPlaceholder methods
Also includes setBracketPlaceholders and setRelationPlaceholders

* Update PlaceholderAPI.java
2020-04-09 11:37:06 -04:00
Glare d706469ed8
Ahem. Let's flex. 2020-04-03 10:44:12 -05:00
darbyjack 5d4decafbe
Bump to 2.10.6 dev 2020-03-25 23:28:48 -05:00
darbyjack bb639328a3
Push to 2.10.5 for release pt2 2020-03-25 23:27:56 -05:00
darbyjack ca0791f3af
Push to 2.10.5 for release 2020-03-25 23:05:12 -05:00
darbyjack 449c927c6c
Add user-friendly message when host can't connect to ecloud 2020-03-25 23:04:00 -05:00
darbyjack e95f1b4850
Removed extra semi 2020-03-25 22:54:26 -05:00
Glare 06513c89bc
Merge pull request #268 from PiggyPiglet/master
covered up string's size insecurities with a fat bufferedreader
2020-03-25 21:42:43 -06:00
PiggyPiglet 38d9185232 made it compile 2020-03-26 11:25:02 +08:00
PiggyPiglet 35738f59d9 covered up string's size insecurities with a fat bufferedreader 2020-03-26 11:15:16 +08:00
darbyjack 66758b1992
Compile under 1.15.2 2020-02-03 12:18:57 -06:00
extendedclip c1cff8ca74 javadoc 2020-01-06 14:29:07 -05:00
extendedclip 2dbf69a74e Allows the setPlaceholders method to specify if color codes should be translated in the output string 2020-01-06 14:27:39 -05:00
darbyjack 6c964baba7
Added support for 1.15.1 2019-12-21 13:56:07 -06:00
darbyjack 4b77eb5d00
Added support for 1.15 2019-12-10 17:49:49 -06:00
darbyjack 6e68929a5c
Updated gitignore to ignore IDEA files. 2019-12-10 17:16:28 -06:00
darbyjack fc263d9ce7
Updated bStats repo version. 2019-12-10 17:15:39 -06:00
Max Berkelmans ab9716489b
Merge pull request #131 from Draycia/master
Formatting, spacing, final modifiers, and a few code fixes
2019-10-16 22:29:38 +02:00
Max Berkelmans 5c6202a8ee
Merge branch 'master' into master 2019-10-16 22:28:19 +02:00
extendedclip 38c1eca590 Bump version to 2.10.5 development 2019-09-19 14:38:33 -04:00
extendedclip a1a1b1afd7 Bump version to 2.10.4 for release 2019-09-19 14:26:35 -04:00
extendedclip 51599c4044 Allow cancelling expansion registration 2019-09-19 14:22:08 -04:00
extendedclip 9871efbadb Allow cancelling expansion registration 2019-09-19 14:16:35 -04:00
Evan Lindsay 6b9f22c7ec Fix case check in PlaceholderExpansion.isRegistered (#161) 2019-08-04 18:03:25 -04:00
aBooDyy 7c54e58ab7
Merge pull request #151 from Andre601/patch-1
Fixing broken link
2019-07-23 19:49:13 +03:00
Andre_601 024d9b281a
Fixing broken link 2019-07-23 17:19:20 +02:00
Leomixer17 6c5cd0ed1f Update plugin.yml (#142)
1.13 set as api version won’t cause issues. I reverted adding 1.14 but we can merge this as it won’t have any conflicts. Thanks for the contribution.
2019-07-12 18:33:35 -04:00
Josh (Vicarious) 719172c185
Merge branch 'master' into master 2019-06-30 21:40:51 -07:00
darbyjack 763bb52d06
Changed some logic to suggest the right command. 2019-06-28 12:14:30 -05:00
darbyjack d0d0c99505
Added message saying to reload papi to enable downloaded expansion. 2019-06-28 12:14:07 -05:00
darbyjack 16726215bb
Updated to dev, fixed spigot version. 2019-06-28 12:13:34 -05:00
Ryan 454b1f19f4
Update README.md
Updated stats
2019-06-25 15:01:08 -04:00
darbyjack 6286451991
Push to 1.14.3-SNAPSHOT. 2019-06-25 05:39:52 -05:00
extendedclip b9881eb70b Fix page indexes when on pages greater than 1 2019-06-21 12:49:45 -04:00
extendedclip 93f586a216 Update to 2.10.3 2019-06-21 12:36:59 -04:00
extendedclip a0ac08b838 Start at 1 2019-06-21 12:36:03 -04:00
extendedclip 2c0b768774 ITS 2019 2019-06-21 12:30:32 -04:00
Glare 21048f83d5
Issue templates update (#128)
Issue templates update
2019-06-11 11:12:32 -05:00
Draycia 5b92dd5553
Shorten line in FileUtil 2019-06-10 11:22:05 -07:00
Draycia 4851655110
Make various things final 2019-06-10 11:10:39 -07:00
Draycia 64a6389ebf
Better use of StringBuilder 2019-06-10 11:10:14 -07:00
Draycia 4860e3f8bf
Remove unused casts 2019-06-10 11:04:01 -07:00
Draycia dfbf1b95f6
Cleanup formatting / spacing 2019-06-10 11:03:48 -07:00
Andre_601 9af9a3570d
Update CONTRIBUTING.md 2019-06-02 20:07:40 +02:00
Andre_601 16c237ce51
Update CONTRIBUTING.md 2019-06-02 20:06:56 +02:00
Andre_601 b44cb13d7a
Create CONTRIBUTING.md 2019-06-02 19:56:33 +02:00
Andre_601 8c509b47d1
Create PULL_REQUEST_TEMPLATE.md 2019-06-02 19:54:17 +02:00
Andre_601 c4cba9c6a7
Update bug_report.md 2019-06-02 19:37:57 +02:00
Andre_601 0809897303
Update and rename feature_request.md to change_request_placeholderapi.md 2019-06-02 19:30:12 +02:00
Andre_601 82181ed74d
Update and rename change_request.md to change_request_wiki.md 2019-06-02 19:20:27 +02:00
Andre_601 85328c473b
Improve the feature_request 2019-06-02 19:01:11 +02:00
darbyjack c9abc4ae00
Updated to 1.14.1 2019-05-13 21:36:33 -05:00
extendedclip 5f23db98a8 Set version to dev builds 2019-05-10 20:37:49 -04:00
extendedclip f367abbdfa Check if config values aren't null before attempting to set them. 2019-05-10 20:36:43 -04:00
extendedclip 9377129554 We don't even need an api version. It breaks stuff.. 2019-05-10 10:48:40 -04:00
extendedclip f4409a6d92 Fix numerical order of expansions in papi ecloud list 2019-05-10 10:28:59 -04:00
extendedclip c902485718 Remove clipsplaceholderapi since its no longer just clips placeholder api 2019-05-10 10:09:17 -04:00
extendedclip 09db82a840 Set API version to 1.14 even though it doesnt matter to us 2019-05-10 10:07:18 -04:00
extendedclip 9b667fe383 Bump version to 2.10.2 for release 2019-05-10 10:05:52 -04:00
darbyjack 00333f9a4e
Changed to use authors instead of hardcoded. 2019-05-09 18:47:16 -05:00
darbyjack 5472be631c
Added myself as an author to the plugin. 2019-05-09 17:09:21 -05:00
darbyjack 68fa793354
Added documentation / explanation for the ServerLoadEvent 2019-05-08 22:22:01 -05:00
darbyjack 111f5462fc
Cleaned up excess code in TimeUtils 2019-05-08 22:19:57 -05:00
darbyjack 62e282cc0e
Initial attempt at preventing EzPlaceholderHook from working. 2019-05-08 15:36:57 -05:00
darbyjack 5aaa9720c8
Changed to use easier way. 2019-05-08 15:05:30 -05:00
darbyjack 9a2fb89e43
Changed placeholders to register 1 tick after server startup. 2019-05-08 15:04:46 -05:00
extendedclip fc1a2af011 Merge branch 'master' of https://github.com/PlaceholderAPI/PlaceholderAPI 2019-05-07 14:17:00 -04:00
extendedclip 82e92ce777 set version for 2.10.1 release 2019-05-07 14:16:23 -04:00
Mitchell Cook 9b317c2210 Someone forgot how to use lambdas properly (#111) 2019-05-06 16:21:15 -04:00
darbyjack 927f942236
Print out console warnings for the plugins still using EzPlaceholderHook 2019-05-06 09:05:19 -05:00
extendedclip 75c3027e05 This will not be around for much longer. Plugin authors need to update to use PlaceholderExpansion rather than this class. 2019-05-05 13:59:40 -04:00
extendedclip a2d408aea9 Possible solution for placeholders that register externally before PlaceholderAPI registers expansions 2019-05-05 13:21:28 -04:00
extendedclip 5386b7c23d Remove load option 2019-05-05 10:39:05 -04:00
extendedclip a741f35139 Check if server supports ServerLoadEvent and if so register the listener, if not delay registration of placeholders for 15 seconds. 2019-05-05 10:38:42 -04:00
extendedclip 1e25f35aac Remove ServerLoadEvent listener 2019-05-05 10:37:54 -04:00
extendedclip 3042e49ddb Move ServerLoadEvent listener to its own class 2019-05-05 10:37:01 -04:00
extendedclip 6495a386a0 Remove EZPlaceholderHook which has been deprecated for over a year. TOODLES! 2019-05-04 21:25:44 -04:00
extendedclip cee214cc98 Remove PluginEnableEvent listener. Not needed anymore. 2019-05-04 20:15:00 -04:00
extendedclip 41390d8ef4 Remove clean method calls 2019-05-04 20:13:04 -04:00
extendedclip c0f6cf225f Remove useless "expansion cache" that I don't even know ever worked. Intention was to cache any expansion that isn't registered due to the dependency not being loaded yet when expansion registration initialized. Non issue now that registration happens in ServerLoadEvent. 2019-05-04 20:08:47 -04:00
extendedclip 16d0a4f690 Register expansions in the ServerLoadEvent which is called after the server startup process is complete.
Fixes #103
2019-05-04 19:56:59 -04:00
extendedclip 8f600aec25 Update to 2.10.0-DEV builds 2019-05-04 19:55:35 -04:00
extendedclip 2c15b4dfcf Update to 2.10.0 2019-05-04 00:19:29 -04:00
darbyjack b943c6fd21
Added support for 1.14 NMS for expansions to hook into 2019-05-03 22:51:34 -05:00
extendedclip 15b142ed64 Remove unused imports 2019-05-03 23:48:00 -04:00
extendedclip b2a488c694 Sort expansions alphabetically without errors Fixes #102 2019-05-03 23:44:51 -04:00
Funnycube 8447395c7b
As per request, daddy has been removed.
Rip Daddy,
2018 - 2019
"Bastards"
2019-04-29 16:36:08 +10:00
darbyjack 0ad11cd755
Push to 1.14-R0.1-SNAPSHOT 2019-04-27 22:08:57 -05:00
Mitchell Cook 29c61373b0 Implementing #93 (#94)
Testing required before PR.
2019-04-13 16:34:03 -04:00
Andre_601 e53cad219e
Changed "being made" to "to be made" 2019-01-26 17:54:41 +01:00
Glare Masters c7d05eff24
Merge pull request #63 from Andre601/master
Adding issue templates and updating readme.md
2019-01-22 11:20:21 -06:00
Andre_601 540a0952e7
"changes being made" sounds better imo 2019-01-22 16:18:00 +01:00
Andre_601 cef0a203dc
Links can be made like that 2019-01-22 16:10:52 +01:00
Andre_601 8f1ba895b2
Updating links 2019-01-02 18:08:39 +01:00
Andre_601 4d570aa526
Update bug_report.md 2019-01-02 18:03:24 +01:00
Andre_601 4c127f325b
Update feature_request.md 2019-01-02 18:02:05 +01:00
Andre_601 71f5e11b03
Update bug_report.md 2019-01-02 17:59:00 +01:00
Andre_601 1129f3d902
Update change_request.md 2019-01-02 17:58:09 +01:00
Andre_601 84a8029d7d
Create bug_report.md 2019-01-02 17:52:09 +01:00
Andre_601 dd6d90dbb6
Create change_request.md 2019-01-02 17:04:29 +01:00
Andre_601 0df9eeb2cc
Create feature_request.md 2019-01-02 17:04:04 +01:00
Ryan 05ce2fb5bf
Merge pull request #61 from Phoenix616/patch-1
Load at startup
2018-12-27 09:14:31 -05:00
Max Lee cb7fbb7820
Load at startup
By default plugins are loaded later. (post world) This complicates hooking into PlaceholderAPI from other plugins that load directly at startup as PlaceholderAPI isn't available yet at that point.
2018-12-27 13:56:09 +01:00
darbyjack ce5bb28247 Push to 1.13.2 2018-10-22 22:02:50 -05:00
darbyjack 639b7967e3 Refresh on download to fix the gold bug 2018-10-20 15:43:38 -05:00
darbyjack 90bc3c8da1 Fixed a bug in /papi installed 2018-10-20 15:30:10 -05:00
darbyjack 556faf4290 Changed the Discord Link 2018-10-18 23:06:52 -05:00
darbyjack 4af2a1c7be Update to 2.9.2-DEV and add in more info when typing /papi 2018-10-17 02:53:39 -05:00
Glare Masters 6ff7be5d64
Merge pull request #46 from Sxtanna/master
Changed to be slightly less trash
2018-10-17 02:22:11 -05:00
Sxtanna 80c6a6d377 This class was trash 2018-10-12 12:43:57 -04:00
Ranald 27f8586d76
Merge pull request #2 from PlaceholderAPI/master
Update
2018-10-12 11:31:47 -04:00
extendedclip d0b4669d1f Update to 2.9.2 release 2018-08-27 00:08:16 -04:00
extendedclip c205a9a1b9 Just make the damn directory 2018-08-27 00:05:51 -04:00
extendedclip ce1ca35ee5 Merge branch 'master' of https://github.com/PlaceholderAPI/PlaceholderAPI 2018-08-26 23:57:28 -04:00
extendedclip 0bfd42d607 Set 1.13.1 Spigot API as dependency, Shade and relocate GSON 2018-08-26 23:56:37 -04:00
extendedclip 197aa5dfe0 Added 1.13 R2 NMS to the enum 2018-08-26 22:58:02 -04:00
darbyjack efa97ce049 Undone for time being 2018-08-26 14:46:05 -05:00
darbyjack e2423cdd70 Added support to versions less than 1.8.3 2018-08-26 14:37:17 -05:00
Ranald 0d30c8ac50
Merge pull request #1 from PlaceholderAPI/master
daddy
2018-08-26 15:08:23 -04:00
extendedclip 589712f7e4 daddy 2018-08-10 23:32:07 -04:00
extendedclip dd5ec37055 try with resources cuz haters 2018-07-22 16:52:36 -04:00
extendedclip 49eceaae50 Use 1.13 spigot-api 2018-07-22 16:52:12 -04:00
extendedclip 7ea2bd94a7 Do not deprecate legacy setPlaceholder methods for now 2018-07-21 22:00:33 -04:00
extendedclip 736b8ada3d Add v1_13_R1 to the NMSVersion enum 2018-07-21 21:59:02 -04:00
extendedclip d08de32852 Add api-version entry for 1.13 2018-07-21 21:58:26 -04:00
Ryan 83e64ee883
Merge pull request #33 from Mishyy/master
Bug fixes, and cosmetic modifications.
2018-07-16 04:06:26 -04:00
Mitchell Cook 27ca32b14c
Updated .gitignore to ignore .iml project files. 2018-07-16 18:01:40 +10:00
Mitchell Cook 838f947a05
Resolve expansion loading bug. 2018-07-16 17:50:12 +10:00
Mitchell Cook efc6a6337b
Added compareTo method for easier comparison in expasions. 2018-07-16 17:50:12 +10:00
Mitchell Cook 9cc5a9678f
Reformatted project to conform to google style guide. 2018-07-16 17:50:07 +10:00
extendedclip bc915af13e Added subcommand to register an expansion by specifying the name of the file, or unregistering by specifying the name of the expansion. 2018-06-29 15:03:53 -04:00
extendedclip 43b8013c29 Added method to register expansion by specifying the file name 2018-06-29 15:02:05 -04:00
extendedclip adca215ea7 Added method to get all class files of a certain type from a specific jar 2018-06-29 14:40:48 -04:00
extendedclip d0445e231d Added register/unregister perm, removed injector perms 2018-06-29 14:34:25 -04:00
extendedclip be96238800 Added ability to use parse subcommand from console when targeting a player, Added ability to broadcast a parse message with bcparse subcommand 2018-06-16 20:05:12 -04:00
extendedclip 0f51b4f2a5 Added broadcast method 2018-06-16 19:57:22 -04:00
extendedclip 287ab16d3a Set version for 2.9.1 dev builds 2018-06-14 15:21:18 -04:00
extendedclip e4a672e57e Require a player be specified when using /papi parse command 2018-06-14 15:17:46 -04:00
extendedclip 46839c4bf2 Set version to 2.9.1 2018-06-13 14:26:16 -04:00
extendedclip 2894d525f2 Add deprecated setPlaceholders(Player) methods back to prevent exceptions with plugins parsing placeholders 2018-06-13 14:14:27 -04:00
extendedclip 53fb678035 Set version to 2.9.0 for release 2018-06-13 12:50:22 -04:00
extendedclip 86a1fe862f New method supporting offlinePlayer renamed to onRequest 2018-06-13 12:50:01 -04:00
extendedclip eba181d04d Revert return type back to String for new onPlaceholderRequest method 2018-06-01 21:01:01 -04:00
extendedclip 25758ee653 Return any Object with the new onPlaceholderRequest method. 2018-05-31 15:14:25 -04:00
extendedclip a50212e395 Add support for OfflinePlayer 2018-05-31 14:35:28 -04:00
extendedclip cfccc69839 Javadoc typo fixes 2018-05-31 13:52:32 -04:00
extendedclip 659af4833e Added getRequiredPlugin method.
Deprecated getPlugin(), getLink(), and getDescription().
fix javadoc for PlaceholderExpansion class...
closes #22, closes #23
2018-05-31 13:46:24 -04:00
extendedclip e1ba07b7bd Set version for dev builds 2018-05-31 13:34:46 -04:00
extendedclip d5146ea3e5 Update to 2.8.7 2018-05-10 11:38:42 -04:00
extendedclip 3a5e3ed950 Refactored update checker 2018-04-20 23:01:01 -04:00
extendedclip 763c0aabc1 Cleanup imports 2018-04-20 22:59:17 -04:00
extendedclip 6eaad829cf Pass option to filter unverified expansions when calling fetch 2018-04-20 22:56:06 -04:00
extendedclip dd45bc16d0 Pass filtering unverified expansions to fetch 2018-04-20 22:23:03 -04:00
extendedclip 7900ee71e0 Check and filter unverified expansions 2018-04-20 22:22:03 -04:00
extendedclip 6825c9afc1 Use registerExpansion instead of registerPlaceholderHook in the register method. 2018-04-20 22:15:13 -04:00
extendedclip 1a905f88a9 Added registerExpansion method. Placeholder map interaction methods now return immutable objects 2018-04-20 22:11:54 -04:00
extendedclip 796136982a Added ExpansionRegisterEvent 2018-04-20 22:07:03 -04:00
extendedclip 3ada9d988b Costants use UPPER_SNAKE_CASE. resolves #17 2018-04-20 21:03:57 -04:00
extendedclip 1504972e51 Remove duplicate method. Make field modifiers consistent resolves #16, resolves #18 2018-04-20 21:03:00 -04:00
Ryan 1789c3b183
Merge pull request #13 from Sxtanna/master
Changed Msg#msg to use method references
2018-04-19 00:21:15 -04:00
Sxtanna e336eccd9a Changed Msg#msg to use method references 2018-04-18 23:36:47 -04:00
Ryan d256286a02
Update version for Jenkins dev builds 2018-04-10 17:20:59 -04:00
Ryan 81aaef2319
Don't set gson to null on clear 2018-04-10 17:15:51 -04:00
extendedclip b7003c5142 Actually show placeholders when the expansion is not installed 2018-04-08 15:41:25 -04:00
extendedclip 1e9811507f Set version to 2.8.6 for Spigot release 2018-04-08 15:24:09 -04:00
extendedclip 06b1599f66 Commands no longer Bukkit / Spigot dependent. 2018-04-08 04:06:56 -04:00
extendedclip 7011a8d8c5 Supports ECloud API v2, added Gson parsing, expansion version history support 2018-04-08 04:04:15 -04:00
extendedclip 92d30ea4cb Format 2018-04-08 04:02:09 -04:00
extendedclip 906bf0a338 Added jsonmessage dependency 2018-04-08 04:00:25 -04:00
extendedclip 134d18c71c Add color utility method 2018-04-08 03:59:06 -04:00
extendedclip 59539d591c Do not pass spigot boolean to command constructor 2018-04-08 03:58:39 -04:00
DoNotSpamPls a5200fd5c1 Check for permissions instead of isOp() (#6) 2018-03-27 10:43:17 -04:00
extendedclip 2856889bbe Escape placeholder pattern. fixes #4 2018-03-26 17:32:18 -04:00
88 changed files with 7900 additions and 3179 deletions

9
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,9 @@
#
# 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

67
.github/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,67 @@
[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 are we 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.

103
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@ -0,0 +1,103 @@
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..."

17
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,17 @@
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

@ -0,0 +1,62 @@
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..."

28
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,28 @@
<!--
### 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" the the issue ID (#id) -->
<!-- DO NOT ALTER ANYTHING BELOW THIS LINE! -->
[Wiki]: https://wiki.placeholderapi.com

145
.github/label-commenter-config.yml vendored Normal file
View File

@ -0,0 +1,145 @@
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 Normal file
View File

@ -0,0 +1,24 @@
#
# 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.

25
.github/workflows/label_comment.yml vendored Normal file
View File

@ -0,0 +1,25 @@
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 }}

31
.github/workflows/pr_build_jars.yml vendored Normal file
View File

@ -0,0 +1,31 @@
name: "Test compiling against Java 8, 11 and 16"
on:
pull_request:
branches:
- development
paths:
- "src/**"
- "build.gradle"
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"

150
.gitignore vendored
View File

@ -1,146 +1,6 @@
### Eclipse ###
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
### Eclipse Patch ###
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries
# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
# Gradle:
.idea/**/gradle.xml
.idea/**/libraries
# CMake
cmake-build-debug/
# Mongo Explorer plugin:
.idea/**/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Ruby plugin and RubyMine
/.rakeTasks
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### Intellij Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
# Sonarlint plugin
.idea/sonarlint
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored)
!/.mvn/wrapper/maven-wrapper.jar
### NetBeans ###
nbproject/private/
.idea/
.gradle/
server/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/
nbactions.xml
out/
*.iml

51
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,51 @@
[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]

View File

@ -1,16 +1,44 @@
[![PlaceholderAPI Logo](https://i.imgur.com/Ea4PURv.png)][spigot]
[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
[![Build Status](http://ci.extendedclip.com/buildStatus/icon?job=PlaceholderAPI)][ci]
[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
[bbb]: https://builtbybit.com/resources/placeholderapi.24306
[Expansions cloud]: https://api.extendedclip.com/home
[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://img.shields.io/nexus/placeholderapi/me.clip/placeholderapi?server=https%3A%2F%2Frepo.extendedclip.com&label=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 100 expansions that support a wide variety of plugins, such as Essentials, Factions, LuckPerms, and Vault.
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 100,000 times and has been used concurrently on over 10,000 servers, which makes it a must-have for a server of any type or scale.
PlaceholderAPI has been downloaded over 1,000,000 times and has been used concurrently on over 40,000 servers, which makes it a must-have for a server of any type or scale.
<!-- TODO: Add contributing section -->
<!-- TODO: Add expansion creation section (possibly add to a wiki?) -->
## 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]
@ -18,20 +46,9 @@ PlaceholderAPI has been downloaded over 100,000 times and has been used concurre
## Quick Links
- [CI Server][ci]
- [Expansions Website][expansions]
- [Placeholder List][placeholder-list]
- [Expansions Cloud]
- [Placeholder List]
- [Spigot Page][spigot]
- [Hangar Page][hangar]
- [BuiltByBit Page][bbb]
- [Plugin Statistics][statistics]
## License
PlaceholderAPI is licensed under the __GNU GPLv3__ license. Refer to the [LICENSE](LICENSE) file for more information.
<!-- Page Links - Placed here to be easier to change later on. -->
[issues]: https://github.com/PlaceholderAPI/PlaceholderAPI/issues
[discord]: https://discord.gg/7sndK3q
[spigot]: https://www.spigotmc.org/resources/placeholderapi.6245/
[ci]: http://ci.extendedclip.com/job/PlaceholderAPI/
[expansions]: https://api.extendedclip.com/all/
[placeholder-list]: https://www.spigotmc.org/wiki/placeholderapi-placeholders/
[statistics]: https://bstats.org/plugin/bukkit/PlaceholderAPI

130
build.gradle.kts Normal file
View File

@ -0,0 +1,130 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins {
`java-library`
`maven-publish`
id("com.github.hierynomus.license") version "0.16.1"
id("com.github.johnrengelman.shadow") version "8.1.0"
}
group = "me.clip"
version = "2.11.7-DEV-${System.getProperty("BUILD_NUMBER")}"
description = "An awesome placeholder provider!"
repositories {
maven("https://oss.sonatype.org/content/repositories/snapshots/")
mavenCentral()
mavenLocal()
maven("https://repo.codemc.org/repository/maven-public/")
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
}
dependencies {
implementation("org.bstats:bstats-bukkit:3.0.1")
implementation("net.kyori:adventure-platform-bukkit:4.3.2")
compileOnly("org.spigotmc:spigot-api:1.20-R0.1-SNAPSHOT")
compileOnlyApi("org.jetbrains:annotations:23.0.0")
testImplementation("org.openjdk.jmh:jmh-core:1.32")
testImplementation("org.openjdk.jmh:jmh-generator-annprocess:1.32")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.8.2")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1")
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
withJavadocJar()
withSourcesJar()
}
license {
header = rootProject.file("config/headers/main.txt")
include("**/*.java")
mapping("java", "JAVADOC_STYLE")
encoding = "UTF-8"
ext {
set("year", 2024)
}
}
val javaComponent: SoftwareComponent = components["java"]
tasks {
processResources {
eachFile { expand("version" to project.version) }
}
build {
dependsOn(named("shadowJar"))
}
withType<JavaCompile> {
options.encoding = "UTF-8"
}
withType<Javadoc> {
isFailOnError = false
with(options as StandardJavadocDocletOptions) {
addStringOption("Xdoclint:none", "-quiet")
addStringOption("encoding", "UTF-8")
addStringOption("charSet", "UTF-8")
}
}
withType<ShadowJar> {
archiveClassifier.set("")
relocate("org.bstats", "me.clip.placeholderapi.metrics")
relocate("net.kyori", "me.clip.placeholderapi.libs.kyori")
exclude("META-INF/versions/**")
}
test {
useJUnitPlatform()
}
publishing {
publications {
create<MavenPublication>("maven") {
artifactId = "placeholderapi"
from(javaComponent)
}
}
repositories {
maven {
if ("-DEV" in version.toString()) {
url = uri("https://repo.extendedclip.com/content/repositories/dev/")
} else {
url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/")
}
credentials {
username = System.getenv("JENKINS_USER")
password = System.getenv("JENKINS_PASS")
}
}
}
}
publish.get().setDependsOn(listOf(build.get()))
}
configurations {
testImplementation {
extendsFrom(compileOnly.get())
}
}

View File

@ -0,0 +1,7 @@
Copyright (c) 2018-2024 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.

17
config/headers/main.txt Normal file
View File

@ -0,0 +1,17 @@
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/>.

569
config/style/daddystyle.xml Normal file
View File

@ -0,0 +1,569 @@
<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
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

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

234
gradlew vendored Executable file
View File

@ -0,0 +1,234 @@
#!/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/master/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
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# 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*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
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 \
"$@"
# 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" "$@"

89
gradlew.bat vendored Normal file
View File

@ -0,0 +1,89 @@
@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=.
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%" == "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%"=="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!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

94
pom.xml
View File

@ -1,94 +0,0 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.8.5</version>
<name>PlaceholderAPI</name>
<description>An awesome placeholder provider!</description>
<url>http://extendedclip.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>bstats-repo</id>
<url>http://repo.bstats.org/content/repositories/releases/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>1.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<defaultGoal>clean package</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<finalName>${project.name}-${project.version}</finalName>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>me.clip.placeholderapi.metrics</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>

1
settings.gradle.kts Normal file
View File

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

View File

@ -1,323 +1,622 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi;
import me.clip.placeholderapi.events.ExpansionUnregisterEvent;
import me.clip.placeholderapi.events.PlaceholderHookUnloadEvent;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Relational;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.util.*;
import com.google.common.collect.ImmutableSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Relational;
import me.clip.placeholderapi.expansion.manager.LocalExpansionManager;
import me.clip.placeholderapi.replacer.CharsReplacer;
import me.clip.placeholderapi.replacer.Replacer;
import me.clip.placeholderapi.replacer.Replacer.Closure;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
public class PlaceholderAPI {
private PlaceholderAPI() {
}
private final static Pattern PLACEHOLDER_PATTERN = Pattern.compile("[%]([^%]+)[%]");
private final static Pattern BRACKET_PLACEHOLDER_PATTERN = Pattern.compile("[{]([^{}]+)[}]");
private final static Pattern RELATIONAL_PLACEHOLDER_PATTERN = Pattern.compile("[%](rel_)([^%]+)[%]");
private final static Map<String, PlaceholderHook> placeholders = new HashMap<>();
/**
* check if a specific placeholder identifier is currently registered
* @param identifier to check
* @return true if identifier is already registered
*/
public static boolean isRegistered(String identifier) {
return !placeholders.isEmpty() && getRegisteredIdentifiers().stream().filter(id -> id.equalsIgnoreCase(identifier)).findFirst().orElse(null) != null;
}
/**
* Register a new placeholder hook
* @param identifier Identifier of the placeholder -> "%(identifier)_(args...)%
*
* @param placeholderHook implementing class that contains the onPlaceholderRequest method which is called when a value is needed for the specific placeholder
* @return true if the hook was successfully registered, false if there is already a hook registered for the specified identifier
*/
public static boolean registerPlaceholderHook(String identifier, PlaceholderHook placeholderHook) {
Validate.notNull(identifier, "Identifier can not be null");
Validate.notNull(placeholderHook, "Placeholderhook can not be null");
if (isRegistered(identifier)) return false;
placeholders.put(identifier.toLowerCase(), placeholderHook);
return true;
}
/**
* unregister a placeholder hook by identifier
* @param identifier the identifier for the placeholder hook to unregister
* @return true if the placeholder hook was successfully unregistered, false if there was no placeholder hook registered for the identifier specified
*/
public static boolean unregisterPlaceholderHook(String identifier) {
Validate.notNull(identifier, "Identifier can not be null");
return placeholders.remove(identifier.toLowerCase()) != null;
}
/**
* Get all registered placeholder identifiers
* @return all registered placeholder identifiers
*/
public static Set<String> getRegisteredIdentifiers() {
if (placeholders.isEmpty()) return new HashSet<>();
return new HashSet<>(placeholders.keySet());
}
public final class PlaceholderAPI {
/**
* Get map of registered placeholders
* @return copy of the internal placeholder map
*/
public static Map<String, PlaceholderHook> getPlaceholders() {
return new HashMap<>(placeholders);
}
private static final Replacer REPLACER_PERCENT = new CharsReplacer(Closure.PERCENT);
private static final Replacer REPLACER_BRACKET = new CharsReplacer(Closure.BRACKET);
public static Set<PlaceholderExpansion> getExpansions() {
return getPlaceholders().values().stream().filter(PlaceholderExpansion.class::isInstance).map(PlaceholderExpansion.class::cast).collect(Collectors.toCollection(HashSet::new));
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("[%]([^%]+)[%]");
private static final Pattern BRACKET_PLACEHOLDER_PATTERN = Pattern.compile("[{]([^{}]+)[}]");
private 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 OfflinePlayer player,
@NotNull final String text) {
return REPLACER_PERCENT.apply(text, player,
PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::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 text List of Strings to set the placeholder values in
* @return String containing all translated placeholders
*/
@NotNull
public static List<String> setPlaceholders(final OfflinePlayer 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 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 OfflinePlayer player,
@NotNull final String text) {
return REPLACER_BRACKET.apply(text, player,
PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::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 text List of Strings to set the placeholder values in
* @return String containing all translated placeholders
*/
@NotNull
public static List<String> setBracketPlaceholders(final OfflinePlayer player,
@NotNull final List<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
*/
public static String setBracketPlaceholders(Player player, 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
*/
public static List<String> setBracketPlaceholders(Player player, 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(Player one, Player 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.getInstance()
.getLocalExpansionManager().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));
}
}
/**
* check if a String contains any PlaceholderAPI placeholders
* @param text String to check
* @return true if String contains any registered placeholder identifiers, 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
* @param text String to check
* @return true if String contains any registered placeholder identifiers, false otherwise
*/
public static boolean containsBracketPlaceholders(String text) {
return text != null && BRACKET_PLACEHOLDER_PATTERN.matcher(text).find();
}
/**
* set placeholders in the list<String> text provided
* placeholders are matched with the pattern {<placeholder>} when set with this method
* @param p Player to parse the placeholders for
* @param text text to set the placeholder values in
* @return modified list with all placeholders set to the corresponding values
*/
public static List<String> setBracketPlaceholders(Player p, List<String> text) {
return setPlaceholders(p, text, BRACKET_PLACEHOLDER_PATTERN);
}
return text;
}
/**
* set placeholders in the list<String> text provided
* placeholders are matched with the pattern %(identifier)_(params)>% when set with this method
* @param p Player to parse the placeholders for
* @param text text to parse the placeholder values in
* @return modified list with all placeholders set to the corresponding values
*/
public static List<String> setPlaceholders(Player p, List<String> text) {
return setPlaceholders(p, text, PLACEHOLDER_PATTERN);
}
/**
* 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(Player one, Player two, List<String> text) {
return text.stream().map(line -> setRelationalPlaceholders(one, two, line))
.collect(Collectors.toList());
}
/**
* set placeholders in the list<String> text provided
* placeholders are matched with the pattern %(identifier)_(params)>% when set with this method
* @param p Player to parse the placeholders for
* @param text text to parse the placeholder values in
* @return modified list with all placeholders set to the corresponding values
*/
public static List<String> setPlaceholders(Player p, List<String> text, Pattern pattern) {
if (text == null) return null;
List<String> temp = new ArrayList<>();
text.forEach(line -> {
temp.add(setPlaceholders(p, line, pattern));
});
return temp;
}
/**
* 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.getInstance().getLocalExpansionManager()
.findExpansionByIdentifier(identifier).isPresent();
}
/**
* set placeholders in the text specified
* placeholders are matched with the pattern {<placeholder>} when set with this method
* @param player Player to parse the placeholders for
* @param text text to parse the placeholder values to
* @return modified text with all placeholders set to the corresponding values
*/
public static String setBracketPlaceholders(Player player, String text) {
return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN);
}
/**
* set placeholders in the text specified
* placeholders are matched with the pattern %<(identifier)_(params)>% when set with this method
* @param player Player to parse the placeholders for
* @param text text to parse the placeholder values to
* @return text with all placeholders set to the corresponding values
*/
public static String setPlaceholders(Player player, String text) {
return setPlaceholders(player, text, PLACEHOLDER_PATTERN);
}
/**
* 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 ImmutableSet
.copyOf(PlaceholderAPIPlugin.getInstance().getLocalExpansionManager().getIdentifiers());
}
/**
* set placeholders in the text specified
* placeholders are matched with the pattern %<(identifier)_(params)>% when set with this method
* @param player Player to parse the placeholders for
* @param text text to parse the placeholder values to
* @param placeholderPattern the pattern to match placeholders to. Capture group 1 must contain an underscore separating the identifier from the params
* @return text with all placeholders set to the corresponding values
*/
public static String setPlaceholders(Player player, String text, Pattern placeholderPattern) {
if (text == null) return null;
if (placeholders.isEmpty()) return colorize(text);
Matcher m = placeholderPattern.matcher(text);
Map<String, PlaceholderHook> hooks = getPlaceholders();
while (m.find()) {
String format = m.group(1);
int index = format.indexOf("_");
if (index <= 0 || index >= format.length()) continue;
String identifier = format.substring(0, index).toLowerCase();
String params = format.substring(index+1);
if (hooks.containsKey(identifier)) {
String value = hooks.get(identifier).onPlaceholderRequest(player, params);
if (value != null) {
text = text.replaceAll(m.group(), Matcher.quoteReplacement(value));
}
}
}
return colorize(text);
}
/**
* set relational placeholders in the text specified
* placeholders are matched with the pattern %<rel_(identifier)_(params)>% when set with this method
* @param one Player to compare
* @param two Player to compare
* @param text text to parse the placeholder values to
* @return text with all relational placeholders set to the corresponding values
*/
public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text) {
if (text == null) return null;
List<String> temp = new ArrayList<>();
text.forEach(line -> {
temp.add(setRelationalPlaceholders(one, two, line));
});
return temp;
}
/**
* set relational placeholders in the text specified
* placeholders are matched with the pattern %<rel_(identifier)_(params)>% when set with this method
* @param one Player to compare
* @param two Player to compare
* @param text text to parse the placeholder values to
* @return text with all relational placeholders set to the corresponding values
*/
public static String setRelationalPlaceholders(Player one, Player two, String text) {
if (text == null) return null;
if (placeholders.isEmpty()) return colorize(text);
Matcher m = RELATIONAL_PLACEHOLDER_PATTERN.matcher(text);
Map<String, PlaceholderHook> hooks = getPlaceholders();
while (m.find()) {
String format = m.group(2);
int index = format.indexOf("_");
if (index <= 0 || index >= format.length()) continue;
String identifier = format.substring(0, index).toLowerCase();
String params = format.substring(index+1);
if (hooks.containsKey(identifier)) {
if (!(hooks.get(identifier) instanceof Relational)) {
continue;
}
Relational rel = (Relational) hooks.get(identifier);
String value = rel.onPlaceholderRequest(one, two, params);
if (value != null) {
text = text.replaceAll(m.group(), Matcher.quoteReplacement(value));
}
}
}
return colorize(text);
}
/**
* Get the normal placeholder pattern.
*
* @return Regex Pattern of {@literal [%]([^%]+)[%]}
*/
public static Pattern getPlaceholderPattern() {
return PLACEHOLDER_PATTERN;
}
/**
* unregister ALL placeholder hooks that are currently registered
*/
protected static void unregisterAll() {
unregisterAllProvidedExpansions();
placeholders.clear();
}
/**
* Get the bracket placeholder pattern.
*
* @return Regex Pattern of {@literal [{]([^{}]+)[}]}
*/
public static Pattern getBracketPlaceholderPattern() {
return BRACKET_PLACEHOLDER_PATTERN;
}
/**
* unregister all expansions provided by PlaceholderAPI
*/
public static void unregisterAllProvidedExpansions() {
if (placeholders.isEmpty()) return;
getPlaceholders().forEach((key, value) -> {
if (value instanceof PlaceholderExpansion) {
PlaceholderExpansion ex = (PlaceholderExpansion) value;
if (!ex.persist()) {
unregisterExpansion(ex);
}
}
});
}
/**
* Get the relational placeholder pattern.
*
* @return Regex Pattern of {@literal [%](rel_)([^%]+)[%]}
*/
public static Pattern getRelationalPlaceholderPattern() {
return RELATIONAL_PLACEHOLDER_PATTERN;
}
public static boolean unregisterExpansion(PlaceholderExpansion ex) {
if (unregisterPlaceholderHook(ex.getIdentifier())) {
Bukkit.getPluginManager().callEvent(new ExpansionUnregisterEvent(ex));
return true;
}
return false;
}
public static Pattern getPlaceholderPattern() {
return PLACEHOLDER_PATTERN;
}
public static Pattern getBracketPlaceholderPattern() {
return BRACKET_PLACEHOLDER_PATTERN;
}
public static Pattern getRelationalPlaceholderPattern() {
return RELATIONAL_PLACEHOLDER_PATTERN;
}
public static String colorize(String text) {
return ChatColor.translateAlternateColorCodes('&', text);
}
@Deprecated
public static Set<String> getRegisteredPlaceholderPlugins() {
return getRegisteredIdentifiers();
}
@Deprecated
public static Set<String> getExternalPlaceholderPlugins() {
return null;
}
@Deprecated
public static boolean registerPlaceholderHook(Plugin plugin, PlaceholderHook placeholderHook) {
return plugin != null && registerPlaceholderHook(plugin.getName(), placeholderHook);
}
@Deprecated
public static boolean unregisterPlaceholderHook(Plugin plugin) {
return plugin != null && unregisterPlaceholderHook(plugin.getName());
}
/**
* 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();
}
// === Deprecated API ===
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static boolean registerExpansion(PlaceholderExpansion expansion)
{
return expansion.register();
}
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static boolean unregisterExpansion(PlaceholderExpansion expansion)
{
return expansion.unregister();
}
/**
* Get map of registered placeholders
*
* @deprecated Use {@link LocalExpansionManager#getExpansions()} instead.
*
* @return Map of registered placeholders
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static Map<String, PlaceholderHook> getPlaceholders() {
return PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()
.getExpansions().stream()
.collect(Collectors.toMap(PlaceholderExpansion::getIdentifier, ex -> ex));
}
/**
* @deprecated Please use {@link PlaceholderExpansion} to
* register placeholders instead
*
* @param plugin The Plugin to register with this {@link PlaceholderHook}
* @param placeholderHook The {@link PlaceholderHook} to register
* @return always false
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static boolean registerPlaceholderHook(Plugin plugin, PlaceholderHook placeholderHook) {
Msg.warn("Nag author(s) %s of plugin %s about their usage of the deprecated PlaceholderHook"
+ " class! This class will be removed in v2.13.0!", plugin.getDescription().getAuthors(),
plugin.getName());
return false;
}
/**
* @deprecated Please use {@link PlaceholderExpansion} to
* register placeholders instead
*
* @param identifier The identifier to use for the {@link PlaceholderHook}
* @param placeholderHook The {@link PlaceholderHook} to register
* @return always false
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static boolean registerPlaceholderHook(String identifier,
PlaceholderHook placeholderHook) {
Msg.warn("%s is attempting to register placeholders via deprecated PlaceholderHook class."
+ " This class is no longer supported and will be removed in v2.13.0!", identifier);
return false;
}
/**
* @deprecated Please use {@link PlaceholderExpansion} to
* unregister placeholders instead
*
* @param plugin The plugin to unregister
* @return always false
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static boolean unregisterPlaceholderHook(Plugin plugin) {
Msg.warn("Nag author(s) %s of plugin %s about their usage of the PlaceholderAPI class."
+ " This way of unregistering placeholders is no longer supported and will be removed"
+ " in v2.13.0!", plugin.getDescription().getAuthors(), plugin.getName());
return false;
}
/**
* @deprecated Please use {@link PlaceholderExpansion} to
* unregister placeholders instead
*
* @param identifier The identifier to unregister
* @return always false
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static boolean unregisterPlaceholderHook(String identifier) {
Msg.warn("%s is attempting to unregister placeholders via PlaceholderAPI class."
+ " This way of unregistering placeholders is no longer supported and will be removed"
+ " in v2.13.0!", identifier);
return false;
}
/**
* @deprecated Will be removed in a future release.
*
* @return Set of registered identifiers
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static Set<String> getRegisteredPlaceholderPlugins() {
return getRegisteredIdentifiers();
}
/**
* @deprecated Will be removed in a future release.
*
* @return always null
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static Set<String> getExternalPlaceholderPlugins() {
return null;
}
/**
* @deprecated Please use {@link #setPlaceholders(OfflinePlayer, String)} instead
*
* @param player The offline player to parse the placeholders against
* @param text The text to parse
* @param pattern The Pattern to use
* @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static String setPlaceholders(OfflinePlayer player,
String text, Pattern pattern, boolean colorize) {
return setPlaceholders(player, text);
}
/**
* @deprecated Please use {@link #setPlaceholders(OfflinePlayer, List)} instead
*
* @param player The offline player to parse the placeholders against
* @param text The List of text to parse
* @param pattern The Pattern to use
* @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static List<String> setPlaceholders(OfflinePlayer player,
List<String> text, Pattern pattern, boolean colorize) {
return setPlaceholders(player, text);
}
/**
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead.
*
* @param player The offline player to parse the placeholders against
* @param text The List of text to parse
* @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static List<String> setPlaceholders(OfflinePlayer player, List<String> text,
boolean colorize) {
return setPlaceholders(player, text);
}
/**
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead.
*
* @param player The offline player to parse the placeholders against
* @param text The List of text to parse
* @param pattern The Pattern to use
* @return String with the parsed placeholders
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static List<String> setPlaceholders(OfflinePlayer player, List<String> text,
Pattern pattern) {
return setPlaceholders(player, text);
}
/**
* @deprecated Will be removed in a future release.
*
* @param player The offline player to parse the placeholders against
* @param text The text to parse
* @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static String setPlaceholders(Player player, String text, boolean colorize) {
return setPlaceholders(player, text);
}
/**
* @deprecated Will be removed in a future release.
*
* @param player The offline player to parse the placeholders against
* @param text The List of text to parse
* @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static List<String> setPlaceholders(Player player, List<String> text, boolean colorize) {
return setPlaceholders(player, text);
}
/**
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead.
*
* @param player The offline player to parse the placeholders against
* @param text The text to parse
* @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static String setPlaceholders(OfflinePlayer player, String text, boolean colorize) {
return setPlaceholders(player, text);
}
/**
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead.
*
* @param player The offline player to parse the placeholders against
* @param text The text to parse
* @param pattern The Pattern to use
* @return String with the parsed placeholders
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static String setPlaceholders(OfflinePlayer player, String text, Pattern pattern) {
return setPlaceholders(player, text);
}
/**
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead.
*
* @param player The offline player to parse the placeholders against
* @param text The List of text to parse
* @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static List<String> setBracketPlaceholders(OfflinePlayer player, List<String> text,
boolean colorize) {
return setBracketPlaceholders(player, text);
}
/**
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead.
*
* @param player The offline player to parse the placeholders against
* @param text The text to parse
* @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static String setBracketPlaceholders(OfflinePlayer player, String text, boolean colorize) {
return setBracketPlaceholders(player, text);
}
/**
* @deprecated Will be removed in a future release.
*
* @param player The offline player to parse the placeholders against
* @param text The text to parse
* @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static String setBracketPlaceholders(Player player, String text, boolean colorize) {
return setBracketPlaceholders(player, text);
}
/**
* @deprecated Will be removed in a future release.
*
* @param player The offline player to parse the placeholders against
* @param text The List of text to parse
* @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static List<String> setBracketPlaceholders(Player player, List<String> text,
boolean colorize) {
return setBracketPlaceholders(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 Player to compare
* @param two Player to compare
* @param text Text to parse the placeholders in
* @param colorize If color codes ({@literal &[0-1a-fk-o]}) should be translated
* @return The text containing the parsed relational placeholders
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead.
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static String setRelationalPlaceholders(Player one, Player two, String text,
boolean colorize) {
return setRelationalPlaceholders(one, two, 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>_<params>%}.
*
* @param one First player to compare
* @param two Second player to compare
* @param text Text to parse the placeholders in
* @param colorize If color codes ({@literal &[0-1a-fk-o]}) should be translated
* @return The text containing the parsed relational placeholders
* @deprecated Use {@link #setRelationalPlaceholders(Player, Player, List)} instead.
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text,
boolean colorize) {
return setRelationalPlaceholders(one, two, text);
}
}

View File

@ -1,272 +1,270 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi;
import me.clip.placeholderapi.commands.PlaceholderAPICommands;
import me.clip.placeholderapi.configuration.PlaceholderAPIConfig;
import me.clip.placeholderapi.expansion.ExpansionManager;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Version;
import me.clip.placeholderapi.expansion.cloud.ExpansionCloudManager;
import me.clip.placeholderapi.updatechecker.UpdateChecker;
import me.clip.placeholderapi.util.TimeUtil;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import me.clip.placeholderapi.commands.PlaceholderCommandRouter;
import me.clip.placeholderapi.configuration.PlaceholderAPIConfig;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Version;
import me.clip.placeholderapi.expansion.manager.CloudExpansionManager;
import me.clip.placeholderapi.expansion.manager.LocalExpansionManager;
import me.clip.placeholderapi.listeners.ServerLoadEventListener;
import me.clip.placeholderapi.updatechecker.UpdateChecker;
import me.clip.placeholderapi.util.Msg;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.AdvancedPie;
import org.bstats.charts.SimplePie;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.event.HandlerList;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
/**
* Yes I have a shit load of work to do...
*
* @author Ryan McCarthy
*
* @author Ryan McCarthy
*/
public class PlaceholderAPIPlugin extends JavaPlugin {
public final class PlaceholderAPIPlugin extends JavaPlugin {
private static PlaceholderAPIPlugin instance;
@NotNull
private static final Version VERSION;
private static PlaceholderAPIPlugin instance;
private PlaceholderAPIConfig config;
static {
String version = Bukkit.getServer().getBukkitVersion().split("-")[0];
String suffix;
if (version.chars()
.filter(c -> c == '.')
.count() == 1) {
suffix = "R1";
version = 'v' + version.replace('.', '_') + '_' + suffix;
} else {
int minor = Integer.parseInt(version.split("\\.")[2].charAt(0) + "");
version = 'v' + version.replace('.', '_').replace("_" + minor, "") + '_' + "R" + (minor - 1);
}
private ExpansionManager expansionManager;
boolean isSpigot;
try {
Class.forName("org.spigotmc.SpigotConfig");
isSpigot = true;
} catch (final ExceptionInInitializerError | ClassNotFoundException ignored) {
isSpigot = false;
}
private ExpansionCloudManager expansionCloud;
VERSION = new Version(version, isSpigot);
}
private static SimpleDateFormat dateFormat;
@NotNull
private final PlaceholderAPIConfig config = new PlaceholderAPIConfig(this);
private static String booleanTrue;
@NotNull
private final LocalExpansionManager localExpansionManager = new LocalExpansionManager(this);
@NotNull
private final CloudExpansionManager cloudExpansionManager = new CloudExpansionManager(this);
private static String booleanFalse;
private BukkitAudiences adventure;
private static Version serverVersion;
/**
* Gets the static instance of the main class for PlaceholderAPI. This class is not the actual API
* class, this is the main class that extends JavaPlugin. For most API methods, use static methods
* available from the class: {@link PlaceholderAPI}
*
* @return PlaceholderAPIPlugin instance
*/
@NotNull
public static PlaceholderAPIPlugin getInstance() {
return instance;
}
private long startTime;
/**
* Get the configurable {@linkplain String} value that should be returned when a boolean is true
*
* @return string value of true
*/
@NotNull
public static String booleanTrue() {
return getInstance().getPlaceholderAPIConfig().booleanTrue();
}
@Override
public void onLoad() {
startTime = System.currentTimeMillis();
instance = this;
serverVersion = getVersion();
config = new PlaceholderAPIConfig(this);
expansionManager = new ExpansionManager(this);
}
/**
* Get the configurable {@linkplain String} value that should be returned when a boolean is false
*
* @return string value of false
*/
@NotNull
public static String booleanFalse() {
return getInstance().getPlaceholderAPIConfig().booleanFalse();
}
@Override
public void onEnable() {
config.loadDefConfig();
setupOptions();
setupCommands();
new PlaceholderListener(this);
getLogger().info("Placeholder expansion registration initializing...");
expansionManager.registerAllExpansions();
if (config.checkUpdates()) {
new UpdateChecker(this);
}
if (config.isCloudEnabled()) {
enableCloud();
}
setupMetrics();
}
/**
* Get the configurable {@linkplain SimpleDateFormat} object that is used to parse time for
* generic time based placeholders
*
* @return date format
*/
@NotNull
public static SimpleDateFormat getDateFormat() {
try {
return new SimpleDateFormat(getInstance().getPlaceholderAPIConfig().dateFormat());
} catch (final IllegalArgumentException ex) {
Msg.warn("Configured date format ('%s') is invalid! Defaulting to 'MM/dd/yy HH:mm:ss'",
ex, getInstance().getPlaceholderAPIConfig().dateFormat());
return new SimpleDateFormat("MM/dd/yy HH:mm:ss");
}
}
@Override
public void onDisable() {
disableCloud();
PlaceholderAPI.unregisterAll();
expansionManager.clean();
expansionManager = null;
Bukkit.getScheduler().cancelTasks(this);
serverVersion = null;
instance = null;
}
@Deprecated
public static Version getServerVersion() {
return VERSION;
}
public void reloadConf(CommandSender s) {
boolean cloudEnabled = this.expansionCloud != null;
expansionManager.clean();
PlaceholderAPI.unregisterAllProvidedExpansions();
reloadConfig();
setupOptions();
expansionManager.registerAllExpansions();
if (!config.isCloudEnabled()) {
disableCloud();
} else if (!cloudEnabled) {
enableCloud();
}
s.sendMessage(ChatColor.translateAlternateColorCodes('&', PlaceholderAPI.getRegisteredIdentifiers().size() + " &aplaceholder hooks successfully registered!"));
}
@Override
public void onLoad() {
instance = this;
private void setupCommands() {
getCommand("placeholderapi").setExecutor(new PlaceholderAPICommands(this, (serverVersion != null && serverVersion.isSpigot())));
}
saveDefaultConfig();
}
private void setupOptions() {
booleanTrue = config.booleanTrue();
if (booleanTrue == null) {
booleanTrue = "true";
}
booleanFalse = config.booleanFalse();
if (booleanFalse == null) {
booleanFalse = "false";
}
try {
dateFormat = new SimpleDateFormat(config.dateFormat());
} catch (Exception e) {
dateFormat = new SimpleDateFormat("MM/dd/yy HH:mm:ss");
}
}
@Override
public void onEnable() {
setupCommand();
setupMetrics();
setupExpansions();
private void setupMetrics() {
Metrics m = new Metrics(this);
m.addCustomChart(new Metrics.SimplePie("using_expansion_cloud", () -> getExpansionCloud() != null ? "yes" : "no"));
m.addCustomChart(new Metrics.SimplePie("using_spigot", () -> getServerVersion().isSpigot() ? "yes" : "no"));
adventure = BukkitAudiences.create(this);
m.addCustomChart(new Metrics.AdvancedPie("expansions_used", () -> {
Map<String, Integer> map = new HashMap<>();
Map<String, PlaceholderHook> p = PlaceholderAPI.getPlaceholders();
if (config.isCloudEnabled()) {
getCloudExpansionManager().load();
}
if (!p.isEmpty()) {
if (config.checkUpdates()) {
new UpdateChecker(this).fetch();
}
}
for (PlaceholderHook hook : p.values()) {
if (hook instanceof PlaceholderExpansion) {
PlaceholderExpansion ex = (PlaceholderExpansion) hook;
map.put(ex.getPlugin() == null ? ex.getIdentifier()
: ex.getPlugin(), 1);
}
}
}
return map;
@Override
public void onDisable() {
getCloudExpansionManager().kill();
getLocalExpansionManager().kill();
}));
HandlerList.unregisterAll(this);
}
Bukkit.getScheduler().cancelTasks(this);
private static Version getVersion() {
String v = "unknown";
boolean spigot = false;
try {
v = Bukkit.getServer().getClass().getPackage().getName()
.split("\\.")[3];
} catch (ArrayIndexOutOfBoundsException ex) {
}
try {
Class.forName("org.spigotmc.SpigotConfig");
Class.forName("net.md_5.bungee.api.chat.BaseComponent");
spigot = true;
} catch (ExceptionInInitializerError | ClassNotFoundException exception) {
}
return new Version(v, spigot);
}
adventure.close();
adventure = null;
public void enableCloud() {
if (expansionCloud == null) {
expansionCloud = new ExpansionCloudManager(this);
expansionCloud.fetch();
} else {
expansionCloud.clean();
expansionCloud.fetch();
}
}
instance = null;
}
public void disableCloud() {
if (expansionCloud != null) {
expansionCloud.clean();
expansionCloud = null;
}
}
public void reloadConf(@NotNull final CommandSender sender) {
getLocalExpansionManager().kill();
/**
* Gets the static instance of the main class for PlaceholderAPI. This class
* is not the actual API class, this is the main class that extends
* JavaPlugin. For most API methods, use static methods available from the
* class: {@link PlaceholderAPI}
*
* @return PlaceholderAPIPlugin instance
*/
public static PlaceholderAPIPlugin getInstance() {
return instance;
}
reloadConfig();
/**
* Get the configurable {@linkplain SimpleDateFormat} object that is used to
* parse time for generic time based placeholders
*
* @return date format
*/
public static SimpleDateFormat getDateFormat() {
return dateFormat != null ? dateFormat : new SimpleDateFormat(
"MM/dd/yy HH:mm:ss");
}
getLocalExpansionManager().load(sender);
/**
* Get the configurable {@linkplain String} value that should be returned
* when a boolean is true
*
* @return string value of true
*/
public static String booleanTrue() {
return booleanTrue != null ? booleanTrue : "true";
}
if (config.isCloudEnabled()) {
getCloudExpansionManager().load();
} else {
getCloudExpansionManager().kill();
}
}
/**
* Get the configurable {@linkplain String} value that should be returned
* when a boolean is false
*
* @return string value of false
*/
public static String booleanFalse() {
return booleanFalse != null ? booleanFalse : "false";
}
@NotNull
public LocalExpansionManager getLocalExpansionManager() {
return localExpansionManager;
}
public static Version getServerVersion() {
return serverVersion != null ? serverVersion : getVersion();
}
@NotNull
public CloudExpansionManager getCloudExpansionManager() {
return cloudExpansionManager;
}
/**
* Obtain the configuration class for PlaceholderAPI.
*
* @return PlaceholderAPIConfig instance
*/
public PlaceholderAPIConfig getPlaceholderAPIConfig() {
return config;
}
@NotNull
public BukkitAudiences getAdventure() {
if(adventure == null) {
throw new IllegalStateException("Tried to access Adventure when the plugin was disabled!");
}
public ExpansionManager getExpansionManager() {
return expansionManager;
}
return adventure;
}
public ExpansionCloudManager getExpansionCloud() {
return expansionCloud;
}
/**
* Obtain the configuration class for PlaceholderAPI.
*
* @return PlaceholderAPIConfig instance
*/
@NotNull
public PlaceholderAPIConfig getPlaceholderAPIConfig() {
return config;
}
public String getUptime() {
return TimeUtil.getTime((int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - startTime));
}
private void setupCommand() {
final PluginCommand pluginCommand = getCommand("placeholderapi");
if (pluginCommand == null) {
return;
}
final PlaceholderCommandRouter router = new PlaceholderCommandRouter(this);
pluginCommand.setExecutor(router);
pluginCommand.setTabCompleter(router);
}
private void setupMetrics() {
final Metrics metrics = new Metrics(this, 438);
metrics.addCustomChart(new SimplePie("using_expansion_cloud",
() -> getPlaceholderAPIConfig().isCloudEnabled() ? "yes" : "no"));
metrics.addCustomChart(new SimplePie("using_spigot", () -> getServerVersion().isSpigot() ? "yes" : "no"));
metrics.addCustomChart(new AdvancedPie("expansions_used", () -> {
final Map<String, Integer> values = new HashMap<>();
for (final PlaceholderExpansion expansion : getLocalExpansionManager().getExpansions()) {
values.put(expansion.getRequiredPlugin() == null ? expansion.getIdentifier()
: expansion.getRequiredPlugin(), 1);
}
return values;
}));
}
private void setupExpansions() {
Bukkit.getPluginManager().registerEvents(getLocalExpansionManager(), this);
try {
Class.forName("org.bukkit.event.server.ServerLoadEvent");
new ServerLoadEventListener(this);
} catch (final ClassNotFoundException ignored) {
Bukkit.getScheduler()
.runTaskLater(this, () -> getLocalExpansionManager().load(Bukkit.getConsoleSender()), 1);
}
}
public long getUptimeMillis() {
return (System.currentTimeMillis() - startTime);
}
}

View File

@ -1,34 +1,42 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class PlaceholderHook {
@Nullable
public String onRequest(final OfflinePlayer player, @NotNull final String params) {
if (player != null && player.isOnline()) {
return onPlaceholderRequest(player.getPlayer(), params);
}
/**
* called when a placeholder is requested from this PlaceholderHook
* @param p Player requesting the placeholder value for, null if not needed for a player
* @param params String passed for the placeholder hook to determine what value to return
* @return value for the requested player and params
*/
public abstract String onPlaceholderRequest(Player p, String params);
return onPlaceholderRequest(null, params);
}
@Nullable
public String onPlaceholderRequest(final Player player, @NotNull final String params) {
return null;
}
}

View File

@ -1,153 +0,0 @@
/*
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
*
* 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/>.
*
*
*/
package me.clip.placeholderapi;
import me.clip.placeholderapi.events.ExpansionUnregisterEvent;
import me.clip.placeholderapi.events.PlaceholderHookUnloadEvent;
import me.clip.placeholderapi.expansion.*;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.external.EZPlaceholderHook;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.PluginEnableEvent;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class PlaceholderListener implements Listener {
private PlaceholderAPIPlugin plugin;
public PlaceholderListener(PlaceholderAPIPlugin instance) {
plugin = instance;
Bukkit.getPluginManager().registerEvents(this, instance);
}
@EventHandler
public void onExpansionUnregister(ExpansionUnregisterEvent event) {
if (event.getExpansion() instanceof Listener) {
HandlerList.unregisterAll((Listener)event.getExpansion());
}
if (event.getExpansion() instanceof Taskable) {
((Taskable) event.getExpansion()).stop();
}
if (event.getExpansion() instanceof Cacheable) {
((Cacheable) event.getExpansion()).clear();
}
if (plugin.getExpansionCloud() != null) {
CloudExpansion ex = plugin.getExpansionCloud().getCloudExpansion(event.getExpansion().getName());
if (ex != null) {
ex.setHasExpansion(false);
ex.setShouldUpdate(false);
}
}
}
@EventHandler
public void onEnable(PluginEnableEvent event) {
ExpansionManager m = plugin.getExpansionManager();
PlaceholderExpansion e = m.getCachedExpansion(event.getPlugin().getName().toLowerCase());
if (e != null && e.canRegister()) {
if (e.isRegistered() || m.registerExpansion(e)) {
m.removeCachedExpansion(e.getPlugin());
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onPluginUnload(PluginDisableEvent e) {
String n = e.getPlugin().getName();
if (n == null) {
return;
}
if (n.equals(plugin.getName())) {
return;
}
Map<String, PlaceholderHook> hooks = PlaceholderAPI.getPlaceholders();
for (Entry<String, PlaceholderHook> hook : hooks.entrySet()) {
PlaceholderHook i = hook.getValue();
if (i instanceof EZPlaceholderHook) {
EZPlaceholderHook h = (EZPlaceholderHook) i;
if (h.getPluginName() == null) {
continue;
}
if (h.getPluginName().equalsIgnoreCase(n)) {
if (PlaceholderAPI.unregisterPlaceholderHook(hook.getKey())) {
plugin.getLogger().info("Unregistered placeholder hook for placeholder: " + h.getPlaceholderName());
break;
}
}
} else if (i instanceof PlaceholderExpansion) {
PlaceholderExpansion ex = (PlaceholderExpansion) i;
if (ex.getPlugin() == null) {
continue;
}
if (ex.getPlugin().equalsIgnoreCase(n)) {
if (PlaceholderAPI.unregisterExpansion(ex)) {
plugin.getLogger().info("Unregistered placeholder expansion: " + ex.getIdentifier());
}
}
}
}
}
@EventHandler
public void onQuit(PlayerQuitEvent e) {
Set<PlaceholderExpansion> expansions = PlaceholderAPI.getExpansions();
if (expansions.isEmpty()) {
return;
}
for (PlaceholderExpansion ex : expansions) {
if (ex instanceof Cleanable) {
((Cleanable) ex).cleanup(e.getPlayer());
}
}
}
}

View File

@ -1,278 +0,0 @@
/*
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
*
* 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/>.
*
*
*/
package me.clip.placeholderapi.commands;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.spigot.ExpansionCloudCommands;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.util.Msg;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Set;
public class PlaceholderAPICommands implements CommandExecutor {
private PlaceholderAPIPlugin plugin;
private CommandExecutor eCloud;
public PlaceholderAPICommands(PlaceholderAPIPlugin i, boolean spigot) {
plugin = i;
if (spigot) {
eCloud = new me.clip.placeholderapi.commands.spigot.ExpansionCloudCommands(i);
} else {
eCloud = new me.clip.placeholderapi.commands.bukkit.ExpansionCloudCommands(i);
}
}
@Override
public boolean onCommand(CommandSender s, Command c, String label, String[] args) {
if (args.length == 0) {
Msg.msg(s, "PlaceholderAPI &7version &b&o" + plugin.getDescription().getVersion(),
"&fCreated by&7: &bextended_clip");
return true;
} else {
if (args[0].equalsIgnoreCase("help")) {
Msg.msg(s, "PlaceholderAPI &aHelp &e(&f" + plugin.getDescription().getVersion() + "&e)",
"&b/papi",
"&fView plugin info/version info",
"&b/papi list",
"&fList all placeholder expansions that are currently active",
"&b/papi info <placeholder name>",
"&fView information for a specific expansion",
"&b/papi parse <...args>",
"&fParse a String with placeholders",
"&b/papi parserel <player one> <player two> <...args>",
"&fParse a String with relational placeholders",
"&b/papi reload",
"&fReload the config settings");
if (s.isOp()) {
if (plugin.getExpansionCloud() == null) {
Msg.msg(s, "&b/papi enablecloud",
"&fEnable the expansion cloud");
} else {
Msg.msg(s, "&b/papi disablecloud",
"&fDisable the expansion cloud",
"&b/papi ecloud",
"&fView information about the PlaceholderAPI expansion cloud",
"&b/papi ecloud status",
"&fView status of the PlaceholderAPI expansion cloud",
"&b/papi ecloud list <all/author> <page>",
"&fList all available expansions",
"&b/papi ecloud info <expansion name>",
"&fView information about a specific expansion on the cloud",
"&b/papi ecloud download <expansion name>",
"&fDownload a specific expansion from the cloud");
}
}
return true;
} else if (args[0].equalsIgnoreCase("ecloud")) {
if (!s.isOp()) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
if (plugin.getExpansionCloud() == null) {
Msg.msg(s, "&7The expansion cloud is not enabled!");
return true;
}
return eCloud.onCommand(s, c, label, args);
} else if (args[0].equalsIgnoreCase("enablecloud")) {
if (!s.isOp()) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
if (plugin.getExpansionCloud() != null) {
Msg.msg(s, "&7The cloud is already enabled!");
return true;
}
plugin.enableCloud();
plugin.getPlaceholderAPIConfig().setCloudEnabled(true);
Msg.msg(s, "&aThe cloud has been enabled!");
return true;
} else if (args[0].equalsIgnoreCase("disablecloud")) {
if (!s.isOp()) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
if (plugin.getExpansionCloud() == null) {
Msg.msg(s, "&7The cloud is already disabled!");
return true;
}
plugin.disableCloud();
plugin.getPlaceholderAPIConfig().setCloudEnabled(false);
Msg.msg(s, "&aThe cloud has been disabled!");
return true;
} else if (args.length > 1 && args[0].equalsIgnoreCase("info")) {
if (!s.hasPermission("placeholderapi.info")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
PlaceholderExpansion ex = plugin.getExpansionManager().getRegisteredExpansion(args[1]);
if (ex == null) {
Msg.msg(s, "&cThere is no expansion loaded with the identifier: &f" + args[1]);
return true;
}
Msg.msg(s, "&7Placeholder expansion info for: &f%" + ex.getIdentifier() + "_<identifier>%");
Msg.msg(s, "&7Status: " + (ex.isRegistered() ? "&aRegistered" : "&cNot registered"));
if (ex.getAuthor() != null) {
Msg.msg(s, "&7Created by: &f" + ex.getAuthor());
}
if (ex.getVersion() != null) {
Msg.msg(s, "&7Version: &f" + ex.getVersion());
}
if (ex.getDescription() != null) {
Msg.msg(s, ex.getDescription());
}
if (ex.getLink() != null) {
Msg.msg(s, "&7Link: &f" + ex.getLink());
}
if (ex.getPlugin() != null) {
Msg.msg(s, "&7Requires plugin: &f" + ex.getPlugin());
}
if (ex.getPlaceholders() != null) {
Msg.msg(s, "&8&m-- &r&7Placeholders &8&m--");
for (String placeholder : ex.getPlaceholders()) {
Msg.msg(s, placeholder);
}
}
return true;
} else if (args.length > 1 && args[0].equalsIgnoreCase("parse")) {
if (!(s instanceof Player)) {
Msg.msg(s, "&cThis command can only be used in game!");
return true;
} else {
if (!s.hasPermission("placeholderapi.parse")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
}
Player p = (Player) s;
String parse = StringUtils.join(args, " ", 1, args.length);
Msg.msg(s, "&r" + PlaceholderAPI.setPlaceholders(p, parse));
return true;
} else if (args.length > 3 && args[0].equalsIgnoreCase("parserel")) {
if (!(s instanceof Player)) {
Msg.msg(s, "&cThis command can only be used in game!");
return true;
} else {
if (!s.hasPermission("placeholderapi.parse")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
}
Player one = Bukkit.getPlayer(args[1]);
if (one == null) {
Msg.msg(s, args[1] + " &cis not online!");
return true;
}
Player two = Bukkit.getPlayer(args[2]);
if (two == null) {
Msg.msg(s, args[2] + " &cis not online!");
return true;
}
String parse = StringUtils.join(args, " ", 3, args.length);
Msg.msg(s, "&r" + PlaceholderAPI.setRelationalPlaceholders(one, two, parse));
return true;
} else if (args[0].equalsIgnoreCase("reload")) {
if (s instanceof Player) {
if (!s.hasPermission("placeholderapi.reload")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
}
Msg.msg(s, "&fPlaceholder&7API &bconfiguration reloaded!");
plugin.reloadConf(s);
} else if (args[0].equalsIgnoreCase("list")) {
if (s instanceof Player) {
if (!s.hasPermission("placeholderapi.list")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
}
Set<String> registered = PlaceholderAPI.getRegisteredIdentifiers();
if (registered.isEmpty()) {
Msg.msg(s, "&7There are no placeholder hooks currently registered!");
return true;
}
Msg.msg(s, registered.size()+" &7Placeholder hooks registered:");
Msg.msg(s, registered.toString());
} else {
Msg.msg(s, "&cIncorrect usage! &7/papi help");
}
}
return true;
}
}

View File

@ -0,0 +1,108 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Stream;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import org.bukkit.command.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;
@Nullable
private String permission;
protected PlaceholderCommand(@NotNull final String label, @NotNull final String... alias) {
this.label = label;
this.alias = Sets.newHashSet(alias);
setPermission("placeholderapi." + label);
}
@NotNull
public static Stream<PlaceholderCommand> filterByPermission(@NotNull final CommandSender sender,
@NotNull final Stream<PlaceholderCommand> commands) {
return commands.filter(
target -> target.getPermission() == null || sender.hasPermission(target.getPermission()));
}
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 ImmutableSet.copyOf(alias);
}
@NotNull
@Unmodifiable
public final Set<String> getLabels() {
return ImmutableSet.<String>builder().add(label).addAll(alias).build();
}
@Nullable
public final String getPermission() {
return permission;
}
public void setPermission(@NotNull final String permission) {
this.permission = permission;
}
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

@ -0,0 +1,143 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Stream;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.impl.cloud.CommandECloud;
import me.clip.placeholderapi.commands.impl.local.CommandDump;
import me.clip.placeholderapi.commands.impl.local.CommandExpansionRegister;
import me.clip.placeholderapi.commands.impl.local.CommandExpansionUnregister;
import me.clip.placeholderapi.commands.impl.local.CommandHelp;
import me.clip.placeholderapi.commands.impl.local.CommandInfo;
import me.clip.placeholderapi.commands.impl.local.CommandList;
import me.clip.placeholderapi.commands.impl.local.CommandParse;
import me.clip.placeholderapi.commands.impl.local.CommandReload;
import me.clip.placeholderapi.commands.impl.local.CommandVersion;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class PlaceholderCommandRouter implements CommandExecutor, TabCompleter {
@Unmodifiable
private static final List<PlaceholderCommand> COMMANDS = ImmutableList.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;
public PlaceholderCommandRouter(@NotNull final PlaceholderAPIPlugin plugin) {
this.plugin = plugin;
final ImmutableMap.Builder<String, PlaceholderCommand> commands = ImmutableMap.builder();
for (final PlaceholderCommand command : COMMANDS) {
command.getLabels().forEach(label -> commands.put(label, command));
}
this.commands = commands.build();
}
@Override
public boolean onCommand(@NotNull final CommandSender sender, @NotNull final Command command,
@NotNull final String alias, @NotNull final String[] args) {
if (args.length == 0) {
final PlaceholderCommand fallback = commands.get("version");
if (fallback != null) {
fallback.evaluate(plugin, sender, "", Collections.emptyList());
}
return true;
}
final String search = args[0].toLowerCase(Locale.ROOT);
final PlaceholderCommand target = commands.get(search);
if (target == null) {
Msg.msg(sender, "&cUnknown command &7" + search);
return true;
}
final String permission = target.getPermission();
if (permission != null && !permission.isEmpty() && !sender.hasPermission(permission)) {
Msg.msg(sender, "&cYou do not have permission to do this!");
return true;
}
target
.evaluate(plugin, sender, search, Arrays.asList(Arrays.copyOfRange(args, 1, args.length)));
return true;
}
@Override
public List<String> onTabComplete(@NotNull final CommandSender sender,
@NotNull final Command command, @NotNull final String alias, @NotNull final String[] args) {
final List<String> suggestions = new ArrayList<>();
if (args.length > 1) {
final PlaceholderCommand target = this.commands.get(args[0].toLowerCase(Locale.ROOT));
if (target != null) {
target.complete(plugin, sender, args[0].toLowerCase(Locale.ROOT),
Arrays.asList(Arrays.copyOfRange(args, 1, args.length)), suggestions);
}
return suggestions;
}
final Stream<String> targets = PlaceholderCommand
.filterByPermission(sender, commands.values().stream()).map(PlaceholderCommand::getLabels)
.flatMap(Collection::stream);
PlaceholderCommand.suggestByParameter(targets, suggestions, args.length == 0 ? null : args[0]);
return suggestions;
}
}

View File

@ -1,232 +0,0 @@
/*
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
*
* 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/>.
*
*
*/
package me.clip.placeholderapi.commands.bukkit;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Map;
import java.util.Map.Entry;
public class ExpansionCloudCommands implements CommandExecutor {
private PlaceholderAPIPlugin plugin;
public ExpansionCloudCommands(PlaceholderAPIPlugin instance) {
plugin = instance;
}
@Override
public boolean onCommand(CommandSender s, Command c, String label, String[] args) {
if (args.length == 1) {
Msg.msg(s, "&bExpansion cloud commands",
" ",
"&b/papi ecloud status",
"&fView status of the cloud",
"&b/papi ecloud list <all/author> (page)",
"&fList all/author specific available expansions",
"&b/papi ecloud info <expansion name>",
"&fView information about a specific expansion available on the cloud",
"&b/papi ecloud download <expansion name>",
"&fDownload a specific expansion from the cloud",
"&b/papi ecloud refresh",
"&fFetch the most up to date list of expansions available.",
"&b/papi ecloud clear",
"&fClear the expansion cloud cache.");
return true;
}
if (args[1].equalsIgnoreCase("refresh")) {
Msg.msg(s, "&aRefresh task started. Use &7/papi ecloud list all &fin a few!!");
plugin.getExpansionCloud().clean();
plugin.getExpansionCloud().fetch();
return true;
}
if (plugin.getExpansionCloud().getCloudExpansions().isEmpty()) {
Msg.msg(s, "&7No cloud expansions are available at this time.");
return true;
}
if (args[1].equalsIgnoreCase("clear")) {
plugin.getExpansionCloud().clean();
Msg.msg(s, "&aThe cloud cache has been cleared!!");
return true;
}
if (args[1].equalsIgnoreCase("download")) {
if (args.length < 3) {
Msg.msg(s, "&cAn expansion name must be specified!");
return true;
}
CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(args[2]);
if (expansion == null) {
Msg.msg(s, "&cNo expansion found with the name: &f" + args[2]);
return true;
}
PlaceholderExpansion loaded = plugin.getExpansionManager().getRegisteredExpansion(args[2]);
if (loaded != null && loaded.isRegistered()) {
PlaceholderAPI.unregisterPlaceholderHook(loaded.getIdentifier());
}
Msg.msg(s, "&aAttempting download of expansion &f" + expansion.getName());
String player = ((s instanceof Player) ? s.getName() : null);
plugin.getExpansionCloud().downloadExpansion(player, expansion);
return true;
}
if (args[1].equalsIgnoreCase("status")) {
Msg.msg(s, "&bThere are &f" + plugin.getExpansionCloud().getCloudExpansions().size() + " &bcloud expansions available to download",
"&bA total of &f" + plugin.getExpansionCloud().getCloudAuthorCount() + " &bauthors have contributed.");
return true;
} else if (args[1].equalsIgnoreCase("info")) {
if (args.length < 3) {
Msg.msg(s, "&cAn expansion name must be specified!");
return true;
}
CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(args[2]);
if (expansion == null) {
Msg.msg(s, "&cNo expansion found with the name: &f" + args[2]);
return true;
}
PlaceholderExpansion exp = plugin.getExpansionManager().getRegisteredExpansion(args[2]);
boolean enabled = false;
String version = null;
if (exp != null) {
enabled = exp.isRegistered();
version = exp.getVersion();
}
Msg.msg(s, "&aExpansion: &f" + expansion.getName());
if (enabled) {
Msg.msg(s, "&aThis expansion is currently enabled!",
"&bYour version&7: &f" + version);
}
Msg.msg(s, "&bCloud version&7: &f" + expansion.getVersion(),
"&bAuthor&7: &f" + expansion.getAuthor());
String desc = expansion.getVersion();
if (desc.indexOf("\n") > 0) {
for (String line : desc.split("\n")) {
Msg.msg(s, line);
}
} else {
Msg.msg(s, desc);
}
Msg.msg(s, "&bDownload with &7/papi ecloud download " + expansion.getName());
return true;
} else if (args[1].equalsIgnoreCase("list")) {
int page = 1;
String author;
if (args.length < 3) {
Msg.msg(s, "&cIncorrect usage! &7/papi ecloud list <all/author> (page)");
return true;
}
author = args[2];
if (author.equalsIgnoreCase("all")) {
author = null;
}
if (args.length >= 4) {
try {
page = Integer.parseInt(args[3]);
} catch (NumberFormatException ex) {
Msg.msg(s, "&cPage number must be an integer!");
return true;
}
}
if (page < 1) {
Msg.msg(s, "&cPage must be greater than or equal to 1!");
return true;
}
int avail;
Map<Integer, CloudExpansion> ex;
if (author == null) {
ex = plugin.getExpansionCloud().getCloudExpansions();
} else {
ex = plugin.getExpansionCloud().getAllByAuthor(author);
}
if (ex == null) {
Msg.msg(s, "&cNo expansions available" + (author != null ? " for author &f" + author : ""));
return true;
}
avail = plugin.getExpansionCloud().getPagesAvailable(ex, 10);
if (page > avail) {
Msg.msg(s, "&cThere " + ((avail == 1) ? " is only &f" + avail + " &cpage available!" : "are only &f" + avail + " &cpages available!"));
return true;
}
Msg.msg(s, "&bExpansion cloud for &f" + (author != null ? author : "all available")+ " &8&m-- &r&bamount&7: &f" + ex.size() + " &bpage&7: &f" + page + "&7/&f" + avail);
ex = plugin.getExpansionCloud().getPage(ex, page, 10);
for (Entry<Integer, CloudExpansion> expansion : ex.entrySet()) {
Msg.msg(s, "&b" + (expansion.getKey()+1) + "&7: &f" + expansion.getValue().getName() + " &8&m-- &r" + expansion.getValue().getLink());
}
Msg.msg(s, "&bDownload an expansion with &7/papi ecloud download <name>",
"&bView more info on an expansion with &7/papi ecloud info <expansion>");
return true;
}
return true;
}
}

View File

@ -0,0 +1,146 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.cloud;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Stream;
public final class CommandECloud extends PlaceholderCommand {
@Unmodifiable
private static final List<PlaceholderCommand> COMMANDS = ImmutableList
.of(new CommandECloudClear(),
new CommandECloudStatus(),
new CommandECloudUpdate(),
new CommandECloudRefresh(),
new CommandECloudDownload(),
new CommandECloudExpansionInfo(),
new CommandECloudExpansionList(),
new CommandECloudExpansionPlaceholders());
static {
COMMANDS
.forEach(command -> command.setPermission("placeholderapi.ecloud." + command.getLabel()));
}
@NotNull
@Unmodifiable
private final Map<String, PlaceholderCommand> commands;
public CommandECloud() {
super("ecloud");
final ImmutableMap.Builder<String, PlaceholderCommand> commands = ImmutableMap.builder();
for (final PlaceholderCommand command : COMMANDS) {
command.getLabels().forEach(label -> commands.put(label, command));
}
this.commands = commands.build();
}
@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()) {
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) {
Msg.msg(sender, "&cUnknown command &7ecloud " + search);
return;
}
final String permission = target.getPermission();
if (permission != null && !permission.isEmpty() && !sender.hasPermission(permission)) {
Msg.msg(sender, "&cYou do not have permission to do this!");
return;
}
if (!plugin.getPlaceholderAPIConfig().isCloudEnabled()) {
Msg.msg(sender, "&cThe eCloud Manager is not enabled! To enable it, set 'cloud_enabled' to true and reload the plugin.");
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

@ -0,0 +1,46 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.cloud;
import java.util.List;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandECloudClear extends PlaceholderCommand {
public CommandECloudClear() {
super("clear");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
plugin.getCloudExpansionManager().clean();
Msg.msg(sender,
"&aThe eCloud cache has been cleared!");
}
}

View File

@ -0,0 +1,139 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.cloud;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandECloudDownload extends PlaceholderCommand {
public CommandECloudDownload() {
super("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) {
if (params.isEmpty()) {
Msg.msg(sender,
"&cYou must supply the name of an expansion.");
return;
}
if (isBlockedExpansion(params.get(0))) {
Msg.msg(sender,
"&cThis expansion can't be downloaded.");
return;
}
final CloudExpansion expansion = plugin.getCloudExpansionManager()
.findCloudExpansionByName(params.get(0)).orElse(null);
if (expansion == null) {
Msg.msg(sender,
"&cFailed to find an expansion named: &f" + params.get(0));
return;
}
if (!expansion.isVerified()) {
Msg.msg(sender, "&cThe expansion '&f" + params.get(0) + "&c' is not verified and can only be downloaded manually from &fhttps://placeholderapi.com/ecloud");
return;
}
final CloudExpansion.Version version;
if (params.size() < 2) {
version = expansion.getVersion(expansion.getLatestVersion());
if (version == null) {
Msg.msg(sender,
"&cCould not find latest version for expansion.");
return;
}
} else {
version = expansion.getVersion(params.get(1));
if (version == null) {
Msg.msg(sender,
"&cCould not find specified version: &f" + params.get(1),
"&7Available versions: &f" + expansion.getAvailableVersions());
return;
}
}
plugin.getCloudExpansionManager().downloadExpansion(expansion, version)
.whenComplete((file, exception) -> {
if (exception != null) {
Msg.msg(sender,
"&cFailed to download expansion: &f" + exception.getMessage());
return;
}
Msg.msg(sender,
"&aSuccessfully downloaded expansion &f" + expansion.getName() + " [" + version
.getVersion() + "] &ato file: &f" + file.getName(),
"&aMake sure to type &f/papi reload &ato enable your new expansion!");
plugin.getCloudExpansionManager().load();
});
}
@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

@ -0,0 +1,129 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.cloud;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandECloudExpansionInfo extends PlaceholderCommand {
public CommandECloudExpansionInfo() {
super("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()) {
Msg.msg(sender,
"&cYou must specify the name of the expansion.");
return;
}
final CloudExpansion expansion = plugin.getCloudExpansionManager()
.findCloudExpansionByName(params.get(0)).orElse(null);
if (expansion == null) {
Msg.msg(sender,
"&cThere is no expansion with the name: &f" + params.get(0));
return;
}
final StringBuilder builder = new StringBuilder();
builder.append("&bExpansion: &f")
.append(expansion.shouldUpdate() ? "&e" : "&a")
.append(expansion.getName())
.append('\n')
.append("&bAuthor: &f")
.append(expansion.getAuthor())
.append('\n')
.append("&bVerified: ")
.append(expansion.isVerified() ? "&a&l✔" : "&c&l❌")
.append('\n');
if (params.size() < 2) {
builder.append("&bLatest Version: &f")
.append(expansion.getLatestVersion())
.append('\n')
.append("&bReleased: &f")
.append(expansion.getTimeSinceLastUpdate())
.append(" ago")
.append('\n')
.append("&bRelease Notes: &f")
.append(expansion.getVersion().getReleaseNotes())
.append('\n');
} else {
final CloudExpansion.Version version = expansion.getVersion(params.get(1));
if (version == null) {
Msg.msg(sender,
"&cCould not find specified version: &f" + params.get(1),
"&aVersions: &f" + expansion.getAvailableVersions());
return;
}
builder.append("&bVersion: &f")
.append(version.getVersion())
.append('\n')
.append("&bRelease Notes: &f")
.append(version.getReleaseNotes())
.append('\n')
.append("&bDownload URL: &f")
.append(version.getUrl())
.append('\n');
}
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() > 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

@ -0,0 +1,352 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.cloud;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.primitives.Ints;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.configuration.ExpansionSort;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.util.Format;
import me.clip.placeholderapi.util.Msg;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
import static net.kyori.adventure.text.Component.*;
import static net.kyori.adventure.text.format.NamedTextColor.*;
public final class CommandECloudExpansionList extends PlaceholderCommand {
private static final int PAGE_SIZE = 10;
@NotNull
private static final Function<CloudExpansion, Object> EXPANSION_NAME =
expansion -> (expansion.shouldUpdate() ? "&6" : expansion.hasExpansion() ? "&a" : "&7")
+ expansion.getName();
@NotNull
private static final Function<CloudExpansion, Object> EXPANSION_AUTHOR =
expansion -> "&f" + expansion.getAuthor();
@NotNull
private static final Function<CloudExpansion, Object> EXPANSION_VERIFIED =
expansion -> expansion.isVerified() ? "&aY" : "&cN";
@NotNull
private static final Function<CloudExpansion, Object> EXPANSION_LATEST_VERSION =
expansion -> "&f" + expansion.getLatestVersion();
@NotNull
private static final Function<CloudExpansion, Object> EXPANSION_CURRENT_VERSION =
expansion -> "&f" + PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()
.findExpansionByName(expansion.getName()).map(PlaceholderExpansion::getVersion)
.orElse("Unknown");
@Unmodifiable
private static final Set<String> OPTIONS = ImmutableSet.of("all", "installed");
public CommandECloudExpansionList() {
super("list");
}
@NotNull
private static Collection<CloudExpansion> getExpansions(@NotNull final String target,
@NotNull final PlaceholderAPIPlugin plugin) {
switch (target.toLowerCase(Locale.ROOT)) {
case "all":
return plugin.getCloudExpansionManager().getCloudExpansions().values();
case "installed":
return plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values();
default:
return plugin.getCloudExpansionManager().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 void addExpansionTitle(@NotNull final StringBuilder builder,
@NotNull final String target, final int page) {
switch (target.toLowerCase(Locale.ROOT)) {
case "all":
builder.append("&bAll Expansions");
break;
case "installed":
builder.append("&bInstalled Expansions");
break;
default:
builder.append("&bExpansions by &f")
.append(target);
break;
}
if (page == -1) {
builder.append('\n');
return;
}
builder.append(" &bPage&7: &a")
.append(page)
.append("&r");
}
private static Component getMessage(@NotNull final List<CloudExpansion> expansions,
final int page, final int limit, @NotNull final String target) {
final SimpleDateFormat format = PlaceholderAPIPlugin.getDateFormat();
final TextComponent.Builder message = text();
for (int index = 0; index < expansions.size(); index++) {
final CloudExpansion expansion = expansions.get(index);
final TextComponent.Builder line = text();
final int expansionNumber = index + ((page - 1) * PAGE_SIZE) + 1;
line.append(text(expansionNumber + ". ", DARK_GRAY));
final NamedTextColor expansionColour;
if (expansion.shouldUpdate()) {
expansionColour = GOLD;
} else {
if (expansion.hasExpansion()) {
expansionColour = GREEN;
} else {
expansionColour = GRAY;
}
}
line.append(text(expansion.getName(), expansionColour));
line.clickEvent(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.isVerified() ? "" : "", expansion.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.append(newline());
}
message.append(line.build());
}
if (limit > 1) {
message.append(newline());
final TextComponent.Builder left = text("", 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.append(left, text(" " + page + " ", GREEN), right);
}
return message.build();
}
private static void addExpansionTable(@NotNull final List<CloudExpansion> expansions,
@NotNull final StringBuilder message, final int startIndex,
@NotNull final String versionTitle,
@NotNull final Function<CloudExpansion, Object> versionFunction) {
final Map<String, Function<CloudExpansion, Object>> functions = new LinkedHashMap<>();
final AtomicInteger counter = new AtomicInteger(startIndex);
functions.put("&f", expansion -> "&8" + counter.getAndIncrement() + ".");
functions.put("&9Name", EXPANSION_NAME);
functions.put("&9Author", EXPANSION_AUTHOR);
functions.put("&9Verified", EXPANSION_VERIFIED);
functions.put(versionTitle, versionFunction);
final List<List<String>> rows = new ArrayList<>();
rows.add(0, new ArrayList<>(functions.keySet()));
for (final CloudExpansion expansion : expansions) {
rows.add(functions.values().stream().map(function -> function.apply(expansion))
.map(Objects::toString).collect(Collectors.toList()));
}
final List<String> table = Format.tablify(Format.Align.LEFT, rows)
.orElse(Collections.emptyList());
if (table.isEmpty()) {
return;
}
table.add(1, "&8" + Strings.repeat("-", table.get(0).length() - (rows.get(0).size() * 2)));
message.append(String.join("\n", table));
}
@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()) {
Msg.msg(sender,
"&cYou must specify an option. [all, {author}, installed]");
return;
}
final boolean installed = params.get(0).equalsIgnoreCase("installed");
final List<CloudExpansion> expansions = Lists
.newArrayList(getExpansions(params.get(0), plugin));
if (expansions.isEmpty()) {
Msg.msg(sender,
"&cNo expansions available to list.");
return;
}
expansions
.sort(plugin.getPlaceholderAPIConfig().getExpansionSort().orElse(ExpansionSort.LATEST));
if (!(sender instanceof Player) && params.size() < 2) {
final StringBuilder builder = new StringBuilder();
addExpansionTitle(builder, params.get(0), -1);
addExpansionTable(expansions,
builder,
1,
installed ? "&9Version" : "&9Latest Version",
installed ? EXPANSION_CURRENT_VERSION : EXPANSION_LATEST_VERSION);
Msg.msg(sender, builder.toString());
return;
}
final int page;
if (params.size() < 2) {
page = 1;
} else {
//noinspection UnstableApiUsage
final Integer parsed = Ints.tryParse(params.get(1));
if (parsed == null) {
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) {
Msg.msg(sender,
"&cPage number must be in the range &8[&a1&7..&a" + limit + "&8]");
return;
}
page = parsed;
}
final StringBuilder builder = new StringBuilder();
final List<CloudExpansion> values = getPage(expansions, page - 1);
addExpansionTitle(builder, params.get(0), page);
if (!(sender instanceof Player)) {
addExpansionTable(values,
builder,
((page - 1) * PAGE_SIZE) + 1,
installed ? "&9Version" : "&9Latest Version",
installed ? EXPANSION_CURRENT_VERSION : EXPANSION_LATEST_VERSION);
Msg.msg(sender, builder.toString());
return;
}
Msg.msg(sender, builder.toString());
final int limit = (int) Math.ceil((double) expansions.size() / PAGE_SIZE);
final Component message = getMessage(values, page, limit, params.get(0));
plugin.getAdventure().player((Player) 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

@ -0,0 +1,94 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.cloud;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandECloudExpansionPlaceholders extends PlaceholderCommand {
public CommandECloudExpansionPlaceholders() {
super("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()) {
Msg.msg(sender,
"&cYou must specify the name of the expansion.");
return;
}
final CloudExpansion expansion = plugin.getCloudExpansionManager()
.findCloudExpansionByName(params.get(0)).orElse(null);
if (expansion == null) {
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()) {
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);
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

@ -0,0 +1,47 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.cloud;
import java.util.List;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandECloudRefresh extends PlaceholderCommand {
public CommandECloudRefresh() {
super("refresh");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
plugin.getCloudExpansionManager().load();
Msg.msg(sender,
"&aThe eCloud manager has been refreshed!");
}
}

View File

@ -0,0 +1,64 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.cloud;
import java.util.List;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.manager.CloudExpansionManager;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandECloudStatus extends PlaceholderCommand {
public CommandECloudStatus() {
super("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.getCloudExpansionManager();
final int updateCount = manager.getCloudUpdateCount();
final int authorCount = manager.getCloudExpansionAuthorCount();
final int expansionCount = manager.getCloudExpansions().size();
final StringBuilder builder = new StringBuilder();
builder.append("&bThere are &a").append(expansionCount)
.append("&b expansions available on the eCloud.").append('\n');
builder.append("&7A total of &f").append(authorCount)
.append("&7 authors have contributed to the eCloud.").append('\n');
if (updateCount > 0) {
builder.append("&eYou have &f").append(updateCount)
.append(updateCount > 1 ? "&e expansions" : "&e expansion").append(" installed that ")
.append(updateCount > 1 ? "have an" : "has an").append(" update available.");
}
Msg.msg(sender, builder.toString());
}
}

View File

@ -0,0 +1,141 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.cloud;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.util.Futures;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.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");
}
private static CompletableFuture<List<@Nullable Class<? extends PlaceholderExpansion>>> downloadAndDiscover(
@NotNull final List<CloudExpansion> expansions, @NotNull final PlaceholderAPIPlugin plugin) {
return expansions.stream()
.map(expansion -> plugin.getCloudExpansionManager()
.downloadExpansion(expansion, expansion.getVersion()))
.map(future -> future.thenCompose(plugin.getLocalExpansionManager()::findExpansionInFile))
.collect(Futures.collector());
}
@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()) {
Msg.msg(sender,
"&cYou must define 'all' or the name of an expansion to update.");
return;
}
final boolean multiple = params.get(0).equalsIgnoreCase("all");
final List<CloudExpansion> expansions = new ArrayList<>();
// gather target expansions
if (multiple) {
expansions.addAll(plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values());
} else {
plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0))
.ifPresent(expansions::add);
}
// remove the ones that are the latest version
expansions.removeIf(expansion -> !expansion.shouldUpdate());
if (expansions.isEmpty()) {
Msg.msg(sender,
"&cNo updates available for " + (!multiple ? "this expansion."
: "your active expansions."));
return;
}
Msg.msg(sender,
"&aUpdating expansions: " + expansions.stream().map(CloudExpansion::getName)
.collect(Collectors.joining("&7, &6", "&8[&6", "&8]&r")));
Futures.onMainThread(plugin, downloadAndDiscover(expansions, plugin), (classes, exception) -> {
if (exception != null) {
Msg.msg(sender,
"&cFailed to update expansions: &e" + exception.getMessage());
return;
}
Msg.msg(sender,
"&aSuccessfully downloaded updates, registering new versions.");
final String message = classes.stream()
.filter(Objects::nonNull)
.map(plugin.getLocalExpansionManager()::register)
.filter(Optional::isPresent)
.map(Optional::get)
.map(expansion -> " &a" + expansion.getName() + " &f" + expansion.getVersion())
.collect(Collectors.joining("\n"));
Msg.msg(sender,
"&7Registered expansions:", 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() > 1) {
return;
}
final List<CloudExpansion> installed = Lists
.newArrayList(plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values());
installed.removeIf(expansion -> !expansion.shouldUpdate());
if (!installed.isEmpty() && (params.isEmpty() || "all"
.startsWith(params.get(0).toLowerCase(Locale.ROOT)))) {
suggestions.add("all");
}
suggestByParameter(
installed.stream().map(CloudExpansion::getName).map(name -> name.replace(" ", "_")),
suggestions, params.isEmpty() ? null : params.get(0));
}
}

View File

@ -0,0 +1,213 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.local;
import com.google.common.io.CharStreams;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
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.Arrays;
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.logging.Level;
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");
}
@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().log(Level.WARNING, "failed to post dump details", exception);
Msg.msg(sender,
"&cFailed to post dump details, check console.");
return;
}
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 = CharStreams.toString(new InputStreamReader(stream, StandardCharsets.UTF_8));
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.getDescription().getVersion())
.append("\n\n");
builder.append("Expansions Registered:")
.append('\n');
final List<PlaceholderExpansion> expansions = plugin.getLocalExpansionManager()
.getExpansions()
.stream()
.sorted(
Comparator.comparing(PlaceholderExpansion::getIdentifier)
.thenComparing(PlaceholderExpansion::getAuthor)
)
.collect(Collectors.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.getLocalExpansionManager()
.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(plugin.getServer().getBukkitVersion())
.append('/')
.append(plugin.getServer().getVersion())
.append("\n");
builder.append("Java Version: ")
.append(System.getProperty("java.version"))
.append("\n\n");
builder.append("Plugin Info:")
.append('\n');
List<Plugin> plugins = Arrays.stream(plugin.getServer().getPluginManager().getPlugins())
.sorted(Comparator.comparing(Plugin::getName))
.collect(Collectors.toList());
size = plugins.stream().map(pl -> pl.getName().length())
.max(Integer::compareTo)
.orElse(0);
for (final Plugin other : plugins) {
builder.append(" ")
.append(String.format("%-" + size + "s", other.getName()))
.append(" [Authors: [")
.append(String.join(", ", other.getDescription().getAuthors()))
.append("], Version: ")
.append(other.getDescription().getVersion())
.append("]")
.append("\n");
}
return builder.toString();
}
}

View File

@ -0,0 +1,110 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.local;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.logging.Level;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.manager.LocalExpansionManager;
import me.clip.placeholderapi.util.Futures;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandExpansionRegister extends PlaceholderCommand {
public CommandExpansionRegister() {
super("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.size() < 1) {
Msg.msg(sender,
"&cYou must specify the name of an expansion file.");
return;
}
final LocalExpansionManager manager = plugin.getLocalExpansionManager();
final File file = new File(manager.getExpansionsFolder(), params.get(0));
if (!file.exists() || !file.getParentFile().equals(manager.getExpansionsFolder())) {
Msg.msg(sender,
"&cThe file &f" + file.getName() + "&c doesn't exist!");
return;
}
Futures.onMainThread(plugin, manager.findExpansionInFile(file), (clazz, exception) -> {
if (exception != null) {
Msg.msg(sender,
"&cFailed to find expansion in file: &f" + file);
plugin.getLogger()
.log(Level.WARNING, "failed to find expansion in file: " + file, exception);
return;
}
if (clazz == null) {
Msg.msg(sender,
"&cNo expansion class found in file: &f" + file);
return;
}
final Optional<PlaceholderExpansion> expansion = manager.register(clazz);
if (!expansion.isPresent()) {
Msg.msg(sender,
"&cFailed to register expansion from &f" + params.get(0));
return;
}
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

@ -0,0 +1,77 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.local;
import java.util.List;
import java.util.Optional;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandExpansionUnregister extends PlaceholderCommand {
public CommandExpansionUnregister() {
super("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()) {
Msg.msg(sender,
"&cYou must specify the name of the expansion.");
return;
}
final Optional<PlaceholderExpansion> expansion = plugin.getLocalExpansionManager()
.findExpansionByName(params.get(0));
if (!expansion.isPresent()) {
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";
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

@ -0,0 +1,72 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.local;
import java.util.List;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.PluginDescriptionFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandHelp extends PlaceholderCommand {
public CommandHelp() {
super("help");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
final PluginDescriptionFile description = plugin.getDescription();
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");
}
}

View File

@ -0,0 +1,113 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.local;
import java.util.List;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandInfo extends PlaceholderCommand {
public CommandInfo() {
super("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()) {
Msg.msg(sender,
"&cYou must specify the name of the expansion.");
return;
}
final PlaceholderExpansion expansion = plugin.getLocalExpansionManager()
.findExpansionByIdentifier(params.get(0)).orElse(null);
if (expansion == null) {
Msg.msg(sender,
"&cThere is no expansion loaded with the identifier: &f" + params.get(0));
return;
}
final StringBuilder builder = new StringBuilder();
builder.append("&7Placeholder expansion info for: &r")
.append(expansion.getName())
.append('\n')
.append("&7Status: &r")
.append(expansion.isRegistered() ? "&aRegistered" : "7cNotRegistered")
.append('\n');
final String author = expansion.getAuthor();
if (author != null) {
builder.append("&7Author: &r")
.append(author)
.append('\n');
}
final String version = expansion.getVersion();
if (version != null) {
builder.append("&7Version: &r")
.append(version)
.append('\n');
}
final String requiredPlugin = expansion.getRequiredPlugin();
if (requiredPlugin != null) {
builder.append("&7Requires plugin: &r")
.append(requiredPlugin)
.append('\n');
}
final List<String> placeholders = expansion.getPlaceholders();
if (placeholders != null && !placeholders.isEmpty()) {
builder.append("&8&m-- &7Placeholders &8&m--&r")
.append('\n');
for (final String placeholder : placeholders) {
builder.append(placeholder)
.append('\n');
}
}
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

@ -0,0 +1,61 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.local;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandList extends PlaceholderCommand {
public CommandList() {
super("list");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
final Set<String> identifiers = PlaceholderAPI.getRegisteredIdentifiers();
if (identifiers.isEmpty()) {
Msg.msg(sender, "&cThere are no placeholder hooks active!");
return;
}
final List<List<String>> partitions = Lists
.partition(identifiers.stream().sorted().collect(Collectors.toList()), 10);
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

@ -0,0 +1,256 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.local;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Stream;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
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");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
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;
}
}
@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) {
switch (alias.toLowerCase(Locale.ROOT)) {
case "parserel":
completeParseRelation(params, suggestions);
break;
case "parse":
case "bcparse":
case "cmdparse":
completeParseSingular(sender, params, suggestions);
break;
}
}
private void evaluateParseSingular(@NotNull final CommandSender sender,
@NotNull @Unmodifiable final List<String> params, final boolean broadcast,
final boolean command) {
if (params.size() < 2) {
Msg.msg(sender,
"&cYou must provide a target and message: &b/papi "
+ (command ? "cmdparse" : (broadcast ? "bcparse" : "parse"))
+ " &7{target} &a{message}");
return;
}
OfflinePlayer player;
if ("me".equalsIgnoreCase(params.get(0))) {
if (!(sender instanceof Player)) {
Msg.msg(sender, "&cYou must be a player to use &7me&c as a target!");
return;
}
player = ((Player) sender);
} else if ("--null".equalsIgnoreCase(params.get(0))) {
player = null;
} else {
final OfflinePlayer target = resolvePlayer(params.get(0));
if (target == null) {
Msg.msg(sender, "&cFailed to find player: &7" + params.get(0));
return;
}
player = target;
}
final String message = PlaceholderAPI
.setPlaceholders(player, String.join(" ", params.subList(1, params.size())));
if (command) {
Bukkit.dispatchCommand(sender, message);
return;
}
if (broadcast) {
Bukkit.broadcastMessage(message);
} else {
sender.sendMessage(message);
}
}
private void evaluateParseRelation(@NotNull final CommandSender sender,
@NotNull @Unmodifiable final List<String> params) {
if (params.size() < 3) {
Msg.msg(sender,
"&cYou must supply two targets, and a message: &b/papi parserel &7{target one} "
+ "{target two} &a{message}");
return;
}
OfflinePlayer playerOne;
if ("me".equalsIgnoreCase(params.get(0))) {
if (!(sender instanceof Player)) {
Msg.msg(sender, "&cYou must be a player to use &7me&c as a target!");
return;
}
playerOne = ((Player) sender);
} else {
playerOne = resolvePlayer(params.get(0));
}
if (playerOne == null || !playerOne.isOnline()) {
Msg.msg(sender, "&cFailed to find player: &f" + params.get(0));
return;
}
OfflinePlayer playerTwo;
if ("me".equalsIgnoreCase(params.get(1))) {
if (!(sender instanceof Player)) {
Msg.msg(sender, "&cYou must be a player to use &7me&c as a target!");
return;
}
playerTwo = ((Player) sender);
} else {
playerTwo = resolvePlayer(params.get(1));
}
if (playerTwo == null || !playerTwo.isOnline()) {
Msg.msg(sender, "&cFailed to find player: &f" + params.get(1));
return;
}
final String message = PlaceholderAPI
.setRelationalPlaceholders((Player) playerOne, (Player) playerTwo,
String.join(" ", params.subList(2, params.size())));
sender.sendMessage(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 = Bukkit.getOnlinePlayers().stream().map(Player::getName);
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.getInstance()
.getLocalExpansionManager().findExpansionByIdentifier(name.substring(1, index))
.orElse(null);
if (expansion == null) {
return;
}
final Set<String> possible = new HashSet<>(expansion.getPlaceholders());
PlaceholderAPIPlugin.getInstance()
.getCloudExpansionManager()
.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 OfflinePlayer resolvePlayer(@NotNull final String name) {
OfflinePlayer target = Bukkit.getPlayerExact(name);
if (target == null) {
// Not the best option, but Spigot doesn't offer a good replacement (as usual)
target = Bukkit.getOfflinePlayer(name);
return target.hasPlayedBefore() ? target : null;
}
return target;
}
}

View File

@ -0,0 +1,43 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.local;
import java.util.List;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandReload extends PlaceholderCommand {
public CommandReload() {
super("reload");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
plugin.reloadConf(sender);
}
}

View File

@ -0,0 +1,52 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.commands.impl.local;
import java.util.List;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.PluginDescriptionFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CommandVersion extends PlaceholderCommand {
public CommandVersion() {
super("version");
}
@Override
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
final PluginDescriptionFile description = plugin.getDescription();
Msg.msg(sender,
"&b&lPlaceholderAPI &7(&f" + description.getVersion() + "&7)",
"&7Author: &f" + description.getAuthors(),
"&7PAPI Commands: &b/papi &fhelp",
"&7eCloud Commands&8: &b/papi &fecloud");
}
}

View File

@ -1,319 +0,0 @@
/*
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
*
* 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/>.
*
*
*/
package me.clip.placeholderapi.commands.spigot;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.util.Msg;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Map;
import java.util.Map.Entry;
public class ExpansionCloudCommands implements CommandExecutor {
private PlaceholderAPIPlugin plugin;
public ExpansionCloudCommands(PlaceholderAPIPlugin instance) {
plugin = instance;
}
@Override
public boolean onCommand(CommandSender s, Command c, String label, String[] args) {
if (args.length == 1) {
Msg.msg(s, "&bExpansion cloud commands",
" ",
"&b/papi ecloud status",
"&fView status of the cloud",
"&b/papi ecloud list <all/author> (page)",
"&fList all/author specific available expansions",
"&b/papi ecloud info <expansion name>",
"&fView information about a specific expansion available on the cloud",
"&b/papi ecloud download <expansion name>",
"&fDownload a specific expansion from the cloud",
"&b/papi ecloud refresh",
"&fFetch the most up to date list of expansions available.",
"&b/papi ecloud clear",
"&fClear the expansion cloud cache.");
return true;
}
if (args[1].equalsIgnoreCase("refresh") || args[1].equalsIgnoreCase("update") || args[1].equalsIgnoreCase("fetch")) {
Msg.msg(s, "&aRefresh task started. Use &f/papi ecloud list all &ain a few!!");
plugin.getExpansionCloud().clean();
plugin.getExpansionCloud().fetch();
return true;
}
if (plugin.getExpansionCloud().getCloudExpansions().isEmpty()) {
Msg.msg(s, "&7No cloud expansions are available at this time.");
return true;
}
if (args[1].equalsIgnoreCase("clear")) {
plugin.getExpansionCloud().clean();
Msg.msg(s, "&aThe cloud cache has been cleared!!");
return true;
}
if (args[1].equalsIgnoreCase("status")) {
Msg.msg(s, "&bThere are &f" + plugin.getExpansionCloud().getCloudExpansions().size() + " &bexpansions available on the cloud.",
"&7A total of &f" + plugin.getExpansionCloud().getCloudAuthorCount() + " &7authors have contributed to the expansion cloud.");
if (plugin.getExpansionCloud().getToUpdateCount() > 0) {
Msg.msg(s, "&eYou have &f" + plugin.getExpansionCloud().getToUpdateCount()
+ " &eexpansions installed that have updates available.");
}
return true;
}
if (args[1].equalsIgnoreCase("info")) {
if (args.length < 3) {
Msg.msg(s, "&cAn expansion name must be specified!");
return true;
}
CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(args[2]);
if (expansion == null) {
Msg.msg(s, "&cNo expansion found with the name: &f" + args[2]);
return true;
}
if (!(s instanceof Player)) {
Msg.msg(s, (expansion.shouldUpdate() ? "&e" : "") + expansion.getName() + " &8&m-- &r" + expansion.getLink());
return true;
}
Player p = (Player) s;
Msg.msg(s, "&bCloud expansion info for&7:" + (expansion.shouldUpdate() ? "&6" : (expansion.hasExpansion() ? "&e" : "")) + expansion.getName());
StringBuilder sb = new StringBuilder();
sb.append(expansion.getDescription());
if (expansion.getReleaseNotes() != null) {
sb.append("\n\n" + expansion.getReleaseNotes());
}
String hover = ChatColor.translateAlternateColorCodes('&', sb.toString());
if (expansion.hasExpansion()) {
if (expansion.shouldUpdate()) {
Msg.msg(s, "&6You have this expansion but there is a newer version available.");
} else {
Msg.msg(s, "&aYou have the latest version of this expansion!");
}
} else {
Msg.msg(s, "&7You do not have this expansion installed");
}
sms(p, "&bAuthor&7: &f" + expansion.getAuthor(), hover, null);
sms(p, "&bVersion&7: &f" + expansion.getVersion(), hover, null);
if (expansion.getLastUpdate() > 1) {
sb.append("&bLast updated&7: &f" + expansion.getTimeSinceLastUpdate() + " ago");
}
sms(p, "&aClick here to download!", hover, expansion.getName());
return true;
}
if (args[1].equalsIgnoreCase("list")) {
int page = 1;
String author;
boolean installed = false;
if (args.length < 3) {
Msg.msg(s, "&cIncorrect usage! &7/papi ecloud list <all/author/installed> (page)");
return true;
}
author = args[2];
if (author.equalsIgnoreCase("all")) {
author = null;
} else if (author.equalsIgnoreCase("installed")) {
author = null;
installed = true;
}
if (args.length >= 4) {
try {
page = Integer.parseInt(args[3]);
} catch (NumberFormatException ex) {
Msg.msg(s, "&cPage number must be an integer!");
return true;
}
}
if (page < 1) {
Msg.msg(s, "&cPage must be greater than or equal to 1!");
return true;
}
int avail;
Map<Integer, CloudExpansion> ex;
if (installed) {
ex = plugin.getExpansionCloud().getAllInstalled();
} else if (author == null) {
ex = plugin.getExpansionCloud().getCloudExpansions();
} else {
ex = plugin.getExpansionCloud().getAllByAuthor(author);
}
if (ex == null || ex.isEmpty()) {
Msg.msg(s, "&cNo expansions available" + (author != null ? " for author &f" + author : ""));
return true;
}
avail = plugin.getExpansionCloud().getPagesAvailable(ex, 10);
if (page > avail) {
Msg.msg(s, "&cThere " + ((avail == 1) ? " is only &f" + avail + " &cpage available!" : "are only &f" + avail + " &cpages available!"));
return true;
}
Msg.msg(s, "&bShowing expansions for&7: &f" + (author != null ? author : (installed ? "all installed" : "all available"))+ " &8&m--&r &bamount&7: &f" + ex.size() + " &bpage&7: &f" + page + "&7/&f" + avail);
ex = plugin.getExpansionCloud().getPage(ex, page, 10);
if (ex == null) {
Msg.msg(s, "&cThere was a problem getting the requested page...");
return true;
}
Msg.msg(s, "&aGreen = Expansions you have");
Msg.msg(s, "&6Gold = Expansions which need updated");
if (!(s instanceof Player)) {
for (Entry<Integer, CloudExpansion> expansion : ex.entrySet()) {
if (expansion == null || expansion.getKey() == null || expansion.getValue() == null) continue;
Msg.msg(s, "&b" + (expansion.getKey()+1) + "&7: " + (expansion.getValue().shouldUpdate() ? "&6" : (expansion.getValue().hasExpansion() ? "&a" : "&7")) + expansion.getValue().getName() + " &8&m-- &r" + expansion.getValue().getLink());
}
return true;
}
Player p = (Player) s;
for (Entry<Integer, CloudExpansion> expansion : ex.entrySet()) {
if (expansion == null || expansion.getValue() == null) {
continue;
}
StringBuilder sb = new StringBuilder();
if (expansion.getValue().shouldUpdate()) {
sb.append("&6Click to update to the latest version of this expansion\n\n");
} else if (!expansion.getValue().hasExpansion()) {
sb.append("&bClick to download this expansion\n\n");
} else {
sb.append("&aYou have the latest version of this expansion\n\n");
}
sb.append("&bAuthor&7: &f" + expansion.getValue().getAuthor() + "\n");
sb.append("&bVersion&7: &f" + expansion.getValue().getVersion() + "\n");
if (expansion.getValue().getLastUpdate() > 1) {
sb.append("&bLast updated&7: &f" + expansion.getValue().getTimeSinceLastUpdate() + " ago\n");
}
if (expansion.getValue().getReleaseNotes() != null) {
sb.append("&bRelease Notes&7: &f" + expansion.getValue().getReleaseNotes() + "\n");
}
sb.append("\n" + expansion.getValue().getDescription());
String msg = ChatColor.translateAlternateColorCodes('&', "&b" + (expansion.getKey()+1) + "&7: " + (expansion.getValue().shouldUpdate() ? "&6" : (expansion.getValue().hasExpansion() ? "&a" : "")) + expansion.getValue().getName());
String hover = ChatColor.translateAlternateColorCodes('&', sb.toString());
sms(p, msg, hover, expansion.getValue().getName());
}
return true;
}
if (args[1].equalsIgnoreCase("download")) {
if (args.length < 3) {
Msg.msg(s, "&cAn expansion name must be specified!");
return true;
}
CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(args[2]);
if (expansion == null) {
Msg.msg(s, "&cNo expansion found with the name: &f" + args[2]);
return true;
}
if (expansion.hasExpansion() && !expansion.shouldUpdate()) {
Msg.msg(s, "&aYou already have this expansion installed and your version is up to date!");
return true;
}
PlaceholderExpansion loaded = plugin.getExpansionManager().getRegisteredExpansion(args[2]);
if (loaded != null && loaded.isRegistered()) {
PlaceholderAPI.unregisterPlaceholderHook(loaded.getIdentifier());
}
Msg.msg(s, "&aAttempting download of expansion &f" + expansion.getName());
String player = ((s instanceof Player) ? s.getName() : null);
plugin.getExpansionCloud().downloadExpansion(player, expansion);
return true;
}
Msg.msg(s, "&cIncorrect usage! &b/papi ecloud");
return true;
}
private void sms(Player p, String text, String hover, String name) {
TextComponent message = new TextComponent( ChatColor.translateAlternateColorCodes('&', text) );
if (hover != null) {
message.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(ChatColor.translateAlternateColorCodes('&', hover)).create() ) );
}
if (name != null) {
message.setClickEvent( new ClickEvent( ClickEvent.Action.SUGGEST_COMMAND, "/papi ecloud download " + name) );
}
p.spigot().sendMessage( message );
}
}

View File

@ -0,0 +1,47 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.configuration;
import java.util.Comparator;
import me.clip.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,66 +1,89 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.configuration;
import java.util.Optional;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import org.jetbrains.annotations.NotNull;
public class PlaceholderAPIConfig {
public final class PlaceholderAPIConfig {
private PlaceholderAPIPlugin plugin;
public PlaceholderAPIConfig(PlaceholderAPIPlugin i) {
plugin = i;
}
public void loadDefConfig() {
plugin.saveDefaultConfig();
plugin.reloadConfig();
}
public boolean checkUpdates() {
return plugin.getConfig().getBoolean("check_updates");
}
@NotNull
private final PlaceholderAPIPlugin plugin;
public PlaceholderAPIConfig(@NotNull final PlaceholderAPIPlugin plugin) {
this.plugin = plugin;
}
public boolean checkUpdates() {
return plugin.getConfig().getBoolean("check_updates");
}
public boolean isCloudEnabled() {
return plugin.getConfig().getBoolean("cloud_enabled");
}
public void setCloudEnabled(boolean state) {
plugin.getConfig().set("cloud_enabled", state);
plugin.saveConfig();
}
public boolean isDebugMode() {
return plugin.getConfig().getBoolean("debug", false);
}
public Optional<ExpansionSort> getExpansionSort() {
final String option = plugin.getConfig()
.getString("cloud_sorting", ExpansionSort.LATEST.name());
try {
//noinspection ConstantConditions (bad spigot annotation)
return Optional.of(ExpansionSort.valueOf(option.toUpperCase()));
} catch (final IllegalArgumentException ignored) {
return Optional.empty();
}
}
@NotNull
public String dateFormat() {
//noinspection ConstantConditions (bad spigot annotation)
return plugin.getConfig().getString("date_format", "MM/dd/yy HH:mm:ss");
}
@NotNull
public String booleanTrue() {
//noinspection ConstantConditions (bad spigot annotation)
return plugin.getConfig().getString("boolean.true", "true");
}
@NotNull
public String booleanFalse() {
//noinspection ConstantConditions (bad spigot annotation)
return plugin.getConfig().getString("boolean.false", "false");
}
public boolean cloudAllowUnverifiedExpansions() {
return plugin.getConfig().getBoolean("cloud_allow_unverified_expansions");
}
public boolean isCloudEnabled() {
return plugin.getConfig().getBoolean("cloud_enabled");
}
public void setCloudEnabled(boolean b) {
plugin.getConfig().set("cloud_enabled", b);
plugin.reloadConfig();
}
public String booleanTrue() {
return plugin.getConfig().getString("boolean.true");
}
public String booleanFalse() {
return plugin.getConfig().getString("boolean.false");
}
public String dateFormat() {
return plugin.getConfig().getString("date_format");
}
}

View File

@ -0,0 +1,89 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.events;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
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 me.clip.placeholderapi.events.ExpansionsLoadedEvent ExpansionsLoadedEvent} instead.
*/
public final class ExpansionRegisterEvent extends Event implements Cancellable {
@NotNull
private static final HandlerList HANDLERS = new HandlerList();
@NotNull
private final PlaceholderExpansion expansion;
private boolean cancelled;
public ExpansionRegisterEvent(@NotNull final PlaceholderExpansion expansion) {
this.expansion = expansion;
}
@NotNull
public static HandlerList getHandlerList() {
return HANDLERS;
}
/**
* 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;
}
@NotNull
@Override
public HandlerList getHandlers() {
return HANDLERS;
}
}

View File

@ -1,49 +1,70 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.events;
import me.clip.placeholderapi.PlaceholderHook;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
public class ExpansionUnregisterEvent extends Event {
/**
* 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 extends Event {
private static final HandlerList handlers = new HandlerList();
private PlaceholderExpansion expansion;
@NotNull
private static final HandlerList HANDLERS = new HandlerList();
@NotNull
private final PlaceholderExpansion expansion;
public ExpansionUnregisterEvent(PlaceholderExpansion expansion) {
this.expansion = expansion;
}
public ExpansionUnregisterEvent(@NotNull final PlaceholderExpansion expansion) {
this.expansion = expansion;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return HANDLERS;
}
/**
* The {@link PlaceholderExpansion PlaceholderExpansion} that was unregistered.
*
* @return The {@link PlaceholderExpansion PlaceholderExpansion} instance.
*/
@NotNull
public PlaceholderExpansion getExpansion() {
return expansion;
}
@NotNull
@Override
public HandlerList getHandlers() {
return HANDLERS;
}
public static HandlerList getHandlerList() {
return handlers;
}
public PlaceholderExpansion getExpansion() {
return expansion;
}
}

View File

@ -0,0 +1,73 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.events;
import java.util.Collections;
import java.util.List;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
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 extends Event {
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;
}
@NotNull
private static final HandlerList HANDLERS = new HandlerList();
@NotNull
@Override
public HandlerList getHandlers() {
return HANDLERS;
}
@NotNull
public static HandlerList getHandlerList() {
return HANDLERS;
}
}

View File

@ -1,55 +1,70 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.events;
import me.clip.placeholderapi.PlaceholderHook;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* @deprecated This event is no longer used.
*/
@Deprecated
public class PlaceholderHookUnloadEvent extends Event {
public final class PlaceholderHookUnloadEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private String plugin;
private PlaceholderHook hook;
@NotNull
private static final HandlerList HANDLERS = new HandlerList();
public PlaceholderHookUnloadEvent(String plugin, PlaceholderHook placeholderHook) {
this.plugin = plugin;
this.hook = placeholderHook;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
@NotNull
private final String plugin;
@NotNull
private final PlaceholderHook placeholderHook;
public PlaceholderHookUnloadEvent(@NotNull final String plugin,
@NotNull final PlaceholderHook placeholderHook) {
this.plugin = plugin;
this.placeholderHook = placeholderHook;
}
@NotNull
public static HandlerList getHandlerList() {
return HANDLERS;
}
@NotNull
public String getHookName() {
return plugin;
}
@NotNull
public PlaceholderHook getHook() {
return placeholderHook;
}
@NotNull
@Override
public HandlerList getHandlers() {
return HANDLERS;
}
public static HandlerList getHandlerList() {
return handlers;
}
public String getHookName() {
return plugin;
}
public PlaceholderHook getHook() {
return hook;
}
}

View File

@ -0,0 +1,29 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.exceptions;
public final class NoDefaultCommandException extends RuntimeException {
public NoDefaultCommandException(final String message) {
super(message);
}
}

View File

@ -1,37 +1,38 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.expansion;
/**
* This interface allows a class which extends a {@link PlaceholderExpansion}
* to have the clear method called when the implementing expansion is unregistered
* from PlaceholderAPI.
* This is useful if we want to do things when the implementing hook is unregistered
* @author Ryan McCarthy
* Classes implementing this interface will have a {@link #clear() clear void} that is called
* by PlaceholderAPI whenever the {@link me.clip.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();
/**
* Called when the implementing class is unregistered from PlaceholderAPI
*/
void clear();
}

View File

@ -1,39 +1,42 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.expansion;
import org.bukkit.entity.Player;
/**
* This interface allows a class which extends a {@link PlaceholderExpansion}
* to have the cleanup method called every time a player leaves the server.
* This is useful if we want to clean up after the player
* @author Ryan McCarthy
* Classes implementing this interface will have a {@link #cleanup(Player) 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(Player p);
/**
* Called when a player leaves the server
*
* @param p (@link Player} who left the server
*/
void cleanup(Player p);
}

View File

@ -1,41 +1,57 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.expansion;
import java.util.Map;
/**
* Any {@link PlaceholderExpansion} class which implements configurable will
* have any options listed in the getDefaults map automatically added to the PlaceholderAPI config.yml file
* @author Ryan McCarthy
* Implementing this interface allows {@link me.clip.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansions}
* to set a list of default configuration values through the {@link #getDefaults() getDefaults method}
* that should be added to the config.yml of PlaceholderAPI.
*
* <p>The entries will be added under {@code expansions} as their own section.
* <h2>Example:</h2>
* returning a Map with key {@code foo} and value {@code bar} will result in the following config entry:
*
* <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 {
/**
* This method will be called before the implementing class is registered
* to obtain a map of configuration options that the implementing class needs
* These paths and values will be added to the PlaceholderAPI config.yml in the configuration section
* expansions.(placeholder identifier).(your key): (your value)
* @return Map of config path / values which need to be added / removed from the PlaceholderAPI config.yml file
*/
Map<String, Object> getDefaults();
/**
* 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 me.clip.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,202 +0,0 @@
/*
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
*
* 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/>.
*
*
*/
package me.clip.placeholderapi.expansion;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.PlaceholderHook;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.util.FileUtil;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.event.Listener;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public final class ExpansionManager {
private PlaceholderAPIPlugin plugin;
private final Map<String, PlaceholderExpansion> cache = new HashMap<>();
public ExpansionManager(PlaceholderAPIPlugin instance) {
plugin = instance;
}
public void clean() {
cache.clear();
}
public PlaceholderExpansion getCachedExpansion(String plugin) {
return cache.getOrDefault(plugin, null);
}
public boolean removeCachedExpansion(String identifier) {
return cache.remove(identifier) != null;
}
public PlaceholderExpansion getRegisteredExpansion(String name) {
for (Entry<String, PlaceholderHook> hook : PlaceholderAPI.getPlaceholders().entrySet()) {
if (hook.getValue() instanceof PlaceholderExpansion) {
if (name.equalsIgnoreCase(hook.getKey())) {
return (PlaceholderExpansion) hook.getValue();
}
}
}
return null;
}
public boolean registerExpansion(PlaceholderExpansion c) {
if (c == null || c.getIdentifier() == null) {
return false;
}
if (c instanceof Configurable) {
Map<String, Object> defaults = ((Configurable) c).getDefaults();
String pre = "expansions." + c.getIdentifier() + ".";
FileConfiguration cfg = plugin.getConfig();
boolean save = false;
for (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 (c instanceof VersionSpecific) {
VersionSpecific nms = (VersionSpecific) c;
if (!nms.isCompatibleWith(PlaceholderAPIPlugin.getServerVersion())) {
plugin.getLogger().info("Your server version is not compatible with expansion: " + c.getIdentifier()
+ " version: " + c.getVersion());
return false;
}
}
if (!c.canRegister()) {
if (c.getPlugin() != null) {
cache.put(c.getPlugin().toLowerCase(), c);
}
return false;
}
if (!c.register()) {
if (c.getPlugin() != null) {
cache.put(c.getPlugin().toLowerCase(), c);
}
return false;
}
if (c instanceof Listener) {
Listener l = (Listener) c;
Bukkit.getPluginManager().registerEvents(l, plugin);
}
plugin.getLogger().info("Successfully registered expansion: " + c.getIdentifier());
if (c instanceof Taskable) {
((Taskable) c).start();
}
return true;
}
public void registerAllExpansions() {
if (plugin == null) {
return;
}
List<Class<?>> subs = FileUtil.getClasses("expansions", PlaceholderExpansion.class);
if (subs == null || subs.isEmpty()) {
return;
}
for (Class<?> klass : subs) {
if (klass == null) {
continue;
}
try {
PlaceholderExpansion ex = null;
Constructor<?>[] c = klass.getConstructors();
if (c.length == 0) {
ex = (PlaceholderExpansion) klass.newInstance();
} else {
for (Constructor<?> con : c) {
if (con.getParameterTypes().length == 0) {
ex = (PlaceholderExpansion) klass.newInstance();
break;
}
}
}
if (ex == null) {
continue;
}
if (registerExpansion(ex)) {
if (plugin.getExpansionCloud() != null) {
CloudExpansion ce = plugin.getExpansionCloud().getCloudExpansion(ex.getIdentifier());
if (ce != null) {
ce.setHasExpansion(true);
if (!ce.getVersion().equals(ex.getVersion())) {
ce.setShouldUpdate(true);
}
}
}
}
} catch (Throwable t) {
plugin.getLogger().severe("Failed to load placeholder expansion from class: " + klass.getName());
plugin.getLogger().severe(t.getMessage());
}
}
}
}

View File

@ -1,57 +1,75 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.expansion;
public enum NMSVersion {
UNKNOWN("unknown"),
SPIGOT_1_7_R1("v1_7_R1"),
SPIGOT_1_7_R2("v1_7_R2"),
SPIGOT_1_7_R3("v1_7_R3"),
SPIGOT_1_7_R4("v1_7_R4"),
SPIGOT_1_8_R1("v1_8_R1"),
SPIGOT_1_8_R2("v1_8_R2"),
SPIGOT_1_8_R3("v1_8_R3"),
SPIGOT_1_9_R1("v1_9_R1"),
SPIGOT_1_9_R2("v1_9_R2"),
SPIGOT_1_10_R1("v1_10_R1"),
SPIGOT_1_11_R1("v1_11_R1"),
SPIGOT_1_12_R1("v1_12_R1");
private String version;
NMSVersion(String version) {
this.version = version;
}
public String getVersion() {
return version;
}
public static NMSVersion getVersion(String version) {
for (NMSVersion v : values()) {
if (v.getVersion().equalsIgnoreCase(version)) {
return v;
}
}
return NMSVersion.UNKNOWN;
}
UNKNOWN("unknown"),
SPIGOT_1_7_R1("v1_7_R1"),
SPIGOT_1_7_R2("v1_7_R2"),
SPIGOT_1_7_R3("v1_7_R3"),
SPIGOT_1_7_R4("v1_7_R4"),
SPIGOT_1_8_R1("v1_8_R1"),
SPIGOT_1_8_R2("v1_8_R2"),
SPIGOT_1_8_R3("v1_8_R3"),
SPIGOT_1_9_R1("v1_9_R1"),
SPIGOT_1_9_R2("v1_9_R2"),
SPIGOT_1_10_R1("v1_10_R1"),
SPIGOT_1_11_R1("v1_11_R1"),
SPIGOT_1_12_R1("v1_12_R1"),
SPIGOT_1_13_R1("v1_13_R1"),
SPIGOT_1_13_R2("v1_13_R2"),
SPIGOT_1_14_R1("v1_14_R1"),
SPIGOT_1_15_R1("v1_15_R1"),
SPIGOT_1_16_R1("v1_16_R1"),
SPIGOT_1_16_R2("v1_16_R2"),
SPIGOT_1_16_R3("v1_16_R3"),
SPIGOT_1_17_R1("v1_17_R1"),
SPIGOT_1_18_R1("v1_18_R1"),
SPIGOT_1_19_R1("v1_19_R1"),
SPIGOT_1_19_R2("v1_19_R2"),
SPIGOT_1_19_R3("v1_19_R3"),
SPIGOT_1_20_R1("v1_20_R1"),
SPIGOT_1_20_R2("v1_20_R2"),
SPIGOT_1_20_R3("v1_20_R3"),
SPIGOT_1_20_R4("v1_20_R4");
private final String version;
NMSVersion(String version) {
this.version = version;
}
public static NMSVersion getVersion(String version) {
for (NMSVersion v : values()) {
if (v.getVersion().equalsIgnoreCase(version)) {
return v;
}
}
return NMSVersion.UNKNOWN;
}
public String getVersion() {
return version;
}
}

View File

@ -1,172 +1,479 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.expansion;
import me.clip.placeholderapi.PlaceholderAPI;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.PlaceholderHook;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* 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 extends PlaceholderHook {
/**
* The name of this expansion
* @return identifier used for expansion if no name present
*/
public String getName() {
return getIdentifier();
}
/**
* 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 the expansion should persist through reloads
*/
public boolean persist() {
return false;
}
/**
* The type is {@link Type#INTERNAL} by default.
* For external expansions, the type is updated on {@link me.clip.placeholderapi.expansion.manager.LocalExpansionManager#register(Class) register}.
* @since 2.11.4
*/
@ApiStatus.Internal
protected Type expansionType = Type.INTERNAL;
/**
* Get the identifier that this placeholder expansion uses to be passed placeholder requests
* @return placeholder identifier that is associated with this class
*/
public abstract String getIdentifier();
/**
* Get the plugin that this expansion hooks into.
* This will ensure the expansion is added to a cache if canRegister() returns false
* get.
* The expansion will be removed from the cache
* once a plugin loads with the name that is here and the expansion is registered
* @return placeholder identifier that is associated with this class
*/
public abstract String getPlugin();
/**
* Get the author of this PlaceholderExpansion
* @return name of the author for this expansion
*/
public abstract String getAuthor();
/**
* Get the version of this PlaceholderExpansion
* @return current version of this expansion
*/
public abstract String getVersion();
/**
* Check if a placeholder has already been registered with this identifier
* @return true if the identifier for this expansion has already been registered
*/
public boolean isRegistered() {
Validate.notNull(getIdentifier(), "Placeholder identifier can not be null!");
return PlaceholderAPI.getRegisteredIdentifiers().contains(getIdentifier());
}
/**
* If any requirements are required to be checked before this hook can register, add them here
* @return true if this hook meets all the requirements to register
*/
public boolean canRegister() {
return getPlugin() == null || Bukkit.getPluginManager().getPlugin(getPlugin()) != null;
}
/**
* Attempt to register this PlaceholderExpansion with PlaceholderAPI
* @return true if this class and identifier have been successfully registered with PlaceholderAPI
*/
public boolean register() {
Validate.notNull(getIdentifier(), "Placeholder identifier can not be null!");
return PlaceholderAPI.registerPlaceholderHook(getIdentifier(), this);
}
/**
* Quick getter for the {@link PlaceholderAPIPlugin} instance
* @return {@link PlaceholderAPIPlugin} instance
*/
public PlaceholderAPIPlugin getPlaceholderAPI() {
return PlaceholderAPIPlugin.getInstance();
}
/**
* A short description of this expansion
* @return null if no description
*/
public String getDescription() {
return null;
}
/**
* The url link to this expansion page
* @return null if no link
*/
public String getLink() {
return null;
}
/**
* A list of all valid placeholders
* @return null if you dont care
*/
public List<String> getPlaceholders() {
return null;
}
public String getString(String path, String def) {
return getPlaceholderAPI().getConfig().getString("expansions." + getIdentifier() + "." + path, def);
}
public int getInt(String path, int def) {
return getPlaceholderAPI().getConfig().getInt("expansions." + getIdentifier() + "." + path, def);
}
public long getLong(String path, long def) {
return getPlaceholderAPI().getConfig().getLong("expansions." + getIdentifier() + "." + path, def);
}
public double getDouble(String path, double def) {
return getPlaceholderAPI().getConfig().getDouble("expansions." + getIdentifier() + "." + path, def);
}
public List<String> getStringList(String path) {
return getPlaceholderAPI().getConfig().getStringList("expansions." + getIdentifier() + "." + path);
}
public Object get(String path, Object def) {
return getPlaceholderAPI().getConfig().get("expansions." + getIdentifier() + "." + path, def);
}
public ConfigurationSection getConfigSection(String path) {
return getPlaceholderAPI().getConfig().getConfigurationSection("expansions." + getIdentifier() + "." + path);
}
public ConfigurationSection getConfigSection() {
return getPlaceholderAPI().getConfig().getConfigurationSection("expansions." + getIdentifier());
}
public boolean configurationContains(String path) {
return getPlaceholderAPI().getConfig().contains("expansions." + getIdentifier() + "." + path);
}
}
/**
* 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().getLocalExpansionManager().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
|| Bukkit.getPluginManager().getPlugin(getRequiredPlugin()) != null;
}
/**
* Attempt to register this PlaceholderExpansion
*
* @return true if this expansion is now registered with PlaceholderAPI
*/
public boolean register() {
return getPlaceholderAPI().getLocalExpansionManager().register(this);
}
/**
* Attempt to unregister this PlaceholderExpansion
*
* @return true if this expansion is now unregistered with PlaceholderAPI
*/
public final boolean unregister() {
return getPlaceholderAPI().getLocalExpansionManager().unregister(this);
}
/**
* Quick getter for the {@link PlaceholderAPIPlugin} instance
*
* @return {@link PlaceholderAPIPlugin} instance
*/
@NotNull
public final PlaceholderAPIPlugin getPlaceholderAPI() {
return PlaceholderAPIPlugin.getInstance();
}
/**
* 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.
*/
@Nullable
public final ConfigurationSection getConfigSection() {
return getPlaceholderAPI().getConfig().getConfigurationSection("expansions." + getIdentifier());
}
/**
* 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 {@link #getConfigSection() default ConfigurationSection} 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) {
final ConfigurationSection section = getConfigSection();
return section == null ? def : section.get(path, def);
}
/**
* Gets the int relative to the {@link #getConfigSection() default ConfigurationSection} 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 ConfigurationSection section = getConfigSection();
return section == null ? def : section.getInt(path, def);
}
/**
* Gets the long relative to the {@link #getConfigSection() default ConfigurationSection} 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 ConfigurationSection section = getConfigSection();
return section == null ? def : section.getLong(path, def);
}
/**
* Gets the double relative to the {@link #getConfigSection() default ConfigurationSection} 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 ConfigurationSection section = getConfigSection();
return section == null ? def : section.getDouble(path, def);
}
/**
* Gets the String relative to the {@link #getConfigSection() default ConfigurationSection} 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 ConfigurationSection section = getConfigSection();
return section == null ? def : section.getString(path, def);
}
/**
* Gets a String List relative to the {@link #getConfigSection() default ConfigurationSection} 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 ConfigurationSection section = getConfigSection();
return section == null ? Collections.emptyList() : section.getStringList(path);
}
/**
* Gets the boolean relative to the {@link #getConfigSection() default ConfigurationSection} 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 ConfigurationSection section = getConfigSection();
return section == null ? def : section.getBoolean(path, def);
}
/**
* Whether the {@link #getConfigSection() default ConfigurationSection} 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 ConfigurationSection section = getConfigSection();
return section != null && section.contains(path);
}
/**
* 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().log(level, "[" + 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().log(level, "[" + 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 ===
/**
* @deprecated As of versions greater than 2.8.7, use {@link #getRequiredPlugin()}
*
* @return The plugin name.
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public String getPlugin() {
return null;
}
/**
* @deprecated As of versions greater than 2.8.7, use the expansion cloud to show a description
*
* @return The description of the expansion.
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public String getDescription() {
return null;
}
/**
* @deprecated As of versions greater than 2.8.7, use the expansion cloud to display a link
*
* @return The link for the expansion.
*/
@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
}
}

View File

@ -1,27 +1,43 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.expansion;
import org.bukkit.entity.Player;
/**
* Implementing this interface allows your {@link me.clip.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 {
String onPlaceholderRequest(Player one, Player two, String identifier);
/**
* 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(Player one, Player two, String identifier);
}

View File

@ -1,37 +1,43 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.expansion;
/**
* Implementing this interface adds the {@link #start() start} and {@link #stop() stop} void
* methods to your {@link me.clip.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
* 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
* Tasks that need to be performed when this expansion has unregistered should go here
*/
void stop();
/**
* 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,41 +1,46 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.expansion;
public class Version {
@Deprecated
public final class Version {
private final boolean isSpigot;
private final String version;
public Version(String version, boolean isSpigot) {
this.version = version;
this.isSpigot = isSpigot;
}
public String getVersion() {
return version == null ? "unknown" : version;
}
public boolean isSpigot() {
return isSpigot;
}
public boolean compareTo(String version) {
return getVersion().equalsIgnoreCase(version);
}
private boolean isSpigot;
private String version;
public Version(String version, boolean isSpigot) {
this.version = version;
this.isSpigot = isSpigot;
}
public String getVersion() {
return version == null ? "unknown" : version;
}
public boolean isSpigot() {
return isSpigot;
}
}

View File

@ -1,39 +1,45 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.expansion;
/**
* Placeholder expansions which use NMS code should be version specific.
* Implementing this class allows you to perform checks based on the version the server is running.
* The isCompatibleWith method will be passed the server version and allow you to return if your expansion is compatible with that version.
* Placeholder expansions which use NMS code should be version specific. Implementing this class
* allows you to perform checks based on the version the server is running. The isCompatibleWith
* method will be passed the server version and allow you to return if your expansion is compatible
* with that version.
*
* @author Ryan McCarthy
*
* @deprecated Will be removed in a future release.
*/
@Deprecated
public interface VersionSpecific {
/**
* This method is called before the expansion is attempted to be registered
* The server version will be passed to this method so you know what version the server is currently running.
*
* @return true if your expansion is compatible with the version the server is running.
*/
boolean isCompatibleWith(Version v);
/**
* This method is called before the expansion is attempted to be registered The server version
* will be passed to this method so you know what version the server is currently running.
*
* @param v The {@link Version} to check against
*
* @return true if your expansion is compatible with the version the server is running.
*/
boolean isCompatibleWith(Version v);
}

View File

@ -1,100 +1,202 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.expansion.cloud;
import me.clip.placeholderapi.util.TimeUtil;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import me.clip.placeholderapi.util.TimeUtil;
public class CloudExpansion {
private String name, author, version, description, link, releaseNotes;
private boolean hasExpansion, shouldUpdate;
private long lastUpdate;
private String name,
author,
latest_version,
description,
source_url,
dependency_url;
public CloudExpansion(String name, String author, String version, String description, String link) {
this.name = name;
this.author = author;
this.version = version;
this.description = description;
this.link = link;
}
public String getName() {
return name;
}
private boolean hasExpansion,
shouldUpdate,
verified;
public String getAuthor() {
return author;
}
private long last_update,
ratings_count;
public String getVersion() {
return version;
}
private double average_rating;
public String getDescription() {
return description;
}
private List<String> placeholders;
public String getLink() {
return link;
}
private List<Version> versions;
public boolean hasExpansion() {
return hasExpansion;
}
public CloudExpansion() {
}
public void setHasExpansion(boolean hasExpansion) {
this.hasExpansion = hasExpansion;
}
public String getTimeSinceLastUpdate() {
int time = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - getLastUpdate());
return TimeUtil.getTime(time);
}
public boolean shouldUpdate() {
return shouldUpdate;
}
public String getName() {
return name;
}
public void setShouldUpdate(boolean shouldUpdate) {
this.shouldUpdate = shouldUpdate;
}
public void setName(String name) {
this.name = name;
}
public long getLastUpdate() {
return lastUpdate;
}
public String getAuthor() {
return author;
}
public void setLastUpdate(long lastUpdate) {
this.lastUpdate = lastUpdate;
}
public void setAuthor(String author) {
this.author = author;
}
public String getReleaseNotes() {
return releaseNotes;
}
public Version getVersion() {
return getLatestVersion() == null ? null : getVersion(getLatestVersion());
}
public void setReleaseNotes(String releaseNotes) {
this.releaseNotes = releaseNotes;
}
public String getTimeSinceLastUpdate() {
int time = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - getLastUpdate());
return TimeUtil.getTime(time);
}
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 boolean isVerified() {
return verified;
}
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;
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;
}
}
}

View File

@ -1,374 +0,0 @@
/*
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
*
* 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/>.
*
*
*/
package me.clip.placeholderapi.expansion.cloud;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class ExpansionCloudManager {
private PlaceholderAPIPlugin plugin;
private final String API = "http://api.extendedclip.com/";
private final File dir;
private final TreeMap<Integer, CloudExpansion> remote = new TreeMap<>();
private final List<String> downloading = new ArrayList<>();
public ExpansionCloudManager(PlaceholderAPIPlugin instance) {
plugin = instance;
dir = new File(instance.getDataFolder() + File.separator + "expansions");
if (!dir.exists()) {
try {
dir.mkdirs();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public void clean() {
remote.clear();
downloading.clear();
}
public boolean isDownloading(String expansion) {
return downloading.contains(expansion);
}
public Map<Integer, CloudExpansion> getCloudExpansions() {
return remote;
}
public CloudExpansion getCloudExpansion(String name) {
return remote.values().stream().filter(ex -> ex.getName().equalsIgnoreCase(name)).findFirst().orElse(null);
}
public int getCloudAuthorCount() {
return remote.values().stream().collect(Collectors.groupingBy(CloudExpansion::getAuthor, Collectors.counting())).size();
}
public long getToUpdateCount() {
return PlaceholderAPI.getExpansions().stream().filter(ex -> getCloudExpansion(ex.getName()) != null && getCloudExpansion(ex.getName()).shouldUpdate()).count();
}
public Map<Integer, CloudExpansion> getAllByAuthor(String author) {
if (remote.isEmpty()) {
return null;
}
TreeMap<Integer, CloudExpansion> byAuthor = new TreeMap<>();
boolean first = true;
for (CloudExpansion ex : remote.values()) {
if (ex.getAuthor().equalsIgnoreCase(author)) {
if (first) {
first = false;
byAuthor.put(0, ex);
} else {
byAuthor.put(byAuthor.lastKey()+1, ex);
}
}
}
if (byAuthor.isEmpty()) {
return null;
}
return byAuthor;
}
public Map<Integer, CloudExpansion> getAllInstalled() {
if (remote.isEmpty()) {
return null;
}
TreeMap<Integer, CloudExpansion> has = new TreeMap<>();
boolean first = true;
for (CloudExpansion ex : remote.values()) {
if (ex.hasExpansion()) {
if (first) {
first = false;
has.put(1, ex);
} else {
has.put(has.lastKey()+1, ex);
}
}
}
if (has.isEmpty()) {
return null;
}
return has;
}
public int getPagesAvailable(Map<Integer, CloudExpansion> map, int amount) {
if (map == null) {
return 0;
}
int pages = map.size() > 0 ? 1 : 0;
if (pages == 0) {
return pages;
}
if (map.size() > amount) {
pages = map.size()/amount;
if (map.size() % amount > 0) {
pages++;
}
}
return pages;
}
public Map<Integer, CloudExpansion> getPage(Map<Integer, CloudExpansion> map, int page, int size) {
if (map == null || map.size() == 0 || page > getPagesAvailable(map, size)) {
return null;
}
int end = size*page;
int start = end-size;
TreeMap<Integer, CloudExpansion> ex = new TreeMap<>();
IntStream.range(start, end).forEach(n -> ex.put(n, map.get(n)));
return ex;
}
public void fetch() {
plugin.getLogger().info("Fetching available expansion information...");
new BukkitRunnable() {
@Override
public void run() {
StringBuilder sb;
try {
URL site = new URL(API);
HttpURLConnection connection = (HttpURLConnection) site.openConnection();
connection.setRequestMethod("GET");
connection.connect();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
connection.disconnect();
} catch (Exception e) {
return;
}
String json = sb.toString();
JSONParser parser = new JSONParser();
Object obj = null;
try {
obj = parser.parse(json);
} catch (ParseException e) {
e.printStackTrace();
}
if (obj == null) {
return;
}
List<CloudExpansion> unsorted = new ArrayList<>();
if (obj instanceof JSONObject) {
JSONObject jo = (JSONObject) obj;
for (Object o : jo.keySet()) {
JSONObject sub = (JSONObject) jo.get(o);
String name = o.toString();
String author = (String) sub.get("author");
String version = (String) sub.get("version");
String link = (String) sub.get("link");
String description = (String) sub.get("description");
String notes = "";
long update = -1;
if (sub.get("release_notes") != null) {
notes = (String) sub.get("release_notes");
}
if (sub.get("last_update") != null) {
Object u = sub.get("last_update");
if (u instanceof Long) {
update = (long) sub.get("last_update");
}
}
CloudExpansion ce = new CloudExpansion(name, author, version, description, link);
ce.setReleaseNotes(notes);
ce.setLastUpdate(update);
PlaceholderExpansion ex = plugin.getExpansionManager().getRegisteredExpansion(name);
if (ex != null && ex.isRegistered()) {
ce.setHasExpansion(true);
if (!ex.getVersion().equals(version)) {
ce.setShouldUpdate(true);
}
}
unsorted.add(ce);
}
int count = 0;
unsorted.sort(Comparator.comparing(CloudExpansion::getLastUpdate).reversed());
for (CloudExpansion e : unsorted) {
remote.put(count, e);
count++;
}
plugin.getLogger().info(count + " placeholder expansions are available on the cloud.");
long updates = getToUpdateCount();
if (updates > 0) {
plugin.getLogger().info(updates + " installed expansions have updates available.");
}
}
}
}.runTaskAsynchronously(plugin);
}
private void download(URL url, String name) throws IOException {
InputStream is = null;
FileOutputStream fos = null;
try {
URLConnection urlConn = url.openConnection();
is = urlConn.getInputStream();
fos = new FileOutputStream(dir.getAbsolutePath() + File.separator + "Expansion-" + name + ".jar");
byte[] buffer = new byte[is.available()];
int l;
while ((l = is.read(buffer)) > 0) {
fos.write(buffer, 0, l);
}
} finally {
try {
if (is != null) {
is.close();
}
} finally {
if (fos != null) {
fos.close();
}
}
}
}
public void downloadExpansion(final String player, final CloudExpansion ex) {
if (downloading.contains(ex.getName())) {
return;
}
if (ex.getLink() == null) {
return;
}
downloading.add(ex.getName());
plugin.getLogger().info("Attempting download of expansion: " + ex.getName() + (player != null ? " by user: " + player : "") + " from url: " + ex.getLink());
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try {
download(new URL(ex.getLink()), ex.getName());
plugin.getLogger().info("Download of expansion: " + ex.getName() + " complete!");
} catch (Exception e) {
plugin.getLogger().warning("Failed to download expansion: " + ex.getName() + " from: " + ex.getLink());
Bukkit.getScheduler().runTask(plugin, () -> {
downloading.remove(ex.getName());
if (player != null) {
Player p = Bukkit.getPlayer(player);
if (p != null) {
Msg.msg(p, "&cThere was a problem downloading expansion: &f" + ex.getName());
}
}
});
return;
}
Bukkit.getScheduler().runTask(plugin, () -> {
downloading.remove(ex.getName());
if (player != null) {
Player p = Bukkit.getPlayer(player);
if (p != null) {
Msg.msg(p, "&aExpansion &f" + ex.getName() + " &adownload complete!");
}
}
});
});
}
}

View File

@ -0,0 +1,278 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.expansion.manager;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Resources;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Type;
import java.net.URL;
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.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.util.Msg;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
public final class CloudExpansionManager {
@NotNull
private static final String API_URL = "http://api.extendedclip.com/v2/";
@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;
@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 ThreadFactoryBuilder().setNameFormat("placeholderapi-io-#%1$d").build());
public CloudExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) {
this.plugin = plugin;
}
@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 ImmutableMap.copyOf(cache);
}
@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.getLocalExpansionManager()
.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() {
plugin.getLogger().info("Fetching available expansion information...");
ASYNC_EXECUTOR.submit(
() -> {
// a defence tactic! use ConcurrentHashMap instead of normal HashMap
Map<String, CloudExpansion> values = new ConcurrentHashMap<>();
try {
//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 (Throwable e) {
// ugly swallowing of every throwable, but we have to be defensive
plugin.getLogger().log(Level.WARNING, "Failed to download expansion information", e);
}
// loop through what's left on the main thread
plugin
.getServer()
.getScheduler()
.runTask(
plugin,
() -> {
try {
for (Map.Entry<String, CloudExpansion> entry : values.entrySet()) {
String name = entry.getKey();
CloudExpansion expansion = entry.getValue();
expansion.setName(name);
Optional<PlaceholderExpansion> localOpt =
plugin.getLocalExpansionManager().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
plugin
.getLogger()
.log(Level.WARNING, "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.getLocalExpansionManager().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) {
Msg.severe("Failed to download %s:%s", exception, expansion.getName(), expansion.getVersion());
}
}, ASYNC_EXECUTOR);
await.put(toIndexName(expansion), download);
return download;
}
}

View File

@ -0,0 +1,494 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.expansion.manager;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.io.File;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.events.ExpansionRegisterEvent;
import me.clip.placeholderapi.events.ExpansionUnregisterEvent;
import me.clip.placeholderapi.events.ExpansionsLoadedEvent;
import me.clip.placeholderapi.expansion.Cacheable;
import me.clip.placeholderapi.expansion.Cleanable;
import me.clip.placeholderapi.expansion.Configurable;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Taskable;
import me.clip.placeholderapi.expansion.VersionSpecific;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.util.FileUtil;
import me.clip.placeholderapi.util.Futures;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.PluginDisableEvent;
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;
@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.getDataFolder(), EXPANSIONS_FOLDER_NAME);
if (!this.folder.exists() && !folder.mkdirs()) {
Msg.warn("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 ImmutableSet.copyOf(expansions.keySet());
} finally {
expansionsLock.unlock();
}
}
@NotNull
@Unmodifiable
public Collection<PlaceholderExpansion> getExpansions() {
expansionsLock.lock();
try {
return ImmutableSet.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 (!Bukkit.getPluginManager().isPluginEnabled(expansion.getRequiredPlugin())) {
Msg.warn("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()) {
Msg.warn("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!";
}
Msg.severe("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)) {
Msg.warn("Failed to load external expansion %s. Identifier is already in use.", expansion.getIdentifier());
return false;
}
if (expansion instanceof Configurable) {
Map<String, Object> defaults = ((Configurable) expansion).getDefaults();
String pre = "expansions." + identifier + ".";
FileConfiguration cfg = plugin.getConfig();
boolean save = false;
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);
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);
}
Msg.info(
"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 (plugin.getPlaceholderAPIConfig().isCloudEnabled() && expansion.getExpansionType() == PlaceholderExpansion.Type.EXTERNAL) {
final Optional<CloudExpansion> cloudExpansionOptional = plugin.getCloudExpansionManager().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;
}
Bukkit.getPluginManager().callEvent(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 (plugin.getPlaceholderAPIConfig().isCloudEnabled()) {
plugin.getCloudExpansionManager().findCloudExpansionByName(expansion.getName())
.ifPresent(cloud -> {
cloud.setHasExpansion(false);
cloud.setShouldUpdate(false);
});
}
return true;
}
private void registerAll(@NotNull final CommandSender sender) {
Msg.info("Placeholder expansion registration initializing...");
Futures.onMainThread(plugin, findExpansionsOnDisk(), (classes, exception) -> {
if (exception != null) {
Msg.severe("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.getCloudExpansionManager().findCloudExpansionByName(expansion.getName()).orElse(null))
.filter(Objects::nonNull)
.filter(CloudExpansion::shouldUpdate)
.count();
StringBuilder message = new StringBuilder(registered.size() == 0 ? "&6" : "&a")
.append(registered.size())
.append(' ')
.append("placeholder hook(s) registered!");
if (needsUpdate > 0) {
message.append(' ')
.append("&6")
.append(needsUpdate)
.append(' ')
.append("placeholder hook(s) have an update available.");
}
Msg.msg(sender, message.toString());
Bukkit.getPluginManager().callEvent(new ExpansionsLoadedEvent(registered));
});
}
private void unregisterAll() {
for (final PlaceholderExpansion expansion : Sets.newHashSet(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) {
Msg.severe("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)) {
Msg.severe("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) {
Msg.severe("Failed to load expansion %s (is a dependency missing?)", e, file.getName());
return null;
} catch (Exception e) {
throw new CompletionException(e.getMessage() + " (expansion file: " + file.getAbsolutePath() + ")", e);
}
});
}
@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());
}
Msg.warn("There was an issue with loading an expansion.");
return null;
}
}
@EventHandler
public void onQuit(@NotNull final PlayerQuitEvent event) {
for (final PlaceholderExpansion expansion : getExpansions()) {
if (!(expansion instanceof Cleanable)) {
continue;
}
((Cleanable) expansion).cleanup(event.getPlayer());
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onPluginDisable(@NotNull final PluginDisableEvent event) {
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

@ -0,0 +1,57 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.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,57 +0,0 @@
/*
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
*
* 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/>.
*
*
*/
package me.clip.placeholderapi.external;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderHook;
import org.apache.commons.lang.Validate;
import org.bukkit.plugin.Plugin;
@Deprecated
public abstract class EZPlaceholderHook extends PlaceholderHook {
private String identifier;
private String plugin;
public EZPlaceholderHook(Plugin plugin, String identifier) {
Validate.notNull(plugin, "Plugin can not be null!");
Validate.notNull(identifier, "Placeholder name can not be null!");
this.identifier = identifier;
this.plugin = plugin.getName();
}
public boolean isHooked() {
return PlaceholderAPI.getRegisteredPlaceholderPlugins().contains(identifier);
}
public boolean hook() {
return PlaceholderAPI.registerPlaceholderHook(identifier, this);
}
public String getPlaceholderName() {
return identifier;
}
public String getPluginName() {
return plugin;
}
}

View File

@ -0,0 +1,48 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.listeners;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.server.ServerLoadEvent;
import org.jetbrains.annotations.NotNull;
public final class ServerLoadEventListener implements Listener {
@NotNull
private final PlaceholderAPIPlugin plugin;
public ServerLoadEventListener(@NotNull final PlaceholderAPIPlugin plugin) {
this.plugin = plugin;
Bukkit.getPluginManager().registerEvents(this, plugin);
}
@EventHandler
public void onServerLoad(@NotNull final ServerLoadEvent event) {
HandlerList.unregisterAll(this);
plugin.getLocalExpansionManager().load(Bukkit.getConsoleSender());
}
}

View File

@ -0,0 +1,137 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.replacer;
import java.util.Locale;
import java.util.function.Function;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
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 OfflinePlayer 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.onRequest(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

@ -0,0 +1,49 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.replacer;
import java.util.function.Function;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface Replacer {
@NotNull
String apply(@NotNull final String text, @Nullable final OfflinePlayer 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,105 +1,124 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.updatechecker;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Arrays;
import javax.net.ssl.HttpsURLConnection;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.regex.Pattern;
/**
* thanks maxim
*/
public class UpdateChecker implements Listener {
private PlaceholderAPIPlugin plugin;
private final int resourceId = 6245;
private static String latestVersion = "";
private static boolean updateAvailable = false;
private final int RESOURCE_ID = 6245;
private final PlaceholderAPIPlugin plugin;
private final String pluginVersion;
private String spigotVersion;
private boolean updateAvailable;
public UpdateChecker(PlaceholderAPIPlugin i) {
plugin = i;
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
if (checkForUpdate()) {
Bukkit.getScheduler().runTask(plugin, () -> {
plugin.getLogger().info("An update for PlaceholderAPI (v" + getLatestVersion() + ") is available at:");
plugin.getLogger().info("https://www.spigotmc.org/resources/placeholderapi." + resourceId + "/");
register();
});
}
});
}
private void register() {
Bukkit.getPluginManager().registerEvents(this, plugin);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onJoin(PlayerJoinEvent e) {
if (e.getPlayer().isOp()) {
e.getPlayer().sendMessage(ChatColor.translateAlternateColorCodes('&', "&bAn update for &fPlaceholder&7API &e(&fPlaceholder&7API &fv" + getLatestVersion() + "&e)"));
e.getPlayer().sendMessage(ChatColor.translateAlternateColorCodes('&', "&bis available at &ehttps://www.spigotmc.org/resources/placeholderapi." + resourceId + "/"));
}
public UpdateChecker(PlaceholderAPIPlugin i) {
plugin = i;
pluginVersion = i.getDescription().getVersion();
}
public boolean hasUpdateAvailable() {
return updateAvailable;
}
public String getSpigotVersion() {
return spigotVersion;
}
public void fetch() {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try {
HttpsURLConnection con = (HttpsURLConnection) new URL(
"https://api.spigotmc.org/legacy/update.php?resource=" + RESOURCE_ID).openConnection();
con.setRequestMethod("GET");
spigotVersion = new BufferedReader(new InputStreamReader(con.getInputStream())).readLine();
} catch (Exception ex) {
plugin.getLogger().info("Failed to check for updates on spigot.");
return;
}
if (spigotVersion == null || spigotVersion.isEmpty()) {
return;
}
updateAvailable = spigotIsNewer();
if (!updateAvailable) {
return;
}
Bukkit.getScheduler().runTask(plugin, () -> {
plugin.getLogger()
.info("An update for PlaceholderAPI (v" + getSpigotVersion() + ") is available at:");
plugin.getLogger()
.info("https://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID + "/");
Bukkit.getPluginManager().registerEvents(this, plugin);
});
});
}
private boolean spigotIsNewer() {
if (spigotVersion == null || spigotVersion.isEmpty()) {
return false;
}
private String getSpigotVersion() {
try {
HttpsURLConnection con = (HttpsURLConnection) new URL("https://api.spigotmc.org/legacy/update.php?resource=" + resourceId).openConnection();
con.setRequestMethod("GET");
String version = new BufferedReader(new InputStreamReader(con.getInputStream())).readLine();
if (version.length() <= 7) {
return version;
}
} catch (Exception ex) {
plugin.getLogger().info("Failed to check for a update on spigot.");
}
return null;
int[] plV = toReadable(pluginVersion);
int[] spV = toReadable(spigotVersion);
if (plV[0] < spV[0]) {
return true;
} else if ((plV[1] < spV[1])) {
return true;
} else {
return plV[2] < spV[2];
}
}
private int[] toReadable(String version) {
if (version.contains("-DEV")) {
version = version.split("-DEV")[0];
}
private boolean checkHigher(String currentVersion, String newVersion) {
String current = toReadable(currentVersion);
String newVers = toReadable(newVersion);
return current.compareTo(newVers) < 0;
}
return Arrays.stream(version.split("\\.")).mapToInt(Integer::parseInt).toArray();
}
public boolean checkForUpdate() {
String version = getSpigotVersion();
if (version != null) {
if (checkHigher(plugin.getDescription().getVersion(), version)) {
latestVersion = version;
updateAvailable = true;
return true;
}
}
return false;
@EventHandler(priority = EventPriority.MONITOR)
public void onJoin(PlayerJoinEvent e) {
if (e.getPlayer().hasPermission("placeholderapi.updatenotify")) {
Msg.msg(e.getPlayer(),
"&bAn update for &fPlaceholder&7API &e(&fPlaceholder&7API &fv" + getSpigotVersion()
+ "&e)"
, "&bis available at &ehttps://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID
+ "/");
}
public static boolean updateAvailable() {
return updateAvailable;
}
public static String getLatestVersion() {
return latestVersion;
}
private String toReadable(String version) {
String[] split = Pattern.compile(".", Pattern.LITERAL).split(version.replace("v", ""));
version = "";
for (String s : split) {
version += String.format("%4s", s);
}
return version;
}
}
}

View File

@ -1,29 +1,30 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.util;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
@ -33,61 +34,44 @@ import java.util.jar.JarInputStream;
public class FileUtil {
public static List<Class<?>> getClasses(String folder, Class<?> type) {
List<Class<?>> list = new ArrayList<>();
try {
File f = new File(PlaceholderAPIPlugin.getInstance().getDataFolder(), folder);
if (!f.exists()) {
if (!f.mkdir()) {
PlaceholderAPIPlugin.getInstance().getLogger().severe("Failed to create " + folder + " folder!");
}
return list;
}
FilenameFilter fileNameFilter = (dir, name) -> {
int i = name.lastIndexOf('.');
return i > 0 && name.substring(i).equals(".jar");
};
File[] jars = f.listFiles(fileNameFilter);
if (jars == null) {
return list;
}
for (File file : jars) {
list = gather(file.toURI().toURL(), list, type);
}
return list;
} catch (Throwable t) {}
return null;
@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;
}
private static List<Class<?>> gather(URL jar, List<Class<?>> list, Class<?> clazz) {
if (list == null) {
list = new ArrayList<>();
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 {
URLClassLoader cl = new URLClassLoader(new URL[]{jar}, clazz.getClassLoader());
JarInputStream jis = new JarInputStream(jar.openStream());
while (true) {
JarEntry j = jis.getNextJarEntry();
if (j == null) {
break;
}
String name = j.getName();
if (name == null || name.isEmpty()) {
continue;
}
if (name.endsWith(".class")) {
name = name.replace("/", ".");
String cname = name.substring(0, name.lastIndexOf(".class"));
Class<?> c = cl.loadClass(cname);
if (clazz.isAssignableFrom(c)) {
list.add(c);
}
}
}
cl.close();
jis.close();
} catch (Throwable t) {
final Class<?> loaded = loader.loadClass(match);
if (clazz.isAssignableFrom(loaded)) {
classes.add(loaded.asSubclass(clazz));
}
} catch (final NoClassDefFoundError ignored) {
}
return list;
}
}
if (classes.isEmpty()) {
loader.close();
return null;
}
return classes.get(0);
}
}

View File

@ -0,0 +1,70 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.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

@ -0,0 +1,77 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.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 org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
public final class Futures {
private Futures() {}
public static <T> void onMainThread(@NotNull final Plugin plugin,
@NotNull final CompletableFuture<T> future,
@NotNull final BiConsumer<T, Throwable> consumer) {
future.whenComplete((value, exception) -> {
if (Bukkit.isPrimaryThread()) {
consumer.accept(value, exception);
} else {
Bukkit.getScheduler().runTask(plugin, () -> 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,35 +1,79 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.util;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.stream.Collectors;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
public final class Msg {
public static void log(Level level, String msg, Object... args) {
PlaceholderAPIPlugin.getInstance().getLogger().log(level, String.format(msg, args));
}
public static void info(String msg, Object... args) {
log(Level.INFO, msg, args);
}
public static void warn(String msg, Object... args) {
log(Level.WARNING, msg, args);
}
public static void warn(String msg, Throwable throwable, Object... args){
PlaceholderAPIPlugin.getInstance().getLogger().log(Level.WARNING, String.format(msg, args), throwable);
}
public static void severe(String msg, Object... args) {
log(Level.SEVERE, msg, args);
}
public static void severe(String msg, Throwable throwable, Object... args) {
PlaceholderAPIPlugin.getInstance().getLogger().log(Level.SEVERE, String.format(msg, args), throwable);
}
public static void msg(@NotNull final CommandSender sender, @NotNull final String... messages) {
if (messages.length == 0) {
return;
}
public class Msg {
sender.sendMessage(Arrays.stream(messages).map(Msg::color).collect(Collectors.joining("\n")));
}
public static void msg(CommandSender s, String... msg) {
Arrays.stream(msg).forEach(text ->
s.sendMessage(ChatColor.translateAlternateColorCodes('&', text)));
}
public static void broadcast(@NotNull final String... messages) {
if (messages.length == 0) {
return;
}
Bukkit.broadcastMessage(
Arrays.stream(messages).map(Msg::color).collect(Collectors.joining("\n")));
}
public static String color(@NotNull final String text) {
return ChatColor.translateAlternateColorCodes('&', text);
}
}

View File

@ -1,29 +1,28 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.util;
public enum TimeFormat {
DAYS,
HOURS,
MINUTES,
SECONDS
DAYS,
HOURS,
MINUTES,
SECONDS
}

View File

@ -1,162 +1,96 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (C) 2018 Ryan McCarthy
* Copyright (c) 2015 - 2024 PlaceholderAPI Team
*
* This program is free software: you can redistribute it and/or modify
* 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.
*
* This program is distributed in the hope that it will be useful,
* 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 me.clip.placeholderapi.util;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.StringJoiner;
public class TimeUtil {
public static String getRemaining(int seconds, TimeFormat type) {
if (seconds < 60) {
switch(type) {
case DAYS:
return "0";
case HOURS:
return "0";
case MINUTES:
return "0";
case SECONDS:
return String.valueOf(seconds);
}
return String.valueOf(seconds);
}
int minutes = seconds / 60;
int s = 60 * minutes;
int secondsLeft = seconds - s;
if (minutes < 60) {
switch(type) {
case DAYS:
return "0";
case HOURS:
return "0";
case MINUTES:
return String.valueOf(minutes);
case SECONDS:
return String.valueOf(secondsLeft);
}
return String.valueOf(seconds);
}
if (minutes < 1440) {
int hours = minutes / 60;
int inMins = 60 * hours;
int leftOver = minutes - inMins;
switch(type) {
case DAYS:
return "0";
case HOURS:
return String.valueOf(hours);
case MINUTES:
return String.valueOf(leftOver);
case SECONDS:
return String.valueOf(secondsLeft);
}
return String.valueOf(seconds);
}
int days = minutes / 1440;
int inMins = 1440 * days;
int leftOver = minutes - inMins;
if (leftOver < 60) {
switch (type) {
case DAYS:
return String.valueOf(days);
case HOURS:
return String.valueOf(0);
case MINUTES:
return String.valueOf(leftOver);
case SECONDS:
return String.valueOf(secondsLeft);
}
return String.valueOf(seconds);
public static String getRemaining(final int seconds, final TimeFormat type) {
return getRemaining((long) seconds, type);
}
} else {
int hours = leftOver / 60;
int hoursInMins = 60 * hours;
int minsLeft = leftOver - hoursInMins;
switch (type) {
case DAYS:
return String.valueOf(days);
case HOURS:
return String.valueOf(hours);
case MINUTES:
return String.valueOf(minsLeft);
case SECONDS:
return String.valueOf(secondsLeft);
}
return String.valueOf(seconds);
}
}
public static String getTime(int seconds) {
if (seconds < 60) {
return seconds+"s";
}
int minutes = seconds / 60;
int s = 60 * minutes;
int secondsLeft = seconds - s;
if (minutes < 60) {
if (secondsLeft > 0) {
return String.valueOf(minutes+"m "+secondsLeft+"s");
} else {
return String.valueOf(minutes+"m");
}
}
if (minutes < 1440) {
String time;
int hours = minutes / 60;
time = hours+"h";
int inMins = 60 * hours;
int leftOver = minutes - inMins;
if (leftOver >= 1) {
time = time+" "+leftOver+"m";
}
if (secondsLeft > 0) {
time = time+" "+secondsLeft+"s";
}
return time;
}
String time;
int days = minutes / 1440;
time = days+"d";
int inMins = 1440 * days;
int leftOver = minutes - inMins;
if (leftOver >= 1) {
if (leftOver < 60) {
time = time+" "+leftOver+"m";
} else {
int hours = leftOver / 60;
time = time+" "+hours+"h";
int hoursInMins = 60 * hours;
int minsLeft = leftOver - hoursInMins;
time = time+" "+minsLeft+"m";
}
}
if (secondsLeft > 0) {
time = time+" "+secondsLeft+"s";
}
return time;
}
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,17 +1,18 @@
# PlaceholderAPI
# Version: ${project.version}
# Version: ${version}
# Created by: extended_clip
# Contributors: https://github.com/PlaceholderAPI/PlaceholderAPI/graphs/contributors
# Issues: https://github.com/PlaceholderAPI/PlaceholderAPI/issues
# Expansions: https://api.extendedclip.com/all/
# Wiki: https://github.com/PlaceholderAPI/PlaceholderAPI/wiki
# Discord: https://discordapp.com/invite/7sndK3q
# 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_allow_unverified_expansions: false
cloud_sorting: "name"
boolean:
'true': 'yes'
'false': 'no'
date_format: MM/dd/yy HH:mm:ss
debug: false

View File

@ -1,32 +1,98 @@
name: ${project.name}
main: me.clip.placeholderapi.PlaceholderAPIPlugin
version: ${project.version}
author: [extended_clip]
description: ${project.description}
permissions:
placeholderapi.*:
description: ability to use all commands
children:
placeholderapi.admin: true
placeholderapi.admin:
description: ability to use all commands
children:
placeholderapi.list: true
placeholderapi.reload: true
placeholderapi.parse: true
placeholderapi.injector.chat.bypass: true
placeholderapi.injector.signs.bypass: true
placeholderapi.injector.anvil.bypass: true
placeholderapi.list:
description: ability to use the list command
default: op
placeholderapi.reload:
description: ability to use the reload command
default: op
placeholderapi.parse:
description: ability to use parse command
default: op
name: PlaceholderAPI
main: "me.clip.placeholderapi.PlaceholderAPIPlugin"
version: ${version}
author: HelpChat
api-version: "1.13"
description: "An awesome placeholder provider!"
commands:
placeholderapi:
description: PlaceholderAPI command
aliases: [clipsplaceholderapi, papi]
placeholderapi:
description: "PlaceholderAPI Command"
aliases: ["papi"]
permissions:
placeholderapi.*:
description: "Ability to use all PAPI commands"
children:
placeholderapi.admin: true
placeholderapi.ecloud.*: true
placeholderapi.admin:
description: "Ability to use all PAPI commands"
children:
placeholderapi.help: true
placeholderapi.info: true
placeholderapi.list: true
placeholderapi.parse: true
placeholderapi.reload: true
placeholderapi.version: true
placeholderapi.register: true
placeholderapi.unregister: true
placeholderapi.updatenotify: true
placeholderapi.ecloud.*:
description: "Ability to use all PAPI ecloud commands"
children:
placeholderapi.ecloud: true
placeholderapi.ecloud.info: true
placeholderapi.ecloud.list: true
placeholderapi.ecloud.clear: true
placeholderapi.ecloud.status: true
placeholderapi.ecloud.update: true
placeholderapi.ecloud.refresh: true
placeholderapi.ecloud.download: true
placeholderapi.ecloud.placeholders: true
placeholderapi.help:
default: "op"
description: "Allows you to view the list of PAPI commands"
placeholderapi.info:
default: "op"
description: "Allows you to view expansion information"
placeholderapi.list:
default: "op"
description: "Allows you to list active expansions"
placeholderapi.ecloud:
default: "op"
description: "Allows you to access PAPI eCloud"
placeholderapi.parse:
default: "op"
description: "Allows you to parse placeholders"
placeholderapi.reload:
default: "op"
description: "Allows you to reload PAPI and its configuration"
placeholderapi.version:
default: "op"
description: "Allows you to view the version of PAPI installed"
placeholderapi.register:
default: "op"
description: "Allows you to register expansions"
placeholderapi.unregister:
default: "op"
description: "Allows you to unregister expansions"
placeholderapi.updatenotify:
default: "op"
description: "Notifies you when there is a PAPI update"
placeholderapi.ecloud.info:
default: "op"
description: "Allows you to view cloud expansion information"
placeholderapi.ecloud.list:
default: "op"
description: "Allows you to list eCloud expansions"
placeholderapi.ecloud.clear:
default: "op"
description: "Allows you to clear the local eCloud expansion cache"
placeholderapi.ecloud.status:
default: "op"
description: "Allows you to view the status of eCloud expansions"
placeholderapi.ecloud.update:
default: "op"
description: "Allows you to update registered eCloud expansions"
placeholderapi.ecloud.refresh:
default: "op"
description: "Allows you to refresh the local eCloud expansion cache"
placeholderapi.ecloud.download:
default: "op"
description: "Allows you to download an expansion from the eCloud"
placeholderapi.ecloud.placeholders:
default: "op"
description: "Allows you to view the placeholders of a eCloud expansion"

View File

@ -0,0 +1,93 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi;
import com.google.common.collect.ImmutableMap;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.replacer.CharsReplacer;
import me.clip.placeholderapi.replacer.Replacer;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface Values {
String SMALL_TEXT = "My name is %player_name%";
String LARGE_TEXT = "My name is %player_name% and my location is (%player_x%, %player_y%, %player_z%), this placeholder is invalid %server_name%";
ImmutableMap<String, PlaceholderExpansion> PLACEHOLDERS = ImmutableMap.<String, PlaceholderExpansion>builder()
.put("player", new MockPlayerPlaceholderExpansion())
.build();
Replacer CHARS_REPLACER = new CharsReplacer(Replacer.Closure.PERCENT);
final class MockPlayerPlaceholderExpansion extends PlaceholderExpansion {
public static final String PLAYER_X = "10";
public static final String PLAYER_Y = "20";
public static final String PLAYER_Z = "30";
public static final String PLAYER_NAME = "Sxtanna";
@NotNull
@Override
public String getIdentifier() {
return "player";
}
@NotNull
@Override
public String getAuthor() {
return "Sxtanna";
}
@NotNull
@Override
public String getVersion() {
return "1.0";
}
@Override
public String onRequest(@Nullable final OfflinePlayer player, @NotNull final String params) {
final String[] parts = params.split("_");
if (parts.length == 0) {
return null;
}
switch (parts[0]) {
case "name":
return PLAYER_NAME;
case "x":
return PLAYER_X;
case "y":
return PLAYER_Y;
case "z":
return PLAYER_Z;
}
return null;
}
}
}

View File

@ -0,0 +1,38 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.replacer;
import me.clip.placeholderapi.Values;
import org.openjdk.jmh.annotations.Benchmark;
public class ReplacerBenchmarks {
@Benchmark
public void measureCharsReplacerSmallText() {
Values.CHARS_REPLACER.apply(Values.SMALL_TEXT, null, Values.PLACEHOLDERS::get);
}
@Benchmark
public void measureCharsReplacerLargeText() {
Values.CHARS_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get);
}
}

View File

@ -0,0 +1,63 @@
/*
* This file is part of PlaceholderAPI
*
* PlaceholderAPI
* Copyright (c) 2015 - 2024 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 me.clip.placeholderapi.replacer;
import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_NAME;
import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_X;
import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_Y;
import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_Z;
import static org.junit.jupiter.api.Assertions.assertEquals;
import me.clip.placeholderapi.Values;
import org.junit.jupiter.api.Test;
public final class ReplacerUnitTester {
@Test
void testCharsReplacerProducesExpectedSingleValue() {
assertEquals(PLAYER_NAME,
Values.CHARS_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get));
}
@Test
void testCharsReplacerProducesExpectedSentence() {
assertEquals(String.format(
"My name is %s and my location is (%s, %s, %s), this placeholder is invalid %%server_name%%",
PLAYER_NAME, PLAYER_X, PLAYER_Y, PLAYER_Z),
Values.CHARS_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get));
}
@Test
void testResultsAreTheSameAsReplacement() {
final String resultChars = Values.CHARS_REPLACER
.apply("%player_name%", null, Values.PLACEHOLDERS::get);
assertEquals(PLAYER_NAME, resultChars);
}
@Test
void testCharsReplacerIgnoresMalformed() {
final String text = "10% and %hello world 15%";
assertEquals(text, Values.CHARS_REPLACER.apply(text, null, Values.PLACEHOLDERS::get));
}
}