Compare commits

..
128 Commits
Author SHA1 Message Date
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
127 changed files with 3303 additions and 1119 deletions

No files matched your search

+73
View File
@@ -1,6 +1,79 @@
# 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.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!
+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.
+10 -7
View File
@@ -1,9 +1,11 @@
# 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)
[![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 Bukkit/Spigot, BungeeCord, Sponge as well as Velocity.
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 +16,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.5</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-2020 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,11 @@ 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();
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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-2020 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-2020 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-2020 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,36 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2020 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,34 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2020 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);
}
@@ -0,0 +1,28 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2020 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,52 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2020 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;
}
/**
* @return wrapped server object for the proxied 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-2020 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-2020 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-2020 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-2020 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.5</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.5</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.15-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-2020 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-2020 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,85 @@ 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);
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
p.disconnect(settingsProxy.getMessage("singleMaintenanceKickComplete").replace("%NEWLINE%", "\n").replace("%SERVER%", server.getName()));
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
@Nullable
public String getServer(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
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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-2020 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,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-2020 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,7 +35,7 @@ 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;
@@ -48,13 +48,12 @@ public final class ProxyPingListener implements Listener {
}
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"), "")
new ServerPing.PlayerInfo(settings.getPlayerCountHoverMessage(), "")
});
if (settings.hasCustomIcon() && plugin.getFavicon() != null)
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-2020 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,89 @@
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;
}
// 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;
final BungeeSenderInfo sender = new BungeeSenderInfo(event.getPlayer());
if (shouldKick(sender)) {
final Server waitingServer = shouldConnectToWaitingServer(sender);
if (waitingServer != null) {
event.setTarget(((BungeeServer) waitingServer).getServer());
sender.sendMessage(settings.getMessage("sentToWaitingServer"));
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 (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-2020 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-2020 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,9 @@ 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);
}
}
public ServerInfo getServer() {
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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.5</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-2020 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.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;
@@ -28,11 +29,9 @@ 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.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* @author KennyTV
@@ -46,19 +45,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 +78,20 @@ public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implement
}
public void serverActions(final Server server, final boolean maintenance) {
if (server instanceof DummyServer) return;
if (server == null || server instanceof DummyServer) return;
if (maintenance) {
final Server fallback = getServer(settingsProxy.getFallbackServer());
final Server fallback = settingsProxy.getFallbackServer();
if (fallback == null) {
if (server.hasPlayers())
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);
eventManager.callEvent(new ServerMaintenanceChangedEvent(server, maintenance));
}
@Override
@@ -92,6 +99,11 @@ public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implement
return serverTasks.containsKey(server.getName());
}
@Override
public Set<String> getMaintenanceServers() {
return Collections.unmodifiableSet(settingsProxy.getMaintenanceServers());
}
public void cancelSingleTask(final Server server) {
final Task task = serverTasks.remove(server.getName());
if (task != null)
@@ -99,13 +111,14 @@ public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implement
}
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));
final MaintenanceRunnableBase runnable = new SingleMaintenanceRunnable(this, settingsProxy, minutes * 60, enable, 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");
list.addAll(settingsProxy.getMaintenanceServers());
@@ -117,11 +130,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;
}
@Nullable
public abstract String getServer(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-2020 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 Set<String> maintenanceServers;
private String fallbackServer;
private List<String> fallbackServers;
private String waitingServer;
private String mySQLTable;
private String serverTable;
@@ -51,18 +53,20 @@ public final class SettingsProxy extends Settings {
}
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,50 @@ 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))
plugin.serverActions(plugin.getServer(s), true);
}
// Disable maintenance on now unlisted servers
for (final String s : maintenanceServers) {
if (!databaseValue.contains(s))
plugin.serverActions(plugin.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 = getMessage("singleMaintenanceKicks." + server, null);
if (message == null) {
message = getMessage("singleMaintenanceKick");
}
return plugin.formatedTimer(message).replace("%SERVER%", server);
}
// Full = being kicked from the proxy, not just a proxied server
public String getFullServerKickMessage(final String server) {
String message = getMessage("singleMaintenanceKicksComplete." + server, null);
if (message == null) {
message = getMessage("singleMaintenanceKickComplete");
}
return plugin.formatedTimer(message).replace("%SERVER%", server);
}
public boolean hasMySQL() {
@@ -188,6 +226,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 +242,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 = plugin.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-2020 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;
@@ -50,7 +50,13 @@ public abstract class MaintenanceProxyCommand extends MaintenanceCommand {
@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) {
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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-2020 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-2020 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 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,19 +43,19 @@ 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.startMaintenanceRunnableForMinutes(Integer.parseInt(args[1]), 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;
}
@@ -68,7 +68,7 @@ public final class SingleEndtimerCommand extends ProxyCommandInfo {
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), false);
sender.sendMessage(getMessage("endtimerStarted").replace("%TIME%", runnable.getTime()));
} 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-2020 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 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 +43,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,12 +51,12 @@ public final class SingleStarttimerCommand extends ProxyCommandInfo {
return;
}
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), true);
plugin.startMaintenanceRunnableForMinutes(Integer.parseInt(args[1]), 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;
}
@@ -70,7 +70,7 @@ public final class SingleStarttimerCommand extends ProxyCommandInfo {
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), true);
sender.sendMessage(getMessage("starttimerStarted").replace("%TIME%", runnable.getTime()));
} 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-2020 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,14 @@ 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.getServer(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);
sender.sendMessage(getHelpMessage());
}
@Override
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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 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
@@ -34,7 +34,9 @@ public final class StatusCommand extends ProxyCommandInfo {
sender.sendMessage(getMessage("singleServerMaintenanceListEmpty"));
} else {
sender.sendMessage(getMessage("singleServerMaintenanceList"));
getSettings().getMaintenanceServers().forEach(server -> sender.sendMessage("§8- §b" + server));
for (final String server : getSettings().getMaintenanceServers()) {
sender.sendMessage("§8- §b" + server);
}
}
}
}
@@ -0,0 +1,122 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2020 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.getServer(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-2020 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-2020 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
@@ -27,11 +27,16 @@ import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
public final class SingleMaintenanceRunnable extends MaintenanceRunnableBase {
private 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);
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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,6 @@ public final class DummyServer implements Server {
}
@Override
public void broadcast(String s) {
public void broadcast(final String s) {
}
}
@@ -0,0 +1,29 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2020 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,46 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2020 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;
}
}
+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.5</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-2020 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,36 @@
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.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 +55,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 +69,15 @@ public abstract class MaintenancePlugin implements IMaintenance {
private final String prefix;
private final ServerType serverType;
private Version newestVersion;
private Task task;
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 +89,98 @@ 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(final String s) {
return s.contains("%TIMER%") ? s.replace("%TIMER%", formatedTimer()) : s;
}
public String formatedTimer() {
if (!isTaskRunning()) return "-";
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 startMaintenanceRunnableForMinutes(final int minutes, final boolean enable) {
startMaintenanceRunnableForSeconds(minutes * 60, enable);
}
public void startMaintenanceRunnableForSeconds(final int seconds, final boolean enable) {
runnable = new MaintenanceRunnable(this, settings, seconds, 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 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 {
final int seconds = (int) TimeUnit.MILLISECONDS.toSeconds(settings.getSavedEndtimer() - current);
startMaintenanceRunnableForSeconds(seconds, false);
getLogger().info("The timer has been continued - maintenance will be disabled in: " + formatedTimer());
}
}
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 +189,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,16 +221,14 @@ 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) {
}
}
}
@@ -170,11 +242,8 @@ public abstract class MaintenancePlugin implements IMaintenance {
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) {
@@ -194,7 +263,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 +279,19 @@ 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 +303,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 +320,7 @@ public abstract class MaintenancePlugin implements IMaintenance {
@Override
public boolean isTaskRunning() {
return task != null && runnable != null;
return runnable != null;
}
@Override
@@ -250,15 +328,25 @@ 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;
}
public int getSaltLevel() {
return Integer.MAX_VALUE;
}
public Version getNewestVersion() {
return newestVersion;
}
@@ -267,6 +355,10 @@ public abstract class MaintenancePlugin implements IMaintenance {
return prefix;
}
/**
* @see #isTaskRunning()
*/
@Nullable
public MaintenanceRunnable getRunnable() {
return runnable;
}
@@ -289,8 +381,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 +403,5 @@ public abstract class MaintenancePlugin implements IMaintenance {
protected abstract void kickPlayers();
protected abstract Task startMaintenanceRunnable(Runnable runnable);
protected abstract File getPluginFile();
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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,16 +20,24 @@ package eu.kennytv.maintenance.core;
import eu.kennytv.maintenance.api.ISettings;
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 +45,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 +53,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 +65,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 +98,19 @@ 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());
}
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 +122,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 +147,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 +168,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";
@@ -289,9 +325,16 @@ public class Settings implements ISettings {
}
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.formatedTimer(s)));
}
@Override
@@ -306,10 +349,15 @@ 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 +378,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 +411,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.formatedTimer(playerCountMessage);
}
public String getPlayerCountHoverMessage() {
return playerCountHoverMessage.replace("%TIMER%", plugin.formatedTimer());
return plugin.formatedTimer(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.formatedTimer(getMessage("kickmessage"));
}
public String getLanguage() {
@@ -391,6 +472,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-2020 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-2020 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,9 +22,9 @@ import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.command.subcommand.*;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.core.util.ServerType;
import java.util.*;
import java.util.stream.Collectors;
public abstract class MaintenanceCommand {
protected final MaintenancePlugin plugin;
@@ -90,8 +90,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();
}
@@ -132,8 +141,13 @@ public abstract class MaintenanceCommand {
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-2020 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;
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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,14 +25,14 @@ import eu.kennytv.maintenance.core.util.SenderInfo;
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 +40,7 @@ public final class EndtimerCommand extends CommandInfo {
return;
}
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), false);
plugin.startMaintenanceRunnableForMinutes(Integer.parseInt(args[1]), 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-2020 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,20 +23,20 @@ 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;
}
@@ -44,7 +44,7 @@ public final class HelpCommand extends CommandInfo {
sendUsage(sender);
} else {
if (!plugin.isNumeric(args[1])) {
sender.sendMessage(helpMessage);
sender.sendMessage(getHelpMessage());
return;
}
@@ -59,7 +59,12 @@ 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;
@@ -71,12 +76,15 @@ public final class HelpCommand extends CommandInfo {
else
filteredCommands = commands.subList((page - 1) * COMMANDS_PER_PAGE, page * COMMANDS_PER_PAGE);
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);
for (final String command : filteredCommands) {
sender.sendMessage(command);
}
if (page * COMMANDS_PER_PAGE < commands.size())
sender.sendMessage("§7Use §b/maintenance help " + (page + 1) + " §7to get to the next help window.");
sender.sendMessage(getMessage("helpNextPage").replace("%PAGE%", Integer.toString(page + 1)));
else
sender.sendMessage("§8× §eVersion " + plugin.getVersion() + " §7by §bKennyTV");
sender.sendMessage(header);
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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,49 @@ 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-2020 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-2020 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(String.valueOf(i));
}
return list;
}
return list;
return Collections.emptyList();
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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,38 @@ 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-2020 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,14 +25,14 @@ import eu.kennytv.maintenance.core.util.SenderInfo;
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 +40,7 @@ public final class StarttimerCommand extends CommandInfo {
return;
}
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), true);
plugin.startMaintenanceRunnableForMinutes(Integer.parseInt(args[1]), 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-2020 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-2020 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,6 +39,11 @@ 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())
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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.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
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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
@@ -41,7 +41,9 @@ public final class WhitelistCommand extends CommandInfo {
} else {
sender.sendMessage(getMessage("whitelistedPlayers"));
final String format = getMessage("whitelistedPlayersFormat");
players.forEach((key, value) -> sender.sendMessage(format.replace("%NAME%", value).replace("%UUID%", key.toString())));
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-2020 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
@@ -46,8 +46,15 @@ public final class WhitelistRemoveCommand extends CommandInfo {
@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) {
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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-2020 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-2020 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,87 @@ 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?
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 +124,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 +171,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-2020 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-2020 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-2020 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,46 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2020 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);
}
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-2020 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-2020 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) {
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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,8 +23,8 @@ import eu.kennytv.maintenance.core.Settings;
public final 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
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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 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 ? startMessageKey() : endMessageKey());
}
seconds--;
@@ -67,10 +67,22 @@ public abstract class MaintenanceRunnableBase implements Runnable {
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();
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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-2020 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-2020 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-2020 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,36 @@ 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)"
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,36 @@ 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)"
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)"
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,94 @@
# Maintenance Plugin by KennyTV
# Don't remove words inbetween the '%' if you don't exactly know why you're doing it
noPermission: "&4No tienes Permiso para ejecutar este comando."
kickmessage: "&cEl servidor se encuentra en &6Mantenimiento!%NEWLINE%&cIntentalo de nuevo mas tarde!"
maintenanceActivated: "&8[&eMaintenance&8] &6Mantenimiento &7Activado"
maintenanceDeactivated: "&8[&eMaintenance&8] &7Modo &6Mantenimiento &7Desactivado"
alreadyEnabled: "&8[&eMaintenance&8] &7Modo &6Mantenimiento &7se encuentra Habilitado!"
alreadyDisabled: "&8[&eMaintenance&8] &7Modo &6Mantenimiento &7se encuentra Deshabilitado!"
endtimerBroadcast: "&8[&eMaintenance&8] &7El Modo &6Mantenimiento &7se desactivara en &6%TIME%&7."
endtimerStarted: "&8[&eMaintenance&8] &7Temporizador Iniciado: El Modo &6Mantenimiento &7se desactivará en &6%TIME%&7."
starttimerBroadcast: "&8[&eMaintenance&8] &7El Modo &6Mantenimiento &7se habilitara en &6%TIME%&7."
starttimerStarted: "&8[&eMaintenance&8] &7Temporizador Iniciado: El Modo &6Mantenimiento &7se activará en &6%TIME%&7."
timerAlreadyRunning: "&8[&eMaintenance&8] &7Ya 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 &6(28 dias)"
timerMotdDisabled: "&8[&eMaintenance&8] &cTienes que configurar 'enable-timerspecific-messages' en la configuración en 'true', 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 &6Mantenimiento&7:"
motdListEmpty: "8[&eMaintenance&8] &c¡No tiene ningún juego de mantenimiento establecido!"
reload: "&8[&eMaintenance&8] &aConfiguracion Recargada"
removedMotd: "&8[&eMaintenance&8] &aNumero de Motd eliminado &6%INDEX%."
removeMotdError: "&8[&eMaintenance&8] &Solo tienes un Motd, por lo que no puedes eliminar ninguno!"
setMotd: "&8[&eMaintenance&8] &aEstablecer linea &6%LINE%&a del &6%INDEX%. &6Mantenimiento&a para %MOTD%"
setMotdIndexError: "&8[&eMaintenance&8] &aActualmente tiene &6%MOTDS%&a Motds, 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)!"
updateDownloading: "&8[&eMaintenance&8] &aDescargando Actualizacion..."
updateFailed: "&8[&eMaintenance&8] &aActualizacion &cFallida!"
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 &6Mantenimiento!"
whitelistAlreadyAdded: "&8[&eMaintenance&8] &a%PLAYER% &7Se encuentra en la lista de &6Mantenimiento!"
whitelistRemoved: "&8[&eMaintenance&8] &c%PLAYER% &7Eliminado de la lista de &6Mantenimiento!"
whitelistNotFound: "&8[&eMaintenance&8] &7No se encuentra en la lista de &6Mantenimiento!"
whitelistEmpty: "&8[&eMaintenance&8] &7La lista de &6Mantenimiento 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 ese 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] &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] &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% &c ha sido desactivado."
singleEndtimerBroadcast: "&8[&eMaintenance&8] &7Modo &6Mantenimiento &7en el Servidor &6%SERVER% &cse desactivará en &6%TIME%"
singleStarttimerBroadcast: "&8[&eMaintenance&8] &7Modo &6Mantenimiento &7en el Servidor &6%SERVER%&7se activará en &6%TIME%"
singleMaintenanceKick: "&8[&eMaintenance&8] &7El servidor &6%SERVER% &7se encuentra en &6Mantenimiento&7! Intentalo mas tarde!"
singleMaintenanceKickComplete: "&7El Servidor &6%SERVER% &7esta en &6Mantenimiento&7!%NEWLINE%&cVuelve Mas Tarde!"
singleMaintenanceActivated: "&8[&eMaintenance&8] &7El Modo&6Mantenimiento &7Esta Activado en el Servidor &6%SERVER%&7."
singleMaintenanceDeactivated: "&8[&eMaintenance&8] &7El Modo &6Mantenimiento &7Ahora esta deshabilitado en &6%SERVER%&7."
singleServerAlreadyEnabled: "&8[&eMaintenance&8] &7El Modo &6Mantenimiento &7se encuentra Habilitado en &6%SERVER%&7!"
singleServerAlreadyDisabled: "&8[&eMaintenance&8] 7El Modo &6Mantenimiento &7se encuentra Deshabilitado en &6%SERVER%&7!"
singleServerMaintenanceList: "&8[&eMaintenance&8] &7Servidores Proxy, que tienen habilitado el &6Mantenimiento:"
singleServerMaintenanceListEmpty: "&8[&eMaintenance&8] &7No hay servidores Proxy que están en &6Mantenimiento&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 &7(Si se ejecuta, se abortará el temporizador actual)"
helpEndtimer: "&6/maintenance endtimer <minutes> &7(Después del tiempo en minutos, se desactivará el modo de mantenimiento)"
helpStarttimer: "&6/maintenance starttimer <minutes> &7(Después del tiempo en minutos, se habilitará el modo de mantenimiento)"
helpDump: "&6/maintenance dump &7(Vuelca información del servidor, usada para informes de errores)"
helpHelp: "&6/maintenance help [page] &7(Muestra esta hermosa ventana de ayuda)"
helpMotd: "&6/maintenance motd [timer] &7(Enumera los motivos de mantenimiento establecidos actualmente. Si se especifica el 'temporizador', se muestran los motivos del temporizador)"
helpRemoveMotd: "&6/maintenance removemotd [timer] <index> &7(Elimina un mantenimiento motd. Si se usa 'timer' como argumento, se eliminará un pingmessage de temporizador específico)"
helpSetMotd: "&6/maintenance setmotd [timer] <index> <1/2> <message> &7(Establece un motd para el modo de mantenimiento. Si usa 'timer' como argumento, se establecerá un mensaje de ping específico para el tiempo)"
helpReload: "&6/maintenance reload &7(Vuelve a cargar el archivo de configuración, el archivo de la lista blanca y el ícono del servidor)"
helpToggle: "&6/maintenance <on/off> &7(Habilita / deshabilita el modo de mantenimiento)"
helpUpdate: "&6/maintenance update &7(Descarga de forma remota la versión más reciente del complemento en su servidor)"
helpWhitelist: "&6/maintenance whitelist &7(Muestra todos los reproductores en lista blanca para el modo de mantenimiento)"
helpWhitelistAdd: "&6/maintenance add <name/uuid> &7(Agrega el reproductor a la lista blanca de mantenimiento, para que puedan unirse al servidor aunque el mantenimiento esté habilitado)"
helpWhitelistRemove: "&6/maintenance remove <name/uuid> &7(Quita el reproductor de la lista blanca de mantenimiento)"
# Messages for the Bungee/Velocity part, just can ignore them if you use the plugin on Spigot/Sponge
helpAbortSingleTimer: "&6/maintenance aborttimer [servidor] &7(Si está funcionando, se abortará el temporizador actual)"
helpSingleEndtimer: "&6/maintenance endtimer [server] <minutes> &7(Después del tiempo en minutos, se desactivará el modo de mantenimiento)"
helpSingleStarttimer: "&6/maintenance starttimer [server] <minutes> &7(Después del tiempo en minutos, el modo de mantenimiento habilitado)"
helpSingleToggle: "&6/maintenance <on/off> [server] &7(Habilita / deshabilita el modo de mantenimiento)"
helpStatus: "&6/maintenance status &7(Enumera todos los servidores proxy, que están actualmente en mantenimiento)"
@@ -7,7 +7,6 @@ maintenanceActivated: "&8[&eMaintenance&8] &6Le mode maintenance est maintenant
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!"
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."
@@ -16,8 +15,12 @@ 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)!"
timerMotdDisabled: "&8[&eMaintenance&8] &cVous devez définir 'enable-timerspecific-messages' dans la configuration sur 'true', si vous voulez utiliser / éditer des timerspecific motd."
motdTimer: "%HOURS%:%MINUTES%:%SECONDS%"
motdTimerNotRunning: "-"
joinNotification: "&8[&eMaintenance&8] &e%PLAYER% &ca essayé de rejoindre le serveur."
motdList: "&8[&eMaintenance&8] &7Liste de vos motd pour la maintenance:"
motdListEmpty: "8[&eMaintenance&8] &cVous n'avez pas de motds d'entretien fixés!"
reload: "&8[&eMaintenance&8] &afichier config, liste blanche (whitelist) joueurs, fichier de langue et l'icône de maintenance, recharger."
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!"
@@ -39,15 +42,11 @@ playerNotFoundUuid: "&8[&eMaintenance&8] &cAucun joueur avec cet uuid n'a pu êt
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!"
second: "second"
seconds: "seconds"
minute: "minute"
minutes: "minutes"
hour: "heur"
hours: "heurs"
# Quelques messages pour la partie Bungee, ignorez-les si vous utilisez le plugin sur Spigot
# Quelques messages pour la partie Bungee/Velocity, ignorez-les si vous utilisez le plugin sur 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] &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."
@@ -60,4 +59,36 @@ singleMaintenanceDeactivated: "&8[&eMaintenance&8] &6La maintenance est maintena
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."
singleServerMaintenanceListEmpty: "&8[&eMaintenance&8] &7Il n'y a pas de serveurs proxy en maintenance."
second: "second"
seconds: "seconds"
minute: "minute"
minutes: "minutes"
hour: "heur"
hours: "heurs"
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(Dépose 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 sont 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, le fichier de liste blanche 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écharger 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 la 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 la 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é)"
helpSingleToggle: "&6/maintenance <on/off> [server] &7(Active/désactive le mode maintenance)"
helpStatus: "&6/maintenance status &7(Répertorie tout les serveurs mandatés, actuellement en maintenance)"
@@ -0,0 +1,94 @@
# Maintenance Plugin by KennyTV
# 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)"
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)"
@@ -2,12 +2,11 @@
# 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 +15,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 +38,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 +59,36 @@ 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)"
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,94 @@
# Maintenance Plugin by KennyTV
# 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Запустить таймер включения режима технических работ."
helpSingleToggle: "&6/maintenance [on|off] [сервер] &7- &fВключить/выключить режим технических работы."
helpStatus: "&6/maintenance status &7- &fСписок всех серверов закрытых на технические работы."
@@ -0,0 +1,95 @@
# 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(在以分钟为单位给定时间后将开启指定服务器的维护模式)"
helpSingleToggle: "&6/maintenance <on/off> [server] &7(开启/关闭指定服务器的维护模式)"
helpStatus: "&6/maintenance status &7(列出当前正在维护的所有服务器)"
@@ -0,0 +1,124 @@
package eu.kennytv.maintenance.core.config;
import com.google.common.io.Files;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import java.io.File;
import java.io.IOException;
// I'm sorry in advance
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ConfigTest {
@BeforeAll
void initAll() {
delete("config.yml");
delete("config-saved.yml");
delete("dirty-config-saved.yml");
delete("dirty-config-upgraded.yml");
copyOriginalToTest("config.yml", "config.yml");
}
@Test
void testDeep() throws IOException {
final Config config = new Config(getTestFile("config.yml"));
config.load();
assert config.getInt("mysql.port") == 3306;
}
@Test
void testSaveConsistency() throws IOException {
final Config config = new Config(getTestFile("config.yml"));
config.load();
final File saveTo = getTestFile("config-saved.yml");
config.saveTo(saveTo);
final Config newlyLoaded = new Config(saveTo);
newlyLoaded.load();
assert newlyLoaded.toString().equals(config.toString());
}
@Test
void testParsing() throws IOException {
final Config config = new Config(getTestFile("dirty-config.yml"));
config.load();
final File saveTo = getTestFile("dirty-config-saved.yml");
config.saveTo(saveTo);
}
@Test
void testUpgrading() throws IOException {
final Config config = new Config(getTestFile("dirty-config.yml"));
config.load();
final Config newestConfig = new Config(getTestFile("config.yml"));
newestConfig.load();
config.addMissingFields(newestConfig.getValues(), newestConfig.getComments());
config.set("config-version", 4);
final File saveTo = getTestFile("dirty-config-upgraded.yml");
config.resetAwesomeHeader();
config.saveTo(saveTo);
final Config newlyLoaded = new Config(saveTo);
newlyLoaded.load();
assert newlyLoaded.contains("waiting-server");
assert newlyLoaded.getComments().get("maintenance-enabled") != null;
assert newlyLoaded.getComments().get("mysql.use-ssl") != null;
assert newlyLoaded.getComments().get("update-checks") != null;
assert newlyLoaded.getHeader().equals(newestConfig.getHeader());
assert newlyLoaded.getSection("mysql").getString("username").equals("useer");
assert newlyLoaded.getInt("config-version") == 4;
}
@Test
void testSetAndContains() throws IOException {
final Config config = new Config(getTestFile("config.yml"));
config.load();
// Test for pre-existing values
assert config.contains("fallback");
assert config.contains("mysql.password");
assert !config.contains("test");
assert config.getComments().containsKey("fallback");
assert config.getComments().containsKey("mysql.use-ssl");
config.set("test", "abc");
config.remove("fallback");
final ConfigSection section = config.getSection("mysql");
section.set("port", 1000);
section.remove("use-ssl");
assert config.contains("test") && config.getString("test").equals("abc");
assert config.getInt("mysql.port") == 1000;
assert !config.contains("mysql.use-ssl") && !config.getSection("mysql").contains("use-ssl");
assert !config.contains("fallback");
assert !config.getComments().containsKey("fallback");
assert !config.getComments().containsKey("mysql.use-ssl");
}
private File getTestFile(final String path) {
return new File("src/test/resources/" + path);
}
private void copyOriginalToTest(final String from, final String to) {
final File file = new File("src/main/resources/" + from);
try {
Files.copy(file, getTestFile(to));
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private void delete(final String path) {
final File file = getTestFile(path);
if (file.exists()) {
file.delete();
}
}
}
@@ -0,0 +1,61 @@
# Enables maintenance mode.
maintenance-enabled: true
# Enables maintenance on certain servers managed by your Bungee instance(s).
proxied-maintenance-servers:
- 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 the fallback server is not reachable/not set, they will just be kicked off the network.
fallback: ''
# 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).
pingmessages:
- |2-
&2&lX's &b&lServer &f- &7&l(1.12.2-1.15.2)
&4&n&lMANUTENZIONE!
enable-timerspecific-messages: true
timerspecific-pingmessages:
- |2-
&2&lX's &b&lServer &f- &7&l(1.12.2-1.15.2)
&4&n&lMANUTENZIONE! Torneremo tra %TIMER%
enable-playercountmessage: true
playercountmessage: '&41.12.2-1.15.2'
playercounthovermessage: '&n&lStato server: In manutenzione'
custom-maintenance-icon: false
send-join-notification: false
kick-online-players: true
language: de
mysql:
use-mysql: false
host: host
port: 3306
database: database
username: useer
password: password
update-interval: 15
use-ssl: true
continue-endtimer-after-restart:
enabled: false
end: 0
timer-broadcast-for-seconds:
- 1200
- 900
- 600
- 300
- 120
- 60
- 30
- 20
- 10
- 5
- 4
- 3
- 2
- 1
update-checks: true
config-version: 3
+13 -6
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.5</version>
</parent>
<artifactId>maintenance-spigot</artifactId>
@@ -14,15 +14,22 @@
<dependencies>
<dependency>
<groupId>eu.kennytv</groupId>
<groupId>eu.kennytv.maintenance</groupId>
<artifactId>maintenance-core</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.13.2-R0.1-SNAPSHOT</version>
<groupId>com.destroystokyo.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.15.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- Needed for backwards compatibility with Paper -->
<dependency>
<groupId>com.mojang</groupId>
<artifactId>authlib</artifactId>
<version>1.5.25</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-2020 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,24 @@ package eu.kennytv.maintenance.spigot;
import eu.kennytv.maintenance.api.IMaintenance;
import eu.kennytv.maintenance.api.IMaintenanceBase;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
public final class MaintenanceSpigotBase extends JavaPlugin implements IMaintenanceBase {
private IMaintenance maintenance;
private MaintenancePlugin maintenance;
@Override
public void onEnable() {
maintenance = new MaintenanceSpigotPlugin(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-2020 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,6 +28,7 @@ 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.spigot.command.MaintenanceSpigotCommand;
import eu.kennytv.maintenance.spigot.listener.PaperServerListPingListener;
import eu.kennytv.maintenance.spigot.listener.PlayerLoginListener;
import eu.kennytv.maintenance.spigot.listener.ServerInfoPacketListener;
import eu.kennytv.maintenance.spigot.listener.ServerListPingListener;
@@ -42,9 +43,11 @@ import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.util.CachedServerIcon;
import org.jetbrains.annotations.Nullable;
import javax.imageio.ImageIO;
import java.io.File;
@@ -67,23 +70,27 @@ public final class MaintenanceSpigotPlugin extends MaintenancePlugin {
super(plugin.getDescription().getVersion(), ServerType.SPIGOT);
this.plugin = plugin;
settings = new Settings(this, "mysql", "proxied-maintenance-servers", "fallback");
settings = new Settings(this, "mysql", "proxied-maintenance-servers", "fallback", "waiting-server");
sendEnableMessage();
final MaintenanceSpigotCommand command = new MaintenanceSpigotCommand(this, settings);
commandManager = command;
plugin.getCommand("maintenancespigot").setExecutor(command);
plugin.getCommand("maintenance").setExecutor(command);
final PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new PlayerLoginListener(this, settings), plugin);
if (pm.isPluginEnabled("ProtocolLib")) {
if (canUsePaperListener()) {
pm.registerEvents(new PaperServerListPingListener(this, settings), plugin);
} else if (pm.isPluginEnabled("ProtocolLib")) {
pm.registerEvents(new ServerInfoPacketListener(this, plugin, settings), plugin);
} else {
pm.registerEvents(new ServerListPingListener(this, settings), plugin);
getLogger().info("To use this plugin on Spigot to its full extend, you need the plugin ProtocolLib!");
getLogger().warning("To use this plugin on Spigot to its full extend, you need the plugin ProtocolLib!");
}
continueLastEndtimer();
new MetricsLite(plugin);
// ServerListPlus integration
@@ -95,6 +102,20 @@ public final class MaintenanceSpigotPlugin extends MaintenancePlugin {
}
}
private boolean canUsePaperListener() {
try {
Class.forName("com.destroystokyo.paper.event.server.PaperServerListPingEvent");
if (getServer().getPluginManager().isPluginEnabled("ProtocolSupport")) {
getLogger().warning("Found ProtocolSupport - switching to ProtocolLib packet adapter, as PS does not fire Paper's ping event");
return false;
}
return true;
} catch (final ClassNotFoundException e) {
return false;
}
}
@Deprecated
public static IMaintenance getAPI() {
return MaintenanceSpigotAPI.getAPI();
@@ -128,12 +149,14 @@ public final class MaintenanceSpigotPlugin extends MaintenancePlugin {
}
@Override
@Nullable
public SenderInfo getOfflinePlayer(final String name) {
final OfflinePlayer player = getServer().getOfflinePlayer(name);
return player.getName() != null ? new BukkitOfflinePlayerInfo(player) : null;
}
@Override
@Nullable
public SenderInfo getOfflinePlayer(final UUID uuid) {
final OfflinePlayer player = getServer().getOfflinePlayer(uuid);
return player.getName() != null ? new BukkitOfflinePlayerInfo(player) : null;
@@ -141,9 +164,11 @@ public final class MaintenanceSpigotPlugin extends MaintenancePlugin {
@Override
protected void kickPlayers() {
getServer().getOnlinePlayers().stream()
.filter(p -> !hasPermission(p, "bypass") && !settings.getWhitelistedPlayers().containsKey(p.getUniqueId()))
.forEach(p -> p.kickPlayer(settings.getKickMessage()));
for (final Player p : getServer().getOnlinePlayers()) {
if (!hasPermission(p, "bypass") && !settings.isWhitelisted(p.getUniqueId())) {
p.kickPlayer(settings.getKickMessage());
}
}
}
@Override
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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
@@ -46,40 +46,6 @@ public final class MaintenanceSpigotCommand extends MaintenanceCommand implement
return true;
}
/*@Override
protected void addPlayerToWhitelist(final SenderInfo sender, final String name) {
final Player selected = Bukkit.getOfflinePlayer(name);
if (selected != null) {
whitelistAddMessage(sender, new BukkitSenderInfo(selected));
return;
}
final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(name);
if (!offlinePlayer.hasPlayedBefore()) {
sender.sendMessage(settings.getMessage("playerNotFound"));
return;
}
whitelistAddMessage(sender, new BukkitOfflinePlayerInfo(offlinePlayer));
}
@Override
protected void removePlayerFromWhitelist(final SenderInfo sender, final String name) {
final Player selected = Bukkit.getOfflinePlayer(name);
if (selected != null) {
whitelistRemoveMessage(sender, new BukkitSenderInfo(selected));
return;
}
final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(name);
if (!offlinePlayer.hasPlayedBefore()) {
sender.sendMessage(settings.getMessage("playerNotFound"));
return;
}
whitelistRemoveMessage(sender, new BukkitOfflinePlayerInfo(offlinePlayer));
}*/
@Override
public List<String> onTabComplete(final CommandSender sender, final Command command, final String alias, final String[] args) {
return getSuggestions(new BukkitSenderInfo(sender), args);
@@ -0,0 +1,146 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018-2020 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.spigot.listener;
import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
import com.destroystokyo.paper.profile.PlayerProfile;
import com.destroystokyo.paper.profile.ProfileProperty;
import com.mojang.authlib.GameProfile;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.spigot.MaintenanceSpigotPlugin;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
public final class PaperServerListPingListener implements Listener {
private final MaintenanceSpigotPlugin plugin;
private final Settings settings;
public PaperServerListPingListener(final MaintenanceSpigotPlugin plugin, final Settings settings) {
this.plugin = plugin;
this.settings = settings;
}
@EventHandler(priority = EventPriority.HIGHEST)
public void serverListPing(final PaperServerListPingEvent event) {
if (!settings.isMaintenance()) return;
event.setMotd(settings.getRandomPingMessage());
if (settings.hasCustomPlayerCountMessage()) {
event.setProtocolVersion(-1);
event.setVersion(settings.getPlayerCountMessage()
.replace("%ONLINE%", Integer.toString(plugin.getServer().getOnlinePlayers().size()))
.replace("%MAX%", Integer.toString(plugin.getServer().getMaxPlayers())));
}
final List<PlayerProfile> sample = event.getPlayerSample();
sample.clear();
for (final String string : settings.getPlayerCountHoverMessage().split("\n")) {
sample.add(new DummyProfile(string));
}
if (settings.hasCustomIcon() && plugin.getFavicon() != null) {
event.setServerIcon(plugin.getFavicon());
}
}
// Less unnecessary object creation :>
private static final class DummyProfile implements PlayerProfile {
private final String name;
private DummyProfile(final String name) {
this.name = name;
}
@Nullable
@Override
public String getName() {
return name;
}
@Override
public String setName(@Nullable final String name) {
return this.name;
}
@Nullable
@Override
public UUID getId() {
return null;
}
@Override
public UUID setId(@Nullable final UUID uuid) {
return null;
}
@Nonnull
@Override
public Set<ProfileProperty> getProperties() {
return Collections.emptySet();
}
@Override
public boolean hasProperty(final String property) {
return false;
}
@Override
public void setProperty(final ProfileProperty property) {
}
@Override
public void setProperties(final Collection<ProfileProperty> properties) {
}
@Override
public boolean removeProperty(final String property) {
return false;
}
@Override
public void clearProperties() {
}
@Override
public boolean isComplete() {
return false;
}
@Override
public boolean completeFromCache() {
return false;
}
@Override
public boolean complete(final boolean textures) {
return false;
}
// Keep this here for backwards compatibility
public GameProfile getGameProfile() {
return null;
}
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* Copyright (C) 2018-2020 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.core.Settings;
import eu.kennytv.maintenance.core.listener.JoinListenerBase;
import eu.kennytv.maintenance.spigot.MaintenanceSpigotPlugin;
import eu.kennytv.maintenance.spigot.util.BukkitSenderInfo;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
@@ -37,15 +38,21 @@ public final class PlayerLoginListener extends JoinListenerBase implements Liste
@EventHandler
public void postLogin(final PlayerLoginEvent event) {
final BukkitSenderInfo sender = new BukkitSenderInfo(event.getPlayer());
if (kickPlayer(sender)) {
if (shouldKick(sender)) {
event.setResult(PlayerLoginEvent.Result.KICK_OTHER);
event.setKickMessage(settings.getKickMessage());
if (settings.isJoinNotifications()) {
broadcastJoinNotification(sender.getName());
}
}
}
@Override
protected void broadcastJoinNotification(final String name) {
plugin.getServer().getOnlinePlayers().stream().filter(p -> plugin.hasPermission(p, "joinnotification"))
.forEach(p -> p.sendMessage(settings.getMessage("joinNotification").replace("%PLAYER%", name)));
for (final Player p : plugin.getServer().getOnlinePlayers()) {
if (plugin.hasPermission(p, "joinnotification")) {
p.sendMessage(settings.getMessage("joinNotification").replace("%PLAYER%", name));
}
}
}
}
Loaded 100 of 127 files, more files were not shown because too many files have changed in this diff. Show more