Compare commits

..
638 Commits
Author SHA1 Message Date
NotAlexNoyle 36117803fe Exclude CODEOWNERS from language statistics 2026-10-29 16:18:50 -04:00
NotAlexNoyle cb4fead942 Add CODEOWNERS (one staff approval) 2026-10-29 16:18:50 -04:00
NotAlexNoyle 60375ab964 Update Maintenance MOTD 2026-05-21 13:45:14 -04:00
NotAlexNoyle 3a94423501 Update Maintenance MOTD 2026-05-21 11:43:06 -04:00
NotAlexNoyle 4b62c83410 Update Maintenance MOTD 2026-05-21 11:05:02 -04:00
NotAlexNoyle 2ccfae5d87 Fix config display on legacy clients 2026-05-20 11:04:16 -04:00
NotAlexNoyle 7f444d0f1c Update MOTD 2026-05-20 10:45:55 -04:00
NotAlexNoyle 46b3a3f14e Update MOTD 2026-05-20 10:37:48 -04:00
NotAlexNoyle 9ddac66d62 Fix runtime error 2026-05-20 10:29:49 -04:00
NotAlexNoyle dd7fa6f08a Fix dots in maintenance strings 2026-05-20 10:13:18 -04:00
NotAlexNoyle c2b4ceef1c Use live TrueOG Network config file 2026-05-20 09:24:57 -04:00
NotAlexNoyle b11136bed0 Merge pull request #1 from true-og/codex/update-plugin-dependency-to-advancedserverlist-og
Prefer AdvancedServerList-OG for Paper integration
2026-03-16 04:18:28 -04:00
NotAlexNoyle 7664d40696 Prefer AdvancedServerList-OG for paper integration 2026-03-16 04:18:17 -04:00
NotAlexNoyle dcbc8f7407 Drop bungee 2026-03-12 12:29:43 -04:00
NotAlexNoyle 752e9aeb19 Update API version 2026-03-12 12:22:14 -04:00
NotAlexNoyle 7fc3f0cbc9 Update gradle to 8.14.3 2025-08-30 10:26:21 -04:00
NotAlexNoyle c3014e8092 Always build with java 17 2025-05-29 21:38:30 -04:00
Nassim Jahnke 7f5a5d8d54 Enable Gradle configuration cache 2024-12-29 13:10:50 +01:00
Nassim Jahnke 27ff56f673 [ci skip] Update Gradle wrapper 2024-12-21 19:27:06 +01:00
Nassim Jahnke db49edaa88 [ci skip] Update Gradle wrapper 2024-11-17 17:51:22 +01:00
Nassim Jahnke b4e331fba3 4.3.0 Release 2024-09-17 10:51:56 +02:00
Maintenancer 563c184c0b New Crowdin updates (#138) 2024-09-15 11:49:45 +02:00
Maintenancer 6dd9ae0ec3 New Crowdin updates (#133) 2024-09-13 17:39:34 +02:00
Nassim Jahnke ac50b28659 Accept time durations in timer commands
Closes #134
2024-09-13 17:36:13 +02:00
Nassim Jahnke 65bf209705 Put ping, player count, and player list hover messages into sections 2024-09-13 16:20:02 +02:00
Nassim Jahnke 6d57f9664e Fix dummy sample player profiles on 1.21 Paper 2024-09-13 15:00:50 +02:00
Nassim Jahnke 1408dee12e Add timer-specific player count and player sample messages
Closes #131
2024-09-13 14:50:17 +02:00
Nassim Jahnke 97f6cb5d68 Don't send broadcasts to the console twice
Fixes #129
2024-09-13 14:15:28 +02:00
Nassim Jahnke 4cd541e158 Remove all leftover legacy chat usage 2024-09-13 13:23:18 +02:00
Nassim Jahnke 9a9793bb90 Clear sample players in Velocity ping listener 2024-09-13 12:47:05 +02:00
Nassim Jahnke 4005416de1 Upgrade Gradle wrapper 2024-09-13 12:45:42 +02:00
Maintenancer 12c9972efd New Crowdin updates (#124)
* New translations language-en.yml (Vietnamese)

* New translations language-en.yml (French)

* New translations language-en.yml (Russian)

* New translations language-en.yml (Hungarian)

* New translations language-en.yml (Spanish)

* New translations language-en.yml (German)
2024-08-29 13:37:28 +02:00
Nassim Jahnke 41acd5db94 Update actions 2024-08-27 22:01:30 +02:00
Nassim Jahnke 337e5739c6 Default to empty list if fallback field is missing/null 2024-08-27 21:51:09 +02:00
Nassim Jahnke 3ad5cff521 Don't log color codes, more message cleanups 2024-08-27 12:06:21 +02:00
Nassim Jahnke 2457cdff71 Rename Paper module, replace dump and update message sending with adventure components 2024-08-26 22:56:07 +02:00
Nassim Jahnke 7a9e8676d9 Fix maintenance dump command 2024-08-26 22:18:39 +02:00
Nassim Jahnke 5f52fa53f4 Update dependencies 2024-08-26 22:12:21 +02:00
Nassim Jahnke 1b1708aa69 Update shadow 2024-08-08 10:05:44 +02:00
Nassim Jahnke fdc6cd9bdd Update Hangar latest release endpoint 2024-07-31 18:14:01 +02:00
Maintenancer 1fb7c0ea42 New Crowdin updates (#121)
* New translations language-en.yml (Portuguese)

* New translations language-en.yml (Spanish)

* New translations language-en.yml (Italian)

* New translations language-en.yml (English)

* Update source file language-en.yml

* New translations language-en.yml (Vietnamese)
2024-06-13 16:33:37 +02:00
Nassim Jahnke 8d75af5b46 Bump version to 4.2.2-SNAPSHOT 2024-06-13 16:32:30 +02:00
Nassim Jahnke 4d0ad57695 Update Gradle wrapper 2024-06-01 17:10:15 +02:00
Nassim Jahnke 4c8ab9ce32 4.2.1 Release 2024-05-17 15:39:28 +02:00
Maintenancer 34bc884a11 New Crowdin updates (#120)
* New translations language-en.yml (Chinese Simplified)

* New translations language-en.yml (Russian)
2024-05-17 15:25:26 +02:00
Maintenancer 0ebde0b8db New Crowdin updates (#119) 2024-04-30 00:10:43 +02:00
Nassim Jahnke 82301fd9f9 Add paperweight-mappings-namespace attribute 2024-04-28 03:53:56 +02:00
EpicPlayerA10 b0d87a94a8 Offline player fetching improvements (#117) 2024-03-24 18:40:20 +01:00
Alec Jensen a380d8bf35 Show proxied maintenance status in ping for forced hosts (#118) 2024-03-24 10:57:56 +01:00
Nassim Jahnke ae8fb9a8db Update Gradle wrapper 2024-03-24 10:30:34 +01:00
Maintenancer 724fcd8395 New Crowdin updates (#114)
* New translations language-en.yml (Russian)

* New translations language-en.yml (Chinese Simplified)
2024-03-02 20:35:26 +01:00
Maintenancer cfbcf0975c New Crowdin updates (#113) 2024-02-04 17:25:28 +01:00
Maintenancer 32baaf620f New translations language-en.yml (French) by Kertie2_ (#112) 2024-01-14 17:45:55 +01:00
Maintenancer 06e3405bcc New Crowdin updates (#110)
* New translations language-en.yml (Italian)

* New translations language-en.yml (Hungarian)

* New translations language-en.yml (Chinese Simplified)

* New translations language-en.yml (Spanish)

* New translations language-en.yml (Turkish)

* New translations language-en.yml (German)

* New translations language-en.yml (Russian)
2024-01-14 17:39:41 +01:00
Nassim Jahnke d2520eed6c Update copyright headers 2024-01-01 21:45:25 +01:00
Nassim Jahnke 24bd5b2618 Don't keep converting player count and count hover messages 2024-01-01 21:44:08 +01:00
Nassim Jahnke f6b6a45fa8 Bump version to 4.2.1-SNAPSHOT 2023-12-31 16:26:22 +01:00
Nassim Jahnke b37bfe6334 Update Gradle wrapper 2023-12-13 22:47:27 +01:00
Nassim Jahnke 1f8574fe26 Update changelog title 2023-09-17 19:43:53 +10:00
Nassim Jahnke 7ee3b8a5fe 4.2.0 Release 2023-09-17 18:31:33 +10:00
Maintenancer cfb7e9e15b New Crowdin updates (#109) 2023-09-17 18:19:30 +10:00
Nassim Jahnke 5d595869ee Add server specific timer command messages 2023-09-17 13:25:38 +10:00
Nassim Jahnke e154b62ef7 Update Blossom 2023-09-17 12:50:37 +10:00
Nassim Jahnke 3d49982e56 Update maven repo for SLP and readd hook 2023-09-11 13:35:19 +10:00
Nassim Jahnke a1bc66a717 Don't publish adventure modules 2023-09-10 15:14:57 +10:00
Nassim Jahnke c42f0ab912 Configure (manual) publishing 2023-09-10 14:47:48 +10:00
Nassim Jahnke 22dd4ce266 Remove SLP dependency for now
The repository is not available and thus breaks building...
2023-09-10 14:11:41 +10:00
Nassim Jahnke 2e66e1b926 Update Gradle wrapper 2023-09-10 13:44:08 +10:00
Maintenancer ac28c94435 New translations language-en.yml (Japanese) (#108) 2023-09-08 11:05:24 +10:00
4acc809dd8 New Crowdin updates (#105)
* New translations language-en.yml (Portuguese)

* New translations language-en.yml (Danish)

* New translations language-en.yml (Korean)

Co-authored-by: JaeWoong Suh <90325840+SuhJae@users.noreply.github.com>
Co-authored-by: Jan CHristensen <skrivtiljan@gmail.com>
2023-08-08 17:04:49 +10:00
Maintenancer 0ff5cd232f Hungarian translation file (thanks to Kende) 2023-06-26 11:46:40 +02:00
Nassim Jahnke d49db3dfbe Add config options for commands on single server maintenance enable/disable 2023-06-15 13:08:28 +02:00
Nassim Jahnke b36adb54fa Update gradle wrapper 2023-06-15 12:30:01 +02:00
Maintenancer 91276ab5f6 New Crowdin updates (#99) 2023-06-15 11:41:00 +02:00
Nassim Jahnke 3dd1d7506a Update dependencies 2023-06-15 11:39:38 +02:00
Nassim Jahnke 00abe8588b Send user-agent to Hangar API 2023-06-15 11:36:28 +02:00
Nassim Jahnke 9fba024e16 Bump version to 4.2.0-SNAPSHOT 2023-06-15 11:34:24 +02:00
Nassim Jahnke fe7a640e3d 4.1.0 Release 2023-04-17 09:57:04 +02:00
Nassim Jahnke 72c9689b6d Update version checker endpoint to Hangar 2023-04-17 09:57:04 +02:00
Nassim Jahnke cfd0dd1be7 Update Gradle wrapper 2023-04-15 11:17:25 +02:00
Maintenancer cfdedfad15 New translations language-en.yml (Japanese) (#98)
Thanks to yu-solt
2023-04-15 11:15:24 +02:00
Nassim Jahnke 32258bc1ef Update Folia class check 2023-03-30 08:45:52 +02:00
Nassim Jahnke c2f297a125 Add preliminary Folia support 2023-03-10 12:53:44 +01:00
Nassim Jahnke 036c225c2c Add enable-playercounthovermessage option, don't disable playercount messages when disabling pingmessages 2023-03-08 15:01:12 +01:00
Nassim Jahnke bc10c6b94c Update Gradle wrapper and shadow 2023-03-08 15:00:25 +01:00
Maintenancer 211dd1e4f2 New Crowdin updates (#95)
* New translations language-en.yml (Spanish)

* New translations language-en.yml (Polish)

* New translations language-en.yml (Russian)
2023-03-08 14:54:39 +01:00
Nassim Jahnke de500d9cd3 Small cleanup 2023-02-25 11:44:13 +01:00
Nassim Jahnke 99d77b2f55 Fix variable replacement with gradients 2023-02-25 10:42:24 +01:00
Nassim Jahnke 2ddafded74 Update Gradle wrapper, dependencies 2023-02-25 10:41:10 +01:00
Nassim Jahnke 876b66392f Update workflow 2023-02-22 16:36:59 +01:00
Maintenancer e59a27d09d New Crowdin updates (#94) 2023-02-07 13:33:40 +01:00
Nassim Jahnke 0c4e9564bd New Crowdin updates (#93) 2023-02-07 13:24:49 +01:00
Nassim Jahnke 9c7f60180b Update README 2023-02-07 13:06:58 +01:00
Nassim Jahnke bbaa53f428 New Crowdin updates (#91) 2023-02-07 12:39:00 +01:00
Nassim Jahnke 9f910d3027 Update Crowdin configuration file 2023-02-07 12:01:13 +01:00
Nassim Jahnke 2c3a324ec9 Remove platform specific aliases 2023-02-07 09:24:48 +01:00
Nassim Jahnke 9ab902b9ce Update download url 2023-01-28 12:06:20 +01:00
Nassim Jahnke 4c5a19fd60 Add Ukrainian translation file (thanks to Mrlucke) 2023-01-01 13:52:19 +01:00
Nassim Jahnke 342cfa4b03 Fix Velocity startup
Closes #87
2022-12-19 17:26:35 +01:00
Nassim Jahnke 6cf9314aaa Thank you gradle, very cool 2022-12-09 11:20:06 +01:00
Nassim Jahnke 967fe77753 Update Gradle wrapper 2022-12-08 10:36:29 +01:00
Nassim Jahnke 6d6ebee2cc Relocate bstats 2022-10-01 13:43:12 +02:00
Nassim Jahnke 0e7bbfd0e2 Fix the message for cancelling proxied server timers not replacing the server argument 2022-10-01 13:41:28 +02:00
Nassim Jahnke 3410f36c10 Update deps, add bstats to Velocity and Sponge modules 2022-09-25 12:18:55 +02:00
Super fe2bfda1b9 Create language-se.yml (#84) 2022-08-30 15:46:49 +02:00
Nassim Jahnke e106aacc47 Add turkish translation file 2022-08-05 09:48:36 +02:00
Nassim Jahnke e7aee8c99f Fix disabling enable-pingmessages not being respected on Paper servers 2022-04-27 16:40:01 +02:00
Nassim Jahnke c84265c1dd Bump version to 4.0.2-SNAPSHOT 2022-04-27 16:39:48 +02:00
original-codematrix 78b08ca164 Switch from assert to Assertions class from JUnit (#77) 2022-04-27 16:06:16 +02:00
Nassim Jahnke 54151515f4 4.0.1 Release 2022-04-16 18:40:34 +02:00
Nassim Jahnke fd1c252594 Update dependencies, actually fix tests 2022-04-15 21:51:29 +02:00
Nassim Jahnke 702349c762 Fix tests 2022-04-15 20:08:13 +02:00
Nassim Jahnke 1f6fb837de Fix config header saving 2022-03-23 09:27:43 +01:00
Nassim Jahnke 0284b80e44 Update workflow 2022-03-23 09:26:53 +01:00
Nassim Jahnke 6f99fe4ce8 Bump version to 4.0.1-SNAPSHOT 2022-03-23 09:20:09 +01:00
Nassim Jahnke 1ac29de1bf Fix Sponge metadata replacement 2022-03-17 10:50:56 +01:00
Nassim Jahnke 2223094461 4.0.0 Release 2022-03-17 10:07:29 +01:00
Nassim Jahnke 6279ae2477 Update adventure, update changelog, fix publishing 2022-03-15 10:44:21 +01:00
Nassim Jahnke 5f90270cc8 Update gradle wrapper to 7.4.1 2022-03-09 18:52:43 +01:00
Nassim Jahnke 885c7249a6 Update language files 2022-03-08 21:47:20 +01:00
Nassim Jahnke ffb8fd5767 Minor cleanup 2022-03-08 19:39:36 +01:00
Nassim Jahnke c3717bc8b1 Update Gradle wrapper to 7.4, adventure to 4.10.0 2022-03-05 12:14:01 +01:00
Nassim Jahnke 665c3816cd Merge remote-tracking branch 'origin/dev' into adventure-support
# Conflicts:
#	maintenance-core/src/main/resources/language-de.yml
2022-02-21 09:21:31 +01:00
Ceddix a586190e1f fixed spelling issue that caused a message not to work (#75) 2022-02-19 09:32:24 +01:00
Nassim Jahnke 820d5138a9 Update default config values 2022-01-19 18:59:21 +01:00
Nassim Jahnke 39f240c1cb Cleanup a bit of language file updating 2022-01-16 19:16:45 +01:00
Nassim Jahnke a8092d430a Fix multiline playercount hover 2022-01-16 16:49:07 +01:00
Nassim Jahnke 8173a69496 Configurable singleServerMaintenanceListEntry, remove LuckPerm context for now 2022-01-16 15:50:29 +01:00
Nassim Jahnke 317afe064a Update language files, update config header 2022-01-16 15:01:04 +01:00
Nassim Jahnke 7d3e6002f1 Update copyright header 2022-01-09 22:31:16 +01:00
Nassim Jahnke 22a75203cf Update Sponge module to API v8 2022-01-09 22:27:56 +01:00
Nassim Jahnke b63ba56f50 Fixup dependencies 2022-01-01 14:58:27 +01:00
Nassim Jahnke e0a20eff46 Improve language updating, add <prefix> placeholder 2021-12-31 16:43:40 +01:00
Nassim Jahnke 77d42f3367 Update workflow 2021-12-28 18:14:43 +01:00
Nassim Jahnke 09f3ad0384 Major version bump
Convert project to Gradle
Change API class names and split module into two
Add adventure component support
2021-12-28 18:03:34 +01:00
Nassim Jahnke 0c2f0cdb96 WIP LuckPerms contexts 2021-12-28 09:40:29 +01:00
Nassim Jahnke 13706a86e5 Update dependencies 2021-12-27 12:12:24 +01:00
Slasherss d121772f3c Add polish translations (#73) 2021-12-22 09:45:42 +01:00
Nassim Jahnke 8b5234b2ad Update language-es.yml (thanks to Jaximo) 2021-12-07 08:59:31 +01:00
Aurélien d659fd173e Remove extra point (#70) 2021-08-19 22:18:25 +02:00
Aurélien 8e44e611d0 Update language-fr.yml (#69) 2021-08-19 22:13:55 +02:00
kennytv 36c2c6183e Update language-pt.yml (thanks to JoaoPinto) 2021-08-18 17:37:25 +02:00
kennytv 06229ab9ae Bump version to 3.0.8-SNAPSHOT, fix missing scheduletimer keys 2021-08-18 12:54:18 +02:00
Nassim Jahnke 9df156703d 3.0.7 Release 2021-08-17 12:58:42 +02:00
kennytv 7ab28b7126 Prepare for 3.0.7 Release 2021-08-17 12:57:36 +02:00
kennytv f4fe7a4aa4 Update copyright header, readme, and license format 2021-08-12 10:43:10 +02:00
kennytv ea6f43f4e0 Remove debug command from help list 2021-08-08 12:54:57 +02:00
kennytv 07304e0ad4 Update workflow and dependencies 2021-08-07 12:37:18 +02:00
kennytv 11bf0287f3 Add helpDump to language files 2021-07-23 10:26:44 +02:00
KennyTV 1bda7aae24 Fix Velocity update message, update depend to 3.0.0-SNAPSHOT 2021-05-27 22:25:58 +02:00
KennyTV a919227b04 Remove that 2021-05-23 14:23:33 +02:00
KennyTV 796f46dd44 Shade mysql connector in Velocity module
Fixes #61
2021-05-22 19:24:38 +02:00
KennyTV 3ebd6e627a Update ProtocolLib Maven repo 2021-05-10 08:48:02 +02:00
KennyTV 53612fe24a Do offline web lookup in whitelist add on proxies 2021-05-08 09:49:23 +02:00
KennyTV cbcbba5678 Update changelog, update sponge repo url 2021-03-06 18:25:01 +01:00
KennyTV 962f7834c6 Have an extra broadcast key for schedule starts
Closes #58
2021-03-06 16:44:58 +01:00
KennyTV f724014efd Add config options to dispatch commands on maintenance toggle 2021-03-06 16:02:09 +01:00
KennyTV 84f39ca478 Fix inverted if condition 2021-02-18 09:15:33 +01:00
KennyTV d06760e83f Add "enable-pingmessages" config option
Closes #57
2021-02-18 09:14:48 +01:00
Aurélien 4e27c5b044 Update language-fr.yml (#56) 2021-02-17 10:48:35 +01:00
KennyTV 8480e1b28b Bump version 3.0.7-SNAPSHOT 2021-02-17 10:47:56 +01:00
KennyTV f56afcf9a7 Update changelog 2021-02-17 10:30:28 +01:00
Nassim de6c56e1ba 3.0.6 Release 2021-02-17 10:25:23 +01:00
KennyTV b37050b317 Prepare for 3.0.6 Release 2021-02-17 10:24:56 +01:00
KennyTV 081a34c51b Actually fire the MaintenanceReloadedEvent 2021-02-07 11:40:41 +01:00
KennyTV ff2ccf0478 Update copyright header 2021-02-07 11:32:00 +01:00
KennyTV 34c6811295 Add "maintenance schedule" command 2021-02-07 11:30:20 +01:00
KennyTV 4b50b67abf Add primitive debug mode (only implemented on Bungee) 2020-12-31 12:59:31 +01:00
KennyTV eee4be4ca0 Hotfix dumps
I will use paste.gg in the future, this is only to make it work at all again
2020-12-31 12:28:24 +01:00
KennyTV f6d5e99a09 Also replace online and max variable in the hover message 2020-11-20 22:38:10 +01:00
KennyTV 29c55e53af Properly register main command with permissions (instead of checking for them in the actual command) 2020-10-26 16:55:37 +01:00
KennyTV ac38cf143b Update Velocity API usage 2020-10-26 16:47:07 +01:00
KennyTV 1bd22f73e5 Update language-es.yml (thanks to Vixo_Ulises) 2020-10-26 16:38:38 +01:00
KennyTV a256a10170 Rename GH build artifact 2020-10-01 09:40:29 +02:00
Nassim 2e6f1b718a Make artifacts work 😎 2020-08-25 14:55:20 +02:00
KennyTV a30b833bfb Upload artifacts 2020-08-25 14:52:15 +02:00
Nassim 4701803045 Create maven.yml 2020-08-25 14:14:56 +02:00
KennyTV 76385f3968 Fix NPE in null pings 2020-08-22 09:48:21 +02:00
KennyTV 9283cb25e7 Update Velocity API usage to 1.1.0-SNAPSHOT 🎉 2020-08-21 20:26:39 +02:00
KennyTV 97dbe14127 Add whitelist add arg to manually add offline uuid+name 2020-08-19 09:44:57 +02:00
KennyTV da41f7cfc8 Fix linebreaks on Bungee in playercount hovermessage 2020-07-30 12:04:05 +02:00
KennyTV 69e94ab3e1 Add MaintenanceReloadedEvent, also fire changed event for unregistered proxy servers 2020-07-29 14:17:49 +02:00
dependabot-preview[bot] 4458533372 Bump junit-jupiter-engine from 5.6.1 to 5.6.2
Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.6.1 to 5.6.2.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.6.1...r5.6.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-27 18:39:05 +02:00
KennyTV ad9251e332 Link to dev branch for Travis builds 2020-07-26 12:15:18 +02:00
KennyTV ffeebfa4aa Add 'mt' command alias, add some braces 2020-07-26 11:08:25 +02:00
KennyTV bc04bf866a Formatting fix in changelog 2020-07-14 12:10:34 +02:00
KennyTV 3a2af01ad2 Missing singleserver kick messages should not throw warnings 2020-06-25 11:28:36 +02:00
KennyTV 27d884ff31 Implement new methods for dummyprofile 2020-06-25 09:12:24 +02:00
KennyTV c69b05501e Add translators to the individual language files 2020-06-21 09:26:59 +02:00
Aurélien 6119cb77a8 Fixes for French translation (#42) 2020-06-21 09:19:16 +02:00
KennyTV 01b0ca9817 Rename method to get server name of player, cleanup config in test 2020-06-18 15:43:39 +02:00
KennyTV 7e188cadaf Version increase to 3.0.6-SNAPSHOT 2020-06-18 15:26:39 +02:00
KennyTV f12d16d686 Sneak a mysql fix in 2020-06-17 14:09:02 +02:00
KennyTV 441f53077b Update API jar to 3.0.5 2020-06-17 11:26:32 +02:00
Nassim cb2b33b9e2 3.0.5 Release 2020-06-17 10:48:13 +02:00
KennyTV f50497b49a Prepare for 3.0.5 release 2020-06-17 10:47:20 +02:00
KennyTV 9fa699d22d Config test additions 2020-06-17 09:31:49 +02:00
KennyTV d94034dc6e Config set cleanup 2020-06-16 17:49:45 +02:00
KennyTV 9b2f44dfaf Use precondition in api getter util 2020-06-16 16:39:23 +02:00
KennyTV a4f0d85cf7 Wrong nullable annotation 2020-06-16 16:20:18 +02:00
KennyTV 4c21049e59 Minor code cleanup to version checking 2020-06-16 16:19:20 +02:00
KennyTV 921aea4623 Update changelog, bump Guava provided version
Not that it matters, but want to get rid of the security alert
2020-06-16 09:51:25 +02:00
KennyTV 465ab57125 Remove config updating from 2.x
See https://github.com/KennyTV/Maintenance/wiki/Updates#updating-from-2x on how to do that manually - virtually noone should be using such old versions anymore
2020-06-10 12:51:25 +02:00
KennyTV 83be201d0f Automatically move files to new dir on updating 2020-06-09 19:25:21 +02:00
KennyTV 251dad766b Update README 2020-06-01 13:21:21 +02:00
KennyTV 880d839b52 Use higher proxy ping listener priority 2020-05-18 22:12:22 +02:00
KennyTV 197f986088 Replace newline variable in language file
Note on why this even exists: Yaml will force save all strings containing line breaks in this rather chunky format:
  key: |-
    First line text
     Second line text.
     ...

This also happens to string lists, making those practically unreadable, as well as confusing for most users in general.
Because of this, I replace %NEWLINE% manually, to spare users from these ugly breaks.
2020-05-15 13:38:41 +02:00
KennyTV 3925baef3c Add option to set multiple fallback servers 2020-05-12 20:52:47 +02:00
KennyTV 143b1f5d80 Add secret language option for server specific kick messages
Closes #38
2020-05-12 20:27:59 +02:00
KennyTV 0461bf4ffc Implement deep get in config 2020-05-12 19:32:42 +02:00
KennyTV 5e0809c448 Remove platform suffix from plugin identifier 2020-04-22 10:59:27 +02:00
KennyTV b4c3fbeb19 Don't hide playercount if custom playercount is disabled 2020-04-21 12:00:23 +02:00
KennyTV 44cedde712 Respect custom playercount setting in Spigot ping 2020-04-21 08:36:28 +02:00
KennyTV ba31683d48 Fix use-ssl option inversion 2020-04-13 09:29:22 +02:00
KennyTV 9780dcdb76 Update copyright headers 2020-04-10 23:42:06 +02:00
KennyTV c3746996a1 Update Russian language file 2020-04-09 08:59:11 +02:00
KennyTV 58f986f0f7 Add placeholder link to readme 2020-04-06 22:34:04 +02:00
KennyTV 0551558b8f Add Italian language file 2020-04-03 12:27:00 +02:00
KennyTV 3808edafca Fix config loading with multiline strings, add small tests
Fixes #37
2020-03-30 12:48:48 +02:00
KennyTV b85c85f4fd Throw around some nullable annotations 2020-03-30 11:02:35 +02:00
KennyTV 3956879fb8 Add Chinese language file 2020-03-17 15:02:47 +01:00
KennyTV 4c8536faeb Version increase to 3.0.5-SNAPSHOT 2020-03-17 11:57:12 +01:00
Nassim ef019df6fa 3.0.4 Release 2020-03-17 11:01:41 +01:00
KennyTV 415833c9b0 Prepare for 3.0.4 release 2020-03-17 11:00:55 +01:00
KennyTV e844df3f26 Rearrange new language entries 2020-03-16 15:49:09 +01:00
KennyTV 2678ab40aa Fix join notifications with waiting servers enabled 2020-03-16 15:48:27 +01:00
KennyTV 360725d4c5 Add waiting-server option for global proxy maintenance
Includes some other, minor fixes
Some proxy modules cleanup
2020-03-16 15:17:09 +01:00
KennyTV 2288d193fd Update missing pt messages (by JoaoPinto) 2020-03-16 11:16:46 +01:00
Max Kade 16f8f15111 Fix single server timer accepting number as seconds and not minutes (#35) 2020-03-11 14:35:56 +01:00
KennyTV 8bec54970b Fix singleserver timers broadcasting globally 2020-02-14 21:40:08 +01:00
KennyTV 607b510bd1 Update bStats metrics 2020-02-12 17:20:37 +01:00
KennyTV 71d174a90c Add option to disable sql ssl 2020-02-09 12:47:28 +01:00
KennyTV 45fb0d1ead Minor beauty changes 2020-01-29 15:11:01 +01:00
KennyTV f7cfb5d813 Forgot the return 2019-11-21 09:46:51 +01:00
KennyTV 24598168bf Add Russian language file (thanks to En_0t_S) 2019-11-21 09:44:23 +01:00
KennyTV 7a5f4e317a Don't throw errors when failing the language update check because of custom langs 2019-11-21 09:41:42 +01:00
KennyTV bb8e6d391f Version increase to 3.0.4-SNAPSHOT 2019-11-21 09:27:32 +01:00
KennyTV 14ce1934f1 Forgot to update the date in the changelog 2019-09-17 09:05:53 +02:00
Nassim a6f362523b 3.0.3 Release 2019-09-17 09:02:27 +02:00
KennyTV 6cbe823c23 Version increase to 3.0.3 2019-09-17 08:29:23 +02:00
KennyTV 5c3a7c3fce Update changelog, fix small oversight in the Bungee serverconnect 2019-09-13 10:30:53 +02:00
KennyTV 74399c49dc Fix playercountmessage on Paper servers with Via 2019-09-09 08:35:53 +02:00
KennyTV 8dd6cd6a1f Remove some old code 2019-08-24 18:55:30 +02:00
KennyTV 25fe2617dc Replace some streams with loops.. because why not
Not really that much of an improvement, but gotta strike those micro optimizations 🤷
2019-08-18 10:18:58 +02:00
KennyTV 6d4ea72e58 Revert "Fix potential config deserialization error"
This reverts commit ac19bac1
2019-08-13 22:33:31 +02:00
KennyTV 29ab1f35f2 Fix potential config deserialization error 2019-08-13 22:21:30 +02:00
KennyTV adfb2a7c86 Minor pom changes 2019-08-13 22:21:11 +02:00
KennyTV 3f434737f8 Fix some redundant config comment checks 2019-07-26 13:20:27 +02:00
KennyTV 097c8b7ce3 Update bStats metrics 2019-07-26 12:29:34 +02:00
KennyTV bfa229edbd Minor config optimizations and cleanup 2019-07-22 09:28:53 +02:00
KennyTV de15485d64 Language autoupdater, fix updating with broken texts 2019-07-21 15:49:10 +02:00
KennyTV b4c81b9359 Add warning with PS 2019-07-20 09:58:00 +02:00
KennyTV ee61f49e63 Add warning with PS 2019-07-20 09:49:00 +02:00
KennyTV 4595c6b00c Switch to ProtocolLib/Spigot ping listener if PS is installed 2019-07-20 09:46:28 +02:00
KennyTV 39b9b0e5a2 Add help page header to language file 2019-06-28 21:43:27 +02:00
Nassim 5c34d4fdee Remove a space in language-es.yml 2019-06-27 10:34:36 +02:00
KennyTV de4a1222e8 Add bypass permission for specific proxied servers 2019-06-27 10:05:57 +02:00
KennyTV 62d1ef6a61 Update changelog 2019-06-09 09:53:04 +02:00
KennyTV c7cf0c073c Update Spanish language (thanks to Vixo_Ulises) 2019-06-09 09:51:04 +02:00
KennyTV 6439684c70 Update French language (thanks to Zendrique) 2019-05-31 21:26:58 +02:00
KennyTV eb7bbb0dad Language changes 2019-05-31 16:26:16 +02:00
KennyTV 4b909dc85a Update travis.yml 2019-05-31 15:45:35 +02:00
KennyTV 66f1eef91f Update travis.yml 2019-05-31 15:38:06 +02:00
KennyTV 7beccd980b I'm a dumbo 2019-05-31 15:31:10 +02:00
KennyTV 13cd8c0348 Add help messages to language files 2019-05-31 15:30:03 +02:00
KennyTV 4408508625 Fix double messages in some server connections 2019-05-24 09:14:51 +02:00
KennyTV 65a3772b3a Kick connecting players before the connection succeeded, fix double join-notification (Bungee) 2019-05-23 22:18:05 +02:00
KennyTV 786dbef1c1 Update config version 2019-05-20 15:28:06 +02:00
KennyTV c7f1b6af2e Add option to not kick online players 2019-05-18 17:23:56 +02:00
KennyTV c81b7b71cc Version increase to 3.0.3-SNAPSHOT 2019-05-18 17:16:37 +02:00
KennyTV 159a95e75b 3.0.2 Release 2019-05-17 09:35:34 +02:00
KennyTV 385846605a 👀 2019-05-17 09:35:14 +02:00
KennyTV 789b16518c Update changelog 2019-05-17 09:31:17 +02:00
KennyTV 2af10d0bca Version increase to 3.0.2 2019-05-17 09:25:57 +02:00
KennyTV 5998db8df3 Finish timerspecific pingmessages 2019-05-17 09:21:35 +02:00
KennyTV 78133f3f00 Update changelog, resort some config entries 2019-05-14 13:48:28 +02:00
KennyTV 10364ef2c9 Timerspecific pingmessages 2019-05-14 09:07:23 +02:00
KennyTV 210e738bec ‍Make setmotd command also set timerspecific messages 2019-05-13 22:53:04 +02:00
KennyTV 67dfb659ce 🤦‍ 2019-05-13 15:30:40 +02:00
KennyTV 1d60f62bcc Make motd command display timerspecific ones 2019-05-13 15:30:00 +02:00
KennyTV fbb0f5c6a2 WIP: Timerspecific pingmessages 2019-05-13 11:02:13 +02:00
KennyTV 6c6d5b870e Make dumps prettier 2019-05-09 22:30:18 +02:00
KennyTV 60ae8a8361 Fix Sponge 8.0.0 compatibility 2019-05-09 21:53:30 +02:00
KennyTV 1d206d4dc7 Update to latest Velocity text api 2019-05-07 09:09:58 +02:00
KennyTV 4bb70ad57a Update README.md 2019-04-27 15:34:07 +02:00
KennyTV 2748d23cbf Fix Velocity autoupdater 2019-04-17 15:38:51 +02:00
KennyTV 282bc50d3e Version increase to 3.0.2-SNAPSHOT 2019-04-17 15:38:33 +02:00
KennyTV 40b6d23dd3 Update api, changelog and readme for latest release 2019-04-17 15:24:51 +02:00
KennyTV d236d26657 Merge pull request #29 from KennyTV/dev
3.0.1 Release
2019-04-17 14:38:55 +02:00
KennyTV ac3b360c42 Version increase to 3.0.1 2019-04-17 14:36:56 +02:00
KennyTV 5eb572dfad Remove interface check 2019-04-17 14:36:47 +02:00
KennyTV f76db64995 Set group id to eu.kennytv.maintenance 2019-04-15 10:54:16 +02:00
KennyTV 37c0e2a024 Fix another potential error on startup 2019-04-14 13:07:01 +02:00
KennyTV 06fa14bae4 Database sync fixes, adjustments to endtimer saving 2019-04-05 14:05:01 +02:00
KennyTV 1550a6c533 Update README 2019-04-05 14:04:45 +02:00
KennyTV 4229be161e Add config updater + endtimer saving after restart 2019-04-03 14:22:06 +02:00
KennyTV 7e7eb62e0a Fix error printing in some cases, close hikari source on disable(/reload) 2019-04-03 11:15:30 +02:00
KennyTV a7896ab1f9 Hackily fix slf4j relocation and shorten jar sizes 2019-03-19 22:35:13 +01:00
KennyTV 3db3f55472 Revert "Only compile SnakeYaml in universal and Velocity file"
This reverts commit b8c0e3a7
2019-03-19 18:07:18 +01:00
KennyTV 817c829bee Only compile SnakeYaml in universal and Velocity file 2019-03-19 18:04:05 +01:00
KennyTV 1f5b008520 Make ServerInfoPacketListener extend PacketAdapter instead of creating anonymous class 2019-03-19 17:04:08 +01:00
KennyTV db1a0ec601 Don't register listener twice 2019-03-13 17:17:31 +01:00
KennyTV 414995a8cd Add Ore url to plugin info 2019-03-13 10:21:29 +01:00
KennyTV a9169367f6 Readd update checking on Sponge, still disallow execution of update 2019-03-13 10:04:16 +01:00
KennyTV ea8bde1fe1 Typo 👀 2019-03-11 13:24:33 +01:00
KennyTV 12512c96a9 Fix Paper pinglistener and remove old code 2019-03-11 13:22:15 +01:00
KennyTV 6ac5614982 Rename dump variable 2019-03-11 13:00:43 +01:00
KennyTV 694e01ce99 Use PaperServerListPingEvent if applicable 2019-03-11 12:48:10 +01:00
KennyTV 77e23811ed Fix exception on ping that does not come from status packet 2019-03-10 19:08:08 +01:00
KennyTV 94fc06283c nooooo 2019-03-08 21:29:28 +01:00
KennyTV d9ed72b472 Try to please the beautiful people over at Ore (Sponge), attempt no 2 2019-03-08 21:28:35 +01:00
KennyTV f8e88fb4bf Try to please the beautiful people over at Ore (Sponge) 2019-03-08 21:18:21 +01:00
KennyTV e0aa2d392b Make endtimer display format adjustable 2019-03-05 16:55:56 +01:00
KennyTV 1282c93fe4 Remove bStats from Sponge module
(Their beautiful repo is down and I don't really need it on Sponge anyways 🤔)
2019-02-21 17:22:29 +01:00
KennyTV bd4a143a0a Minor maintenance event changes 2019-02-21 16:43:13 +01:00
KennyTV f32efaa68e Some language changes 2019-02-21 15:35:52 +01:00
KennyTV ce82285772 Make createFile method public 2019-02-19 17:30:58 +01:00
KennyTV 1d398287eb Add api method to get a list of maintenance servers 2019-02-19 13:25:13 +01:00
KennyTV ed1f227608 Custom maintenance events 2019-02-19 13:08:38 +01:00
KennyTV 81fb399932 Some language changes 2019-02-19 11:28:24 +01:00
KennyTV db0758e949 Version increase to 3.0.1-SNAPSHOT 2019-02-19 00:16:24 +01:00
KennyTV 3dabc3bc9c Sneak Spanish language in 👀 2019-02-17 10:16:36 +01:00
KennyTV 9f5c2c18c4 3.0 Release 2019-02-17 09:22:12 +01:00
KennyTV 2f4ba89b17 Version increase to 3.0 2019-02-17 09:21:51 +01:00
KennyTV fb93a3dc08 Update README 2019-02-15 11:16:14 +01:00
KennyTV 50dca0cc52 Some last refactoring/fixes 2019-02-14 10:25:52 +01:00
KennyTV c3dbc9d8dd Fix velocity update/dump messages 2019-02-12 19:12:27 +01:00
KennyTV faaf125e13 Merge remote-tracking branch 'origin/v3' into v3 2019-02-12 13:30:12 +01:00
KennyTV ce7e1a5708 Minor refactoring and message changes 2019-02-12 13:30:01 +01:00
KennyTV 3ea42cc786 Merge pull request #25 from PSandro/patch
Patch
2019-02-12 10:06:47 +01:00
Sandro Pischinger eb712ecf83 fix typo "seperator" 2019-02-11 22:32:29 +01:00
Sandro Pischinger 03f33b524c fix typo 'Intervalls' 2019-02-11 21:09:54 +01:00
KennyTV 207b2a10de Some message changes 2019-02-11 15:01:11 +01:00
KennyTV 24ac8deb08 SLP actually has a repo 👀 2019-02-11 10:35:36 +01:00
KennyTV a4583a31ac Fix 2019-02-11 08:50:04 +01:00
KennyTV 71556f841f Rename status perm 2019-02-10 11:55:35 +01:00
KennyTV 6a8c2dc99c Let maintenance servers be removed, even if they don't exist on the proxy 2019-02-10 11:17:07 +01:00
KennyTV b95a83eba2 whoops 2019-02-09 16:12:02 +01:00
KennyTV 66d92c1bba Rename some perms 2019-02-09 15:37:21 +01:00
KennyTV 514a63b80a Use maintenance.dump perm for dumpcommand 2019-02-09 15:21:37 +01:00
KennyTV 283297a51f Update changelog 2019-02-09 15:02:53 +01:00
KennyTV bd411b5d01 Update README 2019-02-09 12:41:45 +01:00
KennyTV bcc8d6e0d8 Fix update messages in Sponge and Velocity 2019-02-08 17:24:52 +01:00
KennyTV f63f1ba95d Update README 2019-02-08 15:09:40 +01:00
KennyTV 558c98a8cd Add beautiful changelog file 2019-02-08 15:03:22 +01:00
KennyTV f011540686 whoops 2019-02-08 11:48:54 +01:00
KennyTV e9c7a13548 Some fixes and changes to subcommand system 2019-02-08 11:46:24 +01:00
KennyTV 789c31445b Make subcommand system to finally have that 💩 readable again
* Though it adds 100kb lolz
2019-02-07 19:02:45 +01:00
KennyTV b4f6fa191f Add option to disable update checks 2019-02-07 13:30:11 +01:00
KennyTV a413c588bf Maybe hopefully get rid of the sl4j problem garbage? 2019-02-07 12:48:43 +01:00
KennyTV 1e58a75b25 Final fixes! (hopefully 👀) 2019-02-07 12:12:06 +01:00
KennyTV 309d127ec5 Config comment change 2019-02-07 11:50:25 +01:00
KennyTV a22a2e5fd6 Move fields from SpigotServers file to config (+ automigration) 2019-02-07 11:43:28 +01:00
KennyTV 0876dac2d2 Fixes! 2019-02-07 11:15:18 +01:00
KennyTV 2df8bfad1d slf4j sad 2019-02-07 10:45:16 +01:00
KennyTV 9d6be94f18 Fixes to fallback handling 2019-02-07 10:37:55 +01:00
KennyTV bf35fd05fc Fix error when connecting to fallbackserver 2019-02-07 10:33:34 +01:00
KennyTV 61339381d2 Fix typo 2019-02-07 10:25:37 +01:00
KennyTV 63f81fa37b Do version check on startup async 2019-02-06 13:55:24 +01:00
KennyTV c22f430f13 Rename MaintenanceModePlugin to MaintenancePlugin 2019-02-04 17:09:04 +01:00
KennyTV 4353fc9f0b Minor change 2019-02-04 15:39:46 +01:00
KennyTV ca95932107 Always check for maintenance.admin perm as well 2019-02-04 15:22:36 +01:00
KennyTV 8c493c596c Add some aliases 2019-02-04 10:04:55 +01:00
KennyTV 8445f021f6 Fix typo 2019-02-03 17:48:37 +01:00
KennyTV b363f7ed37 Fixes, dump changes 2019-02-03 15:06:55 +01:00
KennyTV 389b00e89e Actually, noone likes hastebin 2019-02-03 14:24:44 +01:00
KennyTV a9f17f4861 One might say dumping a database's password isn't nice 🤔 2019-02-03 14:03:43 +01:00
KennyTV 6dc0500cdb Changes to config + small help fix 2019-02-03 13:29:51 +01:00
KennyTV de8370eb4b Auto config migration + fixes 2019-02-02 20:10:49 +01:00
KennyTV 5bcfd7a2a1 Beautiful new config system (💛 PSandro) 2019-02-02 15:18:22 +01:00
KennyTV b9f2203c7c Do update checks async 2019-02-01 13:23:25 +01:00
KennyTV ac5854ec0a Dump command response changes 2019-02-01 11:40:27 +01:00
KennyTV da6987cb53 Fixes + dump command 2019-02-01 11:21:38 +01:00
KennyTV 0022be942a Update issue template 2019-02-01 10:26:20 +01:00
KennyTV 94bc061c72 Merge pull request #24 from KennyTV/issue-template
Update issue templates
2019-02-01 10:24:41 +01:00
KennyTV 84aa4d7c69 Update issue templates 2019-02-01 10:24:05 +01:00
KennyTV 32c0550e5f Delete old issue template 2019-02-01 10:23:09 +01:00
KennyTV 17c6548dd2 Merge pull request #23 from PSandro/patch-1
fix typo
2019-02-01 10:20:03 +01:00
Sandro 2d2eef848a fix typo 2019-01-31 21:59:43 +01:00
KennyTV c6d86dd427 Minor change 2019-01-31 20:27:55 +01:00
KennyTV ecd8e3aa8a Whoops 2019-01-31 10:43:53 +01:00
KennyTV 7a6f1e981f Minor refactoring 2019-01-31 10:42:37 +01:00
KennyTV 85050fe395 Minor refactoring 2019-01-31 10:36:55 +01:00
KennyTV 24db266358 Load maintenance-icon from plugin folder, not server directory
Some minor refactoring
2019-01-30 15:12:51 +01:00
KennyTV 3563ff0f2d Fix database value loading 2019-01-30 14:23:46 +01:00
KennyTV a18e7cfc20 Velocity should be done (theoretically 🤔) 2019-01-29 10:33:42 +01:00
KennyTV f91b8a9982 Fixes to Velocity and Sponge 2019-01-28 22:13:47 +01:00
KennyTV c6c2fc0ffc Update README 2019-01-28 20:30:20 +01:00
KennyTV 01cc4a629d Merge remote-tracking branch 'origin/v3' into v3 2019-01-28 20:24:59 +01:00
KennyTV b5cb619399 Update API jar 2019-01-28 20:24:41 +01:00
KennyTV dd55cb3def Merge pull request #22 from PSandro/fix-script
Fix script
2019-01-28 18:15:17 +01:00
KennyTV 3516d143b8 Update README 2019-01-28 18:11:01 +01:00
Sandro 73c1790e79 run install script with skip-input arg on travis 2019-01-28 18:03:36 +01:00
Sandro 401879cdfe add skip-input arg 2019-01-28 18:03:36 +01:00
KennyTV f610a5e2e9 Update README 2019-01-28 17:59:28 +01:00
KennyTV 6fd0cd0803 Update README 2019-01-28 17:52:42 +01:00
KennyTV 188007d6e1 travis integration 2019-01-28 16:27:41 +01:00
KennyTV 9019b75248 Travis very sad :(( 2019-01-28 16:18:31 +01:00
KennyTV 71976a9216 Travis sad :( 2019-01-28 16:15:24 +01:00
KennyTV f03d420e31 Test Travis integration 2019-01-28 16:12:32 +01:00
KennyTV 41a49d1071 Some refactoring 2019-01-28 15:35:42 +01:00
KennyTV 331298a22c Add Maintenance-API.jar to ignored 2019-01-28 14:29:36 +01:00
KennyTV db7d9cc979 Actually get offline Sponge user 2019-01-26 20:59:40 +01:00
KennyTV b8a8388573 Listen to global reload event 2019-01-26 13:29:26 +01:00
KennyTV 62f6e9ba7c Merge branch 'master' of https://github.com/KennyTV/Maintenance into v3 2019-01-26 12:45:38 +01:00
KennyTV e24887ba45 Fix colors in messages in Sponge 2019-01-26 12:37:54 +01:00
KennyTV 7d70e27472 Merge branch dev into master 2019-01-26 11:16:12 +01:00
KennyTV 3d57a979f5 Velocity startup fix 2019-01-25 15:39:08 +01:00
KennyTV 3eb02d6964 Final touches to Sponge 2019-01-25 15:16:52 +01:00
KennyTV 3c5bde4a07 Properly do the uuid remove thingy 2019-01-25 13:44:56 +01:00
KennyTV c93fd06898 Command to remove whitelisted players via their uuid... except on Bungee ;( 2019-01-25 13:15:00 +01:00
KennyTV 2ae384daa5 Velocity command 2019-01-25 12:35:54 +01:00
KennyTV f2e6c9669c Start velocity
Some refactoring and minor improvements
2019-01-24 21:05:42 +01:00
KennyTV 7267e3e6a0 Use proper id when getting api instance 2019-01-23 17:10:29 +01:00
KennyTV ac7fdf5bc3 Single jars now work on their own as well
Minor cleanup
2019-01-23 16:18:59 +01:00
KennyTV 94837b3259 Create CONTRIBUTING.md
Create CONTRIBUTING.md
2019-01-23 10:50:41 +01:00
KennyTV 1244be40e1 Create CONTRIBUTING.md 2019-01-22 22:46:57 +01:00
KennyTV 284d56853c That was a space 2019-01-22 22:32:21 +01:00
KennyTV 5368b1778a Remove licence notice 2019-01-22 22:31:43 +01:00
KennyTV 597dbfeb64 It works! 2019-01-22 18:07:58 +01:00
KennyTV dc6e26ca7c Add copyright notice for funzees 2019-01-22 13:52:14 +01:00
KennyTV 9aad734635 Use YamlConfig (of Bungee) in every module
Fix tabcompletion on Bungee
Even if set to 0, make database calls 'only' every 500 milliseconds

Note that the configuration stuff might completely change again
2019-01-22 13:48:06 +01:00
KennyTV de4c520045 Small message change + merge dev 2019-01-21 14:54:46 +01:00
KennyTV 377f754b88 Merge branch 'dev' of https://github.com/KennyTV/Maintenance into 3.0 2019-01-21 14:51:17 +01:00
KennyTV 934fedf39a Fix NPE 2019-01-21 14:46:31 +01:00
KennyTV be133208a2 Don't create a random UUIDs on each ping (to test) 2019-01-21 14:36:24 +01:00
KennyTV b2c47c9c91 Tabcompletion 2019-01-18 15:19:26 +01:00
KennyTV b31c630c1b Add a small but nice warning 2019-01-17 12:04:55 +01:00
KennyTV 0797335934 Remove slp reference from main class 2019-01-15 16:17:55 +01:00
KennyTV 6d075c2a9a nevermind still dumb i guess i think maybe 2019-01-14 18:23:11 +01:00
KennyTV ef6109c206 Scheduler fix 2019-01-14 15:25:51 +01:00
KennyTV 05bba94e17 Some minor additions/changes 2019-01-14 15:11:54 +01:00
KennyTV e7d667d481 ... because I'm an idiot, obviously 2019-01-14 14:48:47 +01:00
KennyTV e1fc49f955 Small message fix 2019-01-14 14:36:35 +01:00
KennyTV 0d7a01a81b Javadoc 2019-01-14 14:32:07 +01:00
KennyTV 15f8e49ed9 Refactoring and more Sponge stuff 2019-01-14 14:27:26 +01:00
KennyTV 32c6ef23cd Refactoring 2019-01-13 20:05:48 +01:00
KennyTV 0eeb1ecd70 Some ground work for the Sponge part 2019-01-13 15:47:11 +01:00
KennyTV 6c55a22921 Version increase to 3.0-SNAPSHOT 2019-01-13 12:14:07 +01:00
KennyTV 0b3b212a67 Merge remote-tracking branch 'origin/master' into dev 2019-01-13 12:12:53 +01:00
KennyTV 68e729b823 Write plugin name without variable 2019-01-11 15:17:49 +01:00
KennyTV ccc557dc8c Set build name again 2019-01-11 15:14:45 +01:00
KennyTV f260377dcd Improve updater methods 2019-01-11 15:08:11 +01:00
KennyTV ea2ca734a1 Update README 2019-01-11 15:04:32 +01:00
KennyTV 44be0bec3b Merge pull request #17 from PSandro/maven-clean-clean
More maven cleanup
2019-01-09 21:29:14 +01:00
Sandro 4e12762b8f change parent.version to project.parent.version 2019-01-09 21:18:04 +01:00
Sandro 68bd84549d rename directories to fit maven module name 2019-01-09 21:17:15 +01:00
Sandro e57ee84836 remove custom module names 2019-01-09 21:15:48 +01:00
Sandro 7085a6b190 add script -> install ServerListPlus to local repository 2019-01-09 21:15:21 +01:00
KennyTV 9cc5564e23 Some minor refactoring 2019-01-07 20:28:12 +01:00
KennyTV 30f0cae65a Minor change 2019-01-04 11:04:05 +01:00
KennyTV 360e980900 Minor improvement 2018-12-29 21:41:06 +01:00
KennyTV a4bf41bffd Update README 2018-12-28 19:49:07 +01:00
KennyTV f340f5b51b Fix a typo 2018-12-26 12:16:38 +01:00
KennyTV aadf1daf6e Improve isNumeric method 2018-12-21 18:07:30 +01:00
KennyTV 75f27cbd6a Some javadoc changes 2018-12-21 15:00:14 +01:00
KennyTV 8517624bd9 Pom clean up 2018-12-21 14:43:53 +01:00
KennyTV cc0a7205d5 Set api version in plugin.yml 2018-12-19 10:28:51 +01:00
KennyTV 8633b7e2de Version increase to 2.5.3-SNAPSHOT 2018-12-19 10:21:38 +01:00
KennyTV 747757fa5e Language fix 2018-12-17 18:26:07 +01:00
KennyTV d8aac30c3a 2.5.2 Release 2018-12-17 10:10:56 +01:00
KennyTV e8e9419758 Version increase to 2.5.2 2018-12-16 18:16:28 +01:00
KennyTV a3e4fb4198 Small fix, whoopsie? 2018-12-16 18:14:32 +01:00
KennyTV 068ca78259 Added last Portuguese messages 2018-12-16 18:06:23 +01:00
KennyTV bbef35d793 Add Portuguese translations 2018-12-12 10:41:23 +01:00
KennyTV 056a6f91a4 Kick non permitted players when detecting server change from MySQL 2018-12-10 19:33:55 +01:00
KennyTV 84daea05b2 Fix maintenance value with MySQL enabled not loading until the first ping 2018-12-10 19:20:06 +01:00
KennyTV c63a32f44b Make experimental MySQL stuff not so experimental anymore 2018-12-09 10:49:06 +01:00
KennyTV 196abfc5ce Fix maintenance icon for 1.13+ servers 2018-12-08 18:39:40 +01:00
KennyTV ffce4f26f2 Experimental single server database stuff 2018-12-06 17:38:57 +01:00
KennyTV 9c9cd79a20 pom 2018-12-06 11:58:20 +01:00
KennyTV 5790b920b3 pom 2018-12-06 11:57:34 +01:00
KennyTV ad38a56657 Experimental single server database stuff 2018-12-06 11:47:43 +01:00
KennyTV dc03eef9c6 Change config header 2018-12-06 10:37:59 +01:00
KennyTV 266019b6ea Remove some more unnecessary reloads 2018-12-06 10:32:08 +01:00
KennyTV 4c7deca61b Properly fix the last thingy 2018-12-06 10:22:02 +01:00
KennyTV 997366d5e2 Fix 2018-12-05 07:03:26 +01:00
KennyTV 1ed9ad4c9f Don't reload files when toggling maintenance
Update bStats, optimize it a bit... and fix it forgetting some config values, I guess 🤔
2018-12-03 16:58:05 +01:00
KennyTV ccee1db149 Add debug mode 2018-11-25 16:47:58 +01:00
KennyTV 175c608c11 Minor message change 2018-11-25 16:35:09 +01:00
KennyTV ea9a40a297 More french translations, thanks to Spigot user Zendrique 2018-11-23 19:58:17 +01:00
KennyTV 2f1266cdd0 Some tweaks to messages 2018-11-23 18:39:59 +01:00
KennyTV e8672ddaa2 Partially include french translations!
Thanks to Spigot user Zendrique
Still relies on 2.4 format, so some messages are missing and unsorted
2018-11-23 13:34:07 +01:00
KennyTV 8cd71508f8 Version increase to 2.5.2-SNAPSHOT 2018-11-20 15:56:35 +01:00
KennyTV f9fafdd642 Hotfix 2.5.1 2018-11-17 16:57:11 +01:00
KennyTV 1c21dcaddd File loading fix 2018-11-17 16:55:17 +01:00
KennyTV 8174154394 2.5 Release 2018-11-17 11:46:04 +01:00
KennyTV ac1213336c 2.5 API 2018-11-17 11:44:28 +01:00
KennyTV c7d7c4557b Version increase to 2.5 2018-11-17 11:43:43 +01:00
KennyTV ef7aa73031 Some final fixes and changes 2018-11-17 11:41:51 +01:00
KennyTV 1a60a76fd5 Check for other kick reasons 2018-11-16 22:23:58 +01:00
KennyTV c421b96e3b Message changes 2018-11-16 22:08:35 +01:00
KennyTV 1362bfcecb API change 2018-11-10 22:08:29 +01:00
KennyTV fcde435d90 Make the help message a little fancier 2018-11-10 17:38:41 +01:00
KennyTV 2570fc90e7 Some more fixes 2018-11-10 16:50:10 +01:00
KennyTV a6eed677ce Maintenance status command + some more minor changes 2018-11-10 15:08:32 +01:00
KennyTV 3d8378bcd7 Some fixes and changes 2018-11-09 23:20:34 +01:00
KennyTV e1ae515d23 Command 2018-11-09 21:14:32 +01:00
KennyTV eed4f0e1dd pom changes 2018-11-07 21:36:29 +01:00
KennyTV 34d8e055de Timer commands for single server maintenance 2018-11-07 21:32:08 +01:00
KennyTV bc91301c11 API changes 2018-11-07 21:31:49 +01:00
KennyTV e60994eb92 Timers for single server maintenance
Todo: Implementation in command
2018-11-07 20:02:59 +01:00
KennyTV cf61a8a6e1 Some improvements to messages and message handling 2018-11-06 11:01:04 +01:00
KennyTV c7e981fc25 Improve version check handling 2018-11-05 23:02:46 +01:00
KennyTV 76d0f88dbd Improve version check handling 2018-11-05 22:58:12 +01:00
KennyTV d789fcaf61 Further single server maintenance stuff 2018-11-05 21:24:56 +01:00
KennyTV 8b1450a334 Dont save and get Spigot maintenance servers from sql for now 2018-11-04 14:43:47 +01:00
KennyTV beb782b50a Some message changes 2018-10-19 14:21:21 +02:00
KennyTV b20d72860e Some single server maintenance stuff I did during a course at university ¯\_(ツ)_/¯ 2018-10-19 12:08:37 +02:00
KennyTV 82a5c04477 WIP: Add possibility to set single servers to maintenance 2018-10-12 23:17:46 +02:00
KennyTV cfe6396267 Restructured language files 2018-10-02 12:15:08 +02:00
KennyTV 0ae9c0ec13 WIP: Add possibility to set single servers to maintenance 2018-10-02 11:56:30 +02:00
KennyTV 8787f7277a Remove more or less deprecated Guava usages 2018-09-30 11:29:48 +02:00
KennyTV 105a7ddd56 Add multiple language support 2018-09-28 13:22:55 +02:00
KennyTV 436ae975c8 Version increase to 2.5-SNAPSHOT
Increase from 2.4.1-SNAPSHOT as bigger feature updates are planned
2018-09-28 12:42:06 +02:00
KennyTV 12c82f03c5 Add language-de 2018-09-28 12:00:40 +02:00
KennyTV 514fd6da1f Make SenderInfo an interface instead of an abstract class 2018-09-27 10:14:29 +02:00
KennyTV c10dc68a1c Fix starttimer command not working
Remove slf4j shade for now
2018-09-27 09:57:56 +02:00
KennyTV 076c8970b6 Shade slf4j to fix compatibility with plugins using older Hikari dependencies 2018-09-26 11:11:56 +02:00
KennyTV 23ef2c7879 Version increase to 2.4.1-SNAPSHOT
Update ProtocolLib dependency to newest release
2018-09-22 19:20:55 +02:00
KennyTV 654c5feed2 2.4 Release 2018-09-17 10:21:17 +02:00
KennyTV d426d03eb2 2.4 Release API 2018-09-17 10:17:44 +02:00
KennyTV ded6b69ebf Prepare for 2.4 Release 2018-09-17 10:16:23 +02:00
KennyTV 393c25ce77 Some final fixes and changes
Move kickmessage back to config
2018-09-16 22:36:12 +02:00
KennyTV 5a7bfc2921 Update dependencies 2018-09-13 10:43:09 +02:00
KennyTV 9fa317a662 Fix raw color saving in config when upgrading from a version lower than 2.3 2018-09-08 12:29:10 +02:00
KennyTV 3fa20a2c69 Spigot Runnable fix 2018-09-08 12:13:47 +02:00
KennyTV f1f48fcfdb Fix Bungee config not updating 2018-09-08 12:00:21 +02:00
KennyTV 64a25bc980 Add timer variable for the pingmessage
Have broadcasts for timers be set for seconds instead of just minutes + better formatting
Some language fixes
2018-09-07 22:52:20 +02:00
KennyTV c66be61fd2 WIP: Add timer variable for the pingmessage
WIP: Have broadcasts for timers be set for seconds instead of just minutes + better formatting
2018-08-29 00:42:00 +02:00
KennyTV b067ec1d36 Language fixes and changes 2018-08-26 17:56:31 +02:00
KennyTV cea6207662 Switch messages to language file + small fixes 2018-08-26 12:34:28 +02:00
KennyTV b4da98a9a6 Change javadoc message to read the new config field 2018-08-26 11:50:08 +02:00
KennyTV 7467ae9f5f Switch some more messages to language file 2018-08-26 11:49:13 +02:00
KennyTV 1d9313a2c1 Switch some messages to language file 2018-08-25 12:37:23 +02:00
KennyTV 7c58dbd96e Prepare new language file 2018-08-25 12:19:01 +02:00
KennyTV aaaa05ea02 Change helpmessage 2018-08-25 11:41:33 +02:00
KennyTV 76d8076172 Don't enable/disable maintenance mode if it's already in the goal's state 2018-08-25 11:39:49 +02:00
KennyTV 690a89d925 Add possibility to show the default playercount 2018-08-22 20:11:24 +02:00
KennyTV 2cfd53cb89 Relocate HikariCP dependency 2018-08-22 19:08:20 +02:00
KennyTV f1ca524783 Don't spam update notifications on every single join
Also, minor cleanup #3
2018-08-21 21:05:48 +02:00
KennyTV e9f1b723fd Minor cleanup #2 2018-08-21 21:01:12 +02:00
KennyTV 288ab56403 Minor cleanup 2018-08-21 20:58:59 +02:00
KennyTV bc6d1a00db Add variables to show normal playercount 2018-08-21 20:53:15 +02:00
KennyTV 7b7c0bbda6 Whoops 2018-08-17 12:37:49 +02:00
KennyTV ba90b8ad6f Version increase to 2.4-SNAPSHOT 2018-08-17 12:36:08 +02:00
KennyTV a08c0a86a3 2.3.1 Release
Hotfix before the release
2018-08-17 12:30:01 +02:00
KennyTV 57ad385cee Quick hotfix for the 2.3.1 Release
When enabling maintenance on one proxy with MySQL enabled, the other ones will now also kick all non permitted players and switch their ServerListPlus state
2018-08-17 11:29:28 +02:00
KennyTV 9c31d929a2 Minor changes 2018-08-16 19:05:44 +02:00
KennyTV 97f317b396 2.3.1 Release 2018-08-16 17:56:28 +02:00
KennyTV 55da028e56 2.3.1 Release 2018-08-16 17:54:57 +02:00
KennyTV 9fb8bc38b2 Fix 2018-08-15 11:54:35 +02:00
KennyTV ccc686cc10 Only check the mysql delay if it's at least a second 2018-08-15 11:11:25 +02:00
KennyTV 06e53921c0 Fix permission checks for help page 2018-08-11 11:10:25 +02:00
KennyTV 79abdc3841 Fix updated config being overwritten again 2018-08-08 11:56:32 +02:00
KennyTV f8e7bf9d7b Change some javadocs 2018-08-07 23:31:02 +02:00
KennyTV ae9811a198 Return empty string for pingmessages if config list is empty 2018-08-07 23:04:09 +02:00
KennyTV faf4f490bf Remove unnecessary (second) result closing 2018-08-07 22:58:06 +02:00
KennyTV 8d9e595082 Remove unused method 2018-08-07 22:49:22 +02:00
KennyTV 8544c0b95b Replace deprecated ProtocolLib packet 2018-08-07 14:55:19 +02:00
KennyTV bf5dfb3c1a Some pom changes 2018-08-07 13:51:59 +02:00
KennyTV 749787b9ff Only show the commands you have the permission to execute in the helppage 2018-08-06 21:12:36 +02:00
KennyTV 630ef694db Fix config updating unnecessary value in Spigot version 2018-07-27 12:34:09 +02:00
KennyTV 793d763e25 Minor improvement 2018-07-27 12:28:07 +02:00
KennyTV cafe25101a Minor improvement 2018-07-27 11:50:19 +02:00
KennyTV 4e99bef678 Move license and whitelistedplayers file to core module 2018-07-25 00:29:06 +02:00
KennyTV d29c41e805 Fix MySQL millisecondsToCheck variable 2018-07-24 22:29:03 +02:00
KennyTV bbd8b131e8 Only make a request to the database at least x seconds after the last one 2018-07-23 11:52:30 +02:00
KennyTV f3d5c4b66b Add warning and backup string if config value is null 2018-07-23 11:10:16 +02:00
KennyTV ef60dad626 Add warning and backup string if config value is null 2018-07-23 11:09:08 +02:00
KennyTV 98537ac168 Updated BungeeCord dependency to 1.13-SNAPSHOT 2018-07-21 11:02:55 +02:00
KennyTV 91d3e9756a Version increase to 2.3.1-SNAPSHOT 2018-07-18 15:50:35 +02:00
KennyTV 98e62a0576 2.3 Release 2018-07-17 11:45:43 +02:00
KennyTV 3a6860109b Version increase for the 2.3 Release 2018-07-17 11:41:03 +02:00
KennyTV 6180a5123c Minor cleanup 2018-07-16 21:52:27 +02:00
KennyTV 476b753baa The whitelist command now also shows the UUID of the player 2018-07-16 20:25:05 +02:00
KennyTV 32b9ab48c3 Changed help message order 2018-07-16 18:04:14 +02:00
KennyTV 7788ca6e5e Fixed wrong command descriptions 2018-07-16 13:22:46 +02:00
KennyTV 988213c981 Uncommented new help messages 2018-07-16 13:07:59 +02:00
KennyTV a0c8dbdc22 Added missing motd command permission 2018-07-14 22:27:20 +02:00
KennyTV 65e0202312 Added motdlist command 2018-07-09 16:33:51 +02:00
KennyTV 1a47dd7c17 Reworked setmotd command 2018-07-09 15:49:54 +02:00
KennyTV 2117147d76 Removed setmotd command 2018-07-08 11:29:20 +02:00
KennyTV 7cfd8d4412 Config fix 2018-07-08 11:25:47 +02:00
KennyTV 3bd96e02ad Version increase to 2.3-SNAPSHOT 2018-07-08 11:20:18 +02:00
KennyTV d6a572b27c Added multiple pingmessages + minor improvements 2018-07-08 10:54:51 +02:00
KennyTV 90f241b7fd Minor code change 2018-06-18 11:17:47 +02:00
KennyTV f45b75f07a Minor improvement 2018-06-18 11:17:06 +02:00
KennyTV 3d771d4b20 Fixed a problem with the setmotd command 2018-06-17 20:57:50 +02:00
KennyTV 11ff1c6774 Fixed a typo 2018-06-17 20:27:01 +02:00
KennyTV abdbec1134 Removed unused method 2018-06-17 19:58:21 +02:00
KennyTV e1b4be58ab Small logic change 2018-06-17 18:51:35 +02:00
KennyTV 9c80954773 Added permission per subcommand 2018-06-17 18:40:47 +02:00
KennyTV 17a911d50b Message change 2018-06-17 18:29:58 +02:00
KennyTV df62ebdad4 Version increase to 2.2.3-SNAPSHOT 2018-06-17 18:06:59 +02:00
KennyTV 5014abc21c Removed Spigot dependency from Core module 2018-06-17 14:36:18 +02:00
KennyTV 01f856c3aa 2.2.2 Release 2018-06-17 11:24:35 +02:00
KennyTV 57a8aafbf4 2.2.2 Release 2018-06-17 11:22:43 +02:00
KennyTV 53ef1def47 2.2.2 Release 2018-06-17 11:21:10 +02:00
KennyTV 5288bd2aec Maintenance icon fix and reload command message change 2018-06-14 12:35:10 +02:00
KennyTV 1ea04e84b3 Made the loading of the maintenance icon more structured 2018-06-14 12:10:33 +02:00
KennyTV 74bff29a05 Api fix 2018-06-10 10:44:42 +02:00
KennyTV d73a84a764 Removed old config comment 2018-06-09 11:26:58 +02:00
KennyTV 7048e775ef Version increase to 2.2.2-SNAPSHOT
Some minor pom changes
2018-06-09 10:14:21 +02:00
KennyTV 482ba146dc Merge remote-tracking branch 'origin/master' 2018-04-23 11:39:04 +02:00
KennyTV f02582705f Some javadoc and comment changes 2018-04-23 11:38:51 +02:00
KennyTV ea132630c6 2.2.1 release 2018-04-17 04:46:22 +02:00
KennyTV 058342222a Project/pom changes 2018-04-16 20:54:21 +02:00
KennyTV 032d94a7c5 Updated API 2018-04-16 19:50:50 +02:00
KennyTV 182da9da14 Comment line change 2018-04-16 16:35:13 +02:00
KennyTV 59cc67b73d MySQL change 2018-04-16 15:31:50 +02:00
KennyTV 21b74a06f4 MySQL fix 2018-04-16 14:39:40 +02:00
KennyTV 5a03398bec More cleanup 2018-04-16 14:18:19 +02:00
KennyTV fcd2757868 Fixed doc typo 2018-04-15 15:07:19 +02:00
KennyTV fdaa62c569 Various stuff 2018-04-15 13:53:42 +02:00
KennyTV f092a1ecc7 Setmotd fixes 2018-04-15 13:38:21 +02:00
KennyTV 40a9b0d0ee Setmotd fixes 2018-04-15 13:37:07 +02:00
KennyTV cf504c036b Added setmotd command 2018-04-15 13:17:58 +02:00
KennyTV 016f533a29 Create ISSUE_TEMPLATE.md 2018-04-14 19:09:34 +02:00
KennyTV d7ebcdbd77 Added import 2018-04-14 18:46:24 +02:00
KennyTV 710d152bb3 MySQL improvements 2018-04-14 12:25:57 +02:00
KennyTV 016ce19b3c Fixes 2018-04-14 12:06:29 +02:00
KennyTV c7dd702849 Small ServerListPlus integration and command fix 2018-04-14 12:00:46 +02:00
KennyTV 99ada94f32 Fixes 2018-04-13 23:28:15 +02:00
KennyTV 108d20098f Code cleanup 2018-04-13 22:56:41 +02:00
KennyTV e960471ee3 Automatically create sql table if non existing 2018-04-13 20:12:32 +02:00
KennyTV 68a9f3ebfc Moved resources 2018-04-13 19:26:45 +02:00
KennyTV 6cd3088da4 Added license and bumped version to 2.2.1-SNAPSHOT 2018-04-13 19:24:16 +02:00
KennyTV 069f40f2ca Updated README 2018-04-05 23:50:36 +02:00
KennyTV 246aaf4b26 Removed first commit errors 2018-04-05 23:45:39 +02:00
KennyTV ff73fb0e08 Code commit 2018-04-05 23:43:25 +02:00
KennyTV c7fe3e2c0e Update README.md 2018-03-17 11:43:36 +01:00
KennyTV 4578cd9695 Update README.md 2018-03-17 10:30:46 +01:00
KennyTV 595f9a0e69 Update README.md 2018-03-06 21:53:08 +01:00
KennyTV ee7662f96b Update README.md 2018-03-06 21:52:14 +01:00
KennyTV 93eeba64c0 Add files via upload 2018-03-06 21:39:49 +01:00
KennyTV 975ae49594 Create README.md 2018-03-06 21:39:02 +01:00
KennyTV 58562fdb53 Init 2018-02-16 18:39:21 +01:00
146 changed files with 2211 additions and 4235 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
.gitea/CODEOWNERS linguist-detectable=false
+3
View File
@@ -0,0 +1,3 @@
# Pull requests request review from the eligible staff team(s).
# One approval from either an Admin or Developer satisfies branch protection.
* @trueog/Admins @trueog/Developers
+3 -49
View File
@@ -1,52 +1,6 @@
# Maintenance Changelog
This file contains update logs for this project. The top may contain a `Unreleased` section, gathering update logs for a future update during development.
## 5.1.1 - October 17th 2026
### Changed
- Velocity/Bungee: Timer commands now accept `global` as the server argument, with an optional mode: `/maintenance starttimer global [mode] <time>`, `/maintenance scheduletimer global [mode] <time> <duration>`, `/maintenance endtimer global <time>`
- Timer durations now also accept days, e.g. `2d` or `1d12h`
- Folia: Now supports timers
### Fixed
- Folia: Fixed the update check stalling the global region thread
- Velocity/Bungee: Fixed the `redis.enabled` confg key
- Velocity/Bungee: `/maintenance reload` now keeps the maintenance status from Redis instead of overriding it with the local config
- Velocity/Bungee: Fixed `/maintenance aborttimer` tab completion not suggesting servers with running timers
---
## 5.1.0 - May 17th 2026
### Changed
- Made Discord webhooks configurable separately from command messages, including a new `%TIMESTAMP%` parameter for Discord timestamps (e.g. `<t:%TIMESTAMP%:R>`)
### Fixed
- Velocity/Bungee: Fixed proxied-maintenance-servers config loading
---
## 5.0.0 - April 17th 2026
This update removes *a lot* of legacy code, making the code-base a great bit more simple and a lot more performant.
### Requirements
- The Paper part now **requires at least Paper 1.20.1** and no longer supports Spigot
- The universal jar has been removed. Each platform now has its own jar (that is as small as possible)
- Maintenance now **requires at least Java 21**
### Changed
- **Added mode-based maintenance messages** for `ping-message`, `player-count-message`, and `player-list-hover-message`
- You can have different MOTDs depending on the pre-configured mode, e.g. a generic `default` or one for `upcoming-release`.
- Updated proxy/global toggle syntax: `/maintenance on [mode]`
- For proxy servers: `/maintenance on global [mode]`, `/maintenance on <server> [mode]`
- Other updated commands: `/maintenance motd [timer] [mode]`, `/maintenance setmotd [timer] [mode] ...`, `/maintenance removemotd [timer] [mode] ...`
- **Added `webhook` config option for Discord webhooks** when the maintenance status changes, a timer is started or a join is blocked
- **Added `%REASON%` variable to messages**, using the `active-reason` config option. This allows for dynamic MOTD and other messages via a quick command without modifying the messages themselves
- Can be changed via the `/maintenance setreason <reason>` command
- **Added `/maintenance status` command** on Paper/Sponge to display the current maintenance status as well as any running start or end timers.
- Velocity/Bungee: **The existing timer command now displays start and end timers** for proxied servers.
- Velocity/Bungee: **Replaced `mysql` section with `redis`**. This is a more suitable database for such reading and sharing of data and no longer means some server pings can take multiple seconds, if you have multiple proxies linked
### Fixed
- Velocity/Bungee: Fixed the `/maintenance schedule` command for single servers having swapped time arguments
---
## 4.3.0 - September 17th 2024
### Changed
@@ -110,8 +64,8 @@ This update removes *a lot* of legacy code, making the code-base a great bit mor
### Changed
* Added support for hex colors in messages and replaced the component parsing with adventure-minimessage
* This means that section symbols (`§`) are no longer the intended/supported format
* You can use the following page to edit and preview formatted text: https://webui.advntr.dev/
* You can find full documentation on the format (including normal colors and formatting, rgb, click/hover events, and more) here: https://docs.papermc.io/adventure/minimessage/format/
* You can use the following page to edit and preview formatted text: https://webui.adventure.kyori.net/
* You can find full documentation on the format (including normal colors and formatting, rgb, click/hover events, and more) here: https://docs.adventure.kyori.net/minimessage/format
* Your config and language file will be updated to the new format automatically, you won't have to change anything manually!
* Note that the player count and player count hover messages do not support rgb colors
* Updated Sponge module to SpongeAPI v8 (Minecraft 1.15+)
@@ -373,4 +327,4 @@ This update removes *a lot* of legacy code, making the code-base a great bit mor
### Fixed
* Fixed some permission and message bugs
* Fixed problems with adding and removing players from the maintenance whitelist
* Fixed update checks
* Fixed update checks
-14
View File
@@ -1,14 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
cooldown:
default-days: 7
directory: "/"
schedule:
interval: "monthly"
- package-ecosystem: "gradle"
cooldown:
default-days: 7
directory: "/"
schedule:
interval: "monthly"
+6 -8
View File
@@ -7,22 +7,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v4
- uses: gradle/actions/wrapper-validation@v3
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v6
- name: Set up JDK 21
uses: actions/setup-java@v6
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: 21
java-version: 17
distribution: 'temurin'
- name: Build with Gradle
run: ./gradlew build
- name: Upload a Build Artifact
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: Maintenance Files
path: build/libs
+2 -2
View File
@@ -14,7 +14,7 @@ Its features include:
* Nearly all messages are editable via the language file, given in a multitude of different languages
* Features specifically for Bungee/Velocity
* Only want to enable maintenance on a single server? You can also do so by using the `/maintenance <on/off> <servername>` command
* Link multiple proxy instances through a Redis connection, so you don't have to change maintenance status or whitelisted players on each proxy by hand
* Link multiple proxy instances through a MySQL database connection, so you don't have to change maintenance on each proxy by hand
* Use PlaceholderAPI placeholders with the [**MaintenanceAddon**](https://hangar.papermc.io/kennytv/MaintenanceAddon) (for Velocity and Bungee)
A full list of commands, permissions and configuration options can be found in the wiki listed below.
@@ -33,7 +33,7 @@ Join [our Discord](https://discord.gg/vGCUzHq) if you want to get the proofreade
Adding translations for languages not yet listed is always appreciated as well!
## Compiling
To create a working jar yourself, simply clone the project and compile it with Gradle (`gradlew build`). To compile, you need a JDK 21+ (although it targets 17).
To create a working jar yourself, simply clone the project and compile it with Gradle (`gradlew build`).
## License
This project is licensed under the [GNU General Public License v3](LICENSE.txt).
+24
View File
@@ -0,0 +1,24 @@
plugins {
id("com.gradleup.shadow")
}
// Shade and relocate adventure in an extra module, so that common/the rest can directly depend on a
// relocated adventure without breaking native platform's adventure usage with project wide relocation
tasks {
shadowJar {
relocate("net.kyori", "eu.kennytv.maintenance.lib.kyori")
}
build {
dependsOn(shadowJar)
}
}
dependencies {
api(libs.bundles.adventure) {
exclude("net.kyori", "adventure-api")
exclude("net.kyori", "adventure-bom")
exclude("com.google.code.gson", "gson")
}
}
publishShadowJar()
@@ -0,0 +1,20 @@
plugins {
id("com.gradleup.shadow")
}
tasks {
shadowJar {
relocate("net.kyori", "eu.kennytv.maintenance.lib.kyori")
}
build {
dependsOn(shadowJar)
}
}
dependencies {
api(libs.adventurePlatformBukkit) {
exclude("net.kyori", "adventure-api")
}
}
publishShadowJar()
@@ -0,0 +1,20 @@
plugins {
id("com.gradleup.shadow")
}
tasks {
shadowJar {
relocate("net.kyori", "eu.kennytv.maintenance.lib.kyori")
}
build {
dependsOn(shadowJar)
}
}
dependencies {
api(libs.adventurePlatformBungee) {
exclude("net.kyori", "adventure-api")
}
}
publishShadowJar()
+3 -1
View File
@@ -4,7 +4,9 @@ plugins {
dependencies {
api(projects.maintenanceApi)
compileOnly(libs.adventureApi)
compileOnly(projects.adventure.adventureApi) {
targetConfiguration = "shadow"
}
}
java {
@@ -18,26 +18,23 @@
package eu.kennytv.maintenance.api.proxy;
import eu.kennytv.maintenance.api.Maintenance;
import java.util.Set;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
public interface MaintenanceProxy extends Maintenance {
/**
* Enables/disables maintenance mode on a proxied server.
* If enabled, all non-permitted players will be kicked.
* If Redis is enabled, it will also be written into the database.
* If MySQL is enabled, it will also be written into the database.
*
* @param server server to apply the maintenance status to
* @param maintenance true to enable, false to disable maintenance mode
* @return true if the mode was changed
* @see #getServer(String)
*/
boolean setMaintenanceToServer(Server server, boolean maintenance, @Nullable String mode);
default boolean setMaintenanceToServer(final Server server, final boolean maintenance) {
return setMaintenanceToServer(server, maintenance, null);
}
boolean setMaintenanceToServer(Server server, boolean maintenance);
/**
* @param server server to check
@@ -62,18 +59,6 @@ public interface MaintenanceProxy extends Maintenance {
@Nullable
Server getServer(String server);
/**
* Returns a wrapped {@link Server} object of a proxied server, or a dummy server if not registered.
*
* @param serverName name of the proxied server
* @return wrapped server object, or a dummy if not registered
* @see Server#isRegisteredServer()
*/
default Server getServerOrDummy(final String serverName) {
final Server server = getServer(serverName);
return server != null ? server : new DummyServer(serverName);
}
/**
* Returns the currently registered proxied servers.
*
@@ -17,7 +17,7 @@
*/
package eu.kennytv.maintenance.api.proxy;
import net.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
/**
* Wrapper for a proxied server.
@@ -18,7 +18,6 @@
package eu.kennytv.maintenance.api;
import eu.kennytv.maintenance.api.event.manager.EventManager;
import org.jetbrains.annotations.Nullable;
public interface Maintenance {
@@ -26,18 +25,13 @@ public interface Maintenance {
* Enables/disables maintenance mode.
* If enabled, all non-permitted players will be kicked.
* <p>
* If using the BungeeCord version and Redis is enabled,
* If using the BungeeCord version and MySQL is enabled,
* it will also be written into the database.
* </p>
*
* @param maintenance true to enable, false to disable maintenance mode
* @param mode mode, used for custom messages
*/
void setMaintenance(boolean maintenance, @Nullable String mode);
default void setMaintenance(boolean maintenance) {
setMaintenance(maintenance, null);
}
void setMaintenance(boolean maintenance);
/**
* @return true if maintenance is currently enabled
@@ -19,39 +19,16 @@ package eu.kennytv.maintenance.api;
import java.util.Map;
import java.util.UUID;
import org.jetbrains.annotations.Nullable;
public interface Settings {
/**
* Returns whether maintenance is currently enabled.
* Note that the value might need a few seconds to update, if you're on BungeeCord with MySQL enabled
*
* @return true if maintenance is currently enabled
*/
boolean isMaintenance();
/**
* Returns the current active maintenance mode, or null is set to default.
* Used when getting MOTD/player count messages.
*
* @return the current active maintenance mode, or null if set to default
*/
@Nullable String activeMode();
/**
* Returns the reason for the current active mode.
*
* @return variable reason for the current active mode, or empty if no reason is set
*/
String activeReason();
/**
* Sets the reason for the current active mode, used in %REASON% message placeholders.
*
* @param reason reason to set for the current active mode, or null to remove the reason
*/
void setActiveReason(@Nullable String reason);
/**
* @return true if custom ping messages during maintenance should be used
*/
@@ -96,8 +73,8 @@ public interface Settings {
*
* @param name name of the player to remove with original lower-/uppercase letters
* @return true if removing the player was successful
* @see #removeWhitelistedPlayer(UUID)
* @deprecated if a player changes their name, the list will still contain the old one
* @see #removeWhitelistedPlayer(UUID)
*/
@Deprecated
boolean removeWhitelistedPlayer(String name);
@@ -22,5 +22,17 @@ import eu.kennytv.maintenance.api.event.manager.MaintenanceEvent;
/**
* Notification event fired when maintenance mode has been changed.
*/
public record MaintenanceChangedEvent(boolean isMaintenance) implements MaintenanceEvent {
public final class MaintenanceChangedEvent implements MaintenanceEvent {
private final boolean maintenance;
public MaintenanceChangedEvent(final boolean maintenance) {
this.maintenance = maintenance;
}
/**
* @return true if maintenance has been enabled, false otherwise
*/
public boolean isMaintenance() {
return maintenance;
}
}
+1 -2
View File
@@ -8,6 +8,5 @@ repositories {
dependencies {
// version must be manually kept in sync with the one in root project settings.gradle.kts
implementation("com.gradleup.shadow:shadow-gradle-plugin:9.6.1")
implementation("com.gradleup.nmcp:com.gradleup.nmcp.gradle.plugin:1.6.2")
implementation("com.gradleup.shadow", "shadow-gradle-plugin", "8.3.9")
}
+5 -1
View File
@@ -6,12 +6,12 @@ import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.named
import java.io.ByteArrayOutputStream
fun Project.publishShadowJar() {
configurePublication {
artifact(tasks["shadowJar"])
artifact(tasks["sourcesJar"])
artifact(tasks["javadocJar"])
}
}
@@ -34,3 +34,7 @@ fun Project.latestCommitHash(): String {
commandLine = listOf("git", "rev-parse", "--short", "HEAD")
}.standardOutput.asBytes.get().toString(Charsets.UTF_8).trim()
}
fun JavaPluginExtension.javaTarget(version: Int) {
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
}
@@ -2,7 +2,6 @@ plugins {
`java-library`
`maven-publish`
signing
id("com.gradleup.nmcp")
}
tasks {
@@ -11,7 +10,7 @@ tasks {
val ver = project.version.toString()
val desc = project.description
filesMatching(listOf("plugin.yml", "bungee.yml", "META-INF/sponge_plugins.json")) {
expand(mapOf("version" to ver, "description" to desc))
expand("version" to ver, "description" to desc)
}
}
javadoc {
@@ -28,10 +27,8 @@ tasks {
}
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
javaTarget(8)
withSourcesJar()
withJavadocJar()
}
signing {
@@ -48,11 +45,6 @@ publishing {
name.set("Maintenance")
description.set("Paper plugin to enable maintenance mode on your Minecraft server.")
url.set("https://github.com/kennytv/Maintenance")
scm {
url.set("https://github.com/kennytv/Maintenance")
connection.set("scm:git:https://github.com/kennytv/Maintenance.git")
developerConnection.set("scm:git:ssh://git@github.com/kennytv/Maintenance.git")
}
licenses {
license {
name.set("GNU GPLv3")
@@ -67,4 +59,15 @@ publishing {
}
}
}
}
if (!name.startsWith("adventure")) {
repositories.maven {
name = "OSSRH"
url = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")
credentials {
username = System.getenv("OSSRH_USERNAME")
password = System.getenv("OSSRH_PASSWORD")
}
}
}
}
@@ -1,5 +1,6 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.jvm.tasks.Jar
import org.gradle.kotlin.dsl.named
plugins {
id("maintenance.base-conventions")
@@ -23,10 +24,6 @@ tasks {
publishShadowJar()
fun ShadowJar.configureRelocations() {
relocate("com.zaxxer.hikari", "eu.kennytv.maintenance.lib.hikari")
relocate("org.bstats", "eu.kennytv.maintenance.lib.bstats")
// Proxy
relocate("redis.client", "eu.kennytv.maintenance.lib.redis.client")
relocate("org.json", "eu.kennytv.maintenance.lib.json")
relocate("org.apache.commons.pool2", "eu.kennytv.maintenance.lib.apache.commons.pool2")
}
+6 -21
View File
@@ -1,10 +1,9 @@
import org.gradle.api.plugins.JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME
import org.gradle.api.plugins.JavaPlugin.TEST_RUNTIME_ONLY_CONFIGURATION_NAME
plugins {
base
id("eclipse")
id("maintenance.build-logic")
id("com.gradleup.nmcp.aggregation") version "1.6.2"
}
allprojects {
@@ -15,14 +14,17 @@ allprojects {
val platforms = setOf(
projects.maintenancePaper,
projects.maintenanceBungee,
projects.maintenanceSponge,
projects.maintenanceVelocity
).map { it.path }
val special = setOf(
projects.maintenance,
projects.maintenanceApi,
projects.maintenanceApiProxy
projects.maintenanceApiProxy,
projects.adventure,
projects.adventure.adventureApi,
projects.adventure.adventurePlatformBukkit,
).map { it.path }
subprojects {
@@ -35,22 +37,5 @@ subprojects {
dependencies {
TEST_IMPLEMENTATION_CONFIGURATION_NAME(rootProject.libs.bundles.junit)
TEST_IMPLEMENTATION_CONFIGURATION_NAME(rootProject.libs.snakeyaml)
TEST_RUNTIME_ONLY_CONFIGURATION_NAME("org.junit.platform:junit-platform-launcher")
}
}
dependencies {
allprojects {
nmcpAggregation(project(path))
}
}
nmcpAggregation {
centralPortal {
username = System.getenv("MAVEN_CENTRAL_USERNAME")
password = System.getenv("MAVEN_CENTRAL_PASSWORD")
publishingType = "USER_MANAGED"
publicationName = "maintenance:$version"
publishingTimeout = java.time.Duration.ZERO
}
}
-19
View File
@@ -1,19 +0,0 @@
dependencies {
implementation(projects.maintenanceCoreProxy)
implementation(libs.bstatsBungee)
compileOnly(libs.bungee)
}
tasks {
shadowJar {
relocate("net.kyori", "eu.kennytv.maintenance.lib.kyori")
}
}
dependencies {
api(libs.bundles.adventureBungee) {
exclude("com.google.code.gson", "gson")
exclude("org.slf4j", "slf4j-api")
exclude("net.kyori", "adventure-bom")
}
}
@@ -1,47 +0,0 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2024 kennytv (https://github.com/kennytv)
*
* 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 eu.kennytv.maintenance.bungee;
import eu.kennytv.maintenance.api.Maintenance;
import eu.kennytv.maintenance.core.MaintenanceBase;
import net.md_5.bungee.api.plugin.Plugin;
import java.io.File;
public final class MaintenanceBungeeBase extends Plugin implements MaintenanceBase {
private MaintenanceBungeePlugin maintenance;
@Override
public void onEnable() {
maintenance = new MaintenanceBungeePlugin(this);
}
@Override
public void onDisable() {
maintenance.disable();
}
@Override
public Maintenance getApi() {
return maintenance;
}
File getPluginFile() {
return getFile();
}
}
@@ -1,279 +0,0 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2024 kennytv (https://github.com/kennytv)
*
* 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 eu.kennytv.maintenance.bungee;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.bungee.command.MaintenanceBungeeCommand;
import eu.kennytv.maintenance.bungee.command.MaintenanceBungeeCommandBase;
import eu.kennytv.maintenance.bungee.listener.ProxyPingListener;
import eu.kennytv.maintenance.bungee.listener.ServerConnectListener;
import eu.kennytv.maintenance.bungee.util.BungeeSenderInfo;
import eu.kennytv.maintenance.bungee.util.BungeeServer;
import eu.kennytv.maintenance.bungee.util.BungeeTask;
import eu.kennytv.maintenance.bungee.util.ComponentUtil;
import eu.kennytv.maintenance.core.dump.PluginDump;
import eu.kennytv.maintenance.core.hook.ServerListPlusHook;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.core.proxy.SettingsProxy;
import eu.kennytv.maintenance.core.proxy.hook.LuckPermsProxyHook;
import eu.kennytv.maintenance.core.proxy.util.ProfileLookup;
import eu.kennytv.maintenance.core.proxy.util.ProxyOfflineSenderInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.core.util.ServerType;
import eu.kennytv.maintenance.core.util.Task;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.imageio.ImageIO;
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
import net.kyori.adventure.text.Component;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.Favicon;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.plugin.PluginManager;
import org.bstats.bungeecord.Metrics;
import org.jetbrains.annotations.Nullable;
public final class MaintenanceBungeePlugin extends MaintenanceProxyPlugin {
private final MaintenanceBungeeBase plugin;
private final BungeeAudiences audiences;
private Favicon favicon;
MaintenanceBungeePlugin(final MaintenanceBungeeBase plugin) {
super(plugin.getDescription().getVersion(), ServerType.BUNGEE);
this.plugin = plugin;
this.audiences = BungeeAudiences.create(plugin);
settingsProxy = new SettingsProxy(this);
settings = settingsProxy;
sendEnableMessage();
final PluginManager pm = getProxy().getPluginManager();
pm.registerListener(plugin, new ProxyPingListener(this, settingsProxy));
pm.registerListener(plugin, new ServerConnectListener(this, settingsProxy));
commandManager = new MaintenanceBungeeCommand(this, settingsProxy);
pm.registerCommand(plugin, new MaintenanceBungeeCommandBase(commandManager));
continueLastEndtimer();
new Metrics(plugin, 742);
final Plugin serverListPlus = pm.getPlugin("ServerListPlus");
if (serverListPlus != null) {
serverListPlusHook = new ServerListPlusHook(serverListPlus);
if (settings.isEnablePingMessages()) {
serverListPlusHook.setEnabled(!settingsProxy.isMaintenance());
}
plugin.getLogger().info("Enabled ServerListPlus integration!");
}
if (false && pm.getPlugin("LuckPerms") != null) {
LuckPermsProxyHook.<ProxiedPlayer>register(this, player -> {
final net.md_5.bungee.api.connection.Server server = player.getServer();
return server != null ? server.getInfo().getName() : null;
});
getLogger().info("Registered LuckPerms context");
}
}
public boolean isMaintenance(final ServerInfo serverInfo) {
return settingsProxy.isMaintenance(serverInfo.getName());
}
@Override
protected void kickPlayersFromProxy() {
for (final ProxiedPlayer player : getProxy().getPlayers()) {
if (!hasPermission(player, "bypass") && !settingsProxy.isWhitelisted(player.getUniqueId())) {
player.disconnect(ComponentUtil.toBadComponents(settingsProxy.getKickMessage()));
}
}
}
@Override
protected void kickPlayers(final Server server, final Server fallback) {
// Kick players from a proxied server
final ServerInfo fallbackServer = fallback != null ? ((BungeeServer) fallback).server() : null;
final boolean checkForFallback = fallbackServer != null && !isMaintenance(fallback);
for (final ProxiedPlayer player : ((BungeeServer) server).server().getPlayers()) {
if (!hasPermission(player, "bypass") && !settingsProxy.isWhitelisted(player.getUniqueId())) {
if (checkForFallback && fallbackServer.canAccess(player)) {
audiences.player(player).sendMessage(settingsProxy.getMessage("singleMaintenanceActivated", "%SERVER%", server.getName()));
player.connect(fallbackServer);
} else {
player.disconnect(ComponentUtil.toBadComponents(settingsProxy.getFullServerKickMessage(server.getName())));
}
} else {
audiences.player(player).sendMessage(settingsProxy.getMessage("singleMaintenanceActivated", "%SERVER%", server.getName()));
}
}
}
@Override
protected void kickPlayersTo(final Server server) {
// Kick all players to a single waiting server
final ServerInfo serverInfo = ((BungeeServer) server).server();
// Notifications done in global method
for (final ProxiedPlayer player : getProxy().getPlayers()) {
if (hasPermission(player, "bypass") || settingsProxy.isWhitelisted(player.getUniqueId())) continue;
if (player.getServer() != null && player.getServer().getInfo().getName().equals(serverInfo.getName()))
continue;
if (serverInfo.canAccess(player) && !isMaintenance(serverInfo)) {
audiences.player(player).sendMessage(settingsProxy.getMessage("sentToWaitingServer", "%SERVER%", server.getName()));
player.connect(serverInfo);
} else {
player.disconnect(ComponentUtil.toBadComponents(settingsProxy.getKickMessage()));
}
}
}
@Override
public Task startMaintenanceRunnable(final Runnable runnable) {
return new BungeeTask(getProxy().getScheduler().schedule(plugin, runnable, 0, 1, TimeUnit.SECONDS).getId());
}
@Override
public CompletableFuture<@Nullable SenderInfo> getOfflinePlayer(final String name) {
final ProxiedPlayer player = getProxy().getPlayer(name);
if (player != null) {
return CompletableFuture.completedFuture(new BungeeSenderInfo(player));
}
return CompletableFuture.supplyAsync(() -> {
try {
final ProfileLookup profile = doUUIDLookup(name);
return new ProxyOfflineSenderInfo(profile.uuid(), profile.name());
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
@Override
public CompletableFuture<@Nullable SenderInfo> getOfflinePlayer(final UUID uuid) {
final ProxiedPlayer player = getProxy().getPlayer(uuid);
return CompletableFuture.completedFuture(player != null ? new BungeeSenderInfo(player) : null);
}
@Override
@Nullable
public Server getServer(final String server) {
final ServerInfo serverInfo = getProxy().getServerInfo(server);
return serverInfo != null ? new BungeeServer(serverInfo) : null;
}
@Override
public Set<String> getServers() {
return getProxy().getServers().keySet();
}
@Override
@Nullable
public String getServerNameOf(final SenderInfo sender) {
final ProxiedPlayer player = getProxy().getPlayer(sender.uuid());
if (player == null || player.getServer() == null) return null;
return player.getServer().getInfo().getName();
}
@Override
public void async(final Runnable runnable) {
getProxy().getScheduler().runAsync(plugin, runnable);
}
@Override
protected void executeConsoleCommand(final String command) {
getProxy().getPluginManager().dispatchCommand(getProxy().getConsole(), command);
}
@Override
public void broadcast(final Component component) {
audiences.all().sendMessage(component);
}
@Override
public File getDataFolder() {
return plugin.getDataFolder();
}
@Override
public File getPluginFile() {
return plugin.getPluginFile();
}
@Override
protected int getOnlinePlayers() {
return getProxy().getOnlineCount();
}
@Override
protected int getMaxPlayers() {
return getProxy().getConfig().getPlayerLimit();
}
@Override
public InputStream getResource(final String name) {
return plugin.getResourceAsStream(name);
}
@Override
public Logger getLogger() {
return plugin.getLogger();
}
@Override
public String getServerVersion() {
return getProxy().getVersion();
}
@Override
public List<PluginDump> getPlugins() {
return getProxy().getPluginManager().getPlugins().stream().map(plugin ->
new PluginDump(plugin.getDescription().getName(), plugin.getDescription().getVersion(), Arrays.asList(plugin.getDescription().getAuthor()))).collect(Collectors.toList());
}
@Override
protected void loadIcon(final File file) throws IOException {
favicon = Favicon.create(ImageIO.read(file));
}
public boolean hasPermission(final CommandSender sender, final String permission) {
return sender.hasPermission("maintenance." + permission) || sender.hasPermission("maintenance.admin");
}
public ProxyServer getProxy() {
return plugin.getProxy();
}
public Favicon getFavicon() {
return favicon;
}
public BungeeAudiences audiences() {
return audiences;
}
}
@@ -1,59 +0,0 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2024 kennytv (https://github.com/kennytv)
*
* 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 eu.kennytv.maintenance.bungee.command;
import eu.kennytv.maintenance.bungee.MaintenanceBungeePlugin;
import eu.kennytv.maintenance.core.proxy.SettingsProxy;
import eu.kennytv.maintenance.core.proxy.command.MaintenanceProxyCommand;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
public final class MaintenanceBungeeCommand extends MaintenanceProxyCommand {
private final MaintenanceBungeePlugin plugin;
public MaintenanceBungeeCommand(final MaintenanceBungeePlugin plugin, final SettingsProxy settings) {
super(plugin, settings);
this.plugin = plugin;
registerCommands();
}
@Override
public List<String> getServersCompletion(final String s) {
final List<String> list = new ArrayList<>();
for (final Map.Entry<String, ServerInfo> entry : plugin.getProxy().getServers().entrySet()) {
final String serverName = entry.getValue().getName();
if (entry.getKey().toLowerCase(Locale.ROOT).startsWith(s) && !plugin.getSettingsProxy().getMaintenanceServers().contains(serverName)) {
list.add(serverName);
}
}
return list;
}
@Override
public List<String> getPlayersCompletion() {
final List<String> list = new ArrayList<>();
for (final ProxiedPlayer p : plugin.getProxy().getPlayers()) {
list.add(p.getName());
}
return list;
}
}
@@ -1,48 +0,0 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2024 kennytv (https://github.com/kennytv)
*
* 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 eu.kennytv.maintenance.bungee.command;
import eu.kennytv.maintenance.bungee.util.BungeeSenderInfo;
import eu.kennytv.maintenance.core.command.MaintenanceCommand;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
public final class MaintenanceBungeeCommandBase extends Command implements TabExecutor {
private final MaintenanceCommand command;
public MaintenanceBungeeCommandBase(final MaintenanceCommand command) {
super("maintenance", "maintenance.command", "mt");
this.command = command;
}
@Override
public boolean hasPermission(final CommandSender sender) {
return sender.hasPermission("maintenance.admin") || sender.hasPermission("maintenance.command");
}
@Override
public void execute(final CommandSender sender, final String[] args) {
command.execute(new BungeeSenderInfo(sender), args);
}
@Override
public Iterable<String> onTabComplete(final CommandSender sender, final String[] args) {
return command.getSuggestions(new BungeeSenderInfo(sender), args);
}
}
@@ -1,71 +0,0 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2024 kennytv (https://github.com/kennytv)
*
* 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 eu.kennytv.maintenance.bungee.listener;
import eu.kennytv.maintenance.bungee.MaintenanceBungeePlugin;
import eu.kennytv.maintenance.bungee.util.ComponentUtil;
import eu.kennytv.maintenance.core.proxy.SettingsProxy;
import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.event.ProxyPingEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
public final class ProxyPingListener implements Listener {
private final MaintenanceBungeePlugin plugin;
private final SettingsProxy settings;
public ProxyPingListener(final MaintenanceBungeePlugin plugin, final SettingsProxy settings) {
this.plugin = plugin;
this.settings = settings;
}
@EventHandler(priority = 80)
public void proxyPing(final ProxyPingEvent event) {
if (!settings.isMaintenance()) {
return;
}
final ServerPing ping = event.getResponse();
if (settings.hasCustomPlayerCountMessage()) {
ping.setVersion(new ServerPing.Protocol(settings.getLegacyParsedPlayerCountMessage(), 1));
}
if (settings.isEnablePingMessages()) {
ping.setDescriptionComponent(ComponentUtil.toBadComponents(settings.getRandomPingMessage()));
}
if (settings.hasCustomPlayerCountHoverMessage()) {
ServerPing.Players players = ping.getPlayers();
if (players == null) {
players = new ServerPing.Players(0, 0, null);
ping.setPlayers(players);
}
final String[] lines = settings.getLegacyParsedPlayerCountHoverLines();
final ServerPing.PlayerInfo[] samplePlayers = new ServerPing.PlayerInfo[lines.length];
for (int i = 0; i < lines.length; i++) {
samplePlayers[i] = new ServerPing.PlayerInfo(lines[i], "");
}
players.setSample(samplePlayers);
}
if (settings.hasCustomIcon() && plugin.getFavicon() != null) {
ping.setFavicon(plugin.getFavicon());
}
}
}
@@ -1,119 +0,0 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2024 kennytv (https://github.com/kennytv)
*
* 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 eu.kennytv.maintenance.bungee.listener;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.bungee.MaintenanceBungeePlugin;
import eu.kennytv.maintenance.bungee.util.BungeeSenderInfo;
import eu.kennytv.maintenance.bungee.util.BungeeServer;
import eu.kennytv.maintenance.core.proxy.SettingsProxy;
import eu.kennytv.maintenance.core.proxy.listener.ProxyJoinListenerBase;
import eu.kennytv.maintenance.core.proxy.util.ServerConnectResult;
import net.kyori.adventure.text.Component;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
public final class ServerConnectListener extends ProxyJoinListenerBase implements Listener {
private final MaintenanceBungeePlugin plugin;
public ServerConnectListener(final MaintenanceBungeePlugin plugin, final SettingsProxy settings) {
super(plugin, settings);
this.plugin = plugin;
}
@EventHandler
public void initialServerConnect(final ServerConnectEvent event) {
// Global maintenance check
if (event.isCancelled() || event.getReason() != ServerConnectEvent.Reason.JOIN_PROXY) return;
final BungeeSenderInfo player = new BungeeSenderInfo(event.getPlayer());
if (plugin.isDebug()) {
plugin.getLogger().info("Join permission check for " + event.getPlayer().getName()
+ " - Permission: " + player.hasMaintenancePermission("bypass") + ", whitelist: " + settings.isWhitelisted(player.uuid()));
}
if (shouldKick(player)) {
final Server waitingServer = shouldConnectToWaitingServer(player);
if (waitingServer != null) {
event.setTarget(((BungeeServer) waitingServer).server());
player.send(settings.getMessage("sentToWaitingServer"));
if (plugin.isDebug()) {
plugin.getLogger().info("Join to waiting server for " + event.getPlayer().getName());
}
return;
}
event.setCancelled(true);
player.disconnect(settings.getKickMessage());
if (settings.isJoinNotifications()) {
broadcastJoinNotification(player.name());
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void serverConnect(final ServerConnectEvent event) {
// Server specific maintenance check
if (event.isCancelled()) return;
final ProxiedPlayer proxiedPlayer = event.getPlayer();
final boolean normalServerConnect = event.getReason() != ServerConnectEvent.Reason.JOIN_PROXY && event.getReason() != ServerConnectEvent.Reason.KICK_REDIRECT
&& event.getReason() != ServerConnectEvent.Reason.LOBBY_FALLBACK && event.getReason() != ServerConnectEvent.Reason.SERVER_DOWN_REDIRECT;
final BungeeSenderInfo player = new BungeeSenderInfo(proxiedPlayer);
final ServerConnectResult connectResult = serverConnect(player, new BungeeServer(event.getTarget()), normalServerConnect);
if (plugin.isDebug()) {
plugin.getLogger().info("Connectresult for " + player.name() + " to " + event.getTarget().getName() + ": " + connectResult);
}
if (connectResult.isCancelled()) {
event.setCancelled(true);
// Player has no server to connect to
if (proxiedPlayer.getServer() == null) {
player.disconnect(settings.getKickMessage());
}
} else if (connectResult.getTarget() != null) {
event.setTarget(((BungeeServer) connectResult.getTarget()).server());
}
}
@Override
protected void broadcastJoinNotification(final String name) {
sendJoinMessage(ProxyServer.getInstance().getPlayers(), name);
}
@Override
protected void broadcastJoinNotification(final String name, final Server server) {
sendJoinMessage(((BungeeServer) server).server().getPlayers(), name);
}
private void sendJoinMessage(final Iterable<ProxiedPlayer> players, final String name) {
final Component component = settings.getMessage("joinNotification", "%PLAYER%", name);
for (final ProxiedPlayer player : players) {
if (plugin.hasPermission(player, "joinnotification")) {
plugin.audiences().player(player).sendMessage(component);
}
}
}
}
@@ -1,79 +0,0 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2024 kennytv (https://github.com/kennytv)
*
* 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 eu.kennytv.maintenance.bungee.util;
import eu.kennytv.maintenance.api.MaintenanceProvider;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.bungee.MaintenanceBungeePlugin;
import eu.kennytv.maintenance.core.proxy.util.ProxySenderInfo;
import net.kyori.adventure.text.Component;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.Connection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.UUID;
public final class BungeeSenderInfo implements ProxySenderInfo {
private final CommandSender sender;
public BungeeSenderInfo(final CommandSender sender) {
this.sender = sender;
}
@Override
public UUID uuid() {
return sender instanceof ProxiedPlayer proxiedPlayer ? proxiedPlayer.getUniqueId() : null;
}
@Override
public String name() {
return sender.getName();
}
@Override
public boolean hasPermission(final String permission) {
return sender.hasPermission(permission);
}
@Override
public void send(final Component component) {
((MaintenanceBungeePlugin) MaintenanceProvider.get()).audiences().sender(sender).sendMessage(component);
}
@Override
public boolean isPlayer() {
return sender instanceof ProxiedPlayer;
}
public void sendMessage(final TextComponent textComponent) {
sender.sendMessage(textComponent);
}
@Override
public boolean canAccess(final Server server) {
return ((BungeeServer) server).server().canAccess(sender);
}
@Override
public void disconnect(final Component component) {
if (sender instanceof Connection connection) {
connection.disconnect(ComponentUtil.toBadComponent(component));
}
}
}
@@ -1,50 +0,0 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2024 kennytv (https://github.com/kennytv)
*
* 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 eu.kennytv.maintenance.bungee.util;
import eu.kennytv.maintenance.api.proxy.Server;
import net.kyori.adventure.text.Component;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
public record BungeeServer(ServerInfo server) implements Server {
@Override
public String getName() {
return server.getName();
}
@Override
public boolean hasPlayers() {
return !server.getPlayers().isEmpty();
}
@Override
public void broadcast(final Component component) {
final BaseComponent[] components = ComponentUtil.toBadComponent(component);
for (final ProxiedPlayer player : server.getPlayers()) {
player.sendMessage(components);
}
}
@Override
public boolean isRegisteredServer() {
return true;
}
}
-7
View File
@@ -1,7 +0,0 @@
name: Maintenance
version: ${version}
main: eu.kennytv.maintenance.bungee.MaintenanceBungeeBase
author: kennytv
description: ${description}
softDepends: [ServerListPlus, LuckPerms]
website: https://hangar.papermc.io/kennytv/Maintenance
+1 -7
View File
@@ -1,13 +1,7 @@
dependencies {
api(projects.maintenanceApiProxy)
api(projects.maintenanceCore)
// Try to reasonably minimize it...
implementation(libs.jedis) {
exclude("com.google.code.gson", "gson")
exclude("org.slf4j", "slf4j-api")
}
implementation(libs.hikariCP)
compileOnly(libs.luckperms)
compileOnly(libs.guava)
compileOnly(libs.gson)
@@ -28,15 +28,14 @@ import eu.kennytv.maintenance.core.proxy.runnable.SingleMaintenanceRunnable;
import eu.kennytv.maintenance.core.proxy.runnable.SingleMaintenanceScheduleRunnable;
import eu.kennytv.maintenance.core.proxy.util.ProfileLookup;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
import eu.kennytv.maintenance.core.util.DiscordWebhook;
import eu.kennytv.maintenance.core.util.RateLimitedException;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.core.util.ServerType;
import eu.kennytv.maintenance.core.util.Task;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
@@ -47,8 +46,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import java.util.regex.Pattern;
import org.jetbrains.annotations.Blocking;
import org.jetbrains.annotations.Nullable;
@@ -57,8 +54,7 @@ import org.jetbrains.annotations.Nullable;
* @since 3.0
*/
public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implements MaintenanceProxy {
private static final Pattern USERNAME_PATTERN = Pattern.compile("^[A-Za-z0-9_.]{1,16}$");
private final Map<String, MaintenanceRunnableBase> serverTasks = new HashMap<>();
private final Map<String, Task> serverTasks = new HashMap<>();
protected SettingsProxy settingsProxy;
protected MaintenanceProxyPlugin(final String version, final ServerType serverType) {
@@ -68,54 +64,49 @@ public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implement
@Override
public void disable() {
super.disable();
if (settingsProxy.redisHandler() != null) {
settingsProxy.redisHandler().close();
if (settingsProxy.getMySQL() != null) {
settingsProxy.getMySQL().close();
}
}
@Override
public void setMaintenance(final boolean maintenance) {
if (settingsProxy.hasMySQL()) {
settingsProxy.setMaintenanceToSQL(maintenance);
}
super.setMaintenance(maintenance);
}
@Override
public boolean isMaintenance(final Server server) {
return settingsProxy.isMaintenance(server.getName());
}
@Override
public boolean setMaintenanceToServer(final Server server, final boolean maintenance, @Nullable final String mode) {
public boolean setMaintenanceToServer(final Server server, final boolean maintenance) {
if (maintenance) {
if (settingsProxy.addMaintenanceServer(server.getName(), mode)) {
serverActions(server, true);
return true;
if (!settingsProxy.addMaintenanceServer(server.getName())) {
return false;
}
return mode != null && settingsProxy.setMaintenanceServerMode(server.getName(), mode);
}
if (!settingsProxy.removeMaintenanceServer(server.getName())) {
} else if (!settingsProxy.removeMaintenanceServer(server.getName())) {
return false;
}
serverActions(server, false);
serverActions(server, maintenance);
for (final String command : (maintenance ? settingsProxy.getCommandsOnMaintenanceEnable(server) : settingsProxy.getCommandsOnMaintenanceDisable(server))) {
try {
executeConsoleCommand(command.replace("%SERVER%", server.getName()));
} catch (final Exception e) {
getLogger().severe("Error while executing extra maintenance " + (maintenance ? "enable" : "disable") + " command: " + command);
e.printStackTrace();
}
}
return true;
}
@Override
public boolean setMaintenanceToServer(final Server server, final boolean maintenance) {
return setMaintenanceToServer(server, maintenance, null);
}
public boolean setMaintenanceModeToServer(final Server server, @Nullable final String mode) {
if (!settingsProxy.isMaintenance(server.getName())) {
return false;
}
return settingsProxy.setMaintenanceServerMode(server.getName(), mode);
}
public @Nullable String activeMode(final Server server) {
return settingsProxy.activeMode(server.getName());
}
public void serverActions(final Server server, final boolean maintenance) {
if (server == null) {
return;
}
if (server == null) return;
// Skip to the even fire for dummy servers
if (server.isRegisteredServer()) {
@@ -135,19 +126,6 @@ public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implement
}
eventManager.callEvent(new ServerMaintenanceChangedEvent(server, maintenance));
if (maintenance) {
sendWebhookMessage("webhookSingleMaintenanceActivated", DiscordWebhook.EventType.MAINTENANCE_ENABLED, "%SERVER%", server.getName());
} else {
sendWebhookMessage("webhookSingleMaintenanceDeactivated", DiscordWebhook.EventType.MAINTENANCE_DISABLED, "%SERVER%", server.getName());
}
for (final String command : (maintenance ? settingsProxy.getCommandsOnMaintenanceEnable(server) : settingsProxy.getCommandsOnMaintenanceDisable(server))) {
try {
executeConsoleCommand(command.replace("%SERVER%", server.getName()));
} catch (final Exception e) {
getLogger().log(Level.SEVERE, "Error while executing extra maintenance " + (maintenance ? "enable" : "disable") + " command: " + command, e);
}
}
}
@Override
@@ -155,45 +133,28 @@ public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implement
return serverTasks.containsKey(server.getName());
}
public boolean hasServerTasks() {
return !serverTasks.isEmpty();
}
public Map<String, MaintenanceRunnableBase> getServerTasks() {
return serverTasks;
}
public MaintenanceRunnableBase getServerTask(final String server) {
return serverTasks.get(server);
}
@Override
public Set<String> getMaintenanceServers() {
return Collections.unmodifiableSet(settingsProxy.getMaintenanceServers());
}
public void cancelSingleTask(final Server server) {
final MaintenanceRunnableBase task = serverTasks.remove(server.getName());
final Task task = serverTasks.remove(server.getName());
if (task != null) {
task.getTask().cancel();
task.cancel();
}
}
public MaintenanceRunnableBase startSingleMaintenanceRunnable(final Server server, final Duration duration, final boolean enable, @Nullable final String mode) {
final MaintenanceRunnableBase runnable = new SingleMaintenanceRunnable(this, settingsProxy, (int) duration.getSeconds(), enable, server, mode);
serverTasks.put(server.getName(), runnable);
public MaintenanceRunnableBase startSingleMaintenanceRunnable(final Server server, final Duration duration, final boolean enable) {
final MaintenanceRunnableBase runnable = new SingleMaintenanceRunnable(this, settingsProxy, (int) duration.getSeconds(), enable, server);
serverTasks.put(server.getName(), runnable.getTask());
return runnable;
}
public MaintenanceRunnableBase startSingleMaintenanceRunnable(final Server server, final Duration duration, final boolean enable) {
return startSingleMaintenanceRunnable(server, duration, enable, null);
}
public MaintenanceRunnableBase scheduleSingleMaintenanceRunnable(final Server server, final Duration enableIn,
final Duration maintenanceDuration, @Nullable final String mode) {
public MaintenanceRunnableBase scheduleSingleMaintenanceRunnable(final Server server, final Duration enableIn, final Duration maintenanceDuration) {
final MaintenanceRunnableBase runnable = new SingleMaintenanceScheduleRunnable(this, settingsProxy,
(int) enableIn.getSeconds(), (int) maintenanceDuration.getSeconds(), server, mode);
serverTasks.put(server.getName(), runnable);
(int) enableIn.getSeconds(), (int) maintenanceDuration.getSeconds(), server);
serverTasks.put(server.getName(), runnable.getTask());
return runnable;
}
@@ -231,17 +192,15 @@ public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implement
@Blocking
@Nullable
protected ProfileLookup doUUIDLookup(final String name) throws IOException {
ProfileLookup profileLookup = null;
if (USERNAME_PATTERN.matcher(name).matches()) {
try {
profileLookup = doUUIDLookupMojangAPI(name);
} catch (RateLimitedException e) {
// Use fallback API if rate limit is reached
profileLookup = doUUIDLookupAshconAPI(name);
}
ProfileLookup profileLookup;
try {
profileLookup = doUUIDLookupMojangAPI(name);
} catch (RateLimitedException e) {
// Use fallback API if rate limit is reached
profileLookup = doUUIDLookupAshconAPI(name);
}
if (profileLookup == null && settingsProxy.isFallbackToOfflineUUID()) {
if (settingsProxy.isFallbackToOfflineUUID() && profileLookup == null) {
// Use offline uuid
return new ProfileLookup(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8)), name);
}
@@ -254,7 +213,7 @@ public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implement
*/
@Nullable
private ProfileLookup doUUIDLookupMojangAPI(final String name) throws IOException {
final URL url = URI.create("https://api.mojang.com/users/profiles/minecraft/" + name).toURL();
final URL url = new URL("https://api.mojang.com/users/profiles/minecraft/" + name);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
@@ -282,7 +241,7 @@ public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implement
*/
@Nullable
private ProfileLookup doUUIDLookupAshconAPI(final String name) throws IOException {
final URL url = URI.create("https://api.ashcon.app/mojang/v2/user/" + name).toURL();
final URL url = new URL("https://api.ashcon.app/mojang/v2/user/" + name);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
if (connection.getResponseCode() == 403) {
@@ -320,4 +279,4 @@ public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implement
protected abstract void kickPlayersTo(Server server);
protected abstract void kickPlayersFromProxy();
}
}
@@ -17,55 +17,88 @@
*/
package eu.kennytv.maintenance.core.proxy;
import eu.kennytv.maintenance.api.proxy.MaintenanceProxy;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.config.ConfigSection;
import eu.kennytv.maintenance.core.proxy.redis.RedisHandler;
import eu.kennytv.maintenance.core.proxy.mysql.MySQL;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
public final class SettingsProxy extends Settings {
private Map<String, String> maintenanceServers;
private final MaintenanceProxyPlugin proxyPlugin;
private Set<String> maintenanceServers;
private List<String> fallbackServers;
private String waitingServer;
private boolean fallbackToOfflineUUID;
private Map<String, List<String>> commandsOnMaintenanceEnable;
private Map<String, List<String>> commandsOnMaintenanceDisable;
private String mySQLTable;
private String serverTable;
private String maintenanceQuery;
private String serverQuery;
private MySQL mySQL;
private RedisHandler redisHandler;
private long millisecondsToCheck;
private long lastMySQLCheck;
private long lastServerCheck;
public SettingsProxy(final MaintenanceProxyPlugin plugin) {
super(plugin);
this.proxyPlugin = plugin;
}
private void setupMySQL() {
plugin.getLogger().info("Trying to open database connection... (also, you can simply ignore the SLF4J soft-warning if it shows up)");
final ConfigSection section = config.getSection("mysql");
if (section == null) {
plugin.getLogger().warning("Section missing: mysql");
return;
}
mySQL = new MySQL(plugin.getLogger(),
section.getString("host"),
section.getInt("port"),
section.getString("username"),
section.getString("password"),
section.getString("database"),
section.getBoolean("use-ssl", true));
// Varchar as the value regarding the possibility of saving stuff like the motd as well in future updates
mySQLTable = section.getString("table", "maintenance_settings");
serverTable = section.getString("servertable", "maintenance_servers");
mySQL.executeUpdate("CREATE TABLE IF NOT EXISTS " + mySQLTable + " (setting VARCHAR(16) PRIMARY KEY, value VARCHAR(255))");
mySQL.executeUpdate("CREATE TABLE IF NOT EXISTS " + serverTable + " (server VARCHAR(64) PRIMARY KEY)");
maintenanceQuery = "SELECT * FROM " + mySQLTable + " WHERE setting = ?";
serverQuery = "SELECT * FROM " + serverTable;
plugin.getLogger().info("Done!");
}
@Override
protected void loadExtraSettings() {
// Open Redis connection if enabled and not already done
final ConfigSection redisSection = config.getSection("redis");
if (!hasRedis() && redisSection.getBoolean("enabled")) {
connectToRedis(redisSection.getString("uri"));
}
if (hasRedis()) {
maintenance = redisHandler.loadMaintenanceStatus();
activeMode = normalizeMode(redisHandler.loadGlobalMode());
maintenanceServers = redisHandler.loadMaintenanceServers();
// Open database connection if enabled and not already done
if (!hasMySQL() && config.getBoolean("mysql.use-mysql")) {
try {
setupMySQL();
} catch (final Exception e) {
mySQL = null;
plugin.getLogger().warning("Error while trying do open database connection!");
e.printStackTrace();
}
}
final Object fallback = config.getObject("fallback");
fallbackServers = fallback instanceof String s ? Collections.singletonList(s) : config.getStringList("fallback", Collections.emptyList());
fallbackServers = fallback instanceof String ? Collections.singletonList((String) fallback) : config.getStringList("fallback", Collections.emptyList());
waitingServer = config.getString("waiting-server", "");
if (waitingServer.isEmpty() || waitingServer.equalsIgnoreCase("none")) {
@@ -85,36 +118,55 @@ public final class SettingsProxy extends Settings {
commandsOnMaintenanceDisable.put(key.toLowerCase(Locale.ROOT), disableCommandsSection.getStringList(key));
}
if (!hasRedis()) {
final ConfigSection maintenanceServersSection = config.getSection("proxied-maintenance-servers");
maintenanceServers = new LinkedHashMap<>();
for (final Map.Entry<String, ?> entry : maintenanceServersSection.getValues().entrySet()) {
if (entry.getKey() != null) {
maintenanceServers.put(entry.getKey(), normalizeServerMode(entry.getValue()));
}
}
if (hasMySQL()) {
maintenance = loadMaintenance();
maintenanceServers = loadMaintenanceServersFromSQL();
final long configValue = config.getInt("mysql.update-interval");
// Even if set to 0, only check every 500 millis
millisecondsToCheck = configValue > 0 ? configValue * 1000 : 500;
lastMySQLCheck = System.currentTimeMillis();
lastServerCheck = System.currentTimeMillis();
} else {
final List<String> list = config.getStringList("proxied-maintenance-servers");
maintenanceServers = list == null ? new HashSet<>() : new HashSet<>(list);
}
}
private void connectToRedis(final String redisUri) {
redisHandler = new RedisHandler((MaintenanceProxyPlugin) plugin, this);
try {
redisHandler.setup(redisUri);
} catch (final Exception e) {
plugin.getLogger().log(Level.SEVERE, "Error while trying to open Redis connection!", e);
e.printStackTrace();
redisHandler.close();
redisHandler = null;
@Override
public boolean isMaintenance() {
if (hasMySQL() && System.currentTimeMillis() - lastMySQLCheck > millisecondsToCheck) {
final boolean databaseValue = loadMaintenance();
if (databaseValue != maintenance) {
maintenance = databaseValue;
plugin.serverActions(maintenance);
}
lastMySQLCheck = System.currentTimeMillis();
}
return maintenance;
}
public boolean isMaintenance(final String serverName) {
return maintenanceServers.containsKey(serverName);
}
public @Nullable String activeMode(final String serverName) {
final String mode = maintenanceServers.get(serverName);
return mode == null || mode.equals("default") ? null : mode;
if (hasMySQL() && System.currentTimeMillis() - lastServerCheck > millisecondsToCheck) {
final Set<String> databaseValue = loadMaintenanceServersFromSQL();
if (!maintenanceServers.equals(databaseValue)) {
// Enable maintenance on yet unlisted servers
for (final String s : databaseValue) {
if (!maintenanceServers.contains(s)) {
proxyPlugin.serverActions(proxyPlugin.getServer(s), true);
}
}
// Disable maintenance on now unlisted servers
for (final String s : maintenanceServers) {
if (!databaseValue.contains(s)) {
proxyPlugin.serverActions(proxyPlugin.getServer(s), false);
}
}
maintenanceServers = databaseValue;
}
lastServerCheck = System.currentTimeMillis();
}
return maintenanceServers.contains(serverName);
}
public Component getServerKickMessage(final String server) {
@@ -122,154 +174,101 @@ public final class SettingsProxy extends Settings {
if (message == null) {
message = getLanguageString("singleMaintenanceKick", "%SERVER%", server);
}
return parse(plugin.replacePingVariables(message, activeMode(server)));
return parse(plugin.replacePingVariables(message));
}
// Full = being kicked from the proxy, not just a proxied server
public Component getFullServerKickMessage(final String server) {
String message = getLanguageStringOrNull("singleMaintenanceKicksComplete." + server, "%SERVER%", server);
if (message == null) {
message = getLanguageString("singleMaintenanceKickComplete", "%SERVER%", server);
}
return parse(plugin.replacePingVariables(message, activeMode(server)));
return parse(plugin.replacePingVariables(message));
}
public boolean hasRedis() {
return redisHandler != null;
public boolean hasMySQL() {
return mySQL != null;
}
@Override
protected void loadWhitelistedPlayers() {
if (hasRedis()) {
redisHandler.loadPlayers(getWhitelistedPlayers());
} else {
super.loadWhitelistedPlayers();
}
}
@Override
public void setMaintenance(final boolean maintenance, @Nullable final String mode) {
super.setMaintenance(maintenance, mode);
if (hasRedis()) {
redisHandler.set(maintenance, mode != null ? mode : "default");
}
}
@Override
public void setActiveMode(@Nullable final String activeMode) {
super.setActiveMode(activeMode);
if (hasRedis() && isMaintenance()) {
redisHandler.set(true, activeMode != null ? activeMode : "default");
}
}
public void setActiveModeDirect(@Nullable final String activeMode) {
super.setActiveMode(activeMode);
}
public void setMaintenanceDirect(final boolean maintenance, @Nullable final String mode) {
super.setMaintenance(maintenance, mode);
}
@Override
public boolean addWhitelistedPlayer(final UUID uuid, final String name) {
if (super.addWhitelistedPlayer(uuid, name)) {
if (hasRedis()) {
redisHandler.addPlayer(uuid, name);
}
return true;
}
return false;
}
public boolean addWhitelistedPlayerDirect(final UUID uuid, final String name) {
return super.addWhitelistedPlayer(uuid, name);
}
@Override
public boolean removeWhitelistedPlayer(final UUID uuid) {
if (super.removeWhitelistedPlayer(uuid)) {
if (hasRedis()) {
redisHandler.removePlayer(uuid);
}
return true;
}
return false;
}
public boolean removeWhitelistedPlayerDirect(final UUID uuid) {
return super.removeWhitelistedPlayer(uuid);
}
boolean addMaintenanceServer(final String server, @Nullable final String mode) {
final String normalizedMode = normalizeServerMode(mode);
if (hasRedis()) {
if (redisHandler.addServer(server, normalizedMode)) {
maintenanceServers.put(server, normalizedMode);
return true;
}
} else if (maintenanceServers.putIfAbsent(server, normalizedMode) == null) {
saveServersToConfig();
return true;
}
return false;
}
boolean setMaintenanceServerMode(final String server, @Nullable final String mode) {
final String normalizedMode = normalizeServerMode(mode);
final String oldMode = maintenanceServers.get(server);
if (oldMode == null || oldMode.equals(normalizedMode)) {
return false;
}
maintenanceServers.put(server, normalizedMode);
if (hasRedis()) {
redisHandler.setServerMode(server, normalizedMode);
void setMaintenanceToSQL(final boolean maintenance) {
plugin.async(() -> {
final String s = String.valueOf(maintenance);
mySQL.executeUpdate("INSERT INTO " + mySQLTable + " (setting, value) VALUES (?, ?) ON DUPLICATE KEY UPDATE value = ?", "maintenance", s, s);
lastMySQLCheck = System.currentTimeMillis();
});
}
boolean addMaintenanceServer(final String server) {
if (hasMySQL()) {
maintenanceServers = loadMaintenanceServersFromSQL();
if (!maintenanceServers.add(server)) return false;
plugin.async(() -> mySQL.executeUpdate("INSERT INTO " + serverTable + " (server) VALUES (?)", server));
lastServerCheck = System.currentTimeMillis();
} else {
if (!maintenanceServers.add(server)) return false;
saveServersToConfig();
}
return true;
}
boolean removeMaintenanceServer(final String server) {
if (hasRedis()) {
if (redisHandler.removeServer(server)) {
maintenanceServers.remove(server);
return true;
}
} else if (maintenanceServers.remove(server) != null) {
if (hasMySQL()) {
maintenanceServers = loadMaintenanceServersFromSQL();
if (!maintenanceServers.remove(server)) return false;
plugin.async(() -> mySQL.executeUpdate("DELETE FROM " + serverTable + " WHERE server = ?", server));
lastServerCheck = System.currentTimeMillis();
} else {
if (!maintenanceServers.remove(server)) return false;
saveServersToConfig();
return true;
}
return false;
return true;
}
public boolean addMaintenanceServerDirect(final String server, @Nullable final String mode) {
return maintenanceServers.put(server, normalizeServerMode(mode)) == null;
private Set<String> loadMaintenanceServersFromSQL() {
final Set<String> maintenanceServers = new HashSet<>();
mySQL.executeQuery(serverQuery, rs -> {
try {
while (rs.next()) {
maintenanceServers.add(rs.getString("server"));
}
} catch (final SQLException e) {
plugin.getLogger().warning("An error occured while trying to get the list of single servers with maintenance!");
e.printStackTrace();
}
});
return maintenanceServers;
}
public boolean removeMaintenanceServerDirect(final String server) {
return maintenanceServers.remove(server) != null;
}
public void setMaintenanceServerModeDirect(final String server, @Nullable final String mode) {
if (maintenanceServers.containsKey(server)) {
maintenanceServers.put(server, normalizeServerMode(mode));
}
private boolean loadMaintenance() {
final boolean[] databaseValue = {false};
mySQL.executeQuery(maintenanceQuery, rs -> {
try {
if (rs.next()) {
databaseValue[0] = Boolean.parseBoolean(rs.getString("value"));
}
} catch (final SQLException e) {
plugin.getLogger().warning("An error occured while trying to get the maintenance value from the database!");
e.printStackTrace();
}
}, "maintenance");
return databaseValue[0];
}
private void saveServersToConfig() {
config.set("proxied-maintenance-servers", new LinkedHashMap<>(maintenanceServers));
config.set("proxied-maintenance-servers", new ArrayList<>(maintenanceServers));
saveConfig();
}
public Set<String> getMaintenanceServers() {
return maintenanceServers.keySet();
return maintenanceServers;
}
@Nullable
public Server getFallbackServer() {
for (final String fallbackServer : fallbackServers) {
final Server server = ((MaintenanceProxy) plugin).getServer(fallbackServer);
final Server server = proxyPlugin.getServer(fallbackServer);
if (server != null && !isMaintenance(server.getName())) {
return server;
}
@@ -287,7 +286,7 @@ public final class SettingsProxy extends Settings {
}
public List<String> getCommandsOnMaintenanceEnable(final Server server) {
final List<String> enableCommands = new ArrayList<>(commandsOnMaintenanceEnable.getOrDefault("all", Collections.emptyList()));
final List<String> enableCommands = commandsOnMaintenanceEnable.getOrDefault("all", new ArrayList<>());
final List<String> serverEnableCommands = commandsOnMaintenanceEnable.get(server.getName().toLowerCase(Locale.ROOT));
if (serverEnableCommands != null) {
enableCommands.addAll(serverEnableCommands);
@@ -296,7 +295,7 @@ public final class SettingsProxy extends Settings {
}
public List<String> getCommandsOnMaintenanceDisable(final Server server) {
final List<String> disableCommands = new ArrayList<>(commandsOnMaintenanceDisable.getOrDefault("all", Collections.emptyList()));
final List<String> disableCommands = commandsOnMaintenanceDisable.getOrDefault("all", new ArrayList<>());
final List<String> serverDisableCommands = commandsOnMaintenanceDisable.get(server.getName().toLowerCase(Locale.ROOT));
if (serverDisableCommands != null) {
disableCommands.addAll(serverDisableCommands);
@@ -304,15 +303,8 @@ public final class SettingsProxy extends Settings {
return disableCommands;
}
public @Nullable RedisHandler redisHandler() {
return redisHandler;
}
private static String normalizeServerMode(@Nullable final Object mode) {
if (mode == null) {
return "default";
}
final String value = String.valueOf(mode).toLowerCase(Locale.ROOT);
return value.isBlank() ? "default" : value;
@Nullable
MySQL getMySQL() {
return mySQL;
}
}
@@ -26,7 +26,6 @@ import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public abstract class MaintenanceProxyCommand extends MaintenanceCommand {
private final MaintenanceProxyPlugin plugin;
@@ -41,7 +40,7 @@ public abstract class MaintenanceProxyCommand extends MaintenanceCommand {
@Override
protected void addToggleAndTimerCommands() {
add(new SingleToggleCommand(plugin), "on", "off");
add(new ProxyStatusCommand(plugin), "status");
add(new StatusCommand(plugin), "status");
add(new SingleStarttimerCommand(plugin), "starttimer", "start");
add(new SingleEndtimerCommand(plugin), "endtimer", "end");
@@ -53,7 +52,7 @@ public abstract class MaintenanceProxyCommand extends MaintenanceCommand {
public List<String> getMaintenanceServersCompletion(final String s) {
final List<String> list = new ArrayList<>();
for (final String server : settingsBungee.getMaintenanceServers()) {
if (server.toLowerCase(Locale.ROOT).startsWith(s)) {
if (server.toLowerCase().startsWith(s)) {
list.add(server);
}
}
@@ -20,8 +20,6 @@ package eu.kennytv.maintenance.core.proxy.command;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.core.proxy.SettingsProxy;
import java.util.ArrayList;
import java.util.List;
public abstract class ProxyCommandInfo extends CommandInfo {
protected final MaintenanceProxyPlugin plugin;
@@ -35,10 +33,4 @@ public abstract class ProxyCommandInfo extends CommandInfo {
protected SettingsProxy getSettings() {
return plugin.getSettingsProxy();
}
protected List<String> getModesCompletion() {
final List<String> modes = new ArrayList<>(getSettings().getPingMessages().getKeys());
modes.remove("default");
return modes;
}
}
@@ -22,10 +22,8 @@ import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.core.proxy.command.ProxyCommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
public final class AbortSingleTimerCommand extends ProxyCommandInfo {
@@ -69,17 +67,6 @@ public final class AbortSingleTimerCommand extends ProxyCommandInfo {
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
if (args.length != 2 || !sender.hasMaintenancePermission("singleserver.timer")) {
return Collections.emptyList();
}
final String prefix = args[1].toLowerCase(Locale.ROOT);
final List<String> list = new ArrayList<>();
for (final String server : plugin.getServerTasks().keySet()) {
if (server.toLowerCase(Locale.ROOT).startsWith(prefix)) {
list.add(server);
}
}
return list;
return args.length == 2 && sender.hasMaintenancePermission("singleserver.timer") ? plugin.getCommandManager().getServersCompletion(args[1]) : Collections.emptyList();
}
}
@@ -1,74 +0,0 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2024 kennytv (https://github.com/kennytv)
*
* 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 eu.kennytv.maintenance.core.proxy.command.subcommand;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.core.proxy.command.ProxyCommandInfo;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnable;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.Map;
import net.kyori.adventure.text.Component;
public final class ProxyStatusCommand extends ProxyCommandInfo {
public ProxyStatusCommand(final MaintenanceProxyPlugin plugin) {
super(plugin, "singleserver.status");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
final MaintenanceRunnable task = plugin.getCurrentTask();
if (task != null) {
final String key = task.shouldEnable() ? "maintenanceStatusOffWithStartTimer" : "maintenanceStatusOnWithEndTimer";
sender.send(getMessage(key, "%TIME%", task.getTime()));
} else {
sender.send(getMessage(plugin.isMaintenance() ? "maintenanceStatusOn" : "maintenanceStatusOff"));
}
if (getSettings().getMaintenanceServers().isEmpty() && !plugin.hasServerTasks()) {
sender.send(getMessage("singleServerMaintenanceListEmpty"));
return;
}
sender.send(getMessage("singleServerMaintenanceList"));
// Enabled servers first
for (final String server : getSettings().getMaintenanceServers()) {
final MaintenanceRunnableBase serverTask = plugin.getServerTask(server);
if (serverTask != null) {
sender.send(getMessage("singleServerMaintenanceListEntryWithEndTimer", "%SERVER%", server, "%TIME%", serverTask.getTime()));
continue;
}
sender.send(getMessage("singleServerMaintenanceListEntry", "%SERVER%", server));
}
// Then enabling tasks
for (final Map.Entry<String, MaintenanceRunnableBase> entry : plugin.getServerTasks().entrySet()) {
final MaintenanceRunnableBase serverTask = entry.getValue();
if (serverTask.shouldEnable()) {
sender.send(getMessage("singleServerMaintenanceListEntryWithStartTimer", "%SERVER%", entry.getKey(), "%TIME%", serverTask.getTime()));
}
}
}
@Override
public Component getHelpMessage() {
return getMessage("helpStatus");
}
}
@@ -21,14 +21,10 @@ import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.core.proxy.command.ProxyCommandInfo;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
import eu.kennytv.maintenance.core.util.DiscordWebhook;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import net.kyori.adventure.text.Component;
public final class SingleEndtimerCommand extends ProxyCommandInfo {
@@ -44,82 +40,49 @@ public final class SingleEndtimerCommand extends ProxyCommandInfo {
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (args.length == 2) {
endGlobal(sender, args[1]);
} else if (args.length == 3) {
if (args[1].equalsIgnoreCase("global")) {
endGlobal(sender, args[2]);
} else {
endSingle(sender, args[1], args[2]);
if (checkPermission(sender, "timer")) return;
final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[1]);
if (duration == null) {
sender.send(getHelpMessage());
return;
}
if (!plugin.isMaintenance()) {
sender.send(getMessage("alreadyDisabled"));
return;
}
plugin.startMaintenanceRunnable(duration, false);
sender.send(getMessage("endtimerStarted", "%TIME%", plugin.getRunnable().getTime()));
} else if (args.length == 3) {
if (checkPermission(sender, "singleserver.timer")) return;
final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[2], false);
if (duration == null) {
sender.send(getHelpMessage());
return;
}
final Server server = plugin.getCommandManager().checkSingleTimerServerArg(sender, args[1]);
if (server == null) return;
if (!plugin.isMaintenance(server)) {
sender.send(getMessage("singleServerAlreadyDisabled", "%SERVER%", server.getName()));
return;
}
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, duration, false);
sender.send(getMessage(
"singleEndtimerStarted",
"%TIME%", runnable.getTime(),
"%SERVER%", server.getName()
));
} else {
sender.send(getHelpMessage());
}
}
private void endGlobal(final SenderInfo sender, final String durationArg) {
if (checkPermission(sender, "timer")) return;
final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, durationArg);
if (duration == null) {
sender.send(getHelpMessage());
return;
}
if (!plugin.isMaintenance()) {
sender.send(getMessage("alreadyDisabled"));
return;
}
plugin.startMaintenanceRunnable(duration, false);
final Component message = getMessage("endtimerStarted", "%TIME%", plugin.getRunnable().getTime());
sender.send(message);
plugin.sendWebhookMessage("webhookEndtimerStarted", DiscordWebhook.EventType.ENDTIMER_STARTED,
"%TIME%", plugin.getRunnable().getTime(),
"%TIMESTAMP%", plugin.getTargetTimestamp(duration));
}
private void endSingle(final SenderInfo sender, final String serverArg, final String durationArg) {
if (checkPermission(sender, "singleserver.timer")) return;
final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, durationArg, false);
if (duration == null) {
sender.send(getHelpMessage());
return;
}
final Server server = plugin.getCommandManager().checkSingleTimerServerArg(sender, serverArg);
if (server == null) return;
if (!plugin.isMaintenance(server)) {
sender.send(getMessage("singleServerAlreadyDisabled", "%SERVER%", server.getName()));
return;
}
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, duration, false);
final Component message = getMessage(
"singleEndtimerStarted",
"%TIME%", runnable.getTime(),
"%SERVER%", server.getName()
);
sender.send(message);
plugin.sendWebhookMessage("webhookSingleEndtimerStarted", DiscordWebhook.EventType.ENDTIMER_STARTED,
"%TIME%", runnable.getTime(),
"%SERVER%", server.getName(),
"%TIMESTAMP%", plugin.getTargetTimestamp(duration));
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
if (args.length != 2) {
return Collections.emptyList();
}
final List<String> suggestions = new ArrayList<>();
if (sender.hasMaintenancePermission("timer") && plugin.isMaintenance()) {
suggestions.add("global");
}
if (sender.hasMaintenancePermission("singleserver.timer")) {
suggestions.addAll(plugin.getCommandManager().getMaintenanceServersCompletion(args[1].toLowerCase(Locale.ROOT)));
}
return suggestions;
return args.length == 2 && sender.hasMaintenancePermission("singleserver.timer") ? plugin.getCommandManager().getMaintenanceServersCompletion(args[1].toLowerCase()) : Collections.emptyList();
}
}
@@ -23,11 +23,8 @@ import eu.kennytv.maintenance.core.proxy.command.ProxyCommandInfo;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import org.jetbrains.annotations.Nullable;
public final class SingleScheduleTimerCommand extends ProxyCommandInfo {
@@ -43,90 +40,56 @@ public final class SingleScheduleTimerCommand extends ProxyCommandInfo {
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (args.length == 3) {
scheduleGlobal(sender, null, args[1], args[2]);
} else if (args.length == 4 || args.length == 5) {
final String mode = args.length == 5 ? args[2] : null;
final String enableInArg = args.length == 5 ? args[3] : args[2];
final String durationArg = args.length == 5 ? args[4] : args[3];
if (args[1].equalsIgnoreCase("global")) {
scheduleGlobal(sender, mode, enableInArg, durationArg);
} else {
scheduleSingle(sender, args[1], mode, enableInArg, durationArg);
if (checkPermission(sender, "timer")) return;
final Duration enableIn = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[1]);
final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[2], false);
if (enableIn == null || duration == null) {
sender.send(getHelpMessage());
return;
}
if (plugin.isMaintenance()) {
sender.send(getMessage("alreadyEnabled"));
return;
}
plugin.scheduleMaintenanceRunnable(duration, enableIn);
sender.send(getMessage(
"scheduletimerStarted",
"%TIME%", plugin.getRunnable().getTime(),
"%DURATION%", plugin.getFormattedTime((int) duration.getSeconds())
));
} else if (args.length == 4) {
if (checkPermission(sender, "singleserver.timer")) return;
final Duration enableIn = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[2], false);
final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[3], false);
if (enableIn == null || duration == null) {
sender.send(getHelpMessage());
return;
}
final Server server = plugin.getCommandManager().checkSingleTimerServerArg(sender, args[1]);
if (server == null) return;
if (plugin.isMaintenance(server)) {
sender.send(getMessage("singleServerAlreadyEnabled", "%SERVER%", server.getName()));
return;
}
final MaintenanceRunnableBase runnable = plugin.scheduleSingleMaintenanceRunnable(server, enableIn, duration);
sender.send(getMessage(
"singleScheduletimerStarted",
"%TIME%", runnable.getTime(),
"%DURATION%", plugin.getFormattedTime((int) duration.getSeconds()),
"%SERVER%", server.getName()
));
} else {
sender.send(getHelpMessage());
}
}
private void scheduleGlobal(final SenderInfo sender, @Nullable final String mode, final String enableInArg, final String durationArg) {
if (checkPermission(sender, "timer")) return;
final Duration enableIn = plugin.getCommandManager().parseDurationAndCheckTask(sender, enableInArg);
final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, durationArg, false);
if (enableIn == null || duration == null) {
sender.send(getHelpMessage());
return;
}
if (plugin.isMaintenance()) {
sender.send(getMessage("alreadyEnabled"));
return;
}
plugin.scheduleMaintenanceRunnable(enableIn, duration, mode);
sender.send(getMessage(
"scheduletimerStarted",
"%TIME%", plugin.getRunnable().getTime(),
"%DURATION%", plugin.getFormattedTime((int) duration.getSeconds())
));
}
private void scheduleSingle(final SenderInfo sender, final String serverArg, @Nullable final String mode,
final String enableInArg, final String durationArg) {
if (checkPermission(sender, "singleserver.timer")) return;
final Duration enableIn = plugin.getCommandManager().parseDurationAndCheckTask(sender, enableInArg, false);
final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, durationArg, false);
if (enableIn == null || duration == null) {
sender.send(getHelpMessage());
return;
}
final Server server = plugin.getCommandManager().checkSingleTimerServerArg(sender, serverArg);
if (server == null) return;
if (plugin.isMaintenance(server)) {
sender.send(getMessage("singleServerAlreadyEnabled", "%SERVER%", server.getName()));
return;
}
final MaintenanceRunnableBase runnable = plugin.scheduleSingleMaintenanceRunnable(server, enableIn, duration, mode);
sender.send(getMessage(
"singleScheduletimerStarted",
"%TIME%", runnable.getTime(),
"%DURATION%", plugin.getFormattedTime((int) duration.getSeconds()),
"%SERVER%", server.getName()
));
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
if (args.length == 2) {
final List<String> suggestions = new ArrayList<>();
if (sender.hasMaintenancePermission("timer")) {
suggestions.add("global");
}
if (sender.hasMaintenancePermission("singleserver.timer")) {
suggestions.addAll(plugin.getCommandManager().getServersCompletion(args[1].toLowerCase(Locale.ROOT)));
}
return suggestions;
}
if (args.length == 3) {
if (args[1].equalsIgnoreCase("global")) {
return sender.hasMaintenancePermission("timer") ? getModesCompletion() : Collections.emptyList();
}
if (sender.hasMaintenancePermission("singleserver.timer") && plugin.getServer(args[1]) != null) {
return getModesCompletion();
}
}
return Collections.emptyList();
return args.length == 2 && sender.hasMaintenancePermission("singleserver.timer") ? plugin.getCommandManager().getServersCompletion(args[1].toLowerCase()) : Collections.emptyList();
}
}
@@ -21,15 +21,10 @@ import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.core.proxy.command.ProxyCommandInfo;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
import eu.kennytv.maintenance.core.util.DiscordWebhook;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
public final class SingleStarttimerCommand extends ProxyCommandInfo {
@@ -45,90 +40,49 @@ public final class SingleStarttimerCommand extends ProxyCommandInfo {
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (args.length == 2) {
startGlobal(sender, null, args[1]);
} else if (args.length == 3 || args.length == 4) {
final String mode = args.length == 4 ? args[2] : null;
final String durationArg = args.length == 4 ? args[3] : args[2];
if (args[1].equalsIgnoreCase("global")) {
startGlobal(sender, mode, durationArg);
} else {
startSingle(sender, args[1], mode, durationArg);
if (checkPermission(sender, "timer")) return;
final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[1]);
if (duration == null) {
sender.send(getHelpMessage());
return;
}
if (plugin.isMaintenance()) {
sender.send(getMessage("alreadyEnabled"));
return;
}
plugin.startMaintenanceRunnable(duration, true);
sender.send(getMessage("starttimerStarted", "%TIME%", plugin.getRunnable().getTime()));
} else if (args.length == 3) {
if (checkPermission(sender, "singleserver.timer")) return;
final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[2], false);
if (duration == null) {
sender.send(getHelpMessage());
return;
}
final Server server = plugin.getCommandManager().checkSingleTimerServerArg(sender, args[1]);
if (server == null) return;
if (plugin.isMaintenance(server)) {
sender.send(getMessage("singleServerAlreadyEnabled", "%SERVER%", server.getName()));
return;
}
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, duration, true);
sender.send(getMessage(
"singleStarttimerStarted",
"%TIME%", runnable.getTime(),
"%SERVER%", server.getName()
));
} else {
sender.send(getHelpMessage());
}
}
private void startGlobal(final SenderInfo sender, @Nullable final String mode, final String durationArg) {
if (checkPermission(sender, "timer")) return;
final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, durationArg);
if (duration == null) {
sender.send(getHelpMessage());
return;
}
if (plugin.isMaintenance()) {
sender.send(getMessage("alreadyEnabled"));
return;
}
plugin.startMaintenanceRunnable(duration, true, mode);
final Component message = getMessage("starttimerStarted", "%TIME%", plugin.getRunnable().getTime());
sender.send(message);
plugin.sendWebhookMessage("webhookStarttimerStarted", DiscordWebhook.EventType.STARTTIMER_STARTED,
"%TIME%", plugin.getRunnable().getTime(),
"%TIMESTAMP%", plugin.getTargetTimestamp(duration));
}
private void startSingle(final SenderInfo sender, final String serverArg, @Nullable final String mode, final String durationArg) {
if (checkPermission(sender, "singleserver.timer")) return;
final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, durationArg, false);
if (duration == null) {
sender.send(getHelpMessage());
return;
}
final Server server = plugin.getCommandManager().checkSingleTimerServerArg(sender, serverArg);
if (server == null) return;
if (plugin.isMaintenance(server)) {
sender.send(getMessage("singleServerAlreadyEnabled", "%SERVER%", server.getName()));
return;
}
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, duration, true, mode);
final Component message = getMessage(
"singleStarttimerStarted",
"%TIME%", runnable.getTime(),
"%SERVER%", server.getName()
);
sender.send(message);
plugin.sendWebhookMessage("webhookSingleStarttimerStarted", DiscordWebhook.EventType.STARTTIMER_STARTED,
"%TIME%", runnable.getTime(),
"%SERVER%", server.getName(),
"%TIMESTAMP%", plugin.getTargetTimestamp(duration));
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
if (args.length == 2) {
final List<String> suggestions = new ArrayList<>();
if (sender.hasMaintenancePermission("timer")) {
suggestions.add("global");
}
if (sender.hasMaintenancePermission("singleserver.timer")) {
suggestions.addAll(plugin.getCommandManager().getServersCompletion(args[1].toLowerCase(Locale.ROOT)));
}
return suggestions;
}
if (args.length == 3) {
if (args[1].equalsIgnoreCase("global")) {
return sender.hasMaintenancePermission("timer") ? getModesCompletion() : Collections.emptyList();
}
if (sender.hasMaintenancePermission("singleserver.timer") && plugin.getServer(args[1]) != null) {
return getModesCompletion();
}
}
return Collections.emptyList();
return args.length == 2 && sender.hasMaintenancePermission("singleserver.timer") ? plugin.getCommandManager().getServersCompletion(args[1].toLowerCase()) : Collections.emptyList();
}
}
@@ -17,15 +17,14 @@
*/
package eu.kennytv.maintenance.core.proxy.command.subcommand;
import eu.kennytv.maintenance.api.proxy.DummyServer;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.core.proxy.command.ProxyCommandInfo;
import eu.kennytv.maintenance.core.proxy.server.DummyServer;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
public final class SingleToggleCommand extends ProxyCommandInfo {
@@ -40,121 +39,48 @@ public final class SingleToggleCommand extends ProxyCommandInfo {
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (args.length == 0 || args.length > 3) {
sender.send(getHelpMessage());
return;
}
final boolean maintenance = args[0].equalsIgnoreCase("on");
if (args.length == 1) {
toggleGlobal(sender, maintenance, null);
return;
}
final String server = args[1];
final String mode = args.length == 3 ? args[2] : null;
if (server.equalsIgnoreCase("global")) {
if (!maintenance && args.length == 3) {
sender.send(getHelpMessage());
if (checkPermission(sender, "toggle")) return;
final boolean maintenance = args[0].equalsIgnoreCase("on");
if (maintenance == plugin.isMaintenance()) {
sender.send(getMessage(maintenance ? "alreadyEnabled" : "alreadyDisabled"));
return;
}
toggleGlobal(sender, maintenance, mode);
return;
}
if (!maintenance && args.length != 2) {
sender.send(getHelpMessage());
return;
}
toggleServer(sender, maintenance, server, mode);
}
private void toggleGlobal(final SenderInfo sender, final boolean maintenance, final String mode) {
if (checkPermission(sender, "toggle")) {
return;
}
if (maintenance && plugin.isMaintenance()) {
if (mode != null) {
plugin.getSettings().setActiveMode(mode);
return;
plugin.setMaintenance(maintenance);
} else if (args.length == 2) {
if (checkPermission(sender, "singleserver.toggle")) return;
final boolean maintenance = args[0].equalsIgnoreCase("on");
Server server = plugin.getServer(args[1]);
if (server == null) {
if (maintenance) {
sender.send(getMessage("serverNotFound"));
return;
}
// Let servers be removed from the maintenance list, even if they don't exist on the proxy
server = new DummyServer(args[1]);
if (!plugin.isMaintenance(server)) {
sender.send(getMessage("serverNotFound"));
return;
}
}
sender.send(getMessage("alreadyEnabled"));
return;
}
if (maintenance == plugin.isMaintenance()) {
sender.send(getMessage(maintenance ? "alreadyEnabled" : "alreadyDisabled"));
return;
}
plugin.setMaintenance(maintenance, mode);
}
private void toggleServer(final SenderInfo sender, final boolean maintenance, final String serverArg, final String mode) {
if (checkPermission(sender, "singleserver.toggle")) {
return;
}
Server server = plugin.getServer(serverArg);
if (server == null) {
if (maintenance) {
sender.send(getMessage("serverNotFound"));
return;
}
// Let servers be removed from the maintenance list, even if they don't exist on the proxy
server = new DummyServer(serverArg);
if (!plugin.isMaintenance(server)) {
sender.send(getMessage("serverNotFound"));
return;
}
}
if (maintenance && plugin.isMaintenance(server) && mode != null) {
if (plugin.setMaintenanceModeToServer(server, mode)) {
return;
}
sender.send(getMessage("singleServerAlreadyEnabled", "%SERVER%", server.getName()));
return;
}
if (plugin.setMaintenanceToServer(server, maintenance, mode)) {
if (!sender.isPlayer() || !server.getName().equals(plugin.getServerNameOf(sender))) {
sender.send(getMessage(maintenance ? "singleMaintenanceActivated" : "singleMaintenanceDeactivated", "%SERVER%", server.getName()));
if (plugin.setMaintenanceToServer(server, maintenance)) {
if (!sender.isPlayer() || !server.getName().equals(plugin.getServerNameOf(sender))) {
sender.send(getMessage(maintenance ? "singleMaintenanceActivated" : "singleMaintenanceDeactivated", "%SERVER%", server.getName()));
}
} else {
sender.send(getMessage(maintenance ? "singleServerAlreadyEnabled" : "singleServerAlreadyDisabled", "%SERVER%", server.getName()));
}
} else {
sender.send(getMessage(maintenance ? "singleServerAlreadyEnabled" : "singleServerAlreadyDisabled", "%SERVER%", server.getName()));
sender.send(getHelpMessage());
}
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
if (args.length == 2) {
final List<String> suggestions = new ArrayList<>();
if (sender.hasMaintenancePermission("toggle") && args[0].equalsIgnoreCase("on")) {
suggestions.add("global");
}
if (!sender.hasMaintenancePermission("singleserver.toggle")) {
return suggestions;
}
final List<String> serverSuggestions = args[0].equalsIgnoreCase("off")
? plugin.getCommandManager().getMaintenanceServersCompletion(args[1].toLowerCase(Locale.ROOT))
: plugin.getCommandManager().getServersCompletion(args[1].toLowerCase(Locale.ROOT));
suggestions.addAll(serverSuggestions);
return suggestions;
}
if (args.length == 3 && args[0].equalsIgnoreCase("on") && (sender.hasMaintenancePermission("toggle") || sender.hasMaintenancePermission("singleserver.toggle"))) {
final List<String> modes = new ArrayList<>(getSettings().getPingMessages().getKeys());
modes.remove("default");
return modes;
}
return Collections.emptyList();
if (args.length != 2 || !sender.hasMaintenancePermission("singleserver.toggle")) return Collections.emptyList();
return args[0].equalsIgnoreCase("off") ? plugin.getCommandManager().getMaintenanceServersCompletion(args[1].toLowerCase())
: plugin.getCommandManager().getServersCompletion(args[1].toLowerCase());
}
}
@@ -15,33 +15,28 @@
* 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 eu.kennytv.maintenance.core.command.subcommand;
package eu.kennytv.maintenance.core.proxy.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnable;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.core.proxy.command.ProxyCommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import net.kyori.adventure.text.Component;
public final class StatusCommand extends CommandInfo {
public final class StatusCommand extends ProxyCommandInfo {
public StatusCommand(final MaintenancePlugin plugin) {
super(plugin, "status");
public StatusCommand(final MaintenanceProxyPlugin plugin) {
super(plugin, "singleserver.status");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
final MaintenanceRunnable task = plugin.getCurrentTask();
if (task != null) {
final String key = task.shouldEnable() ? "maintenanceStatusOffWithStartTimer" : "maintenanceStatusOnWithEndTimer";
sender.send(getMessage(key, "%TIME%", task.getTime()));
} else {
sender.send(getMessage(plugin.isMaintenance() ? "maintenanceStatusOn" : "maintenanceStatusOff"));
if (getSettings().getMaintenanceServers().isEmpty()) {
sender.send(getMessage("singleServerMaintenanceListEmpty"));
return;
}
sender.send(getMessage("singleServerMaintenanceList"));
for (final String server : getSettings().getMaintenanceServers()) {
sender.send(getMessage("singleServerMaintenanceListEntry", "%SERVER%", server));
}
}
@Override
public Component getHelpMessage() {
return getMessage("helpGlobalStatus");
}
}
@@ -24,7 +24,6 @@ import eu.kennytv.maintenance.core.proxy.SettingsProxy;
import eu.kennytv.maintenance.core.proxy.util.ProxySenderInfo;
import eu.kennytv.maintenance.core.proxy.util.ServerConnectResult;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.Locale;
import org.jetbrains.annotations.Nullable;
public abstract class ProxyJoinListenerBase extends JoinListenerBase {
@@ -49,7 +48,7 @@ public abstract class ProxyJoinListenerBase extends JoinListenerBase {
protected ServerConnectResult serverConnect(final ProxySenderInfo sender, final Server target, final boolean normalServerConnect) {
// Check waiting server for global maintenance
if (settings.isMaintenance()) {
if (sender.hasMaintenancePermission("bypass") || settings.isWhitelisted(sender.uuid())) return ALLOWED;
if (sender.hasMaintenancePermission("bypass") || settings.isWhitelisted(sender.getUuid())) return ALLOWED;
final Server waitingServer = shouldConnectToWaitingServer(sender);
// Should never be null, but just in case
@@ -71,13 +70,13 @@ public abstract class ProxyJoinListenerBase extends JoinListenerBase {
// Single server maintenance
if (!settings.isMaintenance(target.getName())) return ALLOWED;
if (sender.hasMaintenancePermission("bypass") || settings.isWhitelisted(sender.uuid())
|| sender.hasMaintenancePermission("singleserver.bypass." + target.getName().toLowerCase(Locale.ROOT))) {
if (sender.hasMaintenancePermission("bypass") || settings.isWhitelisted(sender.getUuid())
|| sender.hasMaintenancePermission("singleserver.bypass." + target.getName().toLowerCase())) {
return ALLOWED;
}
if (settings.isJoinNotifications()) {
broadcastJoinNotification(sender.name(), target);
broadcastJoinNotification(sender.getName(), target);
}
if (normalServerConnect) {
@@ -0,0 +1,112 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2024 kennytv (https://github.com/kennytv)
*
* 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 eu.kennytv.maintenance.core.proxy.mysql;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.jetbrains.annotations.Nullable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
public final class MySQL {
private final Logger logger;
private final HikariDataSource hikariDataSource;
public MySQL(final Logger logger, final String hostname, final int port, final String username, final String password, final String database, final boolean useSSL) {
this.logger = logger;
final HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setMaximumPoolSize(10);
hikariConfig.addDataSourceProperty("serverName", hostname);
hikariConfig.addDataSourceProperty("user", username);
hikariConfig.addDataSourceProperty("password", password);
String urlProperty = "jdbc:mysql://" + hostname + ":" + port + "/" + database;
if (!useSSL) {
urlProperty += "?useSSL=false";
}
hikariConfig.addDataSourceProperty("url", urlProperty);
hikariConfig.setJdbcUrl(urlProperty);
hikariConfig.setDataSourceClassName(findDriver("com.mysql.jdbc.jdbc2.optional.MysqlDataSource", "com.mysql.cj.jdbc.MysqlDataSource", "org.mariadb.jdbc.MariaDbDataSource"));
hikariDataSource = new HikariDataSource(hikariConfig);
}
@Nullable
private String findDriver(final String... classNames) {
for (final String name : classNames) {
try {
Class.forName(name);
return name;
} catch (final ClassNotFoundException ignored) {
}
}
throw new IllegalArgumentException("No sql driver class found");
}
public void executeUpdate(final String query, final Consumer<Integer> callback, final Object... objects) {
try (final Connection connection = hikariDataSource.getConnection()) {
try (final PreparedStatement preparedStatement = connection.prepareStatement(query)) {
int current = 1;
for (final Object object : objects) {
preparedStatement.setObject(current, object);
current++;
}
callback.accept(preparedStatement.executeUpdate());
}
} catch (final SQLException e) {
logger.log(Level.SEVERE, "Error while executing update method: " + query);
e.printStackTrace();
}
}
public void executeQuery(final String query, final Consumer<ResultSet> callback, final Object... objects) {
try (final Connection connection = hikariDataSource.getConnection()) {
try (final PreparedStatement preparedStatement = connection.prepareStatement(query)) {
int current = 1;
for (final Object object : objects) {
preparedStatement.setObject(current, object);
current++;
}
try (final ResultSet resultSet = preparedStatement.executeQuery()) {
callback.accept(resultSet);
}
}
} catch (final SQLException e) {
logger.log(Level.SEVERE, "Error while executing query method: " + query);
e.printStackTrace();
}
}
public void executeUpdate(final String query, final Object... objects) {
executeUpdate(query, res -> {
}, objects);
}
public void close() {
hikariDataSource.close();
}
}
@@ -1,258 +0,0 @@
package eu.kennytv.maintenance.core.proxy.redis;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.core.proxy.SettingsProxy;
import java.net.URI;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.Locale;
import org.jetbrains.annotations.Nullable;
import redis.clients.jedis.ConnectionPoolConfig;
import redis.clients.jedis.RedisClient;
import redis.clients.jedis.StreamEntryID;
import redis.clients.jedis.params.XReadParams;
import redis.clients.jedis.resps.StreamEntry;
public final class RedisHandler {
private static final String REDIS_STREAM_KEY = "maintenance:stream";
private static final String REDIS_MAINTENANCE_KEY = "maintenance:status";
private static final String REDIS_MODE_KEY = "maintenance:mode";
private static final String REDIS_SERVERS_KEY = "maintenance:servers";
private static final String REDIS_SERVER_MODES_KEY = "maintenance:server_modes";
private static final String REDIS_WHITELIST_KEY = "maintenance:whitelist";
private static final String MSG_TYPE_MAINTENANCE_UPDATE = "status";
private static final String MSG_TYPE_SERVER_ADD = "server_add";
private static final String MSG_TYPE_SERVER_REMOVE = "server_remove";
private static final String MSG_TYPE_PLAYER_ADD = "player_add";
private static final String MSG_TYPE_PLAYER_REMOVE = "player_remove";
private static final String MSG_TYPE = "type";
private static final String MSG_VALUE = "val";
private final AtomicBoolean running = new AtomicBoolean(false);
private final MaintenanceProxyPlugin plugin;
private final SettingsProxy settings;
private RedisClient client;
private StreamEntryID lastStreamId = new StreamEntryID();
public RedisHandler(final MaintenanceProxyPlugin plugin, final SettingsProxy settings) {
this.plugin = plugin;
this.settings = settings;
}
public void setup(final String redisUri) {
plugin.getLogger().info("Trying to open Redis connection...");
final ConnectionPoolConfig poolConfig = new ConnectionPoolConfig();
poolConfig.setMaxWait(Duration.ofSeconds(5));
poolConfig.setMaxTotal(2);
client = RedisClient.builder().poolConfig(poolConfig).fromURI(URI.create(redisUri)).build();
// Get the latest stream ID to only receive new messages
final List<StreamEntry> messages = client.xrevrange(REDIS_STREAM_KEY, (StreamEntryID) null, null, 1);
if (!messages.isEmpty()) {
lastStreamId = messages.getFirst().getID();
}
running.set(true);
plugin.async(this::listenToStream);
plugin.getLogger().info("Connected to Redis!");
}
public boolean loadMaintenanceStatus() {
return Boolean.parseBoolean(client.get(REDIS_MAINTENANCE_KEY));
}
public @Nullable String loadGlobalMode() {
return client.get(REDIS_MODE_KEY);
}
public Map<String, String> loadMaintenanceServers() {
final Set<String> servers = client.smembers(REDIS_SERVERS_KEY);
final Map<String, String> serverModes = new HashMap<>();
if (servers == null) {
return serverModes;
}
final Map<String, String> persistedModes = client.hgetAll(REDIS_SERVER_MODES_KEY);
for (final String server : servers) {
serverModes.put(server, normalizeMode(persistedModes.get(server)));
}
return serverModes;
}
public void loadPlayers(final Map<UUID, String> players) {
for (final Map.Entry<String, String> entry : client.hgetAll(REDIS_WHITELIST_KEY).entrySet()) {
players.put(UUID.fromString(entry.getKey()), entry.getValue());
}
}
public void set(final boolean maintenance, final String mode) {
client.set(REDIS_MAINTENANCE_KEY, Boolean.toString(maintenance));
client.set(REDIS_MODE_KEY, mode);
client.xadd(REDIS_STREAM_KEY, StreamEntryID.NEW_ENTRY, Map.of(
MSG_TYPE, MSG_TYPE_MAINTENANCE_UPDATE,
MSG_VALUE, Boolean.toString(maintenance),
"mode", mode
));
}
public boolean addServer(final String server, final String mode) {
if (client.sadd(REDIS_SERVERS_KEY, server) < 1) {
return false;
}
client.hset(REDIS_SERVER_MODES_KEY, server, mode);
client.xadd(REDIS_STREAM_KEY, StreamEntryID.NEW_ENTRY, Map.of(
MSG_TYPE, MSG_TYPE_SERVER_ADD,
MSG_VALUE, server,
"mode", mode
));
return true;
}
public void setServerMode(final String server, final String mode) {
client.hset(REDIS_SERVER_MODES_KEY, server, mode);
client.xadd(REDIS_STREAM_KEY, StreamEntryID.NEW_ENTRY, Map.of(
MSG_TYPE, MSG_TYPE_SERVER_ADD,
MSG_VALUE, server,
"mode", mode
));
}
public boolean removeServer(final String server) {
if (client.srem(REDIS_SERVERS_KEY, server) < 1) {
return false;
}
client.hdel(REDIS_SERVER_MODES_KEY, server);
send(MSG_TYPE_SERVER_REMOVE, server);
return true;
}
public void addPlayer(final UUID uuid, final String name) {
final String value = uuid.toString();
client.hset(REDIS_WHITELIST_KEY, value, name);
client.xadd(REDIS_STREAM_KEY, StreamEntryID.NEW_ENTRY, Map.of(
MSG_TYPE, MSG_TYPE_PLAYER_ADD,
MSG_VALUE, value,
"name", name
));
}
public void removePlayer(final UUID uuid) {
final String value = uuid.toString();
client.hdel(REDIS_WHITELIST_KEY, value);
send(MSG_TYPE_PLAYER_REMOVE, value);
}
private void send(final String type, final String value) {
client.xadd(REDIS_STREAM_KEY, StreamEntryID.NEW_ENTRY, Map.of(MSG_TYPE, type, MSG_VALUE, value));
}
private void listenToStream() {
while (running.get()) {
try {
final List<Map.Entry<String, List<StreamEntry>>> result = client.xread(
XReadParams.xReadParams().block(5000),
Map.of(REDIS_STREAM_KEY, lastStreamId)
);
if (result != null) {
for (final Map.Entry<String, List<StreamEntry>> streamEntries : result) {
for (final StreamEntry entry : streamEntries.getValue()) {
plugin.sync(() -> processStreamMessage(entry));
lastStreamId = entry.getID();
}
}
}
} catch (final Exception e) {
if (running.get()) {
plugin.getLogger().log(Level.WARNING, "Error reading from Redis stream", e);
try {
Thread.sleep(1000); // retry
} catch (final InterruptedException ignored) {
Thread.currentThread().interrupt();
}
}
}
}
}
private void processStreamMessage(final StreamEntry message) {
final Map<String, String> body = message.getFields();
final String type = body.get(MSG_TYPE);
if (type == null) {
return;
}
final String value = body.get(MSG_VALUE);
switch (type) {
case MSG_TYPE_MAINTENANCE_UPDATE -> handleStatus(value, body.get("mode"));
case MSG_TYPE_SERVER_ADD -> handleServerStatus(value, body.get("mode"), true, "Server added to maintenance via Redis: ");
case MSG_TYPE_SERVER_REMOVE -> handleServerStatus(value, null, false, "Server removed from maintenance via Redis: ");
case MSG_TYPE_PLAYER_ADD -> handlePlayerAdd(value, body.get("name"));
case MSG_TYPE_PLAYER_REMOVE -> handlePlayerRemove(value);
}
}
private void handleStatus(final String value, @Nullable final String mode) {
final boolean maintenance = Boolean.parseBoolean(value);
if (settings.isMaintenance() != maintenance) {
plugin.getLogger().info("Maintenance status updated via Redis: " + maintenance);
settings.setMaintenanceDirect(maintenance, mode);
plugin.serverActions(maintenance);
return;
}
if (maintenance && !normalizeMode(mode).equals(normalizeMode(settings.activeMode()))) {
settings.setActiveModeDirect(mode);
}
}
private void handleServerStatus(final String value, @Nullable final String mode, final boolean maintenance, final String log) {
if (value == null) {
return;
}
final boolean success;
if (maintenance) {
success = settings.addMaintenanceServerDirect(value, mode);
settings.setMaintenanceServerModeDirect(value, mode);
} else {
success = settings.removeMaintenanceServerDirect(value);
}
if (success) {
plugin.getLogger().info(log + value);
final Server server = plugin.getServerOrDummy(value);
plugin.serverActions(server, maintenance);
}
}
private void handlePlayerAdd(final String uuid, final String name) {
settings.addWhitelistedPlayerDirect(UUID.fromString(uuid), name);
}
private void handlePlayerRemove(final String value) {
settings.removeWhitelistedPlayerDirect(UUID.fromString(value));
}
public void close() {
running.set(false);
if (client != null) {
client.close();
client = null;
}
}
private String normalizeMode(@Nullable final String mode) {
return mode == null || mode.isBlank() ? "default" : mode.toLowerCase(Locale.ROOT);
}
}
@@ -17,23 +17,19 @@
*/
package eu.kennytv.maintenance.core.proxy.runnable;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.api.proxy.MaintenanceProxy;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
public class SingleMaintenanceRunnable extends MaintenanceRunnableBase {
protected final Server server;
protected final String mode;
public SingleMaintenanceRunnable(final MaintenancePlugin plugin, final Settings settings, final int seconds,
final boolean enable, final Server server, @Nullable final String mode) {
public SingleMaintenanceRunnable(final MaintenancePlugin plugin, final Settings settings, final int seconds, final boolean enable, final Server server) {
super(plugin, settings, seconds, enable);
this.server = server;
this.mode = mode;
}
@Override
@@ -43,12 +39,7 @@ public class SingleMaintenanceRunnable extends MaintenanceRunnableBase {
@Override
protected void finish() {
final MaintenanceProxyPlugin proxyPlugin = (MaintenanceProxyPlugin) plugin;
proxyPlugin.setMaintenanceToServer(server, enable, mode);
// Make sure no-ops have the platform task cancelled as well
if (proxyPlugin.getServerTasks().remove(server.getName(), this)) {
getTask().cancel();
}
((MaintenanceProxy) plugin).setMaintenanceToServer(server, enable);
}
@Override
@@ -21,16 +21,14 @@ import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import java.time.Duration;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
public final class SingleMaintenanceScheduleRunnable extends SingleMaintenanceRunnable {
private final int maintenanceDurationSeconds;
public SingleMaintenanceScheduleRunnable(final MaintenancePlugin plugin, final Settings settings, final int seconds,
final int maintenanceDuration, final Server server, @Nullable final String mode) {
super(plugin, settings, seconds, true, server, mode);
public SingleMaintenanceScheduleRunnable(final MaintenancePlugin plugin, final Settings settings, final int seconds, final int maintenanceDuration, final Server server) {
super(plugin, settings, seconds, true, server);
this.maintenanceDurationSeconds = maintenanceDuration;
}
@@ -15,11 +15,17 @@
* 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 eu.kennytv.maintenance.api.proxy;
package eu.kennytv.maintenance.core.proxy.server;
import net.kyori.adventure.text.Component;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
public record DummyServer(String name) implements Server {
public final class DummyServer implements Server {
private final String name;
public DummyServer(final String name) {
this.name = name;
}
@Override
public String getName() {
@@ -19,5 +19,20 @@ package eu.kennytv.maintenance.core.proxy.util;
import java.util.UUID;
public record ProfileLookup(UUID uuid, String name) {
public final class ProfileLookup {
private final UUID uuid;
private final String name;
public ProfileLookup(final UUID uuid, final String name) {
this.uuid = uuid;
this.name = name;
}
public UUID getUuid() {
return uuid;
}
public String getName() {
return name;
}
}
@@ -18,11 +18,18 @@
package eu.kennytv.maintenance.core.proxy.util;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import java.util.UUID;
import net.kyori.adventure.text.Component;
public record ProxyOfflineSenderInfo(UUID uuid, String name) implements ProxySenderInfo {
public final class ProxyOfflineSenderInfo implements ProxySenderInfo {
private final UUID uuid;
private final String name;
public ProxyOfflineSenderInfo(final UUID uuid, final String name) {
this.uuid = uuid;
this.name = name;
}
@Override
public boolean canAccess(final Server server) {
@@ -33,6 +40,16 @@ public record ProxyOfflineSenderInfo(UUID uuid, String name) implements ProxySen
public void disconnect(final Component component) {
}
@Override
public UUID getUuid() {
return uuid;
}
@Override
public String getName() {
return name;
}
@Override
public boolean hasPermission(final String permission) {
return false;
@@ -19,7 +19,7 @@ package eu.kennytv.maintenance.core.proxy.util;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.util.SenderInfo;
import net.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
public interface ProxySenderInfo extends SenderInfo {
+3 -4
View File
@@ -16,10 +16,9 @@ sourceSets {
dependencies {
api(projects.maintenanceApi)
compileOnlyApi(libs.adventureApi)
compileOnlyApi(libs.adventureTextMinimessage)
compileOnlyApi(libs.adventureTextSerializerPlain)
compileOnlyApi(libs.adventureTextSerializerLegacy)
api(projects.adventure.adventureApi) {
targetConfiguration = "shadow"
}
compileOnly(libs.luckperms)
compileOnly(libs.serverlistplus)
compileOnly(libs.guava)
@@ -32,11 +32,12 @@ import eu.kennytv.maintenance.core.dump.PluginDump;
import eu.kennytv.maintenance.core.hook.ServerListPlusHook;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnable;
import eu.kennytv.maintenance.core.runnable.MaintenanceScheduleRunnable;
import eu.kennytv.maintenance.core.util.DiscordWebhook;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.core.util.ServerType;
import eu.kennytv.maintenance.core.util.Task;
import eu.kennytv.maintenance.core.util.Version;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.format.NamedTextColor;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
@@ -46,7 +47,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -61,8 +62,6 @@ import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.jetbrains.annotations.Nullable;
public abstract class MaintenancePlugin implements Maintenance {
@@ -97,30 +96,11 @@ public abstract class MaintenancePlugin implements Maintenance {
}
@Override
public void setMaintenance(final boolean maintenance, final String mode) {
settings.setMaintenance(maintenance, mode);
public void setMaintenance(final boolean maintenance) {
settings.setMaintenance(maintenance);
settings.getConfig().set("maintenance-enabled", maintenance);
settings.saveConfig();
serverActions(maintenance);
}
public void serverActions(final boolean maintenance) {
if (isTaskRunning()) {
cancelTask();
}
if (serverListPlusHook != null && settings.isEnablePingMessages()) {
serverListPlusHook.setEnabled(!maintenance);
}
broadcast(maintenance ? settings.getMessage("maintenanceActivated") : settings.getMessage("maintenanceDeactivated"));
if (maintenance && settings.isKickOnlinePlayers()) {
kickPlayers();
}
eventManager.callEvent(new MaintenanceChangedEvent(maintenance));
if (maintenance) {
sendWebhookMessage("webhookMaintenanceActivated", DiscordWebhook.EventType.MAINTENANCE_ENABLED);
} else {
sendWebhookMessage("webhookMaintenanceDeactivated", DiscordWebhook.EventType.MAINTENANCE_DISABLED);
}
for (final String command : (maintenance ? settings.getCommandsOnMaintenanceEnable() : settings.getCommandsOnMaintenanceDisable())) {
try {
@@ -131,35 +111,30 @@ public abstract class MaintenancePlugin implements Maintenance {
}
}
public void sendWebhookMessage(final String messageKey, final DiscordWebhook.EventType eventType, final String... replacements) {
if (!settings.isWebhookEnabled() || !settings.isWebhookEventEnabled(eventType.configKey())) {
return;
public void serverActions(final boolean maintenance) {
if (isTaskRunning()) {
cancelTask();
}
if (serverListPlusHook != null && settings.isEnablePingMessages()) {
serverListPlusHook.setEnabled(!maintenance);
}
async(() -> {
try {
DiscordWebhook.sendMessage(settings.getWebhookMessage(messageKey, replacements), eventType, settings);
} catch (final Exception e) {
getLogger().log(Level.WARNING, "Could not send Discord webhook message", e);
if (maintenance) {
broadcast(settings.getMessage("maintenanceActivated"));
if (settings.isKickOnlinePlayers()) {
kickPlayers();
}
});
} else {
broadcast(settings.getMessage("maintenanceDeactivated"));
}
eventManager.callEvent(new MaintenanceChangedEvent(maintenance));
}
public String getTargetTimestamp(final Duration duration) {
return Long.toString((System.currentTimeMillis() + duration.toMillis()) / TimeUnit.SECONDS.toMillis(1));
}
public String replacePingVariables(final String component) {
return replacePingVariables(component, settings.activeMode());
}
public String replacePingVariables(String component, @Nullable final String mode) {
public String replacePingVariables(String component) {
if (component.contains("%TIMER%")) {
component = component.replace("%TIMER%", getTimerMessage());
}
final String reason = settings.activeReason() == null ? "" : settings.activeReason();
component = component.replace("%REASON%", reason);
component = component.replace("%MODE%", mode == null ? "default" : mode);
component = component.replace("%ONLINE%", String.valueOf(getOnlinePlayers()));
component = component.replace("%MAX%", String.valueOf(getMaxPlayers()));
return component;
@@ -193,18 +168,14 @@ public abstract class MaintenancePlugin implements Maintenance {
private void append(final StringBuilder builder, final String timeUnit, final int time) {
if (time == 0) return;
if (!builder.isEmpty()) {
if (builder.length() != 0) {
builder.append(' ');
}
builder.append(time).append(' ').append(settings.language.getString(time == 1 ? timeUnit : timeUnit + "s"));
}
public void startMaintenanceRunnable(final Duration duration, final boolean enable) {
startMaintenanceRunnable(duration, enable, null);
}
public void startMaintenanceRunnable(final Duration duration, final boolean enable, @Nullable final String mode) {
runnable = new MaintenanceRunnable(this, settings, (int) duration.getSeconds(), enable, mode);
runnable = new MaintenanceRunnable(this, settings, (int) duration.getSeconds(), enable);
// Save the endtimer to be able to continue it after a server stop
if (settings.isSaveEndtimerOnStop() && !runnable.shouldEnable()) {
settings.setSavedEndtimer(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(runnable.getSecondsLeft()));
@@ -212,11 +183,7 @@ public abstract class MaintenancePlugin implements Maintenance {
}
public void scheduleMaintenanceRunnable(final Duration enableIn, final Duration maintenanceDuration) {
scheduleMaintenanceRunnable(enableIn, maintenanceDuration, null);
}
public void scheduleMaintenanceRunnable(final Duration enableIn, final Duration maintenanceDuration, @Nullable final String mode) {
runnable = new MaintenanceScheduleRunnable(this, settings, (int) enableIn.getSeconds(), (int) maintenanceDuration.getSeconds(), mode);
runnable = new MaintenanceScheduleRunnable(this, settings, (int) enableIn.getSeconds(), (int) maintenanceDuration.getSeconds());
}
public boolean updateAvailable() {
@@ -260,7 +227,7 @@ public abstract class MaintenancePlugin implements Maintenance {
if (compare < 0) {
getLogger().warning("Newest version available: Version " + newestVersion + ", you're on " + version);
} else if (compare > 0) {
if (version.getTag() != null && !version.getTag().isBlank()) {
if (version.getTag().equalsIgnoreCase("snapshot")) {
getLogger().info("You're running a development version, please report bugs on the Discord server (https://discord.gg/vGCUzHq) or the GitHub issue tracker (https://github.com/kennytv/Maintenance/issues)");
} else {
getLogger().info("You're running a version, that doesn't exist!");
@@ -270,9 +237,11 @@ public abstract class MaintenancePlugin implements Maintenance {
}
public boolean installUpdate() throws Exception {
final String fileName = "Maintenance-" + serverType.name() + "-" + newestVersion + ".jar";
// Sponge and Velocity need their own jar
final String platformInfix = serverType == ServerType.VELOCITY ? "Velocity-" : serverType == ServerType.SPONGE ? "Sponge-" : "";
final String fileName = "Maintenance-" + platformInfix + newestVersion + ".jar";
final Path tempFilePath = Paths.get(getPluginFolder() + "Maintenance.tmp");
final URLConnection connection = URI.create("https://github.com/kennytv/Maintenance/releases/download/" + newestVersion + "/" + fileName).toURL().openConnection();
final URLConnection connection = new URL("https://github.com/kennytv/Maintenance/releases/download/" + newestVersion + "/" + fileName).openConnection();
try (final BufferedInputStream is = new BufferedInputStream(connection.getInputStream());
final BufferedOutputStream os = new BufferedOutputStream(Files.newOutputStream(tempFilePath))) {
writeFile(is, os);
@@ -304,10 +273,8 @@ public abstract class MaintenancePlugin implements Maintenance {
}
private void checkNewestVersion() throws Exception {
final URLConnection connection = URI.create("https://hangar.papermc.io/api/v1/projects/Maintenance/latestrelease").toURL().openConnection();
final URLConnection connection = new URL("https://hangar.papermc.io/api/v1/projects/Maintenance/latestrelease").openConnection();
connection.setRequestProperty("User-Agent", "Maintenance/" + getVersion());
connection.setConnectTimeout(5_000);
connection.setReadTimeout(10_000);
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
final String newVersionString = reader.readLine();
final Version newVersion = new Version(newVersionString);
@@ -320,7 +287,7 @@ public abstract class MaintenancePlugin implements Maintenance {
public String pasteDump() {
final MaintenanceDump dump = new MaintenanceDump(this, settings);
try {
final HttpURLConnection connection = (HttpURLConnection) URI.create("https://api.pastes.dev/post").toURL().openConnection();
final HttpURLConnection connection = (HttpURLConnection) new URL("https://api.pastes.dev/post").openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("User-Agent", "Maintenance/" + getVersion());
@@ -361,7 +328,8 @@ public abstract class MaintenancePlugin implements Maintenance {
try {
loadIcon(file);
} catch (final Exception e) {
getLogger().log(Level.WARNING, "Could not load the 'maintenance-icon.png' file!", e);
getLogger().log(Level.WARNING, "Could not load the 'maintenance-icon.png' file!");
e.printStackTrace();
}
}
@@ -406,10 +374,6 @@ public abstract class MaintenancePlugin implements Maintenance {
return runnable != null;
}
public @Nullable MaintenanceRunnable getCurrentTask() {
return runnable;
}
@Override
public Settings getSettings() {
return settings;
@@ -472,10 +436,6 @@ public abstract class MaintenancePlugin implements Maintenance {
return "plugins/";
}
public void sync(final Runnable runnable) {
async(runnable);
}
public abstract void async(Runnable runnable);
protected abstract void executeConsoleCommand(String command);
@@ -20,8 +20,11 @@ package eu.kennytv.maintenance.core;
import eu.kennytv.maintenance.api.event.MaintenanceReloadedEvent;
import eu.kennytv.maintenance.core.config.Config;
import eu.kennytv.maintenance.core.config.ConfigSection;
import eu.kennytv.maintenance.core.config.DisplayedMessages;
import eu.kennytv.maintenance.core.util.ServerType;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.TextComponent;
import eu.kennytv.maintenance.lib.kyori.adventure.text.minimessage.MiniMessage;
import eu.kennytv.maintenance.lib.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -29,43 +32,34 @@ import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.function.BiConsumer;
import java.util.logging.Level;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.jetbrains.annotations.Nullable;
public class Settings implements eu.kennytv.maintenance.api.Settings {
public static final String NEW_LINE_REPLACEMENT = "<br>";
private static final int CONFIG_VERSION = 12;
private static final int LANGUAGE_VERSION = 5;
private static final int CONFIG_VERSION = 9;
private static final int LANGUAGE_VERSION = 2;
private static final Random RANDOM = new Random();
protected final MaintenancePlugin plugin;
private final Map<UUID, String> whitelistedPlayers = new HashMap<>();
private final String[] unsupportedFields;
protected boolean maintenance;
protected String activeMode;
protected String activeReason;
private Set<Integer> broadcastIntervals;
private DisplayedMessages pingMessages;
private DisplayedMessages timerSpecificPingMessages;
private List<String> pingMessages;
private List<String> timerSpecificPingMessages;
private List<String> commandsOnMaintenanceEnable;
private List<String> commandsOnMaintenanceDisable;
private DisplayedMessages legacyParsedPlayerCountMessages;
private DisplayedMessages legacyParsedTimerPlayerCountMessages;
private DisplayedMessages legacyParsedPlayerCountHoverLines;
private DisplayedMessages legacyParsedTimerPlayerCountHoverLines;
private String legacyParsedPlayerCountMessage;
private String legacyParsedTimerPlayerCountMessage;
private List<String> legacyParsedPlayerCountHoverLines;
private List<String> legacyParsedTimerPlayerCountHoverLines;
private String prefixString;
private String plainTextPrefix;
private String languageName;
private boolean enablePingMessages;
private boolean customPlayerCountMessage;
@@ -78,13 +72,6 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
private boolean debug;
private long savedEndtimer;
// Webhook settings
private boolean webhookEnabled;
private Set<String> webhookEnabledEvents;
private String webhookUrl;
private String webhookUsername;
private String webhookAvatarUrl;
protected Config config;
protected Config language;
protected Config whitelist;
@@ -132,7 +119,6 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
}
prefixString = language.getString("prefix");
plainTextPrefix = PlainTextComponentSerializer.plainText().serialize(parse(prefixString));
plugin.getEventManager().callEvent(new MaintenanceReloadedEvent());
}
@@ -175,9 +161,6 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
if (file.exists()) return;
try (final InputStream in = plugin.getResource(fileName)) {
if (in == null) {
throw new IOException("No bundled language file " + fileName);
}
Files.copy(in, file.toPath());
} catch (final IOException e) {
plugin.getLogger().warning("Unable to provide language " + languageName);
@@ -196,16 +179,14 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
final ConfigSection pingMessageSection = config.getSection("ping-message");
enablePingMessages = pingMessageSection.getBoolean("enabled", true);
// Can't store this pre-parsed as components because gradients will break replacements
pingMessages = loadPingMessages(pingMessageSection.getSection("messages"));
pingMessages = loadPingMessages(pingMessageSection.getStringList("messages"));
if (pingMessageSection.getBoolean("enable-timer-specific-messages")) {
timerSpecificPingMessages = loadPingMessages(pingMessageSection.getSection("timer-messages"));
timerSpecificPingMessages = loadPingMessages(pingMessageSection.getStringList("timer-messages"));
} else {
timerSpecificPingMessages = null;
}
maintenance = config.getBoolean("maintenance-enabled");
activeMode = normalizeMode(config.getString("active-mode"));
activeReason = normalizeReason(config.getString("active-reason"));
commandsOnMaintenanceEnable = config.getStringList("commands-on-maintenance-enable");
commandsOnMaintenanceDisable = config.getStringList("commands-on-maintenance-disable");
customMaintenanceIcon = config.getBoolean("custom-maintenance-icon");
@@ -216,35 +197,34 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
if (plugin.getServerType() != ServerType.SPONGE) {
final ConfigSection playerCountMessageSection = config.getSection("player-count-message");
customPlayerCountMessage = playerCountMessageSection.getBoolean("enabled");
legacyParsedPlayerCountMessages = loadPlayerCountMessages(playerCountMessageSection.getSection("messages"));
legacyParsedPlayerCountMessage = toLegacy(parse(getConfigMessage(playerCountMessageSection, "message")));
if (playerCountMessageSection.getBoolean("enable-timer-specific-message")) {
legacyParsedTimerPlayerCountMessages = loadPlayerCountMessages(playerCountMessageSection.getSection("timer-messages"));
legacyParsedTimerPlayerCountMessage = toLegacy(parse(getConfigMessage(playerCountMessageSection, "timer-message")));
} else {
legacyParsedTimerPlayerCountMessages = null;
legacyParsedTimerPlayerCountMessage = null;
}
}
final ConfigSection listHoverMessageSection = config.getSection("player-list-hover-message");
customPlayerCountHoverMessage = listHoverMessageSection.getBoolean("enabled");
legacyParsedPlayerCountHoverLines = loadPlayerCountHoverMessages(listHoverMessageSection.getSection("messages"));
legacyParsedPlayerCountHoverLines = new ArrayList<>();
for (final String line : listHoverMessageSection.getString("message").split("<br>")) {
legacyParsedPlayerCountHoverLines.add(toLegacy(parse(line)));
}
if (listHoverMessageSection.getBoolean("enable-timer-specific-message")) {
legacyParsedTimerPlayerCountHoverLines = loadPlayerCountHoverMessages(listHoverMessageSection.getSection("timer-messages"));
legacyParsedTimerPlayerCountHoverLines = new ArrayList<>();
for (final String line : listHoverMessageSection.getString("timer-message").split("<br>")) {
legacyParsedTimerPlayerCountHoverLines.add(toLegacy(parse(line)));
}
} else {
legacyParsedTimerPlayerCountHoverLines = null;
}
languageName = config.getString("language").toLowerCase(Locale.ROOT);
languageName = config.getString("language").toLowerCase();
kickOnlinePlayers = config.getBoolean("kick-online-players", true);
updateChecks = config.getBoolean("update-checks", true);
debug = config.getBoolean("debug");
final ConfigSection webhookSection = config.getSection("webhook");
webhookEnabled = webhookSection.getBoolean("enabled");
webhookEnabledEvents = new HashSet<>(webhookSection.getStringList("enabled-events"));
webhookUrl = webhookSection.getString("url", "");
webhookUsername = webhookSection.getString("username", "Maintenance");
webhookAvatarUrl = webhookSection.getString("avatar-url", "");
final ConfigSection section = config.getSection("continue-endtimer-after-restart");
saveEndtimerOnStop = section.getBoolean("enabled");
savedEndtimer = section.getLong("end");
@@ -253,12 +233,6 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
plugin.loadMaintenanceIcon();
}
loadWhitelistedPlayers();
loadExtraSettings();
}
protected void loadWhitelistedPlayers() {
whitelistedPlayers.clear();
for (final Map.Entry<String, Object> entry : whitelist.getValues().entrySet()) {
try {
@@ -267,6 +241,8 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
plugin.getLogger().warning("Invalid WhitelistedPlayers entry: " + entry.getKey());
}
}
loadExtraSettings();
}
private void updatePluginDirectory() {
@@ -274,7 +250,7 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
String oldDirName = "Maintenance" + plugin.getServerType();
if (plugin.getServerType() == ServerType.SPONGE || plugin.getServerType() == ServerType.VELOCITY) {
oldDirName = oldDirName.toLowerCase(Locale.ROOT);
} else if (plugin.getServerType() == ServerType.PAPER) {
} else if (plugin.getServerType() == ServerType.SPIGOT) {
oldDirName = "MaintenanceSpigot";
}
@@ -314,35 +290,6 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
config.move("enable-playercounthovermessage", "player-list-hover-message.enabled");
config.move("playercounthovermessage", "player-list-hover-message.message");
}
if (version < 11) {
config.move("player-count-message.message", "player-count-message.messages.default");
config.move("player-count-message.timer-message", "player-count-message.timer-messages.default");
config.move("player-list-hover-message.message", "player-list-hover-message.messages.default");
config.move("player-list-hover-message.timer-message", "player-list-hover-message.timer-messages.default");
migrateModeSection("ping-message.messages");
migrateModeSection("ping-message.timer-messages");
migrateModeSection("player-count-message.messages");
migrateModeSection("player-count-message.timer-messages");
migrateModeSection("player-list-hover-message.messages");
migrateModeSection("player-list-hover-message.timer-messages");
final Object proxiedMaintenanceServers = config.getObject("proxied-maintenance-servers");
if (proxiedMaintenanceServers instanceof List<?> list) {
final Map<String, String> migratedServers = new LinkedHashMap<>();
for (final Object entry : list) {
if (entry != null) {
migratedServers.put(String.valueOf(entry), "default");
}
}
config.set("proxied-maintenance-servers", migratedServers);
}
}
if (version < 12) {
// Fix typo in the shipped config key :>
config.move("redis.enables", "redis.enabled");
}
createFile("config-new.yml", "config.yml");
final File file = new File(plugin.getDataFolder(), "config-new.yml");
@@ -374,10 +321,11 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
plugin.getLogger().info("Updating language file to the latest version...");
if (version < 1) {
for (final Map.Entry<String, Object> entry : language.getValues().entrySet()) {
if (!(entry.getValue() instanceof String value)) {
if (!(entry.getValue() instanceof String)) {
continue;
}
String value = (String) entry.getValue();
value = value.replace("&8[&eMaintenance&8] ", "<prefix>");
value = legacyToMinimessage(value);
value = value.replace("%NEWLINE%", NEW_LINE_REPLACEMENT);
@@ -413,17 +361,6 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
return serialized.replaceAll("</[a-z_]+>", "");
}
private void migrateModeSection(final String path) {
final Object section = config.getObject(path);
if (section == null || section instanceof Map<?, ?>) {
return;
}
final Map<String, Object> map = new LinkedHashMap<>();
map.put("default", section);
config.set(path, map);
}
private String getConfigMessage(final ConfigSection section, final String path) {
final String s = section.getString(path);
if (s == null) {
@@ -456,25 +393,6 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
return replaceNewlineVar(s).replace("<prefix>", prefixString);
}
public String getWebhookMessage(final String path, final String... replacements) {
String s = language.getString(path);
if (s == null) {
plugin.getLogger().warning("The language file is missing the following webhook message: " + path);
return path;
}
if (replacements.length != 0) {
if (replacements.length % 2 != 0) {
throw new IllegalArgumentException("Invalid replacement count: " + replacements.length);
}
for (int i = 0; i < replacements.length; i += 2) {
final String key = replacements[i];
s = s.replace(key, replacements[i + 1]);
}
}
return replaceNewlineVar(s);
}
public @Nullable String getLanguageStringOrNull(final String path, final String... replacements) {
return language.contains(path) ? getLanguageString(path, replacements) : null;
}
@@ -485,53 +403,24 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
// TODO Cache platform components if there are no replacements
public Component getRandomPingMessage() {
return getRandomPingMessage(activeMode);
}
public Component getRandomPingMessage(@Nullable final String mode) {
if (plugin.isTaskRunning() && !plugin.getRunnable().shouldEnable() && hasTimerSpecificPingMessages()) {
return getPingMessage(timerSpecificPingMessages, mode);
if (plugin.isTaskRunning() && !plugin.getRunnable().shouldEnable()
&& hasTimerSpecificPingMessages() && !timerSpecificPingMessages.isEmpty()) {
return getPingMessage(timerSpecificPingMessages);
}
return pingMessages.isEmpty() ? Component.empty() : getPingMessage(pingMessages, mode);
return pingMessages.isEmpty() ? Component.empty() : getPingMessage(pingMessages);
}
private Component getPingMessage(final DisplayedMessages list, @Nullable final String mode) {
final String component = list.getRandomEntry(mode);
return parse(plugin.replacePingVariables(component, mode));
private Component getPingMessage(final List<String> list) {
final String component = list.size() == 1 ? list.get(0) : list.get(RANDOM.nextInt(list.size()));
return parse(plugin.replacePingVariables(component));
}
private DisplayedMessages loadPingMessages(final ConfigSection section) {
return loadDisplayedMessages(section, (list, s) -> list.add(replaceNewlineVar(s)));
}
private DisplayedMessages loadPlayerCountHoverMessages(final ConfigSection section) {
return loadDisplayedMessages(section, (list, s) -> {
// Split into separate messages (one per player entry)
for (final String line : s.split("<br>")) {
list.add(toLegacy(parse(line)));
}
});
}
private DisplayedMessages loadPlayerCountMessages(final ConfigSection section) {
return loadDisplayedMessages(section, (list, s) -> list.add(toLegacy(parse(s))));
}
private DisplayedMessages loadDisplayedMessages(final ConfigSection section, final BiConsumer<List<String>, String> messageFunction) {
final Map<String, List<String>> modes = new HashMap<>(section.getKeys().size());
for (final Map.Entry<String, Object> entry : section.getValues().entrySet()) {
final List<String> components = new ArrayList<>();
if (entry.getValue() instanceof String s) {
messageFunction.accept(components, s);
} else if (entry.getValue() instanceof List<?> list) {
//noinspection unchecked
for (final String s : ((Iterable<String>) list)) {
messageFunction.accept(components, s);
}
}
modes.put(entry.getKey(), components);
private List<String> loadPingMessages(final List<String> list) {
final List<String> components = new ArrayList<>(list.size());
for (final String s : list) {
components.add(replaceNewlineVar(s));
}
return new DisplayedMessages(modes);
return components;
}
@Override
@@ -559,19 +448,18 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
return false;
}
return removeWhitelistedPlayer(uuid);
whitelistedPlayers.remove(uuid);
whitelist.remove(uuid.toString());
saveWhitelistedPlayers();
return true;
}
@Override
public boolean addWhitelistedPlayer(final UUID uuid, final String name) {
final boolean added = !name.equals(whitelistedPlayers.put(uuid, name));
if (!added) {
return false;
}
final boolean added = whitelistedPlayers.put(uuid, name) == null;
whitelist.set(uuid.toString(), name);
saveWhitelistedPlayers();
return true;
return added;
}
@Override
@@ -589,47 +477,8 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
return maintenance;
}
@Override
public @Nullable String activeMode() {
return activeMode;
}
public void setActiveMode(@Nullable final String activeMode) {
final String normalized = normalizeMode(activeMode);
if (Objects.equals(this.activeMode, normalized)) {
return;
}
this.activeMode = normalized;
config.set("active-mode", normalized != null ? normalized : "default");
saveConfig();
}
@Override
public String activeReason() {
return activeReason;
}
@Override
public void setActiveReason(@Nullable final String reason) {
final String normalized = normalizeReason(reason);
if (Objects.equals(this.activeReason, normalized)) {
return;
}
this.activeReason = normalized;
config.set("active-reason", normalized);
saveConfig();
}
public void setMaintenance(final boolean maintenance, @Nullable final String mode) {
if (this.maintenance != maintenance) {
this.maintenance = maintenance;
config.set("maintenance-enabled", maintenance);
this.activeMode = normalizeMode(mode);
config.set("active-mode", this.activeMode != null ? this.activeMode : "default");
saveConfig();
}
public void setMaintenance(final boolean maintenance) {
this.maintenance = maintenance;
}
@Override
@@ -686,7 +535,7 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
return config;
}
public DisplayedMessages getPingMessages() {
public List<String> getPingMessages() {
return pingMessages;
}
@@ -698,7 +547,7 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
return commandsOnMaintenanceDisable;
}
public @Nullable DisplayedMessages getTimerSpecificPingMessages() {
public @Nullable List<String> getTimerSpecificPingMessages() {
return timerSpecificPingMessages;
}
@@ -706,50 +555,16 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
return broadcastIntervals;
}
public boolean isWebhookEnabled() {
return webhookEnabled;
}
public boolean isWebhookEventEnabled(final String event) {
return webhookEnabledEvents.contains(event);
}
public String getWebhookUrl() {
return webhookUrl;
}
public String getWebhookUsername() {
return webhookUsername;
}
public String getWebhookAvatarUrl() {
return webhookAvatarUrl;
}
public String getPlainTextPrefix() {
return plainTextPrefix;
}
public String getLegacyParsedPlayerCountMessage() {
return getLegacyParsedPlayerCountMessage(activeMode);
}
public String getLegacyParsedPlayerCountMessage(@Nullable final String mode) {
final DisplayedMessages messages = timerDependent(legacyParsedPlayerCountMessages, legacyParsedTimerPlayerCountMessages);
final String message = messages.getRandomEntry(mode);
return plugin.replacePingVariables(message, mode);
final String message = timerDependent(legacyParsedPlayerCountMessage, legacyParsedTimerPlayerCountMessage);
return plugin.replacePingVariables(message);
}
public String[] getLegacyParsedPlayerCountHoverLines() {
return getLegacyParsedPlayerCountHoverLines(activeMode);
}
public String[] getLegacyParsedPlayerCountHoverLines(@Nullable final String mode) {
final DisplayedMessages messages = timerDependent(legacyParsedPlayerCountHoverLines, legacyParsedTimerPlayerCountHoverLines);
final List<String> lines = messages.getMessages(mode);
final List<String> lines = timerDependent(legacyParsedPlayerCountHoverLines, legacyParsedTimerPlayerCountHoverLines);
final String[] parsedLines = new String[lines.size()];
for (int i = 0; i < lines.size(); i++) {
parsedLines[i] = plugin.replacePingVariables(lines.get(i), mode);
parsedLines[i] = plugin.replacePingVariables(lines.get(i));
}
return parsedLines;
}
@@ -783,7 +598,7 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
}
/*
* Note on why this even exists: YAML will force save all strings containing line breaks '\n' in this rather chunky format:
* Note on why this even exists: Yaml will force save all strings containing line breaks '\n' in this rather chunky format:
* key: |-
* First line text
* Second line text.
@@ -796,17 +611,6 @@ public class Settings implements eu.kennytv.maintenance.api.Settings {
return s.replace(NEW_LINE_REPLACEMENT, "\n");
}
protected @Nullable String normalizeMode(@Nullable final String mode) {
if (mode == null || mode.isBlank() || mode.equalsIgnoreCase("default")) {
return null;
}
return mode.toLowerCase(Locale.ROOT);
}
private String normalizeReason(@Nullable final String reason) {
return reason == null || reason.isBlank() ? "" : reason;
}
protected void loadExtraSettings() {
}
}
@@ -20,7 +20,7 @@ package eu.kennytv.maintenance.core.command;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.util.SenderInfo;
import net.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
@@ -28,10 +28,8 @@ import eu.kennytv.maintenance.core.command.subcommand.MotdCommand;
import eu.kennytv.maintenance.core.command.subcommand.ReloadCommand;
import eu.kennytv.maintenance.core.command.subcommand.RemoveMotdCommand;
import eu.kennytv.maintenance.core.command.subcommand.ScheduleTimerCommand;
import eu.kennytv.maintenance.core.command.subcommand.SetReasonCommand;
import eu.kennytv.maintenance.core.command.subcommand.SetMotdCommand;
import eu.kennytv.maintenance.core.command.subcommand.StarttimerCommand;
import eu.kennytv.maintenance.core.command.subcommand.StatusCommand;
import eu.kennytv.maintenance.core.command.subcommand.ToggleCommand;
import eu.kennytv.maintenance.core.command.subcommand.UpdateCommand;
import eu.kennytv.maintenance.core.command.subcommand.WhitelistAddCommand;
@@ -76,7 +74,6 @@ public abstract class MaintenanceCommand {
add(new SetMotdCommand(plugin), "setmotd");
add(new RemoveMotdCommand(plugin), "removemotd");
add(new MotdCommand(plugin), "motd");
add(new SetReasonCommand(plugin), "setreason");
add(new UpdateCommand(plugin), "update", "forceupdate");
add(new DumpCommand(plugin), "dump");
@@ -100,7 +97,7 @@ public abstract class MaintenanceCommand {
return;
}
final CommandInfo command = commandExecutors.get(args[0].toLowerCase(Locale.ROOT));
final CommandInfo command = commandExecutors.get(args[0].toLowerCase());
if (command == null) {
help.sendUsage(sender);
return;
@@ -115,7 +112,7 @@ public abstract class MaintenanceCommand {
public List<String> getSuggestions(final SenderInfo sender, final String[] args) {
if (!sender.hasMaintenancePermission("command") || args.length == 0) return Collections.emptyList();
final String s = args[0].toLowerCase(Locale.ROOT);
final String s = args[0].toLowerCase();
if (args.length == 1) {
final List<String> list = new ArrayList<>();
for (final Map.Entry<String, CommandInfo> entry : commandExecutors.entrySet()) {
@@ -132,24 +129,6 @@ public abstract class MaintenanceCommand {
return info != null && info.hasPermission(sender) ? info.getTabCompletion(sender, args) : Collections.emptyList();
}
/**
* Converts a user given time like {@code 2d}, {@code 2d12h}, {@code 1h5m}, or {@code 30s} to an ISO-8601 duration string.
* Days are supported in addition to hours, minutes, and seconds.
*
* @return ISO duration string
*/
private static String toIsoDuration(final String time) {
final String upper = time.toUpperCase(Locale.ROOT);
final int dayIndex = upper.indexOf('D');
if (dayIndex == -1) {
return "PT" + upper;
}
final String days = upper.substring(0, dayIndex + 1);
final String rest = upper.substring(dayIndex + 1);
return rest.isEmpty() ? "P" + days : "P" + days + "T" + rest;
}
public @Nullable Duration parseDurationAndCheckTask(final SenderInfo sender, final String time, final boolean taskCheck) {
final Duration duration;
if (plugin.isNumeric(time)) {
@@ -157,7 +136,8 @@ public abstract class MaintenanceCommand {
duration = Duration.ofMinutes(Integer.parseInt(time));
} else {
try {
duration = Duration.parse(toIsoDuration(time));
// Only accept hours, minutes, and seconds
duration = Duration.parse("PT" + time.toUpperCase(Locale.ROOT));
} catch (final DateTimeParseException e) {
return null;
}
@@ -188,7 +168,6 @@ public abstract class MaintenanceCommand {
protected void addToggleAndTimerCommands() {
add(new ToggleCommand(plugin), "on", "off");
add(new StatusCommand(plugin), "status");
add(new StarttimerCommand(plugin), "starttimer", "start");
add(new EndtimerCommand(plugin), "endtimer", "end");
@@ -20,14 +20,12 @@ package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.TextComponent;
import eu.kennytv.maintenance.lib.kyori.adventure.text.event.ClickEvent;
import eu.kennytv.maintenance.lib.kyori.adventure.text.event.HoverEvent;
import eu.kennytv.maintenance.lib.kyori.adventure.text.format.NamedTextColor;
import java.util.concurrent.TimeUnit;
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 static eu.kennytv.maintenance.core.util.ComponentUtil.clickEvent;
public final class DumpCommand extends CommandInfo {
private long lastDump;
@@ -59,7 +57,7 @@ public final class DumpCommand extends CommandInfo {
sender.sendPrefixedRich("<red><click:open_url:'" + url + "'>" + url + "</click>");
if (sender.isPlayer()) {
final TextComponent text = Component.text().content("Click here to copy the link").color(NamedTextColor.GRAY)
.clickEvent(clickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, url))
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, url))
.hoverEvent(HoverEvent.showText(Component.text("Click here to copy the link to your clipboard").color(NamedTextColor.GREEN)))
.build();
sender.send(plugin.prefix().append(text));
@@ -19,10 +19,9 @@ package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.DiscordWebhook;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.time.Duration;
import net.kyori.adventure.text.Component;
public final class EndtimerCommand extends CommandInfo {
@@ -45,11 +44,6 @@ public final class EndtimerCommand extends CommandInfo {
}
plugin.startMaintenanceRunnable(duration, false);
final Component message = getMessage("endtimerStarted", "%TIME%", plugin.getRunnable().getTime());
sender.send(message);
plugin.sendWebhookMessage("webhookEndtimerStarted", DiscordWebhook.EventType.ENDTIMER_STARTED,
"%TIME%", plugin.getRunnable().getTime(),
"%TIMESTAMP%", plugin.getTargetTimestamp(duration));
sender.send(getMessage("endtimerStarted", "%TIME%", plugin.getRunnable().getTime()));
}
}
@@ -21,9 +21,9 @@ import com.google.common.base.Preconditions;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import java.util.ArrayList;
import java.util.List;
import net.kyori.adventure.text.Component;
public final class HelpCommand extends CommandInfo {
private static final int COMMANDS_PER_PAGE = 8;
@@ -19,14 +19,10 @@ package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.config.ConfigSection;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import org.jetbrains.annotations.Nullable;
public final class MotdCommand extends CommandInfo {
@@ -36,29 +32,21 @@ public final class MotdCommand extends CommandInfo {
@Override
public void execute(final SenderInfo sender, final String[] args) {
int indexOffset = 1;
boolean timer = false;
if (args.length > indexOffset && args[indexOffset].equalsIgnoreCase("timer")) {
if (args.length == 1) {
sendList(sender, getSettings().getPingMessages());
} else if (args.length == 2 && args[1].equalsIgnoreCase("timer")) {
if (!getSettings().hasTimerSpecificPingMessages()) {
sender.send(getMessage("timerMotdDisabled"));
return;
}
timer = true;
indexOffset++;
}
if (args.length > indexOffset + 1) {
sendList(sender, getSettings().getTimerSpecificPingMessages());
} else {
sender.send(getHelpMessage());
return;
}
final String mode = args.length == indexOffset + 1 ? args[indexOffset].toLowerCase(Locale.ROOT) : "default";
final ConfigSection section = getSettings().getConfig().getSection("ping-message").getSection(timer ? "timer-messages" : "messages");
sendList(sender, getModeMessages(section, mode));
}
private void sendList(final SenderInfo sender, @Nullable final List<String> list) {
private void sendList(final SenderInfo sender, final List<String> list) {
if (list == null || list.isEmpty()) {
sender.send(getMessage("motdListEmpty"));
return;
@@ -67,43 +55,16 @@ public final class MotdCommand extends CommandInfo {
sender.send(getMessage("motdList"));
for (int i = 0; i < list.size(); i++) {
sender.sendRich("<aqua>" + (i + 1) + "<dark_gray><st>---------");
sender.sendRich(list.get(i).replace("<br>", "\n"));
sender.sendRich(list.get(i));
}
sender.sendRich("<dark_gray><st>----------");
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
if (args.length < 2 || args.length > 3) {
if (args.length != 2 || !getSettings().hasTimerSpecificPingMessages()) {
return Collections.emptyList();
}
if (args.length == 2) {
final List<String> list = new ArrayList<>();
if (getSettings().hasTimerSpecificPingMessages()) {
list.add("timer");
}
final List<String> modes = new ArrayList<>(getSettings().getConfig().getSection("ping-message").getSection("messages").getKeys());
modes.remove("default");
list.addAll(modes);
return list;
}
if (!args[1].equalsIgnoreCase("timer") || !getSettings().hasTimerSpecificPingMessages()) {
return Collections.emptyList();
}
final List<String> modes = new ArrayList<>(getSettings().getConfig().getSection("ping-message").getSection("timer-messages").getKeys());
modes.remove("default");
return modes;
}
private @Nullable List<String> getModeMessages(final ConfigSection section, final String mode) {
final Object value = section.getObject(mode);
if (value instanceof String s) {
return Collections.singletonList(s);
}
return section.getStringList(mode);
return Collections.singletonList("timer");
}
}
@@ -22,10 +22,10 @@ import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.config.ConfigSection;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
public final class RemoveMotdCommand extends CommandInfo {
@@ -34,49 +34,32 @@ public final class RemoveMotdCommand extends CommandInfo {
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
int indexOffset = 1;
public void execute(final SenderInfo sender, String[] args) {
boolean timerPingMessages = false;
if (args.length > indexOffset && args[indexOffset].equalsIgnoreCase("timer")) {
if (args.length == 3 && args[1].equalsIgnoreCase("timer")) {
if (!getSettings().hasTimerSpecificPingMessages()) {
sender.send(getMessage("timerMotdDisabled"));
return;
}
indexOffset++;
args = plugin.removeArrayIndex(args, 1);
timerPingMessages = true;
}
if (args.length <= indexOffset) {
sender.send(getHelpMessage());
return;
}
String mode = "default";
if (!plugin.isNumeric(args[indexOffset])) {
mode = args[indexOffset].toLowerCase(Locale.ROOT);
indexOffset++;
}
if (args.length != indexOffset + 1 || !plugin.isNumeric(args[indexOffset])) {
if (checkArgs(sender, args, 2)) return;
if (!plugin.isNumeric(args[1])) {
sender.send(getHelpMessage());
return;
}
final Settings settings = getSettings();
final ConfigSection section = settings.getConfig().getSection("ping-message");
final ConfigSection messageSection = section.getSection(timerPingMessages ? "timer-messages" : "messages");
final List<String> pingMessages = getModeMessages(messageSection, mode);
if (pingMessages.isEmpty()) {
sender.send(getMessage("motdListEmpty"));
return;
}
if (mode.equals("default") && pingMessages.size() < 2) {
final List<String> pingMessages = section.getStringList(timerPingMessages ? "timer-messages" : "messages");
if (pingMessages.size() < 2) {
sender.send(getMessage("removeMotdError"));
return;
}
final int index = Integer.parseInt(args[indexOffset]);
final int index = Integer.parseInt(args[1]);
if (index == 0 || index > pingMessages.size()) {
sender.send(getMessage("setMotdIndexError",
"%MOTDS%", Integer.toString(pingMessages.size()),
@@ -84,60 +67,24 @@ public final class RemoveMotdCommand extends CommandInfo {
return;
}
final List<String> pingComponents = timerPingMessages ? settings.getTimerSpecificPingMessages() : settings.getPingMessages();
pingComponents.remove(index - 1);
pingMessages.remove(index - 1);
if (pingMessages.isEmpty()) {
messageSection.remove(mode);
} else {
messageSection.set(mode, pingMessages);
}
section.set(timerPingMessages ? "timer-messages" : "messages", pingMessages);
settings.saveConfig();
settings.reloadConfigs();
sender.send(getMessage("removedMotd", "%INDEX%", Integer.toString(index)));
sender.send(getMessage("removedMotd", "%INDEX%", args[1]));
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
final int indexOffset;
final boolean timer;
if (args.length > 1 && args[1].equalsIgnoreCase("timer")) {
timer = true;
indexOffset = 2;
} else {
timer = false;
indexOffset = 1;
}
if (args.length == indexOffset + 1 && !plugin.isNumeric(args[indexOffset])) {
return getModeCompletions(timer);
}
if (args.length == indexOffset + 1 || (args.length == indexOffset + 2 && !plugin.isNumeric(args[indexOffset]))) {
final String mode = plugin.isNumeric(args[indexOffset]) ? "default" : args[indexOffset].toLowerCase(Locale.ROOT);
final int size = getModeMessages(getSettings().getConfig().getSection("ping-message").getSection(timer ? "timer-messages" : "messages"), mode).size();
if (args.length == 2 || (args.length == 3 && args[1].equalsIgnoreCase("timer"))) {
final int size = (args.length == 3 ? plugin.getSettings().getTimerSpecificPingMessages() : plugin.getSettings().getPingMessages()).size();
final List<String> list = new ArrayList<>(size);
for (int i = 1; i <= size; i++) {
list.add(Integer.toString(i));
}
return list;
}
return Collections.emptyList();
}
private List<String> getModeCompletions(final boolean timer) {
final List<String> modes = new ArrayList<>(getSettings().getConfig().getSection("ping-message").getSection(timer ? "timer-messages" : "messages").getKeys());
modes.remove("default");
return modes;
}
private List<String> getModeMessages(final ConfigSection section, final String mode) {
final Object value = section.getObject(mode);
if (value == null) {
return List.of();
}
if (value instanceof String s) {
return new ArrayList<>(Collections.singletonList(s));
}
return new ArrayList<>(section.getStringList(mode));
}
}
@@ -26,7 +26,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static eu.kennytv.maintenance.core.Settings.NEW_LINE_REPLACEMENT;
@@ -37,41 +36,28 @@ public final class SetMotdCommand extends CommandInfo {
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
int indexOffset = 1;
public void execute(final SenderInfo sender, String[] args) {
boolean timerPingMessages = false;
if (args.length > indexOffset && args[indexOffset].equalsIgnoreCase("timer")) {
if (args.length > 1 && args[1].equalsIgnoreCase("timer")) {
if (!getSettings().hasTimerSpecificPingMessages()) {
sender.send(getMessage("timerMotdDisabled"));
return;
}
indexOffset++;
// remove the "timer" off the args to keep the rest the code cleaner
args = plugin.removeArrayIndex(args, 1);
timerPingMessages = true;
}
if (args.length <= indexOffset + 2) {
sender.send(getHelpMessage());
return;
}
String mode = "default";
if (!plugin.isNumeric(args[indexOffset])) {
mode = args[indexOffset].toLowerCase(Locale.ROOT);
indexOffset++;
}
if (args.length <= indexOffset + 2 || !plugin.isNumeric(args[indexOffset])) {
if (args.length < 4 || !plugin.isNumeric(args[1])) {
sender.send(getHelpMessage());
return;
}
final Settings settings = getSettings();
final List<String> pingComponents = timerPingMessages ? settings.getTimerSpecificPingMessages() : settings.getPingMessages();
final ConfigSection section = settings.getConfig().getSection("ping-message");
final ConfigSection messageSection = section.getSection(timerPingMessages ? "timer-messages" : "messages");
final List<String> pingMessages = getOrCreateModeMessages(messageSection, mode);
final int index = Integer.parseInt(args[indexOffset]);
final List<String> pingMessages = section.getStringList(timerPingMessages ? "timer-messages" : "messages");
final int index = Integer.parseInt(args[1]);
if (index == 0 || index > pingMessages.size() + 1) {
sender.send(getMessage("setMotdIndexError",
"%MOTDS%", Integer.toString(pingMessages.size()),
@@ -79,96 +65,63 @@ public final class SetMotdCommand extends CommandInfo {
return;
}
if (!plugin.isNumeric(args[indexOffset + 1])) {
if (!plugin.isNumeric(args[2])) {
sender.send(getMessage("setMotdLineError"));
return;
}
final int line = Integer.parseInt(args[indexOffset + 1]);
final int line = Integer.parseInt(args[2]);
if (line != 1 && line != 2) {
sender.send(getMessage("setMotdLineError"));
return;
}
final String message = String.join(" ", Arrays.copyOfRange(args, indexOffset + 2, args.length));
final String message = String.join(" ", Arrays.copyOfRange(args, 3, args.length));
final String oldMessage = index > pingMessages.size() ? "" : pingMessages.get(index - 1);
final String newMessage;
if (line == 1) {
newMessage = oldMessage.contains(NEW_LINE_REPLACEMENT)
? message + NEW_LINE_REPLACEMENT + oldMessage.split(NEW_LINE_REPLACEMENT, 2)[1]
: message;
newMessage = oldMessage.contains(NEW_LINE_REPLACEMENT) ?
message + NEW_LINE_REPLACEMENT + oldMessage.split(NEW_LINE_REPLACEMENT, 2)[1] : message;
} else {
newMessage = oldMessage.contains(NEW_LINE_REPLACEMENT)
? oldMessage.split(NEW_LINE_REPLACEMENT, 2)[0] + NEW_LINE_REPLACEMENT + message
: oldMessage + NEW_LINE_REPLACEMENT + message;
newMessage = oldMessage.contains(NEW_LINE_REPLACEMENT) ?
oldMessage.split(NEW_LINE_REPLACEMENT, 2)[0] + NEW_LINE_REPLACEMENT + message : oldMessage + NEW_LINE_REPLACEMENT + message;
}
// Replace component in config and the cached list
final String componentString = newMessage.replace(NEW_LINE_REPLACEMENT, "\n");
if (index > pingMessages.size()) {
pingMessages.add(newMessage);
pingComponents.add(componentString);
} else {
pingMessages.set(index - 1, newMessage);
pingComponents.set(index - 1, componentString);
}
messageSection.set(mode, pingMessages);
section.set(timerPingMessages ? "timer-messages" : "messages", pingMessages);
settings.saveConfig();
settings.reloadConfigs();
sender.send(settings.getMessage(
"setMotd",
"%LINE%", Integer.toString(line),
"%INDEX%", Integer.toString(index),
"%MOTD%", newMessage.replace(NEW_LINE_REPLACEMENT, "\n")
"%LINE%", args[2],
"%INDEX%", args[1],
"%MOTD%", componentString
));
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
final int indexOffset;
final boolean timer;
public List<String> getTabCompletion(final SenderInfo sender, String[] args) {
boolean timer = false;
if (args.length > 1 && args[1].equalsIgnoreCase("timer")) {
args = plugin.removeArrayIndex(args, 1);
timer = true;
indexOffset = 2;
} else {
timer = false;
indexOffset = 1;
}
if (args.length == indexOffset + 2) {
return Arrays.asList("1", "2");
}
if (args.length == indexOffset + 1 && !plugin.isNumeric(args[indexOffset])) {
return getModeCompletions(timer);
}
if (args.length == indexOffset + 1) {
final String mode = plugin.isNumeric(args[indexOffset]) ? "default" : args[indexOffset].toLowerCase(Locale.ROOT);
final ConfigSection section = getSettings().getConfig().getSection("ping-message").getSection(timer ? "timer-messages" : "messages");
final int size = getOrCreateModeMessages(section, mode).size();
if (args.length == 3) return Arrays.asList("1", "2");
if (args.length == 2) {
final List<String> list = new ArrayList<>();
for (int i = 1; i <= size + 1; i++) {
for (int i = 1; i <= (timer ? getSettings().getTimerSpecificPingMessages() : getSettings().getPingMessages()).size() + 1; i++) {
list.add(String.valueOf(i));
}
return list;
}
return Collections.emptyList();
}
private List<String> getModeCompletions(final boolean timer) {
final List<String> modes = new ArrayList<>(getSettings().getConfig().getSection("ping-message").getSection(timer ? "timer-messages" : "messages").getKeys());
modes.remove("default");
return modes;
}
private List<String> getOrCreateModeMessages(final ConfigSection section, final String mode) {
final Object value = section.getObject(mode);
if (value == null) {
return new ArrayList<>();
}
if (value instanceof String s) {
return new ArrayList<>(Collections.singletonList(s));
}
return new ArrayList<>(section.getStringList(mode));
}
}
@@ -1,59 +0,0 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2024 kennytv (https://github.com/kennytv)
*
* 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 eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.Collections;
import java.util.List;
public final class SetReasonCommand extends CommandInfo {
public SetReasonCommand(final MaintenancePlugin plugin) {
super(plugin, "setreason");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (args.length < 2) {
sender.send(getHelpMessage());
return;
}
final String value = String.join(" ", java.util.Arrays.copyOfRange(args, 1, args.length));
final String reason;
if (value.equalsIgnoreCase("none") || value.equalsIgnoreCase("clear") || value.equals("-")) {
reason = null;
} else {
reason = value;
}
getSettings().setActiveReason(reason);
sender.send(getMessage("setReason", "%REASON%", reason == null ? "-" : reason));
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
if (args.length != 2) {
return Collections.emptyList();
}
return Collections.singletonList("none");
}
}
@@ -19,10 +19,9 @@ package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.DiscordWebhook;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.time.Duration;
import net.kyori.adventure.text.Component;
public final class StarttimerCommand extends CommandInfo {
@@ -45,11 +44,6 @@ public final class StarttimerCommand extends CommandInfo {
}
plugin.startMaintenanceRunnable(duration, true);
final Component message = getMessage("starttimerStarted", "%TIME%", plugin.getRunnable().getTime());
sender.send(message);
plugin.sendWebhookMessage("webhookStarttimerStarted", DiscordWebhook.EventType.STARTTIMER_STARTED,
"%TIME%", plugin.getRunnable().getTime(),
"%TIMESTAMP%", plugin.getTargetTimestamp(duration));
sender.send(getMessage("starttimerStarted", "%TIME%", plugin.getRunnable().getTime()));
}
}
@@ -20,10 +20,6 @@ package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
public final class ToggleCommand extends CommandInfo {
@@ -33,45 +29,14 @@ public final class ToggleCommand extends CommandInfo {
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (args.length == 0 || args.length > 2) {
sender.send(getHelpMessage());
return;
}
if (checkArgs(sender, args, 1)) return;
final boolean maintenance = args[0].equalsIgnoreCase("on");
final String mode;
if (maintenance && args.length == 2) {
mode = args[1].toLowerCase(Locale.ROOT);
} else if (!maintenance && args.length == 1) {
mode = null;
} else if (maintenance) {
mode = null;
} else {
sender.send(getHelpMessage());
return;
}
if (maintenance == plugin.isMaintenance()) {
if (mode != null) {
plugin.getSettings().setActiveMode(mode);
return;
}
sender.send(getMessage(maintenance ? "alreadyEnabled" : "alreadyDisabled"));
return;
}
plugin.setMaintenance(maintenance, mode);
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
if (args.length != 2 || !args[0].equalsIgnoreCase("on")) {
return Collections.emptyList();
}
final List<String> modes = new ArrayList<>(getSettings().getPingMessages().getKeys());
modes.remove("default");
return modes;
plugin.setMaintenance(maintenance);
}
}
@@ -20,11 +20,11 @@ package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import net.kyori.adventure.text.Component;
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.minimessage.MiniMessage;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.event.ClickEvent;
import eu.kennytv.maintenance.lib.kyori.adventure.text.event.HoverEvent;
import eu.kennytv.maintenance.lib.kyori.adventure.text.format.NamedTextColor;
import eu.kennytv.maintenance.lib.kyori.adventure.text.minimessage.MiniMessage;
public final class UpdateCommand extends CommandInfo {
@@ -99,10 +99,10 @@ public final class WhitelistAddCommand extends CommandInfo {
}
private void addPlayerToWhitelist(final SenderInfo sender, final SenderInfo selected) {
if (getSettings().addWhitelistedPlayer(selected.uuid(), selected.name())) {
sender.send(getMessage("whitelistAdded", "%PLAYER%", selected.name()));
if (getSettings().addWhitelistedPlayer(selected.getUuid(), selected.getName())) {
sender.send(getMessage("whitelistAdded", "%PLAYER%", selected.getName()));
} else {
sender.send(getMessage("whitelistAlreadyAdded", "%PLAYER%", selected.name()));
sender.send(getMessage("whitelistAlreadyAdded", "%PLAYER%", selected.getName()));
}
}
}
@@ -20,10 +20,10 @@ package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import java.util.Map;
import java.util.UUID;
import net.kyori.adventure.text.Component;
public final class WhitelistCommand extends CommandInfo {
@@ -24,7 +24,6 @@ import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
public final class WhitelistRemoveCommand extends CommandInfo {
@@ -51,9 +50,9 @@ public final class WhitelistRemoveCommand extends CommandInfo {
if (args.length != 2) return Collections.emptyList();
final List<String> list = new ArrayList<>();
String matchNameLowerCase = args[1].toLowerCase(Locale.ROOT);
String matchNameLowerCase = args[1].toLowerCase();
for (final String name : getSettings().getWhitelistedPlayers().values()) {
if (name.toLowerCase(Locale.ROOT).startsWith(matchNameLowerCase)) {
if (name.toLowerCase().startsWith(matchNameLowerCase)) {
list.add(name);
}
}
@@ -71,7 +70,7 @@ public final class WhitelistRemoveCommand extends CommandInfo {
return;
}
removePlayerFromWhitelist(sender, selected.uuid(), selected.name());
removePlayerFromWhitelist(sender, selected.getUuid(), selected.getName());
});
}
@@ -80,13 +79,13 @@ public final class WhitelistRemoveCommand extends CommandInfo {
if (selected == null) {
removePlayerFromWhitelist(sender, uuid, uuid.toString());
} else {
removePlayerFromWhitelist(sender, selected.uuid(), selected.name());
removePlayerFromWhitelist(sender, selected.getUuid(), selected.getName());
}
});
}
private void removePlayerFromWhitelist(final SenderInfo sender, final UUID uuid, final String toReplace) {
if (plugin.getSettings().removeWhitelistedPlayer(uuid)) {
if (getSettings().removeWhitelistedPlayer(uuid)) {
sender.send(getMessage("whitelistRemoved", "%PLAYER%", toReplace));
} else {
sender.send(getMessage("whitelistNotFound"));
@@ -17,8 +17,10 @@
*/
package eu.kennytv.maintenance.core.config;
import com.google.common.collect.Sets;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Collections;
import java.util.HashMap;
@@ -38,20 +40,18 @@ import org.yaml.snakeyaml.Yaml;
public final class Config extends ConfigSection {
private static final String AWESOME_HEADER =
"""
###################################################################################################################
# __ __ _ _ _ _ _ #
# | \\/ | __ _(_)_ __ | |_ ___ _ __ __ _ _ __ ___ ___ | |__ _ _ | | _____ _ __ _ __ _ _| |___ __ #
# | |\\/| |/ _` | | '_ \\| __/ _ \\ '_ \\ / _` | '_ \\ / __/ _ \\ | '_ \\| | | | | |/ / _ \\ '_ \\| '_ \\| | | | __\\ \\ / / #
# | | | | (_| | | | | | || __/ | | | (_| | | | | (_| __/ | |_) | |_| | | < __/ | | | | | | |_| | |_ \\ V / #
# |_| |_|\\__,_|_|_| |_|\\__\\___|_| |_|\\__,_|_| |_|\\___\\___| |_.__/ \\__, | |_|\\_\\___|_| |_|_| |_|\\__, |\\__| \\_/ #
# |___/ |___/ #
###################################################################################################################
# You can report bugs here: https://github.com/kennytv/Maintenance/issues
# If you need any other help/support, you can also join my Discord server: https://discord.gg/vGCUzHq
# The config and language files use MiniMessage, NOT legacy text for input. Use https://webui.advntr.dev/ to edit and preview the formatted text.
# For a full list of formats and fancy examples of MiniMessage, see https://docs.papermc.io/adventure/minimessage/format/
""";
"###################################################################################################################\n" +
"# __ __ _ _ _ _ _ #\n" +
"# | \\/ | __ _(_)_ __ | |_ ___ _ __ __ _ _ __ ___ ___ | |__ _ _ | | _____ _ __ _ __ _ _| |___ __ #\n" +
"# | |\\/| |/ _` | | '_ \\| __/ _ \\ '_ \\ / _` | '_ \\ / __/ _ \\ | '_ \\| | | | | |/ / _ \\ '_ \\| '_ \\| | | | __\\ \\ / / #\n" +
"# | | | | (_| | | | | | || __/ | | | (_| | | | | (_| __/ | |_) | |_| | | < __/ | | | | | | |_| | |_ \\ V / #\n" +
"# |_| |_|\\__,_|_|_| |_|\\__\\___|_| |_|\\__,_|_| |_|\\___\\___| |_.__/ \\__, | |_|\\_\\___|_| |_|_| |_|\\__, |\\__| \\_/ #\n" +
"# |___/ |___/ #\n" +
"###################################################################################################################\n" +
"# You can report bugs here: https://github.com/kennytv/Maintenance/issues\n" +
"# If you need any other help/support, you can also join my Discord server: https://discord.gg/vGCUzHq\n" +
"# The config and language files use MiniMessage, NOT legacy text for input. Use https://webui.adventure.kyori.net/ to edit and preview the formatted text.\n" +
"# For a full list of formats and fancy examples of MiniMessage, see https://docs.adventure.kyori.net/minimessage/format.html\n";
private final Yaml yaml = createYaml();
private final File file;
private final Set<String> unsupportedFields;
@@ -61,11 +61,11 @@ public final class Config extends ConfigSection {
public Config(final File file, final String... unsupportedFields) {
super(null, "");
this.file = file;
this.unsupportedFields = unsupportedFields.length == 0 ? Collections.emptySet() : Set.of(unsupportedFields);
this.unsupportedFields = unsupportedFields.length == 0 ? Collections.emptySet() : Sets.newHashSet(unsupportedFields);
}
public void load() throws IOException {
final String data = Files.readString(this.file.toPath());
final String data = new String(Files.readAllBytes(this.file.toPath()), StandardCharsets.UTF_8);
final Map<String, Object> map = yaml.load(data);
this.values = map != null ? map : new LinkedHashMap<>();
this.comments = ConfigSerializer.deserializeComments(data);
@@ -101,11 +101,12 @@ public final class Config extends ConfigSection {
}
public void saveTo(final File file) throws IOException {
final byte[] bytes = toString().getBytes(StandardCharsets.UTF_8);
if (file.getParentFile() != null) {
file.getParentFile().mkdirs();
}
file.createNewFile();
Files.writeString(file.toPath(), toString());
Files.write(file.toPath(), bytes);
}
public void replaceComments(final Config fromConfig) {
@@ -17,6 +17,7 @@
*/
package eu.kennytv.maintenance.core.config;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -35,7 +36,7 @@ public class ConfigSection {
protected Map<String, Object> values;
ConfigSection(final Config root, final String currentPath) {
this(root, currentPath, new LinkedHashMap<>());
this(root, currentPath, new HashMap<>());
}
ConfigSection(final Config root, final String currentPath, final Map<String, Object> values) {
@@ -62,18 +63,20 @@ public class ConfigSection {
@Nullable
public Object getObject(final String key, final Object def) {
final String[] parts = key.split("\\.");
int nextSeparatorIndex = -1;
int sectionStartIndex;
ConfigSection section = this;
for (int i = 0; i < parts.length - 1; i++) {
section = section.getSection(parts[i]);
if (section == null) {
return def;
}
while ((nextSeparatorIndex = key.indexOf('.', sectionStartIndex = nextSeparatorIndex + 1)) != -1) {
section = section.getSection(key.substring(sectionStartIndex, nextSeparatorIndex));
if (section == null) return def;
}
final String valueKey = parts[parts.length - 1];
final Object o = section.values.get(valueKey);
return o != null ? o : def;
final String subKey = key.substring(sectionStartIndex);
if (section == this) {
final Object result = values.get(subKey);
return result != null ? result : def;
}
return section.getObject(subKey, def);
}
@Nullable
@@ -161,7 +164,7 @@ public class ConfigSection {
@Nullable
public String getString(final String key, @Nullable final String def) {
final Object o = getObject(key);
return o instanceof String s ? s : def;
return o instanceof String ? (String) o : def;
}
public int getInt(final String key) {
@@ -170,7 +173,7 @@ public class ConfigSection {
public int getInt(final String key, final int def) {
final Object o = getObject(key);
return o instanceof Number number ? number.intValue() : def;
return o instanceof Number ? ((Number) o).intValue() : def;
}
public double getDouble(final String key) {
@@ -179,7 +182,7 @@ public class ConfigSection {
public double getDouble(final String key, final double def) {
final Object o = getObject(key);
return o instanceof Number number ? number.doubleValue() : def;
return o instanceof Number ? ((Number) o).doubleValue() : def;
}
public long getLong(final String key) {
@@ -188,7 +191,7 @@ public class ConfigSection {
public long getLong(final String key, final long def) {
final Object o = getObject(key);
return o instanceof Number number ? number.longValue() : def;
return o instanceof Number ? ((Number) o).longValue() : def;
}
@Nullable
@@ -250,6 +253,6 @@ public class ConfigSection {
}
protected String getFullKeyInPath(final String key) {
return currentPath.isEmpty() ? key : currentPath + '.' + key;
return currentPath.isEmpty() ? key : currentPath + "." + key;
}
}
@@ -146,6 +146,11 @@ public final class ConfigSerializer {
multiLineValue = false;
}
// YAML list items are values, not keys - skip without touching key/indent state
if (line.length() > indent && line.charAt(indent) == '-') {
continue;
}
// Check if this is a level lower
if (indents <= currentIndents) {
final String[] array = key.split(PATH_SEPARATOR_QUOTED);
@@ -1,62 +0,0 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2024 kennytv (https://github.com/kennytv)
*
* 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 eu.kennytv.maintenance.core.config;
import com.google.common.base.Preconditions;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class DisplayedMessages {
private static final Random RANDOM = new Random();
private final Map<String, List<String>> messages;
private final List<String> defaultMessages;
public DisplayedMessages(final Map<String, List<String>> messages) {
this.messages = messages;
this.defaultMessages = messages.get("default");
}
public List<String> getMessages(@Nullable final String key) {
Preconditions.checkNotNull(defaultMessages, "no default message configured in messages list");
if (key == null || messages.size() == 1) {
return defaultMessages;
}
return messages.getOrDefault(key, defaultMessages);
}
public String getRandomEntry(@Nullable final String key) {
final List<String> messages = getMessages(key);
return messages.get(RANDOM.nextInt(messages.size()));
}
public List<String> getDefaultMessages() {
return defaultMessages;
}
public boolean isEmpty() {
return messages.isEmpty();
}
public Set<String> getKeys() {
return messages.keySet();
}
}
@@ -24,7 +24,6 @@ import eu.kennytv.maintenance.core.Settings;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
@SuppressWarnings({"FieldCanBeLocal", "unused"})
public final class MaintenanceDump {
@@ -36,8 +35,12 @@ public final class MaintenanceDump {
general = new ServerDump(plugin.getVersion(), plugin.getServerType().toString(), plugin.getServerVersion(), plugin.getMaintenanceServersDump());
configuration = new LinkedHashMap<>(settings.getConfig().getValues());
addDBSettings("redis", "enabled");
redact("webhook", "url");
final Object o = configuration.get("mysql");
if (o instanceof Map) {
final Map<String, Object> map = new LinkedHashMap<>(((Map<String, Object>) o));
map.keySet().removeIf(key -> !key.equals("use-mysql") && !key.equals("update-interval"));
configuration.put("mysql", map);
}
configuration.put("whitelisted-players", settings.getWhitelistedPlayers());
configuration.put("icon-exists", new File(plugin.getDataFolder(), "maintenance-icon.png").exists());
@@ -45,28 +48,4 @@ public final class MaintenanceDump {
jsonObject.add("plugins", MaintenancePlugin.GSON.toJsonTree(plugin.getPlugins()));
plugins = jsonObject;
}
private void redact(final String key, final String... subKeys) {
final Object o = configuration.get(key);
if (o instanceof Map) {
final Map<String, Object> map = new LinkedHashMap<>(((Map<String, Object>) o));
for (final String subKey : subKeys) {
final Object value = map.get(subKey);
if (value != null) {
map.put(subKey, value.toString().isEmpty() ? "" : "<redacted>");
}
}
configuration.put(key, map);
}
}
private void addDBSettings(final String key, final String... allowedSubKeys) {
final Set<String> allowedSubKeysSet = Set.of(allowedSubKeys);
final Object o = configuration.get(key);
if (o instanceof Map) {
final Map<String, Object> map = new LinkedHashMap<>(((Map<String, Object>) o));
map.keySet().removeIf(subKey -> !allowedSubKeysSet.contains(subKey));
configuration.put(key, map);
}
}
}
@@ -19,7 +19,12 @@ package eu.kennytv.maintenance.core.dump;
import java.util.List;
public record PluginDump(String name, String version, List<String> authors) {
@SuppressWarnings({"FieldCanBeLocal", "unused"})
public final class PluginDump {
private final String name;
private final String version;
private final List<String> authors;
public PluginDump(final String name, final String version, final List<String> authors) {
this.name = name;
this.version = version;
@@ -19,5 +19,17 @@ package eu.kennytv.maintenance.core.dump;
import java.util.List;
public record ServerDump(String pluginVersion, String platform, String serverVersion, List<String> maintenance) {
@SuppressWarnings({"FieldCanBeLocal", "unused"})
public final class ServerDump {
private final String pluginVersion;
private final String platform;
private final String serverVersion;
private final List<String> maintenance;
public ServerDump(final String pluginVersion, final String platform, final String serverVersion, final List<String> maintenance) {
this.pluginVersion = pluginVersion;
this.platform = platform;
this.serverVersion = serverVersion;
this.maintenance = maintenance;
}
}
@@ -24,10 +24,10 @@ public final class ServerListPlusHook {
private final ServerListPlusCore serverListPlusCore;
public ServerListPlusHook(final Object serverListPlus) {
if (!(serverListPlus instanceof ServerListPlusPlugin serverListPlusPlugin)) {
if (!(serverListPlus instanceof ServerListPlusPlugin)) {
throw new IllegalArgumentException("Couldn't parse ServerListPlus instance!");
}
this.serverListPlusCore = serverListPlusPlugin.getCore();
this.serverListPlusCore = ((ServerListPlusPlugin) serverListPlus).getCore();
}
public void setEnabled(final boolean enable) {
@@ -19,19 +19,17 @@ package eu.kennytv.maintenance.core.listener;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.util.DiscordWebhook;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.TextComponent;
import eu.kennytv.maintenance.lib.kyori.adventure.text.event.ClickEvent;
import eu.kennytv.maintenance.lib.kyori.adventure.text.event.HoverEvent;
import eu.kennytv.maintenance.lib.kyori.adventure.text.format.NamedTextColor;
import eu.kennytv.maintenance.lib.kyori.adventure.text.format.TextDecoration;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
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 static eu.kennytv.maintenance.core.util.ComponentUtil.clickEvent;
public abstract class JoinListenerBase {
protected final MaintenancePlugin plugin;
@@ -50,16 +48,13 @@ public abstract class JoinListenerBase {
* @return true if the sender should be kicked
*/
protected boolean shouldKick(final SenderInfo sender, final boolean updateCheck) {
if (!settings.isMaintenance() || sender.hasMaintenancePermission("bypass") || settings.isWhitelisted(sender.uuid())) {
if (!settings.isMaintenance() || sender.hasMaintenancePermission("bypass") || settings.isWhitelisted(sender.getUuid())) {
if (updateCheck) {
updateCheck(sender);
}
return false;
}
if (settings.isWebhookEnabled()) {
plugin.sendWebhookMessage("webhookJoinNotification", DiscordWebhook.EventType.BLOCKED_JOIN, "%PLAYER%", sender.name());
}
return true;
}
@@ -69,19 +64,19 @@ public abstract class JoinListenerBase {
protected void updateCheck(final SenderInfo sender) {
if (!settings.hasUpdateChecks()) return;
if (!sender.hasPermission("maintenance.admin") || notifiedPlayers.contains(sender.uuid())) return;
if (!sender.hasPermission("maintenance.admin") || notifiedPlayers.contains(sender.getUuid())) return;
plugin.async(() -> {
if (!plugin.updateAvailable()) {
return;
}
notifiedPlayers.add(sender.uuid());
notifiedPlayers.add(sender.getUuid());
sender.sendPrefixedRich("<red>There is a newer version available: <green>Version " + plugin.getNewestVersion() + "<red>, you're on <green>" + plugin.getVersion());
final TextComponent text = Component.text().content("Download it at: ").color(NamedTextColor.RED)
.append(Component.text().content(MaintenancePlugin.HANGAR_URL).color(NamedTextColor.GOLD))
.append(Component.text().content(" (CLICK ME)").color(NamedTextColor.GRAY).decorate(TextDecoration.BOLD))
.clickEvent(clickEvent(ClickEvent.Action.OPEN_URL, MaintenancePlugin.HANGAR_URL))
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, MaintenancePlugin.HANGAR_URL))
.hoverEvent(HoverEvent.showText(Component.text("Download the latest version").color(NamedTextColor.GREEN)))
.build();
sender.send(plugin.prefix().append(text));
@@ -19,24 +19,17 @@ package eu.kennytv.maintenance.core.runnable;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
public class MaintenanceRunnable extends MaintenanceRunnableBase {
protected final String mode;
public MaintenanceRunnable(final MaintenancePlugin plugin, final Settings settings, final int seconds, final boolean enable) {
this(plugin, settings, seconds, enable, null);
}
public MaintenanceRunnable(final MaintenancePlugin plugin, final Settings settings, final int seconds, final boolean enable, @Nullable final String mode) {
super(plugin, settings, seconds, enable);
this.mode = mode;
}
@Override
protected void finish() {
plugin.setMaintenance(enable, mode);
plugin.setMaintenance(enable);
}
@Override
@@ -20,7 +20,7 @@ package eu.kennytv.maintenance.core.runnable;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.util.Task;
import net.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
public abstract class MaintenanceRunnableBase implements Runnable {
protected final MaintenancePlugin plugin;
@@ -19,19 +19,14 @@ package eu.kennytv.maintenance.core.runnable;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import java.time.Duration;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
public final class MaintenanceScheduleRunnable extends MaintenanceRunnable {
private final int maintenanceDuration;
public MaintenanceScheduleRunnable(final MaintenancePlugin plugin, final Settings settings, final int secondsToEnable, final int maintenanceDuration) {
this(plugin, settings, secondsToEnable, maintenanceDuration, null);
}
public MaintenanceScheduleRunnable(final MaintenancePlugin plugin, final Settings settings, final int secondsToEnable, final int maintenanceDuration, @Nullable final String mode) {
super(plugin, settings, secondsToEnable, true, mode);
super(plugin, settings, secondsToEnable, true);
this.maintenanceDuration = maintenanceDuration;
}
@@ -1,48 +0,0 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2024 kennytv (https://github.com/kennytv)
*
* 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 eu.kennytv.maintenance.core.util;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import net.kyori.adventure.text.event.ClickEvent;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class ComponentUtil {
private static final MethodHandle LEGACY_CLICK_EVENT = legacyClickEvent();
@SuppressWarnings({"rawtypes", "unchecked"})
public static ClickEvent clickEvent(final ClickEvent.Action action, final String value) {
if (LEGACY_CLICK_EVENT != null) {
try {
return (ClickEvent) LEGACY_CLICK_EVENT.invoke(action, value);
} catch (final Throwable e) {
throw new RuntimeException(e);
}
}
return ClickEvent.clickEvent(action, ClickEvent.Payload.string(value));
}
private static @Nullable MethodHandle legacyClickEvent() {
try {
return MethodHandles.publicLookup().unreflect(ClickEvent.class.getDeclaredMethod("clickEvent", ClickEvent.Action.class, String.class));
} catch (final NoSuchMethodException | IllegalAccessException e) {
return null;
}
}
}
@@ -1,74 +0,0 @@
package eu.kennytv.maintenance.core.util;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import eu.kennytv.maintenance.core.Settings;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public final class DiscordWebhook {
private static final int COLOR_MAINTENANCE_ENABLED = 0xED4245; // Red
private static final int COLOR_MAINTENANCE_DISABLED = 0x57F287; // Green
private static final int COLOR_STARTTIMER = 0xFEE75C; // Yellow
private static final int COLOR_ENDTIMER = 0x5865F2; // Blue
private static final int COLOR_BLOCKED_JOIN = 0xE67E22; // Orange
public static void sendMessage(final String message, final EventType event, final Settings settings) throws IOException, InterruptedException {
final JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("username", settings.getWebhookUsername());
final String avatarUrl = settings.getWebhookAvatarUrl();
if (!avatarUrl.isEmpty()) {
jsonObject.addProperty("avatar_url", avatarUrl);
}
final JsonObject embed = new JsonObject();
embed.addProperty("description", message);
embed.addProperty("color", getColorForEvent(event));
final JsonArray embeds = new JsonArray();
embeds.add(embed);
jsonObject.add("embeds", embeds);
try (final HttpClient client = HttpClient.newHttpClient()) {
final HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(settings.getWebhookUrl()))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonObject.toString()))
.build();
client.send(request, HttpResponse.BodyHandlers.discarding());
}
}
private static int getColorForEvent(final EventType event) {
return switch (event) {
case MAINTENANCE_ENABLED -> COLOR_MAINTENANCE_ENABLED;
case MAINTENANCE_DISABLED -> COLOR_MAINTENANCE_DISABLED;
case STARTTIMER_STARTED -> COLOR_STARTTIMER;
case ENDTIMER_STARTED -> COLOR_ENDTIMER;
case BLOCKED_JOIN -> COLOR_BLOCKED_JOIN;
};
}
public enum EventType {
MAINTENANCE_ENABLED("maintenance_status"),
MAINTENANCE_DISABLED("maintenance_status"),
STARTTIMER_STARTED("starttimer_started"),
ENDTIMER_STARTED("endtimer_started"),
BLOCKED_JOIN("blocked_join");
private final String configKey;
EventType(final String configKey) {
this.configKey = configKey;
}
public String configKey() {
return configKey;
}
}
}
@@ -17,10 +17,28 @@
*/
package eu.kennytv.maintenance.core.util;
import java.util.UUID;
import net.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
public record DummySenderInfo(UUID uuid, String name) implements SenderInfo {
import java.util.UUID;
public final class DummySenderInfo implements SenderInfo {
private final UUID uuid;
private final String name;
public DummySenderInfo(final UUID uuid, final String name) {
this.uuid = uuid;
this.name = name;
}
@Override
public UUID getUuid() {
return uuid;
}
@Override
public String getName() {
return name;
}
@Override
public boolean hasPermission(final String permission) {
@@ -19,15 +19,15 @@ package eu.kennytv.maintenance.core.util;
import eu.kennytv.maintenance.api.MaintenanceProvider;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.minimessage.MiniMessage;
import java.util.UUID;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
public interface SenderInfo {
UUID uuid();
UUID getUuid();
String name();
String getName();
boolean hasPermission(String permission);
@@ -20,7 +20,7 @@ package eu.kennytv.maintenance.core.util;
public enum ServerType {
BUNGEE("Bungee"),
PAPER("Paper"),
SPIGOT("Spigot"),
SPONGE("Sponge"),
VELOCITY("Velocity");
@@ -89,7 +89,8 @@ public final class Version implements Comparable<Version> {
@Override
public boolean equals(final Object o) {
if (o == this) return true;
if (!(o instanceof Version other)) return false;
if (!(o instanceof Version)) return false;
final Version other = (Version) o;
return version.equals(other.version);
}
}
+34 -66
View File
@@ -8,8 +8,8 @@
###################################################################################################################
# You can report bugs here: https://github.com/kennytv/Maintenance/issues
# If you need any other help/support, you can also join my Discord server: https://discord.gg/vGCUzHq
# The config and language files use MiniMessage, NOT legacy text for input. Use https://webui.advntr.dev/ to edit and preview the formatted text.
# For a full list of formats and fancy examples of MiniMessage, see https://docs.papermc.io/adventure/minimessage/format/
# The config and language files use MiniMessage, NOT legacy text for input. Use https://webui.adventure.kyori.net/ to edit and preview the formatted text.
# For a full list of formats and fancy examples of MiniMessage, see https://docs.adventure.kyori.net/minimessage/format.html
# Changes the language of command feedback/messages.
# If you find missing translations or want to contribute, see https://crowdin.com/project/maintenance
@@ -18,26 +18,16 @@
language: en
# Enables maintenance mode.
maintenance-enabled: false
# The currently active maintenance mode key (used for mode-specific messages/icons).
# Use 'default' or leave empty to use fallback messages.
active-mode: default
# Value for the %REASON% placeholder in maintenance messages.
# This can be changed via /maintenance setreason <text>.
active-reason: ""
maintenance-enabled: true
# Enables maintenance on certain servers managed by your proxy instance(s).
# The value is the mode key used for ping/player count messages for that server.
proxied-maintenance-servers:
PaperServer1: default
# AnotherServer: release
# - AServer
# If maintenance is enabled on a proxied server with players on it, they will be sent to the fallback server instead of being kicked off the network.
# If the fallback server is not reachable/not set, they will just be kicked off the network.
# This can also be set to an array to set multiple fallback servers, in case one server is not always reachable: 'fallback: [s1, s2, s3, ...]'
fallback: lobby
fallback: unreachable
# If maintenance is enabled globally, you can define a "waiting" lobby for players to be sent to instead of being kicked.
# Leave this empty to disable.
@@ -45,53 +35,35 @@ waiting-server: ""
# The message (MOTD) shown in the multiplayer server list motd when maintenance is enabled.
# If you put in multiple entries, one of them will be chosen randomly on every ping.
# The type of mode can be defined in the command, or will be the default mode.
# If running an endtimer, the time left can be displayed by including '%TIMER%' in a ping message.
ping-message:
enabled: true
# Always uses 'default' if not defined in the command or not present in the config.
# Additional examples could look as follows:
# default:
# - "<red>Currently under maintenance<br><gradient:#fbffc2:#0fffff>We will be back soon!"
# - "<red>Wooow you found our secondary MOTD!"
# reason:
# - "<red>Currently under maintenance<br><gradient:#fbffc2:#0fffff>%REASON%"
# release:
# - "<gold>We're currently preparing the release, come back soon!"
messages:
default:
- "<red>Currently under maintenance<br><gradient:#fbffc2:#0fffff>We will be back soon!"
- "<bold><green>True<red>OG</bold> <yellow>Network</yellow> <aqua>》<red> Updating... </red><aqua>《 <gold>[1.8.0-1.21.11]<br><yellow>⚠ <dark_red>Maintenance in progress! <yellow>We'll be back <dark_aqua>soon™"
# If set to true and an endtimer is currently running, a message from this pool will be chosen
# instead of the ones above, so you can have different messages for when an endtimer is running/not running.
enable-timer-specific-messages: true
# If running an endtimer, the time left can be displayed by including '%TIMER%' in a ping message.
timer-messages:
default:
- "<red>Currently under maintenance<br><gradient:#fbffc2:#fffff>Come back in:</gradient> <color:#aa55ee>%TIMER%"
- "<bold><green>True<red>OG</bold> <yellow>Network</yellow> <aqua>》<red>Maintenance Mode</red><aqua>《 <gold>[1.8.0-1.21.11]<br><dark_red>Maintenance ends in <yellow>%TIMER% <gray>| <green>Thanks for waiting!"
# If enabled, the message below will be shown in the top right corner of the server in the server list, where the player count would normally be displayed.
# Same as the ping-message, you can define messages for different modes.
# You can use '%ONLINE%' and '%MAX%' if you want to include the player count in a custom message (e.g. "Maintenance %ONLINE%/%MAX%").
# DOES NOT SUPPORT RGB!
player-count-message:
enabled: true
messages:
default: "<dark_red>Maintenance"
message: "<dark_red>Maintenance"
# If set to true and an endtimer is currently running, the timer message will be used instead of the normal one.
enable-timer-specific-message: false
timer-messages:
default: "<dark_red>Come back in: <yellow>%TIMER%"
enable-timer-specific-message: true
timer-message: "<dark_red>Come back in: <yellow>%TIMER%"
# Is shown when you move your mouse above the text in the top right corner of the server in the server list, where the player count would normally be displayed.
# Same as the ping-message, you can define messages for different modes.
# DOES NOT SUPPORT RGB!
player-list-hover-message:
enabled: true
messages:
default: "<red>Currently under<br><red>maintenance"
message: "<red>Currently under<br><red>maintenance"
# If set to true and an endtimer is currently running, the timer message will be used instead of the normal one.
enable-timer-specific-message: false
timer-messages:
default: "<red>Come back in:<br><red><yellow>%TIMER%"
enable-timer-specific-message: true
timer-message: "<red>Come back in:<br><red><yellow>%TIMER%"
# Any extra commands inside the arrays will be executed when maintenance is enabled/disabled.
# Example: commands-on-maintenance-enable: ["say hello!", "stop"]
@@ -112,7 +84,7 @@ custom-maintenance-icon: false
# If set to true, players with the 'maintenance.joinnotification' permission will receive a message,
# that a player tried to join the server while maintenance is enabled.
send-join-notification: false
send-join-notification: true
# Set this to false if you do not want players to be kicked when you enable maintenance (new connections will still be blocked).
kick-online-players: true
@@ -131,32 +103,28 @@ continue-endtimer-after-restart:
# If using the timer command: In what intervalls before enabling/disabling maintenance there will be a broadcast.
timer-broadcast-for-seconds: [1200, 900, 600, 300, 120, 60, 30, 20, 10, 5, 4, 3, 2, 1]
# Allows sending a Discord webhook on certain events.
webhook:
enabled: false
# Possible values: maintenance_status, starttimer_started, endtimer_started, blocked_join
enabled-events: ["maintenance_status", "starttimer_started", "endtimer_started"]
# Copy and paste the webhook url from Server Settings --> Apps Integrations --> Webhooks
url: ""
# The username displayed for the webhook bot message.
username: "Maintenance"
# The avatar URL used for the webhook bot message. Leave empty to use the default Discord webhook avatar.
avatar-url: ""
# If you have 2 or more proxy instances, the Redis connection will make sure all proxies
# have the same maintenance status (global as well as per server) and whitelisted players,
# so you won't have to update these on every proxy by hand.
redis:
enabled: false
# Make sure your Redis instance is properly protected.
# URI format: redis[s]://[[username][:password]@][host][:port][/db-number]
# E.g. an SSL connection to a password protected redis could look like this: "rediss://user:password@127.0.0.1:6379"
uri: "redis://localhost:6379"
# If you have 2 or more proxy instances, the database connection will make sure all proxies
# have the same maintenance status, so you won't have to enable/disable it on every proxy by hand.
mysql:
use-mysql: false
host: host
port: 3306
database: database
username: username
password: password
# Requests to the database will only be made at least x seconds after the last request,
# so there won't be a request on every single ping on a server with many players.
#
# Set this to 0 to make a database request on (almost) every single ping.
# (0 is not recommended if having more than a hundred concurrent players, then I'd recommend keeping it from 10-60).
update-interval: 15
# If you for some reason cannot establish SSL connections to your database, you may disable it here (not recommended).
use-ssl: true
# If disabled, you will no longer receive any messages if there is an update.
# Not recommended to disable, as new versions generally tend to run better and with fewer bugs.
# However, you can always check for updates manually using the '/maintenance update' command.
update-checks: true
update-checks: false
# Used for autoupdating the config, do not change this value.
config-version: 12
config-version: 9
-124
View File
@@ -1,124 +0,0 @@
#You can use https://webui.advntr.dev/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.papermc.io/adventure/minimessage/format/
#If you want to contribute changes to the default messages, you can do so via https://crowdin.com/project/maintenance
#Messages containing the placeholder "<prefix>" will have it replaced with the following string
prefix: "<dark_gray>[<yellow>Maintenance<dark_gray>] "
noPermission: "<red>No tens permís per executar aquesta ordre."
kickmessage: "<red>El servidor està en manteniment!<br>Torna-ho a provar més tard!"
maintenanceActivated: "<prefix><gold>El mode de manteniment s'ha activat."
maintenanceDeactivated: "<prefix><gold>El mode de manteniment s'ha desactivat."
maintenanceStatusOn: "<prefix><gold>Maintenance mode is currently <green>enabled<gold>."
maintenanceStatusOff: "<prefix><gold>Maintenance mode is currently <red>disabled<gold>."
maintenanceStatusOnWithEndTimer: "<prefix><gold>Maintenance mode is currently <green>enabled <grey>and will be disabled in <gold>%TIME%."
maintenanceStatusOffWithStartTimer: "<prefix><gold>Maintenance mode is currently <red>disabled <grey>and will be enabled in <gold>%TIME%."
alreadyEnabled: "<prefix><red>El manteniment ja està activat!"
alreadyDisabled: "<prefix><red>El manteniment ja està desactivat!"
endtimerBroadcast: "<prefix><gray>El mode de manteniment es desactivarà en <gold>%TIME%<gray>."
endtimerStarted: "<prefix><green>Temporitzador iniciat: <gray>El mode de manteniment es desactivarà en <gold>%TIME%<gray>."
starttimerBroadcast: "<prefix><gray>El mode de manteniment s'activarà en <gold>%TIME%<gray>."
starttimerStarted: "<prefix><green>Temporitzador iniciat: <gray>El mode de manteniment s'activarà en <gold>%TIME%<gray>."
scheduletimerBroadcast: "<prefix><gray>El mode de manteniment s'activarà en <gold>%TIME% <gray>i durarà <gold>%DURATION%<gray>."
scheduletimerStarted: "<prefix><green>Temporitzador iniciat: <gray>El mode de manteniment s'activarà en <gold>%TIME% <gray>i durarà <gold>%DURATION%<gray>."
timerAlreadyRunning: "<prefix><red>Ja hi ha un temporitzador programat!"
timerNotRunning: "<prefix><red>No hi ha cap temporitzador en marxa."
timerCancelled: "<prefix><red>S'ha cancel·lat el temporitzador actual."
timerTooLong: "<prefix><red>La durada ha de ser inferior a 28 dies!"
timerMotdDisabled: "<prefix><red>Has de configurar 'enable-timerspecific-messages' a 'true' al fitxer de configuració per utilitzar/editar missatges MOTD específics del temporitzador."
motdTimer: "%HOURS%:%MINUTES%:%SECONDS%"
motdTimerNotRunning: "-"
joinNotification: "<prefix><yellow>%PLAYER% <red>ha intentat unir-se al servidor."
motdList: "<prefix><gray>Llista dels teus missatges MOTD de manteniment:"
motdListEmpty: "<prefix><red>No tens cap missatge MOTD de manteniment configurat!"
reload: "<prefix><green>S'han recarregat la configuració, la llista de jugadors permitits, el fitxer d'idioma i la icona de manteniment."
removedMotd: "<prefix><green>S'ha eliminat el missatge MOTD número %INDEX%."
removeMotdError: "<prefix><red>Només tens un missatge MOTD, no en pots eliminar cap!"
setMotd: "<prefix><green>S'ha configurat la línia %LINE% del missatge MOTD de manteniment %INDEX% a %MOTD%"
setReason: "<prefix><green>Set maintenance reason to: <yellow>%REASON%"
setMotdIndexError: "<prefix><red>Actualment tens %MOTDS% missatges MOTD, has de triar un número entre 1 i %NEWAMOUNT%."
setMotdLineError: "<prefix><red>El segon argument ha de ser el número de línia (1 o 2)!"
updateDownloading: "<prefix><red><bold>S'està descarregant l'actualització..."
updateFailed: "<prefix><dark_red><bold>L'actualització ha fallat!"
updateFinished: "<prefix><green><bold>L'actualització s'ha completat! Per evitar problemes amb tasques i completar l'actualització, has de reiniciar el servidor!"
whitelistedPlayers: "<prefix><gold>Jugadors permesos durant el manteniment:"
whitelistedPlayersFormat: "<dark_gray>- <yellow>%NAME% <dark_gray>(<gray>%UUID%<dark_gray>)"
whitelistAdded: "<prefix><green>S'ha afegit <aqua>%PLAYER% <green>a la llista blanca de manteniment!"
whitelistAlreadyAdded: "<prefix><aqua>%PLAYER% <red>ja està a la llista blanca de manteniment!"
whitelistRemoved: "<prefix><green>S'ha eliminat <aqua>%PLAYER% <green>de la llista blanca de manteniment!"
whitelistNotFound: "<prefix><red>Aquest jugador no està a la llista blanca de manteniment!"
whitelistEmpty: "<prefix><red>La llista blanca de manteniment està buida! Utilitza <yellow>/maintenance add <player/uuid> <red>per afegir algú!"
playerNotFound: "<prefix><red>No s'ha trobat cap jugador amb aquest nom al servidor."
playerNotFoundUuid: "<prefix><red>No s'ha trobat cap jugador amb aquesta UUID."
playerNotOnline: "<prefix><red>No hi ha cap jugador en línia amb aquest nom."
offlinePlayerFetchError: "<prefix><red>Hi ha hagut un error en obtenir les dades del jugador fora de línia. Torna-ho a provar més tard."
invalidUuid: "<prefix><red>Format d'UUID no vàlid!"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
sentToWaitingServer: "<prefix><red>Se t'ha enviat a un servidor d'espera!"
forceWaitingServer: "<prefix><red>No pots abandonar el servidor d'espera mentre el manteniment estigui actiu!"
serverNotFound: "<prefix><red>No hi ha cap servidor amb aquest nom registrat al proxy!"
singleTimerAlreadyRunning: "<prefix><red>Ja hi ha un temporitzador programat per a aquest servidor!"
singleTimerCancelled: "<prefix><red>S'ha cancel·lat el temporitzador actual per al servidor <yellow>%SERVER%<red>."
singleTimerNotRunning: "<prefix><red>No hi ha cap temporitzador en marxa per a aquest servidor."
singleEndtimerBroadcast: "<prefix><gray>El mode de manteniment al servidor %SERVER% es desactivarà en <gold>%TIME%<gray>."
singleEndtimerStarted: "<prefix><green>Temporitzador iniciat: <gray>El mode de manteniment al servidor %SERVER% es desactivarà en <gold>%TIME%<gray>."
singleStarttimerBroadcast: "<prefix><gray>El mode de manteniment al servidor %SERVER% s'activarà en <gold>%TIME%<gray>."
singleStarttimerStarted: "<prefix><green>Temporitzador iniciat: <gray>El mode de manteniment al servidor %SERVER% s'activarà en <gold>%TIME%<gray>."
singleScheduletimerBroadcast: "<prefix><gray>El mode de manteniment al servidor %SERVER% s'activarà en <gold>%TIME% <gray>i durarà <gold>%DURATION%<gray>."
singleScheduletimerStarted: "<prefix><green>Temporitzador iniciat: <gray>El mode de manteniment al servidor %SERVER% s'activarà en <gold>%TIME% <gray>i durarà <gold>%DURATION%<gray>."
singleMaintenanceKick: "<prefix><red>El servidor %SERVER% està en manteniment! Torna-ho a provar més tard!"
singleMaintenanceKickComplete: "<red>El servidor %SERVER% està en manteniment!<br>Pots tornar a connectar-te per anar a un altre servidor!"
singleMaintenanceActivated: "<prefix><gold>El mode de manteniment s'ha activat al servidor <yellow>%SERVER%<gold>."
singleMaintenanceDeactivated: "<prefix><gold>El mode de manteniment s'ha desactivat al servidor <yellow>%SERVER%<gold>."
singleServerAlreadyEnabled: "<prefix><red>El manteniment ja està activat al servidor <yellow>%SERVER%<red>!"
singleServerAlreadyDisabled: "<prefix><red>El manteniment ja està desactivat al servidor <yellow>%SERVER%<red>!"
singleServerMaintenanceList: "<prefix><gray>Servidors proxy que tenen el manteniment activat:"
singleServerMaintenanceListEmpty: "<prefix><gray>No hi ha cap servidor proxy en manteniment."
singleServerMaintenanceListEntry: "<dark_grey>- <aqua>%SERVER%"
singleServerMaintenanceListEntryWithStartTimer: "<dark_grey>- <grey>%SERVER% <yellow>starting in <gold>%TIME%"
singleServerMaintenanceListEntryWithEndTimer: "<dark_grey>- <aqua>%SERVER% <yellow>ending in <gold>%TIME%"
second: "segon"
seconds: "segons"
minute: "minut"
minutes: "minuts"
hour: "hora"
hours: "hores"
helpHeader: "<dark_gray>========[ <yellow>%NAME% <dark_gray>| <yellow>%PAGE%/%MAX% <dark_gray>]========"
helpPageNotFound: "<prefix><red>No hi ha cap pàgina amb aquest número!"
helpNextPage: "<gray>Fes servir <aqua>/maintenance help %PAGE% <gray>per anar a la següent pàgina d'ajuda."
helpAbortTimer: "<gold>/maintenance aborttimer <gray>(Si està actiu, cancel·la el temporitzador actual)"
helpEndtimer: "<gold>/maintenance endtimer <desactivar en> <gray>(Després del temps indicat, p. ex. 1h5m, es desactivarà el manteniment)"
helpStarttimer: "<gold>/maintenance starttimer <activar en> <gray>(Després del temps indicat, p. ex. 1h5m, s'activarà el manteniment)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <activar en> <durada del manteniment> <gray>(Després del temps indicat, p. ex. 1h5m, s'activarà el manteniment)"
helpDebug: "<gold>/maintenance debug <gray>(Activa el registre de depuració)"
helpDump: "<gold>/maintenance dump <gray>(Extreu informació del servidor, útil per informes d'errors)"
helpHelp: "<gold>/maintenance help [pàgina] <gray>(Mostra aquesta finestra d'ajuda)"
helpMotd: "<gold>/maintenance motd [timer] <gray>(Mostra els missatges MOTD de manteniment. Si s'especifica 'timer', es mostraran els MOTD del temporitzador)"
helpRemoveMotd: "<gold>/maintenance removemotd [timer] <índex> <gray>(Elimina un missatge MOTD de manteniment. Si s'usa 'timer', s'eliminarà un missatge específic del temporitzador)"
helpSetMotd: "<gold>/maintenance setmotd [timer] <índex> <1/2> <missatge> <gray>(Configura un missatge MOTD per al manteniment. Si s'usa 'timer', es configurarà un missatge específic del temporitzador)"
helpSetReason: "<gold>/maintenance setreason <reason/none> <gray>(Sets or clears the %REASON% placeholder value)"
helpReload: "<gold>/maintenance reload <gray>(Recarrega el fitxer de configuració, la llista de permitits i la icona del servidor)"
helpGlobalStatus: "<gold>/maintenance status <gray>(Shows the current maintenance status and any running timers)"
helpToggle: "<gold>/maintenance <on/off> [mode] <gray>(Enables/disables maintenance mode with an optional display mode when enabling)"
helpUpdate: "<gold>/maintenance update <gray>(Descarrega la versió més recent del plugin al servidor)"
helpWhitelist: "<gold>/maintenance whitelist <gray>(Mostra tots els jugadors permitits durant el manteniment)"
helpWhitelistAdd: "<gold>/maintenance add <nom/uuid> <gray>(Afegeix el jugador a la llista de permitits del manteniment)"
helpWhitelistRemove: "<gold>/maintenance remove <nom/uuid> <gray>(Elimina el jugador de la llista de permitits del manteniment)"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
helpAbortSingleTimer: "<gold>/maintenance aborttimer [servidor] <gray>(Si està actiu, cancel·la el temporitzador del servidor)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server|global] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server|global] [mode] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server|global] [mode] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server|global] [mode] <gray>(Enables/disables maintenance mode globally or on a specific server with an optional display mode when enabling)"
helpStatus: "<gold>/maintenance status <gray>(Mostra tots els servidors proxy en manteniment)"
#Discord webhook messages. These use Discord markdown, not MiniMessage.
#For timer webhooks, %TIMESTAMP% is a Unix timestamp for use in Discord timestamp tags, e.g. <t:%TIMESTAMP%:R>.
webhookMaintenanceActivated: "**Maintenance mode enabled.**"
webhookMaintenanceDeactivated: "**Maintenance mode disabled.**"
webhookStarttimerStarted: "Maintenance mode will be enabled <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookEndtimerStarted: "Maintenance mode will be disabled <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookJoinNotification: "Blocked join: `%PLAYER%` tried to join during maintenance."
webhookSingleMaintenanceActivated: "Maintenance mode enabled on `%SERVER%`."
webhookSingleMaintenanceDeactivated: "Maintenance mode disabled on `%SERVER%`."
webhookSingleStarttimerStarted: "Maintenance mode will be enabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookSingleEndtimerStarted: "Maintenance mode will be disabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
#Used for autoupdating the language file, do not change this value.
language-version: 5
+10 -30
View File
@@ -1,16 +1,12 @@
#You can use https://webui.advntr.dev/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.papermc.io/adventure/minimessage/format/
#If you want to contribute changes to the default messages, you can do so via https://crowdin.com/project/maintenance
#Maintenance Plugin by kennytv
#You can use https://webui.adventure.kyori.net/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.adventure.kyori.net/minimessage/format.html
#Messages containing the placeholder "<prefix>" will have it replaced with the following string
prefix: "<dark_gray>[<yellow>Maintenance<dark_gray>] "
noPermission: "<red>Du har ikke tilladelse til at udføre denne kommando."
kickmessage: "<red>Serveren er i øjeblikket under vedligeholdelse!<br>Prøv igen senere!"
maintenanceActivated: "<prefix><gold>Vedligeholdelsestilstand er nu aktiveret."
maintenanceDeactivated: "<prefix><gold>Vedligeholdelsestilstand er nu deaktiveret."
maintenanceStatusOn: "<prefix><gold>Maintenance mode is currently <green>enabled<gold>."
maintenanceStatusOff: "<prefix><gold>Maintenance mode is currently <red>disabled<gold>."
maintenanceStatusOnWithEndTimer: "<prefix><gold>Maintenance mode is currently <green>enabled <grey>and will be disabled in <gold>%TIME%."
maintenanceStatusOffWithStartTimer: "<prefix><gold>Maintenance mode is currently <red>disabled <grey>and will be enabled in <gold>%TIME%."
alreadyEnabled: "<prefix><red>Vedligeholdelsestilstand er allerede aktiveret!"
alreadyDisabled: "<prefix><red>Vedligeholdelsestilstand er allerede deaktiveret!"
endtimerBroadcast: "<prefix><gray>Vedligeholdelsestilstand vil blive deaktiveret om <gold>%TIME%<gray>."
@@ -33,7 +29,6 @@ reload: "<prefix><green>Genindlæs konfigurationsfilen, hvidlistede spillere, sp
removedMotd: "<prefix><green>Slet motd nummer %INDEX%."
removeMotdError: "<prefix><red>Du har kun én motd, så du kan ikke slette nogen!"
setMotd: "<prefix><green>Angiv linje %LINE% af %INDEX%. vedligeholdelses motd til %MOTD%"
setReason: "<prefix><green>Set maintenance reason to: <yellow>%REASON%"
setMotdIndexError: "<prefix><red>Du har %MOTDS% motds, så du skal angive et nummer mellem 1 og %NEWAMOUNT%."
setMotdLineError: "<prefix><red>Det andet argument skal være linjenummer (1 or 2)!"
updateDownloading: "<prefix><red><bold>Downloader opdatering..."
@@ -49,7 +44,7 @@ whitelistEmpty: "<prefix><red>Vedligeholdelseshvidlisten er tom! Brug <yellow>/m
playerNotFound: "<prefix><red>Ingen spillere med dette navn har spillet på denne server før."
playerNotFoundUuid: "<prefix><red>Ingen spiller med den uuid kunne findes."
playerNotOnline: "<prefix><red>Der er ingen spiller online med det navn."
offlinePlayerFetchError: "<prefix><red>Der opstod en fejl under hentning af offline afspiller. Prøv igen senere."
offlinePlayerFetchError: "<prefix><red>There was an error while fetching offline player. Please try again later."
invalidUuid: "<prefix><red>Ugyldigt uuid-format!"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
sentToWaitingServer: "<prefix><red>Du er blevet sendt til en venteserver!"
@@ -73,8 +68,6 @@ singleServerAlreadyDisabled: "<prefix><red>Vedligeholdelsestilstand er allerede
singleServerMaintenanceList: "<prefix><gray>Proxyservere, der har Vedligeholdelsestilstand aktiveret:"
singleServerMaintenanceListEmpty: "<prefix><gray>Der er ingen proxy-servere, der er under vedligeholdelse."
singleServerMaintenanceListEntry: "<dark_grey>- <aqua>%SERVER%"
singleServerMaintenanceListEntryWithStartTimer: "<dark_grey>- <grey>%SERVER% <yellow>starting in <gold>%TIME%"
singleServerMaintenanceListEntryWithEndTimer: "<dark_grey>- <aqua>%SERVER% <yellow>ending in <gold>%TIME%"
second: "sekund"
seconds: "sekunder"
minute: "minut"
@@ -94,31 +87,18 @@ helpHelp: "<gold>/maintenance help [page] <gray>(Viser dette smukke hjælpevindu
helpMotd: "<gold>/maintenance motd [timer] <gray>(Viser den aktuelle vedligeholdelses motds. Hvis 'timer' er angivet, bliver dennes motds vist)"
helpRemoveMotd: "<gold>/maintenance removemotd [timer] <index> <gray>(Sletter en vedligeholdelses motd. Hvis 'timer' er angivet, vil en tidsspecifik pingbesked blive slettet)"
helpSetMotd: "<gold>/maintenance setmotd [timer] <index> <1/2> <message> <gray>(Angiver en motd for vedligeholdelsestilstand. Hvis 'timer' er angivet, vil en tidsspecifik pingbesked blive angivet)"
helpSetReason: "<gold>/maintenance setreason <reason/none> <gray>(Sets or clears the %REASON% placeholder value)"
helpReload: "<gold>/maintenance reload <gray>(Genindlæser konfigurationsfilen, hvidlisten og serverikonet)"
helpGlobalStatus: "<gold>/maintenance status <gray>(Shows the current maintenance status and any running timers)"
helpToggle: "<gold>/maintenance <on/off> [mode] <gray>(Enables/disables maintenance mode with an optional display mode when enabling)"
helpToggle: "<gold>/maintenance <on/off> <gray>(Aktiverer/deaktiverer vedligeholdelsestilstand)"
helpUpdate: "<gold>/maintenance update <gray>(Downloader den nyeste version af plugin'et på din server)"
helpWhitelist: "<gold>/maintenance whitelist <gray>(Viser alle hvidlistede spillere for vedligeholdelsestilstand)"
helpWhitelistAdd: "<gold>/maintenance add <name/uuid> <gray>(Tilføjer spilleren til vedligeholdelseshvidlisten, så de kan forbinde til serveren, selvom vedligeholdelsestilstand er aktiveret)"
helpWhitelistRemove: "<gold>/maintenance remove <name/uuid> <gray>(Sletter spilleren fra vedligeholdelseshvidlisten)"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
helpAbortSingleTimer: "<gold>/maintenance aborttimer [server] <gray>(Hvis timeren kører, vil den blive afbrudt)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server|global] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server|global] [mode] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server|global] [mode] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server|global] [mode] <gray>(Enables/disables maintenance mode globally or on a specific server with an optional display mode when enabling)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server] <gray>(Aktiverer/deaktiverer vedligeholdelsestilstand)"
helpStatus: "<gold>/maintenance status <gray>(Viser alle proxyservere, der har Vedligeholdelsestilstand aktiveret)"
#Discord webhook messages. These use Discord markdown, not MiniMessage.
#For timer webhooks, %TIMESTAMP% is a Unix timestamp for use in Discord timestamp tags, e.g. <t:%TIMESTAMP%:R>.
webhookMaintenanceActivated: "**Maintenance mode enabled.**"
webhookMaintenanceDeactivated: "**Maintenance mode disabled.**"
webhookStarttimerStarted: "Maintenance mode will be enabled <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookEndtimerStarted: "Maintenance mode will be disabled <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookJoinNotification: "Blocked join: `%PLAYER%` tried to join during maintenance."
webhookSingleMaintenanceActivated: "Maintenance mode enabled on `%SERVER%`."
webhookSingleMaintenanceDeactivated: "Maintenance mode disabled on `%SERVER%`."
webhookSingleStarttimerStarted: "Maintenance mode will be enabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookSingleEndtimerStarted: "Maintenance mode will be disabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
#Used for autoupdating the language file, do not change this value.
language-version: 5
language-version: 2
+13 -33
View File
@@ -1,16 +1,12 @@
#You can use https://webui.advntr.dev/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.papermc.io/adventure/minimessage/format/
#If you want to contribute changes to the default messages, you can do so via https://crowdin.com/project/maintenance
#Maintenance Plugin by kennytv
#You can use https://webui.adventure.kyori.net/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.adventure.kyori.net/minimessage/format.html
#Messages containing the placeholder "<prefix>" will have it replaced with the following string
prefix: "<dark_gray>[<yellow>Maintenance<dark_gray>] "
noPermission: "<red>Du hast nicht die erforderliche Berechtigung, um diesen Befehl auszuführen."
kickmessage: "<red>Der Server befindet sich momentan im Wartungsmodus!<br>Bitte versuche es später nochmal!"
maintenanceActivated: "<prefix><gold>Der Wartungsmodus ist jetzt aktiviert."
maintenanceDeactivated: "<prefix><gold>Der Wartungsmodus ist nun deaktiviert."
maintenanceStatusOn: "<prefix><gold>Wartungsmodus ist derzeit <green>aktiviert<gold>."
maintenanceStatusOff: "<prefix><gold>Wartungsmodus ist momentan <red>deaktiviert<gold>."
maintenanceStatusOnWithEndTimer: "<prefix><gold>Wartungsmodus ist momentan <green>aktiviert <grey>und wird deaktiviert in <gold>%TIME%."
maintenanceStatusOffWithStartTimer: "<prefix><gold>Wartungsmodus ist momentan <red>deaktiviert <grey>und wird aktiviert in <gold>%TIME%."
alreadyEnabled: "<prefix><red>Der Wartungsmodus ist bereits aktiviert!"
alreadyDisabled: "<prefix><red>Der Wartungsmodus ist bereits deaktiviert!"
endtimerBroadcast: "<prefix><gray>Der Wartungsmodus wird deaktiviert in: <gold>%TIME%<gray>."
@@ -30,10 +26,9 @@ joinNotification: "<prefix><yellow>%PLAYER% <red>hat versucht dem Server beizutr
motdList: "<prefix><gray>Liste deiner Motds, die während Maintenance angezeigt werden:"
motdListEmpty: "<prefix><red>Du hast keine Maintenance MOTDs gesetzt!"
reload: "<prefix><green>Die Config, die Liste der Spieler die während Maintenance beitreten können, die Sprachdateien und das Icon, das während der Maintenance angezeigt wird, wurden reloaded."
removedMotd: "<prefix><green>Die %INDEX%. Maintenance MOTD wurde entfernt."
removedMotd: "<prefix><green>Die %INDEX%. Wartungs-MOTD wurde entfernt."
removeMotdError: "<prefix><red>Du hast nur eine Maintenance MOTD eingestellt, daher kannst du auch keine entfernen!"
setMotd: "<prefix><green>Die %LINE%. Zeile der %INDEX%. Maintenance MOTD wurde geändert zu: %MOTD%"
setReason: "<prefix><green>Grund für die Wartung gesetzt auf: <yellow>%REASON%"
setMotdIndexError: "<prefix><red>Momentan gibt es %MOTDS% MOTDs, du musst also eine Zahl, die zwischen 1 und %NEWAMOUNT% liegt, wählen."
setMotdLineError: "<prefix><red>Das zweite Argument des Befehls muss die Zeilennummer sein (1 oder 2)!"
updateDownloading: "<prefix><red><bold>Das Update wird heruntergeladen..."
@@ -73,8 +68,6 @@ singleServerAlreadyDisabled: "<prefix><red>Der Wartungsmodus ist bereits aus auf
singleServerMaintenanceList: "<prefix><gray>Unterserver, die im Wartungsmodus sind:"
singleServerMaintenanceListEmpty: "<prefix><gray>Es befindet sich momentan kein Unterserver im Wartungsmodus."
singleServerMaintenanceListEntry: "<dark_grey>- <aqua>%SERVER%"
singleServerMaintenanceListEntryWithStartTimer: "<dark_grey>- <grey>%SERVER% <yellow>startet in <gold>%TIME%"
singleServerMaintenanceListEntryWithEndTimer: "<dark_grey>- <aqua>%SERVER% <yellow>endet in <gold>%TIME%"
second: "Sekunde"
seconds: "Sekunden"
minute: "Minute"
@@ -91,34 +84,21 @@ helpScheduleTimer: "<gold>/maintenance scheduletimer <Aktiviere in> <Wartungsdau
helpDebug: "<gold>/maintenance debug <gray>(Aktiviert Debug Nachrichten in der Konsole)"
helpDump: "<gold>/maintenance dump <gray>(Sammelt wichtige Informationen für Bugreports)"
helpHelp: "<gold>/maintenance help [Seite] <gray>(Zeigt diese wunderschöne Hilfe)"
helpMotd: "<gold>/maintenance motd [Timer] [Modus] <gray>(Zeigt die momentan gesetzten Maintenance Motds an. Mit dem 'timer' Argument werden die timerspezifischen Motds angezeigt)"
helpRemoveMotd: "<gold>/maintenance removemotd [Timer] [Modus] <Index> <gray>(Entfernt eine Maintenance Motd. Mit dem 'timer' Argument wird eine timerspezifischen Motd entfernt)"
helpSetMotd: "<gold>/maintenance setmotd [Timer] [Modus] <Index> <1/2> <Nachricht> <gray>(Setzte eine Motd für den Wartungsmodus. Mit dem 'timer' Argument wird eine timerspezifische Motd gesetzt)"
helpSetReason: "<gold>/maintenance setreason <reason/none> <gray>(Setzt oder löscht den %REASON% Platzhalter)"
helpMotd: "<gold>/maintenance motd [Timer] <gray>(Zeigt die momentan gesetzten Maintenance Motds an. Mit dem 'timer' Argument werden die timerspezifischen Motds angezeigt)"
helpRemoveMotd: "<gold>/maintenance removemotd [Timer] <Index> <gray>(Entfernt eine Maintenance Motd. Mit dem 'timer' Argument wird eine timerspezifischen Motd entfernt)"
helpSetMotd: "<gold>/maintenance setmotd [Timer] <Index> <1/2> <Nachricht> <gray>(Setzte eine Motd für den Wartungsmodus. Mit dem 'timer' Argument wird eine timerspezifische Motd gesetzt)"
helpReload: "<gold>/maintenance reload <gray>(Lädt Config, Language und Whitelist Dateien sowie das Maintenance Icon neu)"
helpGlobalStatus: "<gold>/maintenance status <gray>(Zeigt den aktuellen Wartungsstatus und alle laufenden Timer an)"
helpToggle: "<gold>/maintenance <on/off> [mode] <gray>(Aktiviert/deaktiviert den Wartungsmodus mit einem optionalen Anzeigemodus beim Aktivieren)"
helpToggle: "<gold>/maintenance <on/off> <gray>(Aktiviert/deaktiviert den Wartungsmodus)"
helpUpdate: "<gold>/maintenance update <gray>(Sucht nach neuen Updates für das Plugin und lädt diese auf den Server)"
helpWhitelist: "<gold>/maintenance whitelist <gray>(Zeigt alle gewhitelisteten Spieler für den Wartungsmodus an)"
helpWhitelistAdd: "<gold>/maintenance add <Name/UUID> <gray>(Whitelistet einen Spieler für den Wartungsmodus, sodass dieser während Wartungen den Server betreten kann)"
helpWhitelistRemove: "<gold>/maintenance remove <Name/UUID> <gray>(Entfernt einen Spieler aus der Wartungsmodus Whitelist)"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
helpAbortSingleTimer: "<gold>/maintenance aborttimer [Server] <gray>(Falls momentan ein Timer läuft, wird dieser abgebrochen)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server|global] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server|global] [mode] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server|global] [mode] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server|global] [mode] <gray>(Aktiviert/deaktiviert den Wartungsmodus global oder auf einem bestimmten Server mit optionalem Anzeigemodus beim Aktivieren)"
helpSingleEndtimer: "<gold>/maintenance endtimer [Server] <Deaktiviere in> <gray>(Sobald der Timer, bspw. 1h5m, abläuft wird der Wartungsmodus deaktiviert)"
helpSingleStarttimer: "<gold>/maintenance starttimer [Server] <Aktiviere in> <gray>(Sobald der Timer, bspw. 1h5m, abläuft wird der Wartungsmodus aktiviert)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [Server] <Starte in> <Wartungsdauer> <gray>(Sobald der Timer, bspw. 1h5m, abläuft wird der Wartungsmodus für die gegebene Länge aktiviert)"
helpSingleToggle: "<gold>/maintenance <on/off> [Server] <gray>(Aktiviert/deaktiviert den Wartungsmodus)"
helpStatus: "<gold>/maintenance status <gray>(Zeigt alle Server an, auf denen momentan der Wartungsmodus aktiviert ist)"
#Discord webhook messages. These use Discord markdown, not MiniMessage.
#For timer webhooks, %TIMESTAMP% is a Unix timestamp for use in Discord timestamp tags, e.g. <t:%TIMESTAMP%:R>.
webhookMaintenanceActivated: "**Wartungsmodus aktiviert.**"
webhookMaintenanceDeactivated: "**Wartungsmodus deaktiviert.**"
webhookStarttimerStarted: "Der Wartungsmodus wird aktiviert in <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookEndtimerStarted: "Der Wartungsmodus wird deaktiviert in <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookJoinNotification: "Beitritt gesperrt: `%PLAYER%` hat versucht, während den Wartungsarbeiten beizutreten."
webhookSingleMaintenanceActivated: "Der Wartungsmodus wurde aktiviert auf `%SERVER%`."
webhookSingleMaintenanceDeactivated: "Der Wartungsmodus wurde deaktiviert auf `%SERVER%`."
webhookSingleStarttimerStarted: "Der Wartungsmodus wird aktiviert auf `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookSingleEndtimerStarted: "Der Wartungsmodus wird deaktiviert auf `%SERVER%` <t:%TIMESTAMP%:R>(`%TIME%`)."
#Used for autoupdating the language file, do not change this value.
language-version: 4
language-version: 2
+12 -32
View File
@@ -1,16 +1,12 @@
#You can use https://webui.advntr.dev/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.papermc.io/adventure/minimessage/format/
#If you want to contribute changes to the default messages, you can do so via https://crowdin.com/project/maintenance
#Maintenance Plugin by kennytv
#You can use https://webui.adventure.kyori.net/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.adventure.kyori.net/minimessage/format.html
#Messages containing the placeholder "<prefix>" will have it replaced with the following string
prefix: "<dark_gray>[<yellow>Maintenance<dark_gray>] "
noPermission: "<red>You do not have the permission to execute that command."
kickmessage: "<red>The server is currently under maintenance!<br>Try again later!"
maintenanceActivated: "<prefix><gold>Maintenance mode is now activated."
maintenanceDeactivated: "<prefix><gold>Maintenance mode is now deactivated."
maintenanceStatusOn: "<prefix><gold>Maintenance mode is currently <green>enabled<gold>."
maintenanceStatusOff: "<prefix><gold>Maintenance mode is currently <red>disabled<gold>."
maintenanceStatusOnWithEndTimer: "<prefix><gold>Maintenance mode is currently <green>enabled <grey>and will be disabled in <gold>%TIME%."
maintenanceStatusOffWithStartTimer: "<prefix><gold>Maintenance mode is currently <red>disabled <grey>and will be enabled in <gold>%TIME%."
alreadyEnabled: "<prefix><red>Maintenance is already enabled!"
alreadyDisabled: "<prefix><red>Maintenance is already disabled!"
endtimerBroadcast: "<prefix><gray>Maintenance mode will be disabled in <gold>%TIME%<gray>."
@@ -33,7 +29,6 @@ reload: "<prefix><green>Reloaded config, whitelistedplayers, language file and t
removedMotd: "<prefix><green>Removed motd number %INDEX%."
removeMotdError: "<prefix><red>You only have one motd, so you cannot remove any!"
setMotd: "<prefix><green>Set line %LINE% of the %INDEX%. maintenance motd to %MOTD%"
setReason: "<prefix><green>Set maintenance reason to: <yellow>%REASON%"
setMotdIndexError: "<prefix><red>You currently have %MOTDS% motds, so you have to pick a number between 1 and %NEWAMOUNT%."
setMotdLineError: "<prefix><red>The second argument has to be the line number (1 or 2)!"
updateDownloading: "<prefix><red><bold>Downloading update..."
@@ -73,8 +68,6 @@ singleServerAlreadyDisabled: "<prefix><red>Maintenance is already disabled on se
singleServerMaintenanceList: "<prefix><gray>Proxied servers, that have maintenance enabled:"
singleServerMaintenanceListEmpty: "<prefix><gray>There are no proxied servers that are under maintenance."
singleServerMaintenanceListEntry: "<dark_grey>- <aqua>%SERVER%"
singleServerMaintenanceListEntryWithStartTimer: "<dark_grey>- <grey>%SERVER% <yellow>starting in <gold>%TIME%"
singleServerMaintenanceListEntryWithEndTimer: "<dark_grey>- <aqua>%SERVER% <yellow>ending in <gold>%TIME%"
second: "second"
seconds: "seconds"
minute: "minute"
@@ -91,34 +84,21 @@ helpScheduleTimer: "<gold>/maintenance scheduletimer <enable in> <maintenance du
helpDebug: "<gold>/maintenance debug <gray>(Enables some debug logging)"
helpDump: "<gold>/maintenance dump <gray>(Dumps some server information, used for bug reports)"
helpHelp: "<gold>/maintenance help [page] <gray>(Shows this beautiful help window)"
helpMotd: "<gold>/maintenance motd [timer] [mode] <gray>(Lists maintenance motds. If 'timer' is used, timer-specific motds are shown)"
helpRemoveMotd: "<gold>/maintenance removemotd [timer] [mode] <index> <gray>(Removes a maintenance motd in the selected mode)"
helpSetMotd: "<gold>/maintenance setmotd [timer] [mode] <index> <1/2> <message> <gray>(Sets a maintenance motd in the selected mode)"
helpSetReason: "<gold>/maintenance setreason <reason/none> <gray>(Sets or clears the %REASON% placeholder value)"
helpMotd: "<gold>/maintenance motd [timer] <gray>(Lists the currently set maintenance motds. If specifying 'timer', the timer motds are shown)"
helpRemoveMotd: "<gold>/maintenance removemotd [timer] <index> <gray>(Removes a maintenance motd. If using 'timer' as an argument, a timerspecific pingmessage will be removed)"
helpSetMotd: "<gold>/maintenance setmotd [timer] <index> <1/2> <message> <gray>(Sets a motd for maintenance mode. If using 'timer' as an argument, a timerspecific pingmessage will be set)"
helpReload: "<gold>/maintenance reload <gray>(Reloads the config file, whitelist file and the server-icon)"
helpGlobalStatus: "<gold>/maintenance status <gray>(Shows the current maintenance status and any running timers)"
helpToggle: "<gold>/maintenance <on/off> [mode] <gray>(Enables/disables maintenance mode with an optional display mode when enabling)"
helpToggle: "<gold>/maintenance <on/off> <gray>(Enables/disables maintenance mode)"
helpUpdate: "<gold>/maintenance update <gray>(Remotely downloads the newest version of the plugin onto your server)"
helpWhitelist: "<gold>/maintenance whitelist <gray>(Shows all whitelisted players for the maintenance mode)"
helpWhitelistAdd: "<gold>/maintenance add <name/uuid> <gray>(Adds the player to the maintenance whitelist, so they can join the server even though maintenance is enabled)"
helpWhitelistRemove: "<gold>/maintenance remove <name/uuid> <gray>(Removes the player from the maintenance whitelist)"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
helpAbortSingleTimer: "<gold>/maintenance aborttimer [server] <gray>(If running, the current timer will be aborted)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server|global] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server|global] [mode] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server|global] [mode] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server|global] [mode] <gray>(Enables/disables maintenance mode globally or on a specific server with an optional display mode when enabling)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server] <gray>(Enables/disables maintenance mode)"
helpStatus: "<gold>/maintenance status <gray>(Lists all proxied servers, that are currently under maintenance)"
#Discord webhook messages. These use Discord markdown, not MiniMessage.
#For timer webhooks, %TIMESTAMP% is a Unix timestamp for use in Discord timestamp tags, e.g. <t:%TIMESTAMP%:R>.
webhookMaintenanceActivated: "**Maintenance mode enabled.**"
webhookMaintenanceDeactivated: "**Maintenance mode disabled.**"
webhookStarttimerStarted: "Maintenance mode will be enabled <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookEndtimerStarted: "Maintenance mode will be disabled <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookJoinNotification: "Blocked join: `%PLAYER%` tried to join during maintenance."
webhookSingleMaintenanceActivated: "Maintenance mode enabled on `%SERVER%`."
webhookSingleMaintenanceDeactivated: "Maintenance mode disabled on `%SERVER%`."
webhookSingleStarttimerStarted: "Maintenance mode will be enabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookSingleEndtimerStarted: "Maintenance mode will be disabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
#Used for autoupdating the language file, do not change this value.
language-version: 5
language-version: 2
+27 -47
View File
@@ -1,44 +1,39 @@
#You can use https://webui.advntr.dev/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.papermc.io/adventure/minimessage/format/
#If you want to contribute changes to the default messages, you can do so via https://crowdin.com/project/maintenance
#Maintenance Plugin by kennytv
#You can use https://webui.adventure.kyori.net/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.adventure.kyori.net/minimessage/format.html
#Messages containing the placeholder "<prefix>" will have it replaced with the following string
prefix: "<dark_gray>[<yellow>Maintenance<dark_gray>] "
noPermission: "<prefix><dark_red>No tienes permiso para ejecutar este comando."
kickmessage: "<red>¡El servidor se encuentra en mantenimiento!<br>¡Intentalo de nuevo más tarde!"
maintenanceActivated: "<prefix><gold>Modo Mantenimiento activado."
maintenanceDeactivated: "<prefix><gold>Modo Mantenimiento desactivado."
maintenanceStatusOn: "<prefix><gold>El modo de mantenimiento está actualmente <green>activado<gold>."
maintenanceStatusOff: "<prefix><gold>El modo de mantenimiento está actualmente <red>desactivado<gold>."
maintenanceStatusOnWithEndTimer: "<prefix><gold>El modo de mantenimiento está actualmente <green>habilitado <grey>y se desactivará en <gold>%TIME%."
maintenanceStatusOffWithStartTimer: "<prefix><gold>El modo de mantenimiento está actualmente <red>desactivado <grey>y se activará en <gold>%TIME%."
alreadyEnabled: "<prefix><red>¡Modo mantenimiento ya está activado!"
alreadyDisabled: "<prefix><red>¡Modo mantenimiento ya está desactivado!"
maintenanceActivated: "<prefix><gold>Mantenimiento <gray>activado."
maintenanceDeactivated: "<prefix><gold>Modo mantenimiento desactivado."
alreadyEnabled: "<prefix><gray>¡Modo mantenimiento se encuentra habilitado!"
alreadyDisabled: "<prefix><gray>¡Modo mantenimiento se encuentra deshabilitado!"
endtimerBroadcast: "<prefix><gray>El modo mantenimiento se desactivará en <gold>%TIME%<gray>."
endtimerStarted: "<prefix><green>Temporizador iniciado: <gray>El modo mantenimiento se desactivará en <gold>%TIME%<gray>."
starttimerBroadcast: "<prefix><gray>El modo mantenimiento se activará en <gold>%TIME%<gray>."
starttimerStarted: "<prefix><green>Temporizador iniciado: <gray>El modo mantenimiento se activará en <gold>%TIME%<gray>."
scheduletimerBroadcast: "<prefix><gray>Temporizador iniciado: El modo mantenimiento se activará en <gold>%TIME% <gray>y durará <gold>%DURATION%<gray>."
endtimerStarted: "<prefix><gray>Temporizador iniciado: El modo mantenimiento se desactivará en <gold>%TIME%<gray>."
starttimerBroadcast: "<prefix><gray>El modo mantenimiento se habilitara en <gold>%TIME%<gray>."
starttimerStarted: "<prefix><gray>Temporizador iniciado: El modo mantenimiento se activará en <gold>%TIME%<gray>."
scheduletimerBroadcast: "<prefix><gray>Maintenance mode will be enabled in <gold>%TIME% <gray>and will last for <gold>%DURATION%<gray>."
scheduletimerStarted: "<prefix><gray>Temporizador iniciado: El modo mantenimiento se activará en <gold>%TIME% <gray>y durará <gold>%DURATION%<gray>."
timerAlreadyRunning: "<prefix><red>¡Ya hay un temporizador programado!"
timerNotRunning: "<prefix><red>Actualmente no hay ningún temporizador."
timerAlreadyRunning: "<prefix><red>Ya hay un temporizador programado!"
timerNotRunning: "<prefix><gray>Actualmente no hay temporizador."
timerCancelled: "<prefix><red>El Temporizador actual ha sido deshabilitado."
timerTooLong: "<prefix><red>¡La duración debe ser menor a 28 días!"
timerMotdDisabled: "<prefix><red>Debes configurar 'enable-timerspecific-messages' en la configuración a 'true', si quieres usar/editar motds por temporizador."
timerTooLong: "<prefix><gray>El numero debe ser menor a 40320 <dark_gray>(<gold>28 días<dark_gray>)"
timerMotdDisabled: "<prefix><red>Tienes que configurar <green>'enable-timerspecific-messages'<red> en la configuración en <green>'true'<red>, si quieres usar / editar motdspecers específicos."
motdTimer: "%HOURS%:%MINUTES%:%SECONDS%"
motdTimerNotRunning: "-"
joinNotification: "<prefix><yellow>%PLAYER% <red>intentó unirse al servidor."
joinNotification: "<prefix><red>%PLAYER% <gray>Intenta unirse al servidor."
motdList: "<prefix><gray>Lista de motds de mantenimiento:"
motdListEmpty: "<prefix><red>¡No tienes ningún motd(s) de mantenimiento establecido!"
motdListEmpty: "<prefix><red>¡No tiene ningún motd(s<dark_gray>) de mantenimiento establecido!"
reload: "<prefix><green>Configuracion recargada"
removedMotd: "<prefix><green>Numero de motd eliminado <gold>%INDEX%<green>."
removeMotdError: "<prefix>&Solo tienes un motd, por lo que no puedes eliminar ninguno!"
setMotd: "<prefix><green>Establecer linea <gold>%LINE%<green> sobre <gold>%INDEX%<green>. Para mantenimiento para %MOTD%"
setReason: "<prefix><green>Se estableció el motivo de mantenimiento a: <yellow>%REASON%"
setMotdIndexError: "<prefix><green>Actualmente tiene <gold>%MOTDS%<green> Motd(s<dark_gray>), por lo que debe elegir un número entre 1 y %NEWAMOUNT%."
setMotdLineError: "<prefix><gray>El segundo argumento tiene que ser el numero de línea.(1 ó 2<dark_gray>)!"
updateDownloading: "<prefix><green>Descargando actualización..."
updateFailed: "<prefix><red>Actualizacion fallida!"
updateFinished: "<prefix><green><bold>The update was successful! To prevent issues with tasks and to complete the update, you have to restart the server!"
updateFinished: "<prefix><green>La actualización fue exitosa!, debes reiniciar el servidor!"
whitelistedPlayers: "<prefix><gold>Jugadores en lista blanca:"
whitelistedPlayersFormat: "<gray>- <green>%NAME% <dark_gray>(<gray>%UUID%<dark_gray>)"
whitelistAdded: "<prefix><green>%PLAYER% <gray>Añadido a la lista de mantenimiento!"
@@ -73,8 +68,6 @@ singleServerAlreadyDisabled: "<prefix><gray>El modo mantenimiento se encuentra d
singleServerMaintenanceList: "<prefix><gray>Servidores proxy, que tienen habilitado el mantenimiento:"
singleServerMaintenanceListEmpty: "<prefix><gray>No hay servidores proxy que están en mantenimiento."
singleServerMaintenanceListEntry: "<dark_grey>- <aqua>%SERVER%"
singleServerMaintenanceListEntryWithStartTimer: "<dark_grey>- <yellow>Abriendo <grey>%SERVER% <yellow>en <gold>%TIME%"
singleServerMaintenanceListEntryWithEndTimer: "<dark_grey>- <yellow>Cerrando <aqua>%SERVER% <yellow>en <gold>%TIME%"
second: "Segundo"
seconds: "Segundos"
minute: "Minuto"
@@ -85,40 +78,27 @@ helpHeader: "<dark_gray>========[ <yellow>%NAME% <dark_gray>| <yellow>%PAGE%/%MA
helpPageNotFound: "<prefix><gray>No hay pagina con ese número."
helpNextPage: "<gray>Utilice <aqua>/maintenance help %PAGE% <gray>Para pasar a la siguiente ventana de ayuda."
helpAbortTimer: "<gold>/maintenance aborttimer <dark_gray>(<gray>Si se ejecuta, se abortará el temporizador actual<dark_gray>)"
helpEndtimer: "<gold>/maintenance endtimer <disable in> <gray> (Después del tiempo establecido, ej. 1h5m, el modo de mantenimiento será desactivado)"
helpStarttimer: "<gold>/maintenance starttimer <enable in> <gray>(Después del tiempo indicado, ej: 1h5m, El modo mantenimiento se habilita.)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <enable in> <maintenance duration> <gray>(Después del tiempo indicado, ej. 1h5m, el modo mantenimiento se habilitará.)"
helpEndtimer: "<gold>/maintenance endtimer <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpStarttimer: "<gold>/maintenance starttimer <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpDebug: "<gold>/maintenance debug <gray>(Activa algunos registros de depuración)"
helpDump: "<gold>/maintenance dump <dark_gray>(<gray>Descarga información del servidor, usada para informes de errores<dark_gray>)"
helpHelp: "<gold>/maintenance help [page] <dark_gray>(<gray>Muestra la pagina de ayuda<dark_gray>)"
helpMotd: "<gold>/maintenance motd [timer] <dark_gray>(<gray>Enumera los motivos de mantenimiento establecidos actualmente. Si se especifica el 'temporizador', se muestran los motivos del temporizador<dark_gray>)"
helpRemoveMotd: "<gold>/maintenance removemotd [timer] <index> <dark_gray>(<gray>Elimina un mantenimiento motd. Si se usa 'timer' como argumento, se eliminará un pingmessage de temporizador específico<dark_gray>)"
helpSetMotd: "<gold>/maintenance setmotd [timer] <index> <1/2> <message> <dark_gray>(<gray>Establece un motd para el modo de mantenimiento. Si usa 'timer' como argumento, se establecerá un mensaje de ping específico para el tiempo<dark_gray>)"
helpSetReason: "<gold>/maintenance setreason <reason/none> <gray>(Configura o reestablece el valor por defecto de %REASON%)"
helpReload: "<gold>/maintenance reload <dark_gray>(<gray>Vuelve a cargar el archivo de configuración, el archivo de la lista blanca y el ícono del servidor<dark_gray>)"
helpGlobalStatus: "<gold>/maintenance status <gray>(Muestra el estado de mantenimiento actual y cualquier temporizador activo)"
helpToggle: "<gold>/maintenance <on/off> [mode] <gray>(Habilita/desactiva el modo de mantenimiento con un modo de visualización opcional al habilitar)"
helpToggle: "<gold>/maintenance <on/off> <dark_gray>(<gray>Habilita / deshabilita el modo de mantenimiento<dark_gray>)"
helpUpdate: "<gold>/maintenance update <dark_gray>(<gray>Descarga de forma remota la versión más reciente del complemento en su servidor<dark_gray>)"
helpWhitelist: "<gold>/maintenance whitelist <dark_gray>(<gray>Muestra todos los jugadores en lista blanca para el modo de mantenimiento<dark_gray>)"
helpWhitelistAdd: "<gold>/maintenance add <name/uuid> <dark_gray>(<gray>Agrega al jugador a la lista blanca de mantenimiento, para que puedan unirse al servidor aunque el mantenimiento esté habilitado<dark_gray>)"
helpWhitelistRemove: "<gold>/maintenance remove <name/uuid> <dark_gray>(<gray>Quita al jugador de la lista blanca de mantenimiento<dark_gray>)"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
helpAbortSingleTimer: "<gold>/maintenance aborttimer [servidor] <dark_gray>(<gray>Si está funcionando, se abortará el temporizador actual<dark_gray>)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server|global] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server|global] [mode] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server|global] [mode] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [servidor|global] [mode] <gray> (Habilita/desactiva el modo de mantenimiento globalmente o en un servidor específico con un modo de visualización opcional al habilitar)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server] <dark_gray>(<gray>Habilita / deshabilita el modo de mantenimiento<dark_gray>)"
helpStatus: "<gold>/maintenance status <dark_gray>(<gray>Enumera todos los servidores proxy, que están actualmente en mantenimiento<dark_gray>)"
#Discord webhook messages. These use Discord markdown, not MiniMessage.
#For timer webhooks, %TIMESTAMP% is a Unix timestamp for use in Discord timestamp tags, e.g. <t:%TIMESTAMP%:R>.
webhookMaintenanceActivated: "**Modo de mantenimiento activado.**"
webhookMaintenanceDeactivated: "**Modo de mantenimiento desactivado.**"
webhookStarttimerStarted: "<prefix><gray>El modo mantenimiento se activará en <gold>%TIME%<gray>`)."
webhookEndtimerStarted: "<prefix><gray>El modo mantenimiento se desactivará en <gold>%TIME%<gray>`)."
webhookJoinNotification: "Bloqueado: `%PLAYER%` intentó unirse durante el mantenimiento."
webhookSingleMaintenanceActivated: "Modo de mantenimiento activado en %SERVER%`."
webhookSingleMaintenanceDeactivated: "Modo de mantenimiento desactivado en `%SERVER%`."
webhookSingleStarttimerStarted: "El modo de mantenimiento se activará en `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookSingleEndtimerStarted: "El modo de mantenimiento se desactivará en `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
#Used for autoupdating the language file, do not change this value.
language-version: 5
language-version: 2
+12 -32
View File
@@ -1,16 +1,12 @@
#You can use https://webui.advntr.dev/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.papermc.io/adventure/minimessage/format/
#If you want to contribute changes to the default messages, you can do so via https://crowdin.com/project/maintenance
#Maintenance Plugin by kennytv
#You can use https://webui.adventure.kyori.net/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.adventure.kyori.net/minimessage/format.html
#Messages containing the placeholder "<prefix>" will have it replaced with the following string
prefix: "<dark_gray>[<yellow>Maintenance<dark_gray>] "
noPermission: "<red>Vous n'avez pas la permission d'exécuter cette commande."
kickmessage: "<red>Le serveur est actuellement en maintenance !<br>Réessayez plus tard !"
maintenanceActivated: "<prefix><gold>Le mode maintenance est maintenant activé."
maintenanceDeactivated: "<prefix><gold>Le mode maintenance est maintenant désactivé."
maintenanceStatusOn: "<prefix><gold>Le mode maintenance est actuellement <green>activé<gold>."
maintenanceStatusOff: "<prefix><gold>Le mode maintenance est actuellement <red>désactivé<gold>."
maintenanceStatusOnWithEndTimer: "<prefix><gold>Le mode maintenance est actuellement <green>activé<grey> et sera désactivé dans <gold>%TIME%"
maintenanceStatusOffWithStartTimer: "<prefix><gold>Le mode maintenance est actuellement <red>désactivé<grey> et sera activé dans <gold>%TIME%"
alreadyEnabled: "<prefix><red>La maintenance est déjà activée !"
alreadyDisabled: "<prefix><red>La maintenance est déjà désactivée !"
endtimerBroadcast: "<prefix><gray>Le mode maintenance sera désactivé dans <gold>%TIME%<gray>."
@@ -33,7 +29,6 @@ reload: "<prefix><green>Fichier de configuration, liste blanche (whitelist) des
removedMotd: "<prefix><green>Numéro de motd supprimé %INDEX%."
removeMotdError: "<prefix><red>Vous n’avez qu’un motd, vous ne pouvez donc pas en supprimer !"
setMotd: "<prefix><green>Ligne %LINE% du motd %INDEX%. fixée à %MOTD%"
setReason: "<prefix><green>Raison de la maintenance configurée à : <yellow>%REASON%"
setMotdIndexError: "<prefix><red>Vous avez actuellement %MOTDS% motd(s), vous devez donc choisir un nombre compris entre 1 et %NEWAMOUNT%."
setMotdLineError: "<prefix><red>Le deuxième argument doit être le numéro de ligne (1 ou 2) !"
updateDownloading: "<prefix><red><bold>Téléchargement de la mise à jour..."
@@ -73,8 +68,6 @@ singleServerAlreadyDisabled: "<prefix><red>La maintenance est déjà désactivé
singleServerMaintenanceList: "<prefix><gray>Serveurs proxy ayant la maintenance activée :"
singleServerMaintenanceListEmpty: "<prefix><gray>Il n'y a pas de serveurs proxy en maintenance."
singleServerMaintenanceListEntry: "<dark_grey>- <aqua>%SERVER%"
singleServerMaintenanceListEntryWithStartTimer: "<dark_grey>- <grey>%SERVER% <yellow>comme dans <gold>%TIME%"
singleServerMaintenanceListEntryWithEndTimer: "<dark_grey>- <aqua>%SERVER% <yellow>termine dans <gold>%TIME%"
second: "seconde"
seconds: "secondes"
minute: "minute"
@@ -85,40 +78,27 @@ helpHeader: "<dark_gray>========[ <yellow>%NAME% <dark_gray>| <yellow>%PAGE%/%MA
helpPageNotFound: "<prefix><red>Il n'y a pas cette page !"
helpNextPage: "<gray>Utilisez <aqua>/maintenance help %PAGE% <gray>pour accéder à la fenêtre d’aide suivante."
helpAbortTimer: "<gold>/maintenance aborttimer <gray>(Si en cours d'exécution, le minuteur actuel sera abandonné)"
helpEndtimer: "<gold>/maintenance endtimer <désactiver dans> <gray>(Après le temps imparti, ex. 1h5m, le mode maintenance sera désactiver)"
helpStarttimer: "<gold>/maintenance starttimer <activer dans> <gray>(Après le temps imparti, ex. 1h5m, le mode maintenance sera activé)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <activer dans> <durée de maintenance> <gray>(Après le temps imparti, ex. 1h5m, le mode maintenance sera activé)"
helpEndtimer: "<gold>/maintenance endtimer <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpStarttimer: "<gold>/maintenance starttimer <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpDebug: "<gold>/maintenance debug <gray>(Active certains enregistrements de débogage)"
helpDump: "<gold>/maintenance dump <gray>(Enregistre certaines informations sur le serveur, utilisées pour les rapports de bug)"
helpHelp: "<gold>/maintenance help [page] <gray>(Montre cette belle fenêtre d'aide)"
helpMotd: "<gold>/maintenance motd [timer] <gray>(Répertorie les paramètres de maintenance actuellement définis. Si vous spécifiez 'timer', les mots de la minuterie seront affichés)"
helpRemoveMotd: "<gold>/maintenance removemotd [timer] <index> <gray>(Supprime un motd de maintenance. Si vous utilisez 'timer' comme argument, un message ping spécifique au temporisateur sera supprimé)"
helpSetMotd: "<gold>/maintenance setmotd [timer] <index> <1/2> <message> <gray>(Définit un motd pour le mode maintenance. Si vous utilisez 'timer' comme argument, un message ping spécifique à un temporisateur sera défini)"
helpSetReason: "<gold>/maintenance setreason <reason/none> <gray>(définit ou efface la valeur du placeholder %REASON%)"
helpReload: "<gold>/maintenance reload <gray>(Recharge le fichier de configuration, la liste blanche, le fichier de langue et l'icône du serveur)"
helpGlobalStatus: "<gold>/maintenance status <gray>(Affiche les états de maintenance et les minuteurs actifs)"
helpToggle: "<gold>/maintenance <on/off> [mode] <gray>(Active/désactive le mode maintenance)"
helpToggle: "<gold>/maintenance <on/off> <gray>(Active/désactive le mode maintenance)"
helpUpdate: "<gold>/maintenance update <gray>(Télécharge la dernière version du plugin sur votre serveur)"
helpWhitelist: "<gold>/maintenance whitelist <gray>(Affiche les joueurs de la liste blanche pour le mode maintenance)"
helpWhitelistAdd: "<gold>/maintenance add <name/uuid> <gray>(Ajoute un joueur à la liste blanche de maintenance afin qu'il puisse rejoindre le serveur même si la maintenance est activée)"
helpWhitelistRemove: "<gold>/maintenance remove <name/uuid> <gray>(Supprime un joueur de la liste blanche de maintenance)"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
helpAbortSingleTimer: "<gold>/maintenance aborttimer [server] <gray>(Si en cours d'exécution, le minuteur actuel sera abandonné)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server|global] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server|global] [mode] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server|global] [mode] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server|global] [mode] <gray>(Active/désactive le mode maintenance globalement, ou sur un serveur spécifique avec un mode d'affichage facultatif lors de l'activation)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server] <gray>(Active/désactive le mode maintenance)"
helpStatus: "<gold>/maintenance status <gray>(Répertorie tous les serveurs mandatés actuellement en maintenance)"
#Discord webhook messages. These use Discord markdown, not MiniMessage.
#For timer webhooks, %TIMESTAMP% is a Unix timestamp for use in Discord timestamp tags, e.g. <t:%TIMESTAMP%:R>.
webhookMaintenanceActivated: "\n\n**Mode maintenance activé.**"
webhookMaintenanceDeactivated: "\n\n**Mode maintenance désactivé.**"
webhookStarttimerStarted: "Le mode maintenance sera activé dans <t:%TIMESTAMP%:R>(`%TIME%`)."
webhookEndtimerStarted: "Le mode maintenance sera désactivé dans <t:%TIMESTAMP%:R>(`%TIME%`)."
webhookJoinNotification: "Connexion bloquée : `%PLAYER%` a cherché à rejoindre durant une maintenance."
webhookSingleMaintenanceActivated: "Mode maintenance activé sur `%SERVER%`."
webhookSingleMaintenanceDeactivated: "Mode maintenance désactivé sur `%SERVER%`."
webhookSingleStarttimerStarted: "Le mode maintenance sera activé sur `%SERVER%` <t:%TIMESTAMP%:R>(`%TIME%`)."
webhookSingleEndtimerStarted: "Le mode maintenance sera désactivé sur `%SERVER%` <t:%TIMESTAMP%:R>(`%TIME%`)."
#Used for autoupdating the language file, do not change this value.
language-version: 5
language-version: 2
+12 -32
View File
@@ -1,16 +1,12 @@
#You can use https://webui.advntr.dev/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.papermc.io/adventure/minimessage/format/
#If you want to contribute changes to the default messages, you can do so via https://crowdin.com/project/maintenance
#Maintenance Plugin by kennytv
#You can use https://webui.adventure.kyori.net/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.adventure.kyori.net/minimessage/format.html
#Messages containing the placeholder "<prefix>" will have it replaced with the following string
prefix: "<dark_gray>[<yellow>Maintenance<dark_gray>] "
noPermission: "<red>Nincs engedélyed a parancs használatához."
kickmessage: "<red>A szerver karbantartás alatt áll!<br>Próbáld újra később!"
maintenanceActivated: "<prefix><gold>Karbantartás elindítva."
maintenanceDeactivated: "<prefix><gold>Karbantartás befejezve."
maintenanceStatusOn: "<prefix><gold>Maintenance mode is currently <green>enabled<gold>."
maintenanceStatusOff: "<prefix><gold>Maintenance mode is currently <red>disabled<gold>."
maintenanceStatusOnWithEndTimer: "<prefix><gold>Maintenance mode is currently <green>enabled <grey>and will be disabled in <gold>%TIME%."
maintenanceStatusOffWithStartTimer: "<prefix><gold>Maintenance mode is currently <red>disabled <grey>and will be enabled in <gold>%TIME%."
alreadyEnabled: "<prefix><red>Már engedélyezve van!"
alreadyDisabled: "<prefix><red>Már le van tiltva!"
endtimerBroadcast: "<prefix><gray>Felléphetsz <gold>%TIME%<gray> múlva."
@@ -33,7 +29,6 @@ reload: "<prefix><green>Újratöltve."
removedMotd: "<prefix><green>Motd szám törölve: %INDEX%."
removeMotdError: "<prefix><red>Csak egy motd van,nem törölheted!"
setMotd: "<prefix><green>Sor %LINE% beállítva %INDEX%-re. motd %MOTD%-ra"
setReason: "<prefix><green>Set maintenance reason to: <yellow>%REASON%"
setMotdIndexError: "<prefix><red>Csak %MOTDS%-d van, úgyhogy válassz egy számot 1 és %NEWAMOUNT% között."
setMotdLineError: "<prefix><red>Ennek egy sornak kell lennie (1 vagy 2)!"
updateDownloading: "<prefix><red><bold>Frissítés letöltése..."
@@ -73,8 +68,6 @@ singleServerAlreadyDisabled: "<prefix><red>A karbantartás már le van tiltva a(
singleServerMaintenanceList: "<prefix><gray>Proxy szerverek,karbantartási móddal engedélyezve:"
singleServerMaintenanceListEmpty: "<prefix><gray>Nincsenek proxy szerverek karbantartás alatt."
singleServerMaintenanceListEntry: "<dark_grey>- <aqua>%SERVER%"
singleServerMaintenanceListEntryWithStartTimer: "<dark_grey>- <grey>%SERVER% <yellow>starting in <gold>%TIME%"
singleServerMaintenanceListEntryWithEndTimer: "<dark_grey>- <aqua>%SERVER% <yellow>ending in <gold>%TIME%"
second: "másodperc"
seconds: "másodperc"
minute: "perc"
@@ -85,40 +78,27 @@ helpHeader: "<dark_gray>========[ <yellow>%NAME% <dark_gray>| <yellow>%PAGE%/%MA
helpPageNotFound: "<prefix><red>Nincs ilyen oldal!"
helpNextPage: "<gray>Használd a <aqua>/maintenance help %PAGE% <gray>parancsot,hogy lapozz."
helpAbortTimer: "<gold>/maintenance aborttimer <gray>(Az időzítő,ha fut nem lesz figelembe vévve)"
helpEndtimer: "<gold>/maintenance endtimer <disable in> <gray>(Azután a megadott időben pl. 1h5m, a karbantartásnak vége lesz)"
helpStarttimer: "<gold>/maintenance starttimer <enable in> <gray>(Azután a megadott időben pl. 1h5m, karbantartás elkezdödik)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <enable in> <maintenance duration> <gray>(Azután a megadott időben pl. 1h5m, a karbantartás elkezdödik)"
helpEndtimer: "<gold>/maintenance endtimer <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpStarttimer: "<gold>/maintenance starttimer <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpDebug: "<gold>/maintenance debug <gray>(Hibakeresés bekapcsolása)"
helpDump: "<gold>/maintenance dump <gray>(A hibajelentési előzményeket törli)"
helpHelp: "<gold>/maintenance help [page] <gray>(Megjelenítí a segítség ablakot)"
helpMotd: "<gold>/maintenance motd [timer] <gray>(Megjeleníti a motd-ket)"
helpRemoveMotd: "<gold>/maintenance removemotd [timer] <index> <gray>(Törli a megadott motd-t)"
helpSetMotd: "<gold>/maintenance setmotd [timer] <index> <1/2> <message> <gray>(Beállít egy motd-t)"
helpSetReason: "<gold>/maintenance setreason <reason/none> <gray>(Sets or clears the %REASON% placeholder value)"
helpReload: "<gold>/maintenance reload <gray>(Újratölti a plugint)"
helpGlobalStatus: "<gold>/maintenance status <gray>(Shows the current maintenance status and any running timers)"
helpToggle: "<gold>/maintenance <on/off> [mode] <gray>(Enables/disables maintenance mode with an optional display mode when enabling)"
helpToggle: "<gold>/maintenance <on/off> <gray>(Karbantartás mód ki-be kapcsolása)"
helpUpdate: "<gold>/maintenance update <gray>(Frissíti a plugin verziót)"
helpWhitelist: "<gold>/maintenance whitelist <gray>(Megmutatja a karbantartás fehérlistázottak listáját)"
helpWhitelistAdd: "<gold>/maintenance add <name/uuid> <gray>(Hozzáadja a játékost a karbantartás fehérlistához)"
helpWhitelistRemove: "<gold>/maintenance remove <name/uuid> <gray>(Kitörli a játékost a karbantartás fehérlistáról)"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
helpAbortSingleTimer: "<gold>/maintenance aborttimer [server] <gray>(Ha van karbantartás,akkor figyelmen kívül veszi az időzítőt)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server|global] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server|global] [mode] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server|global] [mode] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server|global] [mode] <gray>(Enables/disables maintenance mode globally or on a specific server with an optional display mode when enabling)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server] <gray>(Ki-be kapcsolja a karbantartás módot)"
helpStatus: "<gold>/maintenance status <gray>(Kiírja az összes proxy szervert, ami karbantartás alatt van)"
#Discord webhook messages. These use Discord markdown, not MiniMessage.
#For timer webhooks, %TIMESTAMP% is a Unix timestamp for use in Discord timestamp tags, e.g. <t:%TIMESTAMP%:R>.
webhookMaintenanceActivated: "**Maintenance mode enabled.**"
webhookMaintenanceDeactivated: "**Maintenance mode disabled.**"
webhookStarttimerStarted: "Maintenance mode will be enabled <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookEndtimerStarted: "Maintenance mode will be disabled <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookJoinNotification: "Blocked join: `%PLAYER%` tried to join during maintenance."
webhookSingleMaintenanceActivated: "Maintenance mode enabled on `%SERVER%`."
webhookSingleMaintenanceDeactivated: "Maintenance mode disabled on `%SERVER%`."
webhookSingleStarttimerStarted: "Maintenance mode will be enabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookSingleEndtimerStarted: "Maintenance mode will be disabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
#Used for autoupdating the language file, do not change this value.
language-version: 5
language-version: 2
+34 -54
View File
@@ -1,23 +1,19 @@
#You can use https://webui.advntr.dev/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.papermc.io/adventure/minimessage/format/
#If you want to contribute changes to the default messages, you can do so via https://crowdin.com/project/maintenance
#Maintenance Plugin by kennytv
#You can use https://webui.adventure.kyori.net/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.adventure.kyori.net/minimessage/format.html
#Messages containing the placeholder "<prefix>" will have it replaced with the following string
prefix: "<dark_gray>[<yellow>Maintenance<dark_gray>] "
noPermission: "<red>Non hai il permesso per eseguire questo comando."
noPermission: "<red>Non hai i permessi necessari per eseguire quel comando."
kickmessage: "<red>Il server è momentaneamente in manutenzione!<br>Riprova più tardi!"
maintenanceActivated: "<prefix><gold>Modalità manutenzione ora attivata."
maintenanceDeactivated: "<prefix><gold>Modalità manutenzione ora disattivata."
maintenanceStatusOn: "<prefix><gold>Maintenance mode is currently <green>enabled<gold>."
maintenanceStatusOff: "<prefix><gold>Maintenance mode is currently <red>disabled<gold>."
maintenanceStatusOnWithEndTimer: "<prefix><gold>Maintenance mode is currently <green>enabled <grey>and will be disabled in <gold>%TIME%."
maintenanceStatusOffWithStartTimer: "<prefix><gold>Maintenance mode is currently <red>disabled <grey>and will be enabled in <gold>%TIME%."
alreadyEnabled: "<prefix><red>La modalità manutenzione è già attiva!"
alreadyDisabled: "<prefix><red>La modalità manutenzione è già disattivata!"
alreadyDisabled: "<prefix><red>La modalità mantenzione è già disattivata!"
endtimerBroadcast: "<prefix><gray>La modalità manutenzione verrà disattivata tra <gold>%TIME%<gray>."
endtimerStarted: "<prefix><green>Timer avviato: <gray>La modalità manutenzione verrà disattivata tra <gold>%TIME%<gray>."
starttimerBroadcast: "<prefix><gray>La modalità manutenzione verrà attivata tra <gold>%TIME%<gray>."
starttimerStarted: "<prefix><green>Timer avviato: <gray>La modalità manutenzione verrà attivata tra <gold>%TIME%<gray>."
scheduletimerBroadcast: "<prefix><gray>La modalità manutenzione sarà abilitata tra <gold>%TIME% <gray>e durerà per <gold>%DURATION%<gray>."
scheduletimerBroadcast: "<prefix><gray>Maintenance mode will be enabled in <gold>%TIME% <gray>and will last for <gold>%DURATION%<gray>."
scheduletimerStarted: "<prefix><green>Timer avviato: la modalità di manutenzione <gray>sarà abilitata in <gold>%TIME% <gray>e durerà per <gold>%DURATION%<gray>."
timerAlreadyRunning: "<prefix><red>C'è già un timer programmato!"
timerNotRunning: "<prefix><red>Non c'è nessun timer attivo al momento."
@@ -27,19 +23,18 @@ timerMotdDisabled: "<prefix><red>Devi impostare 'enable-timerspecific-messages'
motdTimer: "%HOURS%:%MINUTES%:%SECONDS%"
motdTimerNotRunning: "-"
joinNotification: "<prefix><yellow>%PLAYER% <red>ha tentato di accedere al server."
motdList: "<prefix><gray>Lista delle tue MOTD di manutenzione:"
motdListEmpty: "<prefix><red>Non hai ancora nessuna MOTD di manutenzione!"
reload: "<prefix><green>Ricaricata config, whitelistedplayers, file dei linguaggi e l'icona di manutenzione."
removedMotd: "<prefix><green>Rimossa MOTD numero %INDEX%."
removeMotdError: "<prefix><red>Hai soltanto una MOTD, quindi non puoi rimuoverla!"
setMotd: "<prefix><green>Impostata MOTD di manutenzione numero %INDEX%, linea %LINE% a: %MOTD%"
setReason: "<prefix><green>Set maintenance reason to: <yellow>%REASON%"
setMotdIndexError: "<prefix><red>Hai attualmente %MOTDS% MOTD, devi scegliere un numero tra 1 e %NEWAMOUNT%."
motdList: "<prefix><gray>Lista delle tue motds di manutenzione:"
motdListEmpty: "<prefix><red>Non hai ancora nessuna motds di manutenzione!"
reload: "<prefix><green>Ricaricata config, whitelistedplayers, file dei linguaggi e la icona di manutenzione."
removedMotd: "<prefix><green>Rimossa motd numero %INDEX%."
removeMotdError: "<prefix><red>Hai soltanto una motd, quindi non puoi rimuoverla!"
setMotd: "<prefix><green>Impostata linea %LINE% in %INDEX%. motd manutenzione a %MOTD%"
setMotdIndexError: "<prefix><red>Hai attualmente %MOTDS% motds, quindi devi scegliere un numero fra 1 e %NEWAMOUNT%."
setMotdLineError: "<prefix><red>Il secondo argomento deve corrispondere alla linea (1 o 2)!"
updateDownloading: "<prefix><red><bold> Sto scaricando l'aggiornamento..."
updateDownloading: "<prefix><red><bold>Scaricando aggiornamento..."
updateFailed: "<prefix><dark_red><bold>Aggiornamento non riuscito!"
updateFinished: "<prefix><green><bold>L'aggiornamento è completato! Per prevenire problemi e completare l'aggiornamento dovresti riavviare il server!"
whitelistedPlayers: "<prefix><gold>Giocatori in whitelist per la manutenzione:"
whitelistedPlayers: "<prefix><gold>Player in whitelist per la manutenzione:"
whitelistedPlayersFormat: "<dark_gray>- <yellow>%NAME% <dark_gray>(<gray>%UUID%<dark_gray>)"
whitelistAdded: "<prefix><green>Aggiunto <aqua>%PLAYER% <green>alla whitelist della manutenzione!"
whitelistAlreadyAdded: "<prefix><aqua>%PLAYER% <red>è già nella whitelist della manutenzione!"
@@ -47,34 +42,32 @@ whitelistRemoved: "<prefix><green>Rimosso <aqua>%PLAYER% <green>dalla lista dell
whitelistNotFound: "<prefix><red>Questo giocatore non fa parte della whitelist della manutenzione!"
whitelistEmpty: "<prefix><red>La whitelist di manutenzione è vuota! Usa <yellow>/maintenance add <player/uuid> <red>per aggiungere qualcuno!"
playerNotFound: "<prefix><red>Nessun giocatore con questo username è mai entrato nel server."
playerNotFoundUuid: "<prefix><red>Nessun giocatore con quell'uuid è stato trovato."
playerNotFoundUuid: "<prefix><red>Nessun player con quell'uuid è stato trovato."
playerNotOnline: "<prefix><red>Non c'è nessun giocatore online con quell'username."
offlinePlayerFetchError: "<prefix><red>C'è stato un errore cercando il giocatore offline. Riprova più tardi."
offlinePlayerFetchError: "<prefix><red>C'è stato un errore cercando il player offline. Riprova più tardi."
invalidUuid: "<prefix><red>L'uuid presenta un formato invalido!"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
sentToWaitingServer: "<prefix><red>Sei stato inviato su un server d'attesa!"
forceWaitingServer: "<prefix><red>Non puoi abbandonare il server d'attesa durante una manutenzione!"
serverNotFound: "<prefix><red>Nessun server con questo nome è registrato sul proxy server!"
serverNotFound: "<prefix><red>Nessun server con questo nome è registrato sulla proxy!"
singleTimerAlreadyRunning: "<prefix><red>È già presente un timer pianificato per quel server!"
singleTimerCancelled: "<prefix><red>Il timer attuale per il server <yellow>%SERVER% <red>è stato rimosso."
singleTimerNotRunning: "<prefix><red>Non c'è nessun timer correntemente attivo per quel server."
singleEndtimerBroadcast: "<prefix><gray>La modalità manutenzione per il server %SERVER% verrà disabilitata tra <gold>%TIME%<gray>."
singleEndtimerStarted: "<prefix><green>Timer avviato: <gray>La modalità manutenzione per il server %SERVER% verrà disattivata tra <gold>%TIME%<gray>."
singleStarttimerBroadcast: "<prefix><gray>La modalità manutenzione per il server %SERVER% verrà attivata tra <gold>%TIME%<gray>."
singleStarttimerBroadcast: "<prefix><gray>La modalità manutenzione per il server %SERVER% verrà disabilitata tra <gold>%TIME%<gray>."
singleStarttimerStarted: "<prefix><green>Timer avviato: <gray>La modalità manutenzione per il server %SERVER% verrà attivata tra <gold>%TIME%<gray>."
singleScheduletimerBroadcast: "<prefix><gray>La modalità manutenzione sul server %SERVER% sarà abilitata tra <gold>%TIME% <gray>e durerà per <gold>%DURATION%<gray>."
singleScheduletimerBroadcast: "<prefix><gray>Maintenance mode on server %SERVER% will be enabled in <gold>%TIME% <gray>and will last for <gold>%DURATION%<gray>."
singleScheduletimerStarted: "<prefix><green>Timer avviato: <gray>Modalità di manutenzione sul server %SERVER% sarà attivato in <gold>%TIME% <gray>e durerà per <gold>%DURATION%<gray>."
singleMaintenanceKick: "<prefix><red>Il server %SERVER% è in manutenzione al momento! Ritenta più tardi!"
singleMaintenanceKickComplete: "<red>Il server %SERVER% è in manutenzione!<br>Prova a rientrare per accedere a un altro server!"
singleMaintenanceKickComplete: "<red>Il server %SERVER% è in manutenzione!<br>Prova a rientrare per accedere ad un'altro server!"
singleMaintenanceActivated: "<prefix><gold>La modalità manutenzione è ora attiva sul server <yellow>%SERVER%<gold>."
singleMaintenanceDeactivated: "<prefix><gold>La modalità manutenzione è ora disattivata sul server <yellow>%SERVER%<gold>."
singleServerAlreadyEnabled: "<prefix><red>La modalità manutenzione è già attiva sul server <yellow>%SERVER%<red>!"
singleServerAlreadyDisabled: "<prefix><red>La modalità manutenzione è già disattivata sul server <yellow>%SERVER%<red>!"
singleServerMaintenanceList: "<prefix><gray>Server collegati con manutenzione attiva:"
singleServerMaintenanceListEmpty: "<prefix><gray>Nessun server sotto proxy server ha la modalità manutenzione attiva."
singleServerMaintenanceList: "<prefix><gray>Servers sotto proxy che hanno la modalità manutenzione attiva:"
singleServerMaintenanceListEmpty: "<prefix><gray>Nessun server sotto proxy ha la modalità manutenzione attiva."
singleServerMaintenanceListEntry: "<dark_grey>- <aqua>%SERVER%"
singleServerMaintenanceListEntryWithStartTimer: "<dark_grey>- <grey>%SERVER% <yellow>starting in <gold>%TIME%"
singleServerMaintenanceListEntryWithEndTimer: "<dark_grey>- <aqua>%SERVER% <yellow>ending in <gold>%TIME%"
second: "secondo"
seconds: "secondi"
minute: "minuto"
@@ -85,40 +78,27 @@ helpHeader: "<dark_gray>========[ <yellow>%NAME% <dark_gray>| <yellow>%PAGE%/%MA
helpPageNotFound: "<prefix><red>Non c'è alcuna pagina con quel numero!"
helpNextPage: "<gray>Usa <aqua>/maintenance help %PAGE% <gray>per andare alla prossima pagina d'aiuto."
helpAbortTimer: "<gold>/maintenance aborttimer <gray>(Se attivo, l'attuale timer verrà fermato)"
helpEndtimer: "<gold>/maintenance endtimer <tempo di disattivazione> <gray>(Dopo il tempo specificato, es. 1h5m, la modalità manutenzione verrà disattivata)"
helpStarttimer: "<gold>/maintenance starttimer <tempo di attivazione> <gray>(Dopo il tempo specificato, es. 1h5m, la modalità manutenzione verrà attivata)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <tempo di attivazione> <durata manutenzione> <gray>(Dopo il tempo specificato, es. 1h5m, la modalità manutenzione verrà attivata e durerà per il tempo indicato)"
helpDebug: "<gold>/maintenance debug <gray>(Attiva la registrazione di debug)"
helpEndtimer: "<gold>/maintenance endtimer <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpStarttimer: "<gold>/maintenance starttimer <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpDebug: "<gold>/maintenance debug <gray>(Enables some debug logging)"
helpDump: "<gold>/maintenance dump <gray>(Copia alcune informazioni dal server, usato per segnalare problemi)"
helpHelp: "<gold>/maintenance help [page] <gray>(Mostra questa fantastica pagina d'aiuto)"
helpMotd: "<gold>/maintenance motd [timer] <gray>(Elenca le attuali motds di manutenzione impostate. Se specifichi 'timer', verranno mostrati i motds dei timer)"
helpRemoveMotd: "<gold>/maintenance removemotd [timer] <index> <gray>(Rimuove una motd di manutenzione. Se specifichi 'timer' come argomento, un messaggio specifico al timer verrà rimosso)"
helpSetMotd: "<gold>/maintenance setmotd [timer] <index> <1/2> <message> <gray>(Imposta il motd per la manutenzione. Se specifichi 'timer' come argomento, un messaggio specifico al timer verrà impostato)"
helpSetReason: "<gold>/maintenance setreason <reason/none> <gray>(Sets or clears the %REASON% placeholder value)"
helpReload: "<gold>/maintenance reload <gray>(Ricarica il file di configurazione, whitelist server e icona)"
helpGlobalStatus: "<gold>/maintenance status <gray>(Shows the current maintenance status and any running timers)"
helpToggle: "<gold>/maintenance <on/off> [mode] <gray>(Enables/disables maintenance mode with an optional display mode when enabling)"
helpToggle: "<gold>/maintenance <on/off> <gray>(Abilita/Disabilita modalità manutenzione)"
helpUpdate: "<gold>/maintenance update <gray>(Scarica dall'esterno l'ultima versione del plugin nel server)"
helpWhitelist: "<gold>/maintenance whitelist <gray>(Elenca tutti i giocatori nella whitelist per la manutenzione)"
helpWhitelistAdd: "<gold>/maintenance add <name/uuid> <gray>(Aggiunge il giocatore alla whitelist di manutenzione, così possono entrare in un server durante la manutenzione)"
helpWhitelistRemove: "<gold>/maintenance remove <name/uuid> <gray>(Rimuovi il giocatore dalla whitelist della manutenzione)"
helpWhitelistRemove: "<gold>/maintenance remove <name/uuid> <gray>(Rimuovi il player dalla whitelist della manutenzione)"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
helpAbortSingleTimer: "<gold>/maintenance aborttimer [server] <gray>(Se attivo, il timer attuale verrà fermato)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server|global] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server|global] [mode] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server|global] [mode] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server|global] [mode] <gray>(Enables/disables maintenance mode globally or on a specific server with an optional display mode when enabling)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server] <gray>(Abilita/disabilita la modalità di manutenzione)"
helpStatus: "<gold>/maintenance status <gray>(Elenca tutti i server sotto proxy che hanno la modalità manutenzione attiva)"
#Discord webhook messages. These use Discord markdown, not MiniMessage.
#For timer webhooks, %TIMESTAMP% is a Unix timestamp for use in Discord timestamp tags, e.g. <t:%TIMESTAMP%:R>.
webhookMaintenanceActivated: "**Maintenance mode enabled.**"
webhookMaintenanceDeactivated: "**Maintenance mode disabled.**"
webhookStarttimerStarted: "Maintenance mode will be enabled <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookEndtimerStarted: "Maintenance mode will be disabled <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookJoinNotification: "Blocked join: `%PLAYER%` tried to join during maintenance."
webhookSingleMaintenanceActivated: "Maintenance mode enabled on `%SERVER%`."
webhookSingleMaintenanceDeactivated: "Maintenance mode disabled on `%SERVER%`."
webhookSingleStarttimerStarted: "Maintenance mode will be enabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookSingleEndtimerStarted: "Maintenance mode will be disabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
#Used for autoupdating the language file, do not change this value.
language-version: 5
language-version: 2
+12 -32
View File
@@ -1,16 +1,12 @@
#You can use https://webui.advntr.dev/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.papermc.io/adventure/minimessage/format/
#If you want to contribute changes to the default messages, you can do so via https://crowdin.com/project/maintenance
#Maintenance Plugin by kennytv
#You can use https://webui.adventure.kyori.net/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.adventure.kyori.net/minimessage/format.html
#Messages containing the placeholder "<prefix>" will have it replaced with the following string
prefix: "<dark_gray>[<yellow>Maintenance<dark_gray>] "
noPermission: "<red>このコマンドを実行する権限がありません。"
kickmessage: "<red>メンテナンス中です。<br>しばらくたってから、もう一度お試しください"
maintenanceActivated: "<prefix><green>メンテナンスを有効にしました。"
maintenanceDeactivated: "<prefix><yellow>メンテナンスを解除しました。"
maintenanceStatusOn: "<prefix><gold>Maintenance mode is currently <green>enabled<gold>."
maintenanceStatusOff: "<prefix><gold>Maintenance mode is currently <red>disabled<gold>."
maintenanceStatusOnWithEndTimer: "<prefix><gold>Maintenance mode is currently <green>enabled <grey>and will be disabled in <gold>%TIME%."
maintenanceStatusOffWithStartTimer: "<prefix><gold>Maintenance mode is currently <red>disabled <grey>and will be enabled in <gold>%TIME%."
alreadyEnabled: "<prefix><red>メンテナンスは既に有効です。"
alreadyDisabled: "<prefix><red>メンテナンスは既に解除されています。"
endtimerBroadcast: "<prefix><gray>メンテナンスモードは、<gold>%TIME%<gray>で無効になります。"
@@ -33,7 +29,6 @@ reload: "<prefix><green>再読み込みが完了しました。"
removedMotd: "<prefix><green>motd番号%INDEX%を削除しました。"
removeMotdError: "<prefix><red>motdは1つしかないので、削除することはできません。"
setMotd: "<prefix><greenINDEX%.の行 %LINE% を %MOTD% に設定します。"
setReason: "<prefix><green>Set maintenance reason to: <yellow>%REASON%"
setMotdIndexError: "<prefix><red>現在、%MOTDS%のMOTDを持っているので、1から%NEWAMOUNT%の間の数字を選ぶ必要があります。"
setMotdLineError: "<prefix><red>第2引数には、行番号(1または2)を指定する必要があります。"
updateDownloading: "<prefix><red><bold>アップデートをダウンロード中です..."
@@ -73,8 +68,6 @@ singleServerAlreadyDisabled: "<prefix><yellow>%SERVER%<red> のメンテナン
singleServerMaintenanceList: "<prefix><gray>プロキシサーバーで、メンテナンスが有効になっているもの: "
singleServerMaintenanceListEmpty: "<prefix><gray>メンテナンス中のプロキシサーバーはありません。"
singleServerMaintenanceListEntry: "<dark_grey>- <aqua>%SERVER%"
singleServerMaintenanceListEntryWithStartTimer: "<dark_grey>- <grey>%SERVER% <yellow>starting in <gold>%TIME%"
singleServerMaintenanceListEntryWithEndTimer: "<dark_grey>- <aqua>%SERVER% <yellow>ending in <gold>%TIME%"
second: "秒"
seconds: "秒"
minute: "分"
@@ -85,40 +78,27 @@ helpHeader: "<dark_gray>========[ <yellow>%NAME% <dark_gray>| <yellow>%PAGE%/%MA
helpPageNotFound: "<prefix><red>その番号のページがありません。"
helpNextPage: "<gray>Use <aqua>/maintenance help %PAGE% <gray>で次のヘルプウィンドウに移動します。"
helpAbortTimer: "<gold>/maintenance aborttimer <gray>(タイマーを実行していた場合、タイマーの実行を中止します。)"
helpEndtimer: "<gold>/maintenance endtimer <disable in> <gray>(指定された時間(例えば1時間5分)が経過すると、メンテナンス・モードは無効になる)"
helpStarttimer: "<gold>/maintenance starttimer <enable in> <gray>(指定された時間後、例えば1時間5分後にメンテナンス・モードが有効になる)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <enable in> <maintenance duration> <gray>(指定された時間(例えば1時間5分)が経過すると、メンテナンスモードが有効になる)"
helpEndtimer: "<gold>/maintenance endtimer <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpStarttimer: "<gold>/maintenance starttimer <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpDebug: "<gold>/maintenance debug <gray>(デバッグロギングを有効にします。)"
helpDump: "<gold>/maintenance dump <gray>(バグレポートに使用される、いくつかのサーバ情報をダンプします。)"
helpHelp: "<gold>/maintenance help [page] <gray>(このようなヘルプページが表示されます。)"
helpMotd: "<gold>/maintenance motd [timer] <gray>(現在設定されているメンテナンスMOTDを一覧表示します。'timer'を指定した場合は、タイマーの場合のMOTDを表示します。)"
helpRemoveMotd: "<gold>/maintenance removemotd [timer] <index> <gray>(メンテナンスの場合に使用されるMOTDを削除します。引数として'timer'を使用した場合にはタイマー固有のピングメッセージが表示されます。)"
helpSetMotd: "<gold>/maintenance setmotd [timer] <index> <1/2> <message> <gray>(メンテナンスの場合に使用されるMOTDを設定します。引数として'timer'を使用した場合にはタイマー固有のピングメッセージが表示されます。)"
helpSetReason: "<gold>/maintenance setreason <reason/none> <gray>(Sets or clears the %REASON% placeholder value)"
helpReload: "<gold>/maintenance reload <gray>(設定ファイル、ホワイトリストファイル、サーバーアイコンを再読み込みします。)"
helpGlobalStatus: "<gold>/maintenance status <gray>(Shows the current maintenance status and any running timers)"
helpToggle: "<gold>/maintenance <on/off> [mode] <gray>(Enables/disables maintenance mode with an optional display mode when enabling)"
helpToggle: "<gold>/maintenance <on/off> <gray>(メンテナンスモードの有効/解除を設定します。)"
helpUpdate: "<gold>/maintenance update <gray>(最新版のプラグインをサーバーにリモートでダウンロードします。)"
helpWhitelist: "<gold>/maintenance whitelist <gray>(メンテナンスモードのホワイトリストに登録されているすべてのプレーヤーを表示します。)"
helpWhitelistAdd: "<gold>/maintenance add <name/uuid> <gray>(メンテナンスのホワイトリストにユーザーを追加し、メンテナンスが有効な状態でもサーバーに参加できるようにします。)"
helpWhitelistRemove: "<gold>/maintenance remove <name/uuid> <gray>(メンテナンスのホワイトリストからプレーヤーを削除します。)"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
helpAbortSingleTimer: "<gold>/maintenance aborttimer [server] <gray>(もし、タイマーが実行中の場合、現在のタイマーを中止します。)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server|global] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server|global] [mode] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server|global] [mode] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server|global] [mode] <gray>(Enables/disables maintenance mode globally or on a specific server with an optional display mode when enabling)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server] <gray>(メンテナンスモードの有効化/無効化を設定します。)"
helpStatus: "<gold>/maintenance status <gray>(現在メンテナンス中のプロキシサーバーをすべてリストアップします。)"
#Discord webhook messages. These use Discord markdown, not MiniMessage.
#For timer webhooks, %TIMESTAMP% is a Unix timestamp for use in Discord timestamp tags, e.g. <t:%TIMESTAMP%:R>.
webhookMaintenanceActivated: "**Maintenance mode enabled.**"
webhookMaintenanceDeactivated: "**Maintenance mode disabled.**"
webhookStarttimerStarted: "Maintenance mode will be enabled <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookEndtimerStarted: "Maintenance mode will be disabled <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookJoinNotification: "Blocked join: `%PLAYER%` tried to join during maintenance."
webhookSingleMaintenanceActivated: "Maintenance mode enabled on `%SERVER%`."
webhookSingleMaintenanceDeactivated: "Maintenance mode disabled on `%SERVER%`."
webhookSingleStarttimerStarted: "Maintenance mode will be enabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookSingleEndtimerStarted: "Maintenance mode will be disabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
#Used for autoupdating the language file, do not change this value.
language-version: 5
language-version: 2
+9 -29
View File
@@ -1,16 +1,12 @@
#You can use https://webui.advntr.dev/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.papermc.io/adventure/minimessage/format/
#If you want to contribute changes to the default messages, you can do so via https://crowdin.com/project/maintenance
#Maintenance Plugin by kennytv
#You can use https://webui.adventure.kyori.net/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.adventure.kyori.net/minimessage/format.html
#Messages containing the placeholder "<prefix>" will have it replaced with the following string
prefix: "<dark_gray>[<yellow>Maintenance<dark_gray>] "
noPermission: "<red>권한이 없습니다."
kickmessage: "<red>서버가 현재 점검 중입니다!<br>나중에 다시 시도하세요!"
maintenanceActivated: "<prefix><gold>유지 관리 모드가 활성화되었습니다."
maintenanceDeactivated: "<prefix><gold>유지 관리 모드가 비활성화되었습니다."
maintenanceStatusOn: "<prefix><gold>Maintenance mode is currently <green>enabled<gold>."
maintenanceStatusOff: "<prefix><gold>Maintenance mode is currently <red>disabled<gold>."
maintenanceStatusOnWithEndTimer: "<prefix><gold>Maintenance mode is currently <green>enabled <grey>and will be disabled in <gold>%TIME%."
maintenanceStatusOffWithStartTimer: "<prefix><gold>Maintenance mode is currently <red>disabled <grey>and will be enabled in <gold>%TIME%."
alreadyEnabled: "<prefix><red>유지 관리가 이미 활성화되었습니다!"
alreadyDisabled: "<prefix><red>유지보수가 이미 비활성화되었습니다!"
endtimerBroadcast: "<prefix><gray>유지 관리 모드는<gold>%TIME%<gray>에 비활성화됩니다.."
@@ -33,7 +29,6 @@ reload: "<prefix><green>설정, 화이트리스트 플레이어, 언어 파일
removedMotd: "<prefix><green>%INDEX%번째 motd를 삭제했습니다."
removeMotdError: "<prefix><red>motd가 하나만 있으므로 제거할 수 없습니다!"
setMotd: "<prefix><green>INDEX%의 %LINE% 줄을 %MOTD%로 설정합니다."
setReason: "<prefix><green>Set maintenance reason to: <yellow>%REASON%"
setMotdIndexError: "<prefix><red>현재 %MOTDS% motd가 있으므로 1에서 %NEWAMOUNT% 사이의 숫자를 선택해야 합니다."
setMotdLineError: "<prefix><red>두 번째 인수는 줄 번호(1 또는 2)여야 합니다!"
updateDownloading: "<prefix><red><bold>업데이트 다운로드 중..."
@@ -73,8 +68,6 @@ singleServerAlreadyDisabled: "<prefix><red>Maintenance is already disabled on se
singleServerMaintenanceList: "<prefix><gray>Proxied servers, that have maintenance enabled:"
singleServerMaintenanceListEmpty: "<prefix><gray>There are no proxied servers that are under maintenance."
singleServerMaintenanceListEntry: "<dark_grey>- <aqua>%SERVER%"
singleServerMaintenanceListEntryWithStartTimer: "<dark_grey>- <grey>%SERVER% <yellow>starting in <gold>%TIME%"
singleServerMaintenanceListEntryWithEndTimer: "<dark_grey>- <aqua>%SERVER% <yellow>ending in <gold>%TIME%"
second: "second"
seconds: "seconds"
minute: "minute"
@@ -94,31 +87,18 @@ helpHelp: "<gold>/maintenance help [page] <gray>(Shows this beautiful help windo
helpMotd: "<gold>/maintenance motd [timer] <gray>(Lists the currently set maintenance motds. If specifying 'timer', the timer motds are shown)"
helpRemoveMotd: "<gold>/maintenance removemotd [timer] <index> <gray>(Removes a maintenance motd. If using 'timer' as an argument, a timerspecific pingmessage will be removed)"
helpSetMotd: "<gold>/maintenance setmotd [timer] <index> <1/2> <message> <gray>(Sets a motd for maintenance mode. If using 'timer' as an argument, a timerspecific pingmessage will be set)"
helpSetReason: "<gold>/maintenance setreason <reason/none> <gray>(Sets or clears the %REASON% placeholder value)"
helpReload: "<gold>/maintenance reload <gray>(Reloads the config file, whitelist file and the server-icon)"
helpGlobalStatus: "<gold>/maintenance status <gray>(Shows the current maintenance status and any running timers)"
helpToggle: "<gold>/maintenance <on/off> [mode] <gray>(Enables/disables maintenance mode with an optional display mode when enabling)"
helpToggle: "<gold>/maintenance <on/off> <gray>(Enables/disables maintenance mode)"
helpUpdate: "<gold>/maintenance update <gray>(Remotely downloads the newest version of the plugin onto your server)"
helpWhitelist: "<gold>/maintenance whitelist <gray>(Shows all whitelisted players for the maintenance mode)"
helpWhitelistAdd: "<gold>/maintenance add <name/uuid> <gray>(Adds the player to the maintenance whitelist, so they can join the server even though maintenance is enabled)"
helpWhitelistRemove: "<gold>/maintenance remove <name/uuid> <gray>(Removes the player from the maintenance whitelist)"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
helpAbortSingleTimer: "<gold>/maintenance aborttimer [server] <gray>(If running, the current timer will be aborted)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server|global] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server|global] [mode] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server|global] [mode] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server|global] [mode] <gray>(Enables/disables maintenance mode globally or on a specific server with an optional display mode when enabling)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server] <gray>(Enables/disables maintenance mode)"
helpStatus: "<gold>/maintenance status <gray>(Lists all proxied servers, that are currently under maintenance)"
#Discord webhook messages. These use Discord markdown, not MiniMessage.
#For timer webhooks, %TIMESTAMP% is a Unix timestamp for use in Discord timestamp tags, e.g. <t:%TIMESTAMP%:R>.
webhookMaintenanceActivated: "**Maintenance mode enabled.**"
webhookMaintenanceDeactivated: "**Maintenance mode disabled.**"
webhookStarttimerStarted: "Maintenance mode will be enabled <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookEndtimerStarted: "Maintenance mode will be disabled <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookJoinNotification: "Blocked join: `%PLAYER%` tried to join during maintenance."
webhookSingleMaintenanceActivated: "Maintenance mode enabled on `%SERVER%`."
webhookSingleMaintenanceDeactivated: "Maintenance mode disabled on `%SERVER%`."
webhookSingleStarttimerStarted: "Maintenance mode will be enabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookSingleEndtimerStarted: "Maintenance mode will be disabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
#Used for autoupdating the language file, do not change this value.
language-version: 5
language-version: 2
+16 -36
View File
@@ -1,18 +1,14 @@
#You can use https://webui.advntr.dev/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.papermc.io/adventure/minimessage/format/
#If you want to contribute changes to the default messages, you can do so via https://crowdin.com/project/maintenance
#Maintenance Plugin by kennytv
#You can use https://webui.adventure.kyori.net/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.adventure.kyori.net/minimessage/format.html
#Messages containing the placeholder "<prefix>" will have it replaced with the following string
prefix: "<dark_gray>[<yellow>Prace techniczne<dark_gray>] "
noPermission: "<red>Nie posiadasz permisji na użycie tej komendy."
kickmessage: "<red>Serwer jest w trakcie przerwy technicznej!<br>Spróbuj ponownie później!"
maintenanceActivated: "<prefix><gold>Tryb konserwacji włączony."
maintenanceDeactivated: "<prefix><gold>Tryb konserwacji wyłączony."
maintenanceStatusOn: "<prefix><gold>Tryb konserwacji jest obecnie <green>włączony<gold>."
maintenanceStatusOff: "<prefix><gold>Tryb konserwacji jest obecnie <red>wyłączony<gold>."
maintenanceStatusOnWithEndTimer: "<prefix><gold>Tryb konserwacji jest obecnie <green>włączony <grey>i zostanie wyłączony za <gold>%TIME%."
maintenanceStatusOffWithStartTimer: "<prefix><gold>Tryb konserwacji jest obecnie <red>wyłączony <grey>i zostanie włączony za <gold>%TIME%."
alreadyEnabled: "<prefix><red>Tryb konserwacji jest już włączony!"
alreadyDisabled: "<prefix><red>Tryb konserwacji jest już wyłączony!"
alreadyEnabled: "<prefix><red>Przerwa techniczna już jest włącznona!"
alreadyDisabled: "<prefix><red>Przerwa techniczna już jest wyłącznona!"
endtimerBroadcast: "<prefix><gray>Przerwa techniczna zostanie zakończona za <gold>%TIME%<gray>."
endtimerStarted: "<prefix><green>Rozpoczęto timer: <gray>Tryb konserwacji zostanie wyłączony za <gold>%TIME%<gray>."
starttimerBroadcast: "<prefix><gray>Przerwa techniczna zacznie się za <gold>%TIME%<gray>."
@@ -22,7 +18,7 @@ scheduletimerStarted: "<prefix><green>Rozpoczęto timer: <gray>Przerwa techniczn
timerAlreadyRunning: "<prefix><red>Timer został już zaplanowany!"
timerNotRunning: "<prefix><red>Aktualnie nie ma żadnego działającego timera."
timerCancelled: "<prefix><red>Bieżący timer został anulowany."
timerTooLong: "<prefix><red>Podany czas musi być krótszy niż 28 dni!"
timerTooLong: "<prefix><red>Liczba musi byc mniejsz niż 40320 (28 dni)!"
timerMotdDisabled: "<prefix><red>Musisz ustawić 'enable-timerspecific-messages' w konfiguracji na 'true', jeśli chcesz używać motd z timerem."
motdTimer: "%HOURS%:%MINUTES%:%SECONDS%"
motdTimerNotRunning: "-"
@@ -33,7 +29,6 @@ reload: "<prefix><green>Ponownie załadowano plik konfiguracji, białą listę,
removedMotd: "<prefix><green>Usunięto motd numer %INDEX%."
removeMotdError: "<prefix><red>Masz tylko jedno motd, którego nie możesz usunąć!"
setMotd: "<prefix><green>Ustawiono wiersz %LINE% od %INDEX%. motd konserwacji na %MOTD%"
setReason: "<prefix><green>Ustawiono powód konserwacji na: <yellow>%REASON%"
setMotdIndexError: "<prefix><red>Masz aktualnie %MOTDS% motd, więc musisz wybrać liczbę między 1 a %NEWAMOUNT%."
setMotdLineError: "<prefix><red>Drugi argument musi być numerem lini (1 lub 2)!"
updateDownloading: "<prefix><red><bold>Pobieranie aktualizacji..."
@@ -49,7 +44,7 @@ whitelistEmpty: "<prefix><red>Biała lista konserwacji jest pusta! Użyj <yellow
playerNotFound: "<prefix><red>Ten gracz nigdy nie grał na serwerze."
playerNotFoundUuid: "<prefix><red>Nie można znaleźć gracza z tym uuid."
playerNotOnline: "<prefix><red>Nie ma gracza online z tym nickiem."
offlinePlayerFetchError: "<prefix><red>Wystąpił błąd podczas pobierania gracza offline. Spróbuj ponownie później."
offlinePlayerFetchError: "<prefix><red>There was an error while fetching offline player. Please try again later."
invalidUuid: "<prefix><red>Nieprawidłowy format uuid!"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
sentToWaitingServer: "<prefix><red>Zostałeś wysłany do poczekalni!"
@@ -73,8 +68,6 @@ singleServerAlreadyDisabled: "<prefix><red>Tryb konserwacji jest już wyłączon
singleServerMaintenanceList: "<prefix><gray>Serwery z włączonym trybem konserwacji:"
singleServerMaintenanceListEmpty: "<prefix><gray>Brak serwerów pod nadzorem."
singleServerMaintenanceListEntry: "<dark_grey>- <aqua>%SERVER%"
singleServerMaintenanceListEntryWithStartTimer: "<dark_grey>- <grey>%SERVER% <yellow>zaczyna się za <gold>%TIME%"
singleServerMaintenanceListEntryWithEndTimer: "<dark_grey>- <aqua>%SERVER% <yellow>kończy się za <gold>%TIME%"
second: "sekunda"
seconds: "sekund"
minute: "minuta"
@@ -85,40 +78,27 @@ helpHeader: "<dark_gray>========[ <yellow>%NAME% <dark_gray>| <yellow>%PAGE%/%MA
helpPageNotFound: "<prefix><red>Strona z tym numerem nie istnieje!"
helpNextPage: "<gray>Użyj <aqua>/maintenance help %PAGE% <gray>aby przejść do następnej strony pomocy."
helpAbortTimer: "<gold>/maintenance aborttimer <gray>(Jeśli aktywny, timer zostanie anulowany)"
helpEndtimer: "<gold>/maintenance endtimer <czas> <gray>(Po podanym czasie, np. 1h5m, tryb konserwacji zostanie wyłączony)"
helpStarttimer: "<gold>/maintenance starttimer <czas> <gray>(Po podanym czasie, np. 1h5m, tryb konserwacji zostanie włączony)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <czas do włączenia> <czas trwania> <gray>(Po podanym czasie, np. 1h5m, tryb konserwacji zostanie włączony)"
helpEndtimer: "<gold>/maintenance endtimer <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpStarttimer: "<gold>/maintenance starttimer <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpDebug: "<gold>/maintenance debug <gray>(Włacza logowanie dodatkowych informcji do debugowania)"
helpDump: "<gold>/maintenance dump <gray>(Daje informacje o serwerze, używane do raportowania błędów)"
helpHelp: "<gold>/maintenance help [strona] <gray>(Pokazuje tą piękną stronę pomocy)"
helpMotd: "<gold>/maintenance motd [timer] <gray>(Wyświetla aktualnie ustawione motd. Jeśli wstawiono 'timer', motd z timerem zostaną pokazane)"
helpRemoveMotd: "<gold>/maintenance removemotd [timer] <index> <gray>(Usuwa motd konserwacji. Jeśli wstawiono 'timer', motd z timerem zostanie usunięte)"
helpSetMotd: "<gold>/maintenance setmotd [timer] <index> <1/2> <wiadomość> <gray>(Ustawia motd konserwacji. Jeśli wstawiono 'timer', motd z timerem zostanie ustawione)"
helpSetReason: "<gold>/maintenance setreason <powód/none> <gray>(Ustawia albo usuwa powód trybu konserwacji w wiadomościach. Wpisz \"none\" jako powód, aby wyczyścić)"
helpReload: "<gold>/maintenance reload <gray>(Przeładowuje plik konfiguracji, białej listy i ikonę serwera)"
helpGlobalStatus: "<gold>/maintenance status <gray>(Pokazuje status trybu konserwacji i wszystkie minutniki)"
helpToggle: "<gold>/maintenance <on/off> [tryb] <gray>(Włącza/Wyłącza tryb konserwacji, opcjonalnie z trybem podanym podczas włączania)"
helpToggle: "<gold>/maintenance <on/off> <gray>(Włącza/wyłącza tryb konserwacji)"
helpUpdate: "<gold>/maintenance update <gray>(Pobiera najnowszą wersję plugina)"
helpWhitelist: "<gold>/maintenance whitelist <gray>(Pokazuje białą listę trybu konserwacji)"
helpWhitelistAdd: "<gold>/maintenance add <nazwa/uuid> <gray>(Dodaje gracza do listy konserwacji, aby mogli dołączyć do serwera w trakcie konserwacji)"
helpWhitelistRemove: "<gold>/maintenance remove <nazwa/uuid> <gray>(Usuwa gracza z listy trybu konserwacji)"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
helpAbortSingleTimer: "<gold>/maintenance aborttimer [serwer] <gray>(Jeśli aktywny, timer zostanie anulowany)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server|global] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server|global] [mode] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server|global] [mode] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [serwer/global] [tryb] <gray>(Włącza/Wyłącza tryb konserwacji globalnie lub na podanym serwerze, opcjonalnie z trybem podanym podczas włączania)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [serwer] <gray>(Włącza/wyłącza tryb konserwacji)"
helpStatus: "<gold>/maintenance status <gray>(Wyświetla wszystkie serwery w trybie konserwacji)"
#Discord webhook messages. These use Discord markdown, not MiniMessage.
#For timer webhooks, %TIMESTAMP% is a Unix timestamp for use in Discord timestamp tags, e.g. <t:%TIMESTAMP%:R>.
webhookMaintenanceActivated: "**Tryb konserwacji włączony.**"
webhookMaintenanceDeactivated: "**Tryb konserwacji wyłączony.**"
webhookStarttimerStarted: "Tryb konserwacji zostanie włączony <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookEndtimerStarted: "Tryb konserwacji zostanie wyłączony <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookJoinNotification: "Zablokowano dołączenie: `%PLAYER%` próbował(a) dołączyć podczas konserwacji."
webhookSingleMaintenanceActivated: "Tryb konserwacji włączony dla `%SERVER%`."
webhookSingleMaintenanceDeactivated: "Tryb konserwacji wyłączony dla `%SERVER%`."
webhookSingleStarttimerStarted: "Tryb konserwacji zostanie włączony dla `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookSingleEndtimerStarted: "Tryb konserwacji zostanie wyłączony dla `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
#Used for autoupdating the language file, do not change this value.
language-version: 5
language-version: 2
+12 -32
View File
@@ -1,16 +1,12 @@
#You can use https://webui.advntr.dev/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.papermc.io/adventure/minimessage/format/
#If you want to contribute changes to the default messages, you can do so via https://crowdin.com/project/maintenance
#Maintenance Plugin by kennytv
#You can use https://webui.adventure.kyori.net/ to edit and preview the formatted text
#For a full list of formats and fancy examples, see https://docs.adventure.kyori.net/minimessage/format.html
#Messages containing the placeholder "<prefix>" will have it replaced with the following string
prefix: "<dark_gray>[<yellow>Maintenance<dark_gray>] "
noPermission: "<red>Você não tem permissão para executar esse comando."
kickmessage: "<red>O servidor está em manutenção!<br>Tente novamente mais tarde!"
maintenanceActivated: "<prefix><gold>O modo de manutenção agora está ativado."
maintenanceDeactivated: "<prefix><gold>O modo de manutenção agora está desativado."
maintenanceStatusOn: "<prefix><gold>O modo de manutenção está atualmente <green>ativo<gold>."
maintenanceStatusOff: "<prefix><gold>O modo de manutenção está atualmente <red>desativado<gold>."
maintenanceStatusOnWithEndTimer: "<prefix><gold>O modo de manutenção está atualmente <green>habilitado <grey>e será desabilitado em <gold>%TIME%."
maintenanceStatusOffWithStartTimer: "<prefix><gold>O modo de manutenção está atualmente <red>desabilitado <grey>e será habilitado em <gold>%TIME%."
alreadyEnabled: "<prefix><red>A manutenção já está ativada!"
alreadyDisabled: "<prefix><red>A manutenção já está desativada!"
endtimerBroadcast: "<prefix><gray>O modo de manutenção será desativado em <gold>%TIME%<gray>."
@@ -33,7 +29,6 @@ reload: "<prefix><green>Recarregou a configuração, lista de jogadores com perm
removedMotd: "<prefix><green>Motd número %INDEX% removida."
removeMotdError: "<prefix><red>Você possui apenas uma motd, portanto, não pode remover nenhuma!"
setMotd: "<prefix><green>Definiu a linha %LINE% da motd de manutenção %INDEX% para %MOTD%"
setReason: "<prefix><green>Definir motivo de manutenção para: <yellow>%REASON%"
setMotdIndexError: "<prefix><red>No momento, você possui %MOTDS% motds, portanto, deve escolher um número entre 1 e %NEWAMOUNT%."
setMotdLineError: "<prefix><red>O segundo argumento deve ser o número da linha (1 ou 2)!"
updateDownloading: "<prefix><red><bold>Baixando atualização..."
@@ -73,8 +68,6 @@ singleServerAlreadyDisabled: "<prefix><red>A manutenção já está desativada n
singleServerMaintenanceList: "<prefix><gray>Servidores proxy com manutenção ativada:"
singleServerMaintenanceListEmpty: "<prefix><gray>Não há servidores proxy em manutenção no momento."
singleServerMaintenanceListEntry: "<dark_grey>- <aqua>%SERVER%"
singleServerMaintenanceListEntryWithStartTimer: "<dark_grey>- <grey>%SERVER% <yellow>iniciando em <gold>%TIME%"
singleServerMaintenanceListEntryWithEndTimer: "<dark_grey>- <aqua>%SERVER% <yellow>terminando em <gold>%TIME%"
second: "segundo"
seconds: "segundos"
minute: "minuto"
@@ -85,40 +78,27 @@ helpHeader: "<dark_gray>========[ <yellow>%NAME% <dark_gray>| <yellow>%PAGE%/%MA
helpPageNotFound: "<prefix><red>Não há página com esse número!"
helpNextPage: "<gray>Use <aqua>/maintenance help %PAGE% <gray>para ir para a próxima janela de ajuda."
helpAbortTimer: "<gold>/maintenance aborttimer <gray>(Se estiver em execução, o temporizador atual será abortado)"
helpEndtimer: "<gold>/maintenance endtimer <desabilitar em> <gray>(Depois do tempo fornecido, exemplo: 1h5m, o modo manutenção será desabilitado)"
helpStarttimer: "<gold>/maintenance starttimer <habilitar em> <gray>(Depois do tempo fornecido, exemplo: 1h5m, o modo de manutenção será habilitado)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <habilitar em> <duração da manutenção> <gray>(Depois do tempo fornecido, exemplo: 1h5m, o modo de manutenção será habilitado)"
helpEndtimer: "<gold>/maintenance endtimer <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpStarttimer: "<gold>/maintenance starttimer <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpScheduleTimer: "<gold>/maintenance scheduletimer <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpDebug: "<gold>/maintenance debug <gray>(Ativa alguns registros de depuração)"
helpDump: "<gold>/maintenance dump <gray>(Exibe algumas informações do servidor, usadas para relatórios de bugs)"
helpHelp: "<gold>/maintenance help [página] <gray>(Mostra esta bela janela de ajuda)"
helpMotd: "<gold>/maintenance motd [temporizador] <gray>(Lista as motds de manutenção atualmente definidas. Se 'temporizador' for especificado, as motds de temporizador serão mostradas)"
helpRemoveMotd: "<gold>/maintenance removemotd [temporizador] <índice> <gray>(Remove uma motd de manutenção. Se usar 'temporizador' como argumento, uma mensagem de ping específica do temporizador será removida)"
helpSetMotd: "<gold>/maintenance setmotd [temporizador] <índice> <1/2> <mensagem> <gray>(Define uma motd para o modo de manutenção. Se usar 'temporizador' como argumento, uma mensagem de ping específica do temporizador será definida)"
helpSetReason: "<gold>/maintenance setreason <reason/none> <gray>(Define ou limpa o valor %REASON% comum)"
helpReload: "<gold>/maintenance reload <gray>(Recarrega o arquivo de configuração, arquivo de lista branca e o ícone do servidor)"
helpGlobalStatus: "<gold>/maintenance status <gray>(Mostra o estado atual da manutenção e qualquer timer em execução)"
helpToggle: "<gold>/maintenance <on/off> [mode] <gray>(Ativa/desativa modo de manutenção com modo de exibição opcional quando ativado)"
helpToggle: "<gold>/maintenance <on/off> <gray>(Ativa/desativa o modo de manutenção)"
helpUpdate: "<gold>/maintenance update <gray>(Baixa remotamente a versão mais recente do plugin para o seu servidor)"
helpWhitelist: "<gold>/maintenance whitelist <gray>(Mostra todos os jogadores na lista branca para o modo de manutenção)"
helpWhitelistAdd: "<gold>/maintenance add <nome/uuid> <gray>(Adiciona o jogador à lista branca de manutenção, permitindo que eles entrem no servidor mesmo com a manutenção ativada)"
helpWhitelistRemove: "<gold>/maintenance remove <nome/uuid> <gray>(Remove o jogador da lista branca de manutenção)"
#Messages for the Bungee/Velocity part, you can ignore them if you use the plugin on Paper/Sponge
helpAbortSingleTimer: "<gold>/maintenance aborttimer [servidor] <gray>(Se estiver em execução, o temporizador atual será abortado)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server|global] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server|global] [mode] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server|global] [mode] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [server|global] [mode] <gray>(Ativa/desativa modo de manutenção globalmente ou em um servidor especifico com um modo de exibição opcional quando ativado)"
helpSingleEndtimer: "<gold>/maintenance endtimer [server] <disable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be disabled)"
helpSingleStarttimer: "<gold>/maintenance starttimer [server] <enable in> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleScheduleTimer: "<gold>/maintenance scheduletimer [server] <enable in> <maintenance duration> <gray>(After the given time, e.g. 1h5m, maintenance mode will be enabled)"
helpSingleToggle: "<gold>/maintenance <on/off> [servidor] <gray>(Ativa/desativa o modo de manutenção)"
helpStatus: "<gold>/maintenance status <gray>(Lista todos os servidores proxy que estão atualmente em manutenção)"
#Discord webhook messages. These use Discord markdown, not MiniMessage.
#For timer webhooks, %TIMESTAMP% is a Unix timestamp for use in Discord timestamp tags, e.g. <t:%TIMESTAMP%:R>.
webhookMaintenanceActivated: "**Modo de manutenção ativado.**"
webhookMaintenanceDeactivated: "**Modo de manutenção desativado.**"
webhookStarttimerStarted: "Manutenção será ativada em <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookEndtimerStarted: "Manutenção será desativada em <t:%TIMESTAMP%:R> (`%TIME%`)."
webhookJoinNotification: "Entrada bloqueada: `%PLAYER%` tentou conectar durante a manutenção."
webhookSingleMaintenanceActivated: "Manutenção será ativada em `%SERVER%`."
webhookSingleMaintenanceDeactivated: "Manutenção será desativada em `%SERVER%`."
webhookSingleStarttimerStarted: ""
webhookSingleEndtimerStarted: "Maintenance mode will be disabled on `%SERVER%` <t:%TIMESTAMP%:R> (`%TIME%`)."
#Used for autoupdating the language file, do not change this value.
language-version: 5
language-version: 2
Loaded 100 of 146 files, more files were not shown because too many files have changed in this diff. Show more