Compare commits

..
160 Commits
Author SHA1 Message Date
Nassim 29d9fa2ec8 3.0.6 Release 2021-02-17 10:25:23 +01:00
KennyTV ef2ce99746 Prepare for 3.0.6 Release 2021-02-17 10:24:56 +01:00
KennyTV aa5437605f Actually fire the MaintenanceReloadedEvent 2021-02-07 11:40:41 +01:00
KennyTV 22e1d53f81 Update copyright header 2021-02-07 11:32:00 +01:00
KennyTV 1359684c72 Add "maintenance schedule" command 2021-02-07 11:30:20 +01:00
KennyTV 22c53bd4ff Add primitive debug mode (only implemented on Bungee) 2020-12-31 12:59:31 +01:00
KennyTV c0e2586684 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 2f095f32ca Also replace online and max variable in the hover message 2020-11-20 22:38:10 +01:00
KennyTV e1e4926f83 Properly register main command with permissions (instead of checking for them in the actual command) 2020-10-26 16:55:37 +01:00
KennyTV 55b5bf2714 Update Velocity API usage 2020-10-26 16:47:07 +01:00
KennyTV 5f8f885530 Update language-es.yml (thanks to Vixo_Ulises) 2020-10-26 16:38:38 +01:00
KennyTV fc40b0230d Rename GH build artifact 2020-10-01 09:40:29 +02:00
Nassim 6fb79d7051 Make artifacts work 😎 2020-08-25 14:55:20 +02:00
KennyTV 7bc522c1d3 Upload artifacts 2020-08-25 14:52:15 +02:00
Nassim 8d0d97c220 Create maven.yml 2020-08-25 14:14:56 +02:00
KennyTV e7c8430909 Fix NPE in null pings 2020-08-22 09:48:21 +02:00
KennyTV 1646d4e417 Update Velocity API usage to 1.1.0-SNAPSHOT 🎉 2020-08-21 20:26:39 +02:00
KennyTV f8384f4f99 Add whitelist add arg to manually add offline uuid+name 2020-08-19 09:44:57 +02:00
KennyTV 4fd6ba33ff Fix linebreaks on Bungee in playercount hovermessage 2020-07-30 12:04:05 +02:00
KennyTV 94c146d0e9 Add MaintenanceReloadedEvent, also fire changed event for unregistered proxy servers 2020-07-29 14:17:49 +02:00
dependabot-preview[bot] c624b18b8e 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 18a00f9054 Link to dev branch for Travis builds 2020-07-26 12:15:18 +02:00
KennyTV 9778a900a7 Add 'mt' command alias, add some braces 2020-07-26 11:08:25 +02:00
KennyTV 21fa6a3b7f Formatting fix in changelog 2020-07-14 12:10:34 +02:00
KennyTV c7980cbc86 Missing singleserver kick messages should not throw warnings 2020-06-25 11:28:36 +02:00
KennyTV cdb6715744 Implement new methods for dummyprofile 2020-06-25 09:12:24 +02:00
KennyTV d868f069cc Add translators to the individual language files 2020-06-21 09:26:59 +02:00
Aurélien c58b29a78f Fixes for French translation (#42) 2020-06-21 09:19:16 +02:00
KennyTV 5fb4f06f4c Rename method to get server name of player, cleanup config in test 2020-06-18 15:43:39 +02:00
KennyTV 8a3afdd1a8 Version increase to 3.0.6-SNAPSHOT 2020-06-18 15:26:39 +02:00
KennyTV 36e561c413 Sneak a mysql fix in 2020-06-17 14:09:02 +02:00
KennyTV 4739176e9b Update API jar to 3.0.5 2020-06-17 11:26:32 +02:00
Nassim 9546cc7b74 3.0.5 Release 2020-06-17 10:48:13 +02:00
KennyTV 740051dda5 Prepare for 3.0.5 release 2020-06-17 10:47:20 +02:00
KennyTV e53f4f2518 Config test additions 2020-06-17 09:31:49 +02:00
KennyTV 03390d7be9 Config set cleanup 2020-06-16 17:49:45 +02:00
KennyTV 039c5a3d04 Use precondition in api getter util 2020-06-16 16:39:23 +02:00
KennyTV 4360eb03e3 Wrong nullable annotation 2020-06-16 16:20:18 +02:00
KennyTV 89691e8064 Minor code cleanup to version checking 2020-06-16 16:19:20 +02:00
KennyTV 8f4860ad56 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 b8b231ce78 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 fd8b47a9f5 Automatically move files to new dir on updating 2020-06-09 19:25:21 +02:00
KennyTV 10c0b5bab3 Update README 2020-06-01 13:21:21 +02:00
KennyTV cece2b5813 Use higher proxy ping listener priority 2020-05-18 22:12:22 +02:00
KennyTV aa9a686b8a 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 f29b38989c Add option to set multiple fallback servers 2020-05-12 20:52:47 +02:00
KennyTV ad9c989213 Add secret language option for server specific kick messages
Closes #38
2020-05-12 20:27:59 +02:00
KennyTV f01e96a32a Implement deep get in config 2020-05-12 19:32:42 +02:00
KennyTV e247f4ef10 Remove platform suffix from plugin identifier 2020-04-22 10:59:27 +02:00
KennyTV b8e0f84d54 Don't hide playercount if custom playercount is disabled 2020-04-21 12:00:23 +02:00
KennyTV 424617c602 Respect custom playercount setting in Spigot ping 2020-04-21 08:36:28 +02:00
KennyTV 21ed266d3d Fix use-ssl option inversion 2020-04-13 09:29:22 +02:00
KennyTV a409ec5d66 Update copyright headers 2020-04-10 23:42:06 +02:00
KennyTV 66cba12fd3 Update Russian language file 2020-04-09 08:59:11 +02:00
KennyTV f6d178d8d1 Add placeholder link to readme 2020-04-06 22:34:04 +02:00
KennyTV d04749c835 Add Italian language file 2020-04-03 12:27:00 +02:00
KennyTV eebbc4d532 Fix config loading with multiline strings, add small tests
Fixes #37
2020-03-30 12:48:48 +02:00
KennyTV 335fe303b5 Throw around some nullable annotations 2020-03-30 11:02:35 +02:00
KennyTV 1c4b5e62a4 Add Chinese language file 2020-03-17 15:02:47 +01:00
KennyTV d41fa5ab24 Version increase to 3.0.5-SNAPSHOT 2020-03-17 11:57:12 +01:00
Nassim 7fd486ef40 3.0.4 Release 2020-03-17 11:01:41 +01:00
KennyTV d0b10f2524 Prepare for 3.0.4 release 2020-03-17 11:00:55 +01:00
KennyTV 865df5e20a Rearrange new language entries 2020-03-16 15:49:09 +01:00
KennyTV 469e8eb57b Fix join notifications with waiting servers enabled 2020-03-16 15:48:27 +01:00
KennyTV 368ac37099 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 0db4d77c10 Update missing pt messages (by JoaoPinto) 2020-03-16 11:16:46 +01:00
Max Kade ca4c711103 Fix single server timer accepting number as seconds and not minutes (#35) 2020-03-11 14:35:56 +01:00
KennyTV f4a5f288ca Fix singleserver timers broadcasting globally 2020-02-14 21:40:08 +01:00
KennyTV 0a37bfdefe Update bStats metrics 2020-02-12 17:20:37 +01:00
KennyTV 3a30dba011 Add option to disable sql ssl 2020-02-09 12:47:28 +01:00
KennyTV 111a229d48 Minor beauty changes 2020-01-29 15:11:01 +01:00
KennyTV 7e948fbe52 Forgot the return 2019-11-21 09:46:51 +01:00
KennyTV 355aa20244 Add Russian language file (thanks to En_0t_S) 2019-11-21 09:44:23 +01:00
KennyTV 6bc54d1812 Don't throw errors when failing the language update check because of custom langs 2019-11-21 09:41:42 +01:00
KennyTV 0042ce3ccd Version increase to 3.0.4-SNAPSHOT 2019-11-21 09:27:32 +01:00
KennyTV beb0e52371 Forgot to update the date in the changelog 2019-09-17 09:05:53 +02:00
Nassim 4774ec2f2a 3.0.3 Release 2019-09-17 09:02:27 +02:00
KennyTV 34115f443e Version increase to 3.0.3 2019-09-17 08:29:23 +02:00
KennyTV c8f0c1699e Update changelog, fix small oversight in the Bungee serverconnect 2019-09-13 10:30:53 +02:00
KennyTV f22be77023 Fix playercountmessage on Paper servers with Via 2019-09-09 08:35:53 +02:00
KennyTV 730a8dbeea Remove some old code 2019-08-24 18:55:30 +02:00
KennyTV 0548e0c447 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 da0a757c5e Revert "Fix potential config deserialization error"
This reverts commit ac19bac1
2019-08-13 22:33:31 +02:00
KennyTV ac19bac11c Fix potential config deserialization error 2019-08-13 22:21:30 +02:00
KennyTV 1de926bb28 Minor pom changes 2019-08-13 22:21:11 +02:00
KennyTV 94308cde7c Fix some redundant config comment checks 2019-07-26 13:20:27 +02:00
KennyTV d863c709e1 Update bStats metrics 2019-07-26 12:29:34 +02:00
KennyTV 741914283a Minor config optimizations and cleanup 2019-07-22 09:28:53 +02:00
KennyTV 64902d90ff Language autoupdater, fix updating with broken texts 2019-07-21 15:49:10 +02:00
KennyTV d3b4c7c87b Add warning with PS 2019-07-20 09:58:00 +02:00
KennyTV 390b65a70e Add warning with PS 2019-07-20 09:49:00 +02:00
KennyTV 7cff908aae Switch to ProtocolLib/Spigot ping listener if PS is installed 2019-07-20 09:46:28 +02:00
KennyTV d1f049c3e5 Add help page header to language file 2019-06-28 21:43:27 +02:00
Nassim 8d552dbe33 Remove a space in language-es.yml 2019-06-27 10:34:36 +02:00
KennyTV d3a933d21d Add bypass permission for specific proxied servers 2019-06-27 10:05:57 +02:00
KennyTV a4d87dabf5 Update changelog 2019-06-09 09:53:04 +02:00
KennyTV c3b579e86c Update Spanish language (thanks to Vixo_Ulises) 2019-06-09 09:51:04 +02:00
KennyTV b75d2337df Update French language (thanks to Zendrique) 2019-05-31 21:26:58 +02:00
KennyTV b3e83c5c2e Language changes 2019-05-31 16:26:16 +02:00
KennyTV b6f447aded Update travis.yml 2019-05-31 15:45:35 +02:00
KennyTV 9febdfc140 Update travis.yml 2019-05-31 15:38:06 +02:00
KennyTV 90bc30d701 I'm a dumbo 2019-05-31 15:31:10 +02:00
KennyTV 843ba4ac86 Add help messages to language files 2019-05-31 15:30:03 +02:00
KennyTV 032fd7d582 Fix double messages in some server connections 2019-05-24 09:14:51 +02:00
KennyTV 9a0f680177 Kick connecting players before the connection succeeded, fix double join-notification (Bungee) 2019-05-23 22:18:05 +02:00
KennyTV 415d5f3807 Update config version 2019-05-20 15:28:06 +02:00
KennyTV 33c96de5fb Add option to not kick online players 2019-05-18 17:23:56 +02:00
KennyTV d141b40190 Version increase to 3.0.3-SNAPSHOT 2019-05-18 17:16:37 +02:00
KennyTV 77e1444dba 3.0.2 Release 2019-05-17 09:35:34 +02:00
KennyTV 915b43d897 👀 2019-05-17 09:35:14 +02:00
KennyTV adc06e3486 Update changelog 2019-05-17 09:31:17 +02:00
KennyTV cc7f5c2d11 Version increase to 3.0.2 2019-05-17 09:25:57 +02:00
KennyTV 0bb54ffc5d Finish timerspecific pingmessages 2019-05-17 09:21:35 +02:00
KennyTV 15ee2e6074 Update changelog, resort some config entries 2019-05-14 13:48:28 +02:00
KennyTV 89abab36f8 Timerspecific pingmessages 2019-05-14 09:07:23 +02:00
KennyTV e0bb1336b0 ‍Make setmotd command also set timerspecific messages 2019-05-13 22:53:04 +02:00
KennyTV 888ffd301a 🤦‍ 2019-05-13 15:30:40 +02:00
KennyTV 3a55dd3280 Make motd command display timerspecific ones 2019-05-13 15:30:00 +02:00
KennyTV 61c47ba2fa WIP: Timerspecific pingmessages 2019-05-13 11:02:13 +02:00
KennyTV b97e69a71f Make dumps prettier 2019-05-09 22:30:18 +02:00
KennyTV 75c940d089 Fix Sponge 8.0.0 compatibility 2019-05-09 21:53:30 +02:00
KennyTV 849fa2a720 Update to latest Velocity text api 2019-05-07 09:09:58 +02:00
KennyTV 7e249faa99 Update README.md 2019-04-27 15:34:07 +02:00
KennyTV c8272b39d5 Fix Velocity autoupdater 2019-04-17 15:38:51 +02:00
KennyTV b3c561ae26 Version increase to 3.0.2-SNAPSHOT 2019-04-17 15:38:33 +02:00
KennyTV af24c5a331 Update api, changelog and readme for latest release 2019-04-17 15:24:51 +02:00
KennyTV 4cc162f00d Merge pull request #29 from KennyTV/dev
3.0.1 Release
2019-04-17 14:38:55 +02:00
KennyTV 02610fd904 Version increase to 3.0.1 2019-04-17 14:36:56 +02:00
KennyTV bccd1bb936 Remove interface check 2019-04-17 14:36:47 +02:00
KennyTV c08dd5d430 Set group id to eu.kennytv.maintenance 2019-04-15 10:54:16 +02:00
KennyTV 1104a50882 Fix another potential error on startup 2019-04-14 13:07:01 +02:00
KennyTV 56898d7b40 Database sync fixes, adjustments to endtimer saving 2019-04-05 14:05:01 +02:00
KennyTV 4be31a6dd4 Update README 2019-04-05 14:04:45 +02:00
KennyTV 190a063d49 Add config updater + endtimer saving after restart 2019-04-03 14:22:06 +02:00
KennyTV 6e4591d45b Fix error printing in some cases, close hikari source on disable(/reload) 2019-04-03 11:15:30 +02:00
KennyTV 86c556e841 Hackily fix slf4j relocation and shorten jar sizes 2019-03-19 22:35:13 +01:00
KennyTV 404e14ee94 Revert "Only compile SnakeYaml in universal and Velocity file"
This reverts commit b8c0e3a7
2019-03-19 18:07:18 +01:00
KennyTV b8c0e3a799 Only compile SnakeYaml in universal and Velocity file 2019-03-19 18:04:05 +01:00
KennyTV 10d798acd4 Make ServerInfoPacketListener extend PacketAdapter instead of creating anonymous class 2019-03-19 17:04:08 +01:00
KennyTV be057f4b3b Don't register listener twice 2019-03-13 17:17:31 +01:00
KennyTV eea7a595c9 Add Ore url to plugin info 2019-03-13 10:21:29 +01:00
KennyTV bf4bf79b23 Readd update checking on Sponge, still disallow execution of update 2019-03-13 10:04:16 +01:00
KennyTV 686535228e Typo 👀 2019-03-11 13:24:33 +01:00
KennyTV 8b645b6f79 Fix Paper pinglistener and remove old code 2019-03-11 13:22:15 +01:00
KennyTV 4d97293a8c Rename dump variable 2019-03-11 13:00:43 +01:00
KennyTV c746a83f5f Use PaperServerListPingEvent if applicable 2019-03-11 12:48:10 +01:00
KennyTV eb7e6e3f0b Fix exception on ping that does not come from status packet 2019-03-10 19:08:08 +01:00
KennyTV f5ce41853f nooooo 2019-03-08 21:29:28 +01:00
KennyTV e67cde591c Try to please the beautiful people over at Ore (Sponge), attempt no 2 2019-03-08 21:28:35 +01:00
KennyTV 39682635c6 Try to please the beautiful people over at Ore (Sponge) 2019-03-08 21:18:21 +01:00
KennyTV efee532742 Make endtimer display format adjustable 2019-03-05 16:55:56 +01:00
KennyTV 0aee3a8fd6 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 f79b6caccb Minor maintenance event changes 2019-02-21 16:43:13 +01:00
KennyTV 73fd80b456 Some language changes 2019-02-21 15:35:52 +01:00
KennyTV ad1a7eb420 Make createFile method public 2019-02-19 17:30:58 +01:00
KennyTV bfa9b52497 Add api method to get a list of maintenance servers 2019-02-19 13:25:13 +01:00
KennyTV ff4b5b0d2e Custom maintenance events 2019-02-19 13:08:38 +01:00
KennyTV b8e73062fa Some language changes 2019-02-19 11:28:24 +01:00
KennyTV 863a9b3beb Version increase to 3.0.1-SNAPSHOT 2019-02-19 00:16:24 +01:00
KennyTV fe64936ddf Sneak Spanish language in 👀 2019-02-17 10:16:36 +01:00
135 changed files with 4140 additions and 1290 deletions

No files matched your search

+90
View File
@@ -1,6 +1,96 @@
# 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.
---
## 3.0.6 - February 17th 2021
### Changed
* Updated the Velocity version to be compatible with Velocity 1.1.0 (use Maintenance 3.0.5 if you use an older version of Velocity)
* Added `maintenance schedule <minutes> <duration> command`
* This starts a timer for maintenance to be enabled, after which another timer will be started to disable it again (in contrast to `starttimer` and `endtimer`, which each only do one of)
* On proxies, you can use `maintenance schedule [server] <minutes> <duration> command` to schedule maintenance on a proxied server
* Added command alias `mt` for the Maintenance command
* Added secret argument to the whitelist add command: You can use `maintenance add <uuid> <name>` to add offline entries per command
* The maintenance's base command is now properly registered with a permission on each platform, so that it is excluded from tabcomplection to unauthorized players
* Some improvements to the French language file (thanks to @Aurelien30000)
* API addition: Added MaintenanceReloadedEvent
* If you are using the MaintenancePlaceholderAddon, you need to [update it to 1.0.4](https://github.com/KennyTV/MaintenanceAddon/releases)
### Fixed
* Fixed not setting custom singleserver kickmessages throwing warnings
* Bungee: Fixed linebreaks in the playercount hovermessage for 1.16+ clients
---
## 3.0.5 - June 17th 2020
### Changed
* The plugin identifiers are now `Maintenance` instead of the previous `MaintenanceSpigot` and `MaintenanceBungee`,
and `maintenance` instead of `maintenancesponge` and `maintenancevelocity`
* The plugin directory will automatically be renamed accordingly when starting the server
* If you are using the MaintenancePlaceholderAddon, you need to [update it to 1.0.3](https://github.com/KennyTV/MaintenanceAddon/releases)
* Bungee/Velocity: The `fallback` field can now also be set as a list to define multiple fallback servers
* Bungee/Velocity: Added language fields to choose custom kickmessages for individual proxied servers
* See [**HERE**](https://github.com/KennyTV/Maintenance/wiki/Configuration#language-file) for an example setting
* Added Chinese language file (thanks to Spigot user yeban)
* Added Italian language file (thanks to @TheViperShow)
* Updated Russian language file (thanks to Spigot user En_0t_S)
* Removed automated config migration from 2.x->3.0
* See [**HERE**](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
### Fixed
* Fixed the `use-ssl` option being inverted
* Fixed disabling the playercount-message still hiding online/max players
* Fixed config parsing with multi line strings
* Bungee: Fixed compatibility with other motd changing plugins using the 'HIGHEST' ping listener priority
---
## 3.0.4 - March 17th 2020
### Changed
* Bungee/Velocity: Added config option `waiting-server` to send players to a waiting server when global maintenance is enabled (instead of kicking them)
* Bungee/Velocity: Added config option `use-ssl` in the `mysql` section to disable SSL connections
* Added Russian language file (thanks to Spigot user En_0t_S)
* Updated missing translations in Portuguese language file (thanks to Spigot user JoaoPinto)
* Updated bStats metrics
### Fixed
* Fixed singleserver timers using input as seconds instead of minutes (by mxs42)
* Fixed singleserver timers broadcasting globally
* Fixed language updating with an unknown/self-translated language file
* Fixed Velocity server autocompletion in the maintenance command
---
## 3.0.3 - September 17th 2019
### Changed
* Bungee/Velocity: Added `maintenance.singleserver.bypass.<server>` permission to give individual bypasses for proxied servers (`maintenance.bypass` will still bypass everything as the super-perm)
* Added the messages of the help command into the language files
* Added config option `kick-online-players` to disable the kicks when maintenance is enabled (new connections will still be blocked)... not sure why you'd want that, but you can :p
* The language file will now be automatically updated as well, so no need to delete and recreate it anymore, yay!
* Updated missing and new translations in French language file (thanks to Spigot user Zendrique)
* Updated missing and new translations in Spanish language file (thanks to Spigot user Vixo_Ulises)
### Fixed
* Bungee/Velocity: Fixed the join-notifications being sent twice if both global and server maintenance are enabled, as well as when just a server has maintenance in some cases
* Bungee: Fixed players being kicked *after* the initial connection and thus triggering a join and leave message before being kicked
* Bungee: Fixed the kickmessage not being displayed in some cases
* Paper: Fixed the playercount message not being displayed on Paper servers with ViaVersion
* Paper: Fixed the motd not being changed at all on Paper servers with ProtocolSupport (-> ProtocolLib listener used, since ProtocolSupport does not fire Paper's ping event)
* Fixed the config autoupdater when the config contained strings broken over multiple lines
---
## 3.0.2 - May 17th 2019
### Changed
* Added config option `timerspecific-pingmessages` to have specific pingmessages shown when endtimers are run
* You can also set them ingame by using `/maintenance setmotd timer <index> ...` instead of `/maintenance setmotd <index> ...`, along with `/maintenance removemotd timer <index>` and `/maintenance motd timer`
* Made dumps a little prettier
* Support Sponge 8.0.0-SNAPSHOT
* Support latest text/Velocity (now only supports Velocity builds from May 7th upwards)
---
## 3.0.1 - April 17th 2019
### Changed
* Created an addon to have PlaceholderAPI placeholders on Spigot when running the Maintenance plugin on Bungee (see [**here**](https://github.com/KennyTV/Maintenance/wiki/MaintenanceAddon))
* Spigot version: If running on Paper 1.12.2 or higher, ProtocolLib will not be needed anymore
* The universal jar now only includes Bungee and Spigot (whereas before Sponge and Velocity as well) and has been further minimized in size
* To use the plugin on the other platforms, use the `MaintenanceSponge.jar` or `MaintenanceVelocity.jar` respectively
* Added config option `continue-endtimer-after-restart` to have endtimers continued, even if the server restarts during its runtime
* Added custom eventsystem to the API
* Removed bStats metrics from Sponge module
### Fixed
* Actually fixed compatibility to other plugins using the same MySQL library (such as LuckPerms) in the Bungee version
* Fixed an issue with executing the maintenance change with MySQL enabled on connected proxies
* Fixed an occasional error on pings of non clients in the Spigot version
* Fixed 1.13 clients on sub 1.13 servers not showing the playercountmessage in the Spigot version
* Minor fixes/changes to Spanish and Portuguese language files
---
## 3.0 - February 17th 2019
### Changed
* This plugin now also supports the platforms Sponge and Velocity!
+35
View File
@@ -0,0 +1,35 @@
name: Build
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2.1.1
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-maven-
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build with Maven
run: mvn -B package --file pom.xml
- name: Upload a Build Artifact
uses: actions/upload-artifact@v2.1.4
with:
name: MaintenanceFiles
path: |
**/Maintenance.jar
**/MaintenanceSpigot.jar
**/MaintenanceBungee.jar
**/MaintenanceVelocity.jar
**/MaintenanceSponge.jar
+2 -2
View File
@@ -1,5 +1,4 @@
.metadata
dependencies/
bin/
tmp/
*.tmp
@@ -92,4 +91,5 @@ $RECYCLE.BIN/
*.msm
*.msp
*.lnk
!MaintenanceAPI.jar
!MaintenanceAPI.jar
**/src/test/resources/
+2 -2
View File
@@ -1,7 +1,7 @@
language: java
jdk:
- oraclejdk8
dist: trusty
cache:
directories:
- '$HOME/.m2'
- '$HOME/.m2/repository'
Binary file not shown.
+11 -9
View File
@@ -1,9 +1,10 @@
# Maintenance
[![Version](https://img.shields.io/github/release/KennyTV/Maintenance.svg)](https://github.com/KennyTV/Maintenance/releases)
[![Build Status](https://travis-ci.org/KennyTV/Maintenance.svg?branch=master)](https://travis-ci.org/KennyTV/Maintenance)
[![Discord](https://img.shields.io/badge/discord-online-green.svg)](https://discord.gg/vGCUzHq)
Maintenance is probably the most customizable free maintenance plugin for your Minecraft server you can find. It runs on Bukkit/Spigot, BungeeCord, Sponge as well as Velocity.
![Build Status](https://github.com/KennyTV/Maintenance/workflows/Build/badge.svg)
[![GH Downloads](https://img.shields.io/github/downloads/KennyTV/Maintenance/total)](https://github.com/KennyTV/Maintenance/releases)
[![Discord](https://img.shields.io/discord/489135856284729384.svg?label=Discord&logo=discord&logoColor=fff)](https://discord.gg/vGCUzHq)
[![Twitter](https://img.shields.io/twitter/follow/KennyTVN.svg?label=Twitter)](https://twitter.com/KennyTVN)
Maintenance is probably the most customizable free maintenance plugin for your Minecraft server you can find. It runs on Spigot, BungeeCord, Sponge, as well as Velocity.
Its features include:
* A custom motd as well as server icon, that will be shown during maintenance
@@ -14,22 +15,23 @@ Its features include:
* 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 MySQL database connection, so you don't have to change maintenance on each proxy by hand
* Use PlaceholderAPI placeholders with the [**MaintenanceAddon**](https://github.com/KennyTV/Maintenance/wiki/MaintenanceAddon) (only for Bungee)
A full list of commands, permissions and configuration options can be found in the wiki listed below.
* [Wiki](https://github.com/KennyTV/Maintenance/wiki)
* [Wiki](https://github.com/KennyTV/Maintenance/wiki) (configuration, permissions, API usage)
* [Downloads](https://github.com/KennyTV/Maintenance/releases) (GitHub)
* [Development builds](https://kennytv.eu/maintenance/snapshot/) (might be unstable)
* [Changelogs](https://github.com/KennyTV/Maintenance/blob/master/.github/CHANGELOG.md)
* [Issue tracker/bug reports](https://github.com/KennyTV/Maintenance/issues)
* [Discord](https://discord.gg/vGCUzHq)
* [PlaceholderAPI addon](https://github.com/KennyTV/Maintenance/wiki/MaintenanceAddon)
Other forums
Other forum threads
* [Spigot forums](https://www.spigotmc.org/resources/maintenance.40699/)
* [Sponge forums](https://forums.spongepowered.org/t/maintenance/27421)
* [Ore/Sponge Forums](https://ore.spongepowered.org/KennyTV/Maintenance)
* [Velocity forums](https://forums.velocitypowered.com/t/maintenance/129)
## Compiling
To create a working jar yourself, simply clone the project and compile it with maven (by using `mvn clean package` in your IDE console).
## Licence
You may only copy the code on a public repository while also keeping it under the same license (see [GNU General Public License](http://www.gnu.org/licenses/gpl-3.0)).
When modifying the project's code, do that on a public repository while also keeping it under the same license (see [GNU General Public License](http://www.gnu.org/licenses/gpl-3.0)).
+4 -4
View File
@@ -4,9 +4,9 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>eu.kennytv</groupId>
<groupId>eu.kennytv.maintenance</groupId>
<artifactId>maintenance-parent</artifactId>
<version>3.0</version>
<version>3.0.6</version>
</parent>
<artifactId>maintenance-api</artifactId>
@@ -16,13 +16,13 @@
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.13-SNAPSHOT</version>
<version>1.15-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.13.2-R0.1-SNAPSHOT</version>
<version>1.15.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -18,6 +18,8 @@
package eu.kennytv.maintenance.api;
import eu.kennytv.maintenance.api.event.manager.IEventManager;
/**
* @author KennyTV
* @since 2.1
@@ -57,4 +59,23 @@ public interface IMaintenance {
* @return {@link ISettings} instance
*/
ISettings getSettings();
/**
* Returns the {@link IEventManager} instance to register listeners to maintenance events.
*
* @return {@link IEventManager} instance
*/
IEventManager getEventManager();
/**
* @return true if debug mode is enabled, currently only implemented on Bungee
*/
boolean isDebug();
/**
* Sets the debug mode.
*
* @param debug debug state
*/
void setDebug(boolean debug);
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -52,6 +52,14 @@ public interface ISettings {
*/
Map<UUID, String> getWhitelistedPlayers();
/**
* Returns whether the uuid is whitelisted.
*
* @param uuid uuid of the player to check
* @return true if the uuid is whitelisted
*/
boolean isWhitelisted(UUID uuid);
/**
* Removes a player from the maintenance whitelist.
*
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -18,6 +18,7 @@
package eu.kennytv.maintenance.api.bungee;
import com.google.common.base.Preconditions;
import eu.kennytv.maintenance.api.IMaintenanceBase;
import eu.kennytv.maintenance.api.proxy.IMaintenanceProxy;
import net.md_5.bungee.api.ProxyServer;
@@ -41,9 +42,8 @@ public final class MaintenanceBungeeAPI {
* @throws IllegalArgumentException if using a custom (or broken?) version of the plugin, that can't be identified
*/
public static IMaintenanceProxy getAPI() {
final Plugin maintenance = ProxyServer.getInstance().getPluginManager().getPlugin("MaintenanceBungee");
if (maintenance == null)
throw new IllegalArgumentException("Could not get instance of MaintenanceBungee! Broken/custom build of the plugin?");
final Plugin maintenance = ProxyServer.getInstance().getPluginManager().getPlugin("Maintenance");
Preconditions.checkNotNull(maintenance, "Could not get instance of Maintenance! Broken/custom build of the plugin?");
return (IMaintenanceProxy) ((IMaintenanceBase) maintenance).getApi();
}
}
@@ -0,0 +1,42 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.api.event;
import eu.kennytv.maintenance.api.event.manager.MaintenanceEvent;
/**
* Notification event fired when maintenance mode has been changed.
*
* @author KennyTV
* @since 3.0.1
*/
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;
}
}
@@ -0,0 +1,34 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.api.event;
import eu.kennytv.maintenance.api.IMaintenance;
import eu.kennytv.maintenance.api.event.manager.MaintenanceEvent;
import eu.kennytv.maintenance.api.proxy.IMaintenanceProxy;
/**
* Notification event fired when Maintenance configuration is reloaded.
*
* @author KennyTV
* @see IMaintenance#isMaintenance() for the new maintenance status
* @see IMaintenanceProxy#getMaintenanceServers() for the new list of servers under maintenance
* @since 3.0.6
*/
public final class MaintenanceReloadedEvent implements MaintenanceEvent {
}
@@ -0,0 +1,36 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.api.event.manager;
/**
* Abstract class representing a maintenance eventlistener.
*
* @param <T> event to be listened to
* @author KennyTV
* @since 3.0.1
*/
public abstract class EventListener<T extends MaintenanceEvent> {
/**
* This method is to be overwritten and is called on the given event.
*
* @param event fired event
*/
public abstract void onEvent(final T event);
}
@@ -0,0 +1,41 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.api.event.manager;
/**
* @author KennyTV
* @since 3.0.1
*/
public interface IEventManager {
/**
* Registers an eventlistener for the given maintenance event.
*
* @param listener listener to register
* @param eventClass class of the event that should be registered
*/
void registerListener(EventListener listener, Class<? extends MaintenanceEvent> eventClass);
/**
* Fires a maintenance event.
*
* @param event event to fire
*/
void callEvent(MaintenanceEvent event);
}
@@ -0,0 +1,28 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.api.event.manager;
/**
* Dummy interface representing a maintenance event.
*
* @author KennyTV
* @since 3.0.1
*/
public interface MaintenanceEvent {
}
@@ -0,0 +1,57 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.api.event.proxy;
import eu.kennytv.maintenance.api.event.manager.MaintenanceEvent;
import eu.kennytv.maintenance.api.proxy.Server;
/**
* Notification event fired when maintenance mode has been changed on a proxied server.
*
* @author KennyTV
* @since 3.0.1
*/
public final class ServerMaintenanceChangedEvent implements MaintenanceEvent {
private final Server server;
private final boolean maintenance;
public ServerMaintenanceChangedEvent(final Server server, final boolean maintenance) {
this.server = server;
this.maintenance = maintenance;
}
/**
* Returns wrapped server object for the server.
* <br>
* This does not necessarily have to be an existing server:
* If maintenance is disabled on a *previously* registered server, see {@link Server#isRegisteredServer()}.
*
* @return wrapped server object for the server
*/
public Server getServer() {
return server;
}
/**
* @return true if maintenance has been enabled on the server, false otherwise
*/
public boolean isMaintenance() {
return maintenance;
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -19,6 +19,9 @@
package eu.kennytv.maintenance.api.proxy;
import eu.kennytv.maintenance.api.IMaintenance;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
/**
* @author KennyTV
@@ -58,5 +61,11 @@ public interface IMaintenanceProxy extends IMaintenance {
* @param server name of the proxied server
* @return wrapped server object if present, else null
*/
@Nullable
Server getServer(String server);
/**
* @return immutable set with names of all proxied server that are currently under maintenance
*/
Set<String> getMaintenanceServers();
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -43,4 +43,12 @@ public interface Server {
* @param message message to be broadcasted
*/
void broadcast(String message);
/**
* Returns whether the server is registered under the proxy.
* This will only ever be false if maintenance is disabled on a *previously* registered server.
*
* @return whether the server is registered under the proxy
*/
boolean isRegisteredServer();
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -18,6 +18,7 @@
package eu.kennytv.maintenance.api.spigot;
import com.google.common.base.Preconditions;
import eu.kennytv.maintenance.api.IMaintenance;
import eu.kennytv.maintenance.api.IMaintenanceBase;
import org.bukkit.Bukkit;
@@ -41,9 +42,8 @@ public final class MaintenanceSpigotAPI {
* @throws IllegalArgumentException if using a custom (or broken?) version of the plugin, that can't be identified
*/
public static IMaintenance getAPI() {
final Plugin maintenance = Bukkit.getPluginManager().getPlugin("MaintenanceSpigot");
if (maintenance == null)
throw new IllegalArgumentException("Could not get instance of MaintenanceSpigot! Broken/custom build of the plugin?");
final Plugin maintenance = Bukkit.getPluginManager().getPlugin("Maintenance");
Preconditions.checkNotNull(maintenance, "Could not get instance of Maintenance! Broken/custom build of the plugin?");
return ((IMaintenanceBase) maintenance).getApi();
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -18,6 +18,7 @@
package eu.kennytv.maintenance.api.sponge;
import com.google.common.base.Preconditions;
import eu.kennytv.maintenance.api.IMaintenance;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.plugin.PluginContainer;
@@ -42,9 +43,9 @@ public final class MaintenanceSpongeAPI {
* @throws IllegalArgumentException if using a custom (or broken?) version of the plugin, that can't be identified
*/
public static IMaintenance getAPI() {
final Optional<PluginContainer> container = Sponge.getPluginManager().getPlugin("maintenancesponge");
if (!container.isPresent() || !container.get().getInstance().isPresent())
throw new IllegalArgumentException("Could not get instance of MaintenanceSponge! Broken/custom build of the plugin?");
final Optional<PluginContainer> container = Sponge.getPluginManager().getPlugin("maintenance");
Preconditions.checkArgument(container.isPresent() && container.get().getInstance().isPresent(),
"Could not get instance of Maintenance! Broken/custom build of the plugin?");
return (IMaintenance) container.get().getInstance().get();
}
}
+36 -16
View File
@@ -4,9 +4,9 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>eu.kennytv</groupId>
<groupId>eu.kennytv.maintenance</groupId>
<artifactId>maintenance-parent</artifactId>
<version>3.0</version>
<version>3.0.6</version>
</parent>
<artifactId>maintenance-build</artifactId>
@@ -15,28 +15,48 @@
<dependencies>
<!-- Also includes maintenance-core and maintenance-core-proxy modules -->
<dependency>
<groupId>eu.kennytv</groupId>
<groupId>eu.kennytv.maintenance</groupId>
<artifactId>maintenance-bungee</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>eu.kennytv</groupId>
<groupId>eu.kennytv.maintenance</groupId>
<artifactId>maintenance-spigot</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>eu.kennytv</groupId>
<artifactId>maintenance-sponge</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>eu.kennytv</groupId>
<artifactId>maintenance-velocity</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<!-- Don't include Sponge and Velocity in main jar anymore, counters relocation errors and minimizes shading -->
</dependencies>
<!-- Needed to relocate stuff in Bungee module, but not in the core one -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>org.slf4j</pattern>
<shadedPattern>eu.kennytv.lib.slf4j</shadedPattern>
</relocation>
<relocation>
<pattern>com.zaxxer.hikari</pattern>
<shadedPattern>eu.kennytv.lib.hikari</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
+42 -4
View File
@@ -4,9 +4,9 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>eu.kennytv</groupId>
<groupId>eu.kennytv.maintenance</groupId>
<artifactId>maintenance-parent</artifactId>
<version>3.0</version>
<version>3.0.6</version>
</parent>
<artifactId>maintenance-bungee</artifactId>
@@ -14,16 +14,54 @@
<dependencies>
<dependency>
<groupId>eu.kennytv</groupId>
<groupId>eu.kennytv.maintenance</groupId>
<artifactId>maintenance-core-proxy</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<!-- Only compile slf4j on Bungee (not Velocity) to prevent relocation errors -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.13-SNAPSHOT</version>
<version>1.16-R0.4-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<!-- Needed to relocate stuff in Bungee module, but not in the core one -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>org.slf4j</pattern>
<shadedPattern>eu.kennytv.lib.slf4j</shadedPattern>
</relocation>
<relocation>
<pattern>com.zaxxer.hikari</pattern>
<shadedPattern>eu.kennytv.lib.hikari</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -25,13 +25,18 @@ import net.md_5.bungee.api.plugin.Plugin;
import java.io.File;
public final class MaintenanceBungeeBase extends Plugin implements IMaintenanceBase {
private IMaintenance maintenance;
private MaintenanceBungeePlugin maintenance;
@Override
public void onEnable() {
maintenance = new MaintenanceBungeePlugin(this);
}
@Override
public void onDisable() {
maintenance.disable();
}
@Override
public IMaintenance getApi() {
return maintenance;
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -23,7 +23,6 @@ import eu.kennytv.maintenance.api.proxy.IMaintenanceProxy;
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.PostLoginListener;
import eu.kennytv.maintenance.bungee.listener.ProxyPingListener;
import eu.kennytv.maintenance.bungee.listener.ServerConnectListener;
import eu.kennytv.maintenance.bungee.metrics.MetricsLite;
@@ -48,6 +47,7 @@ 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.jetbrains.annotations.Nullable;
import javax.imageio.ImageIO;
import java.io.File;
@@ -78,12 +78,12 @@ public final class MaintenanceBungeePlugin extends MaintenanceProxyPlugin {
sendEnableMessage();
final PluginManager pm = getProxy().getPluginManager();
pm.registerListener(plugin, new PostLoginListener(this, settingsProxy));
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 MetricsLite(plugin);
// ServerListPlus integration
@@ -113,59 +113,87 @@ public final class MaintenanceBungeePlugin extends MaintenanceProxyPlugin {
}
public boolean isMaintenance(final ServerInfo serverInfo) {
return settingsProxy.isMaintenance(new BungeeServer(serverInfo));
return settingsProxy.isMaintenance(serverInfo.getName());
}
@Override
protected void kickPlayers() {
getProxy().getPlayers().stream()
.filter(p -> !hasPermission(p, "bypass") && !settingsProxy.getWhitelistedPlayers().containsKey(p.getUniqueId()))
.forEach(p -> p.disconnect(settingsProxy.getKickMessage()));
protected void kickPlayersFromProxy() {
for (final ProxiedPlayer p : getProxy().getPlayers()) {
if (!hasPermission(p, "bypass") && !settingsProxy.isWhitelisted(p.getUniqueId())) {
p.disconnect(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).getServer() : null;
((BungeeServer) server).getServer().getPlayers().forEach(p -> {
if (!hasPermission(p, "bypass") && !settingsProxy.getWhitelistedPlayers().containsKey(p.getUniqueId())) {
if (fallbackServer != null && fallbackServer.canAccess(p) && !isMaintenance(fallback)) {
p.sendMessage(settingsProxy.getMessage("singleMaintenanceActivated").replace("%SERVER%", server.getName()));
p.connect(fallbackServer);
} else
p.disconnect(settingsProxy.getMessage("singleMaintenanceKickComplete").replace("%NEWLINE%", "\n").replace("%SERVER%", server.getName()));
final boolean checkForFallback = fallbackServer != null && !isMaintenance(fallback);
for (final ProxiedPlayer player : ((BungeeServer) server).getServer().getPlayers()) {
if (!hasPermission(player, "bypass") && !settingsProxy.isWhitelisted(player.getUniqueId())) {
if (checkForFallback && fallbackServer.canAccess(player)) {
player.sendMessage(settingsProxy.getMessage("singleMaintenanceActivated").replace("%SERVER%", server.getName()));
player.connect(fallbackServer);
} else {
player.disconnect(settingsProxy.getFullServerKickMessage(server.getName()));
}
} else {
p.sendMessage(settingsProxy.getMessage("singleMaintenanceActivated").replace("%SERVER%", server.getName()));
player.sendMessage(settingsProxy.getMessage("singleMaintenanceActivated").replace("%SERVER%", server.getName()));
}
});
}
}
@Override
protected Task startMaintenanceRunnable(final Runnable runnable) {
protected void kickPlayersTo(final Server server) {
// Kick all players to a single waiting server
final ServerInfo serverInfo = ((BungeeServer) server).getServer();
// 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)) {
player.sendMessage(settingsProxy.getMessage("sentToWaitingServer").replace("%SERVER%", server.getName()));
player.connect(serverInfo);
} else {
player.disconnect(settingsProxy.getKickMessage());
}
}
}
@Override
public Task startMaintenanceRunnable(final Runnable runnable) {
return new BungeeTask(getProxy().getScheduler().schedule(plugin, runnable, 0, 1, TimeUnit.SECONDS).getId());
}
@Override
@Nullable
public Server getServer(final String server) {
final ServerInfo serverInfo = getProxy().getServerInfo(server);
return serverInfo != null ? new BungeeServer(serverInfo) : null;
}
@Override
@Nullable
public SenderInfo getOfflinePlayer(final String name) {
final ProxiedPlayer player = getProxy().getPlayer(name);
return player != null ? new BungeeSenderInfo(player) : null;
}
@Override
@Nullable
public SenderInfo getOfflinePlayer(final UUID uuid) {
final ProxiedPlayer player = getProxy().getPlayer(uuid);
return player != null ? new BungeeSenderInfo(player) : null;
}
@Override
public String getServer(final SenderInfo sender) {
@Nullable
public String getServerNameOf(final SenderInfo sender) {
final ProxiedPlayer player = getProxy().getPlayer(sender.getUuid());
return player != null ? player.getServer().getInfo().getName() : "";
if (player == null || player.getServer() == null) return null;
return player.getServer().getInfo().getName();
}
@Override
@@ -188,6 +216,16 @@ public final class MaintenanceBungeePlugin extends MaintenanceProxyPlugin {
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);
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -23,13 +23,15 @@ import eu.kennytv.maintenance.bungee.util.BungeeSenderInfo;
import eu.kennytv.maintenance.core.proxy.SettingsProxy;
import eu.kennytv.maintenance.core.proxy.command.MaintenanceProxyCommand;
import eu.kennytv.maintenance.core.util.SenderInfo;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Map;
public final class MaintenanceBungeeCommand extends MaintenanceProxyCommand {
private final MaintenanceBungeePlugin plugin;
@@ -51,9 +53,14 @@ public final class MaintenanceBungeeCommand extends MaintenanceProxyCommand {
@Override
public List<String> getServersCompletion(final String s) {
return plugin.getProxy().getServers().entrySet().stream().filter(entry -> entry.getKey().toLowerCase().startsWith(s))
.filter(entry -> !plugin.getSettingsProxy().getMaintenanceServers().contains(entry.getValue().getName()))
.map(entry -> entry.getValue().getName()).collect(Collectors.toList());
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().startsWith(s) && !plugin.getSettingsProxy().getMaintenanceServers().contains(serverName)) {
list.add(serverName);
}
}
return list;
}
@Override
@@ -67,6 +74,10 @@ public final class MaintenanceBungeeCommand extends MaintenanceProxyCommand {
@Override
public List<String> getPlayersCompletion() {
return plugin.getProxy().getPlayers().stream().map(CommandSender::getName).collect(Collectors.toList());
final List<String> list = new ArrayList<>();
for (final ProxiedPlayer p : plugin.getProxy().getPlayers()) {
list.add(p.getName());
}
return list;
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -28,10 +28,15 @@ public final class MaintenanceBungeeCommandBase extends Command implements TabEx
private final MaintenanceCommand command;
public MaintenanceBungeeCommandBase(final MaintenanceCommand command) {
super("maintenance", "", "maintenancebungee");
super("maintenance", "maintenance.command", "maintenancebungee", "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);
@@ -1,51 +0,0 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 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.BungeeSenderInfo;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.listener.JoinListenerBase;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
public final class PostLoginListener extends JoinListenerBase implements Listener {
private final MaintenanceBungeePlugin plugin;
public PostLoginListener(final MaintenanceBungeePlugin plugin, final Settings settings) {
super(plugin, settings);
this.plugin = plugin;
}
@EventHandler
public void postLogin(final PostLoginEvent event) {
if (kickPlayer(new BungeeSenderInfo(event.getPlayer())))
event.getPlayer().disconnect(settings.getKickMessage());
}
@Override
protected void broadcastJoinNotification(final String name) {
final BaseComponent[] s = TextComponent.fromLegacyText(settings.getMessage("joinNotification").replace("%PLAYER%", name));
ProxyServer.getInstance().getPlayers().stream().filter(p -> plugin.hasPermission(p, "joinnotification")).forEach(p -> p.sendMessage(s));
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -24,7 +24,6 @@ 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;
import net.md_5.bungee.event.EventPriority;
public final class ProxyPingListener implements Listener {
private final MaintenanceBungeePlugin plugin;
@@ -35,26 +34,33 @@ public final class ProxyPingListener implements Listener {
this.settings = settings;
}
@EventHandler(priority = EventPriority.HIGHEST)
@EventHandler(priority = 80)
public void proxyPing(final ProxyPingEvent event) {
if (!settings.isMaintenance()) return;
final ServerPing ping = event.getResponse();
ServerPing.Players players = ping.getPlayers();
if (players == null) {
ping.setPlayers(players = new ServerPing.Players(0, 0, null));
}
if (settings.hasCustomPlayerCountMessage()) {
ping.getVersion().setProtocol(1);
ping.getVersion().setName(settings.getPlayerCountMessage()
.replace("%ONLINE%", Integer.toString(ping.getPlayers().getOnline()))
.replace("%MAX%", Integer.toString(ping.getPlayers().getMax())));
ping.setVersion(new ServerPing.Protocol(settings.getPlayerCountMessage()
.replace("%ONLINE%", Integer.toString(players.getOnline()))
.replace("%MAX%", Integer.toString(players.getMax())), 1));
}
ping.setDescription(settings.getRandomPingMessage());
ping.getPlayers().setOnline(0);
ping.getPlayers().setMax(0);
ping.getPlayers().setSample(new ServerPing.PlayerInfo[]{
new ServerPing.PlayerInfo(settings.getPlayerCountHoverMessage().replace("%NEWLINE%", "\n"), "")
});
if (settings.hasCustomIcon() && plugin.getFavicon() != null)
final String[] split = settings.getPlayerCountHoverMessage().split("\n");
final ServerPing.PlayerInfo[] samplePlayers = new ServerPing.PlayerInfo[split.length];
for (int i = 0; i < split.length; i++) {
samplePlayers[i] = new ServerPing.PlayerInfo(split[i], "");
}
players.setSample(samplePlayers);
if (settings.hasCustomIcon() && plugin.getFavicon() != null) {
ping.setFavicon(plugin.getFavicon());
}
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -18,55 +18,102 @@
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.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.config.ServerInfo;
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 implements Listener {
public final class ServerConnectListener extends ProxyJoinListenerBase implements Listener {
private final MaintenanceBungeePlugin plugin;
private final SettingsProxy settings;
private boolean warned;
public ServerConnectListener(final MaintenanceBungeePlugin plugin, final SettingsProxy settings) {
super(plugin, settings);
this.plugin = plugin;
this.settings = settings;
}
@EventHandler
public void serverConnect(final ServerConnectEvent event) {
final ProxiedPlayer player = event.getPlayer();
final ServerInfo target = event.getTarget();
if (!plugin.isMaintenance(target)) return;
if (plugin.hasPermission(player, "bypass") || settings.getWhitelistedPlayers().containsKey(player.getUniqueId())) return;
public void initialServerConnect(final ServerConnectEvent event) {
// Global maintenance check
if (event.isCancelled() || event.getReason() != ServerConnectEvent.Reason.JOIN_PROXY) return;
if (settings.isJoinNotifications()) {
final BaseComponent[] s = TextComponent.fromLegacyText(settings.getMessage("joinNotification").replace("%PLAYER%", player.getName()));
target.getPlayers().stream().filter(p -> plugin.hasPermission(p, "joinnotification")).forEach(p -> p.sendMessage(s));
}
// Normal serverconnect
if (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) {
player.sendMessage(settings.getMessage("singleMaintenanceKick").replace("%SERVER%", target.getName()));
event.setCancelled(true);
return;
final BungeeSenderInfo sender = new BungeeSenderInfo(event.getPlayer());
if (plugin.isDebug()) {
plugin.getLogger().info("Join permission check for " + event.getPlayer().getName()
+ " - Permission: " + sender.hasMaintenancePermission("bypass") + ", whitelist: " + settings.isWhitelisted(sender.getUuid()));
}
// If it's the initial proxy join or a kick from another server, go back to fallback server
final ServerInfo fallback = plugin.getProxy().getServerInfo(settings.getFallbackServer());
if (fallback == null || !fallback.canAccess(player) || plugin.isMaintenance(fallback)) {
player.disconnect(settings.getMessage("singleMaintenanceKickComplete").replace("%NEWLINE%", "\n").replace("%SERVER%", target.getName()));
if (!warned) {
plugin.getLogger().warning("Could not send player to the set fallback server! Instead kicking player off the network!");
warned = true;
if (shouldKick(sender)) {
final Server waitingServer = shouldConnectToWaitingServer(sender);
if (waitingServer != null) {
event.setTarget(((BungeeServer) waitingServer).getServer());
sender.sendMessage(settings.getMessage("sentToWaitingServer"));
if (plugin.isDebug()) {
plugin.getLogger().info("Join to waiting server for " + event.getPlayer().getName());
}
return;
}
event.setCancelled(true);
event.getPlayer().disconnect(settings.getKickMessage());
if (settings.isJoinNotifications()) {
broadcastJoinNotification(sender.getName());
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void serverConnect(final ServerConnectEvent event) {
// Server specific maintenance check
if (event.isCancelled()) return;
final ProxiedPlayer player = 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 ServerConnectResult connectResult = serverConnect(new BungeeSenderInfo(player), new BungeeServer(event.getTarget()), normalServerConnect);
if (plugin.isDebug()) {
plugin.getLogger().info("Connectresult for " + player.getName() + " to " + event.getTarget().getName() + ": " + connectResult);
}
if (connectResult.isCancelled()) {
event.setCancelled(true);
// Player has no server to connect to
if (player.getServer() == null) {
player.disconnect(settings.getKickMessage());
}
} else if (connectResult.getTarget() != null) {
event.setTarget(((BungeeServer) connectResult.getTarget()).getServer());
}
}
@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).getServer().getPlayers(), name);
}
private void sendJoinMessage(final Iterable<ProxiedPlayer> players, final String name) {
final BaseComponent[] message = TextComponent.fromLegacyText(settings.getMessage("joinNotification").replace("%PLAYER%", name));
for (final ProxiedPlayer player : players) {
if (plugin.hasPermission(player, "joinnotification")) {
player.sendMessage(message);
}
} else {
event.setTarget(fallback);
}
}
}
@@ -23,6 +23,7 @@ import java.util.zip.GZIPOutputStream;
public final class MetricsLite {
public static final int B_STATS_VERSION = 1;
private static final int PLUGIN_ID = 742;
private static final String URL = "https://bStats.org/submitData/bungeecord";
private final Plugin plugin;
private boolean enabled;
@@ -75,10 +76,12 @@ public final class MetricsLite {
public JsonObject getPluginData() {
final JsonObject data = new JsonObject();
final String pluginName = plugin.getDescription().getName();
//final String pluginName = plugin.getDescription().getName();
final String pluginName = "MaintenanceBungee"; // I cut off the suffix, not sure how bStats would like the name change
final String pluginVersion = plugin.getDescription().getVersion();
data.addProperty("pluginName", pluginName);
data.addProperty("id", PLUGIN_ID);
data.addProperty("pluginVersion", pluginVersion);
final JsonArray customCharts = new JsonArray();
@@ -92,8 +95,7 @@ public final class MetricsLite {
}
private JsonObject getServerData() {
int playerAmount = plugin.getProxy().getOnlineCount();
playerAmount = playerAmount > 500 ? 500 : playerAmount;
final int playerAmount = Math.min(plugin.getProxy().getOnlineCount(), 500);
final int onlineMode = plugin.getProxy().getConfig().isOnlineMode() ? 1 : 0;
final String bungeecordVersion = plugin.getProxy().getVersion();
final int managedServers = plugin.getProxy().getServers().size();
@@ -148,9 +150,9 @@ public final class MetricsLite {
}
private void loadConfig() throws IOException {
final Path configPath = plugin.getDataFolder().toPath().getParent().resolve("bStats");
configPath.toFile().mkdirs();
final File configFile = new File(configPath.toFile(), "config.yml");
final File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
bStatsFolder.mkdirs();
final File configFile = new File(bStatsFolder, "config.yml");
if (!configFile.exists()) {
writeFile(configFile,
"#bStats collects some data for plugin authors like how many servers are using their plugins.",
@@ -158,7 +160,7 @@ public final class MetricsLite {
"#This has nearly no effect on the server performance!",
"#Check out https://bStats.org/ to learn more :)",
"enabled: true",
"serverUuid: \"" + UUID.randomUUID().toString() + "\"",
"serverUuid: \"" + UUID.randomUUID() + "\"",
"logFailedRequests: false",
"logSentData: false",
"logResponseStatusText: false");
@@ -200,10 +202,7 @@ public final class MetricsLite {
if (!file.exists()) {
return null;
}
try (
final FileReader fileReader = new FileReader(file);
final BufferedReader bufferedReader = new BufferedReader(fileReader);
) {
try (final BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {
return bufferedReader.readLine();
}
}
@@ -212,10 +211,7 @@ public final class MetricsLite {
if (!file.exists()) {
file.createNewFile();
}
try (
final FileWriter fileWriter = new FileWriter(file);
final BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)
) {
try (final BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) {
for (final String line : lines) {
bufferedWriter.write(line);
bufferedWriter.newLine();
@@ -228,7 +224,7 @@ public final class MetricsLite {
throw new IllegalArgumentException("Data cannot be null");
}
if (logSentData) {
plugin.getLogger().info("Sending data to bStats: " + data.toString());
plugin.getLogger().info("Sending data to bStats: " + data);
}
final HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
@@ -244,22 +240,19 @@ public final class MetricsLite {
connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
connection.setDoOutput(true);
final DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.write(compressedData);
outputStream.flush();
outputStream.close();
try (final DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
outputStream.write(compressedData);
}
if (logResponseStatusText) {
final InputStream inputStream = connection.getInputStream();
final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
final StringBuilder builder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
try (final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
}
}
bufferedReader.close();
plugin.getLogger().info("Sent data to bStats and received response: " + builder.toString());
plugin.getLogger().info("Sent data to bStats and received response: " + builder);
} else {
connection.getInputStream().close();
}
@@ -270,9 +263,9 @@ public final class MetricsLite {
return null;
}
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final GZIPOutputStream gzip = new GZIPOutputStream(outputStream);
gzip.write(str.getBytes(StandardCharsets.UTF_8));
gzip.close();
try (final GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) {
gzip.write(str.getBytes(StandardCharsets.UTF_8));
}
return outputStream.toByteArray();
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -18,14 +18,16 @@
package eu.kennytv.maintenance.bungee.util;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.proxy.util.ProxySenderInfo;
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 SenderInfo {
public final class BungeeSenderInfo implements ProxySenderInfo {
private final CommandSender sender;
public BungeeSenderInfo(final CommandSender sender) {
@@ -60,4 +62,16 @@ public final class BungeeSenderInfo implements SenderInfo {
public void sendMessage(final TextComponent textComponent) {
sender.sendMessage(textComponent);
}
@Override
public boolean canAccess(final Server server) {
return ((BungeeServer) server).getServer().canAccess(sender);
}
@Override
public void disconnect(final String message) {
if (sender instanceof Connection) {
((Connection) sender).disconnect(message);
}
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -22,6 +22,7 @@ import eu.kennytv.maintenance.api.proxy.Server;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
public final class BungeeServer implements Server {
private final ServerInfo server;
@@ -43,7 +44,14 @@ public final class BungeeServer implements Server {
@Override
public void broadcast(final String message) {
final BaseComponent[] s = TextComponent.fromLegacyText(message);
server.getPlayers().forEach(p -> p.sendMessage(s));
for (final ProxiedPlayer p : server.getPlayers()) {
p.sendMessage(s);
}
}
@Override
public boolean isRegisteredServer() {
return true;
}
public ServerInfo getServer() {
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -1,4 +1,4 @@
name: MaintenanceBungee
name: Maintenance
version: ${project.version}
main: eu.kennytv.maintenance.bungee.MaintenanceBungeeBase
author: KennyTV
+11 -4
View File
@@ -4,9 +4,9 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>eu.kennytv</groupId>
<groupId>eu.kennytv.maintenance</groupId>
<artifactId>maintenance-parent</artifactId>
<version>3.0</version>
<version>3.0.6</version>
</parent>
<artifactId>maintenance-core-proxy</artifactId>
@@ -14,7 +14,7 @@
<dependencies>
<dependency>
<groupId>eu.kennytv</groupId>
<groupId>eu.kennytv.maintenance</groupId>
<artifactId>maintenance-core</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
@@ -22,8 +22,15 @@
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.2.0</version>
<version>3.4.2</version>
<scope>compile</scope>
<!-- Shade slf4j specifically and only in the Bungee module to prevent issues -->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -18,21 +18,26 @@
package eu.kennytv.maintenance.core.proxy;
import eu.kennytv.maintenance.api.event.proxy.ServerMaintenanceChangedEvent;
import eu.kennytv.maintenance.api.proxy.IMaintenanceProxy;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.proxy.command.MaintenanceProxyCommand;
import eu.kennytv.maintenance.core.proxy.runnable.SingleMaintenanceRunnable;
import eu.kennytv.maintenance.core.proxy.server.DummyServer;
import eu.kennytv.maintenance.core.proxy.runnable.SingleMaintenanceScheduleRunnable;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.core.util.ServerType;
import eu.kennytv.maintenance.core.util.Task;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @author KennyTV
@@ -46,19 +51,25 @@ public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implement
super(version, serverType);
}
@Override
public void disable() {
super.disable();
if (settingsProxy.getMySQL() != null) {
settingsProxy.getMySQL().close();
}
}
@Override
public void setMaintenance(final boolean maintenance) {
if (settingsProxy.hasMySQL())
if (settingsProxy.hasMySQL()) {
settingsProxy.setMaintenanceToSQL(maintenance);
settingsProxy.setMaintenance(maintenance);
settingsProxy.getConfig().set("maintenance-enabled", maintenance);
settingsProxy.saveConfig();
serverActions(maintenance);
}
super.setMaintenance(maintenance);
}
@Override
public boolean isMaintenance(final Server server) {
return settingsProxy.isMaintenance(server);
return settingsProxy.isMaintenance(server.getName());
}
@Override
@@ -73,18 +84,26 @@ public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implement
}
public void serverActions(final Server server, final boolean maintenance) {
if (server instanceof DummyServer) return;
if (maintenance) {
final Server fallback = getServer(settingsProxy.getFallbackServer());
if (fallback == null) {
if (server.hasPlayers())
getLogger().warning("The set fallback could not be found! Instead kicking players from that server off the network!");
} else if (fallback.getName().equals(server.getName()))
getLogger().warning("Maintenance has been enabled on the fallback server! If a player joins on a proxied server, they will be kicked completely instead of being sent to the fallback server!");
kickPlayers(server, fallback);
} else
server.broadcast(settingsProxy.getMessage("singleMaintenanceDeactivated").replace("%SERVER%", server.getName()));
cancelSingleTask(server);
if (server == null) return;
// Skip to the even fire for dummy servers
if (server.isRegisteredServer()) {
if (maintenance) {
final Server fallback = settingsProxy.getFallbackServer();
if (fallback == null) {
if (server.hasPlayers()) {
getLogger().warning("The set fallback could not be found! Instead kicking players from that server off the network!");
}
}
kickPlayers(server, fallback);
} else {
server.broadcast(settingsProxy.getMessage("singleMaintenanceDeactivated").replace("%SERVER%", server.getName()));
}
cancelSingleTask(server);
}
eventManager.callEvent(new ServerMaintenanceChangedEvent(server, maintenance));
}
@Override
@@ -92,22 +111,38 @@ public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implement
return serverTasks.containsKey(server.getName());
}
public void cancelSingleTask(final Server server) {
final Task task = serverTasks.remove(server.getName());
if (task != null)
task.cancel();
@Override
public Set<String> getMaintenanceServers() {
return Collections.unmodifiableSet(settingsProxy.getMaintenanceServers());
}
public MaintenanceRunnableBase startSingleMaintenanceRunnable(final Server server, final int minutes, final boolean enable) {
final MaintenanceRunnableBase runnable = new SingleMaintenanceRunnable(this, settingsProxy, minutes, enable, server);
serverTasks.put(server.getName(), startMaintenanceRunnable(runnable));
public void cancelSingleTask(final Server server) {
final Task task = serverTasks.remove(server.getName());
if (task != null) {
task.cancel();
}
}
public MaintenanceRunnableBase startSingleMaintenanceRunnable(final Server server, final long duration, final TimeUnit unit, final boolean enable) {
final MaintenanceRunnableBase runnable = new SingleMaintenanceRunnable(this, settingsProxy, (int) unit.toSeconds(duration), enable, server);
serverTasks.put(server.getName(), runnable.getTask());
return runnable;
}
public MaintenanceRunnableBase scheduleSingleMaintenanceRunnable(final Server server, final long duration, final long maintenanceDuration, final TimeUnit unit) {
final MaintenanceRunnableBase runnable = new SingleMaintenanceScheduleRunnable(this, settingsProxy,
(int) unit.toSeconds(duration), (int) unit.toSeconds(maintenanceDuration), server);
serverTasks.put(server.getName(), runnable.getTask());
return runnable;
}
@Override
public List<String> getMaintenanceServers() {
@Nullable
public List<String> getMaintenanceServersDump() {
final List<String> list = new ArrayList<>();
if (isMaintenance()) list.add("global");
if (isMaintenance()) {
list.add("global");
}
list.addAll(settingsProxy.getMaintenanceServers());
return list.isEmpty() ? null : list;
}
@@ -117,11 +152,31 @@ public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implement
return (MaintenanceProxyCommand) commandManager;
}
@Override
protected void kickPlayers() {
// Send players to waiting server is set
if (settingsProxy.getWaitingServer() != null) {
final Server waitingServer = getServer(settingsProxy.getWaitingServer());
if (waitingServer != null) {
kickPlayersTo(waitingServer);
return;
}
}
// If not set, kick players from proxy
kickPlayersFromProxy();
}
public SettingsProxy getSettingsProxy() {
return settingsProxy;
}
public abstract String getServer(SenderInfo sender);
@Nullable
public abstract String getServerNameOf(SenderInfo sender);
protected abstract void kickPlayers(Server server, Server fallback);
protected abstract void kickPlayersTo(Server server);
protected abstract void kickPlayersFromProxy();
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -22,18 +22,20 @@ 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.mysql.MySQL;
import org.jetbrains.annotations.Nullable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
public final class SettingsProxy extends Settings {
private final MaintenanceProxyPlugin plugin;
private final MaintenanceProxyPlugin proxyPlugin;
private Set<String> maintenanceServers;
private String fallbackServer;
private List<String> fallbackServers;
private String waitingServer;
private String mySQLTable;
private String serverTable;
@@ -47,22 +49,24 @@ public final class SettingsProxy extends Settings {
public SettingsProxy(final MaintenanceProxyPlugin plugin) {
super(plugin);
this.plugin = plugin;
this.proxyPlugin = plugin;
}
private void setupMySQL() throws Exception {
super.plugin.getLogger().info("Trying to open database connection...");
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(section.getString("host"),
mySQL = new MySQL(plugin.getLogger(),
section.getString("host"),
section.getInt("port"),
section.getString("username"),
section.getString("password"),
section.getString("database"));
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");
@@ -71,22 +75,30 @@ public final class SettingsProxy extends Settings {
mySQL.executeUpdate("CREATE TABLE IF NOT EXISTS " + serverTable + " (server VARCHAR(64) PRIMARY KEY)");
maintenanceQuery = "SELECT * FROM " + mySQLTable + " WHERE setting = ?";
serverQuery = "SELECT * FROM " + serverTable;
super.plugin.getLogger().info("Done!");
plugin.getLogger().info("Done!");
}
@Override
protected void loadExtraSettings() {
// Open database connection if enabled and not already done
if (!hasMySQL() && (boolean) config.getDeep("mysql.use-mysql")) {
if (!hasMySQL() && config.getBoolean("mysql.use-mysql")) {
try {
setupMySQL();
} catch (final Exception e) {
mySQL = null;
super.plugin.getLogger().log(Level.WARNING, "Error while trying do open database connection!", e);
plugin.getLogger().warning("Error while trying do open database connection!");
e.printStackTrace();
}
}
fallbackServer = config.getString("fallback", "lobby");
final Object fallback = config.getObject("fallback");
fallbackServers = fallback instanceof String ? Collections.singletonList((String) fallback) : config.getStringList("fallback");
waitingServer = config.getString("waiting-server", "");
if (waitingServer.isEmpty() || waitingServer.equalsIgnoreCase("none")) {
waitingServer = null;
}
if (hasMySQL()) {
maintenance = loadMaintenance();
maintenanceServers = loadMaintenanceServersFromSQL();
@@ -107,24 +119,52 @@ public final class SettingsProxy extends Settings {
if (hasMySQL() && System.currentTimeMillis() - lastMySQLCheck > millisecondsToCheck) {
final boolean databaseValue = loadMaintenance();
if (databaseValue != maintenance) {
plugin.serverActions(maintenance);
maintenance = databaseValue;
plugin.serverActions(maintenance);
}
lastMySQLCheck = System.currentTimeMillis();
}
return maintenance;
}
public boolean isMaintenance(final Server server) {
public boolean isMaintenance(final String serverName) {
if (hasMySQL() && System.currentTimeMillis() - lastServerCheck > millisecondsToCheck) {
final Set<String> databaseValue = loadMaintenanceServersFromSQL();
if (!databaseValue.equals(maintenanceServers)) {
plugin.serverActions(server, maintenance);
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(server.getName());
return maintenanceServers.contains(serverName);
}
public String getServerKickMessage(final String server) {
String message = language.getString("singleMaintenanceKicks." + server);
if (message == null) {
message = getMessage("singleMaintenanceKick");
}
return plugin.replacePingVariables(message).replace("%SERVER%", server);
}
// Full = being kicked from the proxy, not just a proxied server
public String getFullServerKickMessage(final String server) {
String message = language.getString("singleMaintenanceKicksComplete." + server);
if (message == null) {
message = getMessage("singleMaintenanceKickComplete");
}
return plugin.replacePingVariables(message).replace("%SERVER%", server);
}
public boolean hasMySQL() {
@@ -156,10 +196,12 @@ public final class SettingsProxy extends Settings {
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;
@@ -188,6 +230,7 @@ public final class SettingsProxy extends Settings {
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");
@@ -203,7 +246,24 @@ public final class SettingsProxy extends Settings {
return maintenanceServers;
}
public String getFallbackServer() {
return fallbackServer;
@Nullable
public Server getFallbackServer() {
for (final String fallbackServer : fallbackServers) {
final Server server = proxyPlugin.getServer(fallbackServer);
if (server != null && !isMaintenance(server.getName())) {
return server;
}
}
return null;
}
@Nullable
public String getWaitingServer() {
return waitingServer;
}
@Nullable
MySQL getMySQL() {
return mySQL;
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -25,8 +25,8 @@ import eu.kennytv.maintenance.core.proxy.SettingsProxy;
import eu.kennytv.maintenance.core.proxy.command.subcommand.*;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public abstract class MaintenanceProxyCommand extends MaintenanceCommand {
private final MaintenanceProxyPlugin plugin;
@@ -45,16 +45,23 @@ public abstract class MaintenanceProxyCommand extends MaintenanceCommand {
add(new SingleStarttimerCommand(plugin), "starttimer", "start");
add(new SingleEndtimerCommand(plugin), "endtimer", "end");
add(new SingleScheduleTimerCommand(plugin), "scheduletimer", "schedule");
add(new AbortSingleTimerCommand(plugin), "aborttimer", "abort");
}
@Override
public List<String> getMaintenanceServersCompletion(final String s) {
return settingsBungee.getMaintenanceServers().stream().filter(server -> server.toLowerCase().startsWith(s)).collect(Collectors.toList());
final List<String> list = new ArrayList<>();
for (final String server : settingsBungee.getMaintenanceServers()) {
if (server.toLowerCase().startsWith(s)) {
list.add(server);
}
}
return list;
}
public Server checkSingleTimerArgs(final SenderInfo sender, final String[] args) {
final Server server = plugin.getServer(args[1]);
public Server checkSingleTimerServerArg(final SenderInfo sender, final String serverName) {
final Server server = plugin.getServer(serverName);
if (server == null) {
sender.sendMessage(settings.getMessage("serverNotFound"));
return null;
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -25,8 +25,8 @@ import eu.kennytv.maintenance.core.proxy.SettingsProxy;
public abstract class ProxyCommandInfo extends CommandInfo {
protected final MaintenanceProxyPlugin plugin;
protected ProxyCommandInfo(final MaintenanceProxyPlugin plugin, final String permission, final String helpMessage) {
super(plugin, permission, helpMessage);
protected ProxyCommandInfo(final MaintenanceProxyPlugin plugin, final String permission) {
super(plugin, permission);
this.plugin = plugin;
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -29,7 +29,7 @@ import java.util.List;
public final class AbortSingleTimerCommand extends ProxyCommandInfo {
public AbortSingleTimerCommand(final MaintenanceProxyPlugin plugin) {
super(plugin, null, "§6/maintenance aborttimer [server] §7(If running, the current timer will be aborted)");
super(plugin, null);
}
@Override
@@ -63,7 +63,7 @@ public final class AbortSingleTimerCommand extends ProxyCommandInfo {
plugin.cancelSingleTask(server);
sender.sendMessage(getMessage("singleTimerCancelled"));
} else
sender.sendMessage(helpMessage);
sender.sendMessage(getHelpMessage());
}
@Override
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -26,11 +26,12 @@ import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
public final class SingleEndtimerCommand extends ProxyCommandInfo {
public SingleEndtimerCommand(final MaintenanceProxyPlugin plugin) {
super(plugin, null, "§6/maintenance endtimer [server] <minutes> §7(After the given time in minutes, maintenance mode will be disabled)");
super(plugin, null);
}
@Override
@@ -43,32 +44,35 @@ public final class SingleEndtimerCommand extends ProxyCommandInfo {
if (args.length == 2) {
if (checkPermission(sender, "timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[1])) {
sender.sendMessage(helpMessage);
sender.sendMessage(getHelpMessage());
return;
}
if (!plugin.isMaintenance()) {
sender.sendMessage(getMessage("alreadyDisabled"));
return;
}
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), false);
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), TimeUnit.MINUTES, false);
sender.sendMessage(getMessage("endtimerStarted").replace("%TIME%", plugin.getRunnable().getTime()));
} else if (args.length == 3) {
if (checkPermission(sender, "singleserver.timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[2], false)) {
sender.sendMessage(helpMessage);
sender.sendMessage(getHelpMessage());
return;
}
final Server server = plugin.getCommandManager().checkSingleTimerArgs(sender, args);
final Server server = plugin.getCommandManager().checkSingleTimerServerArg(sender, args[1]);
if (server == null) return;
if (!plugin.isMaintenance(server)) {
sender.sendMessage(getMessage("singleServerAlreadyDisabled").replace("%SERVER%", server.getName()));
return;
}
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), false);
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), TimeUnit.MINUTES, false);
sender.sendMessage(getMessage("endtimerStarted").replace("%TIME%", runnable.getTime()));
} else
sender.sendMessage(helpMessage);
} else {
sender.sendMessage(getHelpMessage());
}
}
@Override
@@ -0,0 +1,84 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.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.SenderInfo;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
public final class SingleScheduleTimerCommand extends ProxyCommandInfo {
public SingleScheduleTimerCommand(final MaintenanceProxyPlugin plugin) {
super(plugin, null);
}
@Override
public boolean hasPermission(final SenderInfo sender) {
return sender.hasMaintenancePermission("timer") || sender.hasPermission("maintenance.singleserver.timer");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (args.length == 3) {
if (checkPermission(sender, "timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[1])
|| plugin.getCommandManager().checkTimerArgs(sender, args[2], false)) {
sender.sendMessage(getHelpMessage());
return;
}
if (plugin.isMaintenance()) {
sender.sendMessage(getMessage("alreadyEnabled"));
return;
}
plugin.scheduleMaintenanceRunnable(Integer.parseInt(args[1]), Integer.parseInt(args[2]), TimeUnit.MINUTES);
sender.sendMessage(getMessage("starttimerStarted").replace("%TIME%", plugin.getRunnable().getTime()));
} else if (args.length == 4) {
if (checkPermission(sender, "singleserver.timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[2], false)
|| plugin.getCommandManager().checkTimerArgs(sender, args[3], false)) {
sender.sendMessage(getHelpMessage());
return;
}
final Server server = plugin.getCommandManager().checkSingleTimerServerArg(sender, args[1]);
if (server == null) return;
if (plugin.isMaintenance(server)) {
sender.sendMessage(getMessage("singleServerAlreadyEnabled").replace("%SERVER%", server.getName()));
return;
}
final MaintenanceRunnableBase runnable = plugin.scheduleSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), Integer.parseInt(args[3]), TimeUnit.MINUTES);
sender.sendMessage(getMessage("starttimerStarted").replace("%TIME%", runnable.getTime()));
} else {
sender.sendMessage(getHelpMessage());
}
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
return args.length == 2 && sender.hasMaintenancePermission("singleserver.timer") ? plugin.getCommandManager().getServersCompletion(args[1].toLowerCase()) : Collections.emptyList();
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -26,11 +26,12 @@ import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
public final class SingleStarttimerCommand extends ProxyCommandInfo {
public SingleStarttimerCommand(final MaintenanceProxyPlugin plugin) {
super(plugin, null, "§6/maintenance starttimer [server] <minutes> §7(After the given time in minutes, maintenance mode will be enabled)");
super(plugin, null);
}
@Override
@@ -43,7 +44,7 @@ public final class SingleStarttimerCommand extends ProxyCommandInfo {
if (args.length == 2) {
if (checkPermission(sender, "timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[1])) {
sender.sendMessage(helpMessage);
sender.sendMessage(getHelpMessage());
return;
}
if (plugin.isMaintenance()) {
@@ -51,26 +52,27 @@ public final class SingleStarttimerCommand extends ProxyCommandInfo {
return;
}
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), true);
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), TimeUnit.MINUTES, true);
sender.sendMessage(getMessage("starttimerStarted").replace("%TIME%", plugin.getRunnable().getTime()));
} else if (args.length == 3) {
if (checkPermission(sender, "singleserver.timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[2], false)) {
sender.sendMessage(helpMessage);
sender.sendMessage(getHelpMessage());
return;
}
final Server server = plugin.getCommandManager().checkSingleTimerArgs(sender, args);
final Server server = plugin.getCommandManager().checkSingleTimerServerArg(sender, args[1]);
if (server == null) return;
if (plugin.isMaintenance(server)) {
sender.sendMessage(getMessage("singleServerAlreadyEnabled").replace("%SERVER%", server.getName()));
return;
}
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), true);
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), TimeUnit.MINUTES, true);
sender.sendMessage(getMessage("starttimerStarted").replace("%TIME%", runnable.getTime()));
} else
sender.sendMessage(helpMessage);
} else {
sender.sendMessage(getHelpMessage());
}
}
@Override
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -30,7 +30,7 @@ import java.util.List;
public final class SingleToggleCommand extends ProxyCommandInfo {
public SingleToggleCommand(final MaintenanceProxyPlugin plugin) {
super(plugin, null, "§6/maintenance <on/off> [server] §7(Enables/disables maintenance mode)");
super(plugin, null);
}
@Override
@@ -67,12 +67,15 @@ public final class SingleToggleCommand extends ProxyCommandInfo {
}
if (plugin.setMaintenanceToServer(server, maintenance)) {
if (!sender.isPlayer() || !plugin.getServer(sender).equals(server.getName()))
if (!sender.isPlayer() || !server.getName().equals(plugin.getServerNameOf(sender))) {
sender.sendMessage(getMessage(maintenance ? "singleMaintenanceActivated" : "singleMaintenanceDeactivated").replace("%SERVER%", server.getName()));
} else
}
} else {
sender.sendMessage(getMessage(maintenance ? "singleServerAlreadyEnabled" : "singleServerAlreadyDisabled").replace("%SERVER%", server.getName()));
} else
sender.sendMessage(helpMessage);
}
} else {
sender.sendMessage(getHelpMessage());
}
}
@Override
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -25,16 +25,19 @@ import eu.kennytv.maintenance.core.util.SenderInfo;
public final class StatusCommand extends ProxyCommandInfo {
public StatusCommand(final MaintenanceProxyPlugin plugin) {
super(plugin, "singleserver.status", "§6/maintenance status §7(Lists all proxied servers, that are currently under maintenance)");
super(plugin, "singleserver.status");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (getSettings().getMaintenanceServers().isEmpty()) {
sender.sendMessage(getMessage("singleServerMaintenanceListEmpty"));
} else {
sender.sendMessage(getMessage("singleServerMaintenanceList"));
getSettings().getMaintenanceServers().forEach(server -> sender.sendMessage("§8- §b" + server));
return;
}
sender.sendMessage(getMessage("singleServerMaintenanceList"));
for (final String server : getSettings().getMaintenanceServers()) {
sender.sendMessage("§8- §b" + server);
}
}
}
@@ -0,0 +1,122 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.listener;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.listener.JoinListenerBase;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
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 org.jetbrains.annotations.Nullable;
public abstract class ProxyJoinListenerBase extends JoinListenerBase {
private static final ServerConnectResult ALLOWED = new ServerConnectResult(false);
private static final ServerConnectResult DENIED = new ServerConnectResult(true);
protected final MaintenanceProxyPlugin plugin;
protected final SettingsProxy settings;
private boolean warned;
protected ProxyJoinListenerBase(final MaintenanceProxyPlugin plugin, final SettingsProxy settings) {
super(plugin, settings);
this.plugin = plugin;
this.settings = settings;
}
/**
* @param sender joined player
* @param target target server
* @param normalServerConnect true if normal server connect, false if initial proxy join or kick
* @return connect result with data for further handling
*/
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.getUuid())) return ALLOWED;
final Server waitingServer = shouldConnectToWaitingServer(sender);
// Should never be null, but just in case
if (waitingServer == null) return DENIED;
// Player is connecting to the waiting server
if (target.getName().equals(waitingServer.getName())) return ALLOWED;
// Player already is on the waiting server
final String currentServer = plugin.getServerNameOf(sender);
if (waitingServer.getName().equals(currentServer)) {
sender.sendMessage(settings.getMessage("forceWaitingServer"));
return DENIED;
}
sender.sendMessage(settings.getMessage("sentToWaitingServer"));
return new ServerConnectResult(waitingServer);
}
// Single server maintenance
if (!settings.isMaintenance(target.getName())) return ALLOWED;
if (sender.hasMaintenancePermission("bypass") || settings.isWhitelisted(sender.getUuid())
|| sender.hasMaintenancePermission("singleserver.bypass." + target.getName().toLowerCase())) {
return ALLOWED;
}
if (settings.isJoinNotifications()) {
broadcastJoinNotification(sender.getName(), target);
}
if (normalServerConnect) {
sender.sendMessage(settings.getServerKickMessage(target.getName()));
return DENIED;
}
// If it's the initial proxy join or a kick from another server, go back to fallback server
final Server fallback = settings.getFallbackServer();
if (fallback == null || !sender.canAccess(fallback)) {
// Nothing to redirect to, player has to be kicked from the proxy
sender.disconnect(settings.getFullServerKickMessage(target.getName()));
if (!warned) {
plugin.getLogger().warning("Could not send player to the set fallback server; instead kicking player off the network!");
warned = true;
}
return DENIED;
} else {
return new ServerConnectResult(fallback);
}
}
/**
* To be called after {@link #shouldKick(SenderInfo, boolean)} to get the waiting server if present.
* Does not do any permission checks, they should be done separately!
*
* @param sender sender
* @return waiting server, null if player should be kicked
*/
@Nullable
protected Server shouldConnectToWaitingServer(final ProxySenderInfo sender) {
if (settings.getWaitingServer() == null) return null;
final Server waitingServer = plugin.getServer(settings.getWaitingServer());
if (waitingServer == null) return null;
if (!sender.canAccess(waitingServer) || settings.isMaintenance(waitingServer.getName())) return null;
return waitingServer;
}
protected abstract void broadcastJoinNotification(String name, Server server);
}
@@ -1,3 +1,21 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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;
@@ -8,19 +26,29 @@ 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;
// Excuse me and everything to do with the MySQL stuff, I have little to no idea of how to use databases
public MySQL(final String hostname, final int port, final String username, final String password, final String database) {
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);
hikariConfig.addDataSourceProperty("url", "jdbc:mysql://" + hostname + ":" + port + "/" + database);
hikariConfig.setJdbcUrl("jdbc:mysql://" + hostname + ":" + port + "/" + database);
String urlProperty = "jdbc:mysql://" + hostname + ":" + port + "/" + database;
if (!useSSL) {
urlProperty += "?useSSL=false";
}
hikariConfig.addDataSourceProperty("url", urlProperty);
hikariConfig.setJdbcUrl(urlProperty);
hikariConfig.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource");
hikariDataSource = new HikariDataSource(hikariConfig);
}
@@ -37,7 +65,7 @@ public final class MySQL {
callback.accept(preparedStatement.executeUpdate());
}
} catch (final SQLException e) {
System.out.println("Error while executing update method: " + query);
logger.log(Level.SEVERE, "Error while executing update method: " + query);
e.printStackTrace();
}
}
@@ -56,7 +84,7 @@ public final class MySQL {
resultSet.close();
}
} catch (final SQLException e) {
System.out.println("Error while executing query method: " + query);
logger.log(Level.SEVERE, "Error while executing query method: " + query);
e.printStackTrace();
}
}
@@ -65,4 +93,8 @@ public final class MySQL {
executeUpdate(query, res -> {
}, objects);
}
public void close() {
hikariDataSource.close();
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -24,26 +24,31 @@ import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
public final class SingleMaintenanceRunnable extends MaintenanceRunnableBase {
private final Server server;
public class SingleMaintenanceRunnable extends MaintenanceRunnableBase {
protected final Server server;
public SingleMaintenanceRunnable(final MaintenancePlugin plugin, final Settings settings, final int minutes, final boolean enable, final Server server) {
super(plugin, settings, minutes, enable);
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;
}
@Override
protected void broadcast(final String message) {
server.broadcast(message);
}
@Override
protected void finish() {
((IMaintenanceProxy) plugin).setMaintenanceToServer(server, enable);
}
@Override
protected String startMessageKey() {
protected String getStartMessage() {
return settings.getMessage("singleStarttimerBroadcast").replace("%TIME%", getTime()).replace("%SERVER%", server.getName());
}
@Override
protected String endMessageKey() {
protected String getEndMessage() {
return settings.getMessage("singleEndtimerBroadcast").replace("%TIME%", getTime()).replace("%SERVER%", server.getName());
}
}
@@ -0,0 +1,41 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.runnable;
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 java.util.concurrent.TimeUnit;
public final class SingleMaintenanceScheduleRunnable extends SingleMaintenanceRunnable {
private final int maintenanceDuration;
public SingleMaintenanceScheduleRunnable(final MaintenancePlugin plugin, final Settings settings, final int seconds, final int maintenanceDuration, final Server server) {
super(plugin, settings, seconds, true, server);
this.maintenanceDuration = maintenanceDuration;
}
@Override
protected void finish() {
super.finish();
((MaintenanceProxyPlugin) plugin).startSingleMaintenanceRunnable(server, maintenanceDuration, TimeUnit.SECONDS, false);
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -38,6 +38,11 @@ public final class DummyServer implements Server {
}
@Override
public void broadcast(String s) {
public void broadcast(final String s) {
}
@Override
public boolean isRegisteredServer() {
return false;
}
}
@@ -0,0 +1,29 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.util;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.util.SenderInfo;
public interface ProxySenderInfo extends SenderInfo {
boolean canAccess(Server server);
void disconnect(String message);
}
@@ -0,0 +1,54 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.util;
import eu.kennytv.maintenance.api.proxy.Server;
import org.jetbrains.annotations.Nullable;
public final class ServerConnectResult {
private final boolean cancel;
private final Server target;
public ServerConnectResult(final boolean cancel) {
this.cancel = cancel;
this.target = null;
}
public ServerConnectResult(final Server target) {
this.cancel = false;
this.target = target;
}
public boolean isCancelled() {
return cancel;
}
@Nullable
public Server getTarget() {
return target;
}
@Override
public String toString() {
return "ServerConnectResult{" +
"cancel=" + cancel +
", target=" + target +
'}';
}
}
+5 -5
View File
@@ -4,9 +4,9 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>eu.kennytv</groupId>
<groupId>eu.kennytv.maintenance</groupId>
<artifactId>maintenance-parent</artifactId>
<version>3.0</version>
<version>3.0.6</version>
</parent>
<artifactId>maintenance-core</artifactId>
@@ -14,7 +14,7 @@
<dependencies>
<dependency>
<groupId>eu.kennytv</groupId>
<groupId>eu.kennytv.maintenance</groupId>
<artifactId>maintenance-api</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
@@ -23,7 +23,7 @@
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.23</version>
<scope>compile</scope>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.minecrell</groupId>
@@ -34,7 +34,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
<version>29.0-jre</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -18,21 +18,37 @@
package eu.kennytv.maintenance.core;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.io.CharStreams;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import eu.kennytv.maintenance.api.IMaintenance;
import eu.kennytv.maintenance.api.event.MaintenanceChangedEvent;
import eu.kennytv.maintenance.api.event.manager.IEventManager;
import eu.kennytv.maintenance.core.command.MaintenanceCommand;
import eu.kennytv.maintenance.core.dump.MaintenanceDump;
import eu.kennytv.maintenance.core.dump.PluginDump;
import eu.kennytv.maintenance.core.event.EventManager;
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.SenderInfo;
import eu.kennytv.maintenance.core.util.ServerType;
import eu.kennytv.maintenance.core.util.Task;
import eu.kennytv.maintenance.core.util.Version;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
@@ -40,10 +56,12 @@ import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
public abstract class MaintenancePlugin implements IMaintenance {
protected final EventManager eventManager;
protected final Version version;
protected Settings settings;
protected ServerListPlusHook serverListPlusHook;
@@ -52,12 +70,16 @@ public abstract class MaintenancePlugin implements IMaintenance {
private final String prefix;
private final ServerType serverType;
private Version newestVersion;
private Task task;
private boolean debug;
protected MaintenancePlugin(final String version, final ServerType serverType) {
this.version = new Version(version);
this.serverType = serverType;
this.prefix = "§8[§eMaintenance" + serverType + "§8] ";
this.eventManager = new EventManager();
}
public void disable() {
}
@Override
@@ -69,47 +91,105 @@ public abstract class MaintenancePlugin implements IMaintenance {
}
public void serverActions(final boolean maintenance) {
if (isTaskRunning())
if (isTaskRunning()) {
cancelTask();
if (serverListPlusHook != null)
}
if (serverListPlusHook != null) {
serverListPlusHook.setEnabled(!maintenance);
}
if (maintenance) {
kickPlayers();
broadcast(settings.getMessage("maintenanceActivated"));
} else
if (settings.isKickOnlinePlayers()) {
kickPlayers();
}
} else {
broadcast(settings.getMessage("maintenanceDeactivated"));
}
eventManager.callEvent(new MaintenanceChangedEvent(maintenance));
}
public String formatedTimer() {
if (!isTaskRunning()) return "-";
public String replacePingVariables(String s) {
if (s.contains("%TIMER%")) {
s = s.replace("%TIMER%", getTimerMessage());
}
if (s.contains("%ONLINE%")) {
s = s.replace("%ONLINE%", Integer.toString(getOnlinePlayers()));
}
if (s.contains("%MAX%")) {
s = s.replace("%MAX%", Integer.toString(getMaxPlayers()));
}
return s;
}
public String getTimerMessage() {
if (!isTaskRunning()) return settings.getMessage("motdTimerNotRunning", "-");
final int preHours = runnable.getSecondsLeft() / 60;
final int minutes = preHours % 60;
final int seconds = runnable.getSecondsLeft() % 60;
return String.format("%02d:%02d:%02d", preHours / 60, minutes, seconds);
return settings.getMessage("motdTimer", "%HOURS%:%MINUTES%:%SECONDS%")
.replace("%HOURS%", String.format("%02d", preHours / 60))
.replace("%MINUTES%", String.format("%02d", minutes))
.replace("%SECONDS%", String.format("%02d", seconds));
}
public void startMaintenanceRunnable(final int minutes, final boolean enable) {
runnable = new MaintenanceRunnable(this, settings, minutes, enable);
task = startMaintenanceRunnable(runnable);
public void startMaintenanceRunnable(final long duration, final TimeUnit unit, final boolean enable) {
runnable = new MaintenanceRunnable(this, settings, (int) unit.toSeconds(duration), 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()));
}
}
public void scheduleMaintenanceRunnable(final long duration, final int maintenanceDuration, final TimeUnit unit) {
runnable = new MaintenanceScheduleRunnable(this, settings, (int) unit.toSeconds(duration), (int) unit.toSeconds(maintenanceDuration));
}
public boolean updateAvailable() {
checkNewestVersion();
return version.compareTo(newestVersion) == -1;
try {
checkNewestVersion();
return version.compareTo(newestVersion) == -1;
} catch (final Exception e) {
return false;
}
}
protected void continueLastEndtimer() {
if (!settings.isSaveEndtimerOnStop()) return;
if (settings.getSavedEndtimer() == 0) return;
final long current = System.currentTimeMillis();
getLogger().info("Found interrupted endtimer from last uptime...");
if (!isMaintenance()) {
getLogger().info("Maintenance has already been disabled, thus the timer has been cancelled.");
settings.setSavedEndtimer(0);
} else if (settings.getSavedEndtimer() < current) {
getLogger().info("The endtimer has already expired, maintenance has been disabled.");
setMaintenance(false);
settings.setSavedEndtimer(0);
} else {
startMaintenanceRunnable(settings.getSavedEndtimer() - current, TimeUnit.MILLISECONDS, false);
getLogger().info("The timer has been continued - maintenance will be disabled in: " + getTimerMessage());
}
}
protected void sendEnableMessage() {
getLogger().info("Plugin by KennyTV");
if (!settings.hasUpdateChecks()) return;
async(() -> {
checkNewestVersion();
try {
checkNewestVersion();
} catch (final Exception e) {
getLogger().warning("An error occured during update checking!");
return;
}
final int compare = version.compareTo(newestVersion);
if (compare == -1) {
getLogger().info("§cNewest version available: §aVersion " + newestVersion + "§c, you're on §a" + version);
} else if (compare == 1) {
if (version.getTag().equalsIgnoreCase("snapshot")) {
getLogger().info("§cYou're running a development version, please report bugs on the Discord server (https://kennytv.eu/discord) or the GitHub issue tracker (https://kennytv.eu/maintenance/issues)");
getLogger().info("§cYou'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("§cYou're running a version, that doesn't exist! §cN§ai§dc§ee§5!");
}
@@ -118,8 +198,11 @@ public abstract class MaintenancePlugin implements IMaintenance {
}
public boolean installUpdate() {
// Ore sad :(
Preconditions.checkArgument(serverType != ServerType.SPONGE);
try {
final URLConnection conn = new URL("https://github.com/KennyTV/Maintenance/releases/download/" + newestVersion + "/Maintenance.jar").openConnection();
final String fileSuffix = serverType == ServerType.VELOCITY ? "Velocity" : "";
final URLConnection conn = new URL("https://github.com/KennyTV/Maintenance/releases/download/" + newestVersion + "/Maintenance" + fileSuffix + ".jar").openConnection();
writeFile(new BufferedInputStream(conn.getInputStream()), new BufferedOutputStream(new FileOutputStream(getPluginFolder() + "Maintenance.tmp")));
final File file = new File(getPluginFolder() + "Maintenance.tmp");
final long newlength = file.length();
@@ -147,38 +230,33 @@ public abstract class MaintenancePlugin implements IMaintenance {
os.close();
}
private void checkNewestVersion() {
try {
final HttpURLConnection c = (HttpURLConnection) new URL("https://api.spigotmc.org/legacy/update.php?resource=40699").openConnection();
final BufferedReader reader = new BufferedReader(new InputStreamReader(c.getInputStream()));
private void checkNewestVersion() throws Exception {
final HttpURLConnection c = (HttpURLConnection) new URL("https://api.spigotmc.org/legacy/update.php?resource=40699").openConnection();
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(c.getInputStream()))) {
final String newVersionString = reader.readLine();
reader.close();
final Version newVersion = new Version(newVersionString);
if (!newVersion.equals(version))
if (!newVersion.equals(version)) {
newestVersion = newVersion;
} catch (final Exception ignored) {
}
}
}
public String pasteDump() {
final MaintenanceDump dump = new MaintenanceDump(this, settings);
try {
final HttpURLConnection connection = (HttpURLConnection) new URL("https://hasteb.in/documents").openConnection();
final HttpURLConnection connection = (HttpURLConnection) new URL("https://hastebin.com/documents").openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("User-Agent", "Maintenance/" + getVersion());
connection.setRequestProperty("Content-Type", "text/plain");
final GsonBuilder gsonBuilder = new GsonBuilder();
final byte[] bytes = gsonBuilder.setPrettyPrinting().create().toJson(dump).getBytes(StandardCharsets.UTF_8);
connection.setRequestProperty("Content-Length", Integer.toString(bytes.length));
final OutputStream out = connection.getOutputStream();
out.write(bytes);
out.write(gsonBuilder.disableHtmlEscaping().setPrettyPrinting().create().toJson(dump).getBytes(StandardCharsets.UTF_8));
out.close();
if (connection.getResponseCode() == 503) {
getLogger().warning("Could not paste dump, hasteb.in down?");
getLogger().warning("Could not paste dump, hastebin.com down?");
return null;
}
@@ -194,7 +272,8 @@ public abstract class MaintenancePlugin implements IMaintenance {
return jsonOutput.get("key").getAsString();
} catch (final IOException e) {
getLogger().log(Level.WARNING, "Could not paste dump :(", e);
getLogger().log(Level.WARNING, "Could not paste dump :(");
e.printStackTrace();
return null;
}
}
@@ -209,17 +288,21 @@ public abstract class MaintenancePlugin implements IMaintenance {
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();
}
}
public void cancelTask() {
task.cancel();
if (settings.isSaveEndtimerOnStop() && !runnable.shouldEnable()) {
settings.setSavedEndtimer(0);
}
runnable.getTask().cancel();
runnable = null;
task = null;
}
@Nullable
public UUID checkUUID(final SenderInfo sender, final String s) {
final UUID uuid;
try {
@@ -231,6 +314,12 @@ public abstract class MaintenancePlugin implements IMaintenance {
return uuid;
}
public String[] removeArrayIndex(final String[] args, final int index) {
final List<String> argsList = Lists.newArrayList(args);
argsList.remove(index);
return argsList.toArray(new String[0]);
}
public boolean isNumeric(final String string) {
return string.matches("[0-9]+");
}
@@ -242,7 +331,7 @@ public abstract class MaintenancePlugin implements IMaintenance {
@Override
public boolean isTaskRunning() {
return task != null && runnable != null;
return runnable != null;
}
@Override
@@ -250,15 +339,35 @@ public abstract class MaintenancePlugin implements IMaintenance {
return settings;
}
@Override
public IEventManager getEventManager() {
return eventManager;
}
@Override
public String getVersion() {
return version.toString();
}
public List<String> getMaintenanceServers() {
@Nullable
public List<String> getMaintenanceServersDump() {
return isMaintenance() ? Arrays.asList("global") : null;
}
@Override
public boolean isDebug() {
return debug;
}
@Override
public void setDebug(final boolean debug) {
this.debug = debug;
}
public int getSaltLevel() {
return Integer.MAX_VALUE;
}
public Version getNewestVersion() {
return newestVersion;
}
@@ -267,6 +376,10 @@ public abstract class MaintenancePlugin implements IMaintenance {
return prefix;
}
/**
* @see #isTaskRunning()
*/
@Nullable
public MaintenanceRunnable getRunnable() {
return runnable;
}
@@ -289,8 +402,12 @@ public abstract class MaintenancePlugin implements IMaintenance {
public abstract void sendUpdateNotification(SenderInfo sender);
public abstract Task startMaintenanceRunnable(Runnable runnable);
@Nullable
public abstract SenderInfo getOfflinePlayer(String name);
@Nullable
public abstract SenderInfo getOfflinePlayer(UUID uuid);
public abstract File getDataFolder();
@@ -307,7 +424,9 @@ public abstract class MaintenancePlugin implements IMaintenance {
protected abstract void kickPlayers();
protected abstract Task startMaintenanceRunnable(Runnable runnable);
protected abstract File getPluginFile();
protected abstract int getOnlinePlayers();
protected abstract int getMaxPlayers();
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -19,17 +19,26 @@
package eu.kennytv.maintenance.core;
import eu.kennytv.maintenance.api.ISettings;
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.util.ServerType;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.*;
import java.util.logging.Level;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
public class Settings implements ISettings {
private static final int CURRENT_CONFIG_VERSION = 4;
private static final Random RANDOM = new Random();
protected final MaintenancePlugin plugin;
private final Map<UUID, String> whitelistedPlayers = new HashMap<>();
@@ -37,6 +46,7 @@ public class Settings implements ISettings {
protected boolean maintenance;
private Set<Integer> broadcastIntervals;
private List<String> pingMessages;
private List<String> timerSpecificPingMessages;
private String playerCountMessage;
private String playerCountHoverMessage;
private String languageName;
@@ -44,7 +54,10 @@ public class Settings implements ISettings {
private boolean customMaintenanceIcon;
private boolean joinNotifications;
private boolean updateChecks;
private boolean saveEndtimerOnStop;
private boolean kickOnlinePlayers;
private boolean debug;
private long savedEndtimer;
protected Config config;
protected Config language;
@@ -53,8 +66,10 @@ public class Settings implements ISettings {
public Settings(final MaintenancePlugin plugin, final String... unsupportedFields) {
this.plugin = plugin;
this.unsupportedFields = unsupportedFields;
if (!plugin.getDataFolder().exists())
if (!plugin.getDataFolder().exists()) {
updatePluginDirectory();
plugin.getDataFolder().mkdirs();
}
createFile("config.yml");
createFile("WhitelistedPlayers.yml");
@@ -84,10 +99,21 @@ public class Settings implements ISettings {
throw new RuntimeException("Unable to load Maintenance language file!", e);
}
// Directly save colored messages
for (final Map.Entry<String, Object> entry : language.getValues().entrySet()) {
if (!(entry.getValue() instanceof String)) continue;
entry.setValue(getColoredString((String) entry.getValue()));
updateLanguageFile();
// Directly cache colored messages - this should not be saved!
transformColoredMessages(language.getValues());
plugin.getEventManager().callEvent(new MaintenanceReloadedEvent());
}
private void transformColoredMessages(final Map<String, Object> map) {
for (final Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getValue() instanceof Map) {
transformColoredMessages((Map<String, Object>) entry.getValue());
} else if (entry.getValue() instanceof String) {
entry.setValue(getColoredString(replaceNewlineVar((String) entry.getValue())));
}
}
}
@@ -99,10 +125,15 @@ public class Settings implements ISettings {
}
}
protected void createFile(final String name) {
// Public, as it is used in the MaintenanceAddon
public void createFile(final String name) {
createFile(name, name);
}
private void createFile(final String name, final String from) {
final File file = new File(plugin.getDataFolder(), name);
if (!file.exists()) {
try (final InputStream in = plugin.getResource(name)) {
try (final InputStream in = plugin.getResource(from)) {
Files.copy(in, file.toPath());
} catch (final IOException e) {
throw new RuntimeException("Unable to create " + name + " file for Maintenance!", e);
@@ -119,17 +150,19 @@ public class Settings implements ISettings {
}
private void createLanguageFile() {
final File file = new File(plugin.getDataFolder(), "language-" + languageName + ".yml");
if (!file.exists()) {
try (final InputStream in = plugin.getResource("language-" + languageName + ".yml")) {
Files.copy(in, file.toPath());
} catch (final IOException e) {
plugin.getLogger().warning("Unable to provide language " + languageName);
if (!languageName.equals("en")) {
plugin.getLogger().warning("Falling back to default language: en");
languageName = "en";
createLanguageFile();
}
final String fileName = "language-" + languageName + ".yml";
final File file = new File(plugin.getDataFolder(), fileName);
if (file.exists()) return;
try (final InputStream in = plugin.getResource(fileName)) {
Files.copy(in, file.toPath());
} catch (final IOException e) {
plugin.getLogger().warning("Unable to provide language " + languageName);
// Fall back to English language (if not already selected)
if (!languageName.equals("en")) {
plugin.getLogger().warning("Falling back to default language: en");
languageName = "en";
createLanguageFile();
}
}
}
@@ -138,120 +171,126 @@ public class Settings implements ISettings {
updateConfig();
pingMessages = config.getStringList("pingmessages");
if (config.getBoolean("enable-timerspecific-messages")) {
timerSpecificPingMessages = config.getStringList("timerspecific-pingmessages");
}
maintenance = config.getBoolean("maintenance-enabled");
customPlayerCountMessage = config.getBoolean("enable-playercountmessage");
customMaintenanceIcon = config.getBoolean("custom-maintenance-icon");
joinNotifications = config.getBoolean("send-join-notification");
broadcastIntervals = new HashSet<>(config.getIntList("timer-broadcast-for-seconds"));
if (plugin.getServerType() != ServerType.SPONGE)
if (plugin.getServerType() != ServerType.SPONGE) {
playerCountMessage = getColoredString(getConfigString("playercountmessage"));
playerCountHoverMessage = getColoredString(getConfigString("playercounthovermessage"));
}
playerCountHoverMessage = replaceNewlineVar(getColoredString(getConfigString("playercounthovermessage")));
languageName = getConfigString("language").toLowerCase();
kickOnlinePlayers = config.getBoolean("kick-online-players", true);
updateChecks = config.getBoolean("update-checks", true);
debug = config.getBoolean("debug");
final ConfigSection section = config.getSection("continue-endtimer-after-restart");
saveEndtimerOnStop = section.getBoolean("enabled");
savedEndtimer = section.getLong("end");
if (customMaintenanceIcon) {
plugin.loadMaintenanceIcon();
}
whitelistedPlayers.clear();
whitelist.getValues().forEach((key, value) -> {
for (final Map.Entry<String, Object> entry : whitelist.getValues().entrySet()) {
try {
whitelistedPlayers.put(UUID.fromString(key), (String) value);
whitelistedPlayers.put(UUID.fromString(entry.getKey()), (String) entry.getValue());
} catch (final Exception e) {
plugin.getLogger().warning("invalid WhitelistedPlayers entry: " + key);
plugin.getLogger().warning("invalid WhitelistedPlayers entry: " + entry.getKey());
}
});
}
loadExtraSettings();
}
private void updatePluginDirectory() {
// All plugin identifiers were changed to 'Maintenance' ('maintenance' for Sponge and Velocity) in 3.0.5
// Don't worry, this is only checked if no plugin folder is found
String oldDirName = "Maintenance" + plugin.getServerType();
if (plugin.getServerType() == ServerType.SPONGE || plugin.getServerType() == ServerType.VELOCITY) {
oldDirName = oldDirName.toLowerCase();
}
final File oldDir = new File(plugin.getDataFolder().getParentFile(), oldDirName);
if (!oldDir.exists()) return;
try {
Files.move(oldDir.toPath(), plugin.getDataFolder().toPath());
plugin.getLogger().info("Moved old " + oldDirName + " to new " + plugin.getDataFolder().getName() + " directory!");
} catch (final IOException e) {
plugin.getLogger().severe("Error while copying " + oldDirName + " to new " + plugin.getDataFolder().getName() + " directory!");
e.printStackTrace();
}
}
private void updateConfig() {
boolean changed = false;
// 3.0 - update config format from 2.5
if (migrateConfig(new File(plugin.getDataFolder(), "bungee-config.yml"))
|| migrateConfig(new File(plugin.getDataFolder(), "spigot-config.yml"))) {
// Also rename old language file
final File file = new File(plugin.getDataFolder(), "language-" + languageName + ".yml");
if (file.exists()) {
if (file.renameTo(new File(plugin.getDataFolder(), "language-" + languageName + ".old")))
plugin.getLogger().info("Renamed old language file!");
else
plugin.getLogger().warning("Could not rename old language file! Please rename/delete it yourself as soon as possible!");
// Update config to latest version (config version included since 3.0.1)
if (config.getInt("config-version") != CURRENT_CONFIG_VERSION) {
plugin.getLogger().info("Updating config to latest version...");
createFile("config-new.yml", "config.yml");
final File file = new File(plugin.getDataFolder(), "config-new.yml");
final Config tempConfig = new Config(file, unsupportedFields);
try {
tempConfig.load();
} catch (final IOException e) {
e.printStackTrace();
}
config.addMissingFields(tempConfig.getValues(), tempConfig.getComments());
config.set("config-version", CURRENT_CONFIG_VERSION);
file.delete();
tempConfig.clear();
changed = true;
}
// 3.0 - move SpigotServer.yml fields to config
if (plugin.getServerType() == ServerType.BUNGEE && migrateSpigotServersFile()) {
changed = true;
}
// 3.0 - move maintenace-icon from server to plugin directory
final File icon = new File("maintenance-icon.png");
if (icon.exists()) {
if (icon.renameTo(new File(plugin.getDataFolder(), "maintenance-icon.png")))
plugin.getLogger().info("Moved maintenance-icon from server directory to the plugin's directory!");
else
plugin.getLogger().warning("Could not move maintenance-icon from server directory to the plugin's directory! Please do so yourself!");
}
if (changed) {
saveConfig();
plugin.getLogger().info("Done! Updated all configs to the new format!");
plugin.getLogger().info("Done! Updated config!");
}
}
private boolean migrateConfig(final File file) {
if (!file.exists()) return false;
plugin.getLogger().info("Migrating old config to new format...");
final Config oldConfig = new Config(file);
private void updateLanguageFile() {
final String filePrefix = "language-" + languageName;
try {
oldConfig.load();
} catch (final IOException e) {
plugin.getLogger().log(Level.WARNING, "Error while trying to migrate old config file", e);
return false;
createFile(filePrefix + "-new.yml", filePrefix + ".yml");
} catch (final NullPointerException e) {
plugin.getLogger().info("Not checking for updated language strings, since there is no " + filePrefix + ".yml in the resource files (if your file is self translated and up to date, you can ignore this).");
return;
} catch (final Exception e) {
plugin.getLogger().warning("Couldn't update language file, as the " + filePrefix + ".yml could not be loaded from the resource files!");
e.printStackTrace();
return;
}
if (oldConfig.contains("pingmessage"))
config.set("pingmessages", Arrays.asList(oldConfig.getString("pingmessage")));
if (oldConfig.contains("enable-maintenance-mode"))
config.set("maintenance-enabled", oldConfig.getBoolean("enable-maintenance-mode"));
config.getValues().entrySet().forEach(entry -> {
if (!oldConfig.contains(entry.getKey())) return;
entry.setValue(oldConfig.get(entry.getKey()));
});
oldConfig.clear();
if (!file.delete())
plugin.getLogger().warning("Could not delete old config file! Please delete it as soon as possible.");
else
plugin.getLogger().info("Updated to new config file!");
return true;
}
private boolean migrateSpigotServersFile() {
final File file = new File(plugin.getDataFolder(), "SpigotServers.yml");
if (!file.exists()) return false;
final Config oldFile = new Config(file);
final File file = new File(plugin.getDataFolder(), filePrefix + "-new.yml");
final Config tempConfig = new Config(file);
try {
oldFile.load();
tempConfig.load();
} catch (final IOException e) {
plugin.getLogger().log(Level.WARNING, "Error while trying to migrate old SpigotServers file", e);
return false;
e.printStackTrace();
return;
}
if (oldFile.contains("maintenance-on"))
config.set("proxied-maintenance-servers", oldFile.getStringList("maintenance-on"));
if (oldFile.contains("fallback"))
config.set("fallback", oldFile.getString("fallback"));
oldFile.clear();
if (!file.delete())
plugin.getLogger().warning("Could not delete old SpigotServers.yml file! Please delete it as soon as possible.");
else
plugin.getLogger().info("Deleted old SpigotServers.yml file!");
return true;
final boolean updated = language.addMissingFields(tempConfig.getValues(), tempConfig.getComments());
tempConfig.clear();
file.delete();
if (updated) {
try {
language.save();
plugin.getLogger().info("Updated language file!");
} catch (final IOException e) {
e.printStackTrace();
}
}
}
private static final String ALL_CODES = "0123456789AaBbCcDdEeFfKkLlMmNnOoRr";
@@ -269,11 +308,12 @@ public class Settings implements ISettings {
}
public String getConfigString(final String path) {
if (!config.contains(path)) {
final String s = config.getString(path);
if (s == null) {
plugin.getLogger().warning("The config is missing the following string: " + path);
return "null";
}
return config.getString(path);
return s;
}
public String getMessage(final String path) {
@@ -281,17 +321,25 @@ public class Settings implements ISettings {
}
public String getMessage(final String path, final String def) {
if (!language.contains(path)) {
final String s = language.getString(path);
if (s == null) {
plugin.getLogger().warning("The language file is missing the following string: " + path);
return def;
}
return language.getString(path);
return s;
}
public String getRandomPingMessage() {
if (pingMessages.isEmpty()) return "";
final String s = pingMessages.size() > 1 ? pingMessages.get(RANDOM.nextInt(pingMessages.size())) : pingMessages.get(0);
return getColoredString(s.replace("%NEWLINE%", "\n").replace("%TIMER%", plugin.formatedTimer()));
if (plugin.isTaskRunning() && !plugin.getRunnable().shouldEnable()
&& hasTimerSpecificPingMessages() && !timerSpecificPingMessages.isEmpty()) {
return getPingMessage(timerSpecificPingMessages);
}
return pingMessages.isEmpty() ? "" : getPingMessage(pingMessages);
}
private String getPingMessage(final List<String> list) {
final String s = list.size() == 1 ? list.get(0) : list.get(RANDOM.nextInt(list.size()));
return getColoredString(replaceNewlineVar(plugin.replacePingVariables(s)));
}
@Override
@@ -306,10 +354,16 @@ public class Settings implements ISettings {
@Deprecated
@Override
public boolean removeWhitelistedPlayer(final String name) {
final Map.Entry<UUID, String> entry = whitelistedPlayers.entrySet().stream().filter(e -> e.getValue().equalsIgnoreCase(name)).findAny().orElse(null);
if (entry == null) return false;
UUID uuid = null;
for (final Map.Entry<UUID, String> e : whitelistedPlayers.entrySet()) {
if (e.getValue().equalsIgnoreCase(name)) {
uuid = e.getKey();
break;
}
}
if (uuid == null) return false;
final UUID uuid = entry.getKey();
whitelistedPlayers.remove(uuid);
whitelist.remove(uuid.toString());
saveWhitelistedPlayers();
@@ -330,6 +384,11 @@ public class Settings implements ISettings {
return whitelistedPlayers;
}
@Override
public boolean isWhitelisted(final UUID uuid) {
return whitelistedPlayers.containsKey(uuid);
}
@Override
public boolean isMaintenance() {
return maintenance;
@@ -358,29 +417,57 @@ public class Settings implements ISettings {
return updateChecks;
}
public boolean isSaveEndtimerOnStop() {
return saveEndtimerOnStop;
}
public boolean hasTimerSpecificPingMessages() {
return timerSpecificPingMessages != null;
}
public boolean isKickOnlinePlayers() {
return kickOnlinePlayers;
}
public long getSavedEndtimer() {
return savedEndtimer;
}
public void setSavedEndtimer(final long millis) {
if (savedEndtimer == millis) return;
this.savedEndtimer = millis;
config.getSection("continue-endtimer-after-restart").set("end", millis);
saveConfig();
}
public Config getConfig() {
return config;
}
// The ping messages still contain the %NEWLINE% (if they have 2 lines)
public List<String> getPingMessages() {
return pingMessages;
}
@Nullable
public List<String> getTimerSpecificPingMessages() {
return timerSpecificPingMessages;
}
public Set<Integer> getBroadcastIntervals() {
return broadcastIntervals;
}
public String getPlayerCountMessage() {
return playerCountMessage.replace("%TIMER%", plugin.formatedTimer());
return plugin.replacePingVariables(playerCountMessage);
}
public String getPlayerCountHoverMessage() {
return playerCountHoverMessage.replace("%TIMER%", plugin.formatedTimer());
return plugin.replacePingVariables(playerCountHoverMessage);
}
public String getKickMessage() {
return getMessage("kickmessage", "§cThe server is currently under maintenance!%NEWLINE%§cTry again later!")
.replace("%NEWLINE%", "\n").replace("%TIMER%", plugin.formatedTimer());
return plugin.replacePingVariables(getMessage("kickmessage"));
}
public String getLanguage() {
@@ -391,6 +478,20 @@ public class Settings implements ISettings {
return customPlayerCountMessage;
}
/*
* 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.
* ...
*
* This also happens to string lists, making those practically unreadable (in partciular the motd list), as well as confusing for most users in general.
* Because of this, I replace %NEWLINE% manually, to spare users from these ugly breaks.
*/
protected String replaceNewlineVar(final String s) {
return s.replace("%NEWLINE%", "\n");
}
protected void loadExtraSettings() {
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -21,19 +21,21 @@ 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 org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
public abstract class CommandInfo {
protected final MaintenancePlugin plugin;
protected final String helpMessage;
private final String helpMessageKey;
private final String permission;
protected CommandInfo(final MaintenancePlugin plugin, final String permission, final String helpMessage) {
protected CommandInfo(final MaintenancePlugin plugin, @Nullable final String permission) {
this.plugin = plugin;
this.permission = permission;
this.helpMessage = helpMessage;
// Just take the class name as the language key
this.helpMessageKey = "help" + getClass().getSimpleName().replace("Command", "");
}
public boolean hasPermission(final SenderInfo sender) {
@@ -41,7 +43,7 @@ public abstract class CommandInfo {
}
public String getHelpMessage() {
return helpMessage;
return getMessage(helpMessageKey);
}
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
@@ -60,7 +62,7 @@ public abstract class CommandInfo {
protected boolean checkArgs(final SenderInfo sender, final String[] args, final int length) {
if (args.length != length) {
sender.sendMessage(helpMessage);
sender.sendMessage(getHelpMessage());
return true;
}
return false;
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -20,11 +20,30 @@ package eu.kennytv.maintenance.core.command;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.command.subcommand.*;
import eu.kennytv.maintenance.core.command.subcommand.AbortTimerCommand;
import eu.kennytv.maintenance.core.command.subcommand.DebugCommand;
import eu.kennytv.maintenance.core.command.subcommand.DumpCommand;
import eu.kennytv.maintenance.core.command.subcommand.EndtimerCommand;
import eu.kennytv.maintenance.core.command.subcommand.HelpCommand;
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.SetMotdCommand;
import eu.kennytv.maintenance.core.command.subcommand.StarttimerCommand;
import eu.kennytv.maintenance.core.command.subcommand.ToggleCommand;
import eu.kennytv.maintenance.core.command.subcommand.UpdateCommand;
import eu.kennytv.maintenance.core.command.subcommand.WhitelistAddCommand;
import eu.kennytv.maintenance.core.command.subcommand.WhitelistCommand;
import eu.kennytv.maintenance.core.command.subcommand.WhitelistRemoveCommand;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.core.util.ServerType;
import java.util.*;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public abstract class MaintenanceCommand {
protected final MaintenancePlugin plugin;
@@ -55,6 +74,7 @@ public abstract class MaintenanceCommand {
add(new UpdateCommand(plugin), "update", "forceupdate");
add(new DumpCommand(plugin), "dump");
add(new DebugCommand(plugin), "debug");
}
protected void add(final CommandInfo command, final String... aliases) {
@@ -90,8 +110,17 @@ 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();
if (args.length == 1)
return commandExecutors.entrySet().stream().filter(entry -> entry.getKey().startsWith(s) && entry.getValue().hasPermission(sender)).map(Map.Entry::getKey).collect(Collectors.toList());
if (args.length == 1) {
final List<String> list = new ArrayList<>();
for (final Map.Entry<String, CommandInfo> entry : commandExecutors.entrySet()) {
final String command = entry.getKey();
if (command.startsWith(s) && entry.getValue().hasPermission(sender)) {
list.add(command);
}
}
return list;
}
final CommandInfo info = commandExecutors.get(args[0]);
return info != null && info.hasPermission(sender) ? info.getTabCompletion(sender, args) : Collections.emptyList();
}
@@ -126,14 +155,20 @@ public abstract class MaintenanceCommand {
add(new StarttimerCommand(plugin), "starttimer", "start");
add(new EndtimerCommand(plugin), "endtimer", "end");
add(new ScheduleTimerCommand(plugin), "scheduletimer", "schedule");
add(new AbortTimerCommand(plugin), "aborttimer", "abort");
}
public void checkForUpdate(final SenderInfo sender) {
if (plugin.updateAvailable()) {
sender.sendMessage(plugin.getPrefix() + "§cNewest version available: §aVersion " + plugin.getNewestVersion() + "§c, you're on §a" + plugin.getVersion());
sender.sendMessage(plugin.getPrefix() + "§c§lWARNING: §cYou will have to restart the server to prevent further issues and to complete the update! If you can't do that, don't update!");
sendUpdateMessage(sender);
// Ore sad :(
if (plugin.getServerType() != ServerType.SPONGE) {
sender.sendMessage(plugin.getPrefix() + "§c§lWARNING: §cYou will have to restart the server to prevent further issues and to complete the update! If you can't do that, don't update!");
sendUpdateMessage(sender);
} else {
sender.sendMessage(plugin.getPrefix() + "§aDownload the latest version on the Ore plugin page: §bhttps://ore.spongepowered.org/KennyTV/Maintenance");
}
} else
sender.sendMessage(plugin.getPrefix() + "§aYou already have the latest version of the plugin!");
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -25,13 +25,13 @@ import eu.kennytv.maintenance.core.util.SenderInfo;
public final class AbortTimerCommand extends CommandInfo {
public AbortTimerCommand(final MaintenancePlugin plugin) {
super(plugin, "timer", "§6/maintenance aborttimer §7(If running, the current timer will be aborted)");
super(plugin, "timer");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (args.length != 1) {
sender.sendMessage(helpMessage);
sender.sendMessage(getHelpMessage());
return;
}
@@ -0,0 +1,39 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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;
public final class DebugCommand extends CommandInfo {
public DebugCommand(final MaintenancePlugin plugin) {
super(plugin, "debug");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (checkArgs(sender, args, 1)) return;
//TODO put this and the help message into language files
plugin.setDebug(!plugin.isDebug());
sender.sendMessage("Debug mode is now " + (plugin.isDebug() ? "enabled" : "disabled"));
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -28,7 +28,7 @@ public final class DumpCommand extends CommandInfo {
private long lastDump;
public DumpCommand(final MaintenancePlugin plugin) {
super(plugin, "dump", "§6/maintenance dump §7(Dumps some server information, used for bug reports)");
super(plugin, "dump");
}
@Override
@@ -44,15 +44,17 @@ public final class DumpCommand extends CommandInfo {
plugin.async(() -> {
final String key = plugin.pasteDump();
if (key == null) {
if (sender.isPlayer())
if (sender.isPlayer()) {
sender.sendMessage(plugin.getPrefix() + "§cCould not paste dump (see the console for details)");
}
return;
}
final String url = "https://hasteb.in/" + key;
final String url = "https://hastebin.com/" + key;
sender.sendMessage(plugin.getPrefix() + "§c" + url);
if (sender.isPlayer())
if (sender.isPlayer()) {
plugin.getCommandManager().sendDumpMessage(sender, url);
}
});
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -22,17 +22,19 @@ import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.concurrent.TimeUnit;
public final class EndtimerCommand extends CommandInfo {
public EndtimerCommand(final MaintenancePlugin plugin) {
super(plugin, "timer", "§6/maintenance endtimer <minutes> §7(After the given time in minutes, maintenance mode will be disabled)");
super(plugin, "timer");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (checkArgs(sender, args, 2)) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[1])) {
sender.sendMessage(helpMessage);
sender.sendMessage(getHelpMessage());
return;
}
if (!plugin.isMaintenance()) {
@@ -40,7 +42,7 @@ public final class EndtimerCommand extends CommandInfo {
return;
}
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), false);
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), TimeUnit.MINUTES, false);
sender.sendMessage(getMessage("endtimerStarted").replace("%TIME%", plugin.getRunnable().getTime()));
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -23,34 +23,35 @@ 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.List;
import java.util.stream.Collectors;
public final class HelpCommand extends CommandInfo {
private static final int COMMANDS_PER_PAGE = 8;
public HelpCommand(final MaintenancePlugin plugin) {
super(plugin, null, "§6/maintenance help [page] §7(Shows this beautiful help window)");
super(plugin, null);
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (args.length > 2) {
sender.sendMessage(helpMessage);
sender.sendMessage(getHelpMessage());
return;
}
if (args.length == 1) {
sendUsage(sender);
} else {
if (!plugin.isNumeric(args[1])) {
sender.sendMessage(helpMessage);
return;
}
final int page = Integer.parseInt(args[1]);
sendUsage(sender, page == 0 ? 1 : page);
return;
}
if (!plugin.isNumeric(args[1])) {
sender.sendMessage(getHelpMessage());
return;
}
final int page = Integer.parseInt(args[1]);
sendUsage(sender, page == 0 ? 1 : page);
}
public void sendUsage(final SenderInfo sender) {
@@ -59,26 +60,33 @@ public final class HelpCommand extends CommandInfo {
public void sendUsage(final SenderInfo sender, final int page) {
Preconditions.checkArgument(page > 0);
final List<String> commands = plugin.getCommandManager().getCommands().stream().filter(cmd -> cmd.hasPermission(sender)).map(CommandInfo::getHelpMessage).collect(Collectors.toList());
final List<String> commands = new ArrayList<>();
for (final CommandInfo cmd : plugin.getCommandManager().getCommands()) {
if (cmd.hasPermission(sender)) {
commands.add(cmd.getHelpMessage());
}
}
if ((page - 1) * COMMANDS_PER_PAGE >= commands.size()) {
sender.sendMessage(getMessage("helpPageNotFound"));
return;
}
final List<String> filteredCommands;
if (page * COMMANDS_PER_PAGE >= commands.size())
filteredCommands = commands.subList((page - 1) * COMMANDS_PER_PAGE, commands.size());
else
filteredCommands = commands.subList((page - 1) * COMMANDS_PER_PAGE, page * COMMANDS_PER_PAGE);
final List<String> filteredCommands = commands.subList((page - 1) * COMMANDS_PER_PAGE, Math.min(page * COMMANDS_PER_PAGE, commands.size()));
final String header = "§8========[ §eMaintenance" + plugin.getServerType() + " §8| §e" + page + "/" + ((commands.size() + getDivide(commands.size())) / COMMANDS_PER_PAGE) + " §8]========";
final String header = getMessage("helpHeader").replace("%NAME%", "Maintenance" + plugin.getServerType())
.replace("%PAGE%", Integer.toString(page)).replace("%MAX%", Integer.toString((commands.size() + getDivide(commands.size())) / COMMANDS_PER_PAGE));
sender.sendMessage("");
sender.sendMessage(header);
filteredCommands.forEach(sender::sendMessage);
if (page * COMMANDS_PER_PAGE < commands.size())
sender.sendMessage("§7Use §b/maintenance help " + (page + 1) + " §7to get to the next help window.");
else
for (final String command : filteredCommands) {
sender.sendMessage(command);
}
if (page * COMMANDS_PER_PAGE < commands.size()) {
sender.sendMessage(getMessage("helpNextPage").replace("%PAGE%", Integer.toString(page + 1)));
} else {
sender.sendMessage("§8× §eVersion " + plugin.getVersion() + " §7by §bKennyTV");
}
sender.sendMessage(header);
sender.sendMessage("");
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -22,22 +22,50 @@ 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 MotdCommand extends CommandInfo {
public MotdCommand(final MaintenancePlugin plugin) {
super(plugin, "motd", "§6/maintenance motd §7(Lists the currently set maintenance motds)");
super(plugin, "motd");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (checkArgs(sender, args, 1)) return;
if (args.length == 1) {
sendList(sender, getSettings().getPingMessages());
} else if (args.length == 2 && args[1].equalsIgnoreCase("timer")) {
if (!getSettings().hasTimerSpecificPingMessages()) {
sender.sendMessage(getMessage("timerMotdDisabled"));
return;
}
sendList(sender, getSettings().getTimerSpecificPingMessages());
} else {
sender.sendMessage(getHelpMessage());
}
}
private void sendList(final SenderInfo sender, final List<String> list) {
if (list == null || list.isEmpty()) {
sender.sendMessage(getMessage("motdListEmpty"));
return;
}
sender.sendMessage(getMessage("motdList"));
for (int i = 0; i < getSettings().getPingMessages().size(); i++) {
for (int i = 0; i < list.size(); i++) {
sender.sendMessage("§b" + (i + 1) + "§8§m---------");
for (final String motd : getSettings().getColoredString(getSettings().getPingMessages().get(i)).split("%NEWLINE%")) {
for (final String motd : getSettings().getColoredString(list.get(i)).split("%NEWLINE%")) {
sender.sendMessage(motd);
}
}
sender.sendMessage("§8§m----------");
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
if (args.length != 2 || !getSettings().hasTimerSpecificPingMessages()) return Collections.emptyList();
return Collections.singletonList("timer");
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -25,7 +25,7 @@ import eu.kennytv.maintenance.core.util.SenderInfo;
public final class ReloadCommand extends CommandInfo {
public ReloadCommand(final MaintenancePlugin plugin) {
super(plugin, "reload", "§6/maintenance reload §7(Reloads the config file, whitelist file and the server-icon)");
super(plugin, "reload");
}
@Override
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -30,44 +30,57 @@ import java.util.List;
public final class RemoveMotdCommand extends CommandInfo {
public RemoveMotdCommand(final MaintenancePlugin plugin) {
super(plugin, "setmotd", "§6/maintenance removemotd <index> §7(Removes a maintenance motd)");
super(plugin, "setmotd");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
public void execute(final SenderInfo sender, String[] args) {
boolean timerPingMessages = false;
if (args.length == 3 && args[1].equalsIgnoreCase("timer")) {
if (!getSettings().hasTimerSpecificPingMessages()) {
sender.sendMessage(getMessage("timerMotdDisabled"));
return;
}
args = plugin.removeArrayIndex(args, 1);
timerPingMessages = true;
}
if (checkArgs(sender, args, 2)) return;
if (!plugin.isNumeric(args[1])) {
sender.sendMessage(helpMessage);
sender.sendMessage(getHelpMessage());
return;
}
final Settings settings = getSettings();
if (settings.getPingMessages().size() < 2) {
final List<String> pingMessages = timerPingMessages ? settings.getTimerSpecificPingMessages() : settings.getPingMessages();
if (pingMessages.size() < 2) {
sender.sendMessage(getMessage("removeMotdError"));
return;
}
final int index = Integer.parseInt(args[1]);
if (index == 0 || index > settings.getPingMessages().size()) {
sender.sendMessage(getMessage("setMotdIndexError").replace("%MOTDS%", Integer.toString(settings.getPingMessages().size()))
.replace("%NEWAMOUNT%", Integer.toString(settings.getPingMessages().size())));
if (index == 0 || index > pingMessages.size()) {
sender.sendMessage(getMessage("setMotdIndexError").replace("%MOTDS%", Integer.toString(pingMessages.size()))
.replace("%NEWAMOUNT%", Integer.toString(pingMessages.size())));
return;
}
settings.getPingMessages().remove(index - 1);
settings.getConfig().set("pingmessages", settings.getPingMessages());
pingMessages.remove(index - 1);
settings.getConfig().set(timerPingMessages ? "timerspecific-pingmessages" : "pingmessages", pingMessages);
settings.saveConfig();
sender.sendMessage(getMessage("removedMotd").replace("%INDEX%", args[1]));
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
if (args.length != 2) return Collections.emptyList();
final int size = plugin.getSettings().getPingMessages().size();
final List<String> list = new ArrayList<>(size);
for (int i = 1; i <= size; i++) {
list.add(String.valueOf(i));
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 list;
return Collections.emptyList();
}
}
@@ -0,0 +1,49 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.concurrent.TimeUnit;
public final class ScheduleTimerCommand extends CommandInfo {
public ScheduleTimerCommand(final MaintenancePlugin plugin) {
super(plugin, "timer");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (checkArgs(sender, args, 3)) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[1])
|| plugin.getCommandManager().checkTimerArgs(sender, args[2], false)) {
sender.sendMessage(getHelpMessage());
return;
}
if (plugin.isMaintenance()) {
sender.sendMessage(getMessage("alreadyEnabled"));
return;
}
plugin.scheduleMaintenanceRunnable(Integer.parseInt(args[1]), Integer.parseInt(args[2]), TimeUnit.MINUTES);
sender.sendMessage(getMessage("starttimerStarted").replace("%TIME%", plugin.getRunnable().getTime()));
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -31,21 +31,33 @@ import java.util.List;
public final class SetMotdCommand extends CommandInfo {
public SetMotdCommand(final MaintenancePlugin plugin) {
super(plugin, "setmotd", "§6/maintenance setmotd <index> <1/2> <message> §7(Sets a motd for maintenance mode)");
super(plugin, "setmotd");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
public void execute(final SenderInfo sender, String[] args) {
boolean timerPingMessages = false;
if (args.length > 1 && args[1].equalsIgnoreCase("timer")) {
if (!getSettings().hasTimerSpecificPingMessages()) {
sender.sendMessage(getMessage("timerMotdDisabled"));
return;
}
// remove the "timer" off the args to keep the rest the code cleaner
args = plugin.removeArrayIndex(args, 1);
timerPingMessages = true;
}
if (args.length < 4 || !plugin.isNumeric(args[1])) {
sender.sendMessage(helpMessage);
sender.sendMessage(getHelpMessage());
return;
}
final Settings settings = getSettings();
final List<String> pingMessages = timerPingMessages ? settings.getTimerSpecificPingMessages() : settings.getPingMessages();
final int index = Integer.parseInt(args[1]);
if (index == 0 || index > settings.getPingMessages().size() + 1) {
sender.sendMessage(getMessage("setMotdIndexError").replace("%MOTDS%", Integer.toString(settings.getPingMessages().size()))
.replace("%NEWAMOUNT%", Integer.toString(settings.getPingMessages().size() + 1)));
if (index == 0 || index > pingMessages.size() + 1) {
sender.sendMessage(getMessage("setMotdIndexError").replace("%MOTDS%", Integer.toString(pingMessages.size()))
.replace("%NEWAMOUNT%", Integer.toString(pingMessages.size() + 1)));
return;
}
@@ -61,31 +73,39 @@ public final class SetMotdCommand extends CommandInfo {
}
final String message = String.join(" ", Arrays.copyOfRange(args, 3, args.length));
final String oldMessage = index > settings.getPingMessages().size() ? "" : settings.getPingMessages().get(index - 1);
final String oldMessage = index > pingMessages.size() ? "" : pingMessages.get(index - 1);
final String newMessage;
if (line == 1)
if (line == 1) {
newMessage = oldMessage.contains("%NEWLINE%") ?
message + "%NEWLINE%" + oldMessage.split("%NEWLINE%", 2)[1] : message;
else
} else {
newMessage = oldMessage.contains("%NEWLINE%") ?
oldMessage.split("%NEWLINE%", 2)[0] + "%NEWLINE%" + message : oldMessage + "%NEWLINE%" + message;
}
if (index > settings.getPingMessages().size())
settings.getPingMessages().add(newMessage);
else
settings.getPingMessages().set(index - 1, newMessage);
settings.getConfig().set("pingmessages", settings.getPingMessages());
if (index > pingMessages.size()) {
pingMessages.add(newMessage);
} else {
pingMessages.set(index - 1, newMessage);
}
settings.getConfig().set(timerPingMessages ? "timerspecific-pingmessages" : "pingmessages", pingMessages);
settings.saveConfig();
sender.sendMessage(settings.getMessage("setMotd").replace("%LINE%", args[2]).replace("%INDEX%", args[1])
.replace("%MOTD%", "§f" + settings.getColoredString(message)));
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
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;
}
if (args.length == 3) return Arrays.asList("1", "2");
if (args.length == 2) {
final List<String> list = new ArrayList<>();
for (int i = 1; i <= getSettings().getPingMessages().size() + 1; i++) {
for (int i = 1; i <= (timer ? getSettings().getTimerSpecificPingMessages() : getSettings().getPingMessages()).size() + 1; i++) {
list.add(String.valueOf(i));
}
return list;
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -22,17 +22,19 @@ import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.concurrent.TimeUnit;
public final class StarttimerCommand extends CommandInfo {
public StarttimerCommand(final MaintenancePlugin plugin) {
super(plugin, "timer", "§6/maintenance starttimer <minutes> §7(After the given time in minutes, maintenance mode will be enabled)");
super(plugin, "timer");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (checkArgs(sender, args, 2)) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[1])) {
sender.sendMessage(helpMessage);
sender.sendMessage(getHelpMessage());
return;
}
if (plugin.isMaintenance()) {
@@ -40,7 +42,7 @@ public final class StarttimerCommand extends CommandInfo {
return;
}
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), true);
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), TimeUnit.MINUTES, true);
sender.sendMessage(getMessage("starttimerStarted").replace("%TIME%", plugin.getRunnable().getTime()));
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -25,7 +25,7 @@ import eu.kennytv.maintenance.core.util.SenderInfo;
public final class ToggleCommand extends CommandInfo {
public ToggleCommand(final MaintenancePlugin plugin) {
super(plugin, "toggle", "§6/maintenance <on/off> §7(Enables/disables maintenance mode)");
super(plugin, "toggle");
}
@Override
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -21,11 +21,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.core.util.ServerType;
public final class UpdateCommand extends CommandInfo {
public UpdateCommand(final MaintenancePlugin plugin) {
super(plugin, "update", "§6/maintenance update §7(Remotely downloads the newest version of the plugin onto your server)");
super(plugin, "update");
}
@Override
@@ -38,12 +39,18 @@ public final class UpdateCommand extends CommandInfo {
sender.sendMessage(plugin.getPrefix() + "§aYou already have the latest version of the plugin!");
return;
}
// Ore very sad :(
if (plugin.getServerType() == ServerType.SPONGE) {
sender.sendMessage(plugin.getPrefix() + "§cSorry, automated downloading of the plugin is not supported on Sponge! Please download the latest version manually! :(");
return;
}
sender.sendMessage(getMessage("updateDownloading"));
if (plugin.installUpdate())
if (plugin.installUpdate()) {
sender.sendMessage(getMessage("updateFinished"));
else
} else {
sender.sendMessage(getMessage("updateFailed"));
}
}
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -20,6 +20,7 @@ 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.DummySenderInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.Collections;
@@ -29,18 +30,33 @@ import java.util.UUID;
public final class WhitelistAddCommand extends CommandInfo {
public WhitelistAddCommand(final MaintenancePlugin plugin) {
super(plugin, "whitelist.add", "§6/maintenance add <name/uuid> §7(Adds the player to the maintenance whitelist, so they can join the server even though maintenance is enabled)");
super(plugin, "whitelist.add");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (checkArgs(sender, args, 2)) return;
if (args[1].length() == 36) {
if (args.length == 2) {
if (args[1].length() == 36) {
final UUID uuid = plugin.checkUUID(sender, args[1]);
if (uuid != null) {
addPlayerToWhitelist(sender, uuid);
}
} else {
addPlayerToWhitelist(sender, args[1]);
}
} else if (args.length == 3) {
if (args[1].length() != 36) {
sender.sendMessage(getHelpMessage());
return;
}
final UUID uuid = plugin.checkUUID(sender, args[1]);
if (uuid != null)
addPlayerToWhitelist(sender, uuid);
} else
addPlayerToWhitelist(sender, args[1]);
if (uuid != null) {
addPlayerToWhitelist(sender, new DummySenderInfo(uuid, args[2]));
}
} else {
sender.sendMessage(getHelpMessage());
}
}
@Override
@@ -55,7 +71,7 @@ public final class WhitelistAddCommand extends CommandInfo {
return;
}
whitelistAddMessage(sender, selected);
addPlayerToWhitelist(sender, selected);
}
private void addPlayerToWhitelist(final SenderInfo sender, final UUID uuid) {
@@ -65,13 +81,14 @@ public final class WhitelistAddCommand extends CommandInfo {
return;
}
whitelistAddMessage(sender, selected);
addPlayerToWhitelist(sender, selected);
}
private void whitelistAddMessage(final SenderInfo sender, final SenderInfo selected) {
if (getSettings().addWhitelistedPlayer(selected.getUuid(), selected.getName()))
private void addPlayerToWhitelist(final SenderInfo sender, final SenderInfo selected) {
if (getSettings().addWhitelistedPlayer(selected.getUuid(), selected.getName())) {
sender.sendMessage(getMessage("whitelistAdded").replace("%PLAYER%", selected.getName()));
else
} else {
sender.sendMessage(getMessage("whitelistAlreadyAdded").replace("%PLAYER%", selected.getName()));
}
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -28,7 +28,7 @@ import java.util.UUID;
public final class WhitelistCommand extends CommandInfo {
public WhitelistCommand(final MaintenancePlugin plugin) {
super(plugin, "whitelist.list", "§6/maintenance whitelist §7(Shows all whitelisted players for the maintenance mode)");
super(plugin, "whitelist.list");
}
@Override
@@ -38,11 +38,15 @@ public final class WhitelistCommand extends CommandInfo {
final Map<UUID, String> players = getSettings().getWhitelistedPlayers();
if (players.isEmpty()) {
sender.sendMessage(getMessage("whitelistEmpty"));
} else {
sender.sendMessage(getMessage("whitelistedPlayers"));
final String format = getMessage("whitelistedPlayersFormat");
players.forEach((key, value) -> sender.sendMessage(format.replace("%NAME%", value).replace("%UUID%", key.toString())));
sender.sendMessage("");
return;
}
sender.sendMessage(getMessage("whitelistedPlayers"));
final String format = getMessage("whitelistedPlayersFormat");
for (final Map.Entry<UUID, String> entry : players.entrySet()) {
sender.sendMessage(format.replace("%NAME%", entry.getValue()).replace("%UUID%", entry.getKey().toString()));
}
sender.sendMessage("");
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -22,15 +22,15 @@ 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.UUID;
import java.util.stream.Collectors;
public final class WhitelistRemoveCommand extends CommandInfo {
public WhitelistRemoveCommand(final MaintenancePlugin plugin) {
super(plugin, "whitelist.remove", "§6/maintenance remove <name/uuid> §7(Removes the player from the maintenance whitelist)");
super(plugin, "whitelist.remove");
}
@Override
@@ -38,43 +38,55 @@ public final class WhitelistRemoveCommand extends CommandInfo {
if (checkArgs(sender, args, 2)) return;
if (args[1].length() == 36) {
final UUID uuid = plugin.checkUUID(sender, args[1]);
if (uuid != null)
if (uuid != null) {
removePlayerFromWhitelist(sender, uuid);
} else
}
} else {
removePlayerFromWhitelist(sender, args[1]);
}
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
return args.length == 2 ? getSettings().getWhitelistedPlayers().values().stream()
.filter(name -> name.toLowerCase().startsWith(args[1])).collect(Collectors.toList()) : Collections.emptyList();
if (args.length != 2) return Collections.emptyList();
final List<String> list = new ArrayList<>();
for (final String name : getSettings().getWhitelistedPlayers().values()) {
if (name.toLowerCase().startsWith(args[1])) {
list.add(name);
}
}
return list;
}
private void removePlayerFromWhitelist(final SenderInfo sender, final String name) {
final SenderInfo selected = plugin.getOfflinePlayer(name);
if (selected == null) {
if (getSettings().removeWhitelistedPlayer(name))
if (getSettings().removeWhitelistedPlayer(name)) {
sender.sendMessage(getMessage("whitelistRemoved").replace("%PLAYER%", name));
else
} else {
sender.sendMessage(getMessage("whitelistNotFound"));
}
return;
}
whitelistRemoveMessage(sender, selected.getUuid(), selected.getName());
removePlayerFromWhitelist(sender, selected.getUuid(), selected.getName());
}
private void removePlayerFromWhitelist(final SenderInfo sender, final UUID uuid) {
final SenderInfo selected = plugin.getOfflinePlayer(uuid);
if (selected == null)
whitelistRemoveMessage(sender, uuid, uuid.toString());
else
whitelistRemoveMessage(sender, selected.getUuid(), selected.getName());
if (selected == null) {
removePlayerFromWhitelist(sender, uuid, uuid.toString());
} else {
removePlayerFromWhitelist(sender, selected.getUuid(), selected.getName());
}
}
private void whitelistRemoveMessage(final SenderInfo sender, final UUID uuid, final String toReplace) {
if (getSettings().removeWhitelistedPlayer(uuid))
private void removePlayerFromWhitelist(final SenderInfo sender, final UUID uuid, final String toReplace) {
if (getSettings().removeWhitelistedPlayer(uuid)) {
sender.sendMessage(getMessage("whitelistRemoved").replace("%PLAYER%", toReplace));
else
} else {
sender.sendMessage(getMessage("whitelistNotFound"));
}
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -18,6 +18,8 @@
package eu.kennytv.maintenance.core.config;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.Nullable;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
@@ -25,7 +27,11 @@ import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
/**
* Further modified version of the SimpleConfig project of PSandro (https://github.com/PSandro/SimpleConfig).
@@ -53,8 +59,9 @@ public final class Config extends ConfigSection {
private String header;
public Config(final File file, final String... unsupportedFields) {
super(null, "");
this.file = file;
this.unsupportedFields = new HashSet<>(Arrays.asList(unsupportedFields));
this.unsupportedFields = unsupportedFields.length == 0 ? Collections.emptySet() : Sets.newHashSet(unsupportedFields);
}
public void load() throws IOException {
@@ -62,26 +69,27 @@ public final class Config extends ConfigSection {
final Map<String, Object> map = yaml.load(data);
this.values = map != null ? map : new LinkedHashMap<>();
this.comments = ConfigSerializer.deserializeComments(data);
if (comments.containsKey(".header"))
this.header = String.join("\n", comments.remove(".header"));
final String[] header = comments.remove(".header");
if (header != null) {
this.header = String.join("\n", header);
}
final boolean removedFields = values.keySet().removeIf(key -> {
final String[] split = key.split("\\.");
String splitKey = "";
boolean remove = false;
for (final String s : split) {
splitKey += s;
if (!unsupportedFields.contains(splitKey)) {
splitKey += ".";
continue;
}
remove = true;
break;
}
if (remove)
// Unsupported field
comments.remove(key);
return remove;
return true;
}
return false;
});
if (removedFields) {
save();
@@ -89,49 +97,42 @@ public final class Config extends ConfigSection {
}
public void save() throws IOException {
final byte[] bytes = this.saveConfigToString().getBytes(StandardCharsets.UTF_8);
this.file.getParentFile().mkdirs();
this.file.createNewFile();
Files.write(this.file.toPath(), bytes);
saveTo(file);
}
@Override
public void set(final String key, final Object value, final String... comments) {
if (value == null) {
remove(key);
} else {
this.values.put(key, value);
this.comments.put(key, comments);
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.write(file.toPath(), bytes);
}
@Override
public void remove(final String key) {
this.values.remove(key);
this.comments.remove(key);
}
public boolean addMissingFields(final Map<String, Object> fields, final Map<String, String[]> comments) {
// Note: Only scans for the first two levels
boolean changed = false;
for (final Map.Entry<String, Object> entry : fields.entrySet()) {
final Object o = values.get(entry.getKey());
if (o != null) {
final Object o2 = entry.getValue();
if (!(o instanceof Map) || !(o2 instanceof Map)) continue;
/**
* Convenience method, not further established as currently not necessary.
*
* @see #getSection(String)
* @deprecated this config is only made for a quite simple use, only goes one level deeper
*/
@Deprecated
public Object getDeep(final String key) {
final String[] split = key.split("\\.", 2);
if (split.length != 2) return get(key);
final Map<String, Object> deepMap = (Map<String, Object>) o2;
for (final Map.Entry<String, Object> deepEntry : ((Map<String, Object>) o2).entrySet()) {
if (deepMap.containsKey(deepEntry.getKey())) continue;
deepMap.put(deepEntry.getKey(), deepEntry.getValue());
changed = true;
}
continue;
}
final Object o = getObject(split[0]);
if (!(o instanceof Map)) return null;
values.put(entry.getKey(), entry.getValue());
changed = true;
}
final Map<String, Object> map = (Map<String, Object>) o;
return map.get(split[1]);
}
public ConfigSection getSection(final String key) {
final Object o = getObject(key);
return o instanceof Map ? new ConfigSection((Map<String, Object>) o) : null;
this.comments = new HashMap<>(comments);
return changed;
}
private static Yaml createYaml() {
@@ -139,13 +140,10 @@ public final class Config extends ConfigSection {
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
options.setPrettyFlow(false);
options.setIndent(2);
options.setWidth(10_000); // be sneaky because autobreak on saving looks disgusting
return new Yaml(options);
}
public String saveConfigToString() {
return ConfigSerializer.serialize(this.header, this.values, this.comments, this.yaml);
}
public void clear() {
this.values.clear();
this.comments.clear();
@@ -160,6 +158,12 @@ public final class Config extends ConfigSection {
return unsupportedFields;
}
@Override
public Config getRoot() {
return this;
}
@Nullable
public String getHeader() {
return header;
}
@@ -168,5 +172,8 @@ public final class Config extends ConfigSection {
this.header = AWESOME_HEADER;
}
@Override
public String toString() {
return ConfigSerializer.serialize(this.header, this.values, this.comments, this.yaml);
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -18,6 +18,8 @@
package eu.kennytv.maintenance.core.config;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -30,54 +32,88 @@ import java.util.Set;
*/
public class ConfigSection {
protected final Config root;
protected final String currentPath;
protected Map<String, Object> values;
ConfigSection() {
this(new HashMap<>());
ConfigSection(final Config root, final String currentPath) {
this(root, currentPath, new HashMap<>());
}
ConfigSection(final Map<String, Object> values) {
ConfigSection(final Config root, final String currentPath, final Map<String, Object> values) {
this.root = root;
this.currentPath = currentPath;
this.values = values;
}
@Nullable
public <E> E get(final String key) {
return (E) this.values.get(key);
return (E) getObject(key);
}
@Nullable
public <E> E get(final String key, @Nullable final E def) {
final Object o = getObject(key);
return o != null ? (E) o : def;
}
@Nullable
public Object getObject(final String key) {
return this.values.get(key);
return getObject(key, null);
}
public <E> E getOrSet(final String key, final E def) {
if (this.values.containsKey(key)) {
return (E) this.values.get(key);
@Nullable
public Object getObject(final String key, final Object def) {
int i1 = -1;
int i2;
ConfigSection section = this;
while ((i1 = key.indexOf('.', i2 = i1 + 1)) != -1) {
section = section.getSection(key.substring(i2, i1));
if (section == null) return def;
}
final String subKey = key.substring(i2);
if (section == this) {
final Object result = values.get(subKey);
return result != null ? result : def;
}
return section.getObject(subKey, def);
}
@Nullable
public <E> E getOrSet(final String key, @Nullable final E def) {
final Object o = getObject(key);
if (o != null) {
return (E) o;
} else {
this.set(key, def);
return def;
}
}
@Nullable
public ConfigSection getSection(final String key) {
final Object o = getObject(key);
if (!(o instanceof Map)) return null;
return new ConfigSection(getRoot(), getFullKeyInPath(key), (Map<String, Object>) o);
}
public boolean contains(final String key) {
return this.values.containsKey(key);
return getObject(key) != null;
}
public void set(final String key, final Object value) {
public void set(final String key, @Nullable final Object value) {
//TODO go deep if necessary
if (value == null) {
remove(key);
} else
this.values.put(key, value);
}
public void set(final String key, final Object value, final String... comments) {
if (value == null) {
remove(key);
values.remove(key);
getRoot().getComments().remove(getFullKeyInPath(key));
} else {
this.values.put(key, value);
values.put(key, value);
}
}
public void remove(final String key) {
this.values.remove(key);
set(key, null);
}
public Set<String> getKeys() {
@@ -89,53 +125,89 @@ public class ConfigSection {
}
public boolean getBoolean(final String key) {
final Object o = values.get(key);
return o instanceof Boolean && (boolean) o;
return getBoolean(key, false);
}
public boolean getBoolean(final String key, final boolean def) {
return values.containsKey(key) ? get(key) : def;
final Object o = getObject(key);
return o instanceof Boolean ? (boolean) o : def;
}
@Nullable
public String getString(final String key) {
return get(key);
}
public String getString(final String key, final String def) {
return values.containsKey(key) ? get(key) : def;
@Nullable
public String getString(final String key, @Nullable final String def) {
final Object o = getObject(key);
return o instanceof String ? (String) o : def;
}
public int getInt(final String key) {
final Object o = values.get(key);
return o instanceof Number ? ((Number) o).intValue() : 0;
return getInt(key, 0);
}
public int getInt(final String key, final int def) {
return values.containsKey(key) ? get(key) : def;
final Object o = getObject(key);
return o instanceof Number ? ((Number) o).intValue() : def;
}
public double getDouble(final String key) {
final Object o = values.get(key);
return o instanceof Number ? ((Number) o).doubleValue() : 0;
return getDouble(key, 0D);
}
public double getDouble(final String key, final double def) {
return values.containsKey(key) ? get(key) : def;
final Object o = getObject(key);
return o instanceof Number ? ((Number) o).doubleValue() : def;
}
public long getLong(final String key) {
return getLong(key, 0L);
}
public long getLong(final String key, final long def) {
final Object o = getObject(key);
return o instanceof Number ? ((Number) o).longValue() : def;
}
@Nullable
public List<String> getStringList(final String key) {
return get(key);
}
public List<String> getStringList(final String key, final List<String> def) {
return values.containsKey(key) ? get(key) : def;
@Nullable
public List<String> getStringList(final String key, @Nullable final List<String> def) {
final List<String> list = get(key);
return list != null ? list : def;
}
@Nullable
public List<Integer> getIntList(final String key) {
return get(key);
}
public List<Integer> getIntList(final String key, final List<Integer> def) {
return values.containsKey(key) ? get(key) : def;
@Nullable
public List<Integer> getIntList(final String key, @Nullable final List<Integer> def) {
final List<Integer> list = get(key);
return list != null ? list : def;
}
/**
* @return root config
*/
public Config getRoot() {
return root;
}
/**
* @return current path, or empty string if root
*/
public String getCurrentPath() {
return currentPath;
}
protected String getFullKeyInPath(final String key) {
return currentPath.isEmpty() ? key : currentPath + "." + key;
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -35,63 +35,88 @@ import java.util.regex.Pattern;
public final class ConfigSerializer {
private static final String[] EMPTY = new String[0];
private static final int INDENT_UNIT = 2;
private static final String PATH_SEPARATOR_STRING = ".";
private static final String PATH_SEPARATOR_QUOTED = Pattern.quote(PATH_SEPARATOR_STRING);
private static final int INDENT_UNIT = 2;
public static String serialize(final String header, final Map<String, Object> data, final Map<String, String[]> comments, final Yaml yaml) {
if (data.isEmpty()) return yaml.dump(null);
if (data.isEmpty()) {
return yaml.dump(null);
}
final String rawYaml = yaml.dump(data);
final StringBuilder fileData = new StringBuilder();
int currentIndents = 0;
int currentKeyIndents = 0;
String key = "";
for (final String line : rawYaml.split("\n")) {
if (line.isEmpty()) continue;
final int indent = getIndents(line);
final int indents = indent / INDENT_UNIT;
final String indentText = indent > 0 ? line.substring(0, indent) : "";
if (indents <= currentIndents) {
final boolean keyLine;
final String substring = line.substring(indent);
if (substring.trim().isEmpty() || substring.charAt(0) == '-') {
keyLine = false;
} else if (indents <= currentKeyIndents) {
final String[] array = key.split(PATH_SEPARATOR_QUOTED);
final int backspace = currentIndents - indents + 1;
final int backspace = currentKeyIndents - indents + 1;
key = join(array, array.length - backspace);
keyLine = true;
} else {
keyLine = line.indexOf(':') != -1;
}
final String separator = key.isEmpty() ? "" : PATH_SEPARATOR_STRING;
final String lineKey = line.contains(":") ? line.split(Pattern.quote(":"))[0] : line;
key += separator + lineKey.substring(indent);
if (!keyLine) {
// Nothing to do, go to next line
fileData.append(line).append('\n');
continue;
}
currentIndents = indents;
final String newKey = substring.split(Pattern.quote(":"))[0]; // Not sure about the quote thing, so I'll just keep it :aaa:
if (!key.isEmpty()) {
key += PATH_SEPARATOR_STRING;
}
key += newKey;
final String[] strings = comments.get(key);
if (strings != null) {
for (final String comment : strings) {
if (comment.isEmpty())
fileData.append('\n');
else
fileData.append(indentText).append(comment).append('\n');
// Add comments if present
if (comments != null) {
final String[] strings = comments.get(key);
if (strings != null) {
final String indentText = indent > 0 ? line.substring(0, indent) : "";
for (final String comment : strings) {
if (comment.isEmpty()) {
fileData.append('\n');
} else {
fileData.append(indentText).append(comment).append('\n');
}
}
}
}
currentKeyIndents = indents;
fileData.append(line).append('\n');
}
return header != null && !header.isEmpty() ? header + fileData : fileData.toString();
}
public static Map<String, String[]> deserializeComments(final String data) {
//TODO go through known yaml keys and figure out comments from there instead of from line to line?
// ... tho everything here would benefit from a cleanup
final Map<String, String[]> comments = new HashMap<>();
final List<String> currentComments = new ArrayList<>();
boolean header = true;
boolean multiLineValue = false;
int currentIndents = 0;
String key = "";
for (final String line : data.split("\n")) {
final String s = line.trim();
// It's a comment!
if (s.startsWith("#")) {
currentComments.add(s);
continue;
}
// Header is over - save it!
if (header) {
if (!currentComments.isEmpty()) {
currentComments.add("");
@@ -100,21 +125,39 @@ public final class ConfigSerializer {
}
header = false;
}
// Save empty lines as well
if (s.isEmpty()) {
currentComments.add(s);
continue;
}
// Multi line values?
if (s.startsWith("- |")) {
multiLineValue = true;
continue;
}
final int indent = getIndents(line);
final int indents = indent / INDENT_UNIT;
// Check if the multi line value is over
if (multiLineValue) {
if (indents > currentIndents) continue;
multiLineValue = false;
}
// Check if this is a level lower
if (indents <= currentIndents) {
final String[] array = key.split(PATH_SEPARATOR_QUOTED);
final int backspace = currentIndents - indents + 1;
key = join(array, array.length - backspace);
final int delta = array.length - backspace;
key = delta >= 0 ? join(array, delta) : key;
}
// Finish current key
final String separator = key.isEmpty() ? "" : PATH_SEPARATOR_STRING;
final String lineKey = line.contains(":") ? line.split(Pattern.quote(":"))[0] : line;
final String lineKey = line.indexOf(':') != -1 ? line.split(Pattern.quote(":"))[0] : line;
key += separator + lineKey.substring(indent);
currentIndents = indents;
@@ -129,8 +172,11 @@ public final class ConfigSerializer {
private static int getIndents(final String line) {
int count = 0;
for (int i = 0; i < line.length(); i++) {
if (line.charAt(i) == ' ') count++;
else break;
if (line.charAt(i) != ' ') {
break;
}
count++;
}
return count;
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -33,7 +33,7 @@ public final class MaintenanceDump {
private final JsonObject plugins;
public MaintenanceDump(final MaintenancePlugin plugin, final Settings settings) {
general = new ServerDump(plugin.getVersion(), plugin.getServerType().toString(), plugin.getServerVersion(), plugin.getMaintenanceServers());
general = new ServerDump(plugin.getVersion(), plugin.getServerType().toString(), plugin.getServerVersion(), plugin.getMaintenanceServersDump());
configuration = new LinkedHashMap<>(settings.getConfig().getValues());
final Object o = configuration.get("mysql");
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -22,13 +22,13 @@ import java.util.List;
public final class ServerDump {
private final String pluginVersion;
private final String serverType;
private final String platform;
private final String serverVersion;
private final List<String> maintenance;
public ServerDump(final String pluginVersion, final String serverType, final String serverVersion, final List<String> maintenance) {
public ServerDump(final String pluginVersion, final String platform, final String serverVersion, final List<String> maintenance) {
this.pluginVersion = pluginVersion;
this.serverType = serverType;
this.platform = platform;
this.serverVersion = serverVersion;
this.maintenance = maintenance;
}
@@ -0,0 +1,47 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.event;
import eu.kennytv.maintenance.api.event.manager.EventListener;
import eu.kennytv.maintenance.api.event.manager.IEventManager;
import eu.kennytv.maintenance.api.event.manager.MaintenanceEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class EventManager implements IEventManager {
private final Map<String, List<EventListener>> listeners = new HashMap<>();
@Override
public void registerListener(final EventListener listener, final Class<? extends MaintenanceEvent> eventClass) {
listeners.computeIfAbsent(eventClass.getSimpleName(), s -> new ArrayList<>()).add(listener);
}
@Override
public void callEvent(final MaintenanceEvent event) {
final List<EventListener> list = listeners.get(event.getClass().getSimpleName());
if (list != null) {
for (final EventListener listener : list) {
listener.onEvent(event);
}
}
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -25,8 +25,9 @@ public final class ServerListPlusHook {
private final ServerListPlusCore serverListPlusCore;
public ServerListPlusHook(final Object serverListPlus) {
if (!(serverListPlus instanceof ServerListPlusPlugin))
if (!(serverListPlus instanceof ServerListPlusPlugin)) {
throw new IllegalArgumentException("Couldn't parse ServerListPlus instance!");
}
this.serverListPlusCore = ((ServerListPlusPlugin) serverListPlus).getCore();
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -43,21 +43,19 @@ public abstract class JoinListenerBase {
* @param sender wrapper of the joining player
* @return true if the sender should be kicked
*/
protected boolean kickPlayer(final SenderInfo sender, final boolean updateCheck) {
if (settings.isMaintenance() && !sender.getUuid().equals(notifyUuid)) {
if (!sender.hasMaintenancePermission("bypass") && !settings.getWhitelistedPlayers().containsKey(sender.getUuid())) {
if (settings.isJoinNotifications())
broadcastJoinNotification(sender.getName());
return true;
protected boolean shouldKick(final SenderInfo sender, final boolean updateCheck) {
if (!settings.isMaintenance() || sender.hasMaintenancePermission("bypass") || settings.isWhitelisted(sender.getUuid())) {
if (updateCheck) {
updateCheck(sender);
}
return false;
}
if (updateCheck)
updateCheck(sender);
return false;
return true;
}
protected boolean kickPlayer(final SenderInfo sender) {
return kickPlayer(sender, true);
protected boolean shouldKick(final SenderInfo sender) {
return shouldKick(sender, true);
}
protected void updateCheck(final SenderInfo sender) {
@@ -69,6 +67,7 @@ public abstract class JoinListenerBase {
if (!sender.hasPermission("maintenance.admin") || notifiedPlayers.contains(sender.getUuid())) return;
plugin.async(() -> {
if (!plugin.updateAvailable()) return;
notifiedPlayers.add(sender.getUuid());
sender.sendMessage(plugin.getPrefix() + "§cThere is a newer version available: §aVersion " + plugin.getNewestVersion() + "§c, you're on §a" + plugin.getVersion());
plugin.sendUpdateNotification(sender);
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -21,10 +21,10 @@ package eu.kennytv.maintenance.core.runnable;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
public final class MaintenanceRunnable extends MaintenanceRunnableBase {
public class MaintenanceRunnable extends MaintenanceRunnableBase {
public MaintenanceRunnable(final MaintenancePlugin plugin, final Settings settings, final int minutes, final boolean enable) {
super(plugin, settings, minutes, enable);
public MaintenanceRunnable(final MaintenancePlugin plugin, final Settings settings, final int seconds, final boolean enable) {
super(plugin, settings, seconds, enable);
}
@Override
@@ -33,12 +33,12 @@ public final class MaintenanceRunnable extends MaintenanceRunnableBase {
}
@Override
protected String startMessageKey() {
protected String getStartMessage() {
return settings.getMessage("starttimerBroadcast").replace("%TIME%", getTime());
}
@Override
protected String endMessageKey() {
protected String getEndMessage() {
return settings.getMessage("endtimerBroadcast").replace("%TIME%", getTime());
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -20,18 +20,21 @@ 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;
public abstract class MaintenanceRunnableBase implements Runnable {
protected final MaintenancePlugin plugin;
protected final Settings settings;
protected final boolean enable;
private final Task task;
protected boolean enable;
protected int seconds;
protected MaintenanceRunnableBase(final MaintenancePlugin plugin, final Settings settings, final int minutes, final boolean enable) {
protected MaintenanceRunnableBase(final MaintenancePlugin plugin, final Settings settings, final int seconds, final boolean enable) {
this.plugin = plugin;
this.settings = settings;
this.seconds = minutes * 60;
this.seconds = seconds;
this.enable = enable;
this.task = plugin.startMaintenanceRunnable(this);
}
@Override
@@ -39,10 +42,7 @@ public abstract class MaintenanceRunnableBase implements Runnable {
if (seconds == 0) {
finish();
} else if (settings.getBroadcastIntervals().contains(seconds)) {
if (enable)
plugin.broadcast(startMessageKey());
else
plugin.broadcast(endMessageKey());
broadcast(enable ? getStartMessage() : getEndMessage());
}
seconds--;
@@ -62,18 +62,31 @@ public abstract class MaintenanceRunnableBase implements Runnable {
private void append(final StringBuilder builder, final String timeUnit, final int time) {
if (time == 0) return;
if (builder.length() != 0)
builder.append(" ");
builder.append(time).append(" ").append(settings.getMessage(time == 1 ? timeUnit : timeUnit + "s"));
if (builder.length() != 0) {
builder.append(' ');
}
builder.append(time).append(' ').append(settings.getMessage(time == 1 ? timeUnit : timeUnit + "s"));
}
public boolean shouldEnable() {
return enable;
}
public int getSecondsLeft() {
return seconds;
}
public Task getTask() {
return task;
}
protected void broadcast(final String message) {
plugin.broadcast(message);
}
protected abstract void finish();
protected abstract String startMessageKey();
protected abstract String getStartMessage();
protected abstract String endMessageKey();
protected abstract String getEndMessage();
}
@@ -0,0 +1,41 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.runnable;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import java.util.concurrent.TimeUnit;
public final class MaintenanceScheduleRunnable extends MaintenanceRunnable {
private final int maintenanceDuration;
public MaintenanceScheduleRunnable(final MaintenancePlugin plugin, final Settings settings, final int secondsToEnable, final int maintenanceDuration) {
super(plugin, settings, secondsToEnable, true);
this.maintenanceDuration = maintenanceDuration;
}
@Override
protected void finish() {
super.finish();
// Start the timer to disable maintenance again
plugin.startMaintenanceRunnable(maintenanceDuration, TimeUnit.SECONDS, false);
}
}
@@ -0,0 +1,55 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2021 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.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) {
return false;
}
@Override
public void sendMessage(final String message) {
}
@Override
public boolean isPlayer() {
return false;
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2021 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
@@ -18,33 +18,35 @@
package eu.kennytv.maintenance.core.util;
import com.google.common.base.Preconditions;
import org.jetbrains.annotations.Nullable;
public final class Version implements Comparable<Version> {
private final int[] parts;
private final String version;
private final String tag;
/**
* Creates a new version object to be compared.
* The version format are numbers separated by '.', possibly followed by a '-' to include an extra tag after it.
*
* @param version string representation of the version
* @throws IllegalArgumentException if the given version string is null or empty
* @throws NumberFormatException if there are non-number characters in the version (before the tag)
*/
public Version(final String version) {
if (version == null || version.isEmpty()) {
this.version = "";
tag = "";
parts = new int[0];
System.out.println("Unknown Maintenance version detected!");
return;
}
final String[] split = version.split("-", 2)[0].split("\\.");
Preconditions.checkArgument(version != null && !version.isEmpty());
final int index = version.indexOf('-');
final String[] split = (index == -1 ? version : version.substring(0, index)).split("\\.");
parts = new int[split.length];
for (int i = 0; i < split.length; i++) {
if (!split[i].matches("[0-9]+")) {
this.version = "";
tag = "";
System.out.println("Unknown Maintenance version detected!");
return;
}
// Let this throw an exception if parsing fails
parts[i] = Integer.parseInt(split[i]);
}
this.version = version;
tag = version.contains("-") ? version.split("-", 2)[1] : "";
tag = index != -1 ? version.substring(index + 1) : "";
}
/**
@@ -54,20 +56,25 @@ public final class Version implements Comparable<Version> {
* @return 0 if they are the same, 1 if this instance is newer, -1 if older
*/
@Override
public int compareTo(final Version version) {
if (version == null || version.toString() == null) return 0;
public int compareTo(@Nullable final Version version) {
if (version == null) return 0;
final int max = Math.max(this.parts.length, version.parts.length);
for (int i = 0; i < max; i++) {
final int partA = i < this.parts.length ? this.parts[i] : 0;
final int partB = i < version.parts.length ? version.parts[i] : 0;
if (partA < partB) return -1;
if (partA > partB) return 1;
if (partA < partB) {
return -1;
} else if (partA > partB) {
return 1;
}
}
if (this.tag.isEmpty() && !version.tag.isEmpty())
if (this.tag.isEmpty() && !version.tag.isEmpty()) {
return 1;
if (!this.tag.isEmpty() && version.tag.isEmpty())
} else if (!this.tag.isEmpty() && version.tag.isEmpty()) {
return -1;
}
return 0;
}
@@ -82,7 +89,9 @@ public final class Version implements Comparable<Version> {
@Override
public boolean equals(final Object o) {
if (o == null) return false;
return o instanceof Version && o == this || version.equals(o.toString());
if (o == this) return true;
if (!(o instanceof Version)) return false;
final Version other = (Version) o;
return version.equals(other.version);
}
}
+36 -7
View File
@@ -14,14 +14,18 @@ maintenance-enabled: false
# Enables maintenance on certain servers managed by your Bungee instance(s).
proxied-maintenance-servers:
#- SpigotServer1
#- AnotherServer
- SpigotServer1
# - AnotherServer
# 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 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
# 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.
waiting-server: ""
# The message 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.
# If running an endtimer, the time left can be displayed by including '%TIMER%' in a pingmessage (also works in playercount(-hover) message).
@@ -29,10 +33,17 @@ pingmessages:
- "&cMaintenance mode!%NEWLINE%&6We will be back soon!"
# - "Other entry"
# If set to true and an endtimer is currently running, a pingmessage 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-timerspecific-messages: false
timerspecific-pingmessages:
- "&cMaintenance mode!%NEWLINE%&6We will be back in %TIMER%!"
# - "Other entry"
# If set to true, the message below will be shown at the top right corner of the server in the serverlist, where the playercount would normally be displayed.
# If set to false, the normal playercount will be shown.
#
# Alternatively you can use '%ONLINE%' and '%MAX% if you want to include the playercount in a custom message (e.g. "&cMaintenance &7%ONLINE%&8/&7%MAX%").
# Alternatively you can use '%ONLINE%' and '%MAX%' if you want to include the playercount in a custom message (e.g. "&cMaintenance &7%ONLINE%&8/&7%MAX%").
enable-playercountmessage: true
playercountmessage: "&4Maintenance"
@@ -47,8 +58,13 @@ custom-maintenance-icon: false
# that a player tried to join the server while maintenance is enabled.
send-join-notification: false
# Set this to false if you do not want players to be kicked when you enable maintenance (new connections will still be blocked).
# ... I don't know why you would want that, but you can disable it. :p
kick-online-players: true
# Changes the language of command feedback/messages.
# Currently available are: en (English), de (German), fr (French), pt (Portuguese)
# If you find missing translations or want to contribute a new language file, you are very welcome to message me on Spigot or my Discord server! :)
# Currently available are: en (English), de (German), fr (French), pt (Portuguese), es (Spanish), ru (Russian), zh (Chinese), it (Italian)
language: en
# If you have 2 or more proxy instances, the database connection will make sure all proxies
@@ -66,6 +82,16 @@ mysql:
# 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 enabled and the server is restarted while running an endtimer, the timer will be continued after the restart.
# If the timer ends while the server is offline, maintenance will be disabled as soon as the server starts again.
continue-endtimer-after-restart:
enabled: false
# This value is set everytime an endtimer is started, cancelled or ended.
# Do not manually change this value.
end: 0
# 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]
@@ -73,4 +99,7 @@ timer-broadcast-for-seconds: [1200, 900, 600, 300, 120, 60, 30, 20, 10, 5, 4, 3,
# 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 less bugs.
# However, you can always check for updates manually using the '/maintenance update' command.
update-checks: true
update-checks: true
# Used for autoupdating the config, do not change this value.
config-version: 4
@@ -7,7 +7,6 @@ maintenanceActivated: "&8[&eMaintenance&8] &6Der Wartungsmodus ist nun aktiviert
maintenanceDeactivated: "&8[&eMaintenance&8] &6Der Wartungsmodus ist nun deaktiviert."
alreadyEnabled: "&8[&eMaintenance&8] &cDer Wartungsmodus ist bereits aktiviert!"
alreadyDisabled: "&8[&eMaintenance&8] &cDer Wartungsmodus ist bereits deaktiviert!"
helpPageNotFound: "&8[&eMaintenance&8] &cEs gibt keine Seite mit dieser Nummer!"
endtimerBroadcast: "&8[&eMaintenance&8] &7Der Wartungsmodus wird deaktiviert in: &6%TIME%&7."
endtimerStarted: "&8[&eMaintenance&8] &aGestarteter Timer: &7Der Wartungsmodus wird deaktiviert in: &6%TIME%&7."
starttimerBroadcast: "&8[&eMaintenance&8] &7Der Wartungsmodus wird aktiviert in: &6%TIME%&7."
@@ -16,8 +15,12 @@ timerAlreadyRunning: "&8[&eMaintenance&8] &cMomentan läuft bereits ein Timer!"
timerNotRunning: "&8[&eMaintenance&8] &cMomentan läuft kein Timer."
timerCancelled: "&8[&eMaintenance&8] &cDer laufende Timer wurde beendet."
timerTooLong: "&8[&eMaintenance&8] &cDie angegebene Nummer muss kleiner als 40320 sein (= 28 Tage)!"
timerMotdDisabled: "&8[&eMaintenance&8] &cDu musst 'enable-timerspecific-messages' in der Config auf 'true' stellen, wenn du timerspezifische Motds benutzen/editieren möchtest."
motdTimer: "%HOURS%:%MINUTES%:%SECONDS%"
motdTimerNotRunning: "-"
joinNotification: "&8[&eMaintenance&8] &e%PLAYER% &chat versucht den Server beizutreten."
motdList: "&8[&eMaintenance&8] &7Liste der Maintenance MOTDs:"
motdListEmpty: "8[&eMaintenance&8] &cDu hast keine Maintenance MOTDs gesetzt!"
reload: "&8[&eMaintenance&8] &aConfig, WhitelistedPlayers, Language Datei und Maintenance Icon wurden neugeladen."
removedMotd: "&8[&eMaintenance&8] &aDie %INDEX%. Maintenance MOTD wurde entfernt."
removeMotdError: "&8[&eMaintenance&8] &cDu hast nur eine Maintenance MOTD, daher kannst du auch keine entfernen!"
@@ -39,15 +42,11 @@ playerNotFoundUuid: "&8[&eMaintenance&8] &cEs konnte kein Spieler mit dieser UUI
playerNotOnline: "&8[&eMaintenance&8] &cEs ist momentan kein Spieler mit diesem Namen online."
invalidUuid: "&8[&eMaintenance&8] &cUngültiges UUID Format!"
second: "Sekunde"
seconds: "Sekunden"
minute: "Minute"
minutes: "Minuten"
hour: "Stunde"
hours: "Stunden"
# Nachrichten für den Bungee Teil des Plugins, einfach ignorieren, falls das Plugin auf Spigot verwendet wird
# Nachrichten für den Bungee/Velocity Teil des Plugins, einfach ignorieren, falls das Plugin auf Spigot/Sponge verwendet wird
sentToWaitingServer: "&8[&eMaintenance&8] &cDu wurdest auf den Warteserver verbunden!"
forceWaitingServer: "&8[&eMaintenance&8] &cDu kannst den Warteserver nicht verlassen solange der Wartungsmodus aktiviert ist!"
serverNotFound: "&8[&eMaintenance&8] &cEs wurde kein Server mit diesem Namen gefunden!"
singleTimerAlreadyRunning: "&8[&eMaintenance&8] &cMomentan läuft bereits ein Timer auf diesem Server!"
singleTimerNotRunning: "&8[&eMaintenance&8] &cMomentan läuft kein Timer auf diesem Server."
singleTimerCancelled: "&8[&eMaintenance&8] &cDer laufende Timer dieses Servers wurde beendet."
@@ -60,4 +59,37 @@ singleMaintenanceDeactivated: "&8[&eMaintenance&8] &6Der Wartungsmodus wurde auf
singleServerAlreadyEnabled: "&8[&eMaintenance&8] &cDer Wartungsmodus ist bereits an auf &e%SERVER%&c!"
singleServerAlreadyDisabled: "&8[&eMaintenance&8] &cDer Wartungsmodus ist bereits aus auf &e%SERVER%&c!"
singleServerMaintenanceList: "&8[&eMaintenance&8] &7Unterserver, die im Wartungsmodus sind:"
singleServerMaintenanceListEmpty: "&8[&eMaintenance&8] &7Es befindet sich momentan kein Unterserver im Wartungsmodus."
singleServerMaintenanceListEmpty: "&8[&eMaintenance&8] &7Es befindet sich momentan kein Unterserver im Wartungsmodus."
second: "Sekunde"
seconds: "Sekunden"
minute: "Minute"
minutes: "Minuten"
hour: "Stunde"
hours: "Stunden"
helpHeader: "&8========[ &e%NAME% &8| &e%PAGE%/%MAX% &8]========"
helpPageNotFound: "&8[&eMaintenance&8] &cEs gibt keine Seite mit dieser Nummer!"
helpNextPage: "&7Nutze &b/maintenance help %SEITE%&7, um zur nächsten Hilfeseite zu kommen."
helpAbortTimer: "&6/maintenance aborttimer &7(Falls momentan ein Timer läuft, wird dieser abgebrochen)"
helpEndtimer: "&6/maintenance endtimer <Minuten> &7(Sobald der Timer abläuft wird der Wartungsmodus deaktiviert)"
helpStarttimer: "&6/maintenance starttimer <minutes> &7(Sobald der Timer abläuft wird der Wartungsmodus aktiviert)"
helpDump: "&6/maintenance dump &7(Sammelt wichtige Informationen für Bugreports)"
helpHelp: "&6/maintenance help [Seite] &7(Zeigt diese wunderschöne Hilfe)"
helpMotd: "&6/maintenance motd [timer] &7(Zeigt die momentan gesetzten Maintenance Motds an. Mit dem 'timer' Argument werden die timerspezifischen Motds angezeigt)"
helpRemoveMotd: "&6/maintenance removemotd [timer] <Index> &7(Entfernt eine Maintenance Motd. Mit dem 'timer' Argument wird eine timerspezifischen Motd entfernt)"
helpSetMotd: "&6/maintenance setmotd [timer] <Index> <1/2> <Nachricht> &7(Setzte eine Motd für den Wartungsmodus. Mit dem 'timer' Argument as an argument wird eine timerspezifische Motd gesetzt)"
helpReload: "&6/maintenance reload &7(Lädt Config, Language und Whitelist Dateien sowie das Maintenance Icon neu)"
helpToggle: "&6/maintenance <on/off> &7(Aktiviert/deaktiviert den Wartungsmodus)"
helpUpdate: "&6/maintenance update &7(Sucht nach neuen Updates für das Plugin und lädt diese auf den Server)"
helpWhitelist: "&6/maintenance whitelist &7(Zeigt alle gewhitelisteten Spieler für den Wartungsmodus an)"
helpWhitelistAdd: "&6/maintenance add <Name/UUID> &7(Whitelistet einen Spieler für den Wartungsmodus, sodass dieser während Wartungen den Server betreten kann)"
helpWhitelistRemove: "&6/maintenance remove <Name/UUID> &7(Entfernt einen Spieler aus der Wartungsmodus Whitelist)"
# Nachrichten für den Bungee/Velocity Teil des Plugins, einfach ignorieren, falls das Plugin auf Spigot/Sponge verwendet wird
helpAbortSingleTimer: "&6/maintenance aborttimer [Server] &7(Falls momentan ein Timer läuft, wird dieser abgebrochen)"
helpSingleEndtimer: "&6/maintenance endtimer [Server] <Minuten> &7(Sobald der Timer abläuft wird der Wartungsmodus deaktiviert)"
helpSingleStarttimer: "&6/maintenance starttimer [Server] <Minuten> &7(Sobald der Timer abläuft wird der Wartungsmodus aktiviert)"
helpSingleScheduleTimer: "&6/maintenance scheduletimer [Server] <Minuten> <Wartung in Minuten> &7(Sobald der Timer abläuft wird der Wartungsmodus für die gegebene Länge aktiviert)"
helpSingleToggle: "&6/maintenance <on/off> [Server] &7(Aktiviert/deaktiviert den Wartungsmodus)"
helpStatus: "&6/maintenance status &7(Zeigt alle Server an, auf denen momentan der Wartungsmodus aktiviert ist)"
@@ -7,7 +7,6 @@ maintenanceActivated: "&8[&eMaintenance&8] &6Maintenance mode is now activated."
maintenanceDeactivated: "&8[&eMaintenance&8] &6Maintenance mode is now deactivated."
alreadyEnabled: "&8[&eMaintenance&8] &cMaintenance is already enabled!"
alreadyDisabled: "&8[&eMaintenance&8] &cMaintenance is already disabled!"
helpPageNotFound: "&8[&eMaintenance&8] &cThere is no page with that number!"
endtimerBroadcast: "&8[&eMaintenance&8] &7Maintenance mode will be disabled in &6%TIME%&7."
endtimerStarted: "&8[&eMaintenance&8] &aStarted timer: &7Maintenance mode will be deactivated in &6%TIME%&7."
starttimerBroadcast: "&8[&eMaintenance&8] &7Maintenance mode will be enabled in &6%TIME%&7."
@@ -16,8 +15,12 @@ timerAlreadyRunning: "&8[&eMaintenance&8] &cThere is already a timer scheduled!"
timerNotRunning: "&8[&eMaintenance&8] &cThere is currently no running timer."
timerCancelled: "&8[&eMaintenance&8] &cThe current timer has been disabled."
timerTooLong: "&8[&eMaintenance&8] &cThe number has to be less than 40320 (28 days)!"
timerMotdDisabled: "&8[&eMaintenance&8] &cYou have to set 'enable-timerspecific-messages' in the config to 'true', if you want to use/edit timerspecific motds."
motdTimer: "%HOURS%:%MINUTES%:%SECONDS%"
motdTimerNotRunning: "-"
joinNotification: "&8[&eMaintenance&8] &e%PLAYER% &ctried to join the server."
motdList: "&8[&eMaintenance&8] &7List of your maintenance motds:"
motdListEmpty: "8[&eMaintenance&8] &cYou don't have any maintenance motds set!"
reload: "&8[&eMaintenance&8] &aReloaded config, whitelistedplayers, language file and the maintenance icon."
removedMotd: "&8[&eMaintenance&8] &aRemoved motd number %INDEX%."
removeMotdError: "&8[&eMaintenance&8] &cYou only have one motd, so you cannot remove any!"
@@ -39,15 +42,11 @@ playerNotFoundUuid: "&8[&eMaintenance&8] &cNo player with that uuid could be fou
playerNotOnline: "&8[&eMaintenance&8] &cThere is no player online with that name."
invalidUuid: "&8[&eMaintenance&8] &cInvalid uuid format!"
second: "second"
seconds: "seconds"
minute: "minute"
minutes: "minutes"
hour: "hour"
hours: "hours"
# Some messages for the Bungee part, just ignore them if you use the plugin on Spigot
# Messages for the Bungee/Velocity part, just can ignore them if you use the plugin on Spigot/Sponge
sentToWaitingServer: "&8[&eMaintenance&8] &cYou have been sent to a waiting server!"
forceWaitingServer: "&8[&eMaintenance&8] &cYou cannot leave the waiting server while maintenance is enabled!"
serverNotFound: "&8[&eMaintenance&8] &cNo server with this name is registered on the proxy!"
singleTimerAlreadyRunning: "&8[&eMaintenance&8] &cThere is already a timer scheduled for that server!"
singleTimerCancelled: "&8[&eMaintenance&8] &cThe current timer for server &e%SERVER% &chas been disabled."
singleTimerNotRunning: "&8[&eMaintenance&8] &cThere is currently no running timer for that server."
@@ -60,4 +59,38 @@ singleMaintenanceDeactivated: "&8[&eMaintenance&8] &6Maintenance mode is now dea
singleServerAlreadyEnabled: "&8[&eMaintenance&8] &cMaintenance is already enabled on server &e%SERVER%&c!"
singleServerAlreadyDisabled: "&8[&eMaintenance&8] &cMaintenance is already disabled on server &e%SERVER%&c!"
singleServerMaintenanceList: "&8[&eMaintenance&8] &7Proxied servers, that have maintenance enabled:"
singleServerMaintenanceListEmpty: "&8[&eMaintenance&8] &7There are no proxied servers that are under maintenance."
singleServerMaintenanceListEmpty: "&8[&eMaintenance&8] &7There are no proxied servers that are under maintenance."
second: "second"
seconds: "seconds"
minute: "minute"
minutes: "minutes"
hour: "hour"
hours: "hours"
helpHeader: "&8========[ &e%NAME% &8| &e%PAGE%/%MAX% &8]========"
helpPageNotFound: "&8[&eMaintenance&8] &cThere is no page with that number!"
helpNextPage: "&7Use &b/maintenance help %PAGE% &7to get to the next help window."
helpAbortTimer: "&6/maintenance aborttimer &7(If running, the current timer will be aborted)"
helpEndtimer: "&6/maintenance endtimer <minutes> &7(After the given time in minutes, maintenance mode will be disabled)"
helpStarttimer: "&6/maintenance starttimer <minutes> &7(After the given time in minutes, maintenance mode will be enabled)"
helpScheduleTimer: "&6/maintenance scheduletimer <timer minutes> <maintenance duration> &7(After the given time in minutes, maintenance mode will be enabled for the given duration in minutes)"
helpDump: "&6/maintenance dump &7(Dumps some server information, used for bug reports)"
helpHelp: "&6/maintenance help [page] &7(Shows this beautiful help window)"
helpMotd: "&6/maintenance motd [timer] &7(Lists the currently set maintenance motds. If specifying 'timer', the timer motds are shown)"
helpRemoveMotd: "&6/maintenance removemotd [timer] <index> &7(Removes a maintenance motd. If using 'timer' as an argument, a timerspecific pingmessage will be removed)"
helpSetMotd: "&6/maintenance setmotd [timer] <index> <1/2> <message> &7(Sets a motd for maintenance mode. If using 'timer' as an argument, a timerspecific pingmessage will be set)"
helpReload: "&6/maintenance reload &7(Reloads the config file, whitelist file and the server-icon)"
helpToggle: "&6/maintenance <on/off> &7(Enables/disables maintenance mode)"
helpUpdate: "&6/maintenance update &7(Remotely downloads the newest version of the plugin onto your server)"
helpWhitelist: "&6/maintenance whitelist &7(Shows all whitelisted players for the maintenance mode)"
helpWhitelistAdd: "&6/maintenance add <name/uuid> &7(Adds the player to the maintenance whitelist, so they can join the server even though maintenance is enabled)"
helpWhitelistRemove: "&6/maintenance remove <name/uuid> &7(Removes the player from the maintenance whitelist)"
# Messages for the Bungee/Velocity part, just can ignore them if you use the plugin on Spigot/Sponge
helpAbortSingleTimer: "&6/maintenance aborttimer [server] &7(If running, the current timer will be aborted)"
helpSingleEndtimer: "&6/maintenance endtimer [server] <minutes> &7(After the given time in minutes, maintenance mode will be disabled)"
helpSingleStarttimer: "&6/maintenance starttimer [server] <minutes> &7(After the given time in minutes, maintenance mode will be enabled)"
helpSingleScheduleTimer: "&6/maintenance scheduletimer [server] <timer minutes> <maintenance duration> &7(After the given time in minutes, maintenance mode will be enabled for the given duration in minutes)"
helpSingleToggle: "&6/maintenance <on/off> [server] &7(Enables/disables maintenance mode)"
helpStatus: "&6/maintenance status &7(Lists all proxied servers, that are currently under maintenance)"
@@ -0,0 +1,96 @@
# Maintenance Plugin by KennyTV
# Translators: Vixo_Ulises
# Don't remove words inbetween the '%' if you don't exactly know why you're doing it
noPermission: "&8[&eMaintenance&8] &4No tienes permiso para ejecutar este comando."
kickmessage: "&cEl servidor se encuentra en mantenimiento!%NEWLINE%&cIntentalo de nuevo mas tarde!"
maintenanceActivated: "&8[&eMaintenance&8] Mantenimiento &7activado"
maintenanceDeactivated: "&8[&eMaintenance&8] &7Modo mantenimiento &7desactivado"
alreadyEnabled: "&8[&eMaintenance&8] &7Modo mantenimiento se encuentra habilitado!"
alreadyDisabled: "&8[&eMaintenance&8] &7Modo mantenimiento se encuentra deshabilitado!"
endtimerBroadcast: "&8[&eMaintenance&8] &7El modo mantenimiento se desactivara en &6%TIME%&7."
endtimerStarted: "&8[&eMaintenance&8] &7Temporizador iniciado: El modo mantenimiento se desactivará en &6%TIME%&7."
starttimerBroadcast: "&8[&eMaintenance&8] &7El modo mantenimiento se habilitara en &6%TIME%&7."
starttimerStarted: "&8[&eMaintenance&8] &7Temporizador iniciado: El modo mantenimiento se activará en &6%TIME%&7."
timerAlreadyRunning: "&8[&eMaintenance&8] &cYa hay un temporizador programado!"
timerNotRunning: "&8[&eMaintenance&8] &7Actualmente no hay temporizador."
timerCancelled: "&8[&eMaintenance&8] &cEl Temporizador actual ha sido deshabilitado."
timerTooLong: "&8[&eMaintenance&8] &7El numero debe ser menor a 40320 &8(&628 días&8)"
timerMotdDisabled: "&8[&eMaintenance&8] &cTienes que configurar &a'enable-timerspecific-messages'&c en la configuración en &a'true'&c, si quieres usar / editar motdspecers específicos."
motdTimer: "%HOURS%:%MINUTES%:%SECONDS%"
motdTimerNotRunning: "-"
joinNotification: "&8[&eMaintenance&8] &c%PLAYER% &7Intenta unirse al servidor."
motdList: "&8[&eMaintenance&8] &7Lista de motds de mantenimiento&7:"
motdListEmpty: "8[&eMaintenance&8] &c¡No tiene ningún motd(s&8) de mantenimiento establecido!"
reload: "&8[&eMaintenance&8] &aConfiguracion recargada"
removedMotd: "&8[&eMaintenance&8] &aNumero de motd eliminado &6%INDEX%&a."
removeMotdError: "&8[&eMaintenance&8] &Solo tienes un motd, por lo que no puedes eliminar ninguno!"
setMotd: "&8[&eMaintenance&8] &aEstablecer linea &6%LINE%&a sobre &6%INDEX%&a. Para mantenimiento para %MOTD%"
setMotdIndexError: "&8[&eMaintenance&8] &aActualmente tiene &6%MOTDS%&a Motd(s&8), por lo que debe elegir un número entre 1 y %NEWAMOUNT%."
setMotdLineError: "&8[&eMaintenance&8] &7El segundo argumento tiene que ser el numero de línea.(1 ó 2&8)!"
updateDownloading: "&8[&eMaintenance&8] &aDescargando actualización..."
updateFailed: "&8[&eMaintenance&8] &cActualizacion fallida!"
updateFinished: "&8[&eMaintenance&8] &aLa actualización fue exitosa!, debes reiniciar el servidor!"
whitelistedPlayers: "&8[&eMaintenance&8] &6Jugadores en lista blanca:"
whitelistedPlayersFormat: "&7- &a%NAME% &8(&7%UUID%&8)"
whitelistAdded: "&8[&eMaintenance&8] &a%PLAYER% &7Añadido a la lista de mantenimiento!"
whitelistAlreadyAdded: "&8[&eMaintenance&8] &a%PLAYER% &7Se encuentra en la lista de mantenimiento!"
whitelistRemoved: "&8[&eMaintenance&8] &c%PLAYER% &7Eliminado de la lista de mantenimiento!"
whitelistNotFound: "&8[&eMaintenance&8] &7No se encuentra en la lista de mantenimiento!"
whitelistEmpty: "&8[&eMaintenance&8] &7La lista de mantenimiento está vacía! Usa '&6/Maintenance add <Player>' &7para agregar a alguien!"
playerNotFound: "&8[&eMaintenance&8] &7Ningun jugador con este nombre ha jugado en este servidor antes!"
playerNotFoundUuid: "&8[&eMaintenance&8] &cNo se pudo encontrar el jugador con ese UUID."
playerNotOnline: "&8[&eMaintenance&8] &7No hay jugador en línea con este nombre."
invalidUuid: "&8[&eMaintenance&8] &cFormato inválido!"
# Messages for the Bungee/Velocity part, just can ignore them if you use the plugin on Spigot/Sponge
sentToWaitingServer: "&8[&eMaintenance&8] &aHas sido enviado a un servidor de espera!"
forceWaitingServer: "&8[&eMaintenance&8] &cNo puedes dejar el servidor de espera mientras el mantenimiento está activado!"
serverNotFound: "&8[&eMaintenance&8] &cNingún servidor con este nombre está registrado en el proxy!"
singleTimerAlreadyRunning: "&8[&eMaintenance&8] &cYa hay un temporizador programado!"
singleTimerNotRunning: "&8[&eMaintenance&8] &cActualmente no hay ningún temporizador en ejecución para ese servidor."
singleTimerCancelled: "&8[&eMaintenance&8] &cEl temporizador actual para el servidor &6%SERVER% &cha sido desactivado."
singleEndtimerBroadcast: "&8[&eMaintenance&8] &7El modo mantenimiento en el Servidor &6%SERVER% &7se desactivará en &a%TIME%&7."
singleStarttimerBroadcast: "&8[&eMaintenance&8] &7El modo mantenimiento en el servidor &6%SERVER%&7 se activará en &a%TIME%&7"
singleMaintenanceKick: "&8[&eMaintenance&8] &7El servidor &6%SERVER% &7se encuentra en mantenimiento&7! Intentalo mas tarde!"
singleMaintenanceKickComplete: "&7El Servidor &6%SERVER% &7esta en mantenimiento&7!%NEWLINE%&cVuelve Mas Tarde!"
singleMaintenanceActivated: "&8[&eMaintenance&8] &7El modo mantenimiento esta activado en el servidor &6%SERVER%&7."
singleMaintenanceDeactivated: "&8[&eMaintenance&8] &7El modo mantenimiento ahora esta deshabilitado en &6%SERVER%&7."
singleServerAlreadyEnabled: "&8[&eMaintenance&8] &7El modo mantenimiento se encuentra habilitado en &6%SERVER%&7!"
singleServerAlreadyDisabled: "&8[&eMaintenance&8] &7El modo mantenimiento se encuentra deshabilitado en &6%SERVER%&7!"
singleServerMaintenanceList: "&8[&eMaintenance&8] &7Servidores proxy, que tienen habilitado el mantenimiento:"
singleServerMaintenanceListEmpty: "&8[&eMaintenance&8] &7No hay servidores proxy que están en mantenimiento&7."
second: "Segundo"
seconds: "Segundos"
minute: "Minuto"
minutes: "Minutos"
hour: "Hora"
hours: "Horas"
helpHeader: "&8========[ &e%NAME% &8| &e%PAGE%/%MAX% &8]========"
helpPageNotFound: "&8[&eMaintenance&8] &7No hay pagina con ese número."
helpNextPage: "&7Utilice &b/maintenance help %PAGE% &7Para pasar a la siguiente ventana de ayuda."
helpAbortTimer: "&6/maintenance aborttimer &8(&7Si se ejecuta, se abortará el temporizador actual&8)"
helpEndtimer: "&6/maintenance endtimer <minutes> &8(&7Después del tiempo en minutos, se desactivará el modo de mantenimiento&8)"
helpStarttimer: "&6/maintenance starttimer <minutes> &8(&7Después del tiempo en minutos, se habilitará el modo de mantenimiento&8)"
helpDump: "&6/maintenance dump &8(&7Descarga información del servidor, usada para informes de errores&8)"
helpHelp: "&6/maintenance help [page] &8(&7Muestra la pagina de ayuda&8)"
helpMotd: "&6/maintenance motd [timer] &8(&7Enumera los motivos de mantenimiento establecidos actualmente. Si se especifica el 'temporizador', se muestran los motivos del temporizador&8)"
helpRemoveMotd: "&6/maintenance removemotd [timer] <index> &8(&7Elimina un mantenimiento motd. Si se usa 'timer' como argumento, se eliminará un pingmessage de temporizador específico&8)"
helpSetMotd: "&6/maintenance setmotd [timer] <index> <1/2> <message> &8(&7Establece un motd para el modo de mantenimiento. Si usa 'timer' como argumento, se establecerá un mensaje de ping específico para el tiempo&8)"
helpReload: "&6/maintenance reload &8(&7Vuelve a cargar el archivo de configuración, el archivo de la lista blanca y el ícono del servidor&8)"
helpToggle: "&6/maintenance <on/off> &8(&7Habilita / deshabilita el modo de mantenimiento&8)"
helpUpdate: "&6/maintenance update &8(&7Descarga de forma remota la versión más reciente del complemento en su servidor&8)"
helpWhitelist: "&6/maintenance whitelist &8(&7Muestra todos los jugadores en lista blanca para el modo de mantenimiento&8)"
helpWhitelistAdd: "&6/maintenance add <name/uuid> &8(&7Agrega al jugador a la lista blanca de mantenimiento, para que puedan unirse al servidor aunque el mantenimiento esté habilitado&8)"
helpWhitelistRemove: "&6/maintenance remove <name/uuid> &8(&7Quita al jugador de la lista blanca de mantenimiento&8)"
# Messages for the Bungee/Velocity part, just can ignore them if you use the plugin on Spigot/Sponge
helpAbortSingleTimer: "&6/maintenance aborttimer [servidor] &8(&7Si está funcionando, se abortará el temporizador actual&8)"
helpSingleEndtimer: "&6/maintenance endtimer [server] <minutes> &8(&7Después del tiempo en minutos, se desactivará el modo de mantenimiento&8)"
helpSingleStarttimer: "&6/maintenance starttimer [server] <minutes> &8(&7Después del tiempo en minutos, se activara el modo de mantenimiento&8)"
helpSingleScheduleTimer: "&6/maintenance scheduletimer [server] <timer minutes> <maintenance duration> &7(After the given time in minutes, maintenance mode will be enabled for the given duration in minutes)"
helpSingleToggle: "&6/maintenance <on/off> [server] &8(&7Habilita / deshabilita el modo de mantenimiento&8)"
helpStatus: "&6/maintenance status &8(&7Enumera todos los servidores proxy, que están actualmente en mantenimiento&8)"
@@ -1,63 +1,95 @@
# Maintenance Plugin par KennyTV
# Ne supprime pas des mots entre les '%' si tu ne sait pas pourqoi exactement
# Plugin Maintenance par KennyTV, traduit en Français par Zendrique & Aurelien30000.
# Ne supprimez pas de mots entre les '%' si vous ne savez pas exactement pourquoi, ils correspondent à des référencements de valeurs changeantes.
noPermission: "&cVous n'avez pas la permission d'exécuter cette commande."
kickmessage: "&cLe serveur est actuellement en maintenance!%NEWLINE%&cRéessayez plus tard!"
kickmessage: "&cLe serveur est actuellement en maintenance !%NEWLINE%&cRéessayez plus tard !"
maintenanceActivated: "&8[&eMaintenance&8] &6Le mode maintenance est maintenant activé."
maintenanceDeactivated: "&8[&eMaintenance&8] &6Le mode maintenance est maintenant désactivé."
alreadyEnabled: "&8[&eMaintenance&8] &cLa maintenance est déjà activée!"
alreadyDisabled: "&8[&eMaintenance&8] &cLa maintenance est déjà désactivée!"
helpPageNotFound: "&8[&eMaintenance&8] &cIl n'y a pas cette page!"
alreadyEnabled: "&8[&eMaintenance&8] &cLa maintenance est déjà activée !"
alreadyDisabled: "&8[&eMaintenance&8] &cLa maintenance est déjà désactivée !"
endtimerBroadcast: "&8[&eMaintenance&8] &7Le mode maintenance sera désactivé dans &6%TIME%&7."
endtimerStarted: "&8[&eMaintenance&8] &aminuterie: &7Le mode maintenance sera désactivé dans &6%TIME%&7."
starttimerBroadcast: "&8[&eMaintenance&8] &7MLe mode de maintenance sera activé dans &6%TIME%&7."
starttimerStarted: "&8[&eMaintenance&8] &aminuterie: &7Le mode maintenance sera activé dans &6%TIME%&7."
timerAlreadyRunning: "&8[&eMaintenance&8] &cIl y a déjà un horaire prévu!"
endtimerStarted: "&8[&eMaintenance&8] &aMinuterie : &7Le mode maintenance sera désactivé dans &6%TIME%&7."
starttimerBroadcast: "&8[&eMaintenance&8] &7Le mode de maintenance sera activé dans &6%TIME%&7."
starttimerStarted: "&8[&eMaintenance&8] &aMinuterie : &7Le mode maintenance sera activé dans &6%TIME%&7."
timerAlreadyRunning: "&8[&eMaintenance&8] &cIl y a déjà un horaire prévu !"
timerNotRunning: "&8[&eMaintenance&8] &cIl n'y a actuellement aucune maintenance prévue."
timerCancelled: "&8[&eMaintenance&8] &cLa minuterie actuelle a été désactivée."
timerTooLong: "&8[&eMaintenance&8] &cLe nombre doit être inférieur à 40320 (28 jours)!"
joinNotification: "&8[&eMaintenance&8] &e%PLAYER% &ca essayé de rejoindre le serveur."
motdList: "&8[&eMaintenance&8] &7Liste de vos motd pour la maintenance:"
reload: "&8[&eMaintenance&8] &afichier config, liste blanche (whitelist) joueurs, fichier de langue et l'icône de maintenance, recharger."
timerTooLong: "&8[&eMaintenance&8] &cLe nombre doit être inférieur à 40320 (28 jours) !"
timerMotdDisabled: "&8[&eMaintenance&8] &cVous devez définir 'enable-timerspecific-messages' sur 'true' au sein de la configuration si vous souhaitez utiliser / éditer des motds spécifiques au timer."
motdTimer: "%HOURS%:%MINUTES%:%SECONDS%"
motdTimerNotRunning: "-"
joinNotification: "&8[&eMaintenance&8] &e%PLAYER% &ca essayé de rejoindre le serveur !"
motdList: "&8[&eMaintenance&8] &7Liste de vos motds pour la maintenance :"
motdListEmpty: "8[&eMaintenance&8] &cVous n'avez pas de motds d'entretien fixés !"
reload: "&8[&eMaintenance&8] &aFichier de configuration, liste blanche (whitelist) des joueurs autorisés, fichier de langue et icône de maintenance rechargés avec succès."
removedMotd: "&8[&eMaintenance&8] &aNuméro de motd supprimé %INDEX%."
removeMotdError: "&8[&eMaintenance&8] &cVous n’avez qu’un motd, vous ne pouvez donc en supprimer!"
setMotd: "&8[&eMaintenance&8] &aLigne fixe %LINE% du %INDEX%. maintenance motd à %MOTD%"
setMotdIndexError: "&8[&eMaintenance&8] &cVous avez actuellement %MOTDS% vous devez donc choisir un nombre compris entre 1 et %NEWAMOUNT%."
setMotdLineError: "&8[&eMaintenance&8] &cLe deuxième argument doit être le numéro de ligne (1 ou 2)!"
removeMotdError: "&8[&eMaintenance&8] &cVous n’avez qu’un motd, vous ne pouvez donc pas en supprimer !"
setMotd: "&8[&eMaintenance&8] &aLigne %LINE% du motd %INDEX%. fixée à %MOTD%"
setMotdIndexError: "&8[&eMaintenance&8] &cVous avez actuellement %MOTDS% motd(s), vous devez donc choisir un nombre compris entre 1 et %NEWAMOUNT%."
setMotdLineError: "&8[&eMaintenance&8] &cLe deuxième argument doit être le numéro de ligne (1 ou 2) !"
updateDownloading: "&8[&eMaintenance&8] &c&lTéléchargement de la mise à jour..."
updateFailed: "&8[&eMaintenance&8] &4&lLa mise à jour a échoué!"
updateFinished: "&8[&eMaintenance&8] &a&lLa mise à jour a été réussie! Pour éviter les problèmes liés aux tâches et terminer la mise à jour, vous devez redémarrer le serveur!"
whitelistedPlayers: "&8[&eMaintenance&8] &6Liste blanche des joueurs pour la maintenance:"
updateFailed: "&8[&eMaintenance&8] &4&lLa mise à jour a échoué !"
updateFinished: "&8[&eMaintenance&8] &a&lLa mise à jour a été réussie ! Pour éviter les problèmes liés aux tâches et terminer la mise à jour, vous devez redémarrer le serveur !"
whitelistedPlayers: "&8[&eMaintenance&8] &6Liste blanche des joueurs pour la maintenance :"
whitelistedPlayersFormat: "&8- &e%NAME% &8(&7%UUID%&8)"
whitelistAdded: "&8[&eMaintenance&8] &aAdded &b%PLAYER% &aà la liste blanche de maintenance!"
whitelistAlreadyAdded: "&8[&eMaintenance&8] &b%PLAYER% &cest déjà dans la liste blanche de maintenance!"
whitelistRemoved: "&8[&eMaintenance&8] &aEnlevé &b%PLAYER% &ade la liste blanche de maintenance!"
whitelistNotFound: "&8[&eMaintenance&8] &cCe joueur n'est pas dans la liste blanche de la maintenance!"
whitelistEmpty: "&8[&eMaintenance&8] &cLa liste blanche de maintenance est vide! Utilisation &e/maintenance add <joueur/uuid> &cajouter quelqu'un!"
playerNotFound: "&8[&eMaintenance&8] &cAucun joueur avec ce nom n'a joué sur ce serveur auparavant."
playerNotFoundUuid: "&8[&eMaintenance&8] &cAucun joueur avec cet uuid n'a pu être trouvé."
whitelistAdded: "&8[&eMaintenance&8] &b%PLAYER% &aa été ajouté la liste blanche de maintenance !"
whitelistAlreadyAdded: "&8[&eMaintenance&8] &b%PLAYER% &cest déjà dans la liste blanche de maintenance !"
whitelistRemoved: "&8[&eMaintenance&8] &b%PLAYER% &aa été retiré de la liste blanche de maintenance !"
whitelistNotFound: "&8[&eMaintenance&8] &cCe joueur n'est pas dans la liste blanche de maintenance !"
whitelistEmpty: "&8[&eMaintenance&8] &cLa liste blanche de maintenance est vide : Utilisation &e/maintenance add <joueur/uuid> &c afin d'ajouter quelqu'un !"
playerNotFound: "&8[&eMaintenance&8] &cAucun joueur avec ce nom n'a auparavant joué sur ce serveur."
playerNotFoundUuid: "&8[&eMaintenance&8] &cAucun joueur avec cet UUID n'a pu être trouvé."
playerNotOnline: "&8[&eMaintenance&8] &cIl n'y a pas de joueur en ligne avec ce nom."
invalidUuid: "&8[&eMaintenance&8] &cLe format de l'uuid est invalide!"
invalidUuid: "&8[&eMaintenance&8] &cLe format de l'UUID est invalide !"
second: "second"
seconds: "seconds"
# Quelques messages pour la partie Bungee/Velocity, ignorez-les si vous utilisez le plugin sur Spigot/Sponge
sentToWaitingServer: "&8[&eMaintenance&8] &cVous avez été redirigé(e) vers un serveur d'attente !"
forceWaitingServer: "&8[&eMaintenance&8] &cVous ne pouvez pas quitter le serveur d'attente tant que la maintenance est activée !"
serverNotFound: "&8[&eMaintenance&8] &cAucun serveur avec ce nom n'est enregistré sur le proxy !"
singleTimerAlreadyRunning: "&8[&eMaintenance&8] &cIl y a déjà un horaire prévu sur ce serveur !"
singleTimerNotRunning: "&8[&eMaintenance&8] &cIl n'y a actuellement aucune maintenance prévue sur ce serveur."
singleTimerCancelled: "&8[&eMaintenance&8] &cLa minuterie actuelle a été désactivée sur ce serveur."
singleEndtimerBroadcast: "&8[&eMaintenance&8] &7La maintenance sur le serveur %SERVER% sera désactivée dans &6%TIME%&7."
singleStarttimerBroadcast: "&8[&eMaintenance&8] &7La maintenance sur le serveur %SERVER% sera activée dans &6%TIME%&7."
singleMaintenanceKick: "&8[&eMaintenance&8] &cLe serveur %SERVER% est actuellement en maintenance ! Réessayez plus tard !"
singleMaintenanceKickComplete: "&cLe serveur %SERVER% est en maintenance !%NEWLINE%&cVous pouvez essayer un autre serveur !"
singleMaintenanceActivated: "&8[&eMaintenance&8] &6La maintenance est maintenant activée sur le serveur &e%SERVER%&6."
singleMaintenanceDeactivated: "&8[&eMaintenance&8] &6La maintenance est maintenant désactivée sur le serveur &e%SERVER%&6."
singleServerAlreadyEnabled: "&8[&eMaintenance&8] &cLa maintenance est déjà activée sur le serveur &e%SERVER%&c !"
singleServerAlreadyDisabled: "&8[&eMaintenance&8] &cLa maintenance est déjà désactivée sur le serveur &e%SERVER%&c !"
singleServerMaintenanceList: "&8[&eMaintenance&8] &7Serveurs proxy ayant la maintenance activée :"
singleServerMaintenanceListEmpty: "&8[&eMaintenance&8] &7Il n'y a pas de serveurs proxy en maintenance."
second: "seconde"
seconds: "secondes"
minute: "minute"
minutes: "minutes"
hour: "heur"
hours: "heurs"
hour: "heure"
hours: "heures"
# Quelques messages pour la partie Bungee, ignorez-les si vous utilisez le plugin sur Spigot
serverNotFound: "&8[&eMaintenance&8] &cAucun serveur avec ce nom n'est enregistré sur le proxy!"
singleTimerAlreadyRunning: "&8[&eMaintenance&8] &cIl y a déjà un horaire prévu sur ce server!"
singleTimerNotRunning: "&8[&eMaintenance&8] &cIl n'y a actuellement aucune maintenance prévue sur ce server."
singleTimerCancelled: "&8[&eMaintenance&8] &cLa minuterie actuelle a été désactivée sur ce server."
singleEndtimerBroadcast: "&8[&eMaintenance&8] &7maintenance sur serveur %SERVER% sera désactivé dans &6%TIME%&7."
singleStarttimerBroadcast: "&8[&eMaintenance&8] &7Maintenance sur le serveur %SERVER% sera activé dans &6%TIME%&7."
singleMaintenanceKick: "&8[&eMaintenance&8] &cLe serveur %SERVER% est actuellement en maintenance! Réessayez plus tard!"
singleMaintenanceKickComplete: "&cLe serveur %SERVER% est en maintenance!%NEWLINE%&cVous pouvez essayer un autre serveur!"
singleMaintenanceActivated: "&8[&eMaintenance&8] &6La maintenance est maintenant activé sur le serveur &e%SERVER%&6."
singleMaintenanceDeactivated: "&8[&eMaintenance&8] &6La maintenance est maintenant désactivé sur le serveur &e%SERVER%&6."
singleServerAlreadyEnabled: "&8[&eMaintenance&8] &cLa maintenance est déjà activée sur le serveur &e%SERVER%&c!"
singleServerAlreadyDisabled: "&8[&eMaintenance&8] &cLa maintenance est déjà désactivée sur le serveur &e%SERVER%&c!"
singleServerMaintenanceList: "&8[&eMaintenance&8] &7Serveurs proxy avec maintenance activée:"
singleServerMaintenanceListEmpty: "&8[&eMaintenance&8] &7Il n'y a pas de serveurs proxy en maintenance."
helpHeader: "&8========[ &e%NAME% &8| &e%PAGE%/%MAX% &8]========"
helpPageNotFound: "&8[&eMaintenance&8] &cIl n'y a pas cette page !"
helpNextPage: "&7Utilisez &b/maintenance help %PAGE% &7pour accéder à la fenêtre d’aide suivante."
helpAbortTimer: "&6/maintenance aborttimer &7(Si en cours d'exécution, le minuteur actuel sera abandonné)"
helpEndtimer: "&6/maintenance endtimer <minutes> &7(Après le temps imparti en minutes, le mode maintenance sera désactivé)"
helpStarttimer: "&6/maintenance starttimer <minutes> &7(Après le temps imparti en minutes, le mode maintenance sera activé)"
helpDump: "&6/maintenance dump &7(Enregistre certaines informations sur le serveur, utilisées pour les rapports de bug)"
helpHelp: "&6/maintenance help [page] &7(Montre cette belle fenêtre d'aide)"
helpMotd: "&6/maintenance motd [timer] &7(Répertorie les paramètres de maintenance actuellement définis. Si vous spécifiez 'timer', les mots de la minuterie seront affichés)"
helpRemoveMotd: "&6/maintenance removemotd [timer] <index> &7(Supprime un motd de maintenance. Si vous utilisez 'timer' comme argument, un message ping spécifique au temporisateur sera supprimé)"
helpSetMotd: "&6/maintenance setmotd [timer] <index> <1/2> <message> &7(Définit un motd pour le mode maintenance. Si vous utilisez 'timer' comme argument, un message ping spécifique à un temporisateur sera défini)"
helpReload: "&6/maintenance reload &7(Recharge le fichier de configuration, la liste blanche, le fichier de langue et l'icône du serveur)"
helpToggle: "&6/maintenance <on/off> &7(Active/désactive le mode maintenance)"
helpUpdate: "&6/maintenance update &7(Télécharge la dernière version du plugin sur votre serveur)"
helpWhitelist: "&6/maintenance whitelist &7(Affiche les joueurs de la liste blanche pour le mode maintenance)"
helpWhitelistAdd: "&6/maintenance add <name/uuid> &7(Ajoute un joueur à la liste blanche de maintenance afin qu'il puisse rejoindre le serveur même si la maintenance est activée)"
helpWhitelistRemove: "&6/maintenance remove <name/uuid> &7(Supprime un joueur de la liste blanche de maintenance)"
# Quelques messages pour la partie Bungee/Velocity, ignorez-les si vous utilisez le plugin sur Spigot/Sponge
helpAbortSingleTimer: "&6/maintenance aborttimer [server] &7(Si en cours d'exécution, le minuteur actuel sera abandonné)"
helpSingleEndtimer: "&6/maintenance endtimer [server] <minutes> &7(Après le temps imparti en minutes, le mode maintenance sera désactivé)"
helpSingleStarttimer: "&6/maintenance starttimer [server] <minutes> &7(Après le temps imparti en minutes, le mode maintenance sera activé)"
helpSingleScheduleTimer: "&6/maintenance scheduletimer [server] <timer minutes> <maintenance duration> &7(After the given time in minutes, maintenance mode will be enabled for the given duration in minutes)"
helpSingleToggle: "&6/maintenance <on/off> [server] &7(Active/désactive le mode maintenance)"
helpStatus: "&6/maintenance status &7(Répertorie tous les serveurs mandatés actuellement en maintenance)"
@@ -0,0 +1,96 @@
# Maintenance Plugin by KennyTV
# Translators: TheViperShow
# Don't remove words inbetween the '%' if you don't exactly know why you're doing it
noPermission: "&cNon hai i permessi necessari per eseguire quel comando."
kickmessage: "&cIl server è momentaneamente in manutenzione!%NEWLINE%&cRiprova più tardi!"
maintenanceActivated: "&8[&eMaintenance&8] &6Modalità manutenzione ora attivata."
maintenanceDeactivated: "&8[&eMaintenance&8] &6Modalità manutenzione ora disattivata."
alreadyEnabled: "&8[&eMaintenance&8] &cLa modalità manutenzione è già attiva!"
alreadyDisabled: "&8[&eMaintenance&8] &cLa modalità mantenzione è già disattivata!"
endtimerBroadcast: "&8[&eMaintenance&8] &7La modalità manutenzione verrà disattivata tra &6%TIME%&7."
endtimerStarted: "&8[&eMaintenance&8] &aTimer avviato: &7La modalità manutenzione verrà disattivata tra &6%TIME%&7."
starttimerBroadcast: "&8[&eMaintenance&8] &7La modalità manutenzione verrà attivata tra &6%TIME%&7."
starttimerStarted: "&8[&eMaintenance&8] &aTimer avviato: &7La modalità manutenzione verrà attivata tra &6%TIME%&7."
timerAlreadyRunning: "&8[&eMaintenance&8] &cC'è già un timer programmato!"
timerNotRunning: "&8[&eMaintenance&8] &cNon c'è nessun timer attivo al momento."
timerCancelled: "&8[&eMaintenance&8] &cIl timer attuale è stato disattivato."
timerTooLong: "&8[&eMaintenance&8] &cIl numero deve essere inferiore a 40320 (28 giorni)!"
timerMotdDisabled: "&8[&eMaintenance&8] &cDevi impostare 'enable-timerspecific-messages' nella config su 'true', se desideri usare/modificare motds specifiche di un timer."
motdTimer: "%HOURS%:%MINUTES%:%SECONDS%"
motdTimerNotRunning: "-"
joinNotification: "&8[&eMaintenance&8] &e%PLAYER% &cha tentato di accedere al server."
motdList: "&8[&eMaintenance&8] &7Lista delle tue motds di manutenzione:"
motdListEmpty: "8[&eMaintenance&8] &cNon hai ancora nessuna motds di manutenzione!"
reload: "&8[&eMaintenance&8] &aRicaricata config, whitelistedplayers, file dei linguaggi e la icona di manutenzione."
removedMotd: "&8[&eMaintenance&8] &aRimossa motd numero %INDEX%."
removeMotdError: "&8[&eMaintenance&8] &cHai soltanto una motd, quindi non puoi rimuoverla!"
setMotd: "&8[&eMaintenance&8] &aImpostata linea %LINE% in %INDEX%. motd manutenzione a %MOTD%"
setMotdIndexError: "&8[&eMaintenance&8] &cHai attualmente %MOTDS% motds, quindi devi scegliere un numero fra 1 e %NEWAMOUNT%."
setMotdLineError: "&8[&eMaintenance&8] &cIl secondo argomento deve corrispondere alla linea (1 o 2)!"
updateDownloading: "&8[&eMaintenance&8] &c&lScaricando aggiornamento..."
updateFailed: "&8[&eMaintenance&8] &4&lAggiornamento non riuscito!"
updateFinished: "&8[&eMaintenance&8] &a&lL'aggiornamento è completato! Per prevenire problemi e completare l'aggiornamento dovresti riavviare il server!"
whitelistedPlayers: "&8[&eMaintenance&8] &6Player in whitelist per la manutenzione:"
whitelistedPlayersFormat: "&8- &e%NAME% &8(&7%UUID%&8)"
whitelistAdded: "&8[&eMaintenance&8] &aAggiunto &b%PLAYER% &aalla whitelist della manutenzione!"
whitelistAlreadyAdded: "&8[&eMaintenance&8] &b%PLAYER% &cè già nella whitelist della manutenzione!"
whitelistRemoved: "&8[&eMaintenance&8] &aRimosso &b%PLAYER% &adalla lista della manutenzione!"
whitelistNotFound: "&8[&eMaintenance&8] &cQuesto giocatore non fa parte della whitelist della manutenzione!"
whitelistEmpty: "&8[&eMaintenance&8] &cLa whitelist di manutenzione è vuota! Usa &e/maintenance add <player/uuid> &cper aggiungere qualcuno!"
playerNotFound: "&8[&eMaintenance&8] &cNessun giocatore con questo username è mai entrato nel server."
playerNotFoundUuid: "&8[&eMaintenance&8] &cNessun player con quell'uuid è stato trovato."
playerNotOnline: "&8[&eMaintenance&8] &cNon c'è nessun giocatore online con quell'username."
invalidUuid: "&8[&eMaintenance&8] &cL'uuid presenta un formato invalido!"
# Messages for the Bungee/Velocity part, just can ignore them if you use the plugin on Spigot/Sponge
sentToWaitingServer: "&8[&eMaintenance&8] &cSei stato inviato su un server d'attesa!"
forceWaitingServer: "&8[&eMaintenance&8] &cNon puoi abbandonare il server d'attesa durante una manutenzione!"
serverNotFound: "&8[&eMaintenance&8] &cNessun server con questo nome è registrato sulla proxy!"
singleTimerAlreadyRunning: "&8[&eMaintenance&8] &cÈ già presente un timer pianificato per quel server!"
singleTimerCancelled: "&8[&eMaintenance&8] &cIl timer attuale per il server &e%SERVER% &cè stato rimosso."
singleTimerNotRunning: "&8[&eMaintenance&8] &cNon c'è nessun timer correntemente attivo per quel server."
singleEndtimerBroadcast: "&8[&eMaintenance&8] &7La modalità manutenzione per il server %SERVER% verrà disabilitata tra &6%TIME%&7."
singleStarttimerBroadcast: "&8[&eMaintenance&8] &7La modalità manutenzione per il server %SERVER% verrà disabilitata tra &6%TIME%&7."
singleMaintenanceKick: "&8[&eMaintenance&8] &cIl server %SERVER% è in manutenzione al momento! Ritenta più tardi!"
singleMaintenanceKickComplete: "&cIl server %SERVER% è in manutenzione!%NEWLINE%&cProva a rientrare per accedere ad un'altro server!"
singleMaintenanceActivated: "&8[&eMaintenance&8] &6La modalità manutenzione è ora attiva sul server &e%SERVER%&6."
singleMaintenanceDeactivated: "&8[&eMaintenance&8] &6La modalità manutenzione è ora disattivata sul server &e%SERVER%&6."
singleServerAlreadyEnabled: "&8[&eMaintenance&8] &cLa modalità manutenzione è già attiva sul server &e%SERVER%&c!"
singleServerAlreadyDisabled: "&8[&eMaintenance&8] &cLa modalità manutenzione è già disattivata sul server &e%SERVER%&c!"
singleServerMaintenanceList: "&8[&eMaintenance&8] &7Servers sotto proxy che hanno la modalità manutenzione attiva:"
singleServerMaintenanceListEmpty: "&8[&eMaintenance&8] &7Nessun server sotto proxy ha la modalità manutenzione attiva."
second: "secondo"
seconds: "secondi"
minute: "minuto"
minutes: "minuti"
hour: "ora"
hours: "ore"
helpHeader: "&8========[ &e%NAME% &8| &e%PAGE%/%MAX% &8]========"
helpPageNotFound: "&8[&eMaintenance&8] &cNon c'è alcuna pagina con quel numero!"
helpNextPage: "&7Usa &b/maintenance help %PAGE% &7per andare alla prossima pagina d'aiuto."
helpAbortTimer: "&6/maintenance aborttimer &7(Se attivo, l'attuale timer verrà fermato)"
helpEndtimer: "&6/maintenance endtimer <minutes> &7(Dopo il tempo fornito in minuti, la modalità manutenzione sarà rimossa)"
helpStarttimer: "&6/maintenance starttimer <minutes> &7(Dopo il tempo fornito in minuti, la modalità manutenzione sarà attivata)"
helpDump: "&6/maintenance dump &7(Copia alcune informazioni dal server, usato per segnalare problemi)"
helpHelp: "&6/maintenance help [page] &7(Mostra questa fantastica pagina d'aiuto)"
helpMotd: "&6/maintenance motd [timer] &7(Elenca le attuali motds di manutenzione impostate. Se specifichi 'timer', verranno mostrati i motds dei timer)"
helpRemoveMotd: "&6/maintenance removemotd [timer] <index> &7(Rimuove una motd di manutenzione. Se specifichi 'timer' come argomento, un messaggio specifico al timer verrà rimosso)"
helpSetMotd: "&6/maintenance setmotd [timer] <index> <1/2> <message> &7(Imposta il motd per la manutenzione. Se specifichi 'timer' come argomento, un messaggio specifico al timer verrà impostato)"
helpReload: "&6/maintenance reload &7(Ricarica il file di configurazione, whitelist server e icona)"
helpToggle: "&6/maintenance <on/off> &7(Abilita/Disabilita modalità manutenzione)"
helpUpdate: "&6/maintenance update &7(Scarica dall'esterno l'ultima versione del plugin nel server)"
helpWhitelist: "&6/maintenance whitelist &7(Elenca tutti i giocatori nella whitelist per la manutenzione)"
helpWhitelistAdd: "&6/maintenance add <name/uuid> &7(Aggiunge il giocatore alla whitelist di manutenzione, così possono entrare in un server durante la manutenzione)"
helpWhitelistRemove: "&6/maintenance remove <name/uuid> &7(Rimuovi il player dalla whitelist della manutenzione)"
# Messages for the Bungee/Velocity part, just can ignore them if you use the plugin on Spigot/Sponge
helpAbortSingleTimer: "&6/maintenance aborttimer [server] &7(Se attivo, il timer attuale verrà fermato)"
helpSingleEndtimer: "&6/maintenance endtimer [server] <minutes> &7(Dopo il tempo fornito in minuti, la modalità manutenzione sarà rimossa)"
helpSingleStarttimer: "&6/maintenance starttimer [server] <minutes> &7(Dopo il tempo fornito in minuti, la modalità manutenzione sarà attivata)"
helpSingleScheduleTimer: "&6/maintenance scheduletimer [server] <timer minutes> <maintenance duration> &7(After the given time in minutes, maintenance mode will be enabled for the given duration in minutes)"
helpSingleToggle: "&6/maintenance <on/off> [server] &7(Abilita/Disabilita la modalità manutenzione)"
helpStatus: "&6/maintenance status &7(Elenca tutti i server sotto proxy che hanno la modalità manutenzione attiva)"
@@ -1,13 +1,13 @@
# Maintenance Plugin by KennyTV
# Translators: JoaoPinto
# Nao removas o '%' se nao souberes exatamente o que estas a fazer
noPermission: "&cNao tens permissao para executar este comando."
kickmessage: "&cThe server is currently under maintenance!%NEWLINE%&cTry again later!"
kickmessage: "&cO servidor esta em manutencao!%NEWLINE%&cTente mais tarde!"
maintenanceActivated: "&8[&cManutencao&8] &6Manutencao esta agora ativada!"
maintenanceDeactivated: "&8[&cManutencao&8] &6Manutencao esta agora desativada!"
alreadyEnabled: "&8[&cManutencao&8] &cManutencao ja esta ativada!"
alreadyDisabled: "&8[&cManutencao&8] &cManutencao ja esta desativada!"
helpPageNotFound: "&8[&eManutencao&8] &cNao existe nenhuma pagina com esse numero!"
endtimerBroadcast: "&8[&cManutencao&8] &7Manutencao vai ser desativada em &6%TIME%&7"
endtimerStarted: "&8[&cManutencao&8] &aTemporizador: &7Manutencao vai ser desativada em &6%TIME%&7"
starttimerBroadcast: "&8[&cManutencao&8] &7Manutencao vai ser ativada em &6%TIME%&7"
@@ -16,15 +16,19 @@ timerAlreadyRunning: "&8[&cManutencao&8] &cO Timer ja esta a decorrer!"
timerNotRunning: "&8[&cManutencao&8] &cO Timer nao esta a decorrer!"
timerCancelled: "&8[&cManutencao&8] &cO Timer foi cancelado!"
timerTooLong: "&8[&cManutencao&8] &cO numero tem de ser menor que 40320 (28 dias)!"
timerMotdDisabled: "&8[&eMaintenance&8] &cDefine 'enable-timerspecific-messages' no config a 'true', se queres definir/editar motds de manutenção."
motdTimer: "%HOURS%:%MINUTES%:%SECONDS%"
motdTimerNotRunning: "-"
joinNotification: "&8[&cManutencao&8] &e%PLAYER% &ctentou entrar no servidor."
motdList: "&8[&cManutencao&8] &7Lista de motds de manutencao:"
motdListEmpty: "8[&eMaintenance&8] &cNão tens motds de manutenção!"
reload: "&8[&cManutencao&8] &aReloaded config, whitelistedplayers, linguagem e icon de manutencao."
removedMotd: "&8[&cManutencao&8] &aRemovida motd numero %INDEX%."
removeMotdError: "&8[&cManutencao&8] &cSo tens uma motd, entao nao podes remover esta!"
setMotd: "&8[&eManutencao&8] &aLinha %LINE% do %INDEX%. Motd de manutencao %MOTD%"
setMotdIndexError: "&8[&cManutencao&8] §cTens atualmente %MOTDS% motds, entao escolhe um numero entre 1 e %NEWAMOUNT%."
setMotdIndexError: "&8[&cManutencao&8] &cTens atualmente %MOTDS% motds, entao escolhe um numero entre 1 e %NEWAMOUNT%."
setMotdLineError: "&8[&cManutencao&8] &cO segundo argumento tem de ser na linha (1 ou 2)!"
updateDownloading: "&8[&cManutencao&8] &c&lDownloading update..."
updateDownloading: "&8[&cManutencao&8] &c&lA dar download do update..."
updateFailed: "&8[&cManutencao&8] &4&lUpdate falhado!"
updateFinished: "&8[&cManutencao&8] &a&lO update foi feito com sucesso! Reinicia o servidor paa evitar erros e acabar a atualizacao"
whitelistedPlayers: "&8[&cManutencao&8] &6Whitelisted players para a manutencao:"
@@ -35,19 +39,15 @@ whitelistRemoved: "&8[&cManutencao&8] &b%PLAYER% &aremovido da whitelist!"
whitelistNotFound: "&8[&cManutencao&8] &cEste jogador nao esta na whitelist!"
whitelistEmpty: "&8[&cManutencao&8] &cA whitelist esta vazia! Usa &e/maintenance add <player/uuid> &cpara adicionar alguem!"
playerNotFound: "&8[&cManutencao&8] &cNinguem com esse nome se registou no servidor."
playerNotFoundUuid: "&8[&cManutencao&8] &cNinguem com esse uuid se registou no servidor."
playerNotFoundUuid: "&8[&cManutencao&8] &cNenhum player com esse uuid foi encontrado."
playerNotOnline: "&8[&cManutencao&8] &cNao esta ninguem online com esse nome"
invalidUuid: "&8[&eMaintenance&8] &cUuid inválido!"
invalidUuid: "&8[&eMaintenance&8] &cFormato de uuid invalido!"
second: "segundo"
seconds: "segundos"
minute: "minuto"
minutes: "minutos"
hour: "hora"
hours: "horas"
# Algumas mensagens para o Bungee, ignora-as se estas a usar Spigot
# Algumas mensagens para o Bungee/Velocity, ignora-as se estas a usar Spigot/Sponge
sentToWaitingServer: "&8[&eMaintenance&8] &cYou have been sent to a waiting server!"
forceWaitingServer: "&8[&eMaintenance&8] &cYou cannot leave the waiting server while maintenance is enabled!"
serverNotFound: "&8[&cManutencao&8] &cServidor nao encontrado!"
singleTimerAlreadyRunning: "&8[&cManutencao&8] &cO Timer ja esta a decorrer!"
singleTimerNotRunning: "&8[&cManutencao&8] &cO Timer nao esta a decorrer!"
singleTimerCancelled: "&8[&cManutencao&8] &cO Timer foi cancelado no!"
@@ -60,4 +60,37 @@ singleMaintenanceDeactivated: "&8[&cManutencao&8] &6Manutencao esta agora desati
singleServerAlreadyEnabled: "&8[&cManutencao&8] &cManutencao ja esta ativada no &e%SERVER%&c!"
singleServerAlreadyDisabled: "&8[&cManutencao&8] &cManutencao ja esta desativada no &e%SERVER%&c!"
singleServerMaintenanceList: "&8[&cManutencao&8] &7Servidores com manutencao ativa:"
singleServerMaintenanceListEmpty: "&8[&cManutencao&8] &7Nao existem servidores com a manutencao ativa."
singleServerMaintenanceListEmpty: "&8[&cManutencao&8] &7Nao existem servidores com a manutencao ativa."
second: "segundo"
seconds: "segundos"
minute: "minuto"
minutes: "minutos"
hour: "hora"
hours: "horas"
helpHeader: "&8========[ &e%NAME% &8| &e%PAGE%/%MAX% &8]========"
helpPageNotFound: "&8[&eManutencao&8] &cNao existe nenhuma pagina com esse numero!"
helpNextPage: "&7Use &b/maintenance help %PAGE% &7para ir para a próxima págin."
helpAbortTimer: "&6/maintenance aborttimer &7(Se estiver a correr o temporizador vai ser abortado)"
helpEndtimer: "&6/maintenance endtimer <minutes> &7(Depois do temporizador acabar a manutenção vai ser desativada)"
helpStarttimer: "&6/maintenance starttimer <minutes> &7(Depois do temporizador acabar a manutenção vai ser ativa)"
helpDump: "&6/maintenance dump &7(Discarta alguma informação do server, usado para bugs)"
helpHelp: "&6/maintenance help [page] &7(Mostra o help da manutenção)"
helpMotd: "&6/maintenance motd [timer] &7(Lista as motd currentes. Se usar 'timer', os temporizadores vão ser mostrados)"
helpRemoveMotd: "&6/maintenance removemotd [timer] <index> &7(Remove a motd da manutenção. Se usar \"timer\" como argumento uma mensagem com tempo vai ser eliminada)"
helpSetMotd: "&6/maintenance setmotd [timer] <index> <1/2> <message> &7(Define a motd da manutenção. Se usar \"timer\" como argumento uma mensagem com tempo vai aparecer)"
helpReload: "&6/maintenance reload &7(Dá reload ao plugin de manutenção)"
helpToggle: "&6/maintenance <on/off> &7(Ativa/Desativa a manutenção)"
helpUpdate: "&6/maintenance update &7(Arualiza o plugin de manutenção)"
helpWhitelist: "&6/maintenance whitelist &7(Mostra os payers que estão na whitelist)"
helpWhitelistAdd: "&6/maintenance add <name/uuid> &7(Adiciona o player à whitelist para poder entrar durante a manutenção)"
helpWhitelistRemove: "&6/maintenance remove <name/uuid> &7(Remove o player da whitelist)"
# Algumas mensagens para o Bungee/Velocity, ignora-as se estas a usar Spigot/Sponge
helpAbortSingleTimer: "&6/maintenance aborttimer [server] &7(Se o timer estiver ativado este vai ser abortado)"
helpSingleEndtimer: "&6/maintenance endtimer [server] <minutes> &7(Depois do tempo dado a manutenção vai ser desativada)"
helpSingleStarttimer: "&6/maintenance starttimer [server] <minutes> &7(Depois do tempo dado a manutenção vai ser ativa)"
helpSingleScheduleTimer: "&6/maintenance scheduletimer [server] <timer minutes> <maintenance duration> &7(After the given time in minutes, maintenance mode will be enabled for the given duration in minutes)"
helpSingleToggle: "&6/maintenance <on/off> [server] &7(Ativa/Desativa a manutenção)"
helpStatus: "&6/maintenance status &7(Lista os servers em proxy que estão em manutenção)"
@@ -0,0 +1,96 @@
# Maintenance Plugin by KennyTV
# Translators: En_0t_S
# Don't remove words inbetween the '%' if you don't exactly know why you're doing it
noPermission: "&cУ вас недостаточно прав!"
kickmessage: "&cСервер закрыт на технические работы!"
maintenanceActivated: "&aРежим технических работ включен!"
maintenanceDeactivated: "&7Режим технических работ выключен!"
alreadyEnabled: "&cРежим технических работ уже включен!"
alreadyDisabled: "&cРежим технических работ не был включен."
endtimerBroadcast: "&aСервер будет открыт через &f%TIME%&a!"
endtimerStarted: "&aТаймер успешно запущен! &aСервер будет открыт через &f%TIME%&a!"
starttimerBroadcast: "&aСервер будет закрыт на технические работы через &f%TIME%&a!"
starttimerStarted: "&aТаймер успешно запущен! &aСервер будет закрыт на технические работы через &f%TIME%&a!"
timerAlreadyRunning: "&cТаймер уже запущен!"
timerNotRunning: "&cТаймер не был запущен."
timerCancelled: "&7Таймер был остановлен."
timerTooLong: "&cЧисло должно быть не больше чем &f40320 &c(&f28 &cдней)."
timerMotdDisabled: "&cСообщения по таймеру выключены в настройках плагина."
motdTimer: "%HOURS%:%MINUTES%:%SECONDS%"
motdTimerNotRunning: "-"
joinNotification: "&cИгрок &f%PLAYER% &cпытался зайти на сервер."
motdList: "&7Список титульных строк в режиме технических работ:"
motdListEmpty: "&cСписок пуст."
reload: "&aПлагин успешно перезагружен!"
removedMotd: "&aТитульная строка с индексом &f%INDEX% &aуспешно удалена!"
removeMotdError: "&cВы не можете удалить последние 2 титульные строки."
setMotd: "&aТитульная строка &f%LINE% &aс индексом &f%INDEX% &aуспешно изменена: &f%MOTD%"
setMotdIndexError: "&cНеверный индекс, допустимые значения: 1 - %NEWAMOUNT%."
setMotdLineError: "&cВторой аргумент должен быть номером строки (1 или 2)!"
updateDownloading: "&aОбновление загружается..."
updateFailed: "&cОбновление не удалось!"
updateFinished: "&aОбновление успешно пройдено! Перезагрузите сервер, чтобы избежать возможных проблем."
whitelistedPlayers: "&7Белый лист в режиме технических работ:"
whitelistedPlayersFormat: "&7- &f%NAME% &7(&f%UUID%&7)"
whitelistAdded: "&aИгрок &f%PLAYER% &aуспешно добавлен в белый лист!"
whitelistAlreadyAdded: "&cИгрок &f%PLAYER% &cуже в белом листе!"
whitelistRemoved: "&aИгрок &f%PLAYER% &aуспешно удалён из белого листа!"
whitelistNotFound: "&cДанный игрок не находится в белом листе!"
whitelistEmpty: "&cБелый лист пуст! Используйте /maintenance add [игрок|uuid] чтобы добавить кого-нибудь."
playerNotFound: "&cИгрок не найден!"
playerNotFoundUuid: "&cИгрок с таким UUID не найден!"
playerNotOnline: "&cИгрок должен быть онлайн!"
invalidUuid: "&cНеверный формат UUID!"
# Messages for the Bungee/Velocity part, just can ignore them if you use the plugin on Spigot/Sponge
sentToWaitingServer: "&cВы были перемещены в лобби!"
forceWaitingServer: "&cВы не можете покинуть лобби во время технических работ!"
serverNotFound: "&cСервер не найден!"
singleTimerAlreadyRunning: "&cТаймер сервера &f%SERVER% &cуже запущен!"
singleTimerCancelled: "&7Таймер сервера &f%SERVER% &7был остановлен."
singleTimerNotRunning: "&cТаймер сервера &f%SERVER% &cне был запущен."
singleEndtimerBroadcast: "&aСервер &f%SERVER% &aбудет открыт через &f%TIME%&a!"
singleStarttimerBroadcast: "&cВнимание! Сервер &f%SERVER% &cбудет закрыт на технические работы через &f%TIME%&c!"
singleMaintenanceKick: "&cДанный сервер закрыт на технические работы! Попробуйте позже."
singleMaintenanceKickComplete: "&cДанный сервер закрыт на технические работы!%NEWLINE%&cПопробуйте позже."
singleMaintenanceActivated: "&aРежим технических работ на сервере &f%SERVER% &aвключен!"
singleMaintenanceDeactivated: "&aРежим технических работ на сервере &f%SERVER% &aвыключен!"
singleServerAlreadyEnabled: "&cРежим технических работ на сервере &f%SERVER% &cуже включен!"
singleServerAlreadyDisabled: "&cРежим технических работ на сервере &f%SERVER% &cне был включен."
singleServerMaintenanceList: "&7Сервера на которых включен режим технических работ:"
singleServerMaintenanceListEmpty: "&7Сервера на которых включен режим технических работ: &fпусто"
second: "секунду"
seconds: "секунд"
minute: "минуту"
minutes: "минут"
hour: "час"
hours: "часов"
helpHeader: "&7========[ &f%NAME% &7| &6%PAGE%&f/&6%MAX% &7]========"
helpPageNotFound: "&cСтраница не найдена."
helpNextPage: "&fИспользуйте &6/maintenance help %PAGE% &fчтобы перейти на следующую страницу."
helpAbortTimer: "&6/maintenance aborttimer &7- &fОстановить таймер включения/выключения режима технических работ."
helpEndtimer: "&6/maintenance endtimer [время в минутах] &7- &fЗапустить таймер выключения режима технических работ."
helpStarttimer: "&6/maintenance starttimer [время в минутах] &7- &fЗапустить таймер включения режима технических работ."
helpDump: "&6/maintenance dump &7- &fСоздать дамп."
helpHelp: "&6/maintenance help [страница] &7- &fОтобразить список доступных команд."
helpMotd: "&6/maintenance motd <timer> &7- &fОтобразить список титульных сообщений."
helpRemoveMotd: "&6/maintenance removemotd <timer> [индекс] &7- &fУдалить титульное сообщение."
helpSetMotd: "&6/maintenance setmotd <timer> [индекс] [1|2] [сообщение] &7- &fДобавить новое титульное сообщение."
helpReload: "&6/maintenance reload &7- &fПерезагрузить плагин."
helpToggle: "&6/maintenance [on|off] &7- &fВключить/выключить режим технических работ."
helpUpdate: "&6/maintenance update &7- &fОбновить плагин."
helpWhitelist: "&6/maintenance whitelist &7- &fОтобразить всех игроков из белого списка."
helpWhitelistAdd: "&6/maintenance add [ник|uuid] &7- &fДобавить игрока в белый список."
helpWhitelistRemove: "&6/maintenance remove [ник|uuid] &7- &fУдалить игрока из белого списка."
# Messages for the Bungee/Velocity part, just can ignore them if you use the plugin on Spigot/Sponge
helpAbortSingleTimer: "&6/maintenance aborttimer [сервер] &7- &fОстановить таймер включения/выключения режима технических работ."
helpSingleEndtimer: "&6/maintenance endtimer [сервер] [время в минутах] &7- &fЗапустить таймер выключения режима технических работ."
helpSingleStarttimer: "&6/maintenance starttimer [сервер] [время в минутах] &7- &fЗапустить таймер включения режима технических работ."
helpSingleScheduleTimer: "&6/maintenance scheduletimer [server] <timer minutes> <maintenance duration> &7(After the given time in minutes, maintenance mode will be enabled for the given duration in minutes)"
helpSingleToggle: "&6/maintenance [on|off] [сервер] &7- &fВключить/выключить режим технических работы."
helpStatus: "&6/maintenance status &7- &fСписок всех серверов закрытых на технические работы."
@@ -0,0 +1,96 @@
# Maintenance 插件由 KennyTV 开发
# 简体中文由 RinAfter 提供
# 如果你不清楚请不要删除 '%' 之间的单词
noPermission: "&c你没有执行该命令的权限。"
kickmessage: "&c服务器正在维护!%NEWLINE%&c请稍后再试!"
maintenanceActivated: "&8[&eMaintenance&8] &6维护模式已启用。"
maintenanceDeactivated: "&8[&eMaintenance&8] &6维护模式已停用。"
alreadyEnabled: "&8[&eMaintenance&8] &c维护模式已开启。"
alreadyDisabled: "&8[&eMaintenance&8] &c维护模式已关闭!"
endtimerBroadcast: "&8[&eMaintenance&8] &7维护模式将在&6%TIME%&7后关闭"
endtimerStarted: "&8[&eMaintenance&8] &a开始计时: &7维护模式将在&6%TIME%&7后关闭"
starttimerBroadcast: "&8[&eMaintenance&8] &7维护模式将在&6%TIME%&7后开启"
starttimerStarted: "&8[&eMaintenance&8] &a开始计时: &7维护模式将在&6%TIME%&7后开启。"
timerAlreadyRunning: "&8[&eMaintenance&8] &c当前已有计时正在执行!"
timerNotRunning: "&8[&eMaintenance&8] &c当前没有正在运行的计时器。"
timerCancelled: "&8[&eMaintenance&8] &c当前计时器已中止。"
timerTooLong: "&8[&eMaintenance&8] &c数值必须小于40320(28天)!"
timerMotdDisabled: "&8[&eMaintenance&8] &c如果要使用/编辑特定于计时器的MOTD,你必须在Config.yml配置中将'enable-timerspecific-messages'设置为'true'"
motdTimer: "%HOURS%:%MINUTES%:%SECONDS%"
motdTimerNotRunning: "-"
joinNotification: "&8[&eMaintenance&8] &e%PLAYER%&c试图加入服务器。"
motdList: "&8[&eMaintenance&8] &7当前维护模式MOTD:"
motdListEmpty: "8[&eMaintenance&8] &c你没有配置维护模式MOTD!"
reload: "&8[&eMaintenance&8] &a重新加载配置、维护玩家白名单、语言文件和维护图标"
removedMotd: "&8[&eMaintenance&8] &a删除第%INDEX%条维护模式MOTD"
removeMotdError: "&8[&eMaintenance&8] &c你只有一条维护模式MOTD,所有你不能再删除任何MOTD!"
setMotd: "&8[&eMaintenance&8] &a设置第%INDEX%条第%LINE%行维护模式MOTD为%MOTD%"
setMotdIndexError: "&8[&eMaintenance&8] &c你现在有%MOTDS%条MOTD,所以你必须选择一个介于1和%NEWAMOUNT%之间的数字。"
setMotdLineError: "&8[&eMaintenance&8] &c第二个参数必须是行号(1或2)!"
updateDownloading: "&8[&eMaintenance&8] &c&l正在下载更新..."
updateFailed: "&8[&eMaintenance&8] &4&l更新失败!"
updateFinished: "&8[&eMaintenance&8] &a&l插件更新成功!为了防止任务出现问题并完成更新,你必须重新启动服务器!"
whitelistedPlayers: "&8[&eMaintenance&8] &6维护玩家白名单:"
whitelistedPlayersFormat: "&8- &e%NAME% &8(&7%UUID%&8)"
whitelistAdded: "&8[&eMaintenance&8] &a将&b%PLAYER%&a添加到维护玩家白名单!"
whitelistAlreadyAdded: "&8[&eMaintenance&8] &c玩家&b%PLAYER%&c已在维护玩家白名单中!"
whitelistRemoved: "&8[&eMaintenance&8] &a从维护玩家白名单中删除&b%PLAYER%&a!"
whitelistNotFound: "&8[&eMaintenance&8] &c此玩家不在维护玩家白名单中!"
whitelistEmpty: "&8[&eMaintenance&8] &c维护玩家白名单为空!使用&e/maintenance add <player/uuid> &c添加某人!"
playerNotFound: "&8[&eMaintenance&8] &c此服务器上从未出现该名称的玩家"
playerNotFoundUuid: "&8[&eMaintenance&8] &c找不到具有该UUID的玩家。"
playerNotOnline: "&8[&eMaintenance&8] &c没有使用该名称的在线玩家"
invalidUuid: "&8[&eMaintenance&8] &c无效的UUID格式!"
# Bungee/Velocity消息,如果在Spigot/Sponge上使用则可忽略以下内容
sentToWaitingServer: "&8[&eMaintenance&8] &c您已被传送到等待服务器!"
forceWaitingServer: "&8[&eMaintenance&8] &c启用维护时,您不能离开等待服务器!"
serverNotFound: "&8[&eMaintenance&8] &c未找到拥有此名称的服务器!"
singleTimerAlreadyRunning: "&8[&eMaintenance&8] &c该服务器已有计时器正在运行!"
singleTimerCancelled: "&8[&eMaintenance&8] &c服务器&e%SERVER%&c的计时器已中止"
singleTimerNotRunning: "&8[&eMaintenance&8] &c该服务器当前没有正在运行的计时器。"
singleEndtimerBroadcast: "&8[&eMaintenance&8] &7服务器%SERVER%的维护模式将在&6%TIME%&7后关闭。"
singleStarttimerBroadcast: "&8[&eMaintenance&8] &7服务器%SERVER%的维护模式将在&6%TIME%&7后开启。"
singleMaintenanceKick: "&8[&eMaintenance&8] &c服务器%SERVER%正在维护!请稍后再试!"
singleMaintenanceKickComplete: "&c服务器%SERVER%正在维护!%NEWLINE%&c你可以尝试重新加入另一个服务器!"
singleMaintenanceActivated: "&8[&eMaintenance&8] &6服务器&e%SERVER%&6的维护模式已启用。"
singleMaintenanceDeactivated: "&8[&eMaintenance&8] &6服务器&e%SERVER%&6的维护模式已停用。"
singleServerAlreadyEnabled: "&8[&eMaintenance&8] &c服务器&e%SERVER%&c的维护模式已开启!"
singleServerAlreadyDisabled: "&8[&eMaintenance&8] &c服务器&e%SERVER%&c的维护模式已关闭!"
singleServerMaintenanceList: "&8[&eMaintenance&8] &7已开启维护的服务器有:"
singleServerMaintenanceListEmpty: "&8[&eMaintenance&8] &7没有正在维护的服务器"
second: "秒"
seconds: "秒"
minute: "分钟"
minutes: "分钟"
hour: "小时"
hours: "小时"
helpHeader: "&8========[ &e%NAME% &8| &e%PAGE%/%MAX% &8]========"
helpPageNotFound: "&8[&eMaintenance&8] &c没有此页码的帮助页!"
helpNextPage: "&7使用&b/maintenance help %PAGE% &7切换到下一帮助页"
helpAbortTimer: "&6/maintenance aborttimer &7(中止当前开启的计时器)"
helpEndtimer: "&6/maintenance endtimer <minutes> &7(在以分钟为单位给定时间后将关闭维护模式)"
helpStarttimer: "&6/maintenance starttimer <minutes> &7(在以分钟为单位给定时间后将开启维护模式)"
helpDump: "&6/maintenance dump &7(转储一些服务器信息,用于错误报告)"
helpHelp: "&6/maintenance help [page] &7(显示帮助信息)"
helpMotd: "&6/maintenance motd [timer] &7(显示当前设置的维护模式MOTD。如果指定'timer',则显示计时器MOTD)"
helpRemoveMotd: "&6/maintenance removemotd [timer] <index> &7(删除维护模式的MOTD。如果使用'timer'参数,将设置计时器特定的Ping消息)"
helpSetMotd: "&6/maintenance setmotd [timer] <index> <1/2> <message> &7(设置维护模式的MOTD。如果使用'timer'参数,将设置计时器特定的Ping消息)"
helpReload: "&6/maintenance reload &7(重新加载配置、维护玩家白名单、语言文件和维护图标)"
helpToggle: "&6/maintenance <on/off> &7(开启/关闭维护模式)"
helpUpdate: "&6/maintenance update &7(远程下载最新版本插件到服务器)"
helpWhitelist: "&6/maintenance whitelist &7(显示所有维护玩家白名单)"
helpWhitelistAdd: "&6/maintenance add <name/uuid> &7(将玩家加入维护玩家白名单,这样即使开启了维护,他们也能加入服务器)"
helpWhitelistRemove: "&6/maintenance remove <name/uuid> &7(将玩家从维护玩家白名单中移除)"
# Bungee/Velocity消息,如果在Spigot/Sponge上使用则可忽略以下内容
helpAbortSingleTimer: "&6/maintenance aborttimer [server] &7(中止指定服务器开启的计时器)"
helpSingleEndtimer: "&6/maintenance endtimer [server] <minutes> &7(在以分钟为单位给定时间后将关闭指定服务器的维护模式)"
helpSingleStarttimer: "&6/maintenance starttimer [server] <minutes> &7(在以分钟为单位给定时间后将开启指定服务器的维护模式)"
helpSingleScheduleTimer: "&6/maintenance scheduletimer [server] <timer minutes> <maintenance duration> &7(After the given time in minutes, maintenance mode will be enabled for the given duration in minutes)"
helpSingleToggle: "&6/maintenance <on/off> [server] &7(开启/关闭指定服务器的维护模式)"
helpStatus: "&6/maintenance status &7(列出当前正在维护的所有服务器)"
Loaded 100 of 135 files, more files were not shown because too many files have changed in this diff. Show more