Compare commits

..
213 Commits
Author SHA1 Message Date
Nassim Jahnke d8e36d7ff6 4.0.1 Release 2022-04-16 18:40:34 +02:00
Nassim Jahnke 39f966ba5d Update dependencies, actually fix tests 2022-04-15 21:51:29 +02:00
Nassim Jahnke 879f07e3e7 Fix tests 2022-04-15 20:08:13 +02:00
Nassim Jahnke 9cbead310a Fix config header saving 2022-03-23 09:27:43 +01:00
Nassim Jahnke 25375b184d Update workflow 2022-03-23 09:26:53 +01:00
Nassim Jahnke eec5acd0ce Bump version to 4.0.1-SNAPSHOT 2022-03-23 09:20:09 +01:00
Nassim Jahnke 14cef4d53b Fix Sponge metadata replacement 2022-03-17 10:50:56 +01:00
Nassim Jahnke 4d06d0f6b8 4.0.0 Release 2022-03-17 10:07:29 +01:00
Nassim Jahnke 5e22098023 Update adventure, update changelog, fix publishing 2022-03-15 10:44:21 +01:00
Nassim Jahnke 80cc51e48e Update gradle wrapper to 7.4.1 2022-03-09 18:52:43 +01:00
Nassim Jahnke 15ebe045f6 Update language files 2022-03-08 21:47:20 +01:00
Nassim Jahnke be39524717 Minor cleanup 2022-03-08 19:39:36 +01:00
Nassim Jahnke b8616d84c8 Update Gradle wrapper to 7.4, adventure to 4.10.0 2022-03-05 12:14:01 +01:00
Nassim Jahnke 7515d95b82 Merge remote-tracking branch 'origin/dev' into adventure-support
# Conflicts:
#	maintenance-core/src/main/resources/language-de.yml
2022-02-21 09:21:31 +01:00
Ceddix 2c0172d11e fixed spelling issue that caused a message not to work (#75) 2022-02-19 09:32:24 +01:00
Nassim Jahnke 920e3477ee Update default config values 2022-01-19 18:59:21 +01:00
Nassim Jahnke d8e0b6497a Cleanup a bit of language file updating 2022-01-16 19:16:45 +01:00
Nassim Jahnke 113895b564 Fix multiline playercount hover 2022-01-16 16:49:07 +01:00
Nassim Jahnke 99fffb5056 Configurable singleServerMaintenanceListEntry, remove LuckPerm context for now 2022-01-16 15:50:29 +01:00
Nassim Jahnke 3d2aa0ba9c Update language files, update config header 2022-01-16 15:01:04 +01:00
Nassim Jahnke 5486b9542a Update copyright header 2022-01-09 22:31:16 +01:00
Nassim Jahnke 5c2ff9588f Update Sponge module to API v8 2022-01-09 22:27:56 +01:00
Nassim Jahnke 3bcce2dfb9 Fixup dependencies 2022-01-01 14:58:27 +01:00
Nassim Jahnke 0db0d608e5 Improve language updating, add <prefix> placeholder 2021-12-31 16:43:40 +01:00
Nassim Jahnke ae895f4db5 Update workflow 2021-12-28 18:14:43 +01:00
Nassim Jahnke 351d842f3a Major version bump
Convert project to Gradle
Change API class names and split module into two
Add adventure component support
2021-12-28 18:03:34 +01:00
Nassim Jahnke 44dc76f381 WIP LuckPerms contexts 2021-12-28 09:40:29 +01:00
Nassim Jahnke 48792413f7 Update dependencies 2021-12-27 12:12:24 +01:00
Slasherss a81ea8d87d Add polish translations (#73) 2021-12-22 09:45:42 +01:00
Nassim Jahnke ba142a1c31 Update language-es.yml (thanks to Jaximo) 2021-12-07 08:59:31 +01:00
Aurélien f849724a8c Remove extra point (#70) 2021-08-19 22:18:25 +02:00
Aurélien 5e17e60921 Update language-fr.yml (#69) 2021-08-19 22:13:55 +02:00
kennytv fad98d7a14 Update language-pt.yml (thanks to JoaoPinto) 2021-08-18 17:37:25 +02:00
kennytv 31da57c9b2 Bump version to 3.0.8-SNAPSHOT, fix missing scheduletimer keys 2021-08-18 12:54:18 +02:00
Nassim Jahnke c1a03a6733 3.0.7 Release 2021-08-17 12:58:42 +02:00
kennytv 92ab4574e8 Prepare for 3.0.7 Release 2021-08-17 12:57:36 +02:00
kennytv f81851ad9a Update copyright header, readme, and license format 2021-08-12 10:43:10 +02:00
kennytv 6fb153eb9c Remove debug command from help list 2021-08-08 12:54:57 +02:00
kennytv a6e7bfa793 Update workflow and dependencies 2021-08-07 12:37:18 +02:00
kennytv 75656be4f5 Add helpDump to language files 2021-07-23 10:26:44 +02:00
KennyTV f09f95549a Fix Velocity update message, update depend to 3.0.0-SNAPSHOT 2021-05-27 22:25:58 +02:00
KennyTV 78dc87e74a Remove that 2021-05-23 14:23:33 +02:00
KennyTV 3503d02501 Shade mysql connector in Velocity module
Fixes #61
2021-05-22 19:24:38 +02:00
KennyTV f8ea89b0b9 Update ProtocolLib Maven repo 2021-05-10 08:48:02 +02:00
KennyTV d0d672b76b Do offline web lookup in whitelist add on proxies 2021-05-08 09:49:23 +02:00
KennyTV 616d4c7aba Update changelog, update sponge repo url 2021-03-06 18:25:01 +01:00
KennyTV 4415d036a2 Have an extra broadcast key for schedule starts
Closes #58
2021-03-06 16:44:58 +01:00
KennyTV 1f70247c1d Add config options to dispatch commands on maintenance toggle 2021-03-06 16:02:09 +01:00
KennyTV 02ed575e3c Fix inverted if condition 2021-02-18 09:15:33 +01:00
KennyTV 4e005bca17 Add "enable-pingmessages" config option
Closes #57
2021-02-18 09:14:48 +01:00
Aurélien dcf61a4036 Update language-fr.yml (#56) 2021-02-17 10:48:35 +01:00
KennyTV 8e7b80bddf Bump version 3.0.7-SNAPSHOT 2021-02-17 10:47:56 +01:00
KennyTV 16775bda54 Update changelog 2021-02-17 10:30:28 +01:00
Nassim 29d9fa2ec8 3.0.6 Release 2021-02-17 10:25:23 +01:00
KennyTV ef2ce99746 Prepare for 3.0.6 Release 2021-02-17 10:24:56 +01:00
KennyTV aa5437605f Actually fire the MaintenanceReloadedEvent 2021-02-07 11:40:41 +01:00
KennyTV 22e1d53f81 Update copyright header 2021-02-07 11:32:00 +01:00
KennyTV 1359684c72 Add "maintenance schedule" command 2021-02-07 11:30:20 +01:00
KennyTV 22c53bd4ff Add primitive debug mode (only implemented on Bungee) 2020-12-31 12:59:31 +01:00
KennyTV c0e2586684 Hotfix dumps
I will use paste.gg in the future, this is only to make it work at all again
2020-12-31 12:28:24 +01:00
KennyTV 2f095f32ca Also replace online and max variable in the hover message 2020-11-20 22:38:10 +01:00
KennyTV e1e4926f83 Properly register main command with permissions (instead of checking for them in the actual command) 2020-10-26 16:55:37 +01:00
KennyTV 55b5bf2714 Update Velocity API usage 2020-10-26 16:47:07 +01:00
KennyTV 5f8f885530 Update language-es.yml (thanks to Vixo_Ulises) 2020-10-26 16:38:38 +01:00
KennyTV fc40b0230d Rename GH build artifact 2020-10-01 09:40:29 +02:00
Nassim 6fb79d7051 Make artifacts work 😎 2020-08-25 14:55:20 +02:00
KennyTV 7bc522c1d3 Upload artifacts 2020-08-25 14:52:15 +02:00
Nassim 8d0d97c220 Create maven.yml 2020-08-25 14:14:56 +02:00
KennyTV e7c8430909 Fix NPE in null pings 2020-08-22 09:48:21 +02:00
KennyTV 1646d4e417 Update Velocity API usage to 1.1.0-SNAPSHOT 🎉 2020-08-21 20:26:39 +02:00
KennyTV f8384f4f99 Add whitelist add arg to manually add offline uuid+name 2020-08-19 09:44:57 +02:00
KennyTV 4fd6ba33ff Fix linebreaks on Bungee in playercount hovermessage 2020-07-30 12:04:05 +02:00
KennyTV 94c146d0e9 Add MaintenanceReloadedEvent, also fire changed event for unregistered proxy servers 2020-07-29 14:17:49 +02:00
dependabot-preview[bot] c624b18b8e Bump junit-jupiter-engine from 5.6.1 to 5.6.2
Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.6.1 to 5.6.2.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.6.1...r5.6.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-27 18:39:05 +02:00
KennyTV 18a00f9054 Link to dev branch for Travis builds 2020-07-26 12:15:18 +02:00
KennyTV 9778a900a7 Add 'mt' command alias, add some braces 2020-07-26 11:08:25 +02:00
KennyTV 21fa6a3b7f Formatting fix in changelog 2020-07-14 12:10:34 +02:00
KennyTV c7980cbc86 Missing singleserver kick messages should not throw warnings 2020-06-25 11:28:36 +02:00
KennyTV cdb6715744 Implement new methods for dummyprofile 2020-06-25 09:12:24 +02:00
KennyTV d868f069cc Add translators to the individual language files 2020-06-21 09:26:59 +02:00
Aurélien c58b29a78f Fixes for French translation (#42) 2020-06-21 09:19:16 +02:00
KennyTV 5fb4f06f4c Rename method to get server name of player, cleanup config in test 2020-06-18 15:43:39 +02:00
KennyTV 8a3afdd1a8 Version increase to 3.0.6-SNAPSHOT 2020-06-18 15:26:39 +02:00
KennyTV 36e561c413 Sneak a mysql fix in 2020-06-17 14:09:02 +02:00
KennyTV 4739176e9b Update API jar to 3.0.5 2020-06-17 11:26:32 +02:00
Nassim 9546cc7b74 3.0.5 Release 2020-06-17 10:48:13 +02:00
KennyTV 740051dda5 Prepare for 3.0.5 release 2020-06-17 10:47:20 +02:00
KennyTV e53f4f2518 Config test additions 2020-06-17 09:31:49 +02:00
KennyTV 03390d7be9 Config set cleanup 2020-06-16 17:49:45 +02:00
KennyTV 039c5a3d04 Use precondition in api getter util 2020-06-16 16:39:23 +02:00
KennyTV 4360eb03e3 Wrong nullable annotation 2020-06-16 16:20:18 +02:00
KennyTV 89691e8064 Minor code cleanup to version checking 2020-06-16 16:19:20 +02:00
KennyTV 8f4860ad56 Update changelog, bump Guava provided version
Not that it matters, but want to get rid of the security alert
2020-06-16 09:51:25 +02:00
KennyTV b8b231ce78 Remove config updating from 2.x
See https://github.com/KennyTV/Maintenance/wiki/Updates#updating-from-2x on how to do that manually - virtually noone should be using such old versions anymore
2020-06-10 12:51:25 +02:00
KennyTV fd8b47a9f5 Automatically move files to new dir on updating 2020-06-09 19:25:21 +02:00
KennyTV 10c0b5bab3 Update README 2020-06-01 13:21:21 +02:00
KennyTV cece2b5813 Use higher proxy ping listener priority 2020-05-18 22:12:22 +02:00
KennyTV aa9a686b8a Replace newline variable in language file
Note on why this even exists: Yaml will force save all strings containing line breaks in this rather chunky format:
  key: |-
    First line text
     Second line text.
     ...

This also happens to string lists, making those practically unreadable, as well as confusing for most users in general.
Because of this, I replace %NEWLINE% manually, to spare users from these ugly breaks.
2020-05-15 13:38:41 +02:00
KennyTV f29b38989c Add option to set multiple fallback servers 2020-05-12 20:52:47 +02:00
KennyTV ad9c989213 Add secret language option for server specific kick messages
Closes #38
2020-05-12 20:27:59 +02:00
KennyTV f01e96a32a Implement deep get in config 2020-05-12 19:32:42 +02:00
KennyTV e247f4ef10 Remove platform suffix from plugin identifier 2020-04-22 10:59:27 +02:00
KennyTV b8e0f84d54 Don't hide playercount if custom playercount is disabled 2020-04-21 12:00:23 +02:00
KennyTV 424617c602 Respect custom playercount setting in Spigot ping 2020-04-21 08:36:28 +02:00
KennyTV 21ed266d3d Fix use-ssl option inversion 2020-04-13 09:29:22 +02:00
KennyTV a409ec5d66 Update copyright headers 2020-04-10 23:42:06 +02:00
KennyTV 66cba12fd3 Update Russian language file 2020-04-09 08:59:11 +02:00
KennyTV f6d178d8d1 Add placeholder link to readme 2020-04-06 22:34:04 +02:00
KennyTV d04749c835 Add Italian language file 2020-04-03 12:27:00 +02:00
KennyTV eebbc4d532 Fix config loading with multiline strings, add small tests
Fixes #37
2020-03-30 12:48:48 +02:00
KennyTV 335fe303b5 Throw around some nullable annotations 2020-03-30 11:02:35 +02:00
KennyTV 1c4b5e62a4 Add Chinese language file 2020-03-17 15:02:47 +01:00
KennyTV d41fa5ab24 Version increase to 3.0.5-SNAPSHOT 2020-03-17 11:57:12 +01:00
Nassim 7fd486ef40 3.0.4 Release 2020-03-17 11:01:41 +01:00
KennyTV d0b10f2524 Prepare for 3.0.4 release 2020-03-17 11:00:55 +01:00
KennyTV 865df5e20a Rearrange new language entries 2020-03-16 15:49:09 +01:00
KennyTV 469e8eb57b Fix join notifications with waiting servers enabled 2020-03-16 15:48:27 +01:00
KennyTV 368ac37099 Add waiting-server option for global proxy maintenance
Includes some other, minor fixes
Some proxy modules cleanup
2020-03-16 15:17:09 +01:00
KennyTV 0db4d77c10 Update missing pt messages (by JoaoPinto) 2020-03-16 11:16:46 +01:00
Max Kade ca4c711103 Fix single server timer accepting number as seconds and not minutes (#35) 2020-03-11 14:35:56 +01:00
KennyTV f4a5f288ca Fix singleserver timers broadcasting globally 2020-02-14 21:40:08 +01:00
KennyTV 0a37bfdefe Update bStats metrics 2020-02-12 17:20:37 +01:00
KennyTV 3a30dba011 Add option to disable sql ssl 2020-02-09 12:47:28 +01:00
KennyTV 111a229d48 Minor beauty changes 2020-01-29 15:11:01 +01:00
KennyTV 7e948fbe52 Forgot the return 2019-11-21 09:46:51 +01:00
KennyTV 355aa20244 Add Russian language file (thanks to En_0t_S) 2019-11-21 09:44:23 +01:00
KennyTV 6bc54d1812 Don't throw errors when failing the language update check because of custom langs 2019-11-21 09:41:42 +01:00
KennyTV 0042ce3ccd Version increase to 3.0.4-SNAPSHOT 2019-11-21 09:27:32 +01:00
KennyTV beb0e52371 Forgot to update the date in the changelog 2019-09-17 09:05:53 +02:00
Nassim 4774ec2f2a 3.0.3 Release 2019-09-17 09:02:27 +02:00
KennyTV 34115f443e Version increase to 3.0.3 2019-09-17 08:29:23 +02:00
KennyTV c8f0c1699e Update changelog, fix small oversight in the Bungee serverconnect 2019-09-13 10:30:53 +02:00
KennyTV f22be77023 Fix playercountmessage on Paper servers with Via 2019-09-09 08:35:53 +02:00
KennyTV 730a8dbeea Remove some old code 2019-08-24 18:55:30 +02:00
KennyTV 0548e0c447 Replace some streams with loops.. because why not
Not really that much of an improvement, but gotta strike those micro optimizations 🤷
2019-08-18 10:18:58 +02:00
KennyTV da0a757c5e Revert "Fix potential config deserialization error"
This reverts commit ac19bac1
2019-08-13 22:33:31 +02:00
KennyTV ac19bac11c Fix potential config deserialization error 2019-08-13 22:21:30 +02:00
KennyTV 1de926bb28 Minor pom changes 2019-08-13 22:21:11 +02:00
KennyTV 94308cde7c Fix some redundant config comment checks 2019-07-26 13:20:27 +02:00
KennyTV d863c709e1 Update bStats metrics 2019-07-26 12:29:34 +02:00
KennyTV 741914283a Minor config optimizations and cleanup 2019-07-22 09:28:53 +02:00
KennyTV 64902d90ff Language autoupdater, fix updating with broken texts 2019-07-21 15:49:10 +02:00
KennyTV d3b4c7c87b Add warning with PS 2019-07-20 09:58:00 +02:00
KennyTV 390b65a70e Add warning with PS 2019-07-20 09:49:00 +02:00
KennyTV 7cff908aae Switch to ProtocolLib/Spigot ping listener if PS is installed 2019-07-20 09:46:28 +02:00
KennyTV d1f049c3e5 Add help page header to language file 2019-06-28 21:43:27 +02:00
Nassim 8d552dbe33 Remove a space in language-es.yml 2019-06-27 10:34:36 +02:00
KennyTV d3a933d21d Add bypass permission for specific proxied servers 2019-06-27 10:05:57 +02:00
KennyTV a4d87dabf5 Update changelog 2019-06-09 09:53:04 +02:00
KennyTV c3b579e86c Update Spanish language (thanks to Vixo_Ulises) 2019-06-09 09:51:04 +02:00
KennyTV b75d2337df Update French language (thanks to Zendrique) 2019-05-31 21:26:58 +02:00
KennyTV b3e83c5c2e Language changes 2019-05-31 16:26:16 +02:00
KennyTV b6f447aded Update travis.yml 2019-05-31 15:45:35 +02:00
KennyTV 9febdfc140 Update travis.yml 2019-05-31 15:38:06 +02:00
KennyTV 90bc30d701 I'm a dumbo 2019-05-31 15:31:10 +02:00
KennyTV 843ba4ac86 Add help messages to language files 2019-05-31 15:30:03 +02:00
KennyTV 032fd7d582 Fix double messages in some server connections 2019-05-24 09:14:51 +02:00
KennyTV 9a0f680177 Kick connecting players before the connection succeeded, fix double join-notification (Bungee) 2019-05-23 22:18:05 +02:00
KennyTV 415d5f3807 Update config version 2019-05-20 15:28:06 +02:00
KennyTV 33c96de5fb Add option to not kick online players 2019-05-18 17:23:56 +02:00
KennyTV d141b40190 Version increase to 3.0.3-SNAPSHOT 2019-05-18 17:16:37 +02:00
KennyTV 77e1444dba 3.0.2 Release 2019-05-17 09:35:34 +02:00
KennyTV 915b43d897 👀 2019-05-17 09:35:14 +02:00
KennyTV adc06e3486 Update changelog 2019-05-17 09:31:17 +02:00
KennyTV cc7f5c2d11 Version increase to 3.0.2 2019-05-17 09:25:57 +02:00
KennyTV 0bb54ffc5d Finish timerspecific pingmessages 2019-05-17 09:21:35 +02:00
KennyTV 15ee2e6074 Update changelog, resort some config entries 2019-05-14 13:48:28 +02:00
KennyTV 89abab36f8 Timerspecific pingmessages 2019-05-14 09:07:23 +02:00
KennyTV e0bb1336b0 ‍Make setmotd command also set timerspecific messages 2019-05-13 22:53:04 +02:00
KennyTV 888ffd301a 🤦‍ 2019-05-13 15:30:40 +02:00
KennyTV 3a55dd3280 Make motd command display timerspecific ones 2019-05-13 15:30:00 +02:00
KennyTV 61c47ba2fa WIP: Timerspecific pingmessages 2019-05-13 11:02:13 +02:00
KennyTV b97e69a71f Make dumps prettier 2019-05-09 22:30:18 +02:00
KennyTV 75c940d089 Fix Sponge 8.0.0 compatibility 2019-05-09 21:53:30 +02:00
KennyTV 849fa2a720 Update to latest Velocity text api 2019-05-07 09:09:58 +02:00
KennyTV 7e249faa99 Update README.md 2019-04-27 15:34:07 +02:00
KennyTV c8272b39d5 Fix Velocity autoupdater 2019-04-17 15:38:51 +02:00
KennyTV b3c561ae26 Version increase to 3.0.2-SNAPSHOT 2019-04-17 15:38:33 +02:00
KennyTV af24c5a331 Update api, changelog and readme for latest release 2019-04-17 15:24:51 +02:00
KennyTV 4cc162f00d Merge pull request #29 from KennyTV/dev
3.0.1 Release
2019-04-17 14:38:55 +02:00
KennyTV 02610fd904 Version increase to 3.0.1 2019-04-17 14:36:56 +02:00
KennyTV bccd1bb936 Remove interface check 2019-04-17 14:36:47 +02:00
KennyTV c08dd5d430 Set group id to eu.kennytv.maintenance 2019-04-15 10:54:16 +02:00
KennyTV 1104a50882 Fix another potential error on startup 2019-04-14 13:07:01 +02:00
KennyTV 56898d7b40 Database sync fixes, adjustments to endtimer saving 2019-04-05 14:05:01 +02:00
KennyTV 4be31a6dd4 Update README 2019-04-05 14:04:45 +02:00
KennyTV 190a063d49 Add config updater + endtimer saving after restart 2019-04-03 14:22:06 +02:00
KennyTV 6e4591d45b Fix error printing in some cases, close hikari source on disable(/reload) 2019-04-03 11:15:30 +02:00
KennyTV 86c556e841 Hackily fix slf4j relocation and shorten jar sizes 2019-03-19 22:35:13 +01:00
KennyTV 404e14ee94 Revert "Only compile SnakeYaml in universal and Velocity file"
This reverts commit b8c0e3a7
2019-03-19 18:07:18 +01:00
KennyTV b8c0e3a799 Only compile SnakeYaml in universal and Velocity file 2019-03-19 18:04:05 +01:00
KennyTV 10d798acd4 Make ServerInfoPacketListener extend PacketAdapter instead of creating anonymous class 2019-03-19 17:04:08 +01:00
KennyTV be057f4b3b Don't register listener twice 2019-03-13 17:17:31 +01:00
KennyTV eea7a595c9 Add Ore url to plugin info 2019-03-13 10:21:29 +01:00
KennyTV bf4bf79b23 Readd update checking on Sponge, still disallow execution of update 2019-03-13 10:04:16 +01:00
KennyTV 686535228e Typo 👀 2019-03-11 13:24:33 +01:00
KennyTV 8b645b6f79 Fix Paper pinglistener and remove old code 2019-03-11 13:22:15 +01:00
KennyTV 4d97293a8c Rename dump variable 2019-03-11 13:00:43 +01:00
KennyTV c746a83f5f Use PaperServerListPingEvent if applicable 2019-03-11 12:48:10 +01:00
KennyTV eb7e6e3f0b Fix exception on ping that does not come from status packet 2019-03-10 19:08:08 +01:00
KennyTV f5ce41853f nooooo 2019-03-08 21:29:28 +01:00
KennyTV e67cde591c Try to please the beautiful people over at Ore (Sponge), attempt no 2 2019-03-08 21:28:35 +01:00
KennyTV 39682635c6 Try to please the beautiful people over at Ore (Sponge) 2019-03-08 21:18:21 +01:00
KennyTV efee532742 Make endtimer display format adjustable 2019-03-05 16:55:56 +01:00
KennyTV 0aee3a8fd6 Remove bStats from Sponge module
(Their beautiful repo is down and I don't really need it on Sponge anyways 🤔)
2019-02-21 17:22:29 +01:00
KennyTV f79b6caccb Minor maintenance event changes 2019-02-21 16:43:13 +01:00
KennyTV 73fd80b456 Some language changes 2019-02-21 15:35:52 +01:00
KennyTV ad1a7eb420 Make createFile method public 2019-02-19 17:30:58 +01:00
KennyTV bfa9b52497 Add api method to get a list of maintenance servers 2019-02-19 13:25:13 +01:00
KennyTV ff4b5b0d2e Custom maintenance events 2019-02-19 13:08:38 +01:00
KennyTV b8e73062fa Some language changes 2019-02-19 11:28:24 +01:00
KennyTV 863a9b3beb Version increase to 3.0.1-SNAPSHOT 2019-02-19 00:16:24 +01:00
KennyTV fe64936ddf Sneak Spanish language in 👀 2019-02-17 10:16:36 +01:00
202 changed files with 8253 additions and 4858 deletions

No files matched your search

+127
View File
@@ -1,6 +1,133 @@
# 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.
---
## 4.0.1 - April 17th 2022
### Fixed
* Fixed the config header sometimes breaking the config on upgrading/saving
---
## 4.0.0 - March 17th 2022
### Changed
* Added support for hex colors in messages and replaced the component parsing with adventure-minimessage
* This means that section symbols (`§`) are no longer the intended/supported format
* You can use the following page to edit and preview formatted text: https://webui.adventure.kyori.net/
* You can find full documentation on the format (including normal colors and formatting, rgb, click/hover events, and more) here: https://docs.adventure.kyori.net/minimessage/format
* Your config and language file will be updated to the new format automatically, you won't have to change anything manually!
* Note that the player count and player count hover messages do not support rgb colors
* Updated Sponge module to SpongeAPI v8 (Minecraft 1.15+)
* Changed `%NEWLINE%` replacement to `<br>`
* Changed `enable-timerspecific-messages` to default to `true` in newly generated config files
* Added `prefix` entry in language file to use the placeholder `<prefix>` instead of copy-pasting the actual prefix every time
* Added `singleServerMaintenanceListEntry` language string
* Added Polish translations (thanks to Slasherss1)
* Updated French translations (thanks to Aurelien30000)
* Updated Spanish translations (thanks to Jaximo)
* If you were using the MaintenanceAddon, you need to update it to [version 1.2.0](https://github.com/kennytv/MaintenanceAddon/releases/tag/1.2.0)
### Fixed
* Fixed missing language key warning for the scheduletimer command
* Fixed typo in `singleServerMaintenanceListEmpty` default language string
* Fixed typo in language key `whitelistEmpty` in the German language file (by Ceddix)
---
## 3.0.7 - August 17th 2021
### Changed
* Bungee/Velocity: `/maintenance add <name>` now works for offline players as well
* Added config options `commands-on-maintenance-enable` and `commands-on-maintenance-disable` to define commands to be executed after maintenance has been toggled
* Added config option `enable-pingmessages` to can change whether a custom maintenance motd should be displayed during maintenance
* Added language fields `scheduletimerBroadcast` and `singleScheduletimerBroadcast` with the variables `%SERVER%`, `%TIME%`, and `%DURATION%` instead of using the normal starttimer broadcasts
### Fixed
* Fixed SQL loading issues on some platforms
* Fixed missing language key warning for the debug command
* Velocity: Fixed the update message
---
## 3.0.6 - February 17th 2021
### Changed
* Updated the Velocity version to be compatible with Velocity 1.1.0 (use Maintenance 3.0.5 if you use an older version of Velocity)
* Added `maintenance schedule <minutes> <duration> command`
* This starts a timer for maintenance to be enabled, after which another timer will be started to disable it again (in contrast to `starttimer` and `endtimer`, which each only do one of)
* On proxies, you can use `maintenance schedule [server] <minutes> <duration> command` to schedule maintenance on a proxied server
* Added command alias `mt` for the Maintenance command
* Added secret argument to the whitelist add command: You can use `maintenance add <uuid> <name>` to add offline entries per command
* The maintenance's base command is now properly registered with a permission on each platform, so that it is excluded from tabcomplection to unauthorized players
* Some improvements to the French language file (thanks to @Aurelien30000)
* API addition: Added MaintenanceReloadedEvent
* If you are using the MaintenancePlaceholderAddon, you need to [update it to 1.1.0](https://github.com/KennyTV/MaintenanceAddon/releases)
### Fixed
* Fixed not setting custom singleserver kickmessages throwing warnings
* Bungee: Fixed linebreaks in the playercount hovermessage for 1.16+ clients
---
## 3.0.5 - June 17th 2020
### Changed
* The plugin identifiers are now `Maintenance` instead of the previous `MaintenanceSpigot` and `MaintenanceBungee`,
and `maintenance` instead of `maintenancesponge` and `maintenancevelocity`
* The plugin directory will automatically be renamed accordingly when starting the server
* If you are using the MaintenancePlaceholderAddon, you need to [update it to 1.0.3](https://github.com/KennyTV/MaintenanceAddon/releases)
* Bungee/Velocity: The `fallback` field can now also be set as a list to define multiple fallback servers
* Bungee/Velocity: Added language fields to choose custom kickmessages for individual proxied servers
* See [**HERE**](https://github.com/KennyTV/Maintenance/wiki/Configuration#language-file) for an example setting
* Added Chinese language file (thanks to Spigot user yeban)
* Added Italian language file (thanks to @TheViperShow)
* Updated Russian language file (thanks to Spigot user En_0t_S)
* Removed automated config migration from 2.x->3.0
* See [**HERE**](https://github.com/KennyTV/Maintenance/wiki/Updates#updating-from-2x) on how to do that manually - virtually noone should be using such old versions anymore
### Fixed
* Fixed the `use-ssl` option being inverted
* Fixed disabling the playercount-message still hiding online/max players
* Fixed config parsing with multi line strings
* Bungee: Fixed compatibility with other motd changing plugins using the 'HIGHEST' ping listener priority
---
## 3.0.4 - March 17th 2020
### Changed
* Bungee/Velocity: Added config option `waiting-server` to send players to a waiting server when global maintenance is enabled (instead of kicking them)
* Bungee/Velocity: Added config option `use-ssl` in the `mysql` section to disable SSL connections
* Added Russian language file (thanks to Spigot user En_0t_S)
* Updated missing translations in Portuguese language file (thanks to Spigot user JoaoPinto)
* Updated bStats metrics
### Fixed
* Fixed singleserver timers using input as seconds instead of minutes (by mxs42)
* Fixed singleserver timers broadcasting globally
* Fixed language updating with an unknown/self-translated language file
* Fixed Velocity server autocompletion in the maintenance command
---
## 3.0.3 - September 17th 2019
### Changed
* Bungee/Velocity: Added `maintenance.singleserver.bypass.<server>` permission to give individual bypasses for proxied servers (`maintenance.bypass` will still bypass everything as the super-perm)
* Added the messages of the help command into the language files
* Added config option `kick-online-players` to disable the kicks when maintenance is enabled (new connections will still be blocked)... not sure why you'd want that, but you can :p
* The language file will now be automatically updated as well, so no need to delete and recreate it anymore, yay!
* Updated missing and new translations in French language file (thanks to Spigot user Zendrique)
* Updated missing and new translations in Spanish language file (thanks to Spigot user Vixo_Ulises)
### Fixed
* Bungee/Velocity: Fixed the join-notifications being sent twice if both global and server maintenance are enabled, as well as when just a server has maintenance in some cases
* Bungee: Fixed players being kicked *after* the initial connection and thus triggering a join and leave message before being kicked
* Bungee: Fixed the kickmessage not being displayed in some cases
* Paper: Fixed the playercount message not being displayed on Paper servers with ViaVersion
* Paper: Fixed the motd not being changed at all on Paper servers with ProtocolSupport (-> ProtocolLib listener used, since ProtocolSupport does not fire Paper's ping event)
* Fixed the config autoupdater when the config contained strings broken over multiple lines
---
## 3.0.2 - May 17th 2019
### Changed
* Added config option `timerspecific-pingmessages` to have specific pingmessages shown when endtimers are run
* You can also set them ingame by using `/maintenance setmotd timer <index> ...` instead of `/maintenance setmotd <index> ...`, along with `/maintenance removemotd timer <index>` and `/maintenance motd timer`
* Made dumps a little prettier
* Support Sponge 8.0.0-SNAPSHOT
* Support latest text/Velocity (now only supports Velocity builds from May 7th upwards)
---
## 3.0.1 - April 17th 2019
### Changed
* Created an addon to have PlaceholderAPI placeholders on Spigot when running the Maintenance plugin on Bungee (see [**here**](https://github.com/KennyTV/Maintenance/wiki/MaintenanceAddon))
* Spigot version: If running on Paper 1.12.2 or higher, ProtocolLib will not be needed anymore
* The universal jar now only includes Bungee and Spigot (whereas before Sponge and Velocity as well) and has been further minimized in size
* To use the plugin on the other platforms, use the `MaintenanceSponge.jar` or `MaintenanceVelocity.jar` respectively
* Added config option `continue-endtimer-after-restart` to have endtimers continued, even if the server restarts during its runtime
* Added custom eventsystem to the API
* Removed bStats metrics from Sponge module
### Fixed
* Actually fixed compatibility to other plugins using the same MySQL library (such as LuckPerms) in the Bungee version
* Fixed an issue with executing the maintenance change with MySQL enabled on connected proxies
* Fixed an occasional error on pings of non clients in the Spigot version
* Fixed 1.13 clients on sub 1.13 servers not showing the playercountmessage in the Spigot version
* Minor fixes/changes to Spanish and Portuguese language files
---
## 3.0 - February 17th 2019
### Changed
* This plugin now also supports the platforms Sponge and Velocity!
+25
View File
@@ -0,0 +1,25 @@
name: Build
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.0.0
- name: Set up JDK 11
uses: actions/setup-java@v3.0.0
with:
java-version: 11
distribution: 'temurin'
- name: Build with Gradle
run: ./gradlew build
- name: Upload a Build Artifact
uses: actions/upload-artifact@v3.0.0
with:
name: Maintenance Files
path: build/libs
+5 -3
View File
@@ -1,5 +1,6 @@
.metadata
dependencies/
build/
.gradle
bin/
tmp/
*.tmp
@@ -14,7 +15,6 @@ local.properties
.externalToolBuilders/
*.launch
*.pydevproject
*.jar
.cproject
.classpath
.factorypath
@@ -92,4 +92,6 @@ $RECYCLE.BIN/
*.msm
*.msp
*.lnk
!MaintenanceAPI.jar
!MaintenanceAPI.jar
**/src/test/resources/
!core/src/test/resources/dirty-config.yml
-7
View File
@@ -1,7 +0,0 @@
language: java
jdk:
- oraclejdk8
cache:
directories:
- '$HOME/.m2'
+5 -5
View File
@@ -1,7 +1,7 @@
GNU GENERAL PUBLIC LICENSE
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
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/>.
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
@@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
<https://www.gnu.org/licenses/why-not-lgpl.html>.
Binary file not shown.
+17 -15
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)
[![Version](https://img.shields.io/github/release/kennytv/Maintenance.svg)](https://github.com/kennytv/Maintenance/releases)
![Build Status](https://github.com/kennytv/Maintenance/workflows/Build/badge.svg)
[![GH Downloads](https://img.shields.io/github/downloads/kennytv/Maintenance/total)](https://github.com/kennytv/Maintenance/releases)
[![Discord](https://img.shields.io/discord/489135856284729384.svg?label=Discord&logo=discord&logoColor=fff)](https://discord.gg/vGCUzHq)
[![Twitter](https://img.shields.io/twitter/follow/kennytvn.svg?label=Twitter)](https://twitter.com/kennytvn)
Maintenance is probably the most customizable free maintenance plugin for your Minecraft server you can find. It runs on Bukkit/Spigot, BungeeCord, Sponge as well as Velocity.
Maintenance is 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,22 @@ 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)
* [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)
* [Wiki](https://github.com/kennytv/Maintenance/wiki) (configuration, permissions, API usage)
* [Downloads](https://github.com/kennytv/Maintenance/releases) (GitHub)
* [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)
* [Velocity forums](https://forums.velocitypowered.com/t/maintenance/129)
* [Ore/Sponge Forums](https://ore.spongepowered.org/KennyTV/Maintenance)
## 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).
To create a working jar yourself, simply clone the project and compile it with Gradle (`gradlew build`).
## 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)).
## License
This project is licensed under the [GNU General Public License v3](LICENSE.txt).
+24
View File
@@ -0,0 +1,24 @@
plugins {
id("com.github.johnrengelman.shadow")
}
// Shade and relocate adventure in an extra module, so that common/the rest can directly depend on a
// relocated adventure without breaking native platform's adventure usage with project wide relocation
tasks {
shadowJar {
relocate("net.kyori", "eu.kennytv.maintenance.lib.kyori")
}
build {
dependsOn(shadowJar)
}
}
dependencies {
api(libs.bundles.adventure) {
exclude("net.kyori", "adventure-api")
exclude("net.kyori", "adventure-bom")
exclude("com.google.code.gson", "gson")
}
}
publishShadowJar()
@@ -0,0 +1,20 @@
plugins {
id("com.github.johnrengelman.shadow")
}
tasks {
shadowJar {
relocate("net.kyori", "eu.kennytv.maintenance.lib.kyori")
}
build {
dependsOn(shadowJar)
}
}
dependencies {
api(libs.adventurePlatformBukkit) {
exclude("net.kyori", "adventure-api")
}
}
publishShadowJar()
@@ -0,0 +1,20 @@
plugins {
id("com.github.johnrengelman.shadow")
}
tasks {
shadowJar {
relocate("net.kyori", "eu.kennytv.maintenance.lib.kyori")
}
build {
dependsOn(shadowJar)
}
}
dependencies {
api(libs.adventurePlatformBungee) {
exclude("net.kyori", "adventure-api")
}
}
publishShadowJar()
View File
Whitespace-only changes.
+14
View File
@@ -0,0 +1,14 @@
plugins {
id("maintenance.shadow-conventions")
}
dependencies {
api(projects.maintenanceApi)
compileOnly(projects.adventure.adventureApi) {
targetConfiguration = "shadow"
}
}
java {
withJavadocJar()
}
@@ -0,0 +1,53 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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.
*/
public final class ServerMaintenanceChangedEvent implements MaintenanceEvent {
private final Server server;
private final boolean maintenance;
public ServerMaintenanceChangedEvent(final Server server, final boolean maintenance) {
this.server = server;
this.maintenance = maintenance;
}
/**
* Returns wrapped server object for the server.
* <br>
* This does not necessarily have to be an existing server:
* If maintenance is disabled on a *previously* registered server, see {@link Server#isRegisteredServer()}.
*
* @return wrapped server object for the server
*/
public Server getServer() {
return server;
}
/**
* @return true if maintenance has been enabled on the server, false otherwise
*/
public boolean isMaintenance() {
return maintenance;
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,16 +15,14 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.api.proxy;
import eu.kennytv.maintenance.api.IMaintenance;
import eu.kennytv.maintenance.api.Maintenance;
import org.jetbrains.annotations.Nullable;
/**
* @author KennyTV
* @since 3.0
*/
public interface IMaintenanceProxy extends IMaintenance {
import java.util.Set;
public interface MaintenanceProxy extends Maintenance {
/**
* Enables/disables maintenance mode on a proxied server.
@@ -58,5 +56,18 @@ 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);
/**
* Returns the currently registered proxied servers.
*
* @return set of proxied servers
*/
Set<String> getServers();
/**
* @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)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,15 +15,13 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.api.proxy;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
/**
* Wrapper for a proxied server.
* Use {@link IMaintenanceProxy#getServer(String)} to get a server instance.
*
* @author KennyTV
* @since 3.0
* Use {@link MaintenanceProxy#getServer(String)} to get a server instance.
*/
public interface Server {
@@ -40,7 +38,15 @@ public interface Server {
/**
* Sends a message to all players on the server.
*
* @param message message to be broadcasted
* @param component message to be broadcasted
*/
void broadcast(String message);
void broadcast(Component component);
/**
* Returns whether the server is registered under the proxy.
* This will only ever be false if maintenance is disabled on a *previously* registered server.
*
* @return whether the server is registered under the proxy
*/
boolean isRegisteredServer();
}
+11
View File
@@ -0,0 +1,11 @@
plugins {
id("maintenance.shadow-conventions")
}
dependencies {
compileOnlyApi(libs.jetbrainsAnnotations)
}
java {
withJavadocJar()
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,14 +15,11 @@
* 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;
/**
* @author KennyTV
* @since 2.1
*/
public interface IMaintenance {
import eu.kennytv.maintenance.api.event.manager.EventManager;
public interface Maintenance {
/**
* Enables/disables maintenance mode.
@@ -52,9 +49,28 @@ public interface IMaintenance {
String getVersion();
/**
* Returns the {@link ISettings} instance, which gives further insight into settings set in the config files.
* Returns the {@link Settings} instance, which gives further insight into settings set in the config files.
*
* @return {@link ISettings} instance
* @return {@link Settings} instance
*/
ISettings getSettings();
Settings getSettings();
/**
* Returns the {@link EventManager} instance to register listeners to maintenance events.
*
* @return {@link EventManager} instance
*/
EventManager getEventManager();
/**
* @return true if debug mode is enabled, currently only implemented on Bungee
*/
boolean isDebug();
/**
* Sets the debug mode.
*
* @param debug debug state
*/
void setDebug(boolean debug);
}
@@ -0,0 +1,49 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
/**
* Provider to get the maintenance api instance.
*/
public final class MaintenanceProvider {
private static Maintenance maintenance;
private MaintenanceProvider() {
throw new IllegalArgumentException();
}
@ApiStatus.Internal
public static void setMaintenance(final Maintenance maintenance) {
if (MaintenanceProvider.maintenance != null) {
throw new IllegalArgumentException("MaintenanceProvider is already set!");
}
MaintenanceProvider.maintenance = maintenance;
}
/**
* Returns the maintenance api instance, or null if not loaded yet.
*
* @return maintenance api instance
*/
public static @Nullable Maintenance get() {
return maintenance;
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,17 +15,12 @@
* 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;
import java.util.Map;
import java.util.UUID;
/**
* @author KennyTV
* @since 2.1
*/
public interface ISettings {
public interface Settings {
/**
* Note that the value might need a few seconds to update, if you're on BungeeCord with MySQL enabled
@@ -34,6 +29,11 @@ public interface ISettings {
*/
boolean isMaintenance();
/**
* @return true if custom ping messages during maintenance should be used
*/
boolean isEnablePingMessages();
/**
* @return value of the 'send-join-notification' config field
*/
@@ -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.
*
@@ -76,7 +84,7 @@ public interface ISettings {
*
* @param uuid uuid of the player to add
* @param name of the player to add
* @return true if adding the player was successful
* @return true if adding the player was successful, false if already on the whitelist
*/
boolean addWhitelistedPlayer(UUID uuid, String name);
@@ -0,0 +1,38 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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.
*/
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,31 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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.Maintenance;
import eu.kennytv.maintenance.api.event.manager.MaintenanceEvent;
/**
* Notification event fired when Maintenance configuration is reloaded.
*
* @author kennytv
* @see Maintenance#isMaintenance() for the new maintenance status
* //@see MaintenanceProxy#getMaintenanceServers() for the new list of servers under maintenance
*/
public final class MaintenanceReloadedEvent implements MaintenanceEvent {
}
@@ -0,0 +1,33 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
*/
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,36 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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;
public interface EventManager {
/**
* Registers an eventlistener for the given maintenance event.
*
* @param listener listener to register
* @param eventClass class of the event that should be registered
*/
void registerListener(EventListener listener, Class<? extends MaintenanceEvent> eventClass);
/**
* Fires a maintenance event.
*
* @param event event to fire
*/
void callEvent(MaintenanceEvent event);
}
@@ -0,0 +1,24 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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.
*/
public interface MaintenanceEvent {
}
+12
View File
@@ -0,0 +1,12 @@
plugins {
`kotlin-dsl`
}
repositories {
gradlePluginPortal()
}
dependencies {
// version must be manually kept in sync with the one in root project settings.gradle.kts
implementation("gradle.plugin.com.github.johnrengelman", "shadow", "7.1.1")
}
+43
View File
@@ -0,0 +1,43 @@
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.named
import java.io.ByteArrayOutputStream
fun Project.publishShadowJar() {
configurePublication {
artifact(tasks["shadowJar"])
artifact(tasks["sourcesJar"])
}
}
fun Project.publishJavaComponents() {
configurePublication {
from(components["java"])
}
}
private fun Project.configurePublication(configurer: MavenPublication.() -> Unit) {
extensions.configure<PublishingExtension> {
publications.named<MavenPublication>("mavenJava") {
apply(configurer)
}
}
}
fun Project.latestCommitHash(): String {
val byteOut = ByteArrayOutputStream()
exec {
commandLine = listOf("git", "rev-parse", "--short", "HEAD")
standardOutput = byteOut
}
return byteOut.toString(Charsets.UTF_8.name()).trim()
}
fun JavaPluginExtension.javaTarget(version: Int) {
toolchain.languageVersion.set(JavaLanguageVersion.of(version))
}
@@ -0,0 +1,37 @@
plugins {
`java-library`
`maven-publish`
}
tasks {
// Variable replacements
processResources {
filesMatching(listOf("plugin.yml", "bungee.yml", "META-INF/sponge_plugins.json")) {
expand("version" to project.version, "description" to project.description)
}
}
javadoc {
options.encoding = Charsets.UTF_8.name()
(options as StandardJavadocDocletOptions).addStringOption("Xdoclint:none", "-quiet")
}
compileJava {
options.encoding = Charsets.UTF_8.name()
options.compilerArgs.addAll(listOf("-nowarn", "-Xlint:-unchecked", "-Xlint:-deprecation"))
}
test {
useJUnitPlatform()
}
}
java {
javaTarget(8)
withSourcesJar()
}
publishing {
publications.create<MavenPublication>("mavenJava") {
groupId = rootProject.group as String
artifactId = project.name
version = rootProject.version as String
}
}
Whitespace-only changes.
@@ -0,0 +1,10 @@
plugins {
id("maintenance.shadow-conventions")
}
tasks {
shadowJar {
archiveFileName.set("Maintenance-${project.name.substringAfter("maintenance-").capitalize()}-${project.version}.jar")
destinationDirectory.set(rootProject.layout.buildDirectory.dir("libs"))
}
}
@@ -0,0 +1,28 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.jvm.tasks.Jar
import org.gradle.kotlin.dsl.named
plugins {
id("maintenance.base-conventions")
id("com.github.johnrengelman.shadow")
}
tasks {
named<Jar>("jar") {
archiveClassifier.set("unshaded")
from(project.rootProject.file("LICENSE.txt"))
}
val shadowJar = named<ShadowJar>("shadowJar") {
archiveClassifier.set("")
configureRelocations()
}
named("build") {
dependsOn(shadowJar)
}
}
publishShadowJar()
fun ShadowJar.configureRelocations() {
relocate("com.zaxxer.hikari", "eu.kennytv.maintenance.lib.hikari")
}
@@ -0,0 +1,5 @@
plugins {
id("maintenance.base-conventions")
}
publishJavaComponents()
+42
View File
@@ -0,0 +1,42 @@
import org.gradle.api.plugins.JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME
plugins {
base
id("maintenance.build-logic")
}
allprojects {
group = "eu.kennytv.maintenance"
version = property("projectVersion") as String // from gradle.properties
description = "Enable maintenance mode with a custom maintenance motd and icon."
}
val platforms = setOf(
projects.maintenanceSpigot,
projects.maintenanceBungee,
projects.maintenanceSponge,
projects.maintenanceVelocity
).map { it.dependencyProject }
val special = setOf(
projects.maintenance,
projects.maintenanceApi,
projects.maintenanceApiProxy,
projects.adventure,
projects.adventure.adventureApi,
projects.adventure.adventurePlatformBukkit,
projects.adventure.adventurePlatformBungee,
).map { it.dependencyProject }
subprojects {
when (this) {
in platforms -> plugins.apply("maintenance.platform-conventions")
in special -> plugins.apply("maintenance.base-conventions")
else -> plugins.apply("maintenance.standard-conventions")
}
dependencies {
TEST_IMPLEMENTATION_CONFIGURATION_NAME(rootProject.libs.bundles.junit)
TEST_IMPLEMENTATION_CONFIGURATION_NAME(rootProject.libs.snakeyaml)
}
}
+7
View File
@@ -0,0 +1,7 @@
dependencies {
implementation(projects.maintenanceCoreProxy)
implementation(projects.adventure.adventurePlatformBungee) {
targetConfiguration = "shadow"
}
compileOnly(libs.bungee)
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,17 +15,16 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.bungee;
import eu.kennytv.maintenance.api.IMaintenance;
import eu.kennytv.maintenance.api.IMaintenanceBase;
import eu.kennytv.maintenance.api.Maintenance;
import eu.kennytv.maintenance.core.MaintenanceBase;
import net.md_5.bungee.api.plugin.Plugin;
import java.io.File;
public final class MaintenanceBungeeBase extends Plugin implements IMaintenanceBase {
private IMaintenance maintenance;
public final class MaintenanceBungeeBase extends Plugin implements MaintenanceBase {
private MaintenanceBungeePlugin maintenance;
@Override
public void onEnable() {
@@ -33,7 +32,12 @@ public final class MaintenanceBungeeBase extends Plugin implements IMaintenanceB
}
@Override
public IMaintenance getApi() {
public void onDisable() {
maintenance.disable();
}
@Override
public Maintenance getApi() {
return maintenance;
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,28 +15,30 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.bungee;
import eu.kennytv.maintenance.api.bungee.MaintenanceBungeeAPI;
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;
import eu.kennytv.maintenance.bungee.util.BungeeSenderInfo;
import eu.kennytv.maintenance.bungee.util.BungeeServer;
import eu.kennytv.maintenance.bungee.util.BungeeTask;
import eu.kennytv.maintenance.bungee.util.ComponentUtil;
import eu.kennytv.maintenance.core.dump.PluginDump;
import eu.kennytv.maintenance.core.hook.ServerListPlusHook;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.core.proxy.SettingsProxy;
import eu.kennytv.maintenance.core.proxy.hook.LuckPermsProxyHook;
import eu.kennytv.maintenance.core.proxy.util.ProfileLookup;
import eu.kennytv.maintenance.core.proxy.util.ProxyOfflineSenderInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.core.util.ServerType;
import eu.kennytv.maintenance.core.util.Task;
import eu.kennytv.maintenance.lib.kyori.adventure.platform.bungeecord.BungeeAudiences;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.Favicon;
import net.md_5.bungee.api.ProxyServer;
@@ -44,10 +46,12 @@ import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.hover.content.Text;
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;
@@ -55,22 +59,22 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* @author KennyTV
* @since 1.0
*/
public final class MaintenanceBungeePlugin extends MaintenanceProxyPlugin {
private final MaintenanceBungeeBase plugin;
private final BungeeAudiences audiences;
private Favicon favicon;
MaintenanceBungeePlugin(final MaintenanceBungeeBase plugin) {
super(plugin.getDescription().getVersion(), ServerType.BUNGEE);
this.plugin = plugin;
this.audiences = BungeeAudiences.create(plugin);
settingsProxy = new SettingsProxy(this);
settings = settingsProxy;
@@ -78,26 +82,30 @@ 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
final Plugin serverListPlus = pm.getPlugin("ServerListPlus");
if (serverListPlus != null) {
serverListPlusHook = new ServerListPlusHook(serverListPlus);
serverListPlusHook.setEnabled(!settingsProxy.isMaintenance());
if (settings.isEnablePingMessages()) {
serverListPlusHook.setEnabled(!settingsProxy.isMaintenance());
}
plugin.getLogger().info("Enabled ServerListPlus integration!");
}
}
@Deprecated
public static IMaintenanceProxy getAPI() {
return MaintenanceBungeeAPI.getAPI();
if (false && pm.getPlugin("LuckPerms") != null) {
LuckPermsProxyHook.<ProxiedPlayer>register(this, player -> {
final net.md_5.bungee.api.connection.Server server = player.getServer();
return server != null ? server.getInfo().getName() : null;
});
getLogger().info("Registered LuckPerms context");
}
}
@Override
@@ -106,66 +114,110 @@ public final class MaintenanceBungeePlugin extends MaintenanceProxyPlugin {
final TextComponent tc2 = new TextComponent(TextComponent.fromLegacyText("§cDownload it at: §6https://www.spigotmc.org/resources/maintenance.40699/"));
final TextComponent click = new TextComponent(TextComponent.fromLegacyText(" §7§l§o(CLICK ME)"));
click.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://www.spigotmc.org/resources/maintenance.40699/"));
click.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("§aDownload the latest version").create()));
click.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(new ComponentBuilder("§aDownload the latest version").create())));
tc1.addExtra(tc2);
tc1.addExtra(click);
((BungeeSenderInfo) sender).sendMessage(tc1);
}
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 player : getProxy().getPlayers()) {
if (!hasPermission(player, "bypass") && !settingsProxy.isWhitelisted(player.getUniqueId())) {
player.disconnect(ComponentUtil.toBadComponents(settingsProxy.getKickMessage()));
}
}
}
@Override
protected void kickPlayers(final Server server, final Server fallback) {
// Kick players from a proxied server
final ServerInfo fallbackServer = fallback != null ? ((BungeeServer) fallback).getServer() : null;
((BungeeServer) server).getServer().getPlayers().forEach(p -> {
if (!hasPermission(p, "bypass") && !settingsProxy.getWhitelistedPlayers().containsKey(p.getUniqueId())) {
if (fallbackServer != null && fallbackServer.canAccess(p) && !isMaintenance(fallback)) {
p.sendMessage(settingsProxy.getMessage("singleMaintenanceActivated").replace("%SERVER%", server.getName()));
p.connect(fallbackServer);
} else
p.disconnect(settingsProxy.getMessage("singleMaintenanceKickComplete").replace("%NEWLINE%", "\n").replace("%SERVER%", server.getName()));
final boolean checkForFallback = fallbackServer != null && !isMaintenance(fallback);
for (final ProxiedPlayer player : ((BungeeServer) server).getServer().getPlayers()) {
if (!hasPermission(player, "bypass") && !settingsProxy.isWhitelisted(player.getUniqueId())) {
if (checkForFallback && fallbackServer.canAccess(player)) {
audiences.player(player).sendMessage(settingsProxy.getMessage("singleMaintenanceActivated", "%SERVER%", server.getName()));
player.connect(fallbackServer);
} else {
player.disconnect(ComponentUtil.toBadComponents(settingsProxy.getFullServerKickMessage(server.getName())));
}
} else {
p.sendMessage(settingsProxy.getMessage("singleMaintenanceActivated").replace("%SERVER%", server.getName()));
audiences.player(player).sendMessage(settingsProxy.getMessage("singleMaintenanceActivated", "%SERVER%", server.getName()));
}
}
}
@Override
protected void kickPlayersTo(final Server server) {
// Kick all players to a single waiting server
final ServerInfo serverInfo = ((BungeeServer) server).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)) {
audiences.player(player).sendMessage(settingsProxy.getMessage("sentToWaitingServer", "%SERVER%", server.getName()));
player.connect(serverInfo);
} else {
player.disconnect(ComponentUtil.toBadComponents(settingsProxy.getKickMessage()));
}
}
}
@Override
public Task startMaintenanceRunnable(final Runnable runnable) {
return new BungeeTask(getProxy().getScheduler().schedule(plugin, runnable, 0, 1, TimeUnit.SECONDS).getId());
}
@Override
public void getOfflinePlayer(final String name, final Consumer<@Nullable SenderInfo> consumer) {
final ProxiedPlayer player = getProxy().getPlayer(name);
if (player != null) {
consumer.accept(new BungeeSenderInfo(player));
return;
}
getProxy().getScheduler().runAsync(plugin, () -> {
try {
final ProfileLookup profile = doUUIDLookup(name);
consumer.accept(new ProxyOfflineSenderInfo(profile.getUuid(), profile.getName()));
} catch (final IOException e) {
e.printStackTrace();
consumer.accept(null);
}
});
}
@Override
protected Task startMaintenanceRunnable(final Runnable runnable) {
return new BungeeTask(getProxy().getScheduler().schedule(plugin, runnable, 0, 1, TimeUnit.SECONDS).getId());
public void getOfflinePlayer(final UUID uuid, final Consumer<@Nullable SenderInfo> consumer) {
final ProxiedPlayer player = getProxy().getPlayer(uuid);
consumer.accept(player != null ? new BungeeSenderInfo(player) : null);
}
@Override
@Nullable
public Server getServer(final String server) {
final ServerInfo serverInfo = getProxy().getServerInfo(server);
return serverInfo != null ? new BungeeServer(serverInfo) : null;
}
@Override
public SenderInfo getOfflinePlayer(final String name) {
final ProxiedPlayer player = getProxy().getPlayer(name);
return player != null ? new BungeeSenderInfo(player) : null;
public Set<String> getServers() {
return getProxy().getServers().keySet();
}
@Override
public SenderInfo getOfflinePlayer(final UUID uuid) {
final ProxiedPlayer player = getProxy().getPlayer(uuid);
return player != null ? new BungeeSenderInfo(player) : null;
}
@Override
public String getServer(final SenderInfo sender) {
@Nullable
public String getServerNameOf(final SenderInfo sender) {
final ProxiedPlayer player = getProxy().getPlayer(sender.getUuid());
return player != null ? player.getServer().getInfo().getName() : "";
if (player == null || player.getServer() == null) return null;
return player.getServer().getInfo().getName();
}
@Override
@@ -174,8 +226,13 @@ public final class MaintenanceBungeePlugin extends MaintenanceProxyPlugin {
}
@Override
public void broadcast(final String message) {
getProxy().broadcast(message);
protected void executeConsoleCommand(final String command) {
getProxy().getPluginManager().dispatchCommand(getProxy().getConsole(), command);
}
@Override
public void broadcast(final Component component) {
audiences.all().sendMessage(component);
}
@Override
@@ -188,6 +245,16 @@ public final class MaintenanceBungeePlugin extends MaintenanceProxyPlugin {
return plugin.getPluginFile();
}
@Override
protected int getOnlinePlayers() {
return getProxy().getOnlineCount();
}
@Override
protected int getMaxPlayers() {
return getProxy().getConfig().getPlayerLimit();
}
@Override
public InputStream getResource(final String name) {
return plugin.getResourceAsStream(name);
@@ -225,4 +292,8 @@ public final class MaintenanceBungeePlugin extends MaintenanceProxyPlugin {
public Favicon getFavicon() {
return favicon;
}
public BungeeAudiences audiences() {
return audiences;
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.bungee.command;
import eu.kennytv.maintenance.bungee.MaintenanceBungeePlugin;
@@ -23,13 +22,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 +52,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 +73,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)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.bungee.command;
import eu.kennytv.maintenance.bungee.util.BungeeSenderInfo;
@@ -28,10 +27,15 @@ public final class MaintenanceBungeeCommandBase extends Command implements TabEx
private final MaintenanceCommand command;
public MaintenanceBungeeCommandBase(final MaintenanceCommand command) {
super("maintenance", "", "maintenancebungee");
super("maintenance", "maintenance.command", "maintenancebungee", "mt");
this.command = command;
}
@Override
public boolean hasPermission(final CommandSender sender) {
return sender.hasPermission("maintenance.admin") || sender.hasPermission("maintenance.command");
}
@Override
public void execute(final CommandSender sender, final String[] args) {
command.execute(new BungeeSenderInfo(sender), args);
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,16 +15,15 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.bungee.listener;
import eu.kennytv.maintenance.bungee.MaintenanceBungeePlugin;
import eu.kennytv.maintenance.bungee.util.ComponentUtil;
import eu.kennytv.maintenance.core.proxy.SettingsProxy;
import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.event.ProxyPingEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
public final class ProxyPingListener implements Listener {
private final MaintenanceBungeePlugin plugin;
@@ -35,26 +34,33 @@ public final class ProxyPingListener implements Listener {
this.settings = settings;
}
@EventHandler(priority = EventPriority.HIGHEST)
@EventHandler(priority = 80)
public void proxyPing(final ProxyPingEvent event) {
if (!settings.isMaintenance()) return;
if (!settings.isMaintenance() || !settings.isEnablePingMessages()) return;
final ServerPing ping = event.getResponse();
if (settings.hasCustomPlayerCountMessage()) {
ping.getVersion().setProtocol(1);
ping.getVersion().setName(settings.getPlayerCountMessage()
.replace("%ONLINE%", Integer.toString(ping.getPlayers().getOnline()))
.replace("%MAX%", Integer.toString(ping.getPlayers().getMax())));
ServerPing.Players players = ping.getPlayers();
if (players == null) {
ping.setPlayers(players = new ServerPing.Players(0, 0, null));
}
ping.setDescription(settings.getRandomPingMessage());
ping.getPlayers().setOnline(0);
ping.getPlayers().setMax(0);
ping.getPlayers().setSample(new ServerPing.PlayerInfo[]{
new ServerPing.PlayerInfo(settings.getPlayerCountHoverMessage().replace("%NEWLINE%", "\n"), "")
});
if (settings.hasCustomPlayerCountMessage()) {
ping.setVersion(new ServerPing.Protocol(settings.getPlayerCountMessage()
.replace("%ONLINE%", Integer.toString(players.getOnline()))
.replace("%MAX%", Integer.toString(players.getMax())), 1));
}
if (settings.hasCustomIcon() && plugin.getFavicon() != null)
ping.setDescriptionComponent(ComponentUtil.toBadComponents(settings.getRandomPingMessage()));
final String[] lines = settings.getPlayerCountHoverLines();
final ServerPing.PlayerInfo[] samplePlayers = new ServerPing.PlayerInfo[lines.length];
for (int i = 0; i < lines.length; i++) {
samplePlayers[i] = new ServerPing.PlayerInfo(lines[i], "");
}
players.setSample(samplePlayers);
if (settings.hasCustomIcon() && plugin.getFavicon() != null) {
ping.setFavicon(plugin.getFavicon());
}
}
}
@@ -0,0 +1,119 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 kennytv (https://github.com/kennytv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.bungee.listener;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.bungee.MaintenanceBungeePlugin;
import eu.kennytv.maintenance.bungee.util.BungeeSenderInfo;
import eu.kennytv.maintenance.bungee.util.BungeeServer;
import eu.kennytv.maintenance.core.proxy.SettingsProxy;
import eu.kennytv.maintenance.core.proxy.listener.ProxyJoinListenerBase;
import eu.kennytv.maintenance.core.proxy.util.ServerConnectResult;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
public final class ServerConnectListener extends ProxyJoinListenerBase implements Listener {
private final MaintenanceBungeePlugin plugin;
public ServerConnectListener(final MaintenanceBungeePlugin plugin, final SettingsProxy settings) {
super(plugin, settings);
this.plugin = plugin;
}
@EventHandler
public void initialServerConnect(final ServerConnectEvent event) {
// Global maintenance check
if (event.isCancelled() || event.getReason() != ServerConnectEvent.Reason.JOIN_PROXY) return;
final BungeeSenderInfo player = new BungeeSenderInfo(event.getPlayer());
if (plugin.isDebug()) {
plugin.getLogger().info("Join permission check for " + event.getPlayer().getName()
+ " - Permission: " + player.hasMaintenancePermission("bypass") + ", whitelist: " + settings.isWhitelisted(player.getUuid()));
}
if (shouldKick(player)) {
final Server waitingServer = shouldConnectToWaitingServer(player);
if (waitingServer != null) {
event.setTarget(((BungeeServer) waitingServer).getServer());
player.send(settings.getMessage("sentToWaitingServer"));
if (plugin.isDebug()) {
plugin.getLogger().info("Join to waiting server for " + event.getPlayer().getName());
}
return;
}
event.setCancelled(true);
player.disconnect(settings.getKickMessage());
if (settings.isJoinNotifications()) {
broadcastJoinNotification(player.getName());
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void serverConnect(final ServerConnectEvent event) {
// Server specific maintenance check
if (event.isCancelled()) return;
final ProxiedPlayer proxiedPlayer = event.getPlayer();
final boolean normalServerConnect = event.getReason() != ServerConnectEvent.Reason.JOIN_PROXY && event.getReason() != ServerConnectEvent.Reason.KICK_REDIRECT
&& event.getReason() != ServerConnectEvent.Reason.LOBBY_FALLBACK && event.getReason() != ServerConnectEvent.Reason.SERVER_DOWN_REDIRECT;
final BungeeSenderInfo player = new BungeeSenderInfo(proxiedPlayer);
final ServerConnectResult connectResult = serverConnect(player, new BungeeServer(event.getTarget()), normalServerConnect);
if (plugin.isDebug()) {
plugin.getLogger().info("Connectresult for " + player.getName() + " to " + event.getTarget().getName() + ": " + connectResult);
}
if (connectResult.isCancelled()) {
event.setCancelled(true);
// Player has no server to connect to
if (proxiedPlayer.getServer() == null) {
player.disconnect(settings.getKickMessage());
}
} else if (connectResult.getTarget() != null) {
event.setTarget(((BungeeServer) connectResult.getTarget()).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 Component component = settings.getMessage("joinNotification", "%PLAYER%", name);
for (final ProxiedPlayer player : players) {
if (plugin.hasPermission(player, "joinnotification")) {
plugin.audiences().player(player).sendMessage(component);
}
}
}
}
@@ -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)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,17 +15,21 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.bungee.util;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.api.MaintenanceProvider;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.bungee.MaintenanceBungeePlugin;
import eu.kennytv.maintenance.core.proxy.util.ProxySenderInfo;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.Connection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.UUID;
public final class BungeeSenderInfo implements SenderInfo {
public final class BungeeSenderInfo implements ProxySenderInfo {
private final CommandSender sender;
public BungeeSenderInfo(final CommandSender sender) {
@@ -48,10 +52,16 @@ public final class BungeeSenderInfo implements SenderInfo {
}
@Override
@Deprecated
public void sendMessage(final String message) {
sender.sendMessage(message);
}
@Override
public void send(final Component component) {
((MaintenanceBungeePlugin) MaintenanceProvider.get()).audiences().sender(sender).sendMessage(component);
}
@Override
public boolean isPlayer() {
return sender instanceof ProxiedPlayer;
@@ -60,4 +70,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 Component component) {
if (sender instanceof Connection) {
((Connection) sender).disconnect(ComponentUtil.toBadComponent(component));
}
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,13 +15,13 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.bungee.util;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
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;
@@ -41,9 +41,16 @@ 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));
public void broadcast(final Component component) {
final BaseComponent[] components = ComponentUtil.toBadComponent(component);
for (final ProxiedPlayer player : server.getPlayers()) {
player.sendMessage(components);
}
}
@Override
public boolean isRegisteredServer() {
return true;
}
public ServerInfo getServer() {
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.bungee.util;
import eu.kennytv.maintenance.core.util.Task;
@@ -0,0 +1,35 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 kennytv (https://github.com/kennytv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.bungee.util;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.chat.ComponentSerializer;
public final class ComponentUtil {
public static BaseComponent[] toBadComponent(final Component component) {
return ComponentSerializer.parse(GsonComponentSerializer.gson().serialize(component));
}
public static BaseComponent toBadComponents(final Component component) {
return new TextComponent(ComponentSerializer.parse(GsonComponentSerializer.gson().serialize(component)));
}
}
+7
View File
@@ -0,0 +1,7 @@
name: Maintenance
version: ${version}
main: eu.kennytv.maintenance.bungee.MaintenanceBungeeBase
author: kennytv
description: ${description}
softDepends: [ServerListPlus, LuckPerms]
website: https://www.spigotmc.org/resources/maintenance.40699/
+12
View File
@@ -0,0 +1,12 @@
dependencies {
api(projects.maintenanceApiProxy)
api(projects.maintenanceCore)
implementation(libs.hikariCP)
compileOnly(libs.luckperms)
compileOnly(libs.guava)
compileOnly(libs.gson)
}
java {
withJavadocJar()
}
@@ -0,0 +1,203 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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;
import com.google.common.io.CharStreams;
import com.google.gson.JsonObject;
import eu.kennytv.maintenance.api.event.proxy.ServerMaintenanceChangedEvent;
import eu.kennytv.maintenance.api.proxy.MaintenanceProxy;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.proxy.command.MaintenanceProxyCommand;
import eu.kennytv.maintenance.core.proxy.runnable.SingleMaintenanceRunnable;
import eu.kennytv.maintenance.core.proxy.runnable.SingleMaintenanceScheduleRunnable;
import eu.kennytv.maintenance.core.proxy.util.ProfileLookup;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.core.util.ServerType;
import eu.kennytv.maintenance.core.util.Task;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* @author kennytv
* @since 3.0
*/
public abstract class MaintenanceProxyPlugin extends MaintenancePlugin implements MaintenanceProxy {
private final Map<String, Task> serverTasks = new HashMap<>();
protected SettingsProxy settingsProxy;
protected MaintenanceProxyPlugin(final String version, final ServerType serverType) {
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()) {
settingsProxy.setMaintenanceToSQL(maintenance);
}
super.setMaintenance(maintenance);
}
@Override
public boolean isMaintenance(final Server server) {
return settingsProxy.isMaintenance(server.getName());
}
@Override
public boolean setMaintenanceToServer(final Server server, final boolean maintenance) {
if (maintenance) {
if (!settingsProxy.addMaintenanceServer(server.getName())) return false;
} else {
if (!settingsProxy.removeMaintenanceServer(server.getName())) return false;
}
serverActions(server, maintenance);
return true;
}
public void serverActions(final Server server, final boolean maintenance) {
if (server == null) return;
// Skip to the even fire for dummy servers
if (server.isRegisteredServer()) {
if (maintenance) {
final Server fallback = settingsProxy.getFallbackServer();
if (fallback == null) {
if (server.hasPlayers()) {
getLogger().warning("The set fallback could not be found! Instead kicking players from that server off the network!");
}
}
kickPlayers(server, fallback);
} else {
server.broadcast(settingsProxy.getMessage("singleMaintenanceDeactivated", "%SERVER%", server.getName()));
}
cancelSingleTask(server);
}
eventManager.callEvent(new ServerMaintenanceChangedEvent(server, maintenance));
}
@Override
public boolean isServerTaskRunning(final Server server) {
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) {
task.cancel();
}
}
public MaintenanceRunnableBase startSingleMaintenanceRunnable(final Server server, final long duration, final TimeUnit unit, final boolean enable) {
final MaintenanceRunnableBase runnable = new SingleMaintenanceRunnable(this, settingsProxy, (int) unit.toSeconds(duration), enable, server);
serverTasks.put(server.getName(), runnable.getTask());
return runnable;
}
public MaintenanceRunnableBase scheduleSingleMaintenanceRunnable(final Server server, final long duration, final long maintenanceDuration, final TimeUnit unit) {
final MaintenanceRunnableBase runnable = new SingleMaintenanceScheduleRunnable(this, settingsProxy,
(int) unit.toSeconds(duration), (int) unit.toSeconds(maintenanceDuration), server);
serverTasks.put(server.getName(), runnable.getTask());
return runnable;
}
@Override
@Nullable
public List<String> getMaintenanceServersDump() {
final List<String> list = new ArrayList<>();
if (isMaintenance()) {
list.add("global");
}
list.addAll(settingsProxy.getMaintenanceServers());
return list.isEmpty() ? null : list;
}
@Override
public MaintenanceProxyCommand getCommandManager() {
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();
}
protected ProfileLookup doUUIDLookup(final String name) throws IOException {
final URL url = new URL("https://api.ashcon.app/mojang/v2/user/" + name);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try (final InputStream in = connection.getInputStream()) {
final String output = CharStreams.toString(new InputStreamReader(in));
final JsonObject json = GSON.fromJson(output, JsonObject.class);
final UUID uuid = UUID.fromString(json.getAsJsonPrimitive("uuid").getAsString());
final String username = json.getAsJsonPrimitive("username").getAsString();
return new ProfileLookup(uuid, username);
}
}
public SettingsProxy getSettingsProxy() {
return settingsProxy;
}
@Nullable
public abstract String getServerNameOf(SenderInfo sender);
protected abstract void kickPlayers(Server server, Server fallback);
protected abstract void kickPlayersTo(Server server);
protected abstract void kickPlayersFromProxy();
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,25 +15,27 @@
* 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;
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 eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
public final class SettingsProxy extends Settings {
private final MaintenanceProxyPlugin plugin;
private final MaintenanceProxyPlugin proxyPlugin;
private Set<String> maintenanceServers;
private String fallbackServer;
private List<String> fallbackServers;
private String waitingServer;
private String mySQLTable;
private String serverTable;
@@ -47,22 +49,24 @@ public final class SettingsProxy extends Settings {
public SettingsProxy(final MaintenanceProxyPlugin plugin) {
super(plugin);
this.plugin = plugin;
this.proxyPlugin = plugin;
}
private void setupMySQL() throws Exception {
super.plugin.getLogger().info("Trying to open database connection...");
private void setupMySQL() {
plugin.getLogger().info("Trying to open database connection... (also, you can simply ignore the SLF4J soft-warning if it shows up)");
final ConfigSection section = config.getSection("mysql");
if (section == null) {
plugin.getLogger().warning("Section missing: mysql");
return;
}
mySQL = new MySQL(section.getString("host"),
mySQL = new MySQL(plugin.getLogger(),
section.getString("host"),
section.getInt("port"),
section.getString("username"),
section.getString("password"),
section.getString("database"));
section.getString("database"),
section.getBoolean("use-ssl", true));
// Varchar as the value regarding the possibility of saving stuff like the motd as well in future updates
mySQLTable = section.getString("table", "maintenance_settings");
@@ -71,22 +75,30 @@ public final class SettingsProxy extends Settings {
mySQL.executeUpdate("CREATE TABLE IF NOT EXISTS " + serverTable + " (server VARCHAR(64) PRIMARY KEY)");
maintenanceQuery = "SELECT * FROM " + mySQLTable + " WHERE setting = ?";
serverQuery = "SELECT * FROM " + serverTable;
super.plugin.getLogger().info("Done!");
plugin.getLogger().info("Done!");
}
@Override
protected void loadExtraSettings() {
// Open database connection if enabled and not already done
if (!hasMySQL() && (boolean) config.getDeep("mysql.use-mysql")) {
if (!hasMySQL() && config.getBoolean("mysql.use-mysql")) {
try {
setupMySQL();
} catch (final Exception e) {
mySQL = null;
super.plugin.getLogger().log(Level.WARNING, "Error while trying do open database connection!", e);
plugin.getLogger().warning("Error while trying do open database connection!");
e.printStackTrace();
}
}
fallbackServer = config.getString("fallback", "lobby");
final Object fallback = config.getObject("fallback");
fallbackServers = fallback instanceof String ? Collections.singletonList((String) fallback) : config.getStringList("fallback");
waitingServer = config.getString("waiting-server", "");
if (waitingServer.isEmpty() || waitingServer.equalsIgnoreCase("none")) {
waitingServer = null;
}
if (hasMySQL()) {
maintenance = loadMaintenance();
maintenanceServers = loadMaintenanceServersFromSQL();
@@ -107,24 +119,52 @@ public final class SettingsProxy extends Settings {
if (hasMySQL() && System.currentTimeMillis() - lastMySQLCheck > millisecondsToCheck) {
final boolean databaseValue = loadMaintenance();
if (databaseValue != maintenance) {
plugin.serverActions(maintenance);
maintenance = databaseValue;
plugin.serverActions(maintenance);
}
lastMySQLCheck = System.currentTimeMillis();
}
return maintenance;
}
public boolean isMaintenance(final Server server) {
public boolean isMaintenance(final String serverName) {
if (hasMySQL() && System.currentTimeMillis() - lastServerCheck > millisecondsToCheck) {
final Set<String> databaseValue = loadMaintenanceServersFromSQL();
if (!databaseValue.equals(maintenanceServers)) {
plugin.serverActions(server, maintenance);
if (!maintenanceServers.equals(databaseValue)) {
// Enable maintenance on yet unlisted servers
for (final String s : databaseValue) {
if (!maintenanceServers.contains(s)) {
proxyPlugin.serverActions(proxyPlugin.getServer(s), true);
}
}
// Disable maintenance on now unlisted servers
for (final String s : maintenanceServers) {
if (!databaseValue.contains(s)) {
proxyPlugin.serverActions(proxyPlugin.getServer(s), false);
}
}
maintenanceServers = databaseValue;
}
lastServerCheck = System.currentTimeMillis();
}
return maintenanceServers.contains(server.getName());
return maintenanceServers.contains(serverName);
}
public Component getServerKickMessage(final String server) {
Component message = getMessageOrNull("singleMaintenanceKicks." + server, "%SERVER%", server);
if (message == null) {
message = getMessage("singleMaintenanceKick", "%SERVER%", server);
}
return plugin.replacePingVariables(message);
}
// Full = being kicked from the proxy, not just a proxied server
public Component getFullServerKickMessage(final String server) {
Component message = getMessageOrNull("singleMaintenanceKicksComplete." + server, "%SERVER%", server);
if (message == null) {
message = getMessage("singleMaintenanceKickComplete", "%SERVER%", server);
}
return plugin.replacePingVariables(message);
}
public boolean hasMySQL() {
@@ -156,10 +196,12 @@ public final class SettingsProxy extends Settings {
if (hasMySQL()) {
maintenanceServers = loadMaintenanceServersFromSQL();
if (!maintenanceServers.remove(server)) return false;
plugin.async(() -> mySQL.executeUpdate("DELETE FROM " + serverTable + " WHERE server = ?", server));
lastServerCheck = System.currentTimeMillis();
} else {
if (!maintenanceServers.remove(server)) return false;
saveServersToConfig();
}
return true;
@@ -188,6 +230,7 @@ public final class SettingsProxy extends Settings {
databaseValue[0] = Boolean.parseBoolean(rs.getString("value"));
}
} catch (final SQLException e) {
plugin.getLogger().warning("An error occured while trying to get the maintenance value from the database!");
e.printStackTrace();
}
}, "maintenance");
@@ -203,7 +246,24 @@ public final class SettingsProxy extends Settings {
return maintenanceServers;
}
public String getFallbackServer() {
return fallbackServer;
@Nullable
public Server getFallbackServer() {
for (final String fallbackServer : fallbackServers) {
final Server server = proxyPlugin.getServer(fallbackServer);
if (server != null && !isMaintenance(server.getName())) {
return server;
}
}
return null;
}
@Nullable
public String getWaitingServer() {
return waitingServer;
}
@Nullable
MySQL getMySQL() {
return mySQL;
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.proxy.command;
import eu.kennytv.maintenance.api.proxy.Server;
@@ -25,8 +24,8 @@ import eu.kennytv.maintenance.core.proxy.SettingsProxy;
import eu.kennytv.maintenance.core.proxy.command.subcommand.*;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public abstract class MaintenanceProxyCommand extends MaintenanceCommand {
private final MaintenanceProxyPlugin plugin;
@@ -45,22 +44,29 @@ public abstract class MaintenanceProxyCommand extends MaintenanceCommand {
add(new SingleStarttimerCommand(plugin), "starttimer", "start");
add(new SingleEndtimerCommand(plugin), "endtimer", "end");
add(new SingleScheduleTimerCommand(plugin), "scheduletimer", "schedule");
add(new AbortSingleTimerCommand(plugin), "aborttimer", "abort");
}
@Override
public List<String> getMaintenanceServersCompletion(final String s) {
return settingsBungee.getMaintenanceServers().stream().filter(server -> server.toLowerCase().startsWith(s)).collect(Collectors.toList());
final List<String> list = new ArrayList<>();
for (final String server : settingsBungee.getMaintenanceServers()) {
if (server.toLowerCase().startsWith(s)) {
list.add(server);
}
}
return list;
}
public Server checkSingleTimerArgs(final SenderInfo sender, final String[] args) {
final Server server = plugin.getServer(args[1]);
public Server checkSingleTimerServerArg(final SenderInfo sender, final String serverName) {
final Server server = plugin.getServer(serverName);
if (server == null) {
sender.sendMessage(settings.getMessage("serverNotFound"));
sender.send(settings.getMessage("serverNotFound"));
return null;
}
if (plugin.isServerTaskRunning(server)) {
sender.sendMessage(settings.getMessage("singleTimerAlreadyRunning"));
sender.send(settings.getMessage("singleTimerAlreadyRunning"));
return null;
}
return server;
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.proxy.command;
import eu.kennytv.maintenance.core.command.CommandInfo;
@@ -25,8 +24,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)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.proxy.command.subcommand;
import eu.kennytv.maintenance.api.proxy.Server;
@@ -29,7 +28,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
@@ -42,28 +41,28 @@ public final class AbortSingleTimerCommand extends ProxyCommandInfo {
if (args.length == 1) {
if (checkPermission(sender, "timer")) return;
if (!plugin.isTaskRunning()) {
sender.sendMessage(getMessage("timerNotRunning"));
sender.send(getMessage("timerNotRunning"));
return;
}
plugin.cancelTask();
sender.sendMessage(getMessage("timerCancelled"));
sender.send(getMessage("timerCancelled"));
} else if (args.length == 2) {
if (checkPermission(sender, "singleserver.timer")) return;
final Server server = plugin.getServer(args[1]);
if (server == null) {
sender.sendMessage(getMessage("serverNotFound"));
sender.send(getMessage("serverNotFound"));
return;
}
if (!plugin.isServerTaskRunning(server)) {
sender.sendMessage(getMessage("singleTimerNotRunning"));
sender.send(getMessage("singleTimerNotRunning"));
return;
}
plugin.cancelSingleTask(server);
sender.sendMessage(getMessage("singleTimerCancelled"));
sender.send(getMessage("singleTimerCancelled"));
} else
sender.sendMessage(helpMessage);
sender.send(getHelpMessage());
}
@Override
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.proxy.command.subcommand;
import eu.kennytv.maintenance.api.proxy.Server;
@@ -26,11 +25,12 @@ import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
public final class SingleEndtimerCommand extends ProxyCommandInfo {
public SingleEndtimerCommand(final MaintenanceProxyPlugin plugin) {
super(plugin, null, "§6/maintenance endtimer [server] <minutes> §7(After the given time in minutes, maintenance mode will be disabled)");
super(plugin, null);
}
@Override
@@ -43,32 +43,35 @@ public final class SingleEndtimerCommand extends ProxyCommandInfo {
if (args.length == 2) {
if (checkPermission(sender, "timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[1])) {
sender.sendMessage(helpMessage);
sender.send(getHelpMessage());
return;
}
if (!plugin.isMaintenance()) {
sender.sendMessage(getMessage("alreadyDisabled"));
return;
}
plugin.startMaintenanceRunnable(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.send(getMessage("alreadyDisabled"));
return;
}
final Server server = plugin.getCommandManager().checkSingleTimerArgs(sender, args);
if (server == null) return;
if (!plugin.isMaintenance(server)) {
sender.sendMessage(getMessage("singleServerAlreadyDisabled").replace("%SERVER%", server.getName()));
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), TimeUnit.MINUTES, false);
sender.send(getMessage("endtimerStarted", "%TIME%", plugin.getRunnable().getTime()));
} else if (args.length == 3) {
if (checkPermission(sender, "singleserver.timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[2], false)) {
sender.send(getHelpMessage());
return;
}
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), false);
sender.sendMessage(getMessage("endtimerStarted").replace("%TIME%", runnable.getTime()));
} else
sender.sendMessage(helpMessage);
final Server server = plugin.getCommandManager().checkSingleTimerServerArg(sender, args[1]);
if (server == null) return;
if (!plugin.isMaintenance(server)) {
sender.send(getMessage("singleServerAlreadyDisabled", "%SERVER%", server.getName()));
return;
}
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), TimeUnit.MINUTES, false);
sender.send(getMessage("endtimerStarted", "%TIME%", runnable.getTime()));
} else {
sender.send(getHelpMessage());
}
}
@Override
@@ -0,0 +1,83 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 kennytv (https://github.com/kennytv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.proxy.command.subcommand;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.core.proxy.command.ProxyCommandInfo;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
public final class SingleScheduleTimerCommand extends ProxyCommandInfo {
public SingleScheduleTimerCommand(final MaintenanceProxyPlugin plugin) {
super(plugin, null);
}
@Override
public boolean hasPermission(final SenderInfo sender) {
return sender.hasMaintenancePermission("timer") || sender.hasPermission("maintenance.singleserver.timer");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (args.length == 3) {
if (checkPermission(sender, "timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[1])
|| plugin.getCommandManager().checkTimerArgs(sender, args[2], false)) {
sender.send(getHelpMessage());
return;
}
if (plugin.isMaintenance()) {
sender.send(getMessage("alreadyEnabled"));
return;
}
plugin.scheduleMaintenanceRunnable(Integer.parseInt(args[1]), Integer.parseInt(args[2]), TimeUnit.MINUTES);
sender.send(getMessage("starttimerStarted", "%TIME%", plugin.getRunnable().getTime()));
} else if (args.length == 4) {
if (checkPermission(sender, "singleserver.timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[2], false)
|| plugin.getCommandManager().checkTimerArgs(sender, args[3], false)) {
sender.send(getHelpMessage());
return;
}
final Server server = plugin.getCommandManager().checkSingleTimerServerArg(sender, args[1]);
if (server == null) return;
if (plugin.isMaintenance(server)) {
sender.send(getMessage("singleServerAlreadyEnabled", "%SERVER%", server.getName()));
return;
}
final MaintenanceRunnableBase runnable = plugin.scheduleSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), Integer.parseInt(args[3]), TimeUnit.MINUTES);
sender.send(getMessage("starttimerStarted", "%TIME%", runnable.getTime()));
} else {
sender.send(getHelpMessage());
}
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
return args.length == 2 && sender.hasMaintenancePermission("singleserver.timer") ? plugin.getCommandManager().getServersCompletion(args[1].toLowerCase()) : Collections.emptyList();
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.proxy.command.subcommand;
import eu.kennytv.maintenance.api.proxy.Server;
@@ -26,11 +25,12 @@ import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
public final class SingleStarttimerCommand extends ProxyCommandInfo {
public SingleStarttimerCommand(final MaintenanceProxyPlugin plugin) {
super(plugin, null, "§6/maintenance starttimer [server] <minutes> §7(After the given time in minutes, maintenance mode will be enabled)");
super(plugin, null);
}
@Override
@@ -43,34 +43,35 @@ 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.send(getHelpMessage());
return;
}
if (plugin.isMaintenance()) {
sender.sendMessage(getMessage("alreadyEnabled"));
sender.send(getMessage("alreadyEnabled"));
return;
}
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), true);
sender.sendMessage(getMessage("starttimerStarted").replace("%TIME%", plugin.getRunnable().getTime()));
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), TimeUnit.MINUTES, true);
sender.send(getMessage("starttimerStarted", "%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.send(getHelpMessage());
return;
}
final Server server = plugin.getCommandManager().checkSingleTimerArgs(sender, args);
final Server server = plugin.getCommandManager().checkSingleTimerServerArg(sender, args[1]);
if (server == null) return;
if (plugin.isMaintenance(server)) {
sender.sendMessage(getMessage("singleServerAlreadyEnabled").replace("%SERVER%", server.getName()));
sender.send(getMessage("singleServerAlreadyEnabled", "%SERVER%", server.getName()));
return;
}
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), true);
sender.sendMessage(getMessage("starttimerStarted").replace("%TIME%", runnable.getTime()));
} else
sender.sendMessage(helpMessage);
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), TimeUnit.MINUTES, true);
sender.send(getMessage("starttimerStarted", "%TIME%", runnable.getTime()));
} else {
sender.send(getHelpMessage());
}
}
@Override
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.proxy.command.subcommand;
import eu.kennytv.maintenance.api.proxy.Server;
@@ -30,7 +29,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
@@ -44,7 +43,7 @@ public final class SingleToggleCommand extends ProxyCommandInfo {
if (checkPermission(sender, "toggle")) return;
final boolean maintenance = args[0].equalsIgnoreCase("on");
if (maintenance == plugin.isMaintenance()) {
sender.sendMessage(getMessage(maintenance ? "alreadyEnabled" : "alreadyDisabled"));
sender.send(getMessage(maintenance ? "alreadyEnabled" : "alreadyDisabled"));
return;
}
@@ -55,24 +54,27 @@ public final class SingleToggleCommand extends ProxyCommandInfo {
Server server = plugin.getServer(args[1]);
if (server == null) {
if (maintenance) {
sender.sendMessage(getMessage("serverNotFound"));
sender.send(getMessage("serverNotFound"));
return;
}
// Let servers be removed from the maintenance list, even if they don't exist on the proxy
server = new DummyServer(args[1]);
if (!plugin.isMaintenance(server)) {
sender.sendMessage(getMessage("serverNotFound"));
sender.send(getMessage("serverNotFound"));
return;
}
}
if (plugin.setMaintenanceToServer(server, maintenance)) {
if (!sender.isPlayer() || !plugin.getServer(sender).equals(server.getName()))
sender.sendMessage(getMessage(maintenance ? "singleMaintenanceActivated" : "singleMaintenanceDeactivated").replace("%SERVER%", server.getName()));
} else
sender.sendMessage(getMessage(maintenance ? "singleServerAlreadyEnabled" : "singleServerAlreadyDisabled").replace("%SERVER%", server.getName()));
} else
sender.sendMessage(helpMessage);
if (!sender.isPlayer() || !server.getName().equals(plugin.getServerNameOf(sender))) {
sender.send(getMessage(maintenance ? "singleMaintenanceActivated" : "singleMaintenanceDeactivated", "%SERVER%", server.getName()));
}
} else {
sender.send(getMessage(maintenance ? "singleServerAlreadyEnabled" : "singleServerAlreadyDisabled", "%SERVER%", server.getName()));
}
} else {
sender.send(getHelpMessage());
}
}
@Override
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.proxy.command.subcommand;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
@@ -25,16 +24,19 @@ import eu.kennytv.maintenance.core.util.SenderInfo;
public final class StatusCommand extends ProxyCommandInfo {
public StatusCommand(final MaintenanceProxyPlugin plugin) {
super(plugin, "singleserver.status", "§6/maintenance status §7(Lists all proxied servers, that are currently under maintenance)");
super(plugin, "singleserver.status");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (getSettings().getMaintenanceServers().isEmpty()) {
sender.sendMessage(getMessage("singleServerMaintenanceListEmpty"));
} else {
sender.sendMessage(getMessage("singleServerMaintenanceList"));
getSettings().getMaintenanceServers().forEach(server -> sender.sendMessage("§8- §b" + server));
sender.send(getMessage("singleServerMaintenanceListEmpty"));
return;
}
sender.send(getMessage("singleServerMaintenanceList"));
for (final String server : getSettings().getMaintenanceServers()) {
sender.send(getMessage("singleServerMaintenanceListEntry", "%SERVER%", server));
}
}
}
@@ -0,0 +1,78 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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.hook;
import eu.kennytv.maintenance.core.hook.LuckPermsHook;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import net.luckperms.api.LuckPermsProvider;
import net.luckperms.api.context.ContextCalculator;
import net.luckperms.api.context.ContextConsumer;
import net.luckperms.api.context.ContextSet;
import net.luckperms.api.context.ImmutableContextSet;
import org.jetbrains.annotations.NotNull;
import java.util.function.Function;
public final class LuckPermsProxyHook {
public static <T> void register(final MaintenanceProxyPlugin plugin, final Function<T, String> function) {
LuckPermsProvider.get().getContextManager().registerCalculator(new MaintenanceProxyCalculator<T>(plugin, function));
}
public static final class MaintenanceProxyCalculator<T> implements ContextCalculator<T> {
private static final String MAINTENANCE_ON_KEY = "is-maintenance-on-";
private static final String ON_MAINTENANCE_SERVER_KEY = "on-maintenance-server";
private final MaintenanceProxyPlugin maintenance;
private final Function<T, String> playerServerFunction;
private MaintenanceProxyCalculator(final MaintenanceProxyPlugin plugin, final Function<T, String> playerServerFunction) {
this.maintenance = plugin;
this.playerServerFunction = playerServerFunction;
}
@Override
public void calculate(@NotNull final T target, @NotNull final ContextConsumer consumer) {
consumer.accept(LuckPermsHook.MaintenanceCalculator.MAINTENANCE_KEY, Boolean.toString(maintenance.isMaintenance()));
/*for (final String serverName : maintenance.getServers()) {
final Server server = maintenance.getServer(serverName);
if (server != null) {
consumer.accept(MAINTENANCE_ON_KEY + server, Boolean.toString(maintenance.isMaintenance(server)));
}
}*/
final String server = playerServerFunction.apply(target);
if (server != null) {
final String value = Boolean.toString(maintenance.getSettingsProxy().isMaintenance(server));
consumer.accept(MAINTENANCE_ON_KEY + server, value);
consumer.accept(ON_MAINTENANCE_SERVER_KEY, value);
}
}
@Override
public ContextSet estimatePotentialContexts() {
final ImmutableContextSet.Builder builder = ImmutableContextSet.builder();
for (final String serverName : maintenance.getServers()) {
final String key = MAINTENANCE_ON_KEY + serverName;
builder.add(key, "true").add(key, "false");
}
return builder.add(ON_MAINTENANCE_SERVER_KEY, "true").add(ON_MAINTENANCE_SERVER_KEY, "false")
.add(LuckPermsHook.MaintenanceCalculator.MAINTENANCE_KEY, "true")
.add(LuckPermsHook.MaintenanceCalculator.MAINTENANCE_KEY, "false").build();
}
}
}
@@ -0,0 +1,121 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 kennytv (https://github.com/kennytv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.proxy.listener;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.listener.JoinListenerBase;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.core.proxy.SettingsProxy;
import eu.kennytv.maintenance.core.proxy.util.ProxySenderInfo;
import eu.kennytv.maintenance.core.proxy.util.ServerConnectResult;
import eu.kennytv.maintenance.core.util.SenderInfo;
import org.jetbrains.annotations.Nullable;
public abstract class ProxyJoinListenerBase extends JoinListenerBase {
private static final ServerConnectResult ALLOWED = new ServerConnectResult(false);
private static final ServerConnectResult DENIED = new ServerConnectResult(true);
protected final MaintenanceProxyPlugin plugin;
protected final SettingsProxy settings;
private boolean warned;
protected ProxyJoinListenerBase(final MaintenanceProxyPlugin plugin, final SettingsProxy settings) {
super(plugin, settings);
this.plugin = plugin;
this.settings = settings;
}
/**
* @param sender joined player
* @param target target server
* @param normalServerConnect true if normal server connect, false if initial proxy join or kick
* @return connect result with data for further handling
*/
protected ServerConnectResult serverConnect(final ProxySenderInfo sender, final Server target, final boolean normalServerConnect) {
// Check waiting server for global maintenance
if (settings.isMaintenance()) {
if (sender.hasMaintenancePermission("bypass") || settings.isWhitelisted(sender.getUuid())) return ALLOWED;
final Server waitingServer = shouldConnectToWaitingServer(sender);
// Should never be null, but just in case
if (waitingServer == null) return DENIED;
// Player is connecting to the waiting server
if (target.getName().equals(waitingServer.getName())) return ALLOWED;
// Player already is on the waiting server
final String currentServer = plugin.getServerNameOf(sender);
if (waitingServer.getName().equals(currentServer)) {
sender.send(settings.getMessage("forceWaitingServer"));
return DENIED;
}
sender.send(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.send(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);
}
@@ -0,0 +1,112 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 kennytv (https://github.com/kennytv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.proxy.mysql;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.jetbrains.annotations.Nullable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
public final class MySQL {
private final Logger logger;
private final HikariDataSource hikariDataSource;
public MySQL(final Logger logger, final String hostname, final int port, final String username, final String password, final String database, final boolean useSSL) {
this.logger = logger;
final HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setMaximumPoolSize(10);
hikariConfig.addDataSourceProperty("serverName", hostname);
hikariConfig.addDataSourceProperty("user", username);
hikariConfig.addDataSourceProperty("password", password);
String urlProperty = "jdbc:mysql://" + hostname + ":" + port + "/" + database;
if (!useSSL) {
urlProperty += "?useSSL=false";
}
hikariConfig.addDataSourceProperty("url", urlProperty);
hikariConfig.setJdbcUrl(urlProperty);
hikariConfig.setDataSourceClassName(findDriver("com.mysql.jdbc.jdbc2.optional.MysqlDataSource", "com.mysql.cj.jdbc.MysqlDataSource", "org.mariadb.jdbc.MariaDbDataSource"));
hikariDataSource = new HikariDataSource(hikariConfig);
}
@Nullable
private String findDriver(final String... classNames) {
for (final String name : classNames) {
try {
Class.forName(name);
return name;
} catch (final ClassNotFoundException ignored) {
}
}
throw new IllegalArgumentException("No sql driver class found");
}
public void executeUpdate(final String query, final Consumer<Integer> callback, final Object... objects) {
try (final Connection connection = hikariDataSource.getConnection()) {
try (final PreparedStatement preparedStatement = connection.prepareStatement(query)) {
int current = 1;
for (final Object object : objects) {
preparedStatement.setObject(current, object);
current++;
}
callback.accept(preparedStatement.executeUpdate());
}
} catch (final SQLException e) {
logger.log(Level.SEVERE, "Error while executing update method: " + query);
e.printStackTrace();
}
}
public void executeQuery(final String query, final Consumer<ResultSet> callback, final Object... objects) {
try (final Connection connection = hikariDataSource.getConnection()) {
try (final PreparedStatement preparedStatement = connection.prepareStatement(query)) {
int current = 1;
for (final Object object : objects) {
preparedStatement.setObject(current, object);
current++;
}
try (final ResultSet resultSet = preparedStatement.executeQuery()) {
callback.accept(resultSet);
}
}
} catch (final SQLException e) {
logger.log(Level.SEVERE, "Error while executing query method: " + query);
e.printStackTrace();
}
}
public void executeUpdate(final String query, final Object... objects) {
executeUpdate(query, res -> {
}, objects);
}
public void close() {
hikariDataSource.close();
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,35 +15,44 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.proxy.runnable;
import eu.kennytv.maintenance.api.proxy.IMaintenanceProxy;
import eu.kennytv.maintenance.api.proxy.MaintenanceProxy;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
public final class SingleMaintenanceRunnable extends MaintenanceRunnableBase {
private final Server server;
public class SingleMaintenanceRunnable extends MaintenanceRunnableBase {
protected final Server server;
public SingleMaintenanceRunnable(final MaintenancePlugin plugin, final Settings settings, final int minutes, final boolean enable, final Server server) {
super(plugin, settings, minutes, enable);
public SingleMaintenanceRunnable(final MaintenancePlugin plugin, final Settings settings, final int seconds, final boolean enable, final Server server) {
super(plugin, settings, seconds, enable);
this.server = server;
}
@Override
protected void broadcast(final Component component) {
server.broadcast(component);
}
@Override
protected void finish() {
((IMaintenanceProxy) plugin).setMaintenanceToServer(server, enable);
((MaintenanceProxy) plugin).setMaintenanceToServer(server, enable);
}
@Override
protected String startMessageKey() {
return settings.getMessage("singleStarttimerBroadcast").replace("%TIME%", getTime()).replace("%SERVER%", server.getName());
protected Component getStartMessage() {
return settings.getMessage("singleStarttimerBroadcast",
"%TIME%", getTime(),
"%SERVER%", server.getName());
}
@Override
protected String endMessageKey() {
return settings.getMessage("singleEndtimerBroadcast").replace("%TIME%", getTime()).replace("%SERVER%", server.getName());
protected Component getEndMessage() {
return settings.getMessage("singleEndtimerBroadcast",
"%TIME%", getTime(),
"%SERVER%", server.getName());
}
}
@@ -0,0 +1,48 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 kennytv (https://github.com/kennytv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.proxy.runnable;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import java.util.concurrent.TimeUnit;
public final class SingleMaintenanceScheduleRunnable extends SingleMaintenanceRunnable {
private final int maintenanceDuration;
public SingleMaintenanceScheduleRunnable(final MaintenancePlugin plugin, final Settings settings, final int seconds, final int maintenanceDuration, final Server server) {
super(plugin, settings, seconds, true, server);
this.maintenanceDuration = maintenanceDuration;
}
@Override
protected void finish() {
super.finish();
((MaintenanceProxyPlugin) plugin).startSingleMaintenanceRunnable(server, maintenanceDuration, TimeUnit.SECONDS, false);
}
@Override
protected Component getStartMessage() {
return settings.getMessage("singleScheduletimerBroadcast",
"%SERVER%", server.getName(),
"%TIME%", getTime(), "%DURATION%", plugin.getFormattedTime(maintenanceDuration));
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,10 +15,10 @@
* 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.server;
import eu.kennytv.maintenance.api.proxy.Server;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
public final class DummyServer implements Server {
private final String name;
@@ -38,6 +38,11 @@ public final class DummyServer implements Server {
}
@Override
public void broadcast(String s) {
public void broadcast(final Component component) {
}
@Override
public boolean isRegisteredServer() {
return false;
}
}
@@ -0,0 +1,38 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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 java.util.UUID;
public final class ProfileLookup {
private final UUID uuid;
private final String name;
public ProfileLookup(final UUID uuid, final String name) {
this.uuid = uuid;
this.name = name;
}
public UUID getUuid() {
return uuid;
}
public String getName() {
return name;
}
}
@@ -0,0 +1,71 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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.lib.kyori.adventure.text.Component;
import java.util.UUID;
public final class ProxyOfflineSenderInfo implements ProxySenderInfo {
private final UUID uuid;
private final String name;
public ProxyOfflineSenderInfo(final UUID uuid, final String name) {
this.uuid = uuid;
this.name = name;
}
@Override
public boolean canAccess(final Server server) {
return false;
}
@Override
public void disconnect(final Component component) {
}
@Override
public UUID getUuid() {
return uuid;
}
@Override
public String getName() {
return name;
}
@Override
public boolean hasPermission(final String permission) {
return false;
}
@Override
@Deprecated
public void sendMessage(final String message) {
}
@Override
public void send(final Component component) {
}
@Override
public boolean isPlayer() {
return true;
}
}
@@ -0,0 +1,29 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
public interface ProxySenderInfo extends SenderInfo {
boolean canAccess(Server server);
void disconnect(Component component);
}
@@ -0,0 +1,53 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 kennytv (https://github.com/kennytv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.proxy.util;
import eu.kennytv.maintenance.api.proxy.Server;
import org.jetbrains.annotations.Nullable;
public final class ServerConnectResult {
private final boolean cancel;
private final Server target;
public ServerConnectResult(final boolean cancel) {
this.cancel = cancel;
this.target = null;
}
public ServerConnectResult(final Server target) {
this.cancel = false;
this.target = target;
}
public boolean isCancelled() {
return cancel;
}
@Nullable
public Server getTarget() {
return target;
}
@Override
public String toString() {
return "ServerConnectResult{" +
"cancel=" + cancel +
", target=" + target +
'}';
}
}
+24
View File
@@ -0,0 +1,24 @@
plugins {
id("net.kyori.blossom")
}
blossom {
replaceToken("\$VERSION", project.version)
replaceToken("\$IMPL_VERSION", "git-Maintenance-${project.version}:${rootProject.latestCommitHash()}")
}
dependencies {
api(projects.maintenanceApi)
api(projects.adventure.adventureApi) {
targetConfiguration = "shadow"
}
compileOnly(libs.luckperms)
compileOnly(libs.serverlistplus)
compileOnly(libs.guava)
compileOnly(libs.gson)
compileOnly(libs.snakeyaml)
}
java {
withJavadocJar()
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,19 +15,17 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core;
package eu.kennytv.maintenance.api;
import eu.kennytv.maintenance.api.Maintenance;
/**
* @author KennyTV
* @since 2.2.2
*/
public interface IMaintenanceBase {
@FunctionalInterface
public interface MaintenanceBase {
/**
* This method is used internally when getting the api instance.
*
* @return {@link IMaintenance} instance
* @return {@link Maintenance} instance
*/
IMaintenance getApi();
Maintenance getApi();
}
@@ -0,0 +1,469 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.io.CharStreams;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import eu.kennytv.maintenance.api.Maintenance;
import eu.kennytv.maintenance.api.MaintenanceProvider;
import eu.kennytv.maintenance.api.event.MaintenanceChangedEvent;
import eu.kennytv.maintenance.api.event.manager.EventManager;
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.hook.ServerListPlusHook;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnable;
import eu.kennytv.maintenance.core.runnable.MaintenanceScheduleRunnable;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.core.util.ServerType;
import eu.kennytv.maintenance.core.util.Task;
import eu.kennytv.maintenance.core.util.Version;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
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;
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.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
public abstract class MaintenancePlugin implements Maintenance {
public static final Gson GSON = new GsonBuilder().create();
protected final eu.kennytv.maintenance.core.event.EventManager eventManager;
protected final Version version;
protected Settings settings;
protected ServerListPlusHook serverListPlusHook;
protected MaintenanceRunnable runnable;
protected MaintenanceCommand commandManager;
private final String prefix;
private final ServerType serverType;
private Version newestVersion;
private boolean debug;
protected MaintenancePlugin(final String version, final ServerType serverType) {
this.version = new Version(version);
this.serverType = serverType;
this.prefix = "§8[§eMaintenance" + serverType + "§8] ";
this.eventManager = new eu.kennytv.maintenance.core.event.EventManager();
MaintenanceProvider.setMaintenance(this);
}
public void disable() {
}
@Override
public void setMaintenance(final boolean maintenance) {
settings.setMaintenance(maintenance);
settings.getConfig().set("maintenance-enabled", maintenance);
settings.saveConfig();
serverActions(maintenance);
for (final String command : (maintenance ? settings.getCommandsOnMaintenanceEnable() : settings.getCommandsOnMaintenanceDisable())) {
try {
executeConsoleCommand(command);
} catch (final Exception e) {
getLogger().severe("Error while executing extra maintenance " + (maintenance ? "enable" : "disable") + " command: " + command);
e.printStackTrace();
}
}
}
public void serverActions(final boolean maintenance) {
if (isTaskRunning()) {
cancelTask();
}
if (serverListPlusHook != null && settings.isEnablePingMessages()) {
serverListPlusHook.setEnabled(!maintenance);
}
if (maintenance) {
broadcast(settings.getMessage("maintenanceActivated"));
if (settings.isKickOnlinePlayers()) {
kickPlayers();
}
} else {
broadcast(settings.getMessage("maintenanceDeactivated"));
}
eventManager.callEvent(new MaintenanceChangedEvent(maintenance));
}
public Component replacePingVariables(final Component component) {
return component.replaceText(builder -> builder.matchLiteral("%TIMER%").replacement(c -> getTimerMessage()))
.replaceText(builder -> builder.matchLiteral("%ONLINE%").replacement(c -> Component.text(getOnlinePlayers())))
.replaceText(builder -> builder.matchLiteral("%MAX%").replacement(c -> Component.text(getMaxPlayers())));
}
public Component getTimerMessage() {
if (!isTaskRunning()) {
return settings.getMessage("motdTimerNotRunning");
}
final int preHours = runnable.getSecondsLeft() / 60;
final int minutes = preHours % 60;
final int seconds = runnable.getSecondsLeft() % 60;
return settings.getMessage("motdTimer",
"%HOURS%", String.format("%02d", preHours / 60),
"%MINUTES%", String.format("%02d", minutes),
"%SECONDS%", String.format("%02d", seconds));
}
public String getFormattedTime(final int timeSeconds) {
final int preHours = timeSeconds / 60;
final int minutes = preHours % 60;
final int seconds = timeSeconds % 60;
final StringBuilder buider = new StringBuilder();
append(buider, "hour", preHours / 60);
append(buider, "minute", minutes);
append(buider, "second", seconds);
return buider.toString();
}
private void append(final StringBuilder builder, final String timeUnit, final int time) {
if (time == 0) return;
if (builder.length() != 0) {
builder.append(' ');
}
builder.append(time).append(' ').append(settings.language.getString(time == 1 ? timeUnit : timeUnit + "s"));
}
public void startMaintenanceRunnable(final long duration, final TimeUnit unit, final boolean enable) {
runnable = new MaintenanceRunnable(this, settings, (int) unit.toSeconds(duration), enable);
// Save the endtimer to be able to continue it after a server stop
if (settings.isSaveEndtimerOnStop() && !runnable.shouldEnable()) {
settings.setSavedEndtimer(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(runnable.getSecondsLeft()));
}
}
public void scheduleMaintenanceRunnable(final long duration, final int maintenanceDuration, final TimeUnit unit) {
runnable = new MaintenanceScheduleRunnable(this, settings, (int) unit.toSeconds(duration), (int) unit.toSeconds(maintenanceDuration));
}
public boolean updateAvailable() {
try {
checkNewestVersion();
return version.compareTo(newestVersion) == -1;
} catch (final Exception e) {
return false;
}
}
protected void continueLastEndtimer() {
if (!settings.isSaveEndtimerOnStop()) return;
if (settings.getSavedEndtimer() == 0) return;
final long current = System.currentTimeMillis();
getLogger().info("Found interrupted endtimer from last uptime...");
if (!isMaintenance()) {
getLogger().info("Maintenance has already been disabled, thus the timer has been cancelled.");
settings.setSavedEndtimer(0);
} else if (settings.getSavedEndtimer() < current) {
getLogger().info("The endtimer has already expired, maintenance has been disabled.");
setMaintenance(false);
settings.setSavedEndtimer(0);
} else {
startMaintenanceRunnable(settings.getSavedEndtimer() - current, TimeUnit.MILLISECONDS, false);
getLogger().info("The timer has been continued - maintenance will be disabled in: " + getTimerMessage());
}
}
protected void sendEnableMessage() {
if (!settings.hasUpdateChecks()) return;
async(() -> {
try {
checkNewestVersion();
} catch (final Exception e) {
getLogger().warning("An error occured during update checking!");
return;
}
final int compare = version.compareTo(newestVersion);
if (compare == -1) {
//TODO mmmmmmmm legacy chat
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://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!");
}
}
});
}
public boolean installUpdate() {
// Ore sad :(
Preconditions.checkArgument(serverType != ServerType.SPONGE);
try {
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();
if (newlength < 10000) {
file.delete();
return false;
}
writeFile(new FileInputStream(file), new BufferedOutputStream(new FileOutputStream(getPluginFile())));
file.delete();
return true;
} catch (final Exception e) {
e.printStackTrace();
return false;
}
}
private void writeFile(final InputStream is, final OutputStream os) throws IOException {
final byte[] chunk = new byte[1024];
int chunkSize;
while ((chunkSize = is.read(chunk)) != -1) {
os.write(chunk, 0, chunkSize);
}
is.close();
os.close();
}
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();
final Version newVersion = new Version(newVersionString);
if (!newVersion.equals(version)) {
newestVersion = newVersion;
}
}
}
public String pasteDump() {
final MaintenanceDump dump = new MaintenanceDump(this, settings);
try {
final HttpURLConnection connection = (HttpURLConnection) new URL("https://hastebin.com/documents").openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("User-Agent", "Maintenance/" + getVersion());
connection.setRequestProperty("Content-Type", "text/plain");
try (final OutputStream out = connection.getOutputStream()) {
out.write(new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create().toJson(dump).getBytes(StandardCharsets.UTF_8));
}
if (connection.getResponseCode() == 503) {
getLogger().warning("Could not paste dump, hastebin.com down?");
return null;
}
try (final InputStream in = connection.getInputStream()) {
final String output = CharStreams.toString(new InputStreamReader(in));
final JsonObject jsonOutput = GSON.fromJson(output, JsonObject.class);
if (!jsonOutput.has("key")) {
getLogger().log(Level.WARNING, "Could not paste dump, there was no key returned :(");
return null;
}
return jsonOutput.get("key").getAsString();
}
} catch (final IOException e) {
getLogger().log(Level.WARNING, "Could not paste dump :(");
e.printStackTrace();
return null;
}
}
public void loadMaintenanceIcon() {
final File file = new File(getDataFolder(), "maintenance-icon.png");
if (!file.exists()) {
getLogger().warning("Could not find a 'maintenance-icon.png' file - did you create one in the plugin's folder?");
return;
}
try {
loadIcon(file);
} catch (final Exception e) {
getLogger().log(Level.WARNING, "Could not load the 'maintenance-icon.png' file!");
e.printStackTrace();
}
}
public void cancelTask() {
if (settings.isSaveEndtimerOnStop() && !runnable.shouldEnable()) {
settings.setSavedEndtimer(0);
}
runnable.getTask().cancel();
runnable = null;
}
@Nullable
public UUID checkUUID(final SenderInfo sender, final String s) {
final UUID uuid;
try {
uuid = UUID.fromString(s);
} catch (final Exception e) {
sender.send(settings.getMessage("invalidUuid"));
return null;
}
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]+");
}
@Override
public boolean isMaintenance() {
return settings.isMaintenance();
}
@Override
public boolean isTaskRunning() {
return runnable != null;
}
@Override
public Settings getSettings() {
return settings;
}
@Override
public EventManager getEventManager() {
return eventManager;
}
@Override
public String getVersion() {
return version.toString();
}
@Nullable
public List<String> getMaintenanceServersDump() {
return isMaintenance() ? Arrays.asList("global") : null;
}
@Override
public boolean isDebug() {
return debug;
}
@Override
public void setDebug(final boolean debug) {
this.debug = debug;
}
public int getSaltLevel() {
return Integer.MAX_VALUE;
}
public Version getNewestVersion() {
return newestVersion;
}
public String getPrefix() {
return prefix;
}
/**
* @see #isTaskRunning()
*/
@Nullable
public MaintenanceRunnable getRunnable() {
return runnable;
}
public MaintenanceCommand getCommandManager() {
return commandManager;
}
public ServerType getServerType() {
return serverType;
}
protected String getPluginFolder() {
return "plugins/";
}
public abstract void async(Runnable runnable);
protected abstract void executeConsoleCommand(String command);
public abstract void broadcast(Component component);
public abstract void sendUpdateNotification(SenderInfo sender);
public abstract Task startMaintenanceRunnable(Runnable runnable);
/**
* Gets the offline sender info of a player.
* This method may do a web lookup.
*
* @param name name of the player
*/
public abstract void getOfflinePlayer(String name, Consumer<@Nullable SenderInfo> consumer);
public abstract void getOfflinePlayer(UUID uuid, Consumer<@Nullable SenderInfo> consumer);
public abstract File getDataFolder();
@Nullable
public InputStream getResource(String name) {
return this.getClass().getClassLoader().getResourceAsStream(name);
}
public abstract Logger getLogger();
public abstract String getServerVersion();
public abstract List<PluginDump> getPlugins();
protected abstract void loadIcon(File file) throws Exception;
protected abstract void kickPlayers();
protected abstract File getPluginFile();
protected abstract int getOnlinePlayers();
protected abstract int getMaxPlayers();
}
@@ -0,0 +1,560 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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;
import eu.kennytv.maintenance.api.event.MaintenanceReloadedEvent;
import eu.kennytv.maintenance.core.config.Config;
import eu.kennytv.maintenance.core.config.ConfigSection;
import eu.kennytv.maintenance.core.util.ServerType;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.TextComponent;
import eu.kennytv.maintenance.lib.kyori.adventure.text.TextReplacementConfig;
import eu.kennytv.maintenance.lib.kyori.adventure.text.minimessage.MiniMessage;
import eu.kennytv.maintenance.lib.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
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.ArrayList;
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 eu.kennytv.maintenance.api.Settings {
public static final String NEW_LINE_REPLACEMENT = "<br>";
private static final int CONFIG_VERSION = 6;
private static final int LANGUAGE_VERSION = 1;
private static final Random RANDOM = new Random();
protected final MaintenancePlugin plugin;
private final Map<UUID, String> whitelistedPlayers = new HashMap<>();
private final String[] unsupportedFields;
protected boolean maintenance;
private Set<Integer> broadcastIntervals;
private List<Component> pingMessages;
private List<Component> timerSpecificPingMessages;
private List<String> commandsOnMaintenanceEnable;
private List<String> commandsOnMaintenanceDisable;
private Component playerCountMessage;
private List<Component> playerCountHoverLines;
private Component prefix;
private String languageName;
private boolean enablePingMessages;
private boolean customPlayerCountMessage;
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;
protected Config whitelist;
public Settings(final MaintenancePlugin plugin, final String... unsupportedFields) {
this.plugin = plugin;
this.unsupportedFields = unsupportedFields;
if (!plugin.getDataFolder().exists()) {
updatePluginDirectory();
plugin.getDataFolder().mkdirs();
}
createFile("config.yml");
createFile("WhitelistedPlayers.yml");
reloadConfigs();
}
@Override
public void reloadConfigs() {
try {
config = new Config(new File(plugin.getDataFolder(), "config.yml"), unsupportedFields);
config.load();
config.resetAwesomeHeader();
whitelist = new Config(new File(plugin.getDataFolder(), "WhitelistedPlayers.yml"));
whitelist.load();
} catch (final Exception e) {
throw new RuntimeException("Unable to load Maintenance files - probably a malformed config file", e);
}
loadSettings();
createLanguageFile();
try {
language = new Config(new File(plugin.getDataFolder(), "language-" + languageName + ".yml"));
language.load();
} catch (final IOException e) {
throw new RuntimeException("Unable to load Maintenance language file - probably a malformed file", e);
}
try {
updateLanguageFile();
} catch (final IOException e) {
plugin.getLogger().severe("Couldn't update language file");
e.printStackTrace();
}
prefix = MiniMessage.miniMessage().deserialize(language.getString("prefix"));
plugin.getEventManager().callEvent(new MaintenanceReloadedEvent());
}
public void saveConfig() {
try {
config.save();
} catch (final IOException e) {
e.printStackTrace();
}
}
// 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(from)) {
Files.copy(in, file.toPath());
} catch (final IOException e) {
throw new RuntimeException("Unable to create " + name + " file for Maintenance!", e);
}
}
}
private void saveWhitelistedPlayers() {
try {
whitelist.save();
} catch (final IOException e) {
e.printStackTrace();
}
}
private void 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();
}
}
}
private void loadSettings() {
updateConfig();
enablePingMessages = config.getBoolean("enable-pingmessages", true);
pingMessages = loadPingMessages("pingmessages");
if (config.getBoolean("enable-timerspecific-messages")) {
timerSpecificPingMessages = loadPingMessages("timerspecific-pingmessages");
}
maintenance = config.getBoolean("maintenance-enabled");
commandsOnMaintenanceEnable = config.getStringList("commands-on-maintenance-enable");
commandsOnMaintenanceDisable = config.getStringList("commands-on-maintenance-disable");
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) {
playerCountMessage = getConfigMessage("playercountmessage");
}
playerCountHoverLines = new ArrayList<>();
final String playerHoverMessage = config.getString("playercounthovermessage");
for (final String line : playerHoverMessage.split("<br>")) {
playerCountHoverLines.add(MiniMessage.miniMessage().deserialize(line));
}
languageName = config.getString("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();
for (final Map.Entry<String, Object> entry : whitelist.getValues().entrySet()) {
try {
whitelistedPlayers.put(UUID.fromString(entry.getKey()), (String) entry.getValue());
} catch (final Exception e) {
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
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() {
final int version = config.getInt("config-version");
if (version != CONFIG_VERSION) {
plugin.getLogger().info("Updating config to the latest version...");
if (version < 6) {
// Legacy text to MiniMessage
legacyToMinimessage(config.getStringList("pingmessages"));
legacyToMinimessage(config.getStringList("timerspecific-pingmessages"));
config.set("playercounthovermessage", legacyToMinimessage(config.getString("playercounthovermessage")));
config.set("playercountmessage", legacyToMinimessage(config.getString("playercountmessage")));
}
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", CONFIG_VERSION);
file.delete();
tempConfig.clear();
saveConfig();
plugin.getLogger().info("Done! Updated config!");
}
}
private void updateLanguageFile() throws IOException {
final int version = language.getInt("language-version");
if (version == LANGUAGE_VERSION) {
return;
}
plugin.getLogger().info("Updating language file to the latest version...");
if (version < 1) {
for (final Map.Entry<String, Object> entry : language.getValues().entrySet()) {
if (!(entry.getValue() instanceof String)) {
continue;
}
String value = (String) entry.getValue();
value = value.replace("&8[&eMaintenance&8] ", "<prefix>");
value = legacyToMinimessage(value);
value = value.replace("%NEWLINE%", NEW_LINE_REPLACEMENT);
language.set(entry.getKey(), value);
}
}
final String filePrefix = "language-" + languageName;
createFile(filePrefix + "-new.yml", filePrefix + ".yml");
final File file = new File(plugin.getDataFolder(), filePrefix + "-new.yml");
final Config tempConfig = new Config(file);
try {
tempConfig.load();
} finally {
file.delete();
}
language.addMissingFields(tempConfig.getValues(), tempConfig.getComments());
tempConfig.clear();
language.set("language-version", LANGUAGE_VERSION);
language.save();
plugin.getLogger().info("Updated language file!");
}
private String legacyToMinimessage(final String s) {
final TextComponent component = LegacyComponentSerializer.legacyAmpersand().deserialize(s);
final String serialized = MiniMessage.miniMessage().serialize(component);
//TODO hack to remove explicit closing until fixed in MM
return serialized.replaceAll("</[a-z_]+>", "");
}
private void legacyToMinimessage(final List<String> list) {
for (int i = 0; i < list.size(); i++) {
list.set(i, legacyToMinimessage(list.get(i)));
}
}
public Component getConfigMessage(final String path) {
final String s = config.getString(path);
if (s == null) {
plugin.getLogger().warning("The config file is missing the following string: " + path);
return Component.text("null");
}
return MiniMessage.miniMessage().deserialize(replaceNewlineVar(s));
}
public Component getMessage(final String path, final String... replacements) {
String s = language.getString(path);
if (s == null) {
plugin.getLogger().warning("The language file is missing the following string: " + path);
return Component.text("null");
}
if (replacements.length != 0) {
if (replacements.length % 2 != 0) {
throw new IllegalArgumentException("Invalid replacement count: " + replacements.length);
}
for (int i = 0; i < replacements.length; i += 2) {
final String key = replacements[i];
s = s.replace(key, replacements[i + 1]);
}
}
return MiniMessage.miniMessage().deserialize(replaceNewlineVar(s))
.replaceText(TextReplacementConfig.builder().matchLiteral("<prefix>").replacement(prefix).build());
}
public @Nullable Component getMessageOrNull(final String path, final String... replacements) {
return language.contains(path) ? getMessage(path, replacements) : null;
}
public Component getRandomPingMessage() {
if (plugin.isTaskRunning() && !plugin.getRunnable().shouldEnable()
&& hasTimerSpecificPingMessages() && !timerSpecificPingMessages.isEmpty()) {
return getPingMessage(timerSpecificPingMessages);
}
return pingMessages.isEmpty() ? Component.empty() : getPingMessage(pingMessages);
}
private Component getPingMessage(final List<Component> list) {
final Component component = list.size() == 1 ? list.get(0) : list.get(RANDOM.nextInt(list.size()));
return plugin.replacePingVariables(component);
}
private List<Component> loadPingMessages(final String path) {
final List<String> list = config.getStringList(path);
final List<Component> components = new ArrayList<>(list.size());
for (final String s : list) {
components.add(MiniMessage.miniMessage().deserialize(replaceNewlineVar(s)));
}
return components;
}
@Override
public boolean removeWhitelistedPlayer(final UUID uuid) {
if (whitelistedPlayers.remove(uuid) == null) {
return false;
}
whitelist.remove(uuid.toString());
saveWhitelistedPlayers();
return true;
}
@Deprecated
@Override
public boolean removeWhitelistedPlayer(final String name) {
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;
}
whitelistedPlayers.remove(uuid);
whitelist.remove(uuid.toString());
saveWhitelistedPlayers();
return true;
}
@Override
public boolean addWhitelistedPlayer(final UUID uuid, final String name) {
final boolean added = whitelistedPlayers.put(uuid, name) == null;
whitelist.set(uuid.toString(), name);
saveWhitelistedPlayers();
return added;
}
@Override
public Map<UUID, String> getWhitelistedPlayers() {
return whitelistedPlayers;
}
@Override
public boolean isWhitelisted(final UUID uuid) {
return whitelistedPlayers.containsKey(uuid);
}
@Override
public boolean isMaintenance() {
return maintenance;
}
public void setMaintenance(final boolean maintenance) {
this.maintenance = maintenance;
}
@Override
public boolean isEnablePingMessages() {
return enablePingMessages;
}
@Override
public boolean isJoinNotifications() {
return joinNotifications;
}
@Override
public boolean hasCustomIcon() {
return customMaintenanceIcon;
}
@Override
public boolean debugEnabled() {
return debug;
}
public boolean hasUpdateChecks() {
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;
}
public List<Component> getPingMessages() {
return pingMessages;
}
public List<String> getCommandsOnMaintenanceEnable() {
return commandsOnMaintenanceEnable;
}
public List<String> getCommandsOnMaintenanceDisable() {
return commandsOnMaintenanceDisable;
}
@Nullable
public List<Component> getTimerSpecificPingMessages() {
return timerSpecificPingMessages;
}
public Set<Integer> getBroadcastIntervals() {
return broadcastIntervals;
}
// Yikeseroo
public String getPlayerCountMessage() {
return LegacyComponentSerializer.legacySection().serialize(plugin.replacePingVariables(playerCountMessage));
}
public String[] getPlayerCountHoverLines() {
final String[] lines = new String[playerCountHoverLines.size()];
for (int i = 0; i < playerCountHoverLines.size(); i++) {
final Component component = plugin.replacePingVariables(playerCountHoverLines.get(i));
lines[i] = LegacyComponentSerializer.legacySection().serialize(component);
}
return lines;
}
public Component getKickMessage() {
return plugin.replacePingVariables(getMessage("kickmessage"));
}
public String getLanguage() {
return languageName;
}
public boolean hasCustomPlayerCountMessage() {
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 particular the motd list), as well as confusing for most users in general.
* Because of this, I replace <br> manually, to spare users from these ugly breaks (before I inevitably switch to a different configuration library).
*/
protected String replaceNewlineVar(final String s) {
return s.replace(NEW_LINE_REPLACEMENT, "\n");
}
protected void loadExtraSettings() {
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,33 +15,45 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
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;
private final boolean visible;
protected CommandInfo(final MaintenancePlugin plugin, final String permission, final String helpMessage) {
protected CommandInfo(final MaintenancePlugin plugin, @Nullable final String permission) {
this(plugin, permission, true);
}
protected CommandInfo(final MaintenancePlugin plugin, @Nullable final String permission, final boolean visible) {
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", "");
this.visible = visible;
}
public boolean hasPermission(final SenderInfo sender) {
return sender.hasMaintenancePermission(permission);
}
public String getHelpMessage() {
return helpMessage;
public boolean isVisible() {
return visible;
}
public Component getHelpMessage() {
return getMessage(helpMessageKey);
}
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
@@ -52,7 +64,7 @@ public abstract class CommandInfo {
protected boolean checkPermission(final SenderInfo sender, final String permission) {
if (!sender.hasMaintenancePermission(permission)) {
sender.sendMessage(getMessage("noPermission"));
sender.send(getMessage("noPermission"));
return true;
}
return false;
@@ -60,14 +72,14 @@ public abstract class CommandInfo {
protected boolean checkArgs(final SenderInfo sender, final String[] args, final int length) {
if (args.length != length) {
sender.sendMessage(helpMessage);
sender.send(getHelpMessage());
return true;
}
return false;
}
protected String getMessage(final String s) {
return plugin.getSettings().getMessage(s);
protected Component getMessage(final String path, final String... replacements) {
return plugin.getSettings().getMessage(path, replacements);
}
protected Settings getSettings() {
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,16 +15,34 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.command.subcommand.*;
import eu.kennytv.maintenance.core.command.subcommand.AbortTimerCommand;
import eu.kennytv.maintenance.core.command.subcommand.DebugCommand;
import eu.kennytv.maintenance.core.command.subcommand.DumpCommand;
import eu.kennytv.maintenance.core.command.subcommand.EndtimerCommand;
import eu.kennytv.maintenance.core.command.subcommand.HelpCommand;
import eu.kennytv.maintenance.core.command.subcommand.MotdCommand;
import eu.kennytv.maintenance.core.command.subcommand.ReloadCommand;
import eu.kennytv.maintenance.core.command.subcommand.RemoveMotdCommand;
import eu.kennytv.maintenance.core.command.subcommand.ScheduleTimerCommand;
import eu.kennytv.maintenance.core.command.subcommand.SetMotdCommand;
import eu.kennytv.maintenance.core.command.subcommand.StarttimerCommand;
import eu.kennytv.maintenance.core.command.subcommand.ToggleCommand;
import eu.kennytv.maintenance.core.command.subcommand.UpdateCommand;
import eu.kennytv.maintenance.core.command.subcommand.WhitelistAddCommand;
import eu.kennytv.maintenance.core.command.subcommand.WhitelistCommand;
import eu.kennytv.maintenance.core.command.subcommand.WhitelistRemoveCommand;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.core.util.ServerType;
import java.util.*;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public abstract class MaintenanceCommand {
protected final MaintenancePlugin plugin;
@@ -55,6 +73,7 @@ public abstract class MaintenanceCommand {
add(new UpdateCommand(plugin), "update", "forceupdate");
add(new DumpCommand(plugin), "dump");
add(new DebugCommand(plugin), "debug");
}
protected void add(final CommandInfo command, final String... aliases) {
@@ -66,7 +85,7 @@ public abstract class MaintenanceCommand {
public void execute(final SenderInfo sender, final String[] args) {
if (!sender.hasMaintenancePermission("command")) {
sender.sendMessage(settings.getMessage("noPermission"));
sender.send(settings.getMessage("noPermission"));
return;
}
if (args.length == 0) {
@@ -80,7 +99,7 @@ public abstract class MaintenanceCommand {
return;
}
if (!command.hasPermission(sender)) {
sender.sendMessage(settings.getMessage("noPermission"));
sender.send(settings.getMessage("noPermission"));
return;
}
@@ -90,8 +109,18 @@ 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();
final CommandInfo info = entry.getValue();
if (info.isVisible() && command.startsWith(s) && info.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();
}
@@ -100,18 +129,18 @@ public abstract class MaintenanceCommand {
if (!plugin.isNumeric(time)) return true;
if (taskCheck) {
if (plugin.isTaskRunning()) {
sender.sendMessage(settings.getMessage("timerAlreadyRunning"));
sender.send(settings.getMessage("timerAlreadyRunning"));
return true;
}
}
final int minutes = Integer.parseInt(time);
if (minutes > 40320) {
sender.sendMessage(settings.getMessage("timerTooLong"));
sender.send(settings.getMessage("timerTooLong"));
return true;
}
if (minutes < 1) {
sender.sendMessage("§8§o[KennyTV whispers to you] §7§oThink about running a timer for a negative amount of minutes. Doesn't work §lthat §7§owell.");
sender.sendMessage("§8§o[kennytv whispers to you] §7§oThink about running a timer for a negative amount of minutes. Doesn't work §lthat §7§owell.");
return true;
}
return false;
@@ -126,14 +155,20 @@ public abstract class MaintenanceCommand {
add(new StarttimerCommand(plugin), "starttimer", "start");
add(new EndtimerCommand(plugin), "endtimer", "end");
add(new ScheduleTimerCommand(plugin), "scheduletimer", "schedule");
add(new AbortTimerCommand(plugin), "aborttimer", "abort");
}
public void checkForUpdate(final SenderInfo sender) {
if (plugin.updateAvailable()) {
sender.sendMessage(plugin.getPrefix() + "§cNewest version available: §aVersion " + plugin.getNewestVersion() + "§c, you're on §a" + plugin.getVersion());
sender.sendMessage(plugin.getPrefix() + "§c§lWARNING: §cYou will have to restart the server to prevent further issues and to complete the update! If you can't do that, don't update!");
sendUpdateMessage(sender);
// Ore sad :(
if (plugin.getServerType() != ServerType.SPONGE) {
sender.sendMessage(plugin.getPrefix() + "§c§lWARNING: §cYou will have to restart the server to prevent further issues and to complete the update! If you can't do that, don't update!");
sendUpdateMessage(sender);
} else {
sender.sendMessage(plugin.getPrefix() + "§aDownload the latest version on the Ore plugin page: §bhttps://ore.spongepowered.org/KennyTV/Maintenance");
}
} else
sender.sendMessage(plugin.getPrefix() + "§aYou already have the latest version of the plugin!");
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
@@ -25,22 +24,22 @@ 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.send(getHelpMessage());
return;
}
if (!plugin.isTaskRunning()) {
sender.sendMessage(getMessage("timerNotRunning"));
sender.send(getMessage("timerNotRunning"));
return;
}
plugin.cancelTask();
sender.sendMessage(getMessage("timerCancelled"));
sender.send(getMessage("timerCancelled"));
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,29 +15,23 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
public final class MotdCommand extends CommandInfo {
public final class DebugCommand extends CommandInfo {
public MotdCommand(final MaintenancePlugin plugin) {
super(plugin, "motd", "§6/maintenance motd §7(Lists the currently set maintenance motds)");
public DebugCommand(final MaintenancePlugin plugin) {
super(plugin, "debug", false);
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (checkArgs(sender, args, 1)) return;
sender.sendMessage(getMessage("motdList"));
for (int i = 0; i < getSettings().getPingMessages().size(); i++) {
sender.sendMessage("§b" + (i + 1) + "§8§m---------");
for (final String motd : getSettings().getColoredString(getSettings().getPingMessages().get(i)).split("%NEWLINE%")) {
sender.sendMessage(motd);
}
}
sender.sendMessage("§8§m----------");
plugin.setDebug(!plugin.isDebug());
sender.sendMessage("Debug mode is now " + (plugin.isDebug() ? "enabled" : "disabled"));
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
@@ -28,7 +27,7 @@ public final class DumpCommand extends CommandInfo {
private long lastDump;
public DumpCommand(final MaintenancePlugin plugin) {
super(plugin, "dump", "§6/maintenance dump §7(Dumps some server information, used for bug reports)");
super(plugin, "dump");
}
@Override
@@ -44,15 +43,17 @@ public final class DumpCommand extends CommandInfo {
plugin.async(() -> {
final String key = plugin.pasteDump();
if (key == null) {
if (sender.isPlayer())
if (sender.isPlayer()) {
sender.sendMessage(plugin.getPrefix() + "§cCould not paste dump (see the console for details)");
}
return;
}
final String url = "https://hasteb.in/" + key;
final String url = "https://hastebin.com/" + key;
sender.sendMessage(plugin.getPrefix() + "§c" + url);
if (sender.isPlayer())
if (sender.isPlayer()) {
plugin.getCommandManager().sendDumpMessage(sender, url);
}
});
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,32 +15,33 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.concurrent.TimeUnit;
public final class 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.send(getHelpMessage());
return;
}
if (!plugin.isMaintenance()) {
sender.sendMessage(getMessage("alreadyDisabled"));
sender.send(getMessage("alreadyDisabled"));
return;
}
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), false);
sender.sendMessage(getMessage("endtimerStarted").replace("%TIME%", plugin.getRunnable().getTime()));
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), TimeUnit.MINUTES, false);
sender.send(getMessage("endtimerStarted", "%TIME%", plugin.getRunnable().getTime()));
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,42 +15,43 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import com.google.common.base.Preconditions;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import java.util.ArrayList;
import java.util.List;
import 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.send(getHelpMessage());
return;
}
if (args.length == 1) {
sendUsage(sender);
} else {
if (!plugin.isNumeric(args[1])) {
sender.sendMessage(helpMessage);
return;
}
final int page = Integer.parseInt(args[1]);
sendUsage(sender, page == 0 ? 1 : page);
return;
}
if (!plugin.isNumeric(args[1])) {
sender.send(getHelpMessage());
return;
}
final int page = Integer.parseInt(args[1]);
sendUsage(sender, page == 0 ? 1 : page);
}
public void sendUsage(final SenderInfo sender) {
@@ -59,28 +60,37 @@ 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<Component> commands = new ArrayList<>();
for (final CommandInfo cmd : plugin.getCommandManager().getCommands()) {
if (cmd.isVisible() && cmd.hasPermission(sender)) {
commands.add(cmd.getHelpMessage());
}
}
if ((page - 1) * COMMANDS_PER_PAGE >= commands.size()) {
sender.sendMessage(getMessage("helpPageNotFound"));
sender.send(getMessage("helpPageNotFound"));
return;
}
final List<String> filteredCommands;
if (page * COMMANDS_PER_PAGE >= commands.size())
filteredCommands = commands.subList((page - 1) * COMMANDS_PER_PAGE, commands.size());
else
filteredCommands = commands.subList((page - 1) * COMMANDS_PER_PAGE, page * COMMANDS_PER_PAGE);
final List<Component> filteredCommands = commands.subList((page - 1) * COMMANDS_PER_PAGE, Math.min(page * COMMANDS_PER_PAGE, commands.size()));
final String header = "§8========[ §eMaintenance" + plugin.getServerType() + " §8| §e" + page + "/" + ((commands.size() + getDivide(commands.size())) / COMMANDS_PER_PAGE) + " §8]========";
sender.sendMessage("");
sender.sendMessage(header);
filteredCommands.forEach(sender::sendMessage);
if (page * COMMANDS_PER_PAGE < commands.size())
sender.sendMessage("§7Use §b/maintenance help " + (page + 1) + " §7to get to the next help window.");
else
sender.sendMessage("§8× §eVersion " + plugin.getVersion() + " §7by §bKennyTV");
sender.sendMessage(header);
sender.sendMessage("");
final Component header = getMessage("helpHeader",
"%NAME%", "Maintenance" + plugin.getServerType(),
"%PAGE%", Integer.toString(page),
"%MAX%", Integer.toString((commands.size() + getDivide(commands.size())) / COMMANDS_PER_PAGE));
sender.send(Component.empty());
sender.send(header);
for (final Component command : filteredCommands) {
sender.send(command);
}
if (page * COMMANDS_PER_PAGE < commands.size()) {
sender.send(getMessage("helpNextPage", "%PAGE%", Integer.toString(page + 1)));
} else {
sender.sendMessage("§8× §eVersion " + plugin.getVersion() + " §7by §bkennytv");
}
sender.send(header);
sender.send(Component.empty());
}
private int getDivide(final int size) {
@@ -0,0 +1,70 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 kennytv (https://github.com/kennytv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.util.Collections;
import java.util.List;
public final class MotdCommand extends CommandInfo {
public MotdCommand(final MaintenancePlugin plugin) {
super(plugin, "motd");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (args.length == 1) {
sendList(sender, getSettings().getPingMessages());
} else if (args.length == 2 && args[1].equalsIgnoreCase("timer")) {
if (!getSettings().hasTimerSpecificPingMessages()) {
sender.send(getMessage("timerMotdDisabled"));
return;
}
sendList(sender, getSettings().getTimerSpecificPingMessages());
} else {
sender.send(getHelpMessage());
}
}
private void sendList(final SenderInfo sender, final List<Component> list) {
if (list == null || list.isEmpty()) {
sender.send(getMessage("motdListEmpty"));
return;
}
sender.send(getMessage("motdList"));
for (int i = 0; i < list.size(); i++) {
sender.sendMessage("§b" + (i + 1) + "§8§m---------");
sender.send(list.get(i));
}
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)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
@@ -25,13 +24,13 @@ 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
public void execute(final SenderInfo sender, final String[] args) {
if (checkArgs(sender, args, 1)) return;
getSettings().reloadConfigs();
sender.sendMessage(getMessage("reload"));
sender.send(getMessage("reload"));
}
}
@@ -0,0 +1,89 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 kennytv (https://github.com/kennytv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public final class RemoveMotdCommand extends CommandInfo {
public RemoveMotdCommand(final MaintenancePlugin plugin) {
super(plugin, "setmotd");
}
@Override
public void execute(final SenderInfo sender, String[] args) {
boolean timerPingMessages = false;
if (args.length == 3 && args[1].equalsIgnoreCase("timer")) {
if (!getSettings().hasTimerSpecificPingMessages()) {
sender.send(getMessage("timerMotdDisabled"));
return;
}
args = plugin.removeArrayIndex(args, 1);
timerPingMessages = true;
}
if (checkArgs(sender, args, 2)) return;
if (!plugin.isNumeric(args[1])) {
sender.send(getHelpMessage());
return;
}
final Settings settings = getSettings();
final List<String> pingMessages = settings.getConfig().getStringList(timerPingMessages ? "timerspecific-pingmessages" : "pingmessages");
if (pingMessages.size() < 2) {
sender.send(getMessage("removeMotdError"));
return;
}
final int index = Integer.parseInt(args[1]);
if (index == 0 || index > pingMessages.size()) {
sender.send(getMessage("setMotdIndexError",
"%MOTDS%", Integer.toString(pingMessages.size()),
"%NEWAMOUNT%", Integer.toString(pingMessages.size())));
return;
}
final List<Component> pingComponents = timerPingMessages ? settings.getTimerSpecificPingMessages() : settings.getPingMessages();
pingComponents.remove(index - 1);
pingMessages.remove(index - 1);
settings.getConfig().set(timerPingMessages ? "timerspecific-pingmessages" : "pingmessages", pingMessages);
settings.saveConfig();
sender.send(getMessage("removedMotd", "%INDEX%", args[1]));
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
if (args.length == 2 || (args.length == 3 && args[1].equalsIgnoreCase("timer"))) {
final int size = (args.length == 3 ? plugin.getSettings().getTimerSpecificPingMessages() : plugin.getSettings().getPingMessages()).size();
final List<String> list = new ArrayList<>(size);
for (int i = 1; i <= size; i++) {
list.add(Integer.toString(i));
}
return list;
}
return Collections.emptyList();
}
}
@@ -0,0 +1,48 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 kennytv (https://github.com/kennytv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.concurrent.TimeUnit;
public final class ScheduleTimerCommand extends CommandInfo {
public ScheduleTimerCommand(final MaintenancePlugin plugin) {
super(plugin, "timer");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (checkArgs(sender, args, 3)) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[1])
|| plugin.getCommandManager().checkTimerArgs(sender, args[2], false)) {
sender.send(getHelpMessage());
return;
}
if (plugin.isMaintenance()) {
sender.send(getMessage("alreadyEnabled"));
return;
}
plugin.scheduleMaintenanceRunnable(Integer.parseInt(args[1]), Integer.parseInt(args[2]), TimeUnit.MINUTES);
sender.send(getMessage("starttimerStarted", "%TIME%", plugin.getRunnable().getTime()));
}
}
@@ -0,0 +1,125 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 kennytv (https://github.com/kennytv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import eu.kennytv.maintenance.lib.kyori.adventure.text.minimessage.MiniMessage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static eu.kennytv.maintenance.core.Settings.NEW_LINE_REPLACEMENT;
public final class SetMotdCommand extends CommandInfo {
public SetMotdCommand(final MaintenancePlugin plugin) {
super(plugin, "setmotd");
}
@Override
public void execute(final SenderInfo sender, String[] args) {
boolean timerPingMessages = false;
if (args.length > 1 && args[1].equalsIgnoreCase("timer")) {
if (!getSettings().hasTimerSpecificPingMessages()) {
sender.send(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.send(getHelpMessage());
return;
}
final Settings settings = getSettings();
final List<Component> pingComponents = timerPingMessages ? settings.getTimerSpecificPingMessages() : settings.getPingMessages();
final List<String> pingMessages = settings.getConfig().getStringList(timerPingMessages ? "timerspecific-pingmessages" : "pingmessages");
final int index = Integer.parseInt(args[1]);
if (index == 0 || index > pingMessages.size() + 1) {
sender.send(getMessage("setMotdIndexError",
"%MOTDS%", Integer.toString(pingMessages.size()),
"%NEWAMOUNT%", Integer.toString(pingMessages.size() + 1)));
return;
}
if (!plugin.isNumeric(args[2])) {
sender.send(getMessage("setMotdLineError"));
return;
}
final int line = Integer.parseInt(args[2]);
if (line != 1 && line != 2) {
sender.send(getMessage("setMotdLineError"));
return;
}
final String message = String.join(" ", Arrays.copyOfRange(args, 3, args.length));
final String oldMessage = index > pingMessages.size() ? "" : pingMessages.get(index - 1);
final String newMessage;
if (line == 1) {
newMessage = oldMessage.contains(NEW_LINE_REPLACEMENT) ?
message + NEW_LINE_REPLACEMENT + oldMessage.split(NEW_LINE_REPLACEMENT, 2)[1] : message;
} else {
newMessage = oldMessage.contains(NEW_LINE_REPLACEMENT) ?
oldMessage.split(NEW_LINE_REPLACEMENT, 2)[0] + NEW_LINE_REPLACEMENT + message : oldMessage + NEW_LINE_REPLACEMENT + message;
}
// Replace component in config and the cached list
final Component component = MiniMessage.miniMessage().deserialize(newMessage.replace(NEW_LINE_REPLACEMENT, "\n"));
if (index > pingMessages.size()) {
pingMessages.add(newMessage);
pingComponents.add(component);
} else {
pingMessages.set(index - 1, newMessage);
pingComponents.set(index - 1, component);
}
settings.getConfig().set(timerPingMessages ? "timerspecific-pingmessages" : "pingmessages", pingMessages);
settings.saveConfig();
sender.send(settings.getMessage("setMotd",
"%LINE%", args[2],
"%INDEX%", args[1]).replaceText(builder -> builder.matchLiteral("%MOTD%").replacement(component)));
}
@Override
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 <= (timer ? getSettings().getTimerSpecificPingMessages() : getSettings().getPingMessages()).size() + 1; i++) {
list.add(String.valueOf(i));
}
return list;
}
return Collections.emptyList();
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,32 +15,33 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.concurrent.TimeUnit;
public final class 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.send(getHelpMessage());
return;
}
if (plugin.isMaintenance()) {
sender.sendMessage(getMessage("alreadyEnabled"));
sender.send(getMessage("alreadyEnabled"));
return;
}
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), true);
sender.sendMessage(getMessage("starttimerStarted").replace("%TIME%", plugin.getRunnable().getTime()));
plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), TimeUnit.MINUTES, true);
sender.send(getMessage("starttimerStarted", "%TIME%", plugin.getRunnable().getTime()));
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
@@ -25,7 +24,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
@@ -34,7 +33,7 @@ public final class ToggleCommand extends CommandInfo {
final boolean maintenance = args[0].equalsIgnoreCase("on");
if (maintenance == plugin.isMaintenance()) {
sender.sendMessage(getMessage(maintenance ? "alreadyEnabled" : "alreadyDisabled"));
sender.send(getMessage(maintenance ? "alreadyEnabled" : "alreadyDisabled"));
return;
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,17 +15,17 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.core.util.ServerType;
public final class UpdateCommand extends CommandInfo {
public UpdateCommand(final MaintenancePlugin plugin) {
super(plugin, "update", "§6/maintenance update §7(Remotely downloads the newest version of the plugin onto your server)");
super(plugin, "update");
}
@Override
@@ -38,12 +38,18 @@ public final class UpdateCommand extends CommandInfo {
sender.sendMessage(plugin.getPrefix() + "§aYou already have the latest version of the plugin!");
return;
}
// Ore very sad :(
if (plugin.getServerType() == ServerType.SPONGE) {
sender.sendMessage(plugin.getPrefix() + "§cSorry, automated downloading of the plugin is not supported on Sponge! Please download the latest version manually! :(");
return;
}
sender.sendMessage(getMessage("updateDownloading"));
if (plugin.installUpdate())
sender.sendMessage(getMessage("updateFinished"));
else
sender.sendMessage(getMessage("updateFailed"));
sender.send(getMessage("updateDownloading"));
if (plugin.installUpdate()) {
sender.send(getMessage("updateFinished"));
} else {
sender.send(getMessage("updateFailed"));
}
}
}
}
@@ -0,0 +1,95 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 kennytv (https://github.com/kennytv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.DummySenderInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
public final class WhitelistAddCommand extends CommandInfo {
public WhitelistAddCommand(final MaintenancePlugin plugin) {
super(plugin, "whitelist.add");
}
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (args.length == 2) {
if (args[1].length() == 36) {
final UUID uuid = plugin.checkUUID(sender, args[1]);
if (uuid != null) {
addPlayerToWhitelist(sender, uuid);
}
} else {
addPlayerToWhitelist(sender, args[1]);
}
} else if (args.length == 3) {
if (args[1].length() != 36) {
sender.send(getHelpMessage());
return;
}
final UUID uuid = plugin.checkUUID(sender, args[1]);
if (uuid != null) {
addPlayerToWhitelist(sender, new DummySenderInfo(uuid, args[2]));
}
} else {
sender.send(getHelpMessage());
}
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
return args.length == 2 ? plugin.getCommandManager().getPlayersCompletion() : Collections.emptyList();
}
private void addPlayerToWhitelist(final SenderInfo sender, final String name) {
plugin.getOfflinePlayer(name, selected -> {
if (selected == null) {
sender.send(getMessage("playerNotOnline"));
return;
}
addPlayerToWhitelist(sender, selected);
});
}
private void addPlayerToWhitelist(final SenderInfo sender, final UUID uuid) {
plugin.getOfflinePlayer(uuid, selected -> {
if (selected == null) {
sender.send(getMessage("playerNotFoundUuid"));
return;
}
addPlayerToWhitelist(sender, selected);
});
}
private void addPlayerToWhitelist(final SenderInfo sender, final SenderInfo selected) {
if (getSettings().addWhitelistedPlayer(selected.getUuid(), selected.getName())) {
sender.send(getMessage("whitelistAdded", "%PLAYER%", selected.getName()));
} else {
sender.send(getMessage("whitelistAlreadyAdded", "%PLAYER%", selected.getName()));
}
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,12 +15,12 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
import java.util.Map;
import java.util.UUID;
@@ -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
@@ -37,12 +37,17 @@ public final class WhitelistCommand extends CommandInfo {
final Map<UUID, String> players = getSettings().getWhitelistedPlayers();
if (players.isEmpty()) {
sender.sendMessage(getMessage("whitelistEmpty"));
} else {
sender.sendMessage(getMessage("whitelistedPlayers"));
final String format = getMessage("whitelistedPlayersFormat");
players.forEach((key, value) -> sender.sendMessage(format.replace("%NAME%", value).replace("%UUID%", key.toString())));
sender.sendMessage("");
sender.send(getMessage("whitelistEmpty"));
return;
}
sender.send(getMessage("whitelistedPlayers"));
final Component format = getMessage("whitelistedPlayersFormat");
for (final Map.Entry<UUID, String> entry : players.entrySet()) {
sender.send(format.replaceText(builder -> builder.matchLiteral("%NAME%").replacement(entry.getValue()))
.replaceText(builder -> builder.matchLiteral("%UUID%").replacement(entry.getKey().toString())));
}
sender.send(Component.empty());
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,22 +15,21 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.command.subcommand;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
public final class WhitelistRemoveCommand extends CommandInfo {
public WhitelistRemoveCommand(final MaintenancePlugin plugin) {
super(plugin, "whitelist.remove", "§6/maintenance remove <name/uuid> §7(Removes the player from the maintenance whitelist)");
super(plugin, "whitelist.remove");
}
@Override
@@ -38,43 +37,57 @@ public final class WhitelistRemoveCommand extends CommandInfo {
if (checkArgs(sender, args, 2)) return;
if (args[1].length() == 36) {
final UUID uuid = plugin.checkUUID(sender, args[1]);
if (uuid != null)
if (uuid != null) {
removePlayerFromWhitelist(sender, uuid);
} else
}
} else {
removePlayerFromWhitelist(sender, args[1]);
}
}
@Override
public List<String> getTabCompletion(final SenderInfo sender, final String[] args) {
return args.length == 2 ? getSettings().getWhitelistedPlayers().values().stream()
.filter(name -> name.toLowerCase().startsWith(args[1])).collect(Collectors.toList()) : Collections.emptyList();
if (args.length != 2) return Collections.emptyList();
final List<String> list = new ArrayList<>();
for (final String name : getSettings().getWhitelistedPlayers().values()) {
if (name.toLowerCase().startsWith(args[1])) {
list.add(name);
}
}
return list;
}
private void removePlayerFromWhitelist(final SenderInfo sender, final String name) {
final SenderInfo selected = plugin.getOfflinePlayer(name);
if (selected == null) {
if (getSettings().removeWhitelistedPlayer(name))
sender.sendMessage(getMessage("whitelistRemoved").replace("%PLAYER%", name));
else
sender.sendMessage(getMessage("whitelistNotFound"));
return;
}
plugin.getOfflinePlayer(name, selected -> {
if (selected == null) {
if (getSettings().removeWhitelistedPlayer(name)) {
sender.send(getMessage("whitelistRemoved", "%PLAYER%", name));
} else {
sender.send(getMessage("whitelistNotFound"));
}
return;
}
whitelistRemoveMessage(sender, selected.getUuid(), selected.getName());
removePlayerFromWhitelist(sender, selected.getUuid(), selected.getName());
});
}
private void removePlayerFromWhitelist(final SenderInfo sender, final UUID uuid) {
final SenderInfo selected = plugin.getOfflinePlayer(uuid);
if (selected == null)
whitelistRemoveMessage(sender, uuid, uuid.toString());
else
whitelistRemoveMessage(sender, selected.getUuid(), selected.getName());
plugin.getOfflinePlayer(uuid, selected -> {
if (selected == null) {
removePlayerFromWhitelist(sender, uuid, uuid.toString());
} else {
removePlayerFromWhitelist(sender, selected.getUuid(), selected.getName());
}
});
}
private void whitelistRemoveMessage(final SenderInfo sender, final UUID uuid, final String toReplace) {
if (getSettings().removeWhitelistedPlayer(uuid))
sender.sendMessage(getMessage("whitelistRemoved").replace("%PLAYER%", toReplace));
else
sender.sendMessage(getMessage("whitelistNotFound"));
private void removePlayerFromWhitelist(final SenderInfo sender, final UUID uuid, final String toReplace) {
if (getSettings().removeWhitelistedPlayer(uuid)) {
sender.send(getMessage("whitelistRemoved", "%PLAYER%", toReplace));
} else {
sender.send(getMessage("whitelistNotFound"));
}
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,9 +15,10 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.config;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.Nullable;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
@@ -25,27 +26,33 @@ 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).
*
* @author PSandro on 26.01.19
* @author KennyTV
* @author kennytv
*/
public final class Config extends ConfigSection {
private static final String AWESOME_HEADER =
"#######################################################################################################################\n" +
"# __ __ _ _ _ _ __ _______ __ #\n" +
"# | \\/ | __ _(_)_ __ | |_ ___ _ __ __ _ _ __ ___ ___ | |__ _ _ | |/ /___ _ __ _ __ _ |_ _\\ \\ / / #\n" +
"# | |\\/| |/ _` | | '_ \\| __/ _ \\ '_ \\ / _` | '_ \\ / __/ _ \\ | '_ \\| | | | | ' // _ \\ '_ \\| '_ \\| | | || | \\ \\ / / #\n" +
"# | | | | (_| | | | | | || __/ | | | (_| | | | | (_| __/ | |_) | |_| | | . \\ __/ | | | | | | |_| || | \\ V / #\n" +
"# |_| |_|\\__,_|_|_| |_|\\__\\___|_| |_|\\__,_|_| |_|\\___\\___| |_.__/ \\__, | |_|\\_\\___|_| |_|_| |_|\\__, ||_| \\_/ #\n" +
"# |___/ |___/ #\n" +
"#######################################################################################################################\n" +
"# You can report bugs here: https://github.com/KennyTV/Maintenance/issues\n" +
"# If you need any other help/support, you can also join my Discord server: https://discord.gg/vGCUzHq\n";
"###################################################################################################################\n" +
"# __ __ _ _ _ _ _ #\n" +
"# | \\/ | __ _(_)_ __ | |_ ___ _ __ __ _ _ __ ___ ___ | |__ _ _ | | _____ _ __ _ __ _ _| |___ __ #\n" +
"# | |\\/| |/ _` | | '_ \\| __/ _ \\ '_ \\ / _` | '_ \\ / __/ _ \\ | '_ \\| | | | | |/ / _ \\ '_ \\| '_ \\| | | | __\\ \\ / / #\n" +
"# | | | | (_| | | | | | || __/ | | | (_| | | | | (_| __/ | |_) | |_| | | < __/ | | | | | | |_| | |_ \\ V / #\n" +
"# |_| |_|\\__,_|_|_| |_|\\__\\___|_| |_|\\__,_|_| |_|\\___\\___| |_.__/ \\__, | |_|\\_\\___|_| |_|_| |_|\\__, |\\__| \\_/ #\n" +
"# |___/ |___/ #\n" +
"###################################################################################################################\n" +
"# You can report bugs here: https://github.com/kennytv/Maintenance/issues\n" +
"# If you need any other help/support, you can also join my Discord server: https://discord.gg/vGCUzHq\n" +
"# The config and language files use MiniMessage, NOT legacy text for input. Use https://webui.adventure.kyori.net/ to edit and preview the formatted text.\n" +
"# For a full list of formats and fancy examples of MiniMessage, see https://docs.adventure.kyori.net/minimessage/format.html\n";
private final Yaml yaml = createYaml();
private final File file;
private final Set<String> unsupportedFields;
@@ -53,8 +60,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 +70,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 +98,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 +141,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 +159,12 @@ public final class Config extends ConfigSection {
return unsupportedFields;
}
@Override
public Config getRoot() {
return this;
}
@Nullable
public String getHeader() {
return header;
}
@@ -168,5 +173,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);
}
}
@@ -0,0 +1,212 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 kennytv (https://github.com/kennytv)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.config;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Further modified version of the SimpleConfig project of PSandro (https://github.com/PSandro/SimpleConfig).
*
* @author kennytv
*/
public class ConfigSection {
protected final Config root;
protected final String currentPath;
protected Map<String, Object> values;
ConfigSection(final Config root, final String currentPath) {
this(root, currentPath, new HashMap<>());
}
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) 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 getObject(key, null);
}
@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 getObject(key) != null;
}
public void set(final String key, @Nullable final Object value) {
//TODO go deep if necessary
if (value == null) {
values.remove(key);
getRoot().getComments().remove(getFullKeyInPath(key));
} else {
values.put(key, value);
}
}
public void remove(final String key) {
set(key, null);
}
public Set<String> getKeys() {
return this.values.keySet();
}
public Map<String, Object> getValues() {
return this.values;
}
public boolean getBoolean(final String key) {
return getBoolean(key, false);
}
public boolean getBoolean(final String key, final boolean def) {
final Object o = getObject(key);
return o instanceof Boolean ? (boolean) o : def;
}
@Nullable
public String getString(final String key) {
return get(key);
}
@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) {
return getInt(key, 0);
}
public int getInt(final String key, final int def) {
final Object o = getObject(key);
return o instanceof Number ? ((Number) o).intValue() : def;
}
public double getDouble(final String key) {
return getDouble(key, 0D);
}
public double getDouble(final String key, final double 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);
}
@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);
}
@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)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.config;
import org.yaml.snakeyaml.Yaml;
@@ -30,68 +29,93 @@ import java.util.regex.Pattern;
* Further modified version of the SimpleConfig project of PSandro (https://github.com/PSandro/SimpleConfig).
*
* @author PSandro on 26.01.19
* @author KennyTV
* @author kennytv
*/
public final class ConfigSerializer {
private static final String[] EMPTY = new String[0];
private static final int INDENT_UNIT = 2;
private static final String PATH_SEPARATOR_STRING = ".";
private static final String PATH_SEPARATOR_QUOTED = Pattern.quote(PATH_SEPARATOR_STRING);
private static final int INDENT_UNIT = 2;
public static String serialize(final String header, final Map<String, Object> data, final Map<String, String[]> comments, final Yaml yaml) {
if (data.isEmpty()) return yaml.dump(null);
if (data.isEmpty()) {
return yaml.dump(null);
}
final String rawYaml = yaml.dump(data);
final StringBuilder fileData = new StringBuilder();
int currentIndents = 0;
int currentKeyIndents = 0;
String key = "";
for (final String line : rawYaml.split("\n")) {
if (line.isEmpty()) continue;
final int indent = getIndents(line);
final int indents = indent / INDENT_UNIT;
final String indentText = indent > 0 ? line.substring(0, indent) : "";
if (indents <= currentIndents) {
final boolean keyLine;
final String substring = line.substring(indent);
if (substring.trim().isEmpty() || substring.charAt(0) == '-') {
keyLine = false;
} else if (indents <= currentKeyIndents) {
final String[] array = key.split(PATH_SEPARATOR_QUOTED);
final int backspace = currentIndents - indents + 1;
final int backspace = currentKeyIndents - indents + 1;
key = join(array, array.length - backspace);
keyLine = true;
} else {
keyLine = line.indexOf(':') != -1;
}
final String separator = key.isEmpty() ? "" : PATH_SEPARATOR_STRING;
final String lineKey = line.contains(":") ? line.split(Pattern.quote(":"))[0] : line;
key += separator + lineKey.substring(indent);
if (!keyLine) {
// Nothing to do, go to next line
fileData.append(line).append('\n');
continue;
}
currentIndents = indents;
final String newKey = substring.split(Pattern.quote(":"))[0]; // Not sure about the quote thing, so I'll just keep it :aaa:
if (!key.isEmpty()) {
key += PATH_SEPARATOR_STRING;
}
key += newKey;
final String[] strings = comments.get(key);
if (strings != null) {
for (final String comment : strings) {
if (comment.isEmpty())
fileData.append('\n');
else
fileData.append(indentText).append(comment).append('\n');
// Add comments if present
if (comments != null) {
final String[] strings = comments.get(key);
if (strings != null) {
final String indentText = indent > 0 ? line.substring(0, indent) : "";
for (final String comment : strings) {
if (comment.isEmpty()) {
fileData.append('\n');
} else {
fileData.append(indentText).append(comment).append('\n');
}
}
}
}
currentKeyIndents = indents;
fileData.append(line).append('\n');
}
return header != null && !header.isEmpty() ? header + fileData : fileData.toString();
}
public static Map<String, String[]> deserializeComments(final String data) {
//TODO go through known yaml keys and figure out comments from there instead of from line to line?
// ... tho everything here would benefit from a cleanup
final Map<String, String[]> comments = new HashMap<>();
final List<String> currentComments = new ArrayList<>();
boolean header = true;
boolean multiLineValue = false;
int currentIndents = 0;
String key = "";
for (final String line : data.split("\n")) {
final String s = line.trim();
// It's a comment!
if (s.startsWith("#")) {
currentComments.add(s);
continue;
}
// Header is over - save it!
if (header) {
if (!currentComments.isEmpty()) {
currentComments.add("");
@@ -100,21 +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)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,10 +15,8 @@
* 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.dump;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
@@ -33,7 +31,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");
@@ -46,7 +44,7 @@ public final class MaintenanceDump {
configuration.put("icon-exists", new File(plugin.getDataFolder(), "maintenance-icon.png").exists());
final JsonObject jsonObject = new JsonObject();
jsonObject.add("plugins", new GsonBuilder().create().toJsonTree(plugin.getPlugins()));
jsonObject.add("plugins", MaintenancePlugin.GSON.toJsonTree(plugin.getPlugins()));
plugins = jsonObject;
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* 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.dump;
import java.util.List;
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,20 +15,19 @@
* 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.dump;
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,45 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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.MaintenanceEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class EventManager implements eu.kennytv.maintenance.api.event.manager.EventManager {
private final Map<String, List<EventListener>> listeners = new HashMap<>();
@Override
public void registerListener(final EventListener listener, final Class<? extends MaintenanceEvent> eventClass) {
listeners.computeIfAbsent(eventClass.getSimpleName(), s -> new ArrayList<>()).add(listener);
}
@Override
public void callEvent(final MaintenanceEvent event) {
final List<EventListener> list = listeners.get(event.getClass().getSimpleName());
if (list != null) {
for (final EventListener listener : list) {
listener.onEvent(event);
}
}
}
}
@@ -0,0 +1,53 @@
/*
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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.hook;
import eu.kennytv.maintenance.api.Maintenance;
import net.luckperms.api.LuckPermsProvider;
import net.luckperms.api.context.ContextCalculator;
import net.luckperms.api.context.ContextConsumer;
import net.luckperms.api.context.ContextSet;
import net.luckperms.api.context.ImmutableContextSet;
import org.jetbrains.annotations.NotNull;
public final class LuckPermsHook {
public static <T> void register(final Maintenance maintenance) {
LuckPermsProvider.get().getContextManager().registerCalculator(new MaintenanceCalculator<T>(maintenance));
}
public static final class MaintenanceCalculator<T> implements ContextCalculator<T> {
public static final String MAINTENANCE_KEY = "is-maintenance";
private final Maintenance maintenance;
private MaintenanceCalculator(final Maintenance maintenance) {
this.maintenance = maintenance;
}
@Override
public void calculate(@NotNull final T target, @NotNull final ContextConsumer consumer) {
consumer.accept(MAINTENANCE_KEY, Boolean.toString(maintenance.isMaintenance()));
}
@Override
public ContextSet estimatePotentialContexts() {
return ImmutableContextSet.builder().add(MAINTENANCE_KEY, "true").add(MAINTENANCE_KEY, "false").build();
}
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* 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.hook;
import net.minecrell.serverlistplus.core.ServerListPlusCore;
@@ -25,8 +24,9 @@ public final class ServerListPlusHook {
private final ServerListPlusCore serverListPlusCore;
public ServerListPlusHook(final Object serverListPlus) {
if (!(serverListPlus instanceof ServerListPlusPlugin))
if (!(serverListPlus instanceof ServerListPlusPlugin)) {
throw new IllegalArgumentException("Couldn't parse ServerListPlus instance!");
}
this.serverListPlusCore = ((ServerListPlusPlugin) serverListPlus).getCore();
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,7 +15,6 @@
* 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.listener;
import eu.kennytv.maintenance.core.MaintenancePlugin;
@@ -29,7 +28,6 @@ import java.util.UUID;
public abstract class JoinListenerBase {
protected final MaintenancePlugin plugin;
protected final Settings settings;
protected final UUID notifyUuid = new UUID(-6334418481592579467L, -4779835342378829761L);
private final Set<UUID> notifiedPlayers = new HashSet<>();
protected JoinListenerBase(final MaintenancePlugin plugin, final Settings settings) {
@@ -43,32 +41,27 @@ 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) {
if (sender.getUuid().equals(notifyUuid)) {
sender.sendMessage("§6Maintenance §aVersion " + plugin.getVersion());
return;
}
if (!settings.hasUpdateChecks()) return;
if (!sender.hasPermission("maintenance.admin") || notifiedPlayers.contains(sender.getUuid())) return;
plugin.async(() -> {
if (!plugin.updateAvailable()) return;
notifiedPlayers.add(sender.getUuid());
sender.sendMessage(plugin.getPrefix() + "§cThere is a newer version available: §aVersion " + plugin.getNewestVersion() + "§c, you're on §a" + plugin.getVersion());
plugin.sendUpdateNotification(sender);
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,16 +15,16 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.runnable;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
public final class MaintenanceRunnable extends MaintenanceRunnableBase {
public class MaintenanceRunnable extends MaintenanceRunnableBase {
public MaintenanceRunnable(final MaintenancePlugin plugin, final Settings settings, final int minutes, final boolean enable) {
super(plugin, settings, minutes, enable);
public MaintenanceRunnable(final MaintenancePlugin plugin, final Settings settings, final int seconds, final boolean enable) {
super(plugin, settings, seconds, enable);
}
@Override
@@ -33,12 +33,12 @@ public final class MaintenanceRunnable extends MaintenanceRunnableBase {
}
@Override
protected String startMessageKey() {
return settings.getMessage("starttimerBroadcast").replace("%TIME%", getTime());
protected Component getStartMessage() {
return settings.getMessage("starttimerBroadcast", "%TIME%", getTime());
}
@Override
protected String endMessageKey() {
return settings.getMessage("endtimerBroadcast").replace("%TIME%", getTime());
protected Component getEndMessage() {
return settings.getMessage("endtimerBroadcast", "%TIME%", getTime());
}
}
@@ -1,6 +1,6 @@
/*
* Maintenance - https://git.io/maintenancemode
* Copyright (C) 2018 KennyTV (https://github.com/KennyTV)
* This file is part of Maintenance - https://github.com/kennytv/Maintenance
* Copyright (C) 2018-2022 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
@@ -15,23 +15,26 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.kennytv.maintenance.core.runnable;
import eu.kennytv.maintenance.core.MaintenancePlugin;
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.util.Task;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;
public abstract class MaintenanceRunnableBase implements Runnable {
protected final MaintenancePlugin plugin;
protected final Settings settings;
protected final boolean enable;
private final Task task;
protected boolean enable;
protected int seconds;
protected MaintenanceRunnableBase(final MaintenancePlugin plugin, final Settings settings, final int minutes, final boolean enable) {
protected MaintenanceRunnableBase(final MaintenancePlugin plugin, final Settings settings, final int seconds, final boolean enable) {
this.plugin = plugin;
this.settings = settings;
this.seconds = minutes * 60;
this.seconds = seconds;
this.enable = enable;
this.task = plugin.startMaintenanceRunnable(this);
}
@Override
@@ -39,41 +42,35 @@ public abstract class MaintenanceRunnableBase implements Runnable {
if (seconds == 0) {
finish();
} else if (settings.getBroadcastIntervals().contains(seconds)) {
if (enable)
plugin.broadcast(startMessageKey());
else
plugin.broadcast(endMessageKey());
broadcast(enable ? getStartMessage() : getEndMessage());
}
seconds--;
}
public String getTime() {
final int preHours = this.seconds / 60;
final int minutes = preHours % 60;
final int seconds = this.seconds % 60;
final StringBuilder buider = new StringBuilder();
append(buider, "hour", preHours / 60);
append(buider, "minute", minutes);
append(buider, "second", seconds);
return buider.toString();
return plugin.getFormattedTime(seconds);
}
private void append(final StringBuilder builder, final String timeUnit, final int time) {
if (time == 0) return;
if (builder.length() != 0)
builder.append(" ");
builder.append(time).append(" ").append(settings.getMessage(time == 1 ? timeUnit : timeUnit + "s"));
public boolean shouldEnable() {
return enable;
}
public int getSecondsLeft() {
return seconds;
}
public Task getTask() {
return task;
}
protected void broadcast(final Component message) {
plugin.broadcast(message);
}
protected abstract void finish();
protected abstract String startMessageKey();
protected abstract Component getStartMessage();
protected abstract String endMessageKey();
protected abstract Component getEndMessage();
}
Loaded 100 of 202 files, more files were not shown because too many files have changed in this diff. Show more