Compare commits

...

296 Commits

Author SHA1 Message Date
ME1312 d1cb53e0f5
Reoptimize the recycle cleaners 2023-12-24 19:07:54 -05:00
ME1312 903b8a98d3
Optimize the recycle cleaners #87 2023-12-24 18:46:25 -05:00
ME1312 f7f42c8ba9
VanillaCord 2.0 2023-12-22 19:23:48 -05:00
ME1312 ad24b0deb3
Trigger reconnect sequence for linking errors, too 2023-08-12 00:07:05 -04:00
ME1312 78f50e77b2
#83 Fixes some template inheritance issues 2023-05-25 22:22:09 -04:00
ME1312 c511ded3d4
Remove duplicate plugins folder
If you have encountered this issue, know that the correct plugins folder is named `Plugins`.
2023-05-21 22:43:43 -04:00
ME1312 b5cddeb892
Fixes deserialization of UUIDs 2023-05-06 06:00:30 -04:00
ME1312 7d9fabd2b9
Fixes your assembly xml 2023-04-09 09:01:06 -04:00
ME1312 b23aa18661
Ensure folia is not required to compile against us 2023-04-09 05:29:41 -04:00
ME1312 ba80e0a16a
Folia scheduling support
Plugins that depend on SubServers.Client can make use of our platform-`AgnosticScheduler` to achieve the same results
2023-04-09 04:25:30 -04:00
ME1312 ecf76a97de
Reduced and updated dependancies
Also includes potential fixes for external host state desyncing
2023-04-07 22:47:16 -04:00
ME1312 01456fd964
Updated SubData 2023-02-22 17:50:02 -05:00
ME1312 c90dbc8e3f
Updated GalaxiEngine 2023-02-22 17:28:52 -05:00
ME1312 e02093ab2f
Updated dependancies 2023-02-22 16:36:40 -05:00
ME1312 8a5a0cdc4b
Fixes to ping adjustment for global player count 2023-01-10 00:57:31 -05:00
ME1312 cf07e86a09
Mirror the listeners field 2022-12-18 14:30:32 -05:00
ME1312 d8463e25c5
Fix the state of CTRL+C shutdowns 2022-11-12 22:40:43 -05:00
ME1312 cb6d30c882
Fix javadoc linking 2022-10-26 15:12:22 -04:00
ME1312 c5377f7f13
Make the status button clickable 2022-10-26 15:02:06 -04:00
ME1312 36f2821524
#80 Bring creation event handling up to spec 2022-08-17 13:18:44 -04:00
ME1312 41dd2d69d0
Add `subservers:input` for 1.19+
This is a simple plugin message channel that simulates chat spoofing.
2022-06-15 11:54:36 -04:00
ME1312 307ac43df0
Fix PacketExControlPlayer 2022-05-28 05:59:33 -04:00
ME1312 1521acfc51
Fix brief shutdown hang in SubServers.Client 2022-04-12 07:59:33 -04:00
ME1312 ce262c62f0
Fix potential NPE 2022-04-09 21:03:29 -04:00
ME1312 e4300e76e2
Make our bukkit events async
Also, #76 store signs in instance
2022-04-05 19:26:50 -04:00
ME1312 7d9de9bf6e
I'm done now i swear 2022-03-19 14:48:16 -04:00
ME1312 249b0a4fab
Yet more minor tweaks to signs 2022-03-19 13:14:22 -04:00
ME1312 6fc8732003
Revert to instance checking for signs 2022-03-19 12:25:19 -04:00
ME1312 b7c89d26d5
Minor sign efficiency upgrades 2022-03-18 17:16:29 -04:00
ME1312 a4d9f46084
Fix possible NPE 2022-03-18 12:30:54 -04:00
ME1312 58ae08db1e
Improved efficiency when accessing maps
Also, #75 Support for hosts, groups, and external servers on signs
2022-03-18 11:57:38 -04:00
ME1312 f6ce5c92fb
Update lang.yml 2022-03-17 01:42:17 -04:00
ME1312 7433fc04a8
#75 Added Server Signs 2022-03-17 00:18:34 -04:00
ME1312 5454590874
Minor sequence correction 2022-02-15 11:43:25 -05:00
ME1312 3e78536d08
Fix rogue detection for remote subservers 2022-02-15 11:36:07 -05:00
ME1312 8a18b6f5d1
Some minor fixes 2022-02-14 12:53:55 -05:00
ME1312 c5573801c4
Minor reference changes 2021-12-31 17:55:56 -05:00
ME1312 80d2557631
Update dependencies 2021-12-18 13:59:56 -05:00
ME1312 9999cbe39e
Update purpur build location 2021-12-06 03:41:26 -05:00
ME1312 6d457200fe
Remove individual packet versioning 2021-12-01 22:25:54 -05:00
ME1312 0c5a89608b
Update SubData 2021-12-01 22:20:42 -05:00
ME1312 7d9f4f86d3
Fix potential nullpo 2021-12-01 06:00:41 -05:00
ME1312 508c2f7627
Use the previous log level for ambiguous lines 2021-12-01 05:42:55 -05:00
ME1312 7179911d4c
Allow commands to be sent to external servers 2021-12-01 04:50:25 -05:00
ME1312 aef7a164e6
Update default templates 2021-11-30 23:55:50 -05:00
ME1312 a0b8df47ac
Update PacketExSyncPlayer 2021-11-24 04:52:39 -05:00
ME1312 c137906fcd
Update SubData 2021-10-25 01:12:06 -04:00
ME1312 92151d75d0
Update GalaxiEngine (again)
This update removes string unescaping from ObjectMap.

This will surely fix a ton of yet unfound bugs that exist from us simply picking the wrong method.
2021-10-24 14:53:15 -04:00
ME1312 86471491bd
Update GalaxiEngine
Only slight changes this time :)
2021-10-24 03:40:47 -04:00
ME1312 3e074e365d
Update GalaxiEngine
The changes this time are to some of GalaxiEngine's core utilities... which means it took a lot of work this time.
2021-10-24 00:14:07 -04:00
ME1312 16c373b336
Assign a short-hand for getting player data
/sub info u ME1312
2021-10-21 21:31:59 -04:00
ME1312 5d3664cbc7
Rebuild local RemotePlayer cache before reconnecting 2021-10-06 14:11:26 -04:00
ME1312 a3896eccd4
Update purpur download location 2021-09-28 02:40:19 -04:00
ME1312 594ba30c64
Update app launchers 2021-09-14 22:05:56 -04:00
ME1312 9bf1bb0710
Wait for response before marking a server as `registered` 2021-08-02 18:33:10 -04:00
ME1312 6890b94b16
Implement Java 9 process termination
Decided to finally use this now that people are updating their JDK versions.

We can never have too many ways to track down and terminate processes around here, can we?
2021-08-01 01:20:12 -04:00
ME1312 52fd155b5f
Efficient stats for nerds 2021-07-30 21:42:05 -04:00
ME1312 16b170df1e
Updated stats for nerds
Our bstats pages have been reorganised so you can have an easier time finding what you're looking for.

There's also a new versioning stat available for proxies. That'll be neat once we get some data.
2021-07-28 02:28:16 -04:00
ME1312 5263f9d018
Prevent `Directory` from being inherited 2021-07-26 16:50:03 -04:00
ME1312 ef1c593607
SubServers.Sync.Velocity #64 (Preview)
And automatic external server definitions
2021-07-09 01:46:10 -04:00
ME1312 394c4b238b
Add the delete command to SubServers.Client 2021-06-28 23:45:49 -04:00
ME1312 ee82ec32a3
Revert to `.zip` 2021-06-28 21:59:27 -04:00
ME1312 1427ff04e1
Use `tar.xz` for downloading templates 2021-06-28 16:34:49 -04:00
ME1312 d3f3f194d0
Update SubData 2021-06-26 17:24:30 -04:00
ME1312 668fccccfe
Update Dependencies 2021-06-26 16:54:04 -04:00
ME1312 a86571a136
Update README.md 2021-06-26 15:49:43 -04:00
ME1312 9c54dfd2b4
Yet another Forge template update 2021-06-26 03:29:23 -04:00
ME1312 81d2d8b14e
Better log handling & Forge-related fixes 2021-06-25 18:26:49 -04:00
ME1312 1533987bf5
Feature creep commit
This commit has 3 new features in it:
-> Internal Templates
-> The new Purpur Template
-> Changes to External Logging
2021-06-24 23:06:53 -04:00
ME1312 ff709ba314
Allow build scripts to reference a template's source files 2021-06-16 00:38:00 -04:00
ME1312 dfabbcf4ad
Add missing static methods to platform-specific api 2021-06-15 05:15:18 -04:00
ME1312 0a6fdb337f
Fix constructor overrides 2021-06-15 04:23:26 -04:00
ME1312 1fff679005
Fix multi-line JSON message parsing 2021-06-15 01:47:06 -04:00
ME1312 7d6396ec1c
Allow targeting multiple RemotePlayers 2021-06-15 00:09:51 -04:00
ME1312 517074f2b3
Remove some unnecessary conversions 2021-06-14 00:42:06 -04:00
ME1312 2c7175e558
Fix one of the new packets 2021-06-13 22:43:05 -04:00
ME1312 f5a3575e54
Remove duplicate maven plugin 2021-06-13 22:29:28 -04:00
ME1312 89f2d646a5
Update build workflow 2021-06-13 22:22:23 -04:00
ME1312 2a9c74f601
Add action methods to RemotePlayer 2021-06-13 21:31:59 -04:00
ME1312 910b504af8
Update SubServers.Console 2021-06-12 23:20:41 -04:00
ME1312 de0e9a676d
Remove some unused internal classes 2021-06-12 17:14:31 -04:00
ME1312 b6a66cfb3b
Shorten client's data folder name 2021-06-12 15:27:51 -04:00
ME1312 51e83f4fb0
Allow ungrouped servers to be listed 2021-06-11 18:16:05 -04:00
ME1312 34c9effa6f
The release version commit (maybe?) 2021-06-11 16:32:14 -04:00
ME1312 bb592da15b
Pre-render the animations 2021-06-07 14:53:21 -04:00
ME1312 f5c8ade961
Optimizations for Client UI 2021-06-07 03:22:57 -04:00
ME1312 b707f2cc0c
Fixes for Client UI 2021-06-06 17:01:28 -04:00
ME1312 ba6af4d66d
Reset servers to unregistered after removal 2021-06-06 02:59:50 -04:00
ME1312 ee59429e1d
Disallow starting unregistered servers 2021-06-06 02:02:27 -04:00
ME1312 b2b80036d7
Update GalaxiEngine 2021-06-06 01:33:24 -04:00
ME1312 4d081f6e4f
Don't fire edit events for temporary modifications 2021-06-06 01:28:22 -04:00
ME1312 e1de6636f0
Optimizations for developers 2021-06-05 22:44:33 -04:00
ME1312 42a73c8372
Update GalaxiEngine 2021-06-05 14:16:24 -04:00
ME1312 c6a354fe84
Fix shutdown detection 2021-04-23 00:36:54 -04:00
ME1312 6258256081
Minor API corrections to template swapping 2021-04-15 00:45:04 -04:00
ME1312 ce38355c91
Less debugging. 2021-04-14 13:42:51 -04:00
ME1312 d0177ce055
More debugging! 2021-04-13 17:35:06 -04:00
ME1312 5898371780
Add some debug messages 2021-04-13 17:32:41 -04:00
ME1312 0ac4238dc8
Remove unnecessary launch flags
This allows users on non-linux but unix-based systems to install ports of the `setsid` command that might not be feature complete.
2021-04-09 17:12:36 -04:00
ME1312 18953046b8
Shorten the Linux terminator
No need to overcomplicate things. Also, no risk of killing the entire program with this.
2021-04-08 10:44:41 -04:00
ME1312 ff82fd5151
Minor API efficiency improvements 2021-04-08 09:15:35 -04:00
ME1312 eba5e6a7d1
A better terminator for Linux
SubServers' child processes now get their very own Session ID in Linux.
2021-04-07 22:06:13 -04:00
ME1312 746c51e8fa
Update lang.yml 2021-04-03 23:59:51 -04:00
ME1312 23a434054f
Simplify teleportation permissions 2021-03-14 14:03:48 -04:00
ME1312 b188f0d4af
Add `subservers.request` 2021-03-14 09:20:24 -04:00
ME1312 a9b0afb40a
Let plebs use `/sub teleport`
There's still explicit permissions for this command, but granting `subservers.command` is no longer necessary.
2021-03-13 12:09:54 -05:00
ME1312 a992ec7c52
Better legacy API emulation 2021-03-13 11:51:32 -05:00
ME1312 620db38e9b
Corrections to legacy formatting 2021-03-08 12:02:28 -05:00
ME1312 1c010ea9b2
Change placeholder format
This is to make it compatible with PAPI bracket format.
2021-03-08 06:08:54 -05:00
ME1312 98e487b44e
Add placeholders for groups 2021-03-08 04:47:49 -05:00
ME1312 15a4f109a4
Clean up Executable class 2021-02-24 20:07:20 -05:00
ME1312 2beec3ae7a
Put lock in a more strategic location 2021-02-24 17:13:26 -05:00
ME1312 f90a54e636
Set running to TRUE while running start event 2021-02-24 17:09:25 -05:00
ME1312 59d3404abf
Update GalaxiEngine 2021-02-21 04:40:43 -05:00
ME1312 91fe4e74ed
Update GalaxiEngine 2021-02-18 03:31:20 -05:00
ME1312 811d65b68a
Secure the compatibility plugin
This commit moves the loadable section of the compatibility plugin to an anonymous class to prevent misuse of that section of code.
2021-02-15 00:28:06 -05:00
ME1312 5732237477
Update GalaxiEngine 2021-02-13 13:43:09 -05:00
ME1312 d244e6a5b7
Update GalaxiEngine 2021-02-13 02:29:36 -05:00
ME1312 2cb783326a
Update GalaxiEngine 2021-02-13 00:04:20 -05:00
ME1312 76e11f0a0d
Keep the console reader alive during shutdown 2021-02-07 03:09:39 -05:00
ME1312 4e66461848
Move autorun queue to a more appropriate location
This restores plugins' ability to listen for server start events
2021-02-07 01:19:55 -05:00
ME1312 3dea3b67d0
Rework SubServers.Bungee's app lifecycle
SubServers.Bungee now puts code in 2 new places to better load/unload it's data.

When supported, this should give it better compatabilty with ordanary plugins. Also, it no longer has to 'shutdown' to handle /greload. Isn't that neat?
2021-02-06 23:53:03 -05:00
ME1312 25fff82af6
Update SubData 2021-01-30 01:53:30 -05:00
ME1312 e090815b37
Revert something
This change I made a few commits ago is now unnecessary given the previous commit.
2021-01-29 19:23:58 -05:00
ME1312 b0340b498e
SubData API updates & usage optimizations 2021-01-29 19:06:23 -05:00
ME1312 6d32f1b6a0
Update SubData
Can you believe it?
2021-01-29 17:57:47 -05:00
ME1312 bfff48a9ec
Update SubData 2021-01-28 05:16:14 -05:00
ME1312 4debf94fd6
Update SubData 2021-01-28 01:36:08 -05:00
ME1312 2c29182ca5
Update GalaxiEngine 2021-01-22 23:56:43 -05:00
ME1312 9af8dd02ce
Update SubData 2021-01-21 14:28:23 -05:00
ME1312 ea9eec9aa8
Don't store temporary servers in servers.yml 2021-01-16 18:10:51 -05:00
ME1312 08b56fc823
Don't rewrite files with no placeholders 2020-12-20 22:30:33 -05:00
ME1312 fe4f19e713
Rewrite SmartFallback's Fallback process 2020-12-04 23:30:36 -05:00
ME1312 c261be2215
Don't remote reload SubData
It doesn't make any sense to be doing this...
2020-11-27 22:00:54 -05:00
ME1312 2841bdf061
Update SubData 2020-11-23 00:52:36 -05:00
ME1312 bcd7f4f3c3
Update SubData 2020-11-23 00:25:00 -05:00
ME1312 80da5f7b27
Fix host.getRemotePlayers() 2020-11-20 12:14:43 -05:00
ME1312 4ea69298a3
Optimize imports 2020-11-16 15:34:59 -05:00
ME1312 4cfe1b4285
Standardize RemotePlayer
This is the RemotePlayer API, not the GlobalPlayer API.
2020-11-14 13:12:08 -05:00
ME1312 20ab75530a
Update pom.xml 2020-11-14 02:15:41 -05:00
ME1312 8d21771857
Update GalaxiEngine 2020-11-14 02:07:25 -05:00
ME1312 c0197759f4
ClientCommon API 2020-11-14 00:29:29 -05:00
ME1312 34b406e3ae
BungeeCommon API 2020-11-13 22:41:56 -05:00
ME1312 96a3cf797e
Update SubData 2020-11-11 16:07:22 -05:00
ME1312 c62363bdef
Make the compatibility plugin loadable
Some BungeeCord API calls require an actual plugin object. This is a problem.

Fortunately, the 2020 builds of BungeeCord provide a protected constructor that is actually usable by SubServers, so we implemented it.
2020-11-11 02:35:02 -05:00
ME1312 489b25f48d
Update SubData 2020-11-07 11:35:25 -05:00
ME1312 0136419960
Override fallback servers when using `Reconnect` 2020-08-29 06:57:38 -04:00
ME1312 29dbd107c0
More debug options 2020-08-24 12:11:16 -04:00
ME1312 fa82e0ab96
More debug messages 2020-08-24 12:04:21 -04:00
ME1312 d3e6d3e579
Fix some issues with restore points in SubCreator 2020-08-22 22:11:05 -04:00
ME1312 6e60138a79
Add an error checking thread for player sync 2020-08-22 20:01:58 -04:00
ME1312 e9c0075144
Misc fixes regarding the last few commits 2020-08-21 18:33:09 -04:00
ME1312 fa77eeeab0
Allow a subserver's template to be changed 2020-08-19 21:15:55 -04:00
ME1312 443e3c2d44
Favor new connections over the old ones
This is a change to the rules that govern what happens when the same UUID connects to the same network more than once. It is now more BungeeCord like in nature.
2020-08-19 15:24:05 -04:00
ME1312 d43aae8486
Allow command overrides to be disabled seperately
This also leaves room for disabling overrides in other features in the future.
2020-08-18 20:03:59 -04:00
ME1312 b68fa0fec1
Remove some implementation redundancies 2020-08-16 14:30:36 -04:00
ME1312 26490dc140
Use single-threaded I/O for StopAction 2020-08-13 18:26:22 -04:00
ME1312 b18f047d53
Disallow the same UUID to make multiple connections to a multi-proxy network 2020-08-12 20:18:55 -04:00
ME1312 83041a1f3f
Allow SubProtocol to be extended 2020-08-11 20:28:34 -04:00
ME1312 efc12e0649
Fix possible player data desyncs 2020-07-25 05:43:42 -04:00
ME1312 891913dbe3
Ditch RedisBungee. Long live the RemotePlayer API
RedisBungee has been abandoned by it's developers. So we're abanding it too.

SubServers.Sync will now finally pick up the slack and sync basic player information between proxies over their SubData connection.
2020-07-25 01:20:59 -04:00
ME1312 f2f196dc79
Update GalaxiEngine 2020-07-24 14:25:40 -04:00
ME1312 fcc87117dd
Allow arguments & responses to call other methods/placeholders 2020-07-15 21:08:47 -04:00
ME1312 2975ab05f4
Update GalaxiEngine 2020-07-06 17:19:02 -04:00
ME1312 0d052e0774
Make `color` the default behavior for placeholders 2020-07-05 03:33:58 -04:00
ME1312 dacb3aa541
Allow custom responses for some placeholders 2020-07-05 02:13:58 -04:00
ME1312 5ad6b49de7
Update a server's placeholders upon a state change 2020-07-05 00:11:51 -04:00
ME1312 69fad5221c
Allow selecting the master proxy in placeholders 2020-07-04 23:31:58 -04:00
ME1312 1564eaaaf9
Add PAPI placeholders with SubServers.Client 2020-07-04 22:39:59 -04:00
ME1312 db8aff55f6
Allow plugins to modify the result of ping_passthrough 2020-07-03 20:23:27 -04:00
ME1312 ec2d75d0f6
Modify pings for DNS-Forward servers 2020-07-03 19:05:02 -04:00
ME1312 d76d0347e5
Add more features to Smart Fallback 2020-07-03 17:14:59 -04:00
ME1312 928c40addc
Use proper grammar for single items
Not possible for SubServers.Client since it uses global lang, but the mistake was less egregious in that case anyway.
2020-06-26 02:52:34 -04:00
ME1312 312d010585
Some more compatibility changes 2020-06-25 19:47:30 -04:00
ME1312 d8ea0cee66
Rework the SmartFallback API
There were a couple things in Smart Fallback that seemed short-sighted when it came to use by external plugins. Now you can:
-> Make decisions using player data (when available)
-> Assign partial points to a confidence score
2020-06-21 17:42:10 -04:00
ME1312 89856a19b8
Don't update templates that are lacking a `Version` property 2020-06-20 23:46:16 -04:00
ME1312 0812ff3ade
Properly set a default value for the `Replacements` option 2020-06-20 03:45:45 -04:00
ME1312 0e8bae4187
Re-Add local templates to SubServers.Host
Local templates are now stored in `/Templates`

Template cache files are still stored in `/Cache/Templates`

Remote templates are now stored in `/Cache/Remote/Templates`
2020-06-19 21:00:50 -04:00
ME1312 3fc249cf07
Add RegEx to File Selection 2020-06-13 23:23:06 -04:00
ME1312 9d01f46c16
SubCreator File Replacements
SubCreator has several new build options for updating and making replacements in files
2020-06-13 17:53:18 -04:00
ME1312 bb0dd55c95
#50 #46 Selecting Multiple Servers
This commit includes the following major changes and additions:
-> New Command & Permission Formatting
-> RemotePlayer API
-> SubData with Blocks
2020-06-12 01:45:49 -04:00
ME1312 caf8ee793d
Update GalaxiEngine 2020-02-17 19:07:26 -05:00
ME1312 65a5b7d0c9
Send actual data packet on ExCreator reload 2020-02-16 22:25:15 -05:00
ME1312 d2c7512257
Update ExternalSubServer.java 2020-02-16 20:43:52 -05:00
ME1312 4ba0489d9d
Bypass new Oracle argument restrictions 2020-02-16 15:01:17 -05:00
ME1312 bb975413a5
Update SubData 2020-02-12 11:10:22 -05:00
ME1312 207393cfec
Don't get confused by Manifest line splitting 2020-01-25 16:06:05 -05:00
ME1312 11f92f2559
Correct getServerInfo() on Waterfall 2020-01-25 13:30:16 -05:00
ME1312 7a4d28b113
Update BungeeCord
The official BungeeCord fork hit us with a surprise incompatibility recently. Yikes.
2020-01-18 00:13:10 -05:00
ME1312 d39d875e2b
Correct default lang.yml formatting 2019-12-18 21:52:15 -05:00
ME1312 eb8261531d
Update dependencies 2019-12-18 15:07:51 -05:00
ME1312 6e116763c1
Use the same java version for child processes 2019-12-18 14:15:02 -05:00
ME1312 51d3c31220
Add SubCreatedEvent 2019-12-18 02:49:40 -05:00
ME1312 73c402fc53
Add a default Paper template 2019-12-18 00:08:59 -05:00
ME1312 35c80bba80
Use the new .net URL structure 2019-12-11 21:01:28 -05:00
ME1312 611b59f2c8
Fix the reconnect timer 2019-10-19 16:38:44 -04:00
ME1312 bfcb076cfd
Update SubData 2019-10-18 18:24:58 -04:00
ME1312 b7639ae3dc
Add a placeholder for selecting the current server in commands 2019-10-18 13:23:02 -04:00
ME1312 a5c5a532a0
Don't attempt reconnect while shutting down 2019-09-26 12:41:04 -04:00
ME1312 27806b91f9
Update SubData 2019-09-24 15:56:22 -04:00
ME1312 17b63c1e6e
Allow client apps to startup without a SubData connection active
They won't be all that useful like that, but... ¯\_(ツ)_/¯
2019-08-31 13:26:37 -04:00
ME1312 bccbfb39c9
Add a grace period on rogue SubServer detection
Async subdata shenanigans made rogue SubServer detection a little inacurrate. Specifically in regards to the last commit.

This is the fix to that
2019-08-30 15:44:54 -04:00
ME1312 81d37b8b1e
Reduce dependance on SubServers.Bungee
SubServers.Host can now seamlessly reconnect to SubServers.Bungee, even if it's been restarted, without restarting uneffected servers.

Also, you can now shutdown SubServers.Bungee without turning off remote servers. Isn't that neat?
2019-08-29 20:01:52 -04:00
ME1312 3ff2459258
Allow custom formatting of server directories in SubCreator 2019-07-29 20:20:38 -04:00
ME1312 c6d611836c
Add display scaling to SubServers.Console 2019-07-02 00:11:10 -04:00
ME1312 0e19122d9c
Update pom.xml 2019-06-25 17:18:02 -04:00
ME1312 30dd28547f
Add a post-start event 2019-06-25 17:13:27 -04:00
ME1312 ecdc25b520
Update SubData 2019-06-23 23:06:28 -04:00
ME1312 9dedc3b90d
Update GalaxiEngine 2019-06-21 15:41:01 -04:00
ME1312 3af2087f19
Add a post-connect subdata event 2019-06-17 20:20:46 -04:00
ME1312 03ece299d3
Fix unnecessary .edit() of display names during reload 2019-06-17 19:30:30 -04:00
ME1312 be8f87d17c
Add the Update command
And several related UI changes to SubServers.Client
2019-06-16 23:13:48 -04:00
ME1312 96a0624b28
#45 Fix problematic exception handling 2019-05-31 15:20:17 -04:00
ME1312 071e0bceab
Update SubData 2019-05-27 15:33:52 -04:00
ME1312 08e3e202e3
Fix bug in first-time RSA setup 2019-05-25 18:53:23 -04:00
ME1312 49036b8943
Add support for console sudo in GalaxiBungee 2019-05-23 14:37:18 -04:00
ME1312 8514ea5c26
Use .setCancelServers() for fallbacks
This method (as far as I know) is exclusive to GalaxiBungee. The old method is still available as a fallback.
2019-05-23 13:03:14 -04:00
ME1312 b808a62fcb
Add support for GalaxiBungee 2019-05-16 18:36:41 -04:00
ME1312 463ae054a6
Merge branch 'master' into SubData-2 2019-05-13 22:10:43 -04:00
ME1312 185b6b84bb
Mirror changes in SubServers.Sync 2019-05-13 22:02:38 -04:00
ME1312 61ee89cfe3
Mirror changes in SubServers.Host 2019-05-12 23:28:27 -04:00
ME1312 9ef878ba12
Mirror changes in SubServers.Client.Sponge 2019-05-11 21:22:18 -04:00
ME1312 7059b5cad7
General Fixes & Module Updates 2019-05-11 17:23:31 -04:00
ME1312 2a939117ac
Fixes for Multi-Channel SubData 2019-05-10 00:04:10 -04:00
ME1312 504dc7bac4
Implement Multi-Channel SubData 2019-05-09 22:43:34 -04:00
ME1312 1952e7b940
Implement several new packet types 2019-05-09 16:17:15 -04:00
ME1312 4923b7111f
#41 Add `host` to the environment 2019-05-02 12:11:48 -04:00
ME1312 f8d597f513
#41 Add `host` to the environment 2019-05-02 12:10:01 -04:00
ME1312 776183510e
Config Updater & Smart Fallback Update 2019-04-29 11:05:06 -04:00
ME1312 472c83f975
Add proper 1.14 support 2019-04-26 14:03:00 -04:00
ME1312 df029e3a7e
Add proper 1.14 support 2019-04-25 23:40:02 -04:00
ME1312 7f23668623
Clean the Recently Deleted directory periodically 2019-04-25 23:24:10 -04:00
ME1312 2c41c40213
Move encryption keys to a variable 2019-04-19 11:46:39 -04:00
ME1312 09c8c4665b
Change potential version numbers 2019-04-19 11:14:57 -04:00
ME1312 6debb5b605
Update for the Sponge Web API
The sponge dependencies now use two formats. This is adds support for the new one.
2019-04-18 10:10:00 -04:00
ME1312 3dab84c0eb
Begin rewrite for SubData 2 2019-04-18 10:02:09 -04:00
ME1312 463861744c
Stop Ingame-Access from disallowing console access 2019-04-01 22:13:43 -04:00
ME1312 935a59bb34
Ignore servers not running in the confidence score 2019-03-23 19:51:40 -04:00
ME1312 afa34f4993
Add warnings for connecting to known offline servers #39 2019-02-27 14:05:05 -05:00
ME1312 d81e93b583
Only launch the auto-starter thread when needed 2019-01-29 22:32:28 -05:00
ME1312 2bf26a1b74
Give the new option a more fitting name 2019-01-29 22:23:21 -05:00
ME1312 6131790245
Add an option to space out auto-starting servers 2019-01-29 22:05:59 -05:00
ME1312 024dde444c
Update client auto-linking 2019-01-26 21:04:53 -05:00
ME1312 975a12f3b6
#36 Init SubServers.Console before SubAPI 2019-01-23 12:27:34 -05:00
ME1312 7158e0a3da
Fix SubData's log stream 2019-01-22 12:48:47 -05:00
ME1312 361acf7b17
Add a dedicated restart packet
I don't reccommend using this packet over the start & stop combination because of the lack of feedback you get in comparision.

However, if the server sending the packet is requesting to restart itself then this is your only option, so that's why it's here.
2019-01-20 17:49:12 -05:00
ME1312 cd5bdbaa35
Add tab completes for console-only commands 2019-01-17 14:20:13 -05:00
ME1312 36c33b3bc0
Move logging options to seperate static variables 2019-01-17 13:12:32 -05:00
ME1312 fcde0bc845
Add Version support to YAMLConfig 2019-01-17 12:44:47 -05:00
ME1312 8b77434ccf
#35 Add `address` variable to creator/server executable 2019-01-17 11:02:56 -05:00
ME1312 75a872252f
#35 Add command line variables to SubServers
Also, a fix for #34
2019-01-17 10:39:15 -05:00
ME1312 b88facf7f3
#33 Use non-player check instead of console-only one 2019-01-15 14:53:44 -05:00
ME1312 118ac28e4c
Don't follow symlinks for directory copies 2019-01-14 18:47:43 -05:00
ME1312 622ef32b4e
#32 Update the utility class 2019-01-14 18:28:18 -05:00
ME1312 df159f72fe
Allow different interpreters for SubCreator build scripts 2019-01-14 11:02:17 -05:00
ME1312 9b01aebd87
#31 Add environment variables to SubCreator scripts 2019-01-13 19:52:44 -05:00
ME1312 6218b873ca
Expand on the API for restricted servers 2019-01-10 15:52:38 -05:00
ME1312 16480af130
Include dependency version in file name 2019-01-09 17:00:17 -05:00
ME1312 651c61312e
Make JNA dependency optional 2019-01-09 16:41:37 -05:00
ME1312 abaa2f3a0e
Add PID termination in Java 8
Some trickery was applied, but its okay since Java 9 has proper API methods for this stuff anyway
2019-01-09 12:37:02 -05:00
ME1312 0d46c5b604
Add a restart command 2019-01-07 16:09:20 -05:00
ME1312 06898964ce
Rewrite the SubServers.Console commands 2019-01-06 20:32:53 -05:00
ME1312 3635fea2f5
Update SubServers.Console 2019-01-06 15:58:15 -05:00
ME1312 94a95de495
Name SubServers threads
This change does not apply to SubServers.Client because those apps use the platform's native scheduler instead of threads
2019-01-06 01:58:13 -05:00
ME1312 4792e5f8b1
Make `Log-Creator` a per-host option 2019-01-05 16:04:45 -05:00
ME1312 eb70ebaeea
Revise logging GC strategy 2019-01-04 23:35:20 -05:00
ME1312 9cb499c4ec
Properly terminate child processes on windows
This applies to both SubCreator and SubServers. Only works on Java 9+ because Java 8 lacks a way to get the PIDs.
2019-01-04 18:32:01 -05:00
ME1312 1845e9d8f9
Remove the archaic Executable type
Since it was virually no different from one, this has been replaced by a String.

Additionally, the interpreter for start scripts can now be changed from cmd.exe to git bash on windows systems by using the `bash` or `sh` commands.
2019-01-04 16:51:58 -05:00
ME1312 eafacf75c3
#29 Wrap caching directory in proper quotes 2019-01-04 00:35:56 -05:00
ME1312 4d1d266807
Attempt to free up ram usage after every ~4000 log lines 2019-01-03 00:48:15 -05:00
ME1312 c05f5131b5
Remove logger history 2019-01-02 13:46:10 -05:00
ME1312 069ecc1948
Fix template compilation 2018-12-21 16:44:40 -05:00
ME1312 e9e9f19d22
Update GalaxiEngine 2018-12-17 18:49:32 -05:00
ME1312 82dcc68023
Fix an IllegalStateException related to restricted servers 2018-12-02 12:58:56 -05:00
ME1312 4e58e01ec4
Correct BungeeCord repo imports 2018-11-29 19:42:12 -05:00
ME1312 dc63284781
Update GalaxiEngine 2018-11-22 17:55:23 -05:00
ME1312 52ebd6b903
Reverse EventPriority for user input 2018-11-22 10:36:10 -05:00
ME1312 a12ff22645
Correct value replacement for server.properties 2018-11-21 17:33:52 -05:00
ME1312 d877e80b9f
Correct default access rules for restricted servers 2018-11-21 16:52:03 -05:00
ME1312 4ca476c1fa
Correct LinkServer packets & server autodetection 2018-11-19 12:27:06 -05:00
ME1312 32cd201697
Allow null to be passed to YAMLValue 2018-11-17 12:39:37 -05:00
ME1312 e254d37a30
Interrupt other stream when one closes 2018-11-02 19:48:46 -04:00
ME1312 114f4f2209
Add support for unicode escapes outside of the char limit 2018-10-30 15:12:53 -04:00
ME1312 b2bbff0692
Add autocompletes to Galaxi commands
Commands here use cached data, in a simalar fasion to SubServers.Sync.
2018-10-25 16:47:44 -04:00
ME1312 f4a78fc7b0
Update SubServers.Console 2018-10-24 01:37:55 -04:00
ME1312 dfa37c9022
Fix compatibility with the UI Designer & Maven 2018-10-22 22:06:25 -04:00
ME1312 6925a7bccb
Fix version inconsistency 2018-10-22 20:06:39 -04:00
ME1312 2936747df6
Update GalaxiEngine 2018-10-22 19:36:18 -04:00
ME1312 207eca411e
Use the Sponge DownloadAPI instead of Maven for version searching 2018-10-22 19:25:42 -04:00
ME1312 d3ea124351
Fix tab completes for commands using the /sub alias 2018-10-21 00:46:14 -04:00
ME1312 648adeb1c2
Update GalaxiEngine 2018-10-21 00:18:40 -04:00
ME1312 3b9b4ac566
Fix for saving unicode characters in YAML 2018-10-18 15:38:00 -04:00
ME1312 a9f5c387cc
Fix consistency issues in /sub version
The version command looks a little different in SubServers.Host. Let's fix that.
2018-10-17 23:17:23 -04:00
ME1312 52c6da2517
Choose fallback based on confidence score
The fallback server chosen when a server goes down is now chosen based on SubServers' confidence that the server can recieve the player in question.

If there is a tie, the first server to achieve a high score is chosen. Servers meeting these requirements will get the highest score currently possible:
-> Fallback servers should not be white-listed (`Restricted: false`)
-> Fallback servers should be visible (`Hidden: false`)
-> Fallback subservers should be running
-> SubServers trusts that fallback servers connected to SubData are online
2018-10-14 03:26:23 -04:00
ME1312 ba2a69a568
Make the port argument optional
Not sure what port to use? Now SubServers can decide on a port number on it's own.
2018-10-08 17:07:44 -04:00
ME1312 3911b6e867
Add UPnP Forwarding Option 2018-10-07 19:25:08 -04:00
604 changed files with 42925 additions and 38615 deletions

63
.gitattributes vendored
View File

@ -1,63 +0,0 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

View File

@ -11,7 +11,7 @@ Paste in the version information from the SubServers app in question here. To ge
Here you can write about what happened that shouldn't have. If you have any errors in your console related to what happened, you should also paste those here.
### How It Happened
Tell us step-by-step how to recreate the problem. This step is vital for us to determine whether or not the problem happens to everyone else too.
Tell us step-by-step how to recreate the problem. This step is vital for us to determine whether the problem happens to everyone else too.
### Additional Information
Here you can provide any extra details you may think useful for solving the problem.

60
.gitignore vendored
View File

@ -1,47 +1,17 @@
# SubServers 2 Ignored Files
*.iml
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
*.userprefs
## Directory-based project format:
.idea/
## File-based project format:
*.ipr
*.iws
# IntelliJ
# Hide System and IDE Generated Files
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
# Hide Unfinished Project Files
/SubServers.Client/Windows/
/Artifacts/SubServers.Web.jar
/SubServers.Web/
# Hide Others
/Artifacts/-Maven/
/Artifacts/-History/
/Artifacts/-Icon/
/Artifacts/*.jar
/Javadoc/
/SubServers.Test/
/build.ant
/build.log
.idea/
*.iml
.DS_STORE
# Hide Unfinished Projects
/SubServers.Test/
# Hide Compiled Artifacts
/Artifacts/*
/BungeeCord/
/Javadoc/
# Show Interpreted Artifacts
!/Artifacts/Download/
!/Artifacts/SubServers.Patcher.sh

View File

@ -321,14 +321,14 @@
switch (a.attr("href").toLowerCase()) {
case "%adfly_app_download%":
if (hash.hasOwnProperty("build")) {
a.attr("href", "https://adf.ly/18562515/https://src.me1312.net/maven/net/ME1312/SubServers/" + hash.app.replace(/^(.+?)\.([^.]*)$/, '$1') + "/" + hash.build + "/" + hash.app.replace(/^(.+?)\.([^.]*)$/, '$1') + "-" + hash.build + ".jar");
a.attr("href", "https://adf.ly/18562515/https://dev.me1312.net/maven/net/ME1312/SubServers/" + hash.app.replace(/^(.+?)\.([^.]*)$/, '$1') + "/" + hash.build + "/" + hash.app.replace(/^(.+?)\.([^.]*)$/, '$1') + "-" + hash.build + ".jar");
} else {
a.attr("href", "https://adf.ly/18562515/https://raw.githubusercontent.com/ME1312/SubServers-2/" + hash.commit.toLowerCase() + "/Artifacts/" + hash.app);
}
break;
case "%app_download%":
if (hash.hasOwnProperty("build")) {
a.attr("href", "https://src.me1312.net/maven/net/ME1312/SubServers/" + hash.app.replace(/^(.+?)\.([^.]*)$/, '$1') + "/" + hash.build + "/" + hash.app.replace(/^(.+?)\.([^.]*)$/, '$1') + "-" + hash.build + ".jar");
a.attr("href", "https://dev.me1312.net/maven/net/ME1312/SubServers/" + hash.app.replace(/^(.+?)\.([^.]*)$/, '$1') + "/" + hash.build + "/" + hash.app.replace(/^(.+?)\.([^.]*)$/, '$1') + "-" + hash.build + ".jar");
} else {
a.attr("href", "https://raw.githubusercontent.com/ME1312/SubServers-2/" + hash.commit.toLowerCase() + "/Artifacts/" + hash.app);
}

View File

@ -5,7 +5,7 @@
# -> BungeeCord and SubServers.Sync
# -> GalaxiEngine and SubServers.Host
#
# Usage: "bash SubServers.Bungee.Patcher.sh <Platform.jar> <SubServers.jar>"
# Usage: "bash SubServers.Patcher.sh <Platform.jar> <SubServers.jar>"
#
#!/usr/bin/env bash
if [ -z "$1" ]
@ -52,7 +52,7 @@ if [ $__RETURN -eq 0 ]
rm -Rf LICENSE
fi
if [ -f "META-INF/MANIFEST.MF" ]; then
cat META-INF/MANIFEST.MF | sed -e "/^\s*$/d" -e "/^Main-Class:.*$/d" -e "/^Implementation-Title:.*$/d" -e "/^Specification-Title:.*$/d" -e "/^Build-Jdk:.*$/d" -e "/^Created-By:.*$/d" -e "/^Built-By:.*$/d" > ../MANIFEST.MF
cat META-INF/MANIFEST.MF | sed 's/\r$//' | sed ':a;N;$!ba;s/\n //g' | sed -e "/^\s*$/d" -e "/^Main-Class:.*$/d" -e "/^Implementation-Title:.*$/d" -e "/^Specification-Title:.*$/d" -e "/^Build-Jdk:.*$/d" -e "/^Created-By:.*$/d" -e "/^Built-By:.*$/d" > ../MANIFEST.MF
else
printf "Manifest-Version: 1.0\n" > ../MANIFEST.MF
fi
@ -67,8 +67,8 @@ if [ $__RETURN -eq 0 ]
then
echo ">> Writing Changes..."
if [ -f "META-INF/MANIFEST.MF" ]
then
cat META-INF/MANIFEST.MF | sed -e "/^\s*$/d" -e "/^Manifest-Version:.*$/d" -e "/^Class-Path:.*$/d" -e "/^Build-Jdk:.*$/d" -e "/^Created-By:.*$/d" -e "/^Built-By:.*$/d" >> ../MANIFEST.MF
then # (Read File) (Convert to LF) (Rejoin Split Lines) (Omit Empty, Duplicate, and Unnecessary Properties)
cat META-INF/MANIFEST.MF | sed 's/\r$//' | sed ':a;N;$!ba;s/\n //g' | sed -e "/^\s*$/d" -e "/^Manifest-Version:.*$/d" -e "/^Class-Path:.*$/d" -e "/^Build-Jdk:.*$/d" -e "/^Created-By:.*$/d" -e "/^Built-By:.*$/d" >> ../MANIFEST.MF
else
if [ ! -d "META-INF" ]; then
mkdir META-INF
@ -79,13 +79,13 @@ if [ $__RETURN -eq 0 ]
fi
yes | cp -rf . ../Patched.jar
cd ../
printf "Built-By: SubServers.Bungee.Patcher\n" >> MANIFEST.MF
printf "Built-By: SubServers.Patcher\n" >> MANIFEST.MF
cp -f MANIFEST.MF Patched.jar/META-INF
if [ -f "Patched.jar/bungee.yml" ]; then
rm -Rf Patched.jar/bungee.yml
fi
if [ ! -f "MODIFICATIONS" ]; then
printf "# SubServers.Bungee.Patcher generated difference list (may be empty if git is not installed)\n#\n" > MODIFICATIONS
printf "# SubServers.Patcher generated difference list (may be empty if git is not installed)\n#\n" > MODIFICATIONS
fi
printf "@ `date`\n> git --no-pager diff --no-index --name-status SubServers.Patcher/Original.jar SubServers.Patcher/Patched.jar\n" >> MODIFICATIONS
git --no-pager diff --no-index --name-status Original.jar Patched.jar | sed -e "s/\tOriginal.jar\//\t\//" -e "s/\tPatched.jar\//\t\//" >> MODIFICATIONS

View File

@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2017 ME1312
Copyright (C) 2015-2023 ME1312
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
# ![https://s3.postimg.cc/dikyxlz5v/Sub_Banner.png](https://s3.postimg.cc/dikyxlz5v/Sub_Banner.png)
[![Build Status](https://src.me1312.net/jenkins/job/SubServers%20Platform/badge/icon)](https://src.me1312.net/jenkins/job/SubServers%20Platform/)
[![Release Verison](https://img.shields.io/github/release/ME1312/SubServers-2/all.svg)](https://github.com/ME1312/SubServers-2/releases) [![Snapshot Verison](https://img.shields.io/badge/dynamic/xml.svg?label=snapshot&url=https%3A%2F%2Fsrc.me1312.net%2Fmaven%2Fnet%2FME1312%2FSubServers%2FSubServers.Bungee%2Fmaven-metadata.xml&query=%2F%2Fversioning%2Frelease&colorB=blue)](https://src.me1312.net/jenkins/job/SubServers%20Platform/) [![Discord](https://img.shields.io/discord/307936188134850560.svg)](https://discord.gg/gKWpT2K)<br><br>
[![Build Status](https://dev.me1312.net/jenkins/job/SubServers%20Platform/badge/icon)](https://dev.me1312.net/jenkins/job/SubServers%20Platform/)
[![Release Verison](https://img.shields.io/github/release/ME1312/SubServers-2/all.svg)](https://github.com/ME1312/SubServers-2/releases) [![Snapshot Verison](https://img.shields.io/badge/dynamic/xml.svg?label=snapshot&url=https%3A%2F%2Fdev.me1312.net%2Fmaven%2Fnet%2FME1312%2FSubServers%2FSubServers.Bungee%2Fmaven-metadata.xml&query=%2F%2Fversioning%2Frelease&colorB=blue)](https://dev.me1312.net/jenkins/job/SubServers%20Platform/) [![Discord](https://img.shields.io/discord/526520424880930867.svg)](https://discord.gg/zWupnVn)<br><br>
SubServers 2 is a rewrite of SubServers, the Server Management Platform.<br>
> [https://www.spigotmc.org/resources/subservers-bungee.11264/](https://www.spigotmc.org/resources/subservers-bungee.11264/)<br>
> [https://www.spigotmc.org/resources/subservers-host.38833/](https://www.spigotmc.org/resources/subservers-host.38833/)<br>
@ -12,21 +12,26 @@ SubServers 2 is a rewrite of SubServers, the Server Management Platform.<br>
These are some quick links for common resources of SubServers 2.
### How to Install
> [https://github.com/ME1312/SubServers-2/wiki/Install](https://github.com/ME1312/SubServers-2/wiki/Install)
> [https://github.com/ME1312/SubServers-2/wiki/Install](https://github.com/ME1312/SubServers-2/wiki/Installation)
### Snapshot Downloads
> [https://src.me1312.net/jenkins/job/SubServers Platform](https://src.me1312.net/jenkins/job/SubServers%20Platform)
> [https://dev.me1312.net/jenkins/job/SubServers Platform](https://dev.me1312.net/jenkins/job/SubServers%20Platform)
### Javadocs for Developers
> [https://src.me1312.net/jenkins/job/SubServers Platform/javadoc/SubServers.Bungee/](https://src.me1312.net/jenkins/job/SubServers%20Platform/javadoc/SubServers.Bungee/)<br>
> [https://src.me1312.net/jenkins/job/SubServers Platform/javadoc/SubServers.Host/](https://src.me1312.net/jenkins/job/SubServers%20Platform/javadoc/SubServers.Host/)<br>
> [https://src.me1312.net/jenkins/job/SubServers Platform/javadoc/SubServers.Sync/](https://src.me1312.net/jenkins/job/SubServers%20Platform/javadoc/SubServers.Sync/)<br>
> [https://src.me1312.net/jenkins/job/SubServers Platform/javadoc/SubServers.Client.Bukkit/](https://src.me1312.net/jenkins/job/SubServers%20Platform/javadoc/SubServers.Client.Bukkit/)<br>
> [https://src.me1312.net/jenkins/job/SubServers Platform/javadoc/SubServers.Client.Sponge/](https://src.me1312.net/jenkins/job/SubServers%20Platform/javadoc/SubServers.Client.Sponge/)
> [https://dev.me1312.net/jenkins/job/SubServers Platform/javadoc/SubServers.Bungee](https://dev.me1312.net/jenkins/job/SubServers%20Platform/javadoc/SubServers.Bungee)<br>
> [https://dev.me1312.net/jenkins/job/SubServers Platform/javadoc/SubServers.Bungee.Common](https://dev.me1312.net/jenkins/job/SubServers%20Platform/javadoc/SubServers.Bungee.Common)<br>
> [https://dev.me1312.net/jenkins/job/SubServers Platform/javadoc/SubServers.Host](https://dev.me1312.net/jenkins/job/SubServers%20Platform/javadoc/SubServers.Host)<br>
> [https://dev.me1312.net/jenkins/job/SubServers Platform/javadoc/SubServers.Sync](https://dev.me1312.net/jenkins/job/SubServers%20Platform/javadoc/SubServers.Sync)<br>
> [https://dev.me1312.net/jenkins/job/SubServers Platform/javadoc/SubServers.Sync.Velocity](https://dev.me1312.net/jenkins/job/SubServers%20Platform/javadoc/SubServers.Sync.Velocity)<br>
> [https://dev.me1312.net/jenkins/job/SubServers Platform/javadoc/SubServers.Client.Bukkit](https://dev.me1312.net/jenkins/job/SubServers%20Platform/javadoc/SubServers.Client.Bukkit)<br>
> [https://dev.me1312.net/jenkins/job/SubServers Platform/javadoc/SubServers.Client.Common](https://dev.me1312.net/jenkins/job/SubServers%20Platform/javadoc/SubServers.Client.Common)<br>
> [https://dev.me1312.net/jenkins/job/SubServers Platform/javadoc/SubServers.Client.Sponge](https://dev.me1312.net/jenkins/job/SubServers%20Platform/javadoc/SubServers.Client.Sponge)
### Stats for nerds
> [https://bstats.org/plugin/bungeecord/SubServers_Bungee](https://bstats.org/plugin/bungeecord/SubServers%202)<br>
> [https://bstats.org/plugin/other/SubServers_Host](https://bstats.org/plugin/other/SubServers%20Host)<br>
> [https://bstats.org/plugin/bungeecord/SubServers_Sync](https://bstats.org/plugin/bungeecord/SubServers%20Sync)<br>
> [https://bstats.org/plugin/velocity/SubServers_Sync](https://bstats.org/plugin/velocity/SubServers%20Sync)<br>
> [https://bstats.org/plugin/bungeecord/SubServers_Console](https://bstats.org/plugin/bungeecord/SubServers%20Console)<br>
> [https://bstats.org/plugin/bukkit/SubServers_Client](https://bstats.org/plugin/bukkit/SubServers%20Client)<br>
> [https://bstats.org/plugin/sponge/SubServers_Client](https://bstats.org/plugin/sponge/SubServers%20Client)

View File

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.ME1312.SubServers</groupId>
<artifactId>SubServers.Bungee.Common</artifactId>
<version>-PLACEHOLDER</version>
<packaging>jar</packaging>
<repositories>
<repository>
<id>md_5-repo</id>
<url>http://repo.md-5.net/content/repositories/snapshots/</url>
</repository>
<repository>
<id>me1312-repo</id>
<url>https://dev.me1312.net/maven</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>net.md_5</groupId>
<artifactId>bungeecord-internal</artifactId>
<version>1.15-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.ME1312.Galaxi</groupId>
<artifactId>GalaxiBase</artifactId>
<version>23w51a</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<directory>../../out/compile/target/SubServers.Bungee.Common</directory>
<sourceDirectory>src</sourceDirectory>
<resources>
<resource>
<directory>src</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>process-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<mkdir dir="${project.build.directory}" />
<copy file="${basedir}/../../LICENSE" todir="${project.build.directory}/classes" />
</tasks>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<finalName>SubServers.Bungee.Common</finalName>
<outputDirectory>../../Artifacts/Maven</outputDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>javadoc</goal>
</goals>
<configuration>
<windowtitle>SubServers.Bungee.Common</windowtitle>
<doctitle>SubServers.Bungee.Common ${project.version}</doctitle>
<show>protected</show>
<destDir>./</destDir>
<outputDirectory>${basedir}/../../Javadoc/SubServers.Bungee.Common</outputDirectory>
<reportOutputDirectory>${basedir}/../../Javadoc/SubServers.Bungee.Common</reportOutputDirectory>
<additionalOptions>-Xdoclint:none</additionalOptions>
<links>
<link>https://dev.me1312.net/jenkins/job/GalaxiEngine/javadoc/GalaxiBase/</link>
<link>https://ci.md-5.net/job/BungeeCord/ws/api/target/apidocs/</link>
</links>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,137 @@
package net.ME1312.SubServers.Bungee;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.Galaxi.Library.Version.Version;
import net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ServerInfo;
import java.io.File;
import java.util.Collection;
import java.util.Map;
import java.util.UUID;
/**
* SubAPI BungeeCord Common Class
*/
public interface BungeeAPI {
/**
* Gets the SubAPI BungeeCord Common Methods
*
* @return SubAPI BungeeCord Common
*/
static BungeeAPI getInstance() {
return ((BungeeCommon) ProxyServer.getInstance()).api.get();
}
/**
* Gets the BungeeCommon Internals
*
* @deprecated Use BungeeAPI Methods when available
* @return BungeeCommon Internals
*/
@Deprecated
BungeeCommon getInternals();
/**
* Get the number of players on this network across all known proxies
*
* @return Remote Player Collection
*/
int getRemotePlayerCount();
/**
* Get players on this server across all known proxies
*
* @param server Server to search
* @return Remote Player Map
*/
Map<UUID, ? extends RemotePlayer> getRemotePlayers(ServerInfo server);
/**
* Get players on this network across all known proxies
*
* @return Remote Player Map
*/
Map<UUID, ? extends RemotePlayer> getRemotePlayers();
/**
* Get a player on this network by searching across all known proxies
*
* @param name Player name
* @return Remote Player
*/
RemotePlayer getRemotePlayer(String name);
/**
* Get a player on this network by searching across all known proxies
*
* @param id Player UUID
* @return Remote Player
*/
RemotePlayer getRemotePlayer(UUID id);
/**
* Gets the current SubServers Lang Channels
*
* @return SubServers Lang Channel list
*/
Collection<String> getLangChannels();
/**
* Gets values from the SubServers Lang
*
* @param channel Lang Channel
* @return Lang Value
*/
Map<String, String> getLang(String channel);
/**
* Gets a value from the SubServers Lang
*
* @param channel Lang Channel
* @param key Key
* @return Lang Values
*/
default String getLang(String channel, String key) {
Util.nullpo(channel, key);
return getLang(channel).get(key);
}
/**
* Gets the Runtime Directory
*
* @return Directory
*/
File getRuntimeDirectory();
/**
* Gets the SubServers Version
*
* @return SubServers Version
*/
Version getWrapperVersion();
/**
* Gets the SubServers Build Version
*
* @return SubServers Build Version (or null if unsigned)
*/
Version getWrapperBuild();
/**
* Gets the BungeeCord Version
*
* @return BungeeCord Version
*/
Version getProxyVersion();
/**
* Get an array of compatible Minecraft Versions
*
* @return Minecraft Versions
*/
Version[] getGameVersion();
}

View File

@ -0,0 +1,49 @@
package net.ME1312.SubServers.Bungee;
import net.ME1312.Galaxi.Library.Util;
import io.netty.channel.Channel;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.config.ServerInfo;
import java.util.Collection;
import java.util.Map;
import java.util.function.Supplier;
/**
* BungeeCord Common Layout Class
*/
public abstract class BungeeCommon extends BungeeCord {
private static BungeeCommon instance;
final Supplier<BungeeAPI> api;
protected final Collection<Channel> listeners;
protected BungeeCommon(Supplier<BungeeAPI> api) throws Exception {
listeners= Util.reflect(BungeeCord.class.getDeclaredField("listeners"), this);
this.api = api;
instance = this;
}
/**
* Get the name from BungeeCord's original signature (for determining which fork is being used)
*
* @return BungeeCord Software Name
*/
public abstract String getBungeeName();
/**
* Waterfall's getServersCopy()
*
* @return Server Map Copy
*/
public abstract Map<String, ServerInfo> getServersCopy();
/**
* Gets the ProxyServer Common Object
*
* @return ProxyServer Common
*/
public static BungeeCommon getInstance() {
return instance;
}
}

View File

@ -0,0 +1,39 @@
package net.ME1312.SubServers.Bungee.Library.Compatibility;
import net.ME1312.SubServers.Bungee.BungeeCommon;
import java.util.HashMap;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
/**
* Logger Compatibility Class
*/
public class Logger {
private static final HashMap<String, java.util.logging.Logger> existing = new HashMap<String, java.util.logging.Logger>();
/**
* Get a logger
*
* @param prefix Prefix
* @return Logger
*/
public static java.util.logging.Logger get(String prefix) {
if (!existing.containsKey(prefix)) {
java.util.logging.Logger log = java.util.logging.Logger.getAnonymousLogger();
log.setUseParentHandlers(false);
log.addHandler(new Handler() {
@Override
public void publish(LogRecord record) {
BungeeCommon.getInstance().getLogger().log(record.getLevel(), prefix + " > " + record.getMessage(), record.getParameters());
}
@Override
public void flush() {}
public void close() {}
});
existing.put(prefix, log);
}
return existing.get(prefix);
}
}

View File

@ -0,0 +1,52 @@
package net.ME1312.SubServers.Bungee.Library.Compatibility;
import net.md_5.bungee.api.chat.BaseComponent;
import java.util.UUID;
import java.util.function.IntConsumer;
/**
* RemotePlayer Static Implementation Layout Class
*/
public abstract class RPSI {
protected static RPSI instance;
protected RPSI() {
if (instance == null) instance = this;
}
/**
* Sends messages to this player
*
* @param players Players to send to
* @param messages Messages to send
* @param response Success Status
*/
protected abstract void sendMessage(UUID[] players, String[] messages, IntConsumer response);
/**
* Sends messages to this player
*
* @param players Players to send to
* @param messages Messages to send
* @param response Success Status
*/
protected abstract void sendMessage(UUID[] players, BaseComponent[][] messages, IntConsumer response);
/**
* Transfers this player to another server
*
* @param players Players to send to
* @param server Target server
* @param response Success Status
*/
protected abstract void transfer(UUID[] players, String server, IntConsumer response);
/**
* Disconnects this player from the network
*
* @param players Players to send to
* @param reason Disconnect Reason
* @param response Success status
*/
protected abstract void disconnect(UUID[] players, String reason, IntConsumer response);
}

View File

@ -0,0 +1,460 @@
package net.ME1312.SubServers.Bungee.Library.Compatibility;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.net.InetSocketAddress;
import java.util.UUID;
import java.util.function.IntConsumer;
import static net.ME1312.SubServers.Bungee.Library.Compatibility.RPSI.instance;
/**
* RemotePlayer Layout Class
*/
public interface RemotePlayer {
/**
* Get Local Player
*
* @return Local Player (or null when not local)
*/
ProxiedPlayer get();
/**
* Get the UUID of this player.
*
* @return the UUID
*/
UUID getUniqueId();
/**
* Get the unique name of this player.
*
* @return the player's username
*/
String getName();
/**
* Gets the remote address of this connection.
*
* @return the remote address
*/
InetSocketAddress getAddress();
/**
* Gets the name of the proxy this player is connected to.
*
* @return the name of the proxy this player is connected to
*/
String getProxyName();
/**
* Gets the name of the server this player is connected to.
*
* @return the name of the server this player is connected to
*/
String getServerName();
/**
* Gets the server this player is connected to.
*
* @return the server this player is connected to
*/
ServerInfo getServer();
/**
* Sends messages to all players
*
* @param messages Messages to send
*/
static void broadcastMessage(String... messages) {
broadcastMessage(messages, i -> {});
}
/**
* Sends a message to all players
*
* @param message Message to send
* @param response Success Status
*/
static void broadcastMessage(String message, IntConsumer response) {
broadcastMessage(new String[]{ message }, response);
}
/**
* Sends messages to all players
*
* @param messages Messages to send
* @param response Success Status
*/
static void broadcastMessage(String[] messages, IntConsumer response) {
sendMessage(null, messages, response);
}
/**
* Sends messages to this player
*
* @param messages Messages to send
*/
default void sendMessage(String... messages) {
sendMessage(messages, i -> {});
}
/**
* Sends a message to this player
*
* @param message Message to send
* @param response Success Status
*/
default void sendMessage(String message, IntConsumer response) {
sendMessage(new String[]{ message }, response);
}
/**
* Sends messages to this player
*
* @param messages Messages to send
* @param response Success Status
*/
default void sendMessage(String[] messages, IntConsumer response) {
sendMessage(new UUID[]{ getUniqueId() }, messages, response);
}
/**
* Sends messages to these players
*
* @param players Players to select
* @param messages Messages to send
*/
static void sendMessage(UUID[] players, String... messages) {
sendMessage(players, messages, i -> {});
}
/**
* Sends a message to these players
*
* @param players Players to select
* @param message Message to send
* @param response Success Status
*/
static void sendMessage(UUID[] players, String message, IntConsumer response) {
sendMessage(players, new String[]{ message }, response);
}
/**
* Sends messages to these players
*
* @param players Players to select
* @param messages Messages to send
* @param response Success Status
*/
static void sendMessage(UUID[] players, String[] messages, IntConsumer response) {
instance.sendMessage(players, messages, response);
}
/**
* Sends a message to all players
*
* @param message Message to send
*/
static void broadcastMessage(BaseComponent... message) {
broadcastMessage(message, i -> {});
}
/**
* Sends a message to all players
*
* @param message Message to send
* @param response Success Status
*/
static void broadcastMessage(BaseComponent message, IntConsumer response) {
broadcastMessage(new BaseComponent[]{ message }, response);
}
/**
* Sends a messages to all players
*
* @param message Message to send
* @param response Success Status
*/
static void broadcastMessage(BaseComponent[] message, IntConsumer response) {
broadcastMessage(new BaseComponent[][]{ message }, response);
}
/**
* Sends messages to all players
*
* @param messages Messages to send
*/
static void broadcastMessage(BaseComponent[]... messages) {
broadcastMessage(messages, i -> {});
}
/**
* Sends messages to all players
*
* @param messages Messages to send
* @param response Success Status
*/
static void broadcastMessage(BaseComponent[][] messages, IntConsumer response) {
sendMessage(null, messages, response);
}
/**
* Sends a message to this player
*
* @param message Message to send
*/
default void sendMessage(BaseComponent... message) {
sendMessage(message, i -> {});
}
/**
* Sends a message to this player
*
* @param message Message to send
* @param response Success Status
*/
default void sendMessage(BaseComponent message, IntConsumer response) {
sendMessage(new BaseComponent[]{ message }, response);
}
/**
* Sends a message to this player
*
* @param message Message to send
* @param response Success Status
*/
default void sendMessage(BaseComponent[] message, IntConsumer response) {
sendMessage(new BaseComponent[][]{ message }, response);
}
/**
* Sends messages to this player
*
* @param messages Messages to send
*/
default void sendMessage(BaseComponent[]... messages) {
sendMessage(messages, i -> {});
}
/**
* Sends messages to this player
*
* @param messages Messages to send
* @param response Success Status
*/
default void sendMessage(BaseComponent[][] messages, IntConsumer response) {
sendMessage(new UUID[]{ getUniqueId() }, messages, response);
}
/**
* Sends a message to these players
*
* @param players Players to select
* @param message Message to send
*/
static void sendMessage(UUID[] players, BaseComponent... message) {
sendMessage(players, message, i -> {});
}
/**
* Sends a message to these players
*
* @param players Players to select
* @param message Message to send
* @param response Success Status
*/
static void sendMessage(UUID[] players, BaseComponent message, IntConsumer response) {
sendMessage(players, new BaseComponent[]{ message }, response);
}
/**
* Sends a message to these players
*
* @param players Players to select
* @param message Message to send
* @param response Success Status
*/
static void sendMessage(UUID[] players, BaseComponent[] message, IntConsumer response) {
sendMessage(players, new BaseComponent[][]{ message }, response);
}
/**
* Sends messages to these players
*
* @param players Players to select
* @param messages Messages to send
*/
static void sendMessage(UUID[] players, BaseComponent[]... messages) {
sendMessage(players, messages, i -> {});
}
/**
* Sends messages to these players
*
* @param players Players to select
* @param messages Message to send
* @param response Success Status
*/
static void sendMessage(UUID[] players, BaseComponent[][] messages, IntConsumer response) {
instance.sendMessage(players, messages, response);
}
/**
* Transfers this player to another server
*
* @param server Target server
*/
default void transfer(String server) {
transfer(server, i -> {});
}
/**
* Transfers this player to another server
*
* @param server Target server
* @param response Success status
*/
default void transfer(String server, IntConsumer response) {
transfer(new UUID[]{ getUniqueId() }, server, response);
}
/**
* Transfers these players to another server
*
* @param players Players to select
* @param server Target server
*/
static void transfer(UUID[] players, String server) {
transfer(players, server, i -> {});
}
/**
* Transfers these players to another server
*
* @param players Players to select
* @param server Target server
* @param response Success status
*/
static void transfer(UUID[] players, String server, IntConsumer response) {
instance.transfer(players, server, response);
}
/**
* Transfers this player to another server
*
* @param server Target server
*/
default void transfer(ServerInfo server) {
transfer(server, i -> {});
}
/**
* Transfers this player to another server
*
* @param server Target server
* @param response Success status
*/
default void transfer(ServerInfo server, IntConsumer response) {
transfer(new UUID[]{ getUniqueId() }, server, response);
}
/**
* Transfers these players to another server
*
* @param players Players to select
* @param server Target server
*/
static void transfer(UUID[] players, ServerInfo server) {
transfer(players, server, i -> {});
}
/**
* Transfers these players to another server
*
* @param players Players to select
* @param server Target server
* @param response Success status
*/
static void transfer(UUID[] players, ServerInfo server, IntConsumer response) {
instance.transfer(players, server.getName(), response);
}
/**
* Disconnects this player from the network
*/
default void disconnect() {
disconnect((String) null);
}
/**
* Disconnects this player from the network
*
* @param response Success status
*/
default void disconnect(IntConsumer response) {
disconnect((String) null, response);
}
/**
* Disconnects this player from the network
*
* @param reason Disconnect Reason
*/
default void disconnect(String reason) {
disconnect(reason, i -> {});
}
/**
* Disconnects this player from the network
*
* @param reason Disconnect Reason
* @param response Success status
*/
default void disconnect(String reason, IntConsumer response) {
disconnect(new UUID[]{ getUniqueId() }, reason, response);
}
/**
* Disconnects these players from the network
*
* @param players Players to select
*/
static void disconnect(UUID... players) {
disconnect(players, (String) null);
}
/**
* Disconnects these players from the network
*
* @param players Players to select
* @param response Success status
*/
static void disconnect(UUID[] players, IntConsumer response) {
disconnect(players, null, response);
}
/**
* Disconnects these players from the network
*
* @param players Players to select
* @param reason Disconnect Reason
*/
static void disconnect(UUID[] players, String reason) {
disconnect(players, reason, i -> {});
}
/**
* Disconnects these players from the network
*
* @param players Players to select
* @param reason Disconnect Reason
* @param response Success status
*/
static void disconnect(UUID[] players, String reason, IntConsumer response) {
instance.disconnect(players, reason, response);
}
}

View File

@ -0,0 +1,19 @@
package net.ME1312.SubServers.Bungee.Library.Fallback;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
/**
* Fallback Server Inspector Layout Class
*/
public interface FallbackInspector {
/**
* Inspect a fallback server and modify its confidence score
*
* @param player Player that requested (may be null)
* @param server Server to inspect
* @return A Positive Value to add points, a Negative Value to subtract points, a Null Value to invalidate the server, or a Zero Value to do nothing
*/
Double inspect(ProxiedPlayer player, ServerInfo server);
}

View File

@ -0,0 +1,72 @@
package net.ME1312.SubServers.Bungee.Library.Fallback;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.config.ServerInfo;
import java.util.*;
/**
* Fallback Player State Class
*/
public class FallbackState {
public final UUID player;
public final LinkedList<String> names;
public final LinkedList<ServerInfo> servers;
public final BaseComponent[] reason;
private Map<String, ServerInfo> map;
private Timer finish;
/**
* Smart Fallback State Container
*
* @param player Player
* @param servers Fallback Servers
* @param reason Original Disconnect Reason
*/
public FallbackState(UUID player, Map<String, ServerInfo> servers, BaseComponent... reason) {
this.player = player;
this.map = servers;
this.names = new LinkedList<>(servers.keySet());
this.servers = new LinkedList<>(servers.values());
this.reason = reason;
}
/**
* <i>Use</i> a server
*
* @param name Server name to remove
*/
public void remove(String name) {
servers.remove(map.get(name));
names.remove(name);
map.remove(name);
}
/**
* <i>Use</i> a server
*
* @param server Server to remove
*/
public void remove(ServerInfo server) {
map.remove(server.getName());
names.remove(server.getName());
servers.remove(server);
}
/**
* Finish the process
*
* @param callback Finishing callback
* @param delay Delay for determining stability
*/
public void done(Runnable callback, long delay) {
if (finish != null) finish.cancel();
(finish = new Timer("SubServers.Bungee::Fallback_Limbo_Timer(" + player + ')')).schedule(new TimerTask() {
@Override
public void run() {
if (callback != null) callback.run();
finish.cancel();
}
}, delay);
}
}

View File

@ -0,0 +1,209 @@
package net.ME1312.SubServers.Bungee.Library.Fallback;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Try;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.BungeeCommon;
import net.md_5.bungee.UserConnection;
import net.md_5.bungee.api.AbstractReconnectHandler;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.ReconnectHandler;
import net.md_5.bungee.api.config.ListenerInfo;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Smart Fallback Handler Class
*/
public class SmartFallback implements ReconnectHandler {
private static List<FallbackInspector> inspectors = new CopyOnWriteArrayList<FallbackInspector>();
private static ReconnectHandler reconnect;
public static boolean dns_forward = false;
public SmartFallback(ObjectMap<String> settings) {
dns_forward = settings.getBoolean("DNS-Forward", false);
if (reconnect == null && settings.getBoolean("Reconnect", false))
reconnect = Try.all.get(() -> Util.reflect(ProxyServer.getInstance().getPluginManager().getPlugin("reconnect_yaml").getClass().getClassLoader().loadClass("net.md_5.bungee.module.reconnect.yaml.YamlReconnectHandler").getConstructor()));
}
@Override
public ServerInfo getServer(ProxiedPlayer player) {
return getServer(player, player instanceof UserConnection);
}
protected ServerInfo getServer(ProxiedPlayer player, boolean queue) {
ServerInfo override;
if ((override = getForcedHost(player.getPendingConnection())) != null
|| (override = getDNS(player.getPendingConnection())) != null) {
if (queue) ((UserConnection) player).setServerJoinQueue(new LinkedList<>());
return override;
} else {
Map<String, ServerInfo> fallbacks = getFallbackServers(player.getPendingConnection().getListener(), player);
if ((override = getReconnectServer(player)) != null || !fallbacks.isEmpty()) {
if (queue) ((UserConnection) player).setServerJoinQueue(new LinkedList<>(fallbacks.keySet()));
return (override != null)? override : new LinkedList<>(fallbacks.values()).getFirst();
} else {
return null;
}
}
}
/**
* Grabs the Forced Host Server for this connection
*
* @see AbstractReconnectHandler#getForcedHost(PendingConnection) Essentially the same method, but more ambigous
* @param connection Connection to check
* @return Forced Host Server (or null if there is none)
*/
public static ServerInfo getForcedHost(PendingConnection connection) {
if (connection.getVirtualHost() == null) {
return null;
} else {
String forced = connection.getListener().getForcedHosts().get(connection.getVirtualHost().getHostString());
//if (forced == null && con.getListener().isForceDefault()) { // This is the part of the method that made it ambiguous
// forced = con.getListener().getDefaultServer(); // Aside from that, everything else was fine
//} // :(
return ProxyServer.getInstance().getServerInfo(forced);
}
}
/**
* Grabs the Server that a connection's DNS matches
*
* @param connection Connection to check
* @return DNS Forward Server
*/
public static ServerInfo getDNS(PendingConnection connection) {
if (connection.getVirtualHost() == null || !dns_forward) {
return null;
} else {
Map.Entry<String, ServerInfo> server = null;
String dns = connection.getVirtualHost().getHostString().toLowerCase();
for (Map.Entry<String, ServerInfo> s : ((BungeeCommon) ProxyServer.getInstance()).getServersCopy().entrySet()) {
if (dns.startsWith(s.getKey().toLowerCase() + '.'))
if (server == null || server.getKey().length() < s.getKey().length())
server = s;
}
return (server == null)?null:server.getValue();
}
}
/**
* Grabs the Server that a player was last connected to
*
* @param player Player
* @return Reconnect Server
*/
public static ServerInfo getReconnectServer(ProxiedPlayer player) {
if (reconnect == null) {
return null;
} else try {
return Util.reflect(reconnect.getClass().getDeclaredMethod("getStoredServer", ProxiedPlayer.class), reconnect, player);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
return null;
}
}
/**
* Generates a <i>smart</i> sorted map of fallback servers using a generated confidence score
*
* @param listener Listener to grab fallback servers from
* @return Fallback Server Map (with legacy bungee case-sensitive keys)
*/
public static Map<String, ServerInfo> getFallbackServers(ListenerInfo listener) {
return getFallbackServers(listener, null);
}
/**
* Generates a <i>smart</i> sorted map of fallback servers using a generated confidence score
*
* @param listener Listener to grab fallback servers from
* @param player Player that is requesting fallback servers
* @return Fallback Server Map (with legacy bungee case-sensitive keys)
*/
public static Map<String, ServerInfo> getFallbackServers(ListenerInfo listener, ProxiedPlayer player) {
TreeMap<Double, List<ServerInfo>> score = new TreeMap<Double, List<ServerInfo>>(Collections.reverseOrder());
for (String name : listener.getServerPriority()) {
ServerInfo server = ProxyServer.getInstance().getServerInfo(name);
if (server != null) {
boolean valid = true;
double confidence = 0;
List<FallbackInspector> inspectors = new ArrayList<FallbackInspector>();
inspectors.addAll(SmartFallback.inspectors);
for (FallbackInspector inspector : inspectors) try {
Double response = inspector.inspect(player, server);
if (response == null) {
valid = false;
} else {
confidence += response;
}
} catch (Throwable e) {
new InvocationTargetException(e, "Exception while running inspecting fallback server: " + server.getName()).printStackTrace();
}
if (valid) {
List<ServerInfo> servers = (score.containsKey(confidence))?score.get(confidence):new LinkedList<ServerInfo>();
servers.add(server);
score.put(confidence, servers);
}
}
}
Random random = new Random();
LinkedHashMap<String, ServerInfo> map = new LinkedHashMap<String, ServerInfo>();
for (List<ServerInfo> servers : score.values()) {
while (!servers.isEmpty()) {
ServerInfo next = servers.get(random.nextInt(servers.size()));
map.put(next.getName(), next);
servers.remove(next);
}
}
return map;
}
/**
* Add a Fallback Server Inspector
*
* @param inspector Inspector
*/
public static void addInspector(FallbackInspector inspector) {
Util.nullpo(inspector);
inspectors.add(inspector);
}
/**
* Remove a Fallback Server Inspector
*
* @param inspector Inspector
*/
public static void removeInspector(FallbackInspector inspector) {
Util.nullpo(inspector);
Try.all.run(() -> inspectors.remove(inspector));
}
@Override
public void setServer(ProxiedPlayer player) {
if (reconnect != null) reconnect.setServer(player);
}
@Override
public void save() {
if (reconnect != null) reconnect.save();
}
@Override
public void close() {
if (reconnect != null) reconnect.close();
}
}

View File

@ -35,7 +35,7 @@ listeners:
max_players: 1
tab_size: 60
ping_passthrough: false
force_default_server: false
force_default_server: true
player_limit: -1
online_mode: true
log_commands: false

View File

@ -0,0 +1,909 @@
package net.ME1312.SubServers.Bungee.Library;
import net.ME1312.SubServers.Bungee.BungeeAPI;
import net.ME1312.SubServers.Bungee.BungeeCommon;
import gnu.trove.map.hash.TIntObjectHashMap;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
import net.md_5.bungee.protocol.ProtocolConstants;
import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.zip.GZIPOutputStream;
/**
* SubServers BStats Metrics Implementation
*/
public class Metrics {
private final Plugin plugin;
private final MetricsBase metricsBase;
private boolean enabled;
private String serverUUID;
private boolean logErrors = false;
private boolean logSentData;
private boolean logResponseStatusText;
/**
* Creates a new Metrics instance.
*
* @param plugin Your plugin instance.
* @param serviceId The id of the service. It can be found at <a
* href="https://bstats.org/what-is-my-plugin-id">What is my plugin id?</a>
*/
public Metrics(Plugin plugin, int serviceId) {
this.plugin = plugin;
try {
loadConfig();
} catch (IOException e) {
// Failed to load configuration
plugin.getLogger().log(Level.WARNING, "Failed to load bStats config!", e);
metricsBase = null;
return;
}
metricsBase =
new MetricsBase(
"bungeecord",
serverUUID,
serviceId,
enabled,
this::appendPlatformData,
this::appendServiceData,
null,
() -> true,
(message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error),
(message) -> this.plugin.getLogger().log(Level.INFO, message),
logErrors,
logSentData,
logResponseStatusText);
}
/** Loads the bStats configuration. */
private void loadConfig() throws IOException {
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
bStatsFolder.mkdirs();
File configFile = new File(bStatsFolder, "config.yml");
if (!configFile.exists()) {
writeFile(
configFile,
"# bStats (https://bStats.org) collects some basic information for plugin authors, like how",
"# many people use their plugin and their total player count. It's recommended to keep bStats",
"# enabled, but if you're not comfortable with this, you can turn this setting off. There is no",
"# performance penalty associated with having metrics enabled, and data sent to bStats is fully",
"# anonymous.",
"enabled: true",
"serverUuid: \"" + UUID.randomUUID() + "\"",
"logFailedRequests: false",
"logSentData: false",
"logResponseStatusText: false");
}
Configuration configuration =
ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile);
// Load configuration
enabled = configuration.getBoolean("enabled", true);
serverUUID = configuration.getString("serverUuid");
logErrors = configuration.getBoolean("logFailedRequests", false);
logSentData = configuration.getBoolean("logSentData", false);
logResponseStatusText = configuration.getBoolean("logResponseStatusText", false);
}
private void writeFile(File file, String... lines) throws IOException {
try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) {
for (String line : lines) {
bufferedWriter.write(line);
bufferedWriter.newLine();
}
}
}
private static final AdvancedPie PLAYER_VERSIONS;
static {
final int[] PROTOCOL_VERSIONS;
final String[] PROTOCOL_NAMES;
{
TIntObjectHashMap<String> protocols = new TIntObjectHashMap<String>();
try {
for (Field f : ProtocolConstants.class.getDeclaredFields()) {
int fm = f.getModifiers();
if (Modifier.isPublic(fm) && Modifier.isStatic(fm) && Modifier.isFinal(fm) && f.getType() == int.class && f.getName().startsWith("MINECRAFT_")) {
protocols.put(f.getInt(null), f.getName().substring(10).replace('_', '.'));
}
}
} catch (Throwable e) {
e.printStackTrace();
}
PROTOCOL_VERSIONS = protocols.keys();
PROTOCOL_NAMES = new String[PROTOCOL_VERSIONS.length];
Arrays.sort(PROTOCOL_VERSIONS);
for (int i = 0; i < PROTOCOL_VERSIONS.length; ++i) {
PROTOCOL_NAMES[i] = protocols.get(PROTOCOL_VERSIONS[i]);
}
}
PLAYER_VERSIONS = new AdvancedPie("player_versions", () -> {
int[] players = new int[PROTOCOL_VERSIONS.length];
for (ProxiedPlayer player : ProxyServer.getInstance().getPlayers()) {
int i = Arrays.binarySearch(PROTOCOL_VERSIONS, player.getPendingConnection().getVersion());
if (i != -1) {
++players[i];
}
}
HashMap<String, Integer> map = new HashMap<String, Integer>();
for (int i = 0; i < PROTOCOL_NAMES.length; ++i) if (players[i] != 0) {
map.put(PROTOCOL_NAMES[i], players[i]);
}
return map;
});
}
/**
* Add subservers platform information as custom charts
*/
public Metrics addPlatformCharts() {
return addCustomChart(new SimplePie("subservers_version", () -> BungeeAPI.getInstance().getWrapperVersion().toString())).addCustomChart(PLAYER_VERSIONS);
}
/**
* Adds a custom chart.
*
* @param chart The chart to add.
*/
public Metrics addCustomChart(CustomChart chart) {
metricsBase.addCustomChart(chart);
return this;
}
private void appendPlatformData(JsonObjectBuilder builder) {
builder.appendField("playerAmount", plugin.getProxy().getOnlineCount());
builder.appendField("managedServers", ((BungeeCommon) plugin.getProxy()).getServersCopy().size());
builder.appendField("onlineMode", plugin.getProxy().getConfig().isOnlineMode() ? 1 : 0);
builder.appendField("bungeecordVersion", plugin.getProxy().getVersion());
builder.appendField("javaVersion", System.getProperty("java.version"));
builder.appendField("osName", System.getProperty("os.name"));
builder.appendField("osArch", System.getProperty("os.arch"));
builder.appendField("osVersion", System.getProperty("os.version"));
builder.appendField("coreCount", Runtime.getRuntime().availableProcessors());
}
private void appendServiceData(JsonObjectBuilder builder) {
builder.appendField("pluginVersion", plugin.getDescription().getVersion());
}
public static class MetricsBase {
/** The version of the Metrics class. */
public static final String METRICS_VERSION = "3.0.0";
private static final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1, task -> new Thread(task, "bStats-Metrics"));
private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s";
private final String platform;
private final String serverUuid;
private final int serviceId;
private final Consumer<JsonObjectBuilder> appendPlatformDataConsumer;
private final Consumer<JsonObjectBuilder> appendServiceDataConsumer;
private final Consumer<Runnable> submitTaskConsumer;
private final Supplier<Boolean> checkServiceEnabledSupplier;
private final BiConsumer<String, Throwable> errorLogger;
private final Consumer<String> infoLogger;
private final boolean logErrors;
private final boolean logSentData;
private final boolean logResponseStatusText;
private final Set<CustomChart> customCharts = new HashSet<>();
private final boolean enabled;
/**
* Creates a new MetricsBase class instance.
*
* @param platform The platform of the service.
* @param serviceId The id of the service.
* @param serverUuid The server uuid.
* @param enabled Whether or not data sending is enabled.
* @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
* appends all platform-specific data.
* @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
* appends all service-specific data.
* @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be
* used to delegate the data collection to a another thread to prevent errors caused by
* concurrency. Can be {@code null}.
* @param checkServiceEnabledSupplier A supplier to check if the service is still enabled.
* @param errorLogger A consumer that accepts log message and an error.
* @param infoLogger A consumer that accepts info log messages.
* @param logErrors Whether or not errors should be logged.
* @param logSentData Whether or not the sent data should be logged.
* @param logResponseStatusText Whether or not the response status text should be logged.
*/
public MetricsBase(
String platform,
String serverUuid,
int serviceId,
boolean enabled,
Consumer<JsonObjectBuilder> appendPlatformDataConsumer,
Consumer<JsonObjectBuilder> appendServiceDataConsumer,
Consumer<Runnable> submitTaskConsumer,
Supplier<Boolean> checkServiceEnabledSupplier,
BiConsumer<String, Throwable> errorLogger,
Consumer<String> infoLogger,
boolean logErrors,
boolean logSentData,
boolean logResponseStatusText) {
this.platform = platform;
this.serverUuid = serverUuid;
this.serviceId = serviceId;
this.enabled = enabled;
this.appendPlatformDataConsumer = appendPlatformDataConsumer;
this.appendServiceDataConsumer = appendServiceDataConsumer;
this.submitTaskConsumer = submitTaskConsumer;
this.checkServiceEnabledSupplier = checkServiceEnabledSupplier;
this.errorLogger = errorLogger;
this.infoLogger = infoLogger;
this.logErrors = logErrors;
this.logSentData = logSentData;
this.logResponseStatusText = logResponseStatusText;
checkRelocation();
if (enabled) {
// WARNING: Removing the option to opt-out will get your plugin banned from bStats
startSubmitting();
}
}
public void addCustomChart(CustomChart chart) {
this.customCharts.add(chart);
}
private void startSubmitting() {
final Runnable submitTask =
() -> {
if (!enabled || !checkServiceEnabledSupplier.get()) {
// Submitting data or service is disabled
scheduler.shutdown();
return;
}
if (submitTaskConsumer != null) {
submitTaskConsumer.accept(this::submitData);
} else {
this.submitData();
}
};
// Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution
// of requests on the
// bStats backend. To circumvent this problem, we introduce some randomness into the initial
// and second delay.
// WARNING: You must not modify and part of this Metrics class, including the submit delay or
// frequency!
// WARNING: Modifying this code will get your plugin banned on bStats. Just don't do it!
long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3));
long secondDelay = (long) (1000 * 60 * (Math.random() * 30));
scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS);
scheduler.scheduleAtFixedRate(
submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS);
}
private void submitData() {
final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder();
appendPlatformDataConsumer.accept(baseJsonBuilder);
final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder();
appendServiceDataConsumer.accept(serviceJsonBuilder);
JsonObjectBuilder.JsonObject[] chartData =
customCharts.stream()
.map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors))
.filter(Objects::nonNull)
.toArray(JsonObjectBuilder.JsonObject[]::new);
serviceJsonBuilder.appendField("id", serviceId);
serviceJsonBuilder.appendField("customCharts", chartData);
baseJsonBuilder.appendField("service", serviceJsonBuilder.build());
baseJsonBuilder.appendField("serverUUID", serverUuid);
baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION);
JsonObjectBuilder.JsonObject data = baseJsonBuilder.build();
scheduler.execute(
() -> {
try {
// Send the data
sendData(data);
} catch (Exception e) {
// Something went wrong! :(
if (logErrors) {
errorLogger.accept("Could not submit bStats metrics data", e);
}
}
});
}
private void sendData(JsonObjectBuilder.JsonObject data) throws Exception {
if (logSentData) {
infoLogger.accept("Sent bStats metrics data: " + data.toString());
}
String url = String.format(REPORT_URL, platform);
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
// Compress the data to save bandwidth
byte[] compressedData = compress(data.toString());
connection.setRequestMethod("POST");
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.addRequestProperty("Content-Encoding", "gzip");
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("User-Agent", "Metrics-Service/1");
connection.setDoOutput(true);
try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
outputStream.write(compressedData);
}
StringBuilder builder = new StringBuilder();
try (BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
}
}
if (logResponseStatusText) {
infoLogger.accept("Sent data to bStats and received response: " + builder);
}
}
/** Checks that the class was properly relocated. */
private void checkRelocation() {
// You can use the property to disable the check in your test environment
if (System.getProperty("bstats.relocatecheck") == null
|| !System.getProperty("bstats.relocatecheck").equals("false")) {
// Maven's Relocate is clever and changes strings, too. So we have to use this little
// "trick" ... :D
final String defaultPackage =
new String(new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'});
final String examplePackage =
new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
// We want to make sure no one just copy & pastes the example and uses the wrong package
// names
if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage)
|| MetricsBase.class.getPackage().getName().startsWith(examplePackage)) {
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
}
}
}
/**
* Gzips the given string.
*
* @param str The string to gzip.
* @return The gzipped string.
*/
private static byte[] compress(final String str) throws IOException {
if (str == null) {
return null;
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) {
gzip.write(str.getBytes(StandardCharsets.UTF_8));
}
return outputStream.toByteArray();
}
}
public static class DrilldownPie extends CustomChart {
private final Callable<Map<String, Map<String, Integer>>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public DrilldownPie(String chartId, Callable<Map<String, Map<String, Integer>>> callable) {
super(chartId);
this.callable = callable;
}
@Override
public JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, Map<String, Integer>> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean reallyAllSkipped = true;
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
JsonObjectBuilder valueBuilder = new JsonObjectBuilder();
boolean allSkipped = true;
for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue());
allSkipped = false;
}
if (!allSkipped) {
reallyAllSkipped = false;
valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build());
}
}
if (reallyAllSkipped) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
public static class AdvancedPie extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public AdvancedPie(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getValue() == 0) {
// Skip this invalid
continue;
}
allSkipped = false;
valuesBuilder.appendField(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
public static class MultiLineChart extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public MultiLineChart(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getValue() == 0) {
// Skip this invalid
continue;
}
allSkipped = false;
valuesBuilder.appendField(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
public static class SimpleBarChart extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SimpleBarChart(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
for (Map.Entry<String, Integer> entry : map.entrySet()) {
valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()});
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
public abstract static class CustomChart {
private final String chartId;
protected CustomChart(String chartId) {
if (chartId == null) {
throw new IllegalArgumentException("chartId must not be null");
}
this.chartId = chartId;
}
public JsonObjectBuilder.JsonObject getRequestJsonObject(
BiConsumer<String, Throwable> errorLogger, boolean logErrors) {
JsonObjectBuilder builder = new JsonObjectBuilder();
builder.appendField("chartId", chartId);
try {
JsonObjectBuilder.JsonObject data = getChartData();
if (data == null) {
// If the data is null we don't send the chart.
return null;
}
builder.appendField("data", data);
} catch (Throwable t) {
if (logErrors) {
errorLogger.accept("Failed to get data for custom chart with id " + chartId, t);
}
return null;
}
return builder.build();
}
protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception;
}
public static class SimplePie extends CustomChart {
private final Callable<String> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SimplePie(String chartId, Callable<String> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
String value = callable.call();
if (value == null || value.isEmpty()) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("value", value).build();
}
}
public static class AdvancedBarChart extends CustomChart {
private final Callable<Map<String, int[]>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public AdvancedBarChart(String chartId, Callable<Map<String, int[]>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, int[]> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, int[]> entry : map.entrySet()) {
if (entry.getValue().length == 0) {
// Skip this invalid
continue;
}
allSkipped = false;
valuesBuilder.appendField(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
public static class SingleLineChart extends CustomChart {
private final Callable<Integer> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SingleLineChart(String chartId, Callable<Integer> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
int value = callable.call();
if (value == 0) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("value", value).build();
}
}
/**
* An extremely simple JSON builder.
*
* <p>While this class is neither feature-rich nor the most performant one, it's sufficient enough
* for its use-case.
*/
public static class JsonObjectBuilder {
private StringBuilder builder = new StringBuilder();
private boolean hasAtLeastOneField = false;
public JsonObjectBuilder() {
builder.append("{");
}
/**
* Appends a null field to the JSON.
*
* @param key The key of the field.
* @return A reference to this object.
*/
public JsonObjectBuilder appendNull(String key) {
appendFieldUnescaped(key, "null");
return this;
}
/**
* Appends a string field to the JSON.
*
* @param key The key of the field.
* @param value The value of the field.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, String value) {
if (value == null) {
throw new IllegalArgumentException("JSON value must not be null");
}
appendFieldUnescaped(key, "\"" + escape(value) + "\"");
return this;
}
/**
* Appends an integer field to the JSON.
*
* @param key The key of the field.
* @param value The value of the field.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, int value) {
appendFieldUnescaped(key, String.valueOf(value));
return this;
}
/**
* Appends an object to the JSON.
*
* @param key The key of the field.
* @param object The object.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, JsonObject object) {
if (object == null) {
throw new IllegalArgumentException("JSON object must not be null");
}
appendFieldUnescaped(key, object.toString());
return this;
}
/**
* Appends a string array to the JSON.
*
* @param key The key of the field.
* @param values The string array.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, String[] values) {
if (values == null) {
throw new IllegalArgumentException("JSON values must not be null");
}
String escapedValues =
Arrays.stream(values)
.map(value -> "\"" + escape(value) + "\"")
.collect(Collectors.joining(","));
appendFieldUnescaped(key, "[" + escapedValues + "]");
return this;
}
/**
* Appends an integer array to the JSON.
*
* @param key The key of the field.
* @param values The integer array.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, int[] values) {
if (values == null) {
throw new IllegalArgumentException("JSON values must not be null");
}
String escapedValues =
Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(","));
appendFieldUnescaped(key, "[" + escapedValues + "]");
return this;
}
/**
* Appends an object array to the JSON.
*
* @param key The key of the field.
* @param values The integer array.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, JsonObject[] values) {
if (values == null) {
throw new IllegalArgumentException("JSON values must not be null");
}
String escapedValues =
Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(","));
appendFieldUnescaped(key, "[" + escapedValues + "]");
return this;
}
/**
* Appends a field to the object.
*
* @param key The key of the field.
* @param escapedValue The escaped value of the field.
*/
private void appendFieldUnescaped(String key, String escapedValue) {
if (builder == null) {
throw new IllegalStateException("JSON has already been built");
}
if (key == null) {
throw new IllegalArgumentException("JSON key must not be null");
}
if (hasAtLeastOneField) {
builder.append(",");
}
builder.append("\"").append(escape(key)).append("\":").append(escapedValue);
hasAtLeastOneField = true;
}
/**
* Builds the JSON string and invalidates this builder.
*
* @return The built JSON string.
*/
public JsonObject build() {
if (builder == null) {
throw new IllegalStateException("JSON has already been built");
}
JsonObject object = new JsonObject(builder.append("}").toString());
builder = null;
return object;
}
/**
* Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt.
*
* <p>This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'.
* Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n").
*
* @param value The value to escape.
* @return The escaped value.
*/
private static String escape(String value) {
final StringBuilder builder = new StringBuilder();
for (int i = 0; i < value.length(); i++) {
char c = value.charAt(i);
if (c == '"') {
builder.append("\\\"");
} else if (c == '\\') {
builder.append("\\\\");
} else if (c <= '\u000F') {
builder.append("\\u000").append(Integer.toHexString(c));
} else if (c <= '\u001F') {
builder.append("\\u00").append(Integer.toHexString(c));
} else {
builder.append(c);
}
}
return builder.toString();
}
/**
* A super simple representation of a JSON object.
*
* <p>This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not
* allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String,
* JsonObject)}.
*/
public static class JsonObject {
private final String value;
private JsonObject(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
}
}

View File

@ -1,7 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.ME1312.SubServers</groupId>
@ -10,9 +8,13 @@
<packaging>jar</packaging>
<repositories>
<repository>
<id>md_5-repo</id>
<url>http://repo.md-5.net/content/repositories/snapshots/</url>
</repository>
<repository>
<id>me1312-repo</id>
<url>https://src.me1312.net/maven</url>
<url>https://dev.me1312.net/maven</url>
</repository>
</repositories>
@ -20,20 +22,26 @@
<dependency>
<groupId>net.md_5</groupId>
<artifactId>bungeecord-internal</artifactId>
<version>1.9-SNAPSHOT</version>
<version>1.15-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>msgpack-core</artifactId>
<version>0.8.16</version>
<groupId>net.ME1312.SubServers</groupId>
<artifactId>SubServers.Bungee.Common</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.imaginarycode.minecraft</groupId>
<artifactId>RedisBungee</artifactId>
<version>0.3.8-SNAPSHOT</version>
<scope>provided</scope>
<groupId>net.ME1312.SubData</groupId>
<artifactId>Server</artifactId>
<version>23w08b</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.dosse.upnp</groupId>
<artifactId>WaifUPnP</artifactId>
<version>1.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
@ -63,6 +71,7 @@
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>process</id>
<phase>process-resources</phase>
<goals>
<goal>run</goal>
@ -71,20 +80,42 @@
<tasks>
<mkdir dir="${project.build.directory}" />
<copy file="${basedir}/../LICENSE" todir="${project.build.directory}/classes" />
<copy file="${basedir}/../Artifacts/SubServers.Client.jar" tofile="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/client.jar" />
<zip basedir="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates" destfile="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates/forge.zip" includes="Forge/*" />
<delete dir="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates/Forge" />
<zip basedir="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates" destfile="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates/spigot.zip" includes="Spigot/*" />
<delete dir="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates/Spigot" />
<zip basedir="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates" destfile="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates/sponge.zip" includes="Sponge/*" />
<delete dir="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates/Sponge" />
<zip basedir="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates" destfile="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates/vanilla.zip" includes="Vanilla/*" />
<delete dir="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates/Vanilla" />
<mkdir dir="${basedir}/../Artifacts/Modulized" />
<copy file="${basedir}/../Artifacts/SubServers.Client.Universal.jar" tofile="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/client.jar" />
<mkdir dir="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates" />
<zip basedir="${basedir}/../SubServers.Creator" destfile="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates/forge.zip" includes="Forge/**" />
<zip basedir="${basedir}/../SubServers.Creator" destfile="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates/purpur.zip" includes="Purpur/**" />
<zip basedir="${basedir}/../SubServers.Creator" destfile="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates/spigot.zip" includes="Spigot/**" />
<zip basedir="${basedir}/../SubServers.Creator" destfile="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates/sponge.zip" includes="Sponge/**" />
<zip basedir="${basedir}/../SubServers.Creator" destfile="${project.build.directory}/classes/net/ME1312/SubServers/Bungee/Library/Files/Templates/vanilla.zip" includes="Vanilla/**" />
</tasks>
</configuration>
</execution>
<execution>
<id>verify</id>
<phase>verify</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks> <!-- Dependency Stripped Jar for Testing -->
<jar destfile="${basedir}/../Artifacts/Modulized/SubServers.Bungee.jar" manifest="src/META-INF/MANIFEST.MOD.MF">
<zipfileset src="${basedir}/../Artifacts/SubServers.Bungee.jar" excludes="net/ME1312/Galaxi/** net/ME1312/SubData/**" />
</jar>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<finalName>SubServers.Bungee</finalName>
<outputDirectory>../Artifacts/Maven</outputDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
@ -95,9 +126,9 @@
<archive>
<manifestFile>src/META-INF/MANIFEST.MF</manifestFile>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<descriptors>
<descriptor>../SubServers.Client/Common/jar-with-some-dependencies.xml</descriptor>
</descriptors>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
<executions>
@ -121,13 +152,22 @@
<goal>javadoc</goal>
</goals>
<configuration>
<windowtitle>SubServers.Bungee Javadoc</windowtitle>
<doctitle>SubServers.Bungee Javadoc</doctitle>
<show>public</show>
<windowtitle>SubServers.Bungee</windowtitle>
<doctitle>SubServers.Bungee ${project.version}</doctitle>
<show>protected</show>
<destDir>./</destDir>
<outputDirectory>${basedir}/../Javadoc/SubServers.Bungee</outputDirectory>
<reportOutputDirectory>${basedir}/../Javadoc/SubServers.Bungee</reportOutputDirectory>
<additionalOptions>-Xdoclint:none</additionalOptions>
<links>
<link>https://dev.me1312.net/jenkins/job/GalaxiEngine/javadoc/GalaxiBase/</link>
<link>https://dev.me1312.net/jenkins/job/SubData/javadoc/Server/</link>
<link>https://ci.md-5.net/job/BungeeCord/ws/api/target/apidocs/</link>
</links>
<includeDependencySources>true</includeDependencySources>
<dependencySourceIncludes>
<dependencySourceInclude>net.ME1312.SubServers:SubServers.Bungee.Common:*</dependencySourceInclude>
</dependencySourceIncludes>
</configuration>
</execution>
</executions>

View File

@ -0,0 +1,4 @@
Manifest-Version: 1.0
Class-Path: libraries/GalaxiBase.jar libraries/SubDataServer.jar libraries/BungeeCord.jar
Main-Class: net.ME1312.SubServers.Bungee.Launch
Implementation-Title: SubServers.Bungee

View File

@ -1,4 +1,4 @@
name: SubServers-Bungee
main: net.ME1312.SubServers.Bungee.Library.Compatibility.Plugin
version: x.x.xx
version: 2.XX.Xx
author: ME1312

View File

@ -1,9 +1,9 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.Host;
import net.ME1312.SubServers.Bungee.Host.Server;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
@ -24,7 +24,7 @@ public class SubAddHostEvent extends Event implements SubEvent, Cancellable {
* @param host Host Being Added
*/
public SubAddHostEvent(UUID player, Host host) {
if (Util.isNull(host)) throw new NullPointerException();
Util.nullpo(host);
this.player = player;
this.host = host;
}

View File

@ -1,8 +1,9 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.Proxy;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.md_5.bungee.api.plugin.Event;
/**
@ -17,7 +18,7 @@ public class SubAddProxyEvent extends Event implements SubEvent {
* @param proxy Host Being Added
*/
public SubAddProxyEvent(Proxy proxy) {
if (Util.isNull(proxy)) throw new NullPointerException();
Util.nullpo(proxy);
this.proxy = proxy;
}

View File

@ -1,9 +1,10 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.Host;
import net.ME1312.SubServers.Bungee.Host.Server;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
@ -26,7 +27,7 @@ public class SubAddServerEvent extends Event implements SubEvent, Cancellable {
* @param server Server Starting
*/
public SubAddServerEvent(UUID player, Host host, Server server) {
if (Util.isNull(server)) throw new NullPointerException();
Util.nullpo(server);
this.player = player;
this.host = host;
this.server = server;

View File

@ -1,10 +1,12 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.Galaxi.Library.Version.Version;
import net.ME1312.SubServers.Bungee.Host.Host;
import net.ME1312.SubServers.Bungee.Host.SubCreator;
import net.ME1312.SubServers.Bungee.Host.SubServer;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.Library.Version.Version;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
@ -16,6 +18,7 @@ import java.util.UUID;
public class SubCreateEvent extends Event implements SubEvent, Cancellable {
private boolean cancelled = false;
private UUID player;
private SubServer update;
private Host host;
private String name;
private SubCreator.ServerTemplate template;
@ -33,7 +36,7 @@ public class SubCreateEvent extends Event implements SubEvent, Cancellable {
* @param port Server Port Number
*/
public SubCreateEvent(UUID player, Host host, String name, SubCreator.ServerTemplate template, Version version, int port) {
if (Util.isNull(host, name, template, version, port)) throw new NullPointerException();
Util.nullpo(host, name, template);
this.player = player;
this.host = host;
this.name = name;
@ -42,6 +45,25 @@ public class SubCreateEvent extends Event implements SubEvent, Cancellable {
this.port = port;
}
/**
* Server Create Event (as an Update)
*
* @param player Player Updating
* @param server Server to be Updated
* @param template Server Template
* @param version Server Version
*/
public SubCreateEvent(UUID player, SubServer server, SubCreator.ServerTemplate template, Version version) {
Util.nullpo(server);
this.player = player;
this.update = server;
this.name = server.getName();
this.host = server.getHost();
this.template = template;
this.version = version;
this.port = server.getAddress().getPort();
}
/**
* Get the Host the SubServer will run on
*
@ -51,6 +73,24 @@ public class SubCreateEvent extends Event implements SubEvent, Cancellable {
return host;
}
/**
* Get if SubCreator is being run in update mode
*
* @return Update Mode Status
*/
public boolean isUpdate() {
return update != null;
}
/**
* Get the Server that's being updated
*
* @return Updating Server
*/
public SubServer getUpdatingServer() {
return update;
}
/**
* Get the name the SubServer will use
*

View File

@ -0,0 +1,132 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.Galaxi.Library.Version.Version;
import net.ME1312.SubServers.Bungee.Host.Host;
import net.ME1312.SubServers.Bungee.Host.SubCreator;
import net.ME1312.SubServers.Bungee.Host.SubServer;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* Server Created Event
*/
public class SubCreatedEvent extends Event implements SubEvent {
private UUID player;
private SubServer server;
private boolean success;
private boolean update;
private Host host;
private String name;
private SubCreator.ServerTemplate template;
private Version version;
private int port;
/**
* Server Created Event
*
* @param player Player Creating
* @param host Potential Host
* @param name Server Name
* @param template Server Template
* @param version Server Version
* @param port Server Port Number
* @param server Server Object
* @param update Update Mode Status
* @param success Success Status
*/
public SubCreatedEvent(UUID player, Host host, String name, SubCreator.ServerTemplate template, Version version, int port, SubServer server, boolean update, boolean success) {
Util.nullpo(host, name, template);
this.player = player;
this.host = host;
this.name = name;
this.template = template;
this.version = version;
this.port = port;
this.server = server;
this.update = update;
this.success = success;
}
/**
* Get the Host the SubServer runs on
*
* @return Host
*/
public Host getHost() {
return host;
}
/**
* Get if SubCreator was being run in update mode
*
* @return Update Mode Status
*/
public boolean wasUpdate() {
return update;
}
/**
* Get if the operation was a success
*
* @return Success Status
*/
public boolean wasSuccessful() {
return success;
}
/**
* Get the Server that was created/updated
*
* @return Finished Server
*/
public SubServer getServer() {
return server;
}
/**
* Get the name the SubServer used
*
* @return SubServer Name
*/
public String getName() {
return name;
}
/**
* Get the Template that was used
*
* @return Server Template
*/
public SubCreator.ServerTemplate getTemplate() {
return template;
}
/**
* Get the Version the Server used
*
* @return Server Version
*/
public Version getVersion() {
return version;
}
/**
* Get the Port the Server used
*
* @return Port Number
*/
public int getPort() {
return port;
}
/**
* Gets the player that triggered the Event
*
* @return The Player that triggered this Event or null if Console
*/
public UUID getPlayer() { return player; }
}

View File

@ -1,11 +1,13 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Container.ContainedPair;
import net.ME1312.Galaxi.Library.Container.Pair;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Map.ObjectMapValue;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.Server;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLValue;
import net.ME1312.SubServers.Bungee.Library.NamedContainer;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
@ -18,8 +20,7 @@ public class SubEditServerEvent extends Event implements SubEvent, Cancellable {
private boolean cancelled = false;
private UUID player;
private Server server;
private NamedContainer<String, YAMLValue> edit;
private boolean perm;
private Pair<String, ObjectMapValue> edit;
/**
* Server Edit Event
@ -27,16 +28,14 @@ public class SubEditServerEvent extends Event implements SubEvent, Cancellable {
* @param player Player Adding Server
* @param server Server to be Edited
* @param edit Edit to make
* @param permanent If the change is permanent
*/
public SubEditServerEvent(UUID player, Server server, NamedContainer<String, ?> edit, boolean permanent) {
if (Util.isNull(server, edit)) throw new NullPointerException();
YAMLSection section = new YAMLSection();
section.set(".", edit.get());
public SubEditServerEvent(UUID player, Server server, Pair<String, ?> edit) {
Util.nullpo(server, edit);
ObjectMap<String> section = new ObjectMap<String>();
section.set(".", edit.value());
this.player = player;
this.server = server;
this.edit = new NamedContainer<String, YAMLValue>(edit.name(), section.get("."));
this.perm = permanent;
this.edit = new ContainedPair<String, ObjectMapValue>(edit.key(), section.get("."));
}
/**
@ -58,19 +57,10 @@ public class SubEditServerEvent extends Event implements SubEvent, Cancellable {
*
* @return Edit to be made
*/
public NamedContainer<String, YAMLValue> getEdit() {
public Pair<String, ObjectMapValue> getEdit() {
return edit;
}
/**
* Gets if the edit is permanent
*
* @return Permanent Status
*/
public boolean isPermanent() {
return perm;
}
/**
* Gets the Cancelled Status
*

View File

@ -1,28 +1,28 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubData.Server.DataClient;
import net.ME1312.SubData.Server.DataServer;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.Network.SubDataServer;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
import java.net.InetAddress;
/**
* SubData Network Connect Event
*/
public class SubNetworkConnectEvent extends Event implements SubEvent, Cancellable {
private boolean cancelled = false;
private SubDataServer network;
private InetAddress address;
private DataServer network;
private DataClient client;
/**
* SubData Network Connect Event
*/
public SubNetworkConnectEvent(SubDataServer network, InetAddress address) {
if (Util.isNull(network, address)) throw new NullPointerException();
public SubNetworkConnectEvent(DataServer network, DataClient client) {
Util.nullpo(network, client);
this.network = network;
this.address = address;
this.client = client;
}
/**
@ -30,17 +30,17 @@ public class SubNetworkConnectEvent extends Event implements SubEvent, Cancellab
*
* @return SubData Network
*/
public SubDataServer getNetwork() {
public DataServer getNetwork() {
return network;
}
/**
* Get the address of the connecting client
* Get the connecting client
*
* @return Client address
* @return Client
*/
public InetAddress getAddress() {
return address;
public DataClient getClient() {
return client;
}
/**

View File

@ -1,25 +1,29 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubData.Server.DataClient;
import net.ME1312.SubData.Server.DataServer;
import net.ME1312.SubData.Server.Library.DisconnectReason;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.Network.Client;
import net.ME1312.SubServers.Bungee.Network.SubDataServer;
import net.md_5.bungee.api.plugin.Event;
/**
* SubData Network Disconnect Event
*/
public class SubNetworkDisconnectEvent extends Event implements SubEvent {
private SubDataServer network;
private Client client;
private DataServer network;
private DataClient client;
private DisconnectReason reason;
/**
* SubData Network Disconnect Event
*/
public SubNetworkDisconnectEvent(SubDataServer network, Client client) {
if (Util.isNull(network, client)) throw new NullPointerException();
public SubNetworkDisconnectEvent(DataServer network, DataClient client, DisconnectReason reason) {
Util.nullpo(network, client, reason);
this.network = network;
this.client = client;
this.reason = reason;
}
/**
@ -27,7 +31,7 @@ public class SubNetworkDisconnectEvent extends Event implements SubEvent {
*
* @return SubData Network
*/
public SubDataServer getNetwork() {
public DataServer getNetwork() {
return network;
}
@ -36,8 +40,16 @@ public class SubNetworkDisconnectEvent extends Event implements SubEvent {
*
* @return Client
*/
public Client getClient() {
public DataClient getClient() {
return client;
}
/**
* Get the reason the client disconnected
*
* @return Disconnect Reason
*/
public DisconnectReason getReason() {
return reason;
}
}

View File

@ -0,0 +1,43 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubData.Server.DataClient;
import net.ME1312.SubData.Server.DataServer;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.md_5.bungee.api.plugin.Event;
/**
* SubData Network Login Event
*/
public class SubNetworkLoginEvent extends Event implements SubEvent {
private DataServer network;
private DataClient client;
/**
* SubData Network Login Event
*/
public SubNetworkLoginEvent(DataServer network, DataClient client) {
Util.nullpo(network, client);
this.network = network;
this.client = client;
}
/**
* Get the network the client is connected to
*
* @return SubData Network
*/
public DataServer getNetwork() {
return network;
}
/**
* Get the connecting client
*
* @return Client
*/
public DataClient getClient() {
return client;
}
}

View File

@ -1,9 +1,9 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.Host;
import net.ME1312.SubServers.Bungee.Host.Server;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
@ -24,7 +24,7 @@ public class SubRemoveHostEvent extends Event implements SubEvent, Cancellable {
* @param host Host to be added
*/
public SubRemoveHostEvent(UUID player, Host host) {
if (Util.isNull(host)) throw new NullPointerException();
Util.nullpo(host);
this.player = player;
this.host = host;
}

View File

@ -1,8 +1,9 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.Proxy;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.md_5.bungee.api.plugin.Event;
/**
@ -17,7 +18,7 @@ public class SubRemoveProxyEvent extends Event implements SubEvent {
* @param proxy Host Being Added
*/
public SubRemoveProxyEvent(Proxy proxy) {
if (Util.isNull(proxy)) throw new NullPointerException();
Util.nullpo(proxy);
this.proxy = proxy;
}

View File

@ -1,9 +1,10 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.Host;
import net.ME1312.SubServers.Bungee.Host.Server;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
@ -26,7 +27,7 @@ public class SubRemoveServerEvent extends Event implements SubEvent, Cancellable
* @param server Server Starting
*/
public SubRemoveServerEvent(UUID player, Host host, Server server) {
if (Util.isNull(server)) throw new NullPointerException();
Util.nullpo(server);
this.player = player;
this.host = host;
this.server = server;

View File

@ -1,8 +1,9 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.SubServers.Bungee.Host.SubServer;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.Server;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
@ -14,20 +15,24 @@ import java.util.UUID;
public class SubSendCommandEvent extends Event implements SubEvent, Cancellable {
private boolean cancelled = false;
private UUID player;
private SubServer server;
private Server server;
private String command;
private UUID target;
/**
* Server Command Event
*
* @param player Player Commanding Server
* @param server Server being Commanded
* @param player Player Commanding
* @param server Target Server
* @param command Command to Send
* @param target Player that will send
*/
public SubSendCommandEvent(UUID player, SubServer server, String command) {
if (Util.isNull(server, command)) throw new NullPointerException();
public SubSendCommandEvent(UUID player, Server server, String command, UUID target) {
Util.nullpo(server, command);
this.player = player;
this.server = server;
this.command = command;
this.target = target;
}
/**
@ -35,7 +40,7 @@ public class SubSendCommandEvent extends Event implements SubEvent, Cancellable
*
* @return The Server Effected
*/
public SubServer getServer() { return server; }
public Server getServer() { return server; }
/**
* Gets the player that triggered the Event
@ -62,6 +67,15 @@ public class SubSendCommandEvent extends Event implements SubEvent, Cancellable
command = value;
}
/**
* Gets the Player that will be forced to send the Command
*
* @return Target Player or null if Console
*/
public UUID getTarget() {
return target;
}
/**
* Gets the Cancelled Status
*

View File

@ -1,8 +1,9 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.SubServer;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
@ -23,7 +24,7 @@ public class SubStartEvent extends Event implements SubEvent, Cancellable {
* @param server Server Starting
*/
public SubStartEvent(UUID player, SubServer server) {
if (Util.isNull(server)) throw new NullPointerException();
Util.nullpo(server);
this.player = player;
this.server = server;
}

View File

@ -0,0 +1,32 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.SubServer;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.md_5.bungee.api.plugin.Event;
/**
* Server Started Event
*/
public class SubStartedEvent extends Event implements SubEvent {
private SubServer server;
/**
* Server Started Event<br>
* <b>This event can only be called when a SubData connection is made!</b>
*
* @param server Server Starting
*/
public SubStartedEvent(SubServer server) {
Util.nullpo(server);
this.server = server;
}
/**
* Gets the Server Effected
*
* @return The Server Effected
*/
public SubServer getServer() { return server; }
}

View File

@ -1,8 +1,9 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.SubServer;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
@ -25,7 +26,7 @@ public class SubStopEvent extends Event implements SubEvent, Cancellable {
* @param force If it was a Forced Shutdown
*/
public SubStopEvent(UUID player, SubServer server, boolean force) {
if (Util.isNull(server, force)) throw new NullPointerException();
Util.nullpo(server, force);
this.player = player;
this.server = server;
this.force = force;

View File

@ -1,8 +1,9 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.SubServer;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.md_5.bungee.api.plugin.Event;
/**
@ -17,7 +18,7 @@ public class SubStoppedEvent extends Event implements SubEvent {
* @param server Server that Stopped
*/
public SubStoppedEvent(SubServer server) {
if (Util.isNull(server)) throw new NullPointerException();
Util.nullpo(server);
this.server = server;
}

View File

@ -1,75 +1,121 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.Galaxi.Library.Platform;
import net.ME1312.Galaxi.Library.Try;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Library.Compatibility.JNA;
import java.io.File;
import java.io.Serializable;
import java.util.stream.Stream;
/**
* Executable Variable Class
* Executable Handler Class
*/
@SuppressWarnings("serial")
public class Executable implements Serializable {
private boolean isFile;
private File File;
private String Str;
public class Executable {
private Executable() {}
private static final boolean USE_SESSION_TRACKING;
/**
* New Executable
* Format a command to be executed
*
* @param exe Executable String or File Path
* @param gitbash Git Bash location (optional)
* @param exec Executable String
* @return Formatted Executable
*/
public Executable(String exe) {
if (Util.isNull(exe)) throw new NullPointerException();
if (new File(exe).exists()) {
isFile = true;
File = new File(exe);
Str = exe;
public static String[] parse(String gitbash, String exec) {
if (exec.startsWith("java "))
exec = '\"' + System.getProperty("java.home") + File.separator + "bin" + File.separator + "java" + '\"' + exec.substring(4);
String[] cmd;
if (Platform.getSystem() == Platform.WINDOWS) {
if (gitbash != null && (exec.toLowerCase().startsWith("bash ") || exec.toLowerCase().startsWith("sh ")))
exec = '"' + gitbash + ((gitbash.endsWith(File.separator))?"":File.separator) + "bin" + File.separatorChar + "sh.exe\" -lc \"" +
exec.replace("\\", "/\\").replace("\"", "\\\"").replace("^", "^^").replace("%", "^%").replace("&", "^&").replace("<", "^<").replace(">", "^>").replace("|", "^|") + '"';
cmd = new String[]{"cmd.exe", "/q", "/c", '"'+exec+'"'};
} else if (USE_SESSION_TRACKING) {
cmd = new String[]{"setsid", "sh", "-lc", exec};
} else {
isFile = false;
File = null;
Str = exe;
cmd = new String[]{"sh", "-lc", exec};
}
return cmd;
}
static {
USE_SESSION_TRACKING = Platform.getSystem() != Platform.WINDOWS && Try.all.get(() -> {
Process test = Runtime.getRuntime().exec(new String[]{"setsid", "bash", "-c", "exit 0"});
test.waitFor(); // The purpose of this block is to test for the 'setsid' command
return test.exitValue() == 0;
}, false);
}
/**
* Get the PID of a currently running process
*
* @param process Process
* @return Process ID (null if unknown)
*/
@SuppressWarnings("JavaReflectionMemberAccess")
public static Long pid(Process process) {
if (process.isAlive()) {
try { // Java 9 Standard
return (long) Process.class.getMethod("pid").invoke(process);
} catch (Throwable e) {
try { // Java 8 Not-so-standard
Object response = Util.reflect(process.getClass().getDeclaredField("pid"), process);
if (response instanceof Number) {
return ((Number) response).longValue();
} else throw e;
} catch (Throwable e2) {
if (Platform.getSystem() == Platform.WINDOWS) try {
long handle = Util.reflect(process.getClass().getDeclaredField("handle"), process);
ClassLoader jna = JNA.get();
Class<?> pc = jna.loadClass("com.sun.jna.Pointer"),
ntc = jna.loadClass("com.sun.jna.platform.win32.WinNT$HANDLE"),
k32c = jna.loadClass("com.sun.jna.platform.win32.Kernel32");
Object k32 = k32c.getField("INSTANCE").get(null),
nt = ntc.getConstructor().newInstance();
ntc.getMethod("setPointer", pc).invoke(nt, pc.getMethod("createConstant", long.class).invoke(null, handle));
return ((Number) k32c.getMethod("GetProcessId", ntc).invoke(k32, nt)).longValue();
} catch (Throwable e3) {
// No way to find pid, I suppose.
}
}
}
}
return null;
}
/**
* Terminate a currently running process
*
* @param process Process
*/
public static void terminate(Process process) {
if (process.isAlive()) {
Long pid;
if (Platform.getSystem() == Platform.WINDOWS) {
if ((pid = pid(process)) != null) Try.all.run(() -> Runtime.getRuntime().exec(new String[]{"taskkill.exe", "/T", "/F", "/PID", pid.toString()}).waitFor());
} else if (USE_SESSION_TRACKING) {
if ((pid = pid(process)) != null) Try.all.run(() -> Runtime.getRuntime().exec(new String[]{"bash", "-c", "kill -9 $(ps -s " + pid + " -o pid=)"}).waitFor());
}
if (process.isAlive() && terminate9(process)) {
process.destroyForcibly();
}
}
}
/**
* New Executable
*
* @param path File Path
*/
public Executable(File path) {
if (Util.isNull(path)) throw new NullPointerException();
isFile = true;
File = path;
Str = path.toString();
}
@Override
public String toString() {
String String;
if (isFile) {
String = File.toString();
} else {
String = Str;
private static boolean terminate9(Object handle) {
try { // Attempt iteration over Java 9 ProcessHandle objects
Class<?> clazz = handle.getClass();
Stream<?> children = (Stream<?>) clazz.getMethod("children").invoke(handle);
clazz.getMethod("destroyForcibly").invoke(handle);
children.forEach(Executable::terminate9);
return false;
} catch (Throwable e) {
return true;
}
return String;
}
/**
* Check if the Executable String is a file
*
* @return File Status
*/
public boolean isFile() {
return isFile;
}
/**
* Get Executable File
*
* @return File or Null if Executable isn't a file
*/
public File toFile() {
return File;
}
}

View File

@ -1,24 +1,26 @@
package net.ME1312.SubServers.Bungee.Host.External;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Try;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubData.Server.ClientHandler;
import net.ME1312.SubData.Server.DataClient;
import net.ME1312.SubData.Server.Protocol.PacketOut;
import net.ME1312.SubData.Server.SubDataClient;
import net.ME1312.SubServers.Bungee.Event.SubAddServerEvent;
import net.ME1312.SubServers.Bungee.Event.SubRemoveServerEvent;
import net.ME1312.SubServers.Bungee.Host.Executable;
import net.ME1312.SubServers.Bungee.Host.Host;
import net.ME1312.SubServers.Bungee.Host.SubCreator;
import net.ME1312.SubServers.Bungee.Host.SubServer;
import net.ME1312.SubServers.Bungee.Library.Callback;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import net.ME1312.SubServers.Bungee.Library.NamedContainer;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.Network.Client;
import net.ME1312.SubServers.Bungee.Network.ClientHandler;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketExAddServer;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketExDeleteServer;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketExRemoveServer;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketOutReset;
import net.ME1312.SubServers.Bungee.Network.PacketOut;
import net.ME1312.SubServers.Bungee.SubPlugin;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketOutExReset;
import net.ME1312.SubServers.Bungee.SubProxy;
import com.google.common.collect.Range;
import java.net.InetAddress;
import java.util.*;
@ -27,77 +29,111 @@ import java.util.*;
* External Host Class
*/
public class ExternalHost extends Host implements ClientHandler {
private HashMap<Integer, SubDataClient> subdata = new HashMap<Integer, SubDataClient>();
private HashMap<String, SubServer> servers = new HashMap<String, SubServer>();
private String name;
boolean available;
private boolean enabled;
private InetAddress address;
private SubCreator creator;
private String directory;
protected NamedContainer<Boolean, Client> client;
private LinkedList<PacketOut> queue;
private boolean clean;
protected SubPlugin plugin;
SubProxy plugin;
/**
* Creates an External Host
*
* @param plugin Plugin
* @param name Name
* @param enabled Enabled Status
* @param address Address
* @param directory Directory
* @param gitBash Git Bash Location
* @param plugin SubServers Internals
* @param name The Name of your Host
* @param ports The range of ports to auto-select from
* @param log Whether apps like SubCreator should log to console (does not apply to servers)
* @param enabled If your host is Enabled
* @param address The address of your Host
* @param directory The runtime directory of your Host
* @param gitBash The Git Bash directory
*/
public ExternalHost(SubPlugin plugin, String name, Boolean enabled, InetAddress address, String directory, String gitBash) {
super(plugin, name, enabled, address, directory, gitBash);
if (Util.isNull(plugin, name, enabled, address, directory, gitBash)) throw new NullPointerException();
public ExternalHost(SubProxy plugin, String name, boolean enabled, Range<Integer> ports, boolean log, InetAddress address, String directory, String gitBash) {
super(plugin, name, enabled, ports, log, address, directory, gitBash);
this.plugin = plugin;
this.name = name;
this.available = false;
this.enabled = enabled;
this.address = address;
this.client = new NamedContainer<Boolean, Client>(false, null);
this.creator = new ExternalSubCreator(this, gitBash);
this.creator = new ExternalSubCreator(this, ports, log, gitBash);
this.directory = directory;
this.queue = new LinkedList<PacketOut>();
this.clean = false;
subdata.put(0, null);
}
@Override
public Client getSubData() {
return client.get();
public DataClient[] getSubData() {
Integer[] keys = subdata.keySet().toArray(new Integer[0]);
DataClient[] channels = new DataClient[keys.length];
Arrays.sort(keys);
for (int i = 0; i < keys.length; ++i) channels[i] = subdata.get(keys[i]);
return channels;
}
public void setSubData(DataClient client, int channel) {
if (channel < 0) throw new IllegalArgumentException("Subchannel ID cannot be less than zero");
if (client == null && channel == 0) available = false;
if (client != null || channel == 0) {
if (!subdata.containsKey(channel) || (channel == 0 && (client == null || subdata.get(channel) == null))) {
subdata.put(channel, (SubDataClient) client);
if (client != null && (client.getHandler() == null || !equals(client.getHandler()))) ((SubDataClient) client).setHandler(this);
}
} else {
subdata.remove(channel);
}
}
@Override
public void setSubData(Client client) {
this.client = new NamedContainer<Boolean, Client>(false, client);
if (client != null && (client.getHandler() == null || !equals(client.getHandler()))) client.setHandler(this);
public void removeSubData(DataClient client) {
for (Integer channel : Util.getBackwards(subdata, (SubDataClient) client)) setSubData(null, channel);
}
protected void queue(PacketOut... packet) {
for (PacketOut p : packet) if (client.get() == null || client.name() == false) {
void queue(PacketOut... packet) {
for (PacketOut p : packet) if (getSubData()[0] == null || !available) {
queue.add(p);
} else {
client.get().sendPacket(p);
((SubDataClient) getSubData()[0]).sendPacket(p);
}
}
private void requeue() {
SubDataClient client = (SubDataClient) getSubData()[0];
if (!clean) {
client.get().sendPacket(new PacketOutReset("Prevent Desync"));
client.sendPacket(new PacketOutExReset("Prevent Desync"));
clean = true;
}
HashSet<String> served = new HashSet<String>();
LinkedList<PacketOut> queue = this.queue; this.queue = new LinkedList<PacketOut>();
PacketOut[] payload = new PacketOut[queue.size()];
for (int i = 0; i < payload.length; ++i) {
PacketOut packet = queue.get(i);
if (packet instanceof PacketExAddServer) served.add(((PacketExAddServer) packet).peek());
payload[i] = packet;
}
for (SubServer server : servers.values()) {
client.get().sendPacket(new PacketExAddServer(server.getName(), server.isEnabled(), server.isLogging(), server.getPath(), ((ExternalSubServer) server).exec, server.getStopCommand(), (server.isRunning())?((ExternalSubLogger) server.getLogger()).getExternalAddress():null));
if (!served.contains(server.getName())) {
client.sendPacket(new PacketExAddServer((ExternalSubServer) server, (server.isRunning())?((ExternalSubLogger) server.getLogger()).getExternalAddress():null, data -> {
if (data.contains(0x0002)) ((ExternalSubServer) server).started(data.getUUID(0x0002));
else if (server.isRunning()) ((ExternalSubServer) server).stopped(false);
}));
}
}
while (queue.size() != 0) {
client.get().sendPacket(queue.get(0));
queue.remove(0);
client.sendPacket(payload);
available = true;
while (this.queue.size() != 0) {
client.sendPacket(this.queue.remove(0));
}
client.rename(true);
}
@Override
public boolean isAvailable() {
return this.client.name();
return available;
}
@Override
@ -137,40 +173,52 @@ public class ExternalHost extends Host implements ClientHandler {
@Override
public SubServer getSubServer(String name) {
if (Util.isNull(name)) throw new NullPointerException();
return getSubServers().get(name.toLowerCase());
if (Util.isNull(name)) return null;
return servers.get(name.toLowerCase());
}
@Override
public SubServer addSubServer(UUID player, String name, boolean enabled, int port, String motd, boolean log, String directory, Executable executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
if (plugin.api.getServers().keySet().contains(name.toLowerCase())) throw new InvalidServerException("A Server already exists with this name!");
SubServer server = new ExternalSubServer(this, name, enabled, port, motd, log, directory, executable, stopcmd, hidden, restricted);
public SubServer constructSubServer(String name, boolean enabled, int port, String motd, boolean log, String directory, String executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
return ExternalSubServer.construct(this, name, enabled, port, motd, log, directory, executable, stopcmd, hidden, restricted);
}
@Override
public boolean addSubServer(UUID player, SubServer server) throws InvalidServerException {
if (server.getHost() != this) throw new IllegalArgumentException("That Server does not belong to this Host!");
if (plugin.api.getServers().containsKey(server.getName().toLowerCase())) throw new InvalidServerException("A Server already exists with this name!");
SubAddServerEvent event = new SubAddServerEvent(player, this, server);
plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
queue(new PacketExAddServer(name, enabled, log, directory, executable, stopcmd, (server.isRunning())?((ExternalSubLogger) server.getLogger()).getExternalAddress():null));
servers.put(name.toLowerCase(), server);
return server;
queue(new PacketExAddServer(((ExternalSubServer) server), (server.isRunning())?((ExternalSubLogger) server.getLogger()).getExternalAddress():null, data -> {
if (data.contains(0x0002)) ((ExternalSubServer) server).started(data.getUUID(0x0002));
((ExternalSubServer) server).registered(true);
}));
servers.put(server.getName().toLowerCase(), server);
return true;
} else {
return null;
return false;
}
}
@Override
public boolean removeSubServer(UUID player, String name) throws InterruptedException {
if (Util.isNull(name)) throw new NullPointerException();
String server = servers.get(name.toLowerCase()).getName();
protected boolean removeSubServer(UUID player, String name, boolean forced) throws InterruptedException {
Util.nullpo(name);
ExternalSubServer server = (ExternalSubServer) servers.get(name.toLowerCase());
SubRemoveServerEvent event = new SubRemoveServerEvent(player, this, getSubServer(server));
SubRemoveServerEvent event = new SubRemoveServerEvent(player, this, server);
plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
if (getSubServer(server).isRunning()) {
getSubServer(server).stop();
getSubServer(server).waitFor();
if (forced || !event.isCancelled()) {
server.registered(false);
if (server.isRunning()) {
server.stop();
server.waitFor();
}
queue(new PacketExRemoveServer(server, data -> {
if (data.getInt("r") == 0) {
servers.remove(server.toLowerCase());
servers.remove(name.toLowerCase());
queue(new PacketExRemoveServer(name.toLowerCase(), data -> {
if (data.getInt(0x0001) != 0 && data.getInt(0x0001) != 1) {
server.registered(true);
servers.put(name.toLowerCase(), server);
}
}));
return true;
@ -178,56 +226,41 @@ public class ExternalHost extends Host implements ClientHandler {
}
@Override
public boolean forceRemoveSubServer(UUID player, String name) {
if (Util.isNull(name)) throw new NullPointerException();
String server = servers.get(name.toLowerCase()).getName();
protected boolean recycleSubServer(UUID player, String name, boolean forced) throws InterruptedException {
Util.nullpo(name);
ExternalSubServer s = (ExternalSubServer) servers.get(name.toLowerCase());
String server = s.getName();
SubRemoveServerEvent event = new SubRemoveServerEvent(player, this, getSubServer(server));
SubRemoveServerEvent event = new SubRemoveServerEvent(player, this, s);
plugin.getPluginManager().callEvent(event);
if (getSubServer(server).isRunning()) {
getSubServer(server).terminate();
}
queue(new PacketExRemoveServer(server, data -> {
if (data.getInt("r") == 0) {
servers.remove(server.toLowerCase());
}
}));
return true;
}
@Override
public boolean deleteSubServer(UUID player, String name) throws InterruptedException {
if (Util.isNull(name)) throw new NullPointerException();
String server = servers.get(name.toLowerCase()).getName();
SubRemoveServerEvent event = new SubRemoveServerEvent(player, this, getSubServer(server));
plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
if (getSubServer(server).isRunning()) {
getSubServer(server).stop();
getSubServer(server).waitFor();
if (forced || !event.isCancelled()) {
s.registered(false);
if (s.isRunning()) {
s.stop();
s.waitFor();
}
System.out.println("SubServers > Saving...");
YAMLSection info = (plugin.config.get().getSection("Servers").getKeys().contains(server))?plugin.config.get().getSection("Servers").getSection(server).clone():new YAMLSection();
Logger.get("SubServers").info("Saving...");
ObjectMap<String> info = (plugin.servers.get().getMap("Servers").getKeys().contains(server))?plugin.servers.get().getMap("Servers").getMap(server).clone():new ObjectMap<String>();
info.set("Name", server);
info.set("Timestamp", Calendar.getInstance().getTime().getTime());
try {
if (plugin.config.get().getSection("Servers").getKeys().contains(server)) {
plugin.config.get().getSection("Servers").remove(server);
plugin.config.save();
if (plugin.servers.get().getMap("Servers").getKeys().contains(server)) {
plugin.servers.get().getMap("Servers").remove(server);
plugin.servers.save();
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("SubServers > Removing Files...");
queue(new PacketExDeleteServer(server, info, data -> {
if (data.getInt("r") == 0) {
Logger.get("SubServers").info("Moving Files...");
queue(new PacketExDeleteServer(server, info, true, data -> {
if (data.getInt(0x0001) == 0 || data.getInt(0x0001) == 1) {
servers.remove(server.toLowerCase());
System.out.println("SubServers > Deleted SubServer: " + server);
Logger.get("SubServers").info("Deleted SubServer: " + server);
} else {
System.out.println("SubServers > Couldn't remove " + server + " from memory. See " + getName() + " console for more details");
s.registered(true);
Logger.get("SubServers").info("Couldn't remove " + server + " from memory. See " + getName() + " console for more details");
}
}));
return true;
@ -235,39 +268,61 @@ public class ExternalHost extends Host implements ClientHandler {
}
@Override
public boolean forceDeleteSubServer(UUID player, String name) throws InterruptedException {
if (Util.isNull(name)) throw new NullPointerException();
String server = servers.get(name.toLowerCase()).getName();
protected boolean deleteSubServer(UUID player, String name, boolean forced) throws InterruptedException {
Util.nullpo(name);
ExternalSubServer s = (ExternalSubServer) servers.get(name.toLowerCase());
String server = s.getName();
SubRemoveServerEvent event = new SubRemoveServerEvent(player, this, getSubServer(server));
plugin.getPluginManager().callEvent(event);
if (getSubServer(server).isRunning()) {
getSubServer(server).terminate();
}
System.out.println("SubServers > Saving...");
YAMLSection info = (plugin.config.get().getSection("Servers").getKeys().contains(server))?plugin.config.get().getSection("Servers").getSection(server).clone():new YAMLSection();
info.set("Name", server);
info.set("Timestamp", Calendar.getInstance().getTime().getTime());
try {
if (plugin.config.get().getSection("Servers").getKeys().contains(server)) {
plugin.config.get().getSection("Servers").remove(server);
plugin.config.save();
if (forced || !event.isCancelled()) {
s.registered(false);
if (s.isRunning()) {
s.stop();
s.waitFor();
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("SubServers > Removing Files...");
queue(new PacketExDeleteServer(server, info, data -> {
if (data.getInt("r") == 0) {
for (String group : getSubServer(server).getGroups()) getSubServer(server).removeGroup(group);
servers.remove(server.toLowerCase());
System.out.println("SubServers > Deleted SubServer: " + server);
} else {
System.out.println("SubServers > Couldn't remove " + server + " from memory. See " + getName() + " console for more details");
Logger.get("SubServers").info("Saving...");
ObjectMap<String> info = (plugin.servers.get().getMap("Servers").getKeys().contains(server))?plugin.servers.get().getMap("Servers").getMap(server).clone():new ObjectMap<String>();
info.set("Name", server);
info.set("Timestamp", Calendar.getInstance().getTime().getTime());
try {
if (plugin.servers.get().getMap("Servers").getKeys().contains(server)) {
plugin.servers.get().getMap("Servers").remove(server);
plugin.servers.save();
}
} catch (Exception e) {
e.printStackTrace();
}
}));
Logger.get("SubServers").info("Removing Files...");
queue(new PacketExDeleteServer(server, info, false, data -> {
if (data.getInt(0x0001) == 0 || data.getInt(0x0001) == 1) {
servers.remove(server.toLowerCase());
Logger.get("SubServers").info("Deleted SubServer: " + server);
} else {
s.registered(true);
Logger.get("SubServers").info("Couldn't remove " + server + " from memory. See " + getName() + " console for more details");
}
}));
return true;
} else return false;
}
@Override
public boolean destroy() {
if (Try.all.get(() -> Util.reflect(SubProxy.class.getDeclaredField("running"), plugin), true)) {
return super.destroy();
}
return true;
}
@Override
public ObjectMap<String> forSubData() {
ObjectMap<String> hinfo = super.forSubData();
ObjectMap<Integer> subdata = new ObjectMap<Integer>();
for (int channel : this.subdata.keySet()) subdata.set(channel, (this.subdata.get(channel) == null)?null:this.subdata.get(channel).getID());
hinfo.set("subdata", subdata);
return hinfo;
}
}

View File

@ -1,18 +1,38 @@
package net.ME1312.SubServers.Bungee.Host.External;
import net.ME1312.Galaxi.Library.Config.YAMLConfig;
import net.ME1312.Galaxi.Library.Container.ContainedPair;
import net.ME1312.Galaxi.Library.Container.Container;
import net.ME1312.Galaxi.Library.Container.Pair;
import net.ME1312.Galaxi.Library.Container.Value;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Try;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.Galaxi.Library.Version.Version;
import net.ME1312.SubData.Server.SubDataClient;
import net.ME1312.SubServers.Bungee.Event.SubCreateEvent;
import net.ME1312.SubServers.Bungee.Host.*;
import net.ME1312.SubServers.Bungee.Library.*;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLConfig;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.SubServers.Bungee.Library.Version.Version;
import net.ME1312.SubServers.Bungee.Event.SubCreatedEvent;
import net.ME1312.SubServers.Bungee.Host.Host;
import net.ME1312.SubServers.Bungee.Host.SubCreator;
import net.ME1312.SubServers.Bungee.Host.SubLogger;
import net.ME1312.SubServers.Bungee.Host.SubServer;
import net.ME1312.SubServers.Bungee.Host.SubServer.StopAction;
import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketExConfigureHost;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketExCreateServer;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketExDownloadTemplates;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketExUploadTemplates;
import net.ME1312.SubServers.Bungee.SubAPI;
import net.ME1312.SubServers.Bungee.SubProxy;
import com.google.common.collect.Range;
import net.md_5.bungee.api.ChatColor;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.function.Consumer;
/**
* External SubCreator Class
@ -20,109 +40,84 @@ import java.util.*;
@SuppressWarnings("unchecked")
public class ExternalSubCreator extends SubCreator {
private HashMap<String, ServerTemplate> templates = new HashMap<String, ServerTemplate>();
private HashMap<String, ServerTemplate> templatesR = new HashMap<String, ServerTemplate>();
private Boolean enableRT = false;
private ExternalHost host;
private Range<Integer> ports;
private Value<Boolean> log;
private String gitBash;
private TreeMap<String, ExternalSubLogger> thread;
private TreeMap<String, Pair<Integer, ExternalSubLogger>> thread;
/**
* Creates an External SubCreator
*
* @param host Host
* @param gitBash Git Bash
* @param ports The range of ports to auto-select from
* @param log Whether SubCreator should log to console
* @param gitBash The Git Bash directory
*/
public ExternalSubCreator(ExternalHost host, String gitBash) {
if (Util.isNull(host, gitBash)) throw new NullPointerException();
public ExternalSubCreator(ExternalHost host, Range<Integer> ports, boolean log, String gitBash) {
if (!ports.hasLowerBound() || !ports.hasUpperBound()) throw new IllegalArgumentException("Port range is not bound");
Util.nullpo(host, ports, log, gitBash);
this.host = host;
this.ports = ports;
this.log = new Container<Boolean>(log);
this.gitBash = gitBash;
this.thread = new TreeMap<String, ExternalSubLogger>();
this.thread = new TreeMap<String, Pair<Integer, ExternalSubLogger>>();
reload();
}
@Override
public void reload() {
templates.clear();
if (new UniversalFile(host.plugin.dir, "SubServers:Templates").exists()) for (File file : new UniversalFile(host.plugin.dir, "SubServers:Templates").listFiles()) {
templatesR.clear();
if (new File(host.plugin.dir, "SubServers/Templates").exists()) for (File file : new File(host.plugin.dir, "SubServers/Templates").listFiles()) {
try {
if (file.isDirectory()) {
YAMLSection config = (new UniversalFile(file, "template.yml").exists())?new YAMLConfig(new UniversalFile(file, "template.yml")).get().getSection("Template", new YAMLSection()):new YAMLSection();
ServerTemplate template = new ServerTemplate(file.getName(), config.getBoolean("Enabled", true), config.getRawString("Icon", "::NULL::"), file, config.getSection("Build", new YAMLSection()), config.getSection("Settings", new YAMLSection()));
templates.put(file.getName().toLowerCase(), template);
if (config.getKeys().contains("Display")) template.setDisplayName(config.getString("Display"));
if (file.isDirectory() && !file.getName().endsWith(".x")) {
ObjectMap<String> config = (new File(file, "template.yml").exists())? new YAMLConfig(new File(file, "template.yml")).get().getMap("Template", new ObjectMap<String>()) : new ObjectMap<String>();
ServerTemplate template = loadTemplate(file.getName(), config.getBoolean("Enabled", true), config.getBoolean("Internal", false), config.getString("Icon", "::NULL::"), file, config.getMap("Build", new ObjectMap<String>()), config.getMap("Settings", new ObjectMap<String>()));
templatesR.put(file.getName().toLowerCase(), template);
if (config.getKeys().contains("Display")) template.setDisplayName(Util.unescapeJavaString(config.getString("Display")));
}
} catch (Exception e) {
System.out.println(host.getName() + "/Creator > Couldn't load template: " + file.getName());
Logger.get(host.getName()).severe("Couldn't load template: " + file.getName());
e.printStackTrace();
}
}
if (host.client.name()) host.queue(new PacketExConfigureHost(host.plugin, host));
if (host.available && !Try.all.get(() -> Util.reflect(SubProxy.class.getDeclaredField("reloading"), host.plugin), false)) {
host.queue(new PacketExConfigureHost(host.plugin, host), new PacketExUploadTemplates(host.plugin, () -> {
if (enableRT == null || enableRT) host.queue(new PacketExDownloadTemplates(host.plugin, host));
}));
}
}
@Override
public boolean create(UUID player, String name, ServerTemplate template, Version version, int port, Callback<SubServer> callback) {
if (Util.isNull(name, template, version, port)) throw new NullPointerException();
if (host.isAvailable() && host.isEnabled() && template.isEnabled() && !SubAPI.getInstance().getSubServers().keySet().contains(name.toLowerCase()) && !SubCreator.isReserved(name)) {
StackTraceElement[] origin = new Exception().getStackTrace();
ExternalSubLogger logger = new ExternalSubLogger(this, name + File.separator + "Creator", new Container<Boolean>(host.plugin.config.get().getSection("Settings").getBoolean("Log-Creator")), null);
thread.put(name.toLowerCase(), logger);
public boolean create(UUID player, String name, ServerTemplate template, Version version, Integer port, Consumer<SubServer> callback) {
Util.nullpo(name, template);
if (host.isAvailable() && host.isEnabled() && template.isEnabled() && !SubAPI.getInstance().getSubServers().containsKey(name.toLowerCase()) && !SubCreator.isReserved(name) && (version != null || !template.requiresVersion())) {
StackTraceElement[] origin = new Throwable().getStackTrace();
if (port == null) {
Container<Integer> i = new Container<Integer>(ports.lowerEndpoint() - 1);
port = Util.getNew(getAllReservedAddresses(), () -> {
do {
++i.value;
if (i.value > ports.upperEndpoint()) throw new IllegalStateException("There are no more ports available in range: " + ports.toString());
} while (!ports.contains(i.value));
return new InetSocketAddress(host.getAddress(), i.value);
}).getPort();
}
String prefix = name + File.separator + "Creator";
ExternalSubLogger logger = new ExternalSubLogger(this, prefix, log, null);
thread.put(name.toLowerCase(), new ContainedPair<>(port, logger));
final int fport = port;
final SubCreateEvent event = new SubCreateEvent(player, host, name, template, version, port);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
logger.start();
host.queue(new PacketExCreateServer(name, template, version, port, logger.getExternalAddress(), data -> {
try {
if (data.getInt("r") == 0) {
System.out.println(name + "/Creator > Saving...");
if (host.plugin.exServers.keySet().contains(name.toLowerCase()))
host.plugin.exServers.remove(name.toLowerCase());
YAMLSection server = new YAMLSection();
YAMLSection config = new YAMLSection((Map<String, ?>) convert(data.getSection("c").get(), new NamedContainer<>("$player$", (player == null)?"":player.toString()), new NamedContainer<>("$name$", name),
new NamedContainer<>("$template$", template.getName()), new NamedContainer<>("$type$", template.getType().toString()), new NamedContainer<>("$version$", version.toString().replace(" ", "@")), new NamedContainer<>("$port$", Integer.toString(port))));
server.set("Enabled", true);
server.set("Display", "");
server.set("Host", host.getName());
server.set("Group", new ArrayList<String>());
server.set("Port", port);
server.set("Motd", "Some SubServer");
server.set("Log", true);
server.set("Directory", "." + File.separatorChar + name);
server.set("Executable", "java -Xmx1024M -jar " + template.getType().toString() + ".jar");
server.set("Stop-Command", "stop");
server.set("Stop-Action", "NONE");
server.set("Run-On-Launch", false);
server.set("Restricted", false);
server.set("Incompatible", new ArrayList<String>());
server.set("Hidden", false);
server.setAll(config);
SubServer subserver = host.addSubServer(player, name, server.getBoolean("Enabled"), port, server.getColoredString("Motd", '&'), server.getBoolean("Log"), server.getRawString("Directory"),
new Executable(server.getRawString("Executable")), server.getRawString("Stop-Command"), server.getBoolean("Hidden"), server.getBoolean("Restricted"));
if (server.getString("Display").length() > 0) subserver.setDisplayName(server.getString("Display"));
for (String group : server.getStringList("Group")) subserver.addGroup(group);
SubServer.StopAction action = Util.getDespiteException(() -> SubServer.StopAction.valueOf(server.getRawString("Stop-Action").toUpperCase().replace('-', '_').replace(' ', '_')), null);
if (action != null) subserver.setStopAction(action);
if (server.contains("Extra")) for (String extra : server.getSection("Extra").getKeys())
subserver.addExtra(extra, server.getSection("Extra").getObject(extra));
host.plugin.config.get().getSection("Servers").set(name, server);
host.plugin.config.save();
if (template.getBuildOptions().getBoolean("Run-On-Finish", true))
subserver.start();
if (callback != null) try {
callback.run(subserver);
} catch (Throwable e) {
Throwable ew = new InvocationTargetException(e);
ew.setStackTrace(origin);
ew.printStackTrace();
}
} else {
System.out.println(name + "/Creator > " + data.getString("m"));
}
} catch (Exception e) {
e.printStackTrace();
}
logger.stop();
host.queue(new PacketExCreateServer(player, name, template, version, port, logger.getExternalAddress(), data -> {
finish(player, null, name, template, version, fport, prefix, origin, data, callback);
this.thread.remove(name.toLowerCase());
}));
return true;
@ -131,33 +126,129 @@ public class ExternalSubCreator extends SubCreator {
return false;
}
} else return false;
} private Object convert(Object value, NamedContainer<String, String>... replacements) {
if (value instanceof Map) {
List<String> list = new ArrayList<String>();
list.addAll(((Map<String, Object>) value).keySet());
for (String key : list) ((Map<String, Object>) value).put(key, convert(((Map<String, Object>) value).get(key), replacements));
return value;
} else if (value instanceof Collection) {
List<Object> list = new ArrayList<Object>();
for (Object val : (Collection<Object>) value) list.add(convert(val, replacements));
return list;
} else if (value.getClass().isArray()) {
List<Object> list = new ArrayList<Object>();
for (int i = 0; i < ((Object[]) value).length; i++) list.add(convert(((Object[]) value)[i], replacements));
return list;
} else if (value instanceof String) {
return replace((String) value, replacements);
} else {
return value;
} private <T> void callback(StackTraceElement[] origin, Consumer<T> callback, T value) {
if (callback != null) try {
callback.accept(value);
} catch (Throwable e) {
Throwable ew = new InvocationTargetException(e);
ew.setStackTrace(origin);
ew.printStackTrace();
}
}
@Override
public boolean update(UUID player, SubServer server, ServerTemplate template, Version version, Consumer<Boolean> callback) {
Util.nullpo(server);
final ServerTemplate ft = (template == null)?server.getTemplate():template;
if (host.isAvailable() && host.isEnabled() && host == server.getHost() && server.isAvailable() && !server.isRunning() && ft != null && ft.isEnabled() && ft.canUpdate() && (version != null || !ft.requiresVersion())) {
StackTraceElement[] origin = new Throwable().getStackTrace();
String name = server.getName();
String prefix = name + File.separator + "Updater";
((ExternalSubServer) server).updating(true);
ExternalSubLogger logger = new ExternalSubLogger(this, prefix, log, null);
thread.put(name.toLowerCase(), new ContainedPair<>(server.getAddress().getPort(), logger));
final SubCreateEvent event = new SubCreateEvent(player, server, ft, version);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
logger.start();
host.queue(new PacketExCreateServer(player, server, ft, version, logger.getExternalAddress(), data -> {
finish(player, server, server.getName(), ft, version, server.getAddress().getPort(), prefix, origin, data, s -> {
((ExternalSubServer) server).updating(false);
if (callback != null) callback.accept(s != null);
});
this.thread.remove(name.toLowerCase());
}));
return true;
} else {
thread.remove(name.toLowerCase());
return false;
}
} else return false;
}
private void finish(UUID player, SubServer update, String name, ServerTemplate template, Version version, int port, String prefix, StackTraceElement[] origin, ObjectMap<Integer> data, Consumer<SubServer> callback) {
try {
if (data.getInt(0x0001) == 0) {
Logger.get(prefix).info("Saving...");
SubServer subserver = update;
if (update == null || update.getTemplate() != template || template.getBuildOptions().getBoolean("Update-Settings", false)) {
if (host.plugin.exServers.containsKey(name.toLowerCase()))
host.plugin.exServers.remove(name.toLowerCase());
ObjectMap<String> server = new ObjectMap<String>();
ObjectMap<String> config = new ObjectMap<String>((Map<String, ?>) data.getObject(0x0002));
if (config.contains("Directory") && (update != null || !template.getConfigOptions().contains("Directory"))) config.remove("Directory");
if (update == null) {
server.set("Enabled", true);
server.set("Display", "");
server.set("Host", host.getName());
server.set("Template", template.getName());
server.set("Group", new ArrayList<String>());
server.set("Port", port);
server.set("Motd", "Some SubServer");
server.set("Log", true);
server.set("Directory", "./" + name);
server.set("Executable", "java -Xmx1024M -jar " + template.getType().toString() + ".jar");
server.set("Stop-Command", "stop");
server.set("Stop-Action", "NONE");
server.set("Run-On-Launch", false);
server.set("Restricted", false);
server.set("Incompatible", new ArrayList<String>());
server.set("Hidden", false);
} else {
server.setAll(host.plugin.servers.get().getMap("Servers").getMap(name, new HashMap<>()));
server.set("Template", template.getName());
}
server.setAll(config);
if (update != null) Try.all.run(() -> update.getHost().forceRemoveSubServer(name));
subserver = host.constructSubServer(name, server.getBoolean("Enabled"), port, ChatColor.translateAlternateColorCodes('&', Util.unescapeJavaString(server.getString("Motd"))), server.getBoolean("Log"),
server.getString("Directory"), server.getString("Executable"), server.getString("Stop-Command"), server.getBoolean("Hidden"), server.getBoolean("Restricted"));
if (server.getString("Display").length() > 0) subserver.setDisplayName(Util.unescapeJavaString(server.getString("Display")));
subserver.setTemplate(server.getString("Template"));
for (String group : server.getStringList("Group")) subserver.addGroup(group);
SubServer.StopAction action = Try.all.get(() -> SubServer.StopAction.valueOf(server.getString("Stop-Action").toUpperCase().replace('-', '_').replace(' ', '_')));
if (action != null) subserver.setStopAction(action);
if (server.contains("Extra")) for (String extra : server.getMap("Extra").getKeys())
subserver.addExtra(extra, server.getMap("Extra").getObject(extra));
if ((update != null && host.plugin.servers.get().getMap("Servers").contains(name)) ||
!(subserver.getStopAction() == StopAction.REMOVE_SERVER || subserver.getStopAction() == StopAction.RECYCLE_SERVER || subserver.getStopAction() == StopAction.DELETE_SERVER)) {
host.plugin.servers.get().getMap("Servers").set(name, server);
host.plugin.servers.save();
}
host.addSubServer(subserver);
if (update == null && template.getBuildOptions().getBoolean("Run-On-Finish", true)) {
while (!subserver.isAvailable() && host.isAvailable()) {
Thread.sleep(250);
}
if (subserver.isAvailable()) {
subserver.start();
}
}
}
host.plugin.getPluginManager().callEvent(new SubCreatedEvent(player, host, name, template, version, port, subserver, update != null, true));
callback(origin, callback, subserver);
} else {
Logger.get(prefix).info(data.getString(0x0003));
host.plugin.getPluginManager().callEvent(new SubCreatedEvent(player, host, name, template, version, port, update, update != null, false));
callback(origin, callback, null);
}
} catch (Exception e) {
e.printStackTrace();
callback(origin, callback, null);
}
} private String replace(String string, NamedContainer<String, String>... replacements) {
for (NamedContainer<String, String> replacement : replacements) string = string.replace(replacement.name(), replacement.get());
return string;
}
@Override
public void terminate() {
HashMap<String, ExternalSubLogger> thread = new HashMap<String, ExternalSubLogger>();
HashMap<String, Pair<Integer, ExternalSubLogger>> thread = new HashMap<String, Pair<Integer, ExternalSubLogger>>();
thread.putAll(this.thread);
for (String i : thread.keySet()) {
terminate(i);
@ -166,15 +257,15 @@ public class ExternalSubCreator extends SubCreator {
@Override
public void terminate(String name) {
if (this.thread.keySet().contains(name.toLowerCase())) {
host.getSubData().sendPacket(new PacketExCreateServer(name.toLowerCase()));
if (this.thread.containsKey(name.toLowerCase())) {
((SubDataClient) host.getSubData()[0]).sendPacket(new PacketExCreateServer(name.toLowerCase()));
thread.remove(name.toLowerCase());
}
}
@Override
public void waitFor() throws InterruptedException {
HashMap<String, ExternalSubLogger> thread = new HashMap<String, ExternalSubLogger>();
HashMap<String, Pair<Integer, ExternalSubLogger>> thread = new HashMap<String, Pair<Integer, ExternalSubLogger>>();
thread.putAll(this.thread);
for (String i : thread.keySet()) {
waitFor(i);
@ -183,7 +274,7 @@ public class ExternalSubCreator extends SubCreator {
@Override
public void waitFor(String name) throws InterruptedException {
while (this.thread.keySet().contains(name.toLowerCase()) && host.client.get() != null) {
while (this.thread.containsKey(name.toLowerCase()) && host.getSubData()[0] != null) {
Thread.sleep(250);
}
}
@ -193,19 +284,47 @@ public class ExternalSubCreator extends SubCreator {
return host;
}
@Override
public Range getPortRange() {
return ports;
}
@Override
public void setPortRange(Range<Integer> value) {
if (!value.hasLowerBound() || !value.hasUpperBound()) throw new IllegalArgumentException("Port range is not bound");
ports = value;
}
@Override
public String getBashDirectory() {
return gitBash;
}
@Override
public List<SubLogger> getLogger() {
return new LinkedList<SubLogger>(thread.values());
public List<SubLogger> getLoggers() {
List<SubLogger> loggers = new ArrayList<SubLogger>();
HashMap<String, Pair<Integer, ExternalSubLogger>> temp = new HashMap<String, Pair<Integer, ExternalSubLogger>>();
temp.putAll(thread);
for (String i : temp.keySet()) {
loggers.add(getLogger(i));
}
return loggers;
}
@Override
public SubLogger getLogger(String name) {
return this.thread.get(name.toLowerCase());
return this.thread.get(name.toLowerCase()).value();
}
@Override
public boolean isLogging() {
return log.value();
}
@Override
public void setLogging(boolean value) {
Util.nullpo(value);
log.value(value);
}
@Override
@ -213,14 +332,36 @@ public class ExternalSubCreator extends SubCreator {
return new ArrayList<String>(thread.keySet());
}
@Override
public List<Integer> getReservedPorts() {
List<Integer> ports = new ArrayList<Integer>();
for (Pair<Integer, ExternalSubLogger> task : thread.values()) ports.add(task.key());
return ports;
}
@Override
public Map<String, ServerTemplate> getTemplates() {
return new TreeMap<String, ServerTemplate>(templates);
TreeMap<String, ServerTemplate> map = new TreeMap<String, ServerTemplate>();
if (enableRT != null && enableRT) for (Map.Entry<String, ServerTemplate> template : templatesR.entrySet()) {
if (!template.getValue().isInternal()) map.put(template.getKey(), template.getValue());
}
for (Map.Entry<String, ServerTemplate> template : templates.entrySet()) {
if (!template.getValue().isInternal()) map.put(template.getKey(), template.getValue());
}
return map;
}
@Override
public ServerTemplate getTemplate(String name) {
if (Util.isNull(name)) throw new NullPointerException();
return getTemplates().get(name.toLowerCase());
Util.nullpo(name);
name = name.toLowerCase();
ServerTemplate template = templates.getOrDefault(name, null);
if (template == null && enableRT != null && enableRT) template = templatesR.getOrDefault(name, null);
if (template == null || template.isInternal()) {
return null;
} else {
return template;
}
}
}

View File

@ -1,37 +1,37 @@
package net.ME1312.SubServers.Bungee.Host.External;
import net.ME1312.Galaxi.Library.Container.Value;
import net.ME1312.Galaxi.Library.Try;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.SubLogFilter;
import net.ME1312.SubServers.Bungee.Host.SubLogger;
import net.ME1312.SubServers.Bungee.Library.Container;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketInExLogMessage;
import net.ME1312.SubServers.Bungee.SubAPI;
import net.md_5.bungee.api.ProxyServer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* External Process Logger Class
*/
public class ExternalSubLogger extends SubLogger {
private Object handle;
protected UUID id = null;
protected String name;
protected Container<Boolean> log;
private List<SubLogFilter> filters = new ArrayList<SubLogFilter>();
private List<LogMessage> messages = new LinkedList<LogMessage>();
protected File file;
UUID id = null;
String name;
Value<Boolean> log;
private List<SubLogFilter> filters = new CopyOnWriteArrayList<>();
File file;
private PrintWriter writer = null;
private boolean started = false;
@ -43,7 +43,7 @@ public class ExternalSubLogger extends SubLogger {
* @param log Console Logging Status
* @param file File to log to (or null for disabled)
*/
protected ExternalSubLogger(Object user, String name, Container<Boolean> log, File file) {
ExternalSubLogger(Object user, String name, Value<Boolean> log, File file) {
this.handle = user;
this.name = name;
this.log = log;
@ -72,44 +72,21 @@ public class ExternalSubLogger extends SubLogger {
}
}
/**
* Get the External Logger Address
*
* @return External Address
*/
public UUID getExternalAddress() {
return id;
}
/**
* Log a Message
*
* @param line Message
*/
@SuppressWarnings("deprecation")
public void log(String line) {
private void log(int type, String msg) {
if (started) {
String msg = line;
Level level;
// REGEX Formatting
String type = "";
Matcher matcher = Pattern.compile("^((?:\\s*\\[?([0-9]{2}:[0-9]{2}:[0-9]{2})]?)?[\\s\\/\\\\\\|]*(?:\\[|\\[.*\\/)?(MESSAGE|INFO|WARNING|WARN|ERROR|ERR|SEVERE)\\]?:?(?:\\s*>)?\\s*)").matcher(msg.replaceAll("\u001B\\[[;\\d]*m", ""));
while (matcher.find()) {
type = matcher.group(3).toUpperCase();
}
msg = msg.substring(msg.length() - msg.replaceAll("^((?:\\s*\\[?([0-9]{2}:[0-9]{2}:[0-9]{2})]?)?[\\s\\/\\\\\\|]*(?:\\[|\\[.*\\/)?(MESSAGE|INFO|WARNING|WARN|ERROR|ERR|SEVERE)\\]?:?(?:\\s*>)?\\s*)", "").length());
// Determine LOG LEVEL
switch (type) {
case "WARNING":
case "WARN":
case 80:
level = Level.FINE;
break;
case 40:
level = Level.WARNING;
break;
case "SEVERE":
case "ERROR":
case "ERR":
case 30:
case 20:
level = Level.SEVERE;
break;
default:
@ -117,7 +94,7 @@ public class ExternalSubLogger extends SubLogger {
}
// Filter Message
boolean allow = log.get() && (!SubAPI.getInstance().getInternals().canSudo || SubAPI.getInstance().getInternals().sudo == null || SubAPI.getInstance().getInternals().sudo == getHandler());
boolean allow = (SubAPI.getInstance().getInternals().sudo == getHandler() && SubAPI.getInstance().getInternals().canSudo) || (log.value() && (SubAPI.getInstance().getInternals().sudo == null || !SubAPI.getInstance().getInternals().canSudo));
List<SubLogFilter> filters = new ArrayList<SubLogFilter>();
filters.addAll(this.filters);
for (SubLogFilter filter : filters)
@ -128,35 +105,40 @@ public class ExternalSubLogger extends SubLogger {
}
// Log to CONSOLE
if (allow) ProxyServer.getInstance().getLogger().log(level, name + " > " + msg);
// Log to MEMORY
messages.add(new LogMessage(level, msg));
if (allow) Logger.get(name).log(level, msg);
// Log to FILE
if (writer != null) {
writer.println(line);
writer.println('[' + new SimpleDateFormat("HH:mm:ss").format(Calendar.getInstance().getTime()) + "] [" + level + "] > " + msg);
writer.flush();
}
}
}
/**
* Get the External Logger Address
*
* @return External Address
*/
public UUID getExternalAddress() {
return id;
}
@Override
public void registerFilter(SubLogFilter filter) {
if (Util.isNull(filter)) throw new NullPointerException();
Util.nullpo(filter);
filters.add(filter);
}
@Override
public void unregisterFilter(SubLogFilter filter) {
if (Util.isNull(filter)) throw new NullPointerException();
filters.remove(filter);
Util.nullpo(filter);
Try.all.run(() -> filters.remove(filter));
}
@Override
public void stop() {
if (started) {
PacketInExLogMessage.unregister(id);
id = null;
started = false;
List<SubLogFilter> filters = new ArrayList<SubLogFilter>();
@ -166,11 +148,10 @@ public class ExternalSubLogger extends SubLogger {
} catch (Throwable e) {
new InvocationTargetException(e, "Exception while running SubLogger Event").printStackTrace();
}
messages.clear();
if (writer != null) {
PrintWriter writer = this.writer;
this.writer = null;
int l = (int) Math.floor((("---------- LOG START \u2014 " + name + " ----------").length() - 9) / 2);
int l = (("---------- LOG START \u2014 " + name + " ----------").length() - 9) / 2;
String s = "";
while (s.length() < l) s += '-';
writer.println(s + " LOG END " + s);
@ -191,11 +172,6 @@ public class ExternalSubLogger extends SubLogger {
@Override
public boolean isLogging() {
return log.get();
}
@Override
public List<LogMessage> getMessageHistory() {
return new LinkedList<LogMessage>(messages);
return log.value();
}
}

View File

@ -1,34 +1,41 @@
package net.ME1312.SubServers.Bungee.Host.External;
import net.ME1312.Galaxi.Library.Container.ContainedPair;
import net.ME1312.Galaxi.Library.Container.Container;
import net.ME1312.Galaxi.Library.Container.Value;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Map.ObjectMapValue;
import net.ME1312.Galaxi.Library.Try;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubData.Server.SubDataClient;
import net.ME1312.SubServers.Bungee.Event.*;
import net.ME1312.SubServers.Bungee.Host.*;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLValue;
import net.ME1312.SubServers.Bungee.Library.Container;
import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import net.ME1312.SubServers.Bungee.Library.NamedContainer;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketExUpdateServer;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketExControlServer;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketExControlServer.Action;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketOutExEditServer;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketOutExEditServer.Edit;
import net.ME1312.SubServers.Bungee.SubAPI;
import net.md_5.bungee.BungeeServerInfo;
import java.io.File;
import net.md_5.bungee.api.ChatColor;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import java.util.function.Supplier;
/**
* External SubServer Class
*/
public class ExternalSubServer extends SubServerContainer {
public class ExternalSubServer extends SubServerImpl {
private ExternalHost host;
private boolean enabled;
private Container<Boolean> log;
private Value<Boolean> log;
private String dir;
protected Executable exec;
String exec;
private String stopcmd;
private StopAction stopaction;
private LinkedList<LoggedCommand> history;
@ -52,9 +59,34 @@ public class ExternalSubServer extends SubServerContainer {
* @param restricted Restricted Status
* @throws InvalidServerException
*/
public ExternalSubServer(ExternalHost host, String name, boolean enabled, int port, String motd, boolean log, String directory, Executable executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
public static ExternalSubServer construct(ExternalHost host, String name, boolean enabled, int port, String motd, boolean log, String directory, String executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
try {
return new ExternalSubServer(host, name, enabled, port, motd, log, directory, executable, stopcmd, hidden, restricted);
} catch (NoSuchMethodError e) {
return new ExternalSubServer(host, name, enabled, (Integer) port, motd, log, directory, executable, stopcmd, hidden, restricted);
}
}
/**
* Super Method 2 (newest)
* @see #construct(ExternalHost, String, boolean, int, String, boolean, String, String, String, boolean, boolean) for method details
*/
protected ExternalSubServer(ExternalHost host, String name, boolean enabled, int port, String motd, boolean log, String directory, String executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
super(host, name, port, motd, hidden, restricted);
if (Util.isNull(host, name, enabled, port, motd, log, stopcmd, hidden, restricted)) throw new NullPointerException();
init(host, name, enabled, port, motd, log, directory, executable, stopcmd, hidden, restricted);
}
/**
* Super Method 1 (oldest)
* @see #construct(ExternalHost, String, boolean, int, String, boolean, String, String, String, boolean, boolean) for method details
*/
protected ExternalSubServer(ExternalHost host, String name, boolean enabled, Integer port, String motd, boolean log, String directory, String executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
super(host, name, port, motd, hidden, restricted);
init(host, name, enabled, port, motd, log, directory, executable, stopcmd, hidden, restricted);
}
private void init(ExternalHost host, String name, boolean enabled, int port, String motd, boolean log, String directory, String executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
Util.nullpo(host, name, enabled, port, motd, log, stopcmd, hidden, restricted);
this.host = host;
this.enabled = enabled;
this.log = new Container<Boolean>(log);
@ -69,24 +101,46 @@ public class ExternalSubServer extends SubServerContainer {
this.lock = false;
}
void registered(boolean value) {
registered = value;
}
void updating(boolean value) {
updating = value;
}
@Override
public boolean start(UUID player) {
if (!lock && isEnabled() && !running && getCurrentIncompatibilities().size() == 0) {
if (!lock && isAvailable() && isEnabled() && !running && getCurrentIncompatibilities().size() == 0) {
lock = true;
SubStartEvent event = new SubStartEvent(player, this);
host.plugin.getPluginManager().callEvent(event);
lock = false;
if (!event.isCancelled()) {
System.out.println("SubServers > Now starting " + getName());
running = true;
logger.start();
host.queue(new PacketExUpdateServer(this, PacketExUpdateServer.UpdateType.START, logger.getExternalAddress().toString()));
Logger.get("SubServers").info("Now starting " + getName());
started(null);
host.queue(new PacketExControlServer(this, Action.START, logger.getExternalAddress().toString()));
return true;
} else return false;
} else {
lock = false;
return false;
}
} else return false;
}
void started(UUID address) {
if (!running) {
stopping = false;
started = false;
running = true;
lock = false;
logger.start();
if (address != null) {
if (address != logger.getExternalAddress()) host.queue(new PacketExControlServer(this, Action.SET_LOGGING_ADDRESS, logger.getExternalAddress().toString()));
host.plugin.getPluginManager().callEvent(new SubStartEvent(null, this));
}
}
}
private void falsestart() {
System.out.println("SubServers > Couldn't start " + getName() + " - See the " + host.getName() + " console for more details");
Logger.get("SubServers").info("Couldn't start " + getName() + " - See the " + host.getName() + " console for more details");
running = false;
logger.stop();
}
@ -98,28 +152,33 @@ public class ExternalSubServer extends SubServerContainer {
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
history.add(new LoggedCommand(player, stopcmd));
host.queue(new PacketExUpdateServer(this, PacketExUpdateServer.UpdateType.STOP));
host.queue(new PacketExControlServer(this, Action.STOP));
stopping = true;
return true;
} else return false;
} else return false;
}
private void stopped(Boolean allowrestart) {
SubStoppedEvent event = new SubStoppedEvent(this);
host.plugin.getPluginManager().callEvent(event);
System.out.println("SubServers > " + getName() + " has stopped");
void stopped(Boolean allowrestart) {
logger.stop();
history.clear();
started = false;
running = false;
stopping = false;
SubStoppedEvent event = new SubStoppedEvent(this);
host.plugin.getPluginManager().callEvent(event);
Logger.get("SubServers").info(getName() + " has stopped");
if (stopaction == StopAction.REMOVE_SERVER || stopaction == StopAction.DELETE_SERVER) {
if (stopaction == StopAction.REMOVE_SERVER || stopaction == StopAction.RECYCLE_SERVER || stopaction == StopAction.DELETE_SERVER) {
try {
if (stopaction == StopAction.DELETE_SERVER) {
if (stopaction == StopAction.RECYCLE_SERVER) {
host.recycleSubServer(getName());
} else if (stopaction == StopAction.DELETE_SERVER) {
host.deleteSubServer(getName());
} else {
try {
if (host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
host.plugin.config.get().getSection("Servers").remove(getName());
host.plugin.config.save();
if (host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
host.plugin.servers.get().getMap("Servers").remove(getName());
host.plugin.servers.save();
}
} catch (IOException e) {
e.printStackTrace();
@ -138,7 +197,7 @@ public class ExternalSubServer extends SubServerContainer {
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}, "SubServers.Bungee::External_Server_Restart_Handler(" + getName() + ')').start();
}
}
}
@ -149,7 +208,8 @@ public class ExternalSubServer extends SubServerContainer {
SubStopEvent event = new SubStopEvent(player, this, true);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
host.queue(new PacketExUpdateServer(this, PacketExUpdateServer.UpdateType.TERMINATE));
host.queue(new PacketExControlServer(this, Action.TERMINATE));
stopping = true;
return true;
} else return false;
} else return false;
@ -157,306 +217,317 @@ public class ExternalSubServer extends SubServerContainer {
@Override
public boolean command(UUID player, String command) {
if (Util.isNull(command)) throw new NullPointerException();
Util.nullpo(command);
if (running) {
SubSendCommandEvent event = new SubSendCommandEvent(player, this, command);
SubSendCommandEvent event = new SubSendCommandEvent(player, this, command, null);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
if (!event.isCancelled() && (player == null || !DISALLOWED_COMMANDS.matcher(command).find())) {
history.add(new LoggedCommand(player, event.getCommand()));
if (event.getCommand().equalsIgnoreCase(stopcmd)) {
host.queue(new PacketExUpdateServer(this, PacketExUpdateServer.UpdateType.STOP));
host.queue(new PacketExControlServer(this, Action.STOP));
stopping = true;
} else {
host.queue(new PacketExUpdateServer(this, PacketExUpdateServer.UpdateType.COMMAND, event.getCommand()));
host.queue(new PacketExControlServer(this, Action.COMMAND, event.getCommand()));
}
return true;
} else return false;
} else return false;
}
@SuppressWarnings("deprecation")
public int edit(UUID player, YAMLSection edit) {
int c = 0;
boolean state = isRunning();
SubServer forward = null;
YAMLSection pending = edit.clone();
for (String key : edit.getKeys()) {
pending.remove(key);
YAMLValue value = edit.get(key);
SubEditServerEvent event = new SubEditServerEvent(player, this, new NamedContainer<String, YAMLValue>(key, value), true);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
try {
switch (key) {
case "name":
if (value.isString() && host.removeSubServer(player, getName())) {
SubServer server = host.addSubServer(player, value.asRawString(), isEnabled(), getAddress().getPort(), getMotd(), isLogging(), getPath(), getExecutable(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
YAMLSection config = this.host.plugin.config.get().getSection("Servers").getSection(getName());
this.host.plugin.config.get().getSection("Servers").remove(getName());
this.host.plugin.config.get().getSection("Servers").set(server.getName(), config);
this.host.plugin.config.save();
@SuppressWarnings({"deprecation", "unchecked"})
@Override
protected int edit(UUID player, ObjectMap<String> edit, boolean perma) {
if (isAvailable()) {
int c = 0;
boolean state = isRunning();
SubServer forward = null;
ObjectMap<String> pending = edit.clone();
for (String key : edit.getKeys()) {
pending.remove(key);
ObjectMapValue value = edit.get(key);
boolean allowed = true;
if (perma) {
SubEditServerEvent event = new SubEditServerEvent(player, this, new ContainedPair<String, ObjectMapValue>(key, value));
host.plugin.getPluginManager().callEvent(event);
allowed = !event.isCancelled();
}
if (allowed) {
try {
switch (key.toLowerCase()) {
case "name":
if (value.isString() && host.removeSubServer(player, getName())) {
SubServer server = host.constructSubServer(value.asString(), isEnabled(), getAddress().getPort(), getMotd(), isLogging(), getPath(), getExecutable(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
ObjectMap<String> config = this.host.plugin.servers.get().getMap("Servers").getMap(getName());
this.host.plugin.servers.get().getMap("Servers").remove(getName());
this.host.plugin.servers.get().getMap("Servers").set(server.getName(), config);
this.host.plugin.servers.save();
}
forward = server;
c++;
}
forward = server;
c++;
}
}
break;
case "display":
if (value.isString()) {
Field f = ServerContainer.class.getDeclaredField("nick");
f.setAccessible(true);
if (value == null || value.asString().length() == 0 || getName().equals(value)) {
f.set(this, null);
} else {
f.set(this, value.asString());
}
f.setAccessible(false);
logger.name = getDisplayName();
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
if (getName().equals(getDisplayName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).remove("Display");
} else {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Display", getDisplayName());
}
this.host.plugin.config.save();
}
c++;
}
break;
case "enabled":
if (value.isBoolean()) {
if (enabled != value.asBoolean()) host.queue(new PacketExUpdateServer(this, PacketExUpdateServer.UpdateType.SET_ENABLED, (Boolean) value.asBoolean()));
enabled = value.asBoolean();
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Enabled", isEnabled());
this.host.plugin.config.save();
}
c++;
}
break;
case "group":
if (value.isList()) {
Field f = ServerContainer.class.getDeclaredField("groups");
f.setAccessible(true);
f.set(this, value.asStringList());
f.setAccessible(false);
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Group", value.asStringList());
this.host.plugin.config.save();
}
c++;
}
break;
case "host":
if (value.isString() && host.removeSubServer(player, getName())) {
waitFor(() -> host.getSubServer(getName()), null);
SubServer server = this.host.plugin.api.getHost(value.asRawString()).addSubServer(player, getName(), isEnabled(), getAddress().getPort(), getMotd(), isLogging(), getPath(), getExecutable(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Host", server.getHost().getName());
this.host.plugin.config.save();
}
forward = server;
c++;
}
}
break;
case "port":
if (value.isNumber() && host.removeSubServer(player, getName())) {
waitFor(() -> host.getSubServer(getName()), null);
SubServer server = host.addSubServer(player, getName(), isEnabled(), value.asInt(), getMotd(), isLogging(), getPath(), getExecutable(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Port", server.getAddress().getPort());
this.host.plugin.config.save();
}
forward = server;
c++;
}
}
break;
case "motd":
if (value.isString()) {
Field f = BungeeServerInfo.class.getDeclaredField("motd");
f.setAccessible(true);
f.set(this, value.asColoredString('&'));
f.setAccessible(false);
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Motd", value.asString());
this.host.plugin.config.save();
}
c++;
}
break;
case "log":
if (value.isBoolean()) {
if (log.get() != value.asBoolean()) host.queue(new PacketExUpdateServer(this, PacketExUpdateServer.UpdateType.SET_LOGGING, (Boolean) value.asBoolean()));
log.set(value.asBoolean());
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Log", isLogging());
this.host.plugin.config.save();
}
c++;
}
break;
case "dir":
if (value.isString() && host.removeSubServer(player, getName())) {
waitFor(() -> host.getSubServer(getName()), null);
SubServer server = host.addSubServer(player, getName(), isEnabled(), getAddress().getPort(), getMotd(), isLogging(), value.asRawString(), getExecutable(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Directory", server.getPath());
this.host.plugin.config.save();
}
forward = server;
c++;
}
}
break;
case "exec":
if (value.isString() && host.removeSubServer(player, getName())) {
waitFor(() -> host.getSubServer(getName()), null);
SubServer server = host.addSubServer(player, getName(), isEnabled(), getAddress().getPort(), getMotd(), isLogging(), getPath(), new Executable(value.asRawString()), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Executable", value.asRawString());
this.host.plugin.config.save();
}
forward = server;
c++;
}
}
break;
case "state":
if (value.isBoolean()) {
state = value.asBoolean();
}
break;
case "stop-cmd":
if (value.isString()) {
if (!stopcmd.equals(value)) host.queue(new PacketExUpdateServer(this, PacketExUpdateServer.UpdateType.SET_STOP_COMMAND, value.asRawString()));
stopcmd = value.asRawString();
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Stop-Command", getStopCommand());
this.host.plugin.config.save();
}
c++;
}
break;
case "stop-action":
if (value.isString()) {
StopAction action = Util.getDespiteException(() -> StopAction.valueOf(value.asRawString().toUpperCase().replace('-', '_').replace(' ', '_')), null);
if (action != null) {
stopaction = action;
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Stop-Action", getStopAction().toString());
this.host.plugin.config.save();
break;
case "display":
if (value.isString()) {
setDisplayName(value.asString());
logger.name = getDisplayName();
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
if (getName().equals(getDisplayName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).remove("Display");
} else {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Display", getDisplayName());
}
this.host.plugin.servers.save();
}
c++;
}
}
break;
case "auto-run":
if (value.isBoolean()) {
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Run-On-Launch", value.asBoolean());
this.host.plugin.config.save();
break;
case "enabled":
if (value.isBoolean()) {
if (enabled != value.asBoolean()) host.queue(new PacketExControlServer(this, Action.SET_ENABLED, (Boolean) value.asBoolean()));
enabled = value.asBoolean();
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Enabled", isEnabled());
this.host.plugin.servers.save();
}
c++;
}
c++;
}
break;
case "incompatible":
if (value.isList()) {
for (String oname : value.asStringList()) {
SubServer oserver = host.plugin.api.getSubServer(oname);
if (oserver != null && isCompatible(oserver)) toggleCompatibility(oserver);
break;
case "group":
if (value.isList()) {
Util.reflect(ServerImpl.class.getDeclaredField("groups"), this, value.asStringList());
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Group", value.asStringList());
this.host.plugin.servers.save();
}
c++;
}
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Incompatible", value.asStringList());
this.host.plugin.config.save();
break;
case "host":
if (value.isString() && host.removeSubServer(player, getName())) {
waitFor(() -> host.getSubServer(getName()), null);
SubServer server = this.host.plugin.api.getHost(value.asString()).constructSubServer(getName(), isEnabled(), getAddress().getPort(), getMotd(), isLogging(), getPath(), getExecutable(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Host", server.getHost().getName());
this.host.plugin.servers.save();
}
forward = server;
c++;
}
}
c++;
}
break;
case "restricted":
if (value.isBoolean()) {
Field f = BungeeServerInfo.class.getDeclaredField("restricted");
f.setAccessible(true);
f.set(this, value.asBoolean());
f.setAccessible(false);
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Restricted", isRestricted());
this.host.plugin.config.save();
break;
case "template":
if (value.isString()) {
setTemplate(value.asString());
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Template", value.asString());
this.host.plugin.servers.save();
}
c++;
}
c++;
}
break;
case "hidden":
if (value.isBoolean()) {
Field f = ServerContainer.class.getDeclaredField("hidden");
f.setAccessible(true);
f.set(this, value.asBoolean());
f.setAccessible(false);
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Hidden", isHidden());
this.host.plugin.config.save();
break;
case "port":
if (value.isNumber() && host.removeSubServer(player, getName())) {
waitFor(() -> host.getSubServer(getName()), null);
SubServer server = host.constructSubServer(getName(), isEnabled(), value.asInt(), getMotd(), isLogging(), getPath(), getExecutable(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Port", server.getAddress().getPort());
this.host.plugin.servers.save();
}
forward = server;
c++;
}
}
c++;
}
break;
}
if (forward != null) {
forward.setStopAction(getStopAction());
if (!getName().equals(getDisplayName())) forward.setDisplayName(getDisplayName());
List<String> groups = new ArrayList<String>();
groups.addAll(getGroups());
for (String group : groups) {
removeGroup(group);
forward.addGroup(group);
break;
case "motd":
if (value.isString()) {
setMotd(ChatColor.translateAlternateColorCodes('&', Util.unescapeJavaString(value.asString())));
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Motd", value.asString());
this.host.plugin.servers.save();
}
c++;
}
break;
case "log":
if (value.isBoolean()) {
if (log.value() != value.asBoolean()) host.queue(new PacketExControlServer(this, Action.SET_LOGGING, (Boolean) value.asBoolean()));
log.value(value.asBoolean());
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Log", isLogging());
this.host.plugin.servers.save();
}
c++;
}
break;
case "dir":
case "directory":
if (value.isString() && host.removeSubServer(player, getName())) {
waitFor(() -> host.getSubServer(getName()), null);
SubServer server = host.constructSubServer(getName(), isEnabled(), getAddress().getPort(), getMotd(), isLogging(), value.asString(), getExecutable(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Directory", server.getPath());
this.host.plugin.servers.save();
}
forward = server;
c++;
}
}
break;
case "exec":
case "executable":
if (value.isString() && host.removeSubServer(player, getName())) {
waitFor(() -> host.getSubServer(getName()), null);
SubServer server = host.constructSubServer(getName(), isEnabled(), getAddress().getPort(), getMotd(), isLogging(), getPath(), value.asString(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Executable", value.asString());
this.host.plugin.servers.save();
}
forward = server;
c++;
}
}
break;
case "state":
if (value.isBoolean()) {
state = value.asBoolean();
}
break;
case "stop-cmd":
case "stop-command":
if (value.isString()) {
if (!stopcmd.equals(value.asString())) host.queue(new PacketExControlServer(this, Action.SET_STOP_COMMAND, value.asString()));
stopcmd = value.asString();
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Stop-Command", getStopCommand());
this.host.plugin.servers.save();
}
c++;
}
break;
case "stop-action":
if (value.isString()) {
StopAction action = Try.all.get(() -> StopAction.valueOf(value.asString().toUpperCase().replace('-', '_').replace(' ', '_')));
if (action != null) {
stopaction = action;
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Stop-Action", getStopAction().toString());
this.host.plugin.servers.save();
}
c++;
}
}
break;
case "auto-run":
case "run-on-launch":
if (value.isBoolean()) {
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Run-On-Launch", value.asBoolean());
this.host.plugin.servers.save();
}
c++;
}
break;
case "incompatible":
if (value.isList()) {
for (SubServer oserver : getIncompatibilities()) toggleCompatibility(oserver);
for (String oname : (List<String>) value.asStringList()) {
SubServer oserver = host.plugin.api.getSubServer(oname);
if (oserver != null && isCompatible(oserver)) toggleCompatibility(oserver);
}
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Incompatible", value.asStringList());
this.host.plugin.servers.save();
}
c++;
}
break;
case "restricted":
if (value.isBoolean()) {
setRestricted(value.asBoolean());
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Restricted", isRestricted());
this.host.plugin.servers.save();
}
c++;
}
break;
case "hidden":
if (value.isBoolean()) {
setHidden(value.asBoolean());
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Hidden", isHidden());
this.host.plugin.servers.save();
}
c++;
}
break;
case "whitelist":
if (value.isList()) {
Util.reflect(ServerImpl.class.getDeclaredField("whitelist"), this, value.asUUIDList());
if (isRegistered()) for (Proxy proxy : SubAPI.getInstance().getProxies().values()) if (proxy.getSubData()[0] != null) {
((SubDataClient) proxy.getSubData()[0]).sendPacket(new PacketOutExEditServer(this, Edit.WHITELIST_SET, value.asUUIDList()));
}
c++;
}
break;
}
for (SubServer server : getIncompatibilities()) {
toggleCompatibility(server);
forward.toggleCompatibility(server);
}
for (String extra : getExtra().getKeys()) forward.addExtra(extra, getExtra(extra));
if (forward != null) {
forward.setStopAction(getStopAction());
if (!getName().equals(getDisplayName())) forward.setDisplayName(getDisplayName());
List<String> groups = new ArrayList<String>();
forward.setTemplate(getTemplate());
groups.addAll(getGroups());
for (String group : groups) {
removeGroup(group);
forward.addGroup(group);
}
for (SubServer server : getIncompatibilities()) {
toggleCompatibility(server);
forward.toggleCompatibility(server);
}
for (String extra : getExtra().getKeys()) forward.addExtra(extra, getExtra(extra));
if (state) pending.set("state", true);
c += forward.edit(player, pending);
break;
if (state) pending.set("state", true);
c += (perma)?forward.permaEdit(player, pending):forward.edit(player, pending);
break;
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (!isRunning() && forward == null && state) start(player);
return c;
} private <V> void waitFor(Util.ReturnRunnable<V> method, V value) throws InterruptedException {
while (method.run() != value) {
if (!isRunning() && forward == null && state) start(player);
return c;
} else return -1;
} private <V> void waitFor(Supplier<V> method, V value) throws InterruptedException {
while (method.get() != value) {
Thread.sleep(250);
}
}
@Override
public void waitFor() throws InterruptedException {
while (running && host.client.get() != null) {
while (running && host.getSubData()[0] != null) {
Thread.sleep(250);
}
}
@Override
public boolean isRunning() {
return running;
return running || lock;
}
@Override
public void setDisplayName(String value) {
super.setDisplayName(value);
logger.name = getDisplayName();
host.plugin.getPluginManager().callEvent(new SubEditServerEvent(null, this, new NamedContainer<String, Object>("display", value), false));
}
@Override
@ -466,28 +537,26 @@ public class ExternalSubServer extends SubServerContainer {
@Override
public boolean isEnabled() {
return enabled;
return enabled && host.isEnabled();
}
@Override
public void setEnabled(boolean value) {
if (Util.isNull(value)) throw new NullPointerException();
host.plugin.getPluginManager().callEvent(new SubEditServerEvent(null, this, new NamedContainer<String, Object>("enabled", value), false));
if (enabled != value) host.queue(new PacketExUpdateServer(this, PacketExUpdateServer.UpdateType.SET_ENABLED, (Boolean) value));
Util.nullpo(value);
if (enabled != value) host.queue(new PacketExControlServer(this, Action.SET_ENABLED, (Boolean) value));
enabled = value;
}
@Override
public boolean isLogging() {
return log.get();
return log.value();
}
@Override
public void setLogging(boolean value) {
if (Util.isNull(value)) throw new NullPointerException();
host.plugin.getPluginManager().callEvent(new SubEditServerEvent(null, this, new NamedContainer<String, Object>("log", value), false));
if (log.get() != value) host.queue(new PacketExUpdateServer(this, PacketExUpdateServer.UpdateType.SET_LOGGING, (Boolean) value));
log.set(value);
Util.nullpo(value);
if (log.value() != value) host.queue(new PacketExControlServer(this, Action.SET_LOGGING, (Boolean) value));
log.value(value);
}
@Override
@ -506,7 +575,7 @@ public class ExternalSubServer extends SubServerContainer {
}
@Override
public Executable getExecutable() {
public String getExecutable() {
return exec;
}
@ -517,9 +586,8 @@ public class ExternalSubServer extends SubServerContainer {
@Override
public void setStopCommand(String value) {
if (Util.isNull(value)) throw new NullPointerException();
host.plugin.getPluginManager().callEvent(new SubEditServerEvent(null, this, new NamedContainer<String, Object>("stop-cmd", value), false));
if (!stopcmd.equals(value)) host.queue(new PacketExUpdateServer(this, PacketExUpdateServer.UpdateType.SET_STOP_COMMAND, value));
Util.nullpo(value);
if (!stopcmd.equals(value)) host.queue(new PacketExControlServer(this, Action.SET_STOP_COMMAND, value));
stopcmd = value;
}
@ -530,8 +598,7 @@ public class ExternalSubServer extends SubServerContainer {
@Override
public void setStopAction(StopAction action) {
if (Util.isNull(action)) throw new NullPointerException();
host.plugin.getPluginManager().callEvent(new SubEditServerEvent(null, this, new NamedContainer<String, Object>("stop-action", action), false));
Util.nullpo(action);
stopaction = action;
}
}

View File

@ -1,25 +1,29 @@
package net.ME1312.SubServers.Bungee.Host;
import com.google.gson.Gson;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLValue;
import net.ME1312.Galaxi.Library.ExtraDataHandler;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Map.ObjectMapValue;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidHostException;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import net.ME1312.SubServers.Bungee.Library.ExtraDataHandler;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.Network.ClientHandler;
import net.ME1312.SubServers.Bungee.Network.SubDataServer;
import net.ME1312.SubServers.Bungee.SubPlugin;
import net.ME1312.SubServers.Bungee.SubAPI;
import net.ME1312.SubServers.Bungee.SubProxy;
import com.google.common.collect.Range;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.net.InetAddress;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Map;
import java.util.UUID;
/**
* Host Layout Class
*/
public abstract class Host implements ExtraDataHandler {
private YAMLSection extra = new YAMLSection();
public abstract class Host implements ExtraDataHandler<String> {
private final ObjectMap<String> extra = new ObjectMap<String>();
private final String signature;
private String nick = null;
@ -28,15 +32,20 @@ public abstract class Host implements ExtraDataHandler {
*
* @param plugin SubServers Internals
* @param name The Name of your Host
* @param ports The range of ports to auto-select from
* @param log Whether apps like SubCreator should log to console (does not apply to servers)
* @param enabled If your host is Enabled
* @param address The address of your Host
* @param directory The runtime directory of your Host
* @param gitBash The Git Bash directory
*/
public Host(SubPlugin plugin, String name, Boolean enabled, InetAddress address, String directory, String gitBash) {
@SuppressWarnings("deprecation")
public Host(SubProxy plugin, String name, boolean enabled, Range<Integer> ports, boolean log, InetAddress address, String directory, String gitBash) {
if (name.contains(" ")) throw new InvalidHostException("Host names cannot have spaces: " + name);
if (!ports.hasLowerBound() || !ports.hasUpperBound()) throw new InvalidHostException("Port range is not bound");
Util.nullpo(plugin, name, enabled, ports, log, address, directory, gitBash);
signature = plugin.api.signAnonymousObject();
SubDataServer.allowConnection(address.getHostAddress());
SubAPI.getInstance().getInternals().subprotocol.whitelist(address.getHostAddress());
}
/**
@ -105,6 +114,32 @@ public abstract class Host implements ExtraDataHandler {
}
}
/**
* Get players on servers provided by this host
*
* @return Local Player Collection
*/
public Collection<ProxiedPlayer> getPlayers() {
LinkedList<ProxiedPlayer> players = new LinkedList<ProxiedPlayer>();
for (SubServer server : getSubServers().values()) {
players.addAll(server.getPlayers());
}
return players;
}
/**
* Get players on servers provided by this host across all known proxies
*
* @return Remote Player Collection
*/
public Collection<RemotePlayer> getRemotePlayers() {
LinkedList<RemotePlayer> players = new LinkedList<RemotePlayer>();
for (SubServer server : getSubServers().values()) {
players.addAll(server.getRemotePlayers());
}
return players;
}
/**
* Starts the Servers Specified
*
@ -230,23 +265,22 @@ public abstract class Host implements ExtraDataHandler {
public abstract SubServer getSubServer(String name);
/**
* Adds a SubServer
* Constructs a SubServer (but doesn't add it to the server manager)
*
* @param player Player who Added
* @param name Name of Server
* @param enabled Enabled Status
* @param port Port Number
* @param motd Motd of the Server
* @param log Logging Status
* @param directory Directory
* @param executable Executable
* @param executable Executable String
* @param stopcmd Command to Stop the Server
* @param hidden if the server should be hidden from players
* @param restricted Players will need a permission to join if true
* @return The SubServer
* @throws InvalidServerException
*/
public abstract SubServer addSubServer(UUID player, String name, boolean enabled, int port, String motd, boolean log, String directory, Executable executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException;
public abstract SubServer constructSubServer(String name, boolean enabled, int port, String motd, boolean log, String directory, String executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException;
/**
* Adds a SubServer
@ -257,17 +291,58 @@ public abstract class Host implements ExtraDataHandler {
* @param motd Motd of the Server
* @param log Logging Status
* @param directory Directory
* @param executable Executable
* @param executable Executable String
* @param stopcmd Command to Stop the Server
* @param hidden if the server should be hidden from players
* @param restricted Players will need a permission to join if true
* @return The SubServer
* @throws InvalidServerException
*/
public SubServer addSubServer(String name, boolean enabled, int port, String motd, boolean log, String directory, Executable executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
public SubServer addSubServer(String name, boolean enabled, int port, String motd, boolean log, String directory, String executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
return addSubServer(null, name, enabled, port, motd, log, directory, executable, stopcmd, hidden, restricted);
}
/**
* Adds a SubServer
*
* @param player Player who Added
* @param name Name of Server
* @param enabled Enabled Status
* @param port Port Number
* @param motd Motd of the Server
* @param log Logging Status
* @param directory Directory
* @param executable Executable String
* @param stopcmd Command to Stop the Server
* @param hidden if the server should be hidden from players
* @param restricted Players will need a permission to join if true
* @return The SubServer
* @throws InvalidServerException
*/
public SubServer addSubServer(UUID player, String name, boolean enabled, int port, String motd, boolean log, String directory, String executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
SubServer server = constructSubServer(name, enabled, port, motd, log, directory, executable, stopcmd, hidden, restricted);
return (addSubServer(player, server))?server:null;
}
/**
* Adds a SubServer
*
* @param server SubServer to add
* @return Success status
*/
public boolean addSubServer(SubServer server) throws InvalidServerException {
return addSubServer(null, server);
}
/**
* Adds a SubServer
*
* @param player Player who added
* @param server SubServer to add
* @return Success status
*/
public abstract boolean addSubServer(UUID player, SubServer server) throws InvalidServerException;
/**
* Removes a SubServer
*
@ -277,7 +352,7 @@ public abstract class Host implements ExtraDataHandler {
*/
public boolean removeSubServer(String name) throws InterruptedException {
return removeSubServer(null, name);
};
}
/**
* Removes a SubServer
@ -287,12 +362,26 @@ public abstract class Host implements ExtraDataHandler {
* @throws InterruptedException
* @return Success Status
*/
public abstract boolean removeSubServer(UUID player, String name) throws InterruptedException;
public boolean removeSubServer(UUID player, String name) throws InterruptedException {
return removeSubServer(player, name, false);
}
/**
* Removes a SubServer
*
* @param player Player Removing
* @param name SubServer Name
* @param forced Forces the Removal
* @throws InterruptedException
* @return Success Status
*/
protected abstract boolean removeSubServer(UUID player, String name, boolean forced) throws InterruptedException;
/**
* Forces the Removal of a SubServer
*
* @param name SubServer Name
* @return Success Status
*/
public boolean forceRemoveSubServer(String name) throws InterruptedException {
return forceRemoveSubServer(null, name);
@ -303,11 +392,66 @@ public abstract class Host implements ExtraDataHandler {
*
* @param player Player Removing
* @param name SubServer Name
* @return Success Status
*/
public abstract boolean forceRemoveSubServer(UUID player, String name) throws InterruptedException;
public boolean forceRemoveSubServer(UUID player, String name) throws InterruptedException {
return removeSubServer(player, name, true);
}
/**
* Delete a SubServer
* Deletes a SubServer (will move to 'Recently Deleted')
*
* @param name SubServer Name
* @return Success Status
*/
public boolean recycleSubServer(String name) throws InterruptedException {
return recycleSubServer(null, name);
}
/**
* Deletes a SubServer (will move to 'Recently Deleted')
*
* @param player Player Deleting
* @param name SubServer Name
* @return Success Status
*/
public boolean recycleSubServer(UUID player, String name) throws InterruptedException {
return recycleSubServer(player, name, false);
}
/**
* Deletes a SubServer (will move to 'Recently Deleted')
*
* @param player Player Deleting
* @param name SubServer Name
* @param forced Forces the Deletion
* @return Success Status
*/
protected abstract boolean recycleSubServer(UUID player, String name, boolean forced) throws InterruptedException;
/**
* Forces the Deletion of a SubServer (will move to 'Recently Deleted')
*
* @param name SubServer Name
* @return Success Status
*/
public boolean forceRecycleSubServer(String name) throws InterruptedException {
return forceRecycleSubServer(null, name);
}
/**
* Forces the Deletion of a SubServer (will move to 'Recently Deleted')
*
* @param player Player Deleting
* @param name SubServer Name
* @return Success Status
*/
public boolean forceRecycleSubServer(UUID player, String name) throws InterruptedException {
return recycleSubServer(player, name, true);
}
/**
* Deletes a SubServer
*
* @param name SubServer Name
* @return Success Status
@ -317,22 +461,34 @@ public abstract class Host implements ExtraDataHandler {
}
/**
* Delete a SubServer
* Deletes a SubServer
*
* @param player Player Deleting
* @param name SubServer Name
* @return Success Status
*/
public abstract boolean deleteSubServer(UUID player, String name) throws InterruptedException;
public boolean deleteSubServer(UUID player, String name) throws InterruptedException {
return deleteSubServer(player, name, false);
}
/**
* Forced the Deletion of a SubServer
* Deletes a SubServer
*
* @param player Player Deleting
* @param name SubServer Name
* @param forced Forces the Deletion
* @return Success Status
*/
protected abstract boolean deleteSubServer(UUID player, String name, boolean forced) throws InterruptedException;
/**
* Forces the Deletion of a SubServer
*
* @param name SubServer Name
* @return Success Status
*/
public boolean forceDeleteSubServer(String name) throws InterruptedException {
return deleteSubServer(null, name);
return forceDeleteSubServer(null, name);
}
/**
@ -342,7 +498,32 @@ public abstract class Host implements ExtraDataHandler {
* @param name SubServer Name
* @return Success Status
*/
public abstract boolean forceDeleteSubServer(UUID player, String name) throws InterruptedException;
public boolean forceDeleteSubServer(UUID player, String name) throws InterruptedException {
return deleteSubServer(player, name, true);
}
/**
* Resets this Host object
*
* @return Success Status
*/
@SuppressWarnings("unchecked")
public boolean destroy() {
try {
Map.Entry<String, SubServer>[] subservers = getSubServers().entrySet().toArray(new Map.Entry[0]);
for (Map.Entry<String, SubServer> entry : subservers) {
if (entry.getValue().isRunning()) Logger.get("SubServers").info("Stopping " + entry.getValue().getName());
forceRemoveSubServer(entry.getKey());
}
getCreator().terminate();
getCreator().waitFor();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* Get the Signature of this Object
@ -353,39 +534,42 @@ public abstract class Host implements ExtraDataHandler {
return signature;
}
@Override
public boolean equals(Object obj) {
return obj instanceof Host && signature.equals(((Host) obj).signature);
}
@Override
public void addExtra(String handle, Object value) {
if (Util.isNull(handle, value)) throw new NullPointerException();
Util.nullpo(handle, value);
extra.set(handle, value);
}
@Override
public boolean hasExtra(String handle) {
if (Util.isNull(handle)) throw new NullPointerException();
Util.nullpo(handle);
return extra.getKeys().contains(handle);
}
@Override
public YAMLValue getExtra(String handle) {
if (Util.isNull(handle)) throw new NullPointerException();
public ObjectMapValue getExtra(String handle) {
Util.nullpo(handle);
return extra.get(handle);
}
@Override
public YAMLSection getExtra() {
public ObjectMap<String> getExtra() {
return extra.clone();
}
@Override
public void removeExtra(String handle) {
if (Util.isNull(handle)) throw new NullPointerException();
Util.nullpo(handle);
extra.remove(handle);
}
@Override
@SuppressWarnings("unchecked")
public String toString() {
YAMLSection hinfo = new YAMLSection();
public ObjectMap<String> forSubData() {
ObjectMap<String> hinfo = new ObjectMap<String>();
hinfo.set("type", "Host");
hinfo.set("name", getName());
hinfo.set("display", getDisplayName());
@ -394,21 +578,20 @@ public abstract class Host implements ExtraDataHandler {
hinfo.set("address", getAddress().getHostAddress());
hinfo.set("dir", getPath());
YAMLSection cinfo = new YAMLSection();
YAMLSection templates = new YAMLSection();
ObjectMap<String> cinfo = new ObjectMap<String>();
ObjectMap<String> templates = new ObjectMap<String>();
for (SubCreator.ServerTemplate template : getCreator().getTemplates().values())
templates.set(template.getName(), new YAMLSection(new Gson().fromJson(template.toString(), Map.class)));
templates.set(template.getName(), template.forSubData());
cinfo.set("templates", templates);
hinfo.set("creator", cinfo);
YAMLSection servers = new YAMLSection();
ObjectMap<String> servers = new ObjectMap<String>();
for (SubServer server : getSubServers().values()) {
servers.set(server.getName(), new YAMLSection(new Gson().fromJson(server.toString(), Map.class)));
servers.set(server.getName(), server.forSubData());
}
hinfo.set("servers", servers);
if (this instanceof ClientHandler && ((ClientHandler) this).getSubData() != null) hinfo.set("subdata", ((ClientHandler) this).getSubData().getAddress().toString());
hinfo.set("signature", signature);
hinfo.set("extra", getExtra());
return hinfo.toJSON();
return hinfo;
}
}

View File

@ -1,16 +1,21 @@
package net.ME1312.SubServers.Bungee.Host.Internal;
import net.ME1312.Galaxi.Library.Config.YAMLSection;
import net.ME1312.Galaxi.Library.Directories;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Event.SubAddServerEvent;
import net.ME1312.SubServers.Bungee.Event.SubRemoveServerEvent;
import net.ME1312.SubServers.Bungee.Host.Executable;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import net.ME1312.SubServers.Bungee.Host.Host;
import net.ME1312.SubServers.Bungee.Host.SubCreator;
import net.ME1312.SubServers.Bungee.Host.SubServer;
import net.ME1312.SubServers.Bungee.Library.UniversalFile;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.SubPlugin;
import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import net.ME1312.SubServers.Bungee.SubProxy;
import com.dosse.upnp.UPnP;
import com.google.common.collect.Range;
import com.google.gson.Gson;
import java.io.File;
import java.io.FileWriter;
@ -28,27 +33,28 @@ public class InternalHost extends Host {
private InetAddress address;
private SubCreator creator;
private String directory;
protected SubPlugin plugin;
SubProxy plugin;
/**
* Creates an Internal Host
*
* @param plugin Plugin
* @param name Name
* @param enabled Enabled Status
* @param address Address
* @param directory Directory
* @param gitBash Git Bash Location
* @param plugin SubServers Internals
* @param name The Name of your Host
* @param ports The range of ports to auto-select from
* @param log Whether apps like SubCreator should log to console (does not apply to servers)
* @param enabled If your host is Enabled
* @param address The address of your Host
* @param directory The runtime directory of your Host
* @param gitBash The Git Bash directory
*/
public InternalHost(SubPlugin plugin, String name, Boolean enabled, InetAddress address, String directory, String gitBash) {
super(plugin, name, enabled, address, directory, gitBash);
public InternalHost(SubProxy plugin, String name, boolean enabled, Range<Integer> ports, boolean log, InetAddress address, String directory, String gitBash) {
super(plugin, name, enabled, ports, log, address, directory, gitBash);
if (!DRM_ALLOW) throw new IllegalStateException("SubServers' hosting capabilities have been disabled by your provider");
if (Util.isNull(plugin, name, enabled, address, directory, gitBash)) throw new NullPointerException();
this.plugin = plugin;
this.name = name;
this.enabled = enabled;
this.address = address;
this.creator = new InternalSubCreator(this, gitBash);
this.creator = new InternalSubCreator(this, ports, log, gitBash);
this.directory = directory;
}
@ -89,139 +95,156 @@ public class InternalHost extends Host {
@Override
public SubServer getSubServer(String name) {
if (Util.isNull(name)) throw new NullPointerException();
return getSubServers().get(name.toLowerCase());
if (Util.isNull(name)) return null;
return servers.get(name.toLowerCase());
}
@Override
public SubServer addSubServer(UUID player, String name, boolean enabled, int port, String motd, boolean log, String directory, Executable executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
if (plugin.api.getServers().keySet().contains(name.toLowerCase())) throw new InvalidServerException("A Server already exists with this name!");
SubServer server = new InternalSubServer(this, name, enabled, port, motd, log, directory, executable, stopcmd, hidden, restricted);
public SubServer constructSubServer(String name, boolean enabled, int port, String motd, boolean log, String directory, String executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
return InternalSubServer.construct(this, name, enabled, port, motd, log, directory, executable, stopcmd, hidden, restricted);
}
@Override
public boolean addSubServer(UUID player, SubServer server) throws InvalidServerException {
if (server.getHost() != this) throw new IllegalArgumentException("That Server does not belong to this Host!");
if (plugin.api.getServers().containsKey(server.getName().toLowerCase())) throw new InvalidServerException("A Server already exists with this name!");
SubAddServerEvent event = new SubAddServerEvent(player, this, server);
plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
servers.put(name.toLowerCase(), server);
return server;
((InternalSubServer) server).registered(true);
servers.put(server.getName().toLowerCase(), server);
if (UPnP.isUPnPAvailable() && plugin.config.get().getMap("Settings").getMap("UPnP", new ObjectMap<String>()).getBoolean("Forward-Servers", false)) UPnP.openPortTCP(server.getAddress().getPort());
return true;
} else {
return null;
return false;
}
}
@Override
public boolean removeSubServer(UUID player, String name) throws InterruptedException {
if (Util.isNull(name)) throw new NullPointerException();
String server = servers.get(name.toLowerCase()).getName();
SubRemoveServerEvent event = new SubRemoveServerEvent(player, this, getSubServer(server));
protected boolean removeSubServer(UUID player, String name, boolean forced) throws InterruptedException {
Util.nullpo(name);
InternalSubServer server = (InternalSubServer) servers.get(name.toLowerCase());
SubRemoveServerEvent event = new SubRemoveServerEvent(player, this, server);
plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
if (getSubServer(server).isRunning()) {
getSubServer(server).stop();
getSubServer(server).waitFor();
if (forced || !event.isCancelled()) {
server.registered(false);
if (server.isRunning()) {
server.stop();
server.waitFor();
}
servers.remove(server.toLowerCase());
servers.remove(name.toLowerCase());
if (UPnP.isUPnPAvailable() && UPnP.isMappedTCP(server.getAddress().getPort()))
UPnP.closePortTCP(server.getAddress().getPort());
return true;
} else return false;
}
@Override
public boolean forceRemoveSubServer(UUID player, String name) {
if (Util.isNull(name)) throw new NullPointerException();
String server = servers.get(name.toLowerCase()).getName();
SubRemoveServerEvent event = new SubRemoveServerEvent(player, this, getSubServer(server));
plugin.getPluginManager().callEvent(event);
if (getSubServer(server).isRunning()) {
getSubServer(server).terminate();
}
servers.remove(server.toLowerCase());
return true;
protected boolean recycleSubServer(UUID player, String name, boolean forced) throws InterruptedException {
return recycleSubServer(player, name, forced, true);
}
@Override
public boolean deleteSubServer(UUID player, String name) throws InterruptedException {
if (Util.isNull(name)) throw new NullPointerException();
/**
* Deletes a SubServer (will move to 'Recently Deleted')
*
* @param player Player Deleting
* @param name SubServer Name
* @param forced Forces the Deletion
* @param multithreading Uses Multithreading for I/O
* @return Success Status
*/
protected boolean recycleSubServer(UUID player, String name, boolean forced, boolean multithreading) throws InterruptedException {
Util.nullpo(name);
String server = servers.get(name.toLowerCase()).getName();
File from = new File(getPath(), servers.get(server.toLowerCase()).getPath());
if (removeSubServer(player, server)) {
new Thread(() -> {
UniversalFile to = new UniversalFile(plugin.dir, "SubServers:Recently Deleted:" + server.toLowerCase());
if (removeSubServer(player, server, forced)) {
Runnable method = () -> {
File to = new File(plugin.dir, "SubServers/Recently Deleted/" + server.toLowerCase());
try {
if (from.exists()) {
System.out.println("SubServers > Removing Files...");
Logger.get("SubServers").info("Moving Files...");
if (to.exists()) {
if (to.isDirectory()) Util.deleteDirectory(to);
if (to.isDirectory()) Directories.delete(to);
else to.delete();
}
to.mkdirs();
Util.copyDirectory(from, to);
Util.deleteDirectory(from);
Directories.copy(from, to);
Directories.delete(from);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("SubServers > Saving...");
YAMLSection info = (plugin.config.get().getSection("Servers").getKeys().contains(server))?plugin.config.get().getSection("Servers").getSection(server).clone():new YAMLSection();
Logger.get("SubServers").info("Saving...");
YAMLSection info = (plugin.servers.get().getMap("Servers").getKeys().contains(server))?new YAMLSection(plugin.servers.get().getMap("Servers").getMap(server).get()):new YAMLSection();
info.set("Name", server);
info.set("Timestamp", Calendar.getInstance().getTime().getTime());
try {
if (plugin.config.get().getSection("Servers").getKeys().contains(server)) {
plugin.config.get().getSection("Servers").remove(server);
plugin.config.save();
}
if (!to.exists()) to.mkdirs();
FileWriter writer = new FileWriter(new File(to, "info.json"));
writer.write(info.toJSON());
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("SubServers > Deleted SubServer: " + server);
}).start();
return true;
} else return false;
}
@Override
public boolean forceDeleteSubServer(UUID player, String name) throws InterruptedException {
if (Util.isNull(name)) throw new NullPointerException();
String server = servers.get(name.toLowerCase()).getName();
File from = new File(getPath(), servers.get(server.toLowerCase()).getPath());
if (forceRemoveSubServer(player, server)) {
new Thread(() -> {
UniversalFile to = new UniversalFile(plugin.dir, "SubServers:Recently Deleted:" + server.toLowerCase());
try {
if (from.exists()) {
System.out.println("SubServers > Removing Files...");
if (to.exists()) {
if (to.isDirectory()) Util.deleteDirectory(to);
else to.delete();
}
to.mkdirs();
Util.copyDirectory(from, to);
Util.deleteDirectory(from);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("SubServers > Saving...");
YAMLSection info = (plugin.config.get().getSection("Servers").getKeys().contains(server))?plugin.config.get().getSection("Servers").getSection(server).clone():new YAMLSection();
info.set("Name", server);
info.set("Timestamp", Calendar.getInstance().getTime().getTime());
try {
if (plugin.config.get().getSection("Servers").getKeys().contains(server)) {
plugin.config.get().getSection("Servers").remove(server);
plugin.config.save();
if (plugin.servers.get().getMap("Servers").getKeys().contains(server)) {
plugin.servers.get().getMap("Servers").remove(server);
plugin.servers.save();
}
if (!to.exists()) to.mkdirs();
FileWriter writer = new FileWriter(new File(to, "info.json"), false);
writer.write(info.toJSON());
writer.write(new Gson().toJson(info.get()));
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("SubServers > Deleted SubServer: " + server);
}).start();
Logger.get("SubServers").info("Deleted SubServer: " + server);
};
if (multithreading) {
new Thread(method, "SubServers.Bungee::Internal_Server_Recycler(" + name + ')').start();
} else method.run();
return true;
} else return false;
}
@Override
protected boolean deleteSubServer(UUID player, String name, boolean forced) throws InterruptedException {
return deleteSubServer(player, name, forced, true);
}
/**
* Deletes a SubServer
*
* @param player Player Deleting
* @param name SubServer Name
* @param forced Forces the Deletion
* @param multithreading Uses Multithreading for I/O
* @return Success Status
*/
protected boolean deleteSubServer(UUID player, String name, boolean forced, boolean multithreading) throws InterruptedException {
Util.nullpo(name);
String server = servers.get(name.toLowerCase()).getName();
File from = new File(getPath(), servers.get(server.toLowerCase()).getPath());
if (removeSubServer(player, server, forced)) {
Runnable method = () -> {
try {
if (from.exists()) {
Logger.get("SubServers").info("Removing Files...");
Directories.delete(from);
}
} catch (Exception e) {
e.printStackTrace();
}
Logger.get("SubServers").info("Saving...");
try {
if (plugin.servers.get().getMap("Servers").getKeys().contains(server)) {
plugin.servers.get().getMap("Servers").remove(server);
plugin.servers.save();
}
} catch (Exception e) {
e.printStackTrace();
}
Logger.get("SubServers").info("Deleted SubServer: " + server);
};
if (multithreading) {
new Thread(method, "SubServers.Bungee::Internal_Server_Deletion(" + name + ')').start();
} else method.run();
return true;
} else return false;
}

View File

@ -1,28 +1,48 @@
package net.ME1312.SubServers.Bungee.Host.Internal;
import net.ME1312.Galaxi.Library.Config.YAMLConfig;
import net.ME1312.Galaxi.Library.Config.YAMLSection;
import net.ME1312.Galaxi.Library.Container.ContainedPair;
import net.ME1312.Galaxi.Library.Container.Container;
import net.ME1312.Galaxi.Library.Container.Pair;
import net.ME1312.Galaxi.Library.Container.Value;
import net.ME1312.Galaxi.Library.Directories;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Map.ObjectMapValue;
import net.ME1312.Galaxi.Library.Try;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.Galaxi.Library.Version.Version;
import net.ME1312.SubServers.Bungee.Event.SubCreateEvent;
import net.ME1312.SubServers.Bungee.Event.SubCreatedEvent;
import net.ME1312.SubServers.Bungee.Host.*;
import net.ME1312.SubServers.Bungee.Library.*;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLConfig;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.SubServers.Bungee.Host.SubServer.StopAction;
import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import net.ME1312.SubServers.Bungee.Library.Exception.SubCreatorException;
import net.ME1312.SubServers.Bungee.Library.Version.Version;
import net.ME1312.SubServers.Bungee.Library.ReplacementScanner;
import net.ME1312.SubServers.Bungee.SubAPI;
import net.ME1312.SubServers.Bungee.SubPlugin;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import net.ME1312.SubServers.Bungee.SubProxy;
import com.google.common.collect.Range;
import com.google.gson.Gson;
import net.md_5.bungee.api.ChatColor;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.StandardCopyOption;
import java.security.MessageDigest;
import java.util.*;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
/**
* Internal SubCreator Class
*/
@ -30,277 +50,378 @@ import java.util.regex.Pattern;
public class InternalSubCreator extends SubCreator {
private HashMap<String, ServerTemplate> templates = new HashMap<String, ServerTemplate>();
private InternalHost host;
private Range<Integer> ports;
private Value<Boolean> log;
private String gitBash;
private TreeMap<String, NamedContainer<Thread, NamedContainer<InternalSubLogger, Process>>> thread;
private TreeMap<String, CreatorTask> thread;
private class CreatorTask extends Thread {
private final UUID player;
private final SubServer update;
private final String name;
private final ServerTemplate template;
private final Version version;
private final int port;
private final String prefix;
private final InternalSubLogger log;
private final LinkedList<String> replace;
private final HashMap<String, String> replacements;
private final Consumer<SubServer> callback;
private boolean install;
private Process process;
private CreatorTask(UUID player, String name, ServerTemplate template, Version version, int port, Consumer<SubServer> callback) {
super("SubServers.Bungee::Internal_SubCreator_Process_Handler(" + name + ')');
this.player = player;
this.update = null;
this.name = name;
this.template = template;
this.version = version;
this.port = port;
this.log = new InternalSubLogger(null, this, prefix = name + File.separator + "Creator", InternalSubCreator.this.log, null);
(this.replace = new LinkedList<String>()).add("/server.properties");
this.replacements = new HashMap<String, String>();
this.callback = callback;
this.install = true;
}
private CreatorTask(UUID player, SubServer server, ServerTemplate template, Version version, Consumer<SubServer> callback) {
super("SubServers.Bungee::Internal_SubCreator_Process_Handler(" + server.getName() + ')');
this.player = player;
this.update = server;
this.name = server.getName();
this.template = template;
this.version = version;
this.port = server.getAddress().getPort();
this.log = new InternalSubLogger(null, this, prefix = name + File.separator + "Updater", InternalSubCreator.this.log, null);
(this.replace = new LinkedList<String>()).add("/server.properties");
this.replacements = new HashMap<String, String>();
this.callback = callback;
this.install = true;
}
private ObjectMap<String> build(File dir, ServerTemplate template, List<ServerTemplate> history, List<ServerTemplate> stack) throws SubCreatorException {
ObjectMap<String> server = new ObjectMap<String>();
Version version = this.version;
HashMap<String, String> var = new HashMap<String, String>();
boolean error = false;
if (stack.contains(template)) throw new IllegalStateException("Infinite template import loop detected");
stack.add(template);
for (String other : template.getBuildOptions().getStringList("Import", new ArrayList<String>())) {
if (templates.containsKey(other.toLowerCase())) {
final ServerTemplate ot = templates.get(other.toLowerCase());
if (ot.isEnabled()) {
if (version != null || !ot.requiresVersion()) {
if (update == null || ot.canUpdate()) {
if (!history.contains(ot)) {
server.setAll(this.build(dir, ot, history, stack));
} else {
log.log(WARNING, "Skipping template that is already loaded: " + other);
}
} else {
log.log(WARNING, "Skipping template that cannot be run in update mode: " + other);
}
} else {
log.log(WARNING, "Skipping template that requires extra versioning information: " + other);
}
} else {
log.log(WARNING, "Skipping disabled template: " + other);
}
} else {
log.log(WARNING, "Skipping missing template: " + other);
}
}
history.add(template);
stack.remove(template);
server.setAll(template.getConfigOptions());
try {
log.log(INFO, "Loading" + ((template.isDynamic())?" Dynamic":"") + " Template: " + template.getDisplayName());
updateDirectory(template.getDirectory(), dir, template.getBuildOptions().getBoolean("Update-Files", false));
install = template.getBuildOptions().getBoolean("Install-Client", install);
replace.addAll(template.getBuildOptions().getStringList("Replace", Collections.emptyList()));
for (ObjectMapValue<String> replacement : template.getBuildOptions().getMap("Replacements", new ObjectMap<>()).getValues()) if (!replacement.isNull()) {
replacements.put(replacement.getHandle().toLowerCase().replace('-', '_').replace(' ', '_'), replacement.asString());
}
var.putAll(replacements);
var.put("java", System.getProperty("java.home") + File.separator + "bin" + File.separator + "java");
var.put("mode", (update == null)? "CREATE" : ((CreatorTask.this.template.equals(update.getTemplate()))?"UPDATE":"SWITCH"));
if (player != null) var.put("player", player.toString().toUpperCase());
else var.remove("player");
var.put("name", name);
var.put("host", host.getName());
var.put("template", template.getName());
var.put("type", template.getType().toString().toUpperCase());
if (version != null) var.put("version", version.toString());
else var.remove("version");
var.put("address", host.getAddress().getHostAddress());
var.put("port", Integer.toString(port));
switch (template.getType()) {
case SPONGE:
case FORGE:
if (version != null) {
log.log(INFO, "Searching Versions...");
ObjectMap<String> spversionmanifest = new ObjectMap<String>(new Gson().fromJson("{\"versions\":" + Util.readAll(new BufferedReader(new InputStreamReader(new URL("https://dl-api.spongepowered.org/v1/org.spongepowered/sponge" + ((template.getType() == ServerType.FORGE)?"forge":"vanilla") + "/downloads?type=stable&minecraft=" + version).openStream(), Charset.forName("UTF-8")))) + '}', Map.class));
ObjectMap<String> spprofile = null;
Version spversion = null;
for (ObjectMap<String> profile : spversionmanifest.getMapList("versions")) {
if (profile.getMap("dependencies").getString("minecraft").equalsIgnoreCase(version.toString()) && (spversion == null || new Version(profile.getString("version")).compareTo(spversion) >= 0)) {
spprofile = profile;
spversion = new Version(profile.getString("version"));
}
}
if (spversion == null)
throw new InvalidServerException("Cannot find Sponge version for Minecraft " + version.toString());
log.log(INFO, "Found \"sponge" + ((template.getType() == ServerType.FORGE)?"forge":"vanilla") + "-" + spversion.toString() + '"');
if (template.getType() == ServerType.FORGE) {
Version mcfversion = new Version(((spprofile.getMap("dependencies").getString("forge").contains("-"))?"":spprofile.getMap("dependencies").getString("minecraft") + '-') + spprofile.getMap("dependencies").getString("forge"));
log.log(INFO, "Found \"forge-" + mcfversion.toString() + '"');
var.put("mcf_version", mcfversion.toString());
}
var.put("sp_version", spversion.toString());
}
break;
}
} catch (Exception e) {
e.printStackTrace();
}
if (template.getBuildOptions().contains("Executable")) {
File cache = null;
if (template.getBuildOptions().getBoolean("Use-Cache", true)) {
cache = new File(host.plugin.dir, "SubServers/Cache/Templates/" + template.getName());
cache.mkdirs();
var.put("cache", cache.getAbsolutePath());
}
var.put("source", dir.getAbsolutePath());
try {
log.log(INFO, "Launching Build Script...");
ProcessBuilder pb = new ProcessBuilder().command(Executable.parse(gitBash, template.getBuildOptions().getString("Executable"))).directory(dir);
pb.environment().putAll(var);
log.file = new File(dir, "SubCreator-" + template.getName() + ((version != null)?"-"+version.toString():"") + ".log");
process = pb.start();
log.process = process;
log.start();
process.waitFor();
Thread.sleep(250);
if (process.exitValue() != 0) error = true;
} catch (InterruptedException e) {
error = true;
} catch (Exception e) {
error = true;
e.printStackTrace();
}
if (cache != null) {
if (cache.isDirectory() && cache.listFiles().length == 0) cache.delete();
cache = new File(host.plugin.dir, "SubServers/Cache/Templates");
if (cache.isDirectory() && cache.listFiles().length == 0) cache.delete();
cache = new File(host.plugin.dir, "SubServers/Cache");
if (cache.isDirectory() && cache.listFiles().length == 0) cache.delete();
}
}
new File(dir, "template.yml").delete();
if (error) throw new SubCreatorException();
return server;
}
public void run() {
Runnable declaration = () -> {
replacements.put("player", (player == null)?"":player.toString());
replacements.put("name", name);
replacements.put("host", host.getName());
replacements.put("template", template.getName());
replacements.put("type", template.getType().toString());
replacements.put("version", (version != null)?version.toString():"");
replacements.put("address", host.getAddress().getHostAddress());
replacements.put("port", Integer.toString(port));
};
declaration.run();
File dir = (update != null)?new File(update.getFullPath()):new File(host.getPath(),
(template.getConfigOptions().contains("Directory"))?new ReplacementScanner(replacements).replace(template.getConfigOptions().getString("Directory")).toString():name);
ObjectMap<String> server = new ObjectMap<String>();
ObjectMap<String> config;
try {
log.init();
config = build(dir, template, new LinkedList<>(), new LinkedList<>());
} catch (SubCreatorException e) {
config = null;
} catch (Exception e) {
config = null;
e.printStackTrace();
} finally {
log.destroy();
}
declaration.run();
ReplacementScanner replacements = new ReplacementScanner(this.replacements);
if (config != null) {
try {
if (install) generateClient(dir, template.getType(), name);
replacements.replace(dir, replace.toArray(new String[0]));
} catch (Exception e) {
config = null;
e.printStackTrace();
}
}
if (config != null) {
try {
Logger.get(prefix).info("Saving...");
SubServer subserver = update;
if (update == null || update.getTemplate() != template || template.getBuildOptions().getBoolean("Update-Settings", false)) {
if (host.plugin.exServers.containsKey(name.toLowerCase()))
host.plugin.exServers.remove(name.toLowerCase());
config = new ObjectMap<String>((Map<String, ?>) replacements.replace(config.get()));
if (config.contains("Directory") && (update != null || !template.getConfigOptions().contains("Directory"))) config.remove("Directory");
if (update == null) {
server.set("Enabled", true);
server.set("Display", "");
server.set("Host", host.getName());
server.set("Template", template.getName());
server.set("Group", new ArrayList<String>());
server.set("Port", port);
server.set("Motd", "Some SubServer");
server.set("Log", true);
server.set("Directory", "./" + name);
server.set("Executable", "java -Xmx1024M -jar " + template.getType().toString() + ".jar");
server.set("Stop-Command", "stop");
server.set("Stop-Action", "NONE");
server.set("Run-On-Launch", false);
server.set("Restricted", false);
server.set("Incompatible", new ArrayList<String>());
server.set("Hidden", false);
} else {
server.setAll(host.plugin.servers.get().getMap("Servers").getMap(name, new HashMap<>()));
server.set("Template", template.getName());
}
server.setAll(config);
if (update != null) Try.all.run(() -> update.getHost().forceRemoveSubServer(name));
subserver = host.constructSubServer(name, server.getBoolean("Enabled"), port, ChatColor.translateAlternateColorCodes('&', Util.unescapeJavaString(server.getString("Motd"))), server.getBoolean("Log"),
server.getString("Directory"), server.getString("Executable"), server.getString("Stop-Command"), server.getBoolean("Hidden"), server.getBoolean("Restricted"));
if (server.getString("Display").length() > 0) subserver.setDisplayName(Util.unescapeJavaString(server.getString("Display")));
subserver.setTemplate(server.getString("Template"));
for (String group : server.getStringList("Group")) subserver.addGroup(group);
SubServer.StopAction action = Try.all.get(() -> SubServer.StopAction.valueOf(server.getString("Stop-Action").toUpperCase().replace('-', '_').replace(' ', '_')));
if (action != null) subserver.setStopAction(action);
if (server.contains("Extra")) for (String extra : server.getMap("Extra").getKeys())
subserver.addExtra(extra, server.getMap("Extra").getObject(extra));
if ((update != null && host.plugin.servers.get().getMap("Servers").contains(name)) ||
!(subserver.getStopAction() == StopAction.REMOVE_SERVER || subserver.getStopAction() == StopAction.RECYCLE_SERVER || subserver.getStopAction() == StopAction.DELETE_SERVER)) {
host.plugin.servers.get().getMap("Servers").set(name, server);
host.plugin.servers.save();
}
host.addSubServer(subserver);
if (update == null && template.getBuildOptions().getBoolean("Run-On-Finish", true))
subserver.start();
}
InternalSubCreator.this.thread.remove(name.toLowerCase());
host.plugin.getPluginManager().callEvent(new SubCreatedEvent(player, host, name, template, version, port, subserver, update != null, true));
callback.accept(subserver);
} catch (Exception e) {
e.printStackTrace();
host.plugin.getPluginManager().callEvent(new SubCreatedEvent(player, host, name, template, version, port, update, update != null, false));
callback.accept(null);
}
} else {
Logger.get(prefix).info("Couldn't build the server jar. Check the SubCreator logs for more detail.");
host.plugin.getPluginManager().callEvent(new SubCreatedEvent(player, host, name, template, version, port, update, update != null, false));
callback.accept(null);
}
InternalSubCreator.this.thread.remove(name.toLowerCase());
}
}
/**
* Creates an Internal SubCreator
*
* @param host Host
* @param gitBash Git Bash
* @param ports The range of ports to auto-select from
* @param log Whether SubCreator should log to console
* @param gitBash The Git Bash directory
*/
public InternalSubCreator(InternalHost host, String gitBash) {
if (Util.isNull(host, gitBash)) throw new NullPointerException();
public InternalSubCreator(InternalHost host, Range<Integer> ports, boolean log, String gitBash) {
if (!ports.hasLowerBound() || !ports.hasUpperBound()) throw new IllegalArgumentException("Port range is not bound");
Util.nullpo(host, ports, log, gitBash);
this.host = host;
this.gitBash = (System.getenv("ProgramFiles(x86)") == null) ? Pattern.compile("%(ProgramFiles)\\(x86\\)%", Pattern.CASE_INSENSITIVE).matcher(gitBash).replaceAll("%$1%") : gitBash;
this.thread = new TreeMap<String, NamedContainer<Thread, NamedContainer<InternalSubLogger, Process>>>();
this.ports = ports;
this.log = new Container<Boolean>(log);
this.gitBash = (System.getenv("ProgramFiles(x86)") == null)?Pattern.compile("%(ProgramFiles)\\(x86\\)%", Pattern.CASE_INSENSITIVE).matcher(gitBash).replaceAll("%$1%"):gitBash;
if (this.gitBash.endsWith(File.pathSeparator)) this.gitBash = this.gitBash.substring(0, this.gitBash.length() - 1);
this.thread = new TreeMap<String, CreatorTask>();
reload();
}
@Override
public void reload() {
templates.clear();
if (new UniversalFile(host.plugin.dir, "SubServers:Templates").exists())
for (File file : new UniversalFile(host.plugin.dir, "SubServers:Templates").listFiles()) {
if (new File(host.plugin.dir, "SubServers/Templates").exists())
for (File file : new File(host.plugin.dir, "SubServers/Templates").listFiles()) {
try {
if (file.isDirectory()) {
YAMLSection config = (new UniversalFile(file, "template.yml").exists()) ? new YAMLConfig(new UniversalFile(file, "template.yml")).get().getSection("Template", new YAMLSection()) : new YAMLSection();
ServerTemplate template = new ServerTemplate(file.getName(), config.getBoolean("Enabled", true), config.getRawString("Icon", "::NULL::"), file, config.getSection("Build", new YAMLSection()), config.getSection("Settings", new YAMLSection()));
if (file.isDirectory() && !file.getName().endsWith(".x")) {
ObjectMap<String> config = (new File(file, "template.yml").exists())? new YAMLConfig(new File(file, "template.yml")).get().getMap("Template", new ObjectMap<String>()) : new ObjectMap<String>();
ServerTemplate template = loadTemplate(file.getName(), config.getBoolean("Enabled", true), config.getBoolean("Internal", false), config.getString("Icon", "::NULL::"), file, config.getMap("Build", new ObjectMap<String>()), config.getMap("Settings", new ObjectMap<String>()));
templates.put(file.getName().toLowerCase(), template);
if (config.getKeys().contains("Display")) template.setDisplayName(config.getString("Display"));
if (config.getKeys().contains("Display")) template.setDisplayName(Util.unescapeJavaString(config.getString("Display")));
}
} catch (Exception e) {
System.out.println(host.getName() + File.separator + "Creator > Couldn't load template: " + file.getName());
Logger.get(host.getName()).severe("Couldn't load template: " + file.getName());
e.printStackTrace();
}
}
}
private YAMLSection build(NamedContainer<InternalSubLogger, Process> thread, File dir, String name, ServerTemplate template, Version version, List<ServerTemplate> history) throws SubCreatorException {
YAMLSection server = new YAMLSection();
boolean error = false;
if (history.contains(template)) throw new IllegalStateException("Template Import loop detected");
history.add(template);
for (String other : template.getBuildOptions().getStringList("Import", new ArrayList<String>())) {
if (templates.keySet().contains(other.toLowerCase())) {
if (templates.get(other.toLowerCase()).isEnabled()) {
YAMLSection config = build(thread, dir, other, templates.get(other.toLowerCase()), version, history);
if (config == null) {
throw new SubCreatorException();
} else {
server.setAll(config);
}
} else {
System.out.println(name + File.separator + "Creator > Skipping disabled template: " + other);
}
} else {
System.out.println(name + File.separator + "Creator > Skipping missing template: " + other);
}
}
server.setAll(template.getConfigOptions());
try {
System.out.println(name + File.separator + "Creator > Loading Template: " + template.getDisplayName());
Util.copyDirectory(template.getDirectory(), dir);
if (template.getType() == ServerType.FORGE || template.getType() == ServerType.SPONGE) {
System.out.println(name + File.separator + "Creator > Searching Versions...");
Document spongexml = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(Util.readAll(new BufferedReader(new InputStreamReader(new URL("https://repo.spongepowered.org/maven/org/spongepowered/sponge" + ((template.getType() == ServerType.FORGE)?"forge":"vanilla") + "/maven-metadata.xml").openStream(), Charset.forName("UTF-8")))))));
NodeList spnodeList = spongexml.getElementsByTagName("version");
Version spversion = null;
for (int i = 0; i < spnodeList.getLength(); i++) {
Node node = spnodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
if (node.getTextContent().startsWith(version.toString() + '-') && (spversion == null || new Version(node.getTextContent()).compareTo(spversion) >= 0)) {
spversion = new Version(node.getTextContent());
}
}
}
if (spversion == null)
throw new InvalidServerException("Cannot find Sponge version for Minecraft " + version.toString());
System.out.println(name + File.separator + "Creator > Found \"sponge" + ((template.getType() == ServerType.FORGE)?"forge":"vanilla") + "-" + spversion.toString() + '"');
if (template.getType() == ServerType.FORGE) {
Document forgexml = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(Util.readAll(new BufferedReader(new InputStreamReader(new URL("http://files.minecraftforge.net/maven/net/minecraftforge/forge/maven-metadata.xml").openStream(), Charset.forName("UTF-8")))))));
NodeList mcfnodeList = forgexml.getElementsByTagName("version");
Version mcfversion = null;
for (int i = 0; i < mcfnodeList.getLength(); i++) {
Node node = mcfnodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
if (node.getTextContent().contains(spversion.toString().split("\\-")[1]) && (mcfversion == null || new Version(node.getTextContent()).compareTo(mcfversion) >= 0)) {
mcfversion = new Version(node.getTextContent());
}
}
}
if (mcfversion == null)
throw new InvalidServerException("Cannot find Forge version for Sponge " + spversion.toString());
System.out.println(name + File.separator + "Creator > Found \"forge-" + mcfversion.toString() + '"');
version = new Version(mcfversion.toString() + " " + spversion.toString());
} else version = new Version(spversion.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
if (template.getBuildOptions().contains("Shell-Location")) {
String gitBash = this.gitBash + ((this.gitBash.endsWith(File.separator)) ? "" : File.separator) + "bin" + File.separatorChar + "bash.exe";
File cache;
if (template.getBuildOptions().getBoolean("Use-Cache", true)) {
cache = new UniversalFile(host.plugin.dir, "SubServers:Cache:Templates:" + template.getName());
cache.mkdirs();
} else {
cache = null;
}
if (!(System.getProperty("os.name").toLowerCase().indexOf("win") >= 0) && template.getBuildOptions().contains("Permission")) {
try {
Process process = Runtime.getRuntime().exec("chmod " + template.getBuildOptions().getRawString("Permission") + ' ' + template.getBuildOptions().getRawString("Shell-Location"), null, dir);
Thread.sleep(500);
if (process.exitValue() != 0) {
System.out.println(name + File.separator + "Creator > Couldn't set " + template.getBuildOptions().getRawString("Permission") + " permissions to " + template.getBuildOptions().getRawString("Shell-Location"));
}
} catch (Exception e) {
System.out.println(name + File.separator + "Creator > Couldn't set " + template.getBuildOptions().getRawString("Permission") + " permissions to " + template.getBuildOptions().getRawString("Shell-Location"));
e.printStackTrace();
}
}
try {
System.out.println(name + File.separator + "Creator > Launching " + template.getBuildOptions().getRawString("Shell-Location"));
thread.set(Runtime.getRuntime().exec((System.getProperty("os.name").toLowerCase().indexOf("win") >= 0)?"cmd.exe /c \"\"" + gitBash + "\" --login -i -c \"bash " + template.getBuildOptions().getRawString("Shell-Location") + ' ' + version.toString() + ' ' + ((cache == null)?':':cache.toString().replace('\\', '/').replace(" ", "\\ ")) + "\"\"":("bash " + template.getBuildOptions().getRawString("Shell-Location") + ' ' + version.toString() + ' ' + ((cache == null)?':':cache.toString().replace(" ", "\\ "))), null, dir));
thread.name().log.set(host.plugin.config.get().getSection("Settings").getBoolean("Log-Creator"));
thread.name().file = new File(dir, "SubCreator-" + template.getName() + "-" + version.toString().replace(" ", "@") + ".log");
thread.name().process = thread.get();
thread.name().start();
thread.get().waitFor();
Thread.sleep(500);
if (thread.get().exitValue() != 0) error = true;
} catch (InterruptedException e) {
error = true;
} catch (Exception e) {
error = true;
e.printStackTrace();
}
if (cache != null) {
if (cache.isDirectory() && cache.listFiles().length == 0) cache.delete();
cache = new UniversalFile(host.plugin.dir, "SubServers:Cache:Templates");
if (cache.isDirectory() && cache.listFiles().length == 0) cache.delete();
cache = new UniversalFile(host.plugin.dir, "SubServers:Cache");
if (cache.isDirectory() && cache.listFiles().length == 0) cache.delete();
}
}
new UniversalFile(dir, "template.yml").delete();
if (error) throw new SubCreatorException();
return server;
}
private SubServer run(UUID player, String name, ServerTemplate template, Version version, int port) {
NamedContainer<InternalSubLogger, Process> thread = this.thread.get(name.toLowerCase()).get();
UniversalFile dir = new UniversalFile(new File(host.getPath()), name);
dir.mkdirs();
YAMLSection server = new YAMLSection();
YAMLSection config;
try {
config = build(thread, dir, name, template, version, new LinkedList<>());
generateProperties(dir, port);
generateClient(dir, template.getType(), name);
} catch (SubCreatorException e) {
config = null;
} catch (Exception e) {
config = null;
e.printStackTrace();
}
if (config != null) {
try {
System.out.println(name + File.separator + "Creator > Saving...");
if (host.plugin.exServers.keySet().contains(name.toLowerCase()))
host.plugin.exServers.remove(name.toLowerCase());
config = new YAMLSection((Map<String, ?>) convert(config.get(), new NamedContainer<>("$player$", (player == null)?"":player.toString()), new NamedContainer<>("$name$", name), new NamedContainer<>("$template$", template.getName()),
new NamedContainer<>("$type$", template.getType().toString()), new NamedContainer<>("$version$", version.toString().replace(" ", "@")), new NamedContainer<>("$port$", Integer.toString(port))));
server.set("Enabled", true);
server.set("Display", "");
server.set("Host", host.getName());
server.set("Group", new ArrayList<String>());
server.set("Port", port);
server.set("Motd", "Some SubServer");
server.set("Log", true);
server.set("Directory", "." + File.separatorChar + name);
server.set("Executable", "java -Xmx1024M -jar " + template.getType().toString() + ".jar");
server.set("Stop-Command", "stop");
server.set("Stop-Action", "NONE");
server.set("Run-On-Launch", false);
server.set("Restricted", false);
server.set("Incompatible", new ArrayList<String>());
server.set("Hidden", false);
server.setAll(config);
SubServer subserver = host.addSubServer(player, name, server.getBoolean("Enabled"), port, server.getColoredString("Motd", '&'), server.getBoolean("Log"), server.getRawString("Directory"),
new Executable(server.getRawString("Executable")), server.getRawString("Stop-Command"), server.getBoolean("Hidden"), server.getBoolean("Restricted"));
if (server.getString("Display").length() > 0) subserver.setDisplayName(server.getString("Display"));
for (String group : server.getStringList("Group")) subserver.addGroup(group);
SubServer.StopAction action = Util.getDespiteException(() -> SubServer.StopAction.valueOf(server.getRawString("Stop-Action").toUpperCase().replace('-', '_').replace(' ', '_')), null);
if (action != null) subserver.setStopAction(action);
if (server.contains("Extra")) for (String extra : server.getSection("Extra").getKeys())
subserver.addExtra(extra, server.getSection("Extra").getObject(extra));
host.plugin.config.get().getSection("Servers").set(name, server);
host.plugin.config.save();
if (template.getBuildOptions().getBoolean("Run-On-Finish", true))
subserver.start();
this.thread.remove(name.toLowerCase());
return subserver;
} catch (Exception e) {
e.printStackTrace();
}
} else {
System.out.println(name + File.separator + "Creator > Couldn't build the server jar. Check the SubCreator logs for more detail.");
}
this.thread.remove(name.toLowerCase());
return null;
} private Object convert(Object value, NamedContainer<String, String>... replacements) {
if (value instanceof Map) {
List<String> list = new ArrayList<String>();
list.addAll(((Map<String, Object>) value).keySet());
for (String key : list) ((Map<String, Object>) value).put(key, convert(((Map<String, Object>) value).get(key), replacements));
return value;
} else if (value instanceof Collection) {
List<Object> list = new ArrayList<Object>();
for (Object val : (Collection<Object>) value) list.add(convert(val, replacements));
return list;
} else if (value.getClass().isArray()) {
List<Object> list = new ArrayList<Object>();
for (int i = 0; i < ((Object[]) value).length; i++) list.add(convert(((Object[]) value)[i], replacements));
return list;
} else if (value instanceof String) {
return replace((String) value, replacements);
} else {
return value;
}
} private String replace(String string, NamedContainer<String, String>... replacements) {
for (NamedContainer<String, String> replacement : replacements) string = string.replace(replacement.name(), replacement.get());
return string;
}
@SuppressWarnings("deprecation")
@Override
public boolean create(UUID player, String name, ServerTemplate template, Version version, int port, Callback<SubServer> callback) {
if (Util.isNull(name, template, version, port)) throw new NullPointerException();
if (host.isAvailable() && host.isEnabled() && template.isEnabled() && !SubAPI.getInstance().getSubServers().keySet().contains(name.toLowerCase()) && !SubCreator.isReserved(name)) {
StackTraceElement[] origin = new Exception().getStackTrace();
NamedContainer<Thread, NamedContainer<InternalSubLogger, Process>> thread = new NamedContainer<Thread, NamedContainer<InternalSubLogger, Process>>(null, new NamedContainer<InternalSubLogger, Process>(new InternalSubLogger(null, this, name + File.separator + "Creator", new Container<Boolean>(false), null), null));
this.thread.put(name.toLowerCase(), thread);
public boolean create(UUID player, String name, ServerTemplate template, Version version, Integer port, Consumer<SubServer> callback) {
Util.nullpo(name, template);
if (host.isAvailable() && host.isEnabled() && template.isEnabled() && !SubAPI.getInstance().getSubServers().containsKey(name.toLowerCase()) && !SubCreator.isReserved(name) && (version != null || !template.requiresVersion())) {
StackTraceElement[] origin = new Throwable().getStackTrace();
if (port == null) {
Value<Integer> i = new Container<Integer>(ports.lowerEndpoint() - 1);
port = Util.getNew(getAllReservedAddresses(), () -> {
do {
i.value(i.value() + 1);
if (i.value() > ports.upperEndpoint()) throw new IllegalStateException("There are no more ports available in range: " + ports.toString());
} while (!ports.contains(i.value()));
return new InetSocketAddress(host.getAddress(), i.value());
}).getPort();
}
CreatorTask task = new CreatorTask(player, name, template, version, port, server -> {
if (callback != null) try {
callback.accept(server);
} catch (Throwable e) {
Throwable ew = new InvocationTargetException(e);
ew.setStackTrace(origin);
ew.printStackTrace();
}
});
this.thread.put(name.toLowerCase(), task);
final SubCreateEvent event = new SubCreateEvent(player, host, name, template, version, port);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
thread.rename(new Thread(() -> {
SubServer server = InternalSubCreator.this.run(player, name, event.getTemplate(), event.getVersion(), port);
if (callback != null && server != null) try {
callback.run(server);
} catch (Throwable e) {
Throwable ew = new InvocationTargetException(e);
ew.setStackTrace(origin);
ew.printStackTrace();
}
}));
thread.name().start();
task.start();
return true;
} else {
this.thread.remove(name.toLowerCase());
@ -309,9 +430,42 @@ public class InternalSubCreator extends SubCreator {
} else return false;
}
@SuppressWarnings("deprecation")
@Override
public boolean update(UUID player, SubServer server, ServerTemplate template, Version version, Consumer<Boolean> callback) {
Util.nullpo(server);
final ServerTemplate ft = (template == null)?server.getTemplate():template;
if (host.isAvailable() && host.isEnabled() && host == server.getHost() && server.isAvailable() && !server.isRunning() && ft != null && ft.isEnabled() && ft.canUpdate() && (version != null || !ft.requiresVersion())) {
StackTraceElement[] origin = new Throwable().getStackTrace();
((InternalSubServer) server).updating(true);
CreatorTask task = new CreatorTask(player, server, ft, version, x -> {
((InternalSubServer) server).updating(false);
if (callback != null) try {
callback.accept(x != null);
} catch (Throwable e) {
Throwable ew = new InvocationTargetException(e);
ew.setStackTrace(origin);
ew.printStackTrace();
}
});
this.thread.put(server.getName().toLowerCase(), task);
final SubCreateEvent event = new SubCreateEvent(player, server, ft, version);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
task.start();
return true;
} else {
this.thread.remove(server.getName().toLowerCase());
return false;
}
} else return false;
}
@Override
public void terminate() {
HashMap<String, NamedContainer<Thread, NamedContainer<InternalSubLogger, Process>>> temp = new HashMap<String, NamedContainer<Thread, NamedContainer<InternalSubLogger, Process>>>();
HashMap<String, CreatorTask> temp = new HashMap<String, CreatorTask>();
temp.putAll(thread);
for (String i : temp.keySet()) {
terminate(i);
@ -320,17 +474,19 @@ public class InternalSubCreator extends SubCreator {
@Override
public void terminate(String name) {
if (this.thread.get(name.toLowerCase()).get().get() != null && this.thread.get(name.toLowerCase()).get().get().isAlive()) {
this.thread.get(name.toLowerCase()).get().get().destroyForcibly();
} else if (this.thread.get(name.toLowerCase()).name() != null && this.thread.get(name.toLowerCase()).name().isAlive()) {
this.thread.get(name.toLowerCase()).name().interrupt();
this.thread.remove(name.toLowerCase());
if (this.thread.containsKey(name.toLowerCase())) {
if (this.thread.get(name.toLowerCase()).process != null && this.thread.get(name.toLowerCase()).process.isAlive()) {
Executable.terminate(this.thread.get(name.toLowerCase()).process);
} else if (this.thread.get(name.toLowerCase()).isAlive()) {
this.thread.get(name.toLowerCase()).interrupt();
this.thread.remove(name.toLowerCase());
}
}
}
@Override
public void waitFor() throws InterruptedException {
HashMap<String, NamedContainer<Thread, NamedContainer<InternalSubLogger, Process>>> temp = new HashMap<String, NamedContainer<Thread, NamedContainer<InternalSubLogger, Process>>>();
HashMap<String, CreatorTask> temp = new HashMap<String, CreatorTask>();
temp.putAll(thread);
for (String i : temp.keySet()) {
waitFor(i);
@ -339,7 +495,7 @@ public class InternalSubCreator extends SubCreator {
@Override
public void waitFor(String name) throws InterruptedException {
while (this.thread.keySet().contains(name.toLowerCase()) && this.thread.get(name.toLowerCase()).name() != null && this.thread.get(name.toLowerCase()).name().isAlive()) {
while (this.thread.containsKey(name.toLowerCase()) && this.thread.get(name.toLowerCase()).isAlive()) {
Thread.sleep(250);
}
}
@ -349,15 +505,26 @@ public class InternalSubCreator extends SubCreator {
return host;
}
@Override
public Range getPortRange() {
return ports;
}
@Override
public void setPortRange(Range<Integer> value) {
if (!value.hasLowerBound() || !value.hasUpperBound()) throw new IllegalArgumentException("Port range is not bound");
ports = value;
}
@Override
public String getBashDirectory() {
return gitBash;
}
@Override
public List<SubLogger> getLogger() {
public List<SubLogger> getLoggers() {
List<SubLogger> loggers = new ArrayList<SubLogger>();
HashMap<String, NamedContainer<Thread, NamedContainer<InternalSubLogger, Process>>> temp = new HashMap<String, NamedContainer<Thread, NamedContainer<InternalSubLogger, Process>>>();
HashMap<String, CreatorTask> temp = new HashMap<String, CreatorTask>();
temp.putAll(thread);
for (String i : temp.keySet()) {
loggers.add(getLogger(i));
@ -367,7 +534,18 @@ public class InternalSubCreator extends SubCreator {
@Override
public SubLogger getLogger(String name) {
return this.thread.get(name.toLowerCase()).get().name();
return this.thread.get(name.toLowerCase()).log;
}
@Override
public boolean isLogging() {
return log.value();
}
@Override
public void setLogging(boolean value) {
Util.nullpo(value);
log.value(value);
}
@Override
@ -375,45 +553,109 @@ public class InternalSubCreator extends SubCreator {
return new ArrayList<String>(thread.keySet());
}
@Override
public List<Integer> getReservedPorts() {
List<Integer> ports = new ArrayList<Integer>();
for (CreatorTask task : thread.values()) ports.add(task.port);
return ports;
}
@Override
public Map<String, ServerTemplate> getTemplates() {
return new TreeMap<String, ServerTemplate>(templates);
TreeMap<String, ServerTemplate> map = new TreeMap<String, ServerTemplate>();
for (Map.Entry<String, ServerTemplate> template : templates.entrySet()) {
if (!template.getValue().isInternal()) map.put(template.getKey(), template.getValue());
}
return map;
}
@Override
public ServerTemplate getTemplate(String name) {
if (Util.isNull(name)) throw new NullPointerException();
return getTemplates().get(name.toLowerCase());
Util.nullpo(name);
ServerTemplate template = templates.getOrDefault(name.toLowerCase(), null);
if (template == null || template.isInternal()) {
return null;
} else {
return template;
}
}
private static Pair<YAMLSection, Map<String, Object>> subdata = null;
private Map<String, Object> getSubData() {
if (subdata == null || host.plugin.config.get() != subdata.key()) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("Address", host.plugin.config.get().getMap("Settings").getMap("SubData").getString("Address", "127.0.0.1").replace("0.0.0.0", "127.0.0.1"));
if (host.plugin.config.get().getMap("Settings").getMap("SubData").getString("Password", "").length() > 0) map.put("Password", host.plugin.config.get().getMap("Settings").getMap("SubData").getString("Password"));
subdata = new ContainedPair<>(host.plugin.config.get(), map);
}
return subdata.value();
}
private void generateClient(File dir, ServerType type, String name) throws IOException {
if (new UniversalFile(dir, "subservers.client").exists()) {
if (type == ServerType.SPIGOT) {
if (!new UniversalFile(dir, "plugins").exists()) new UniversalFile(dir, "plugins").mkdirs();
Util.copyFromJar(SubPlugin.class.getClassLoader(), "net/ME1312/SubServers/Bungee/Library/Files/client.jar", new UniversalFile(dir, "plugins:SubServers.Client.jar").getPath());
} else if (type == ServerType.FORGE || type == ServerType.SPONGE) {
if (!new UniversalFile(dir, "mods").exists()) new UniversalFile(dir, "mods").mkdirs();
Util.copyFromJar(SubPlugin.class.getClassLoader(), "net/ME1312/SubServers/Bungee/Library/Files/client.jar", new UniversalFile(dir, "mods:SubServers.Client.jar").getPath());
}
boolean installed = false;
if (type == ServerType.SPIGOT) {
installed = true;
if (!new File(dir, "plugins").exists()) new File(dir, "plugins").mkdirs();
if (!new File(dir, "plugins/SubServers.Client.jar").exists())
Util.copyFromJar(SubProxy.class.getClassLoader(), "net/ME1312/SubServers/Bungee/Library/Files/client.jar", new File(dir, "plugins/SubServers.Client.jar").getPath());
} else if (type == ServerType.FORGE || type == ServerType.SPONGE) {
installed = true;
if (!new File(dir, "mods").exists()) new File(dir, "mods").mkdirs();
if (!new File(dir, "mods/SubServers.Client.jar").exists())
Util.copyFromJar(SubProxy.class.getClassLoader(), "net/ME1312/SubServers/Bungee/Library/Files/client.jar", new File(dir, "mods/SubServers.Client.jar").getPath());
}
if (installed) {
YAMLSection config = new YAMLSection();
FileWriter writer = new FileWriter(new UniversalFile(dir, "subservers.client"), false);
config.set("Name", name);
config.set("Address", host.plugin.config.get().getSection("Settings").getSection("SubData").getRawString("Address", "127.0.0.1").replace("0.0.0.0", "127.0.0.1"));
config.set("Password", host.plugin.config.get().getSection("Settings").getSection("SubData").getRawString("Password", ""));
config.set("Encryption", host.plugin.config.get().getSection("Settings").getSection("SubData").getRawString("Encryption", "NONE"));
writer.write(config.toJSON());
FileWriter writer = new FileWriter(new File(dir, "subdata.json"), false);
config.setAll(getSubData());
writer.write(new Gson().toJson(config.get()));
writer.close();
if (!new File(dir, "subdata.rsa.key").exists() && new File("SubServers/subdata.rsa.key").exists()) {
Files.copy(new File("SubServers/subdata.rsa.key").toPath(), new File(dir, "subdata.rsa.key").toPath());
}
}
}
private void generateProperties(File dir, int port) throws IOException {
File file = new File(dir, "server.properties");
if (!file.exists()) file.createNewFile();
InputStream stream = new FileInputStream(file);
String content = Util.readAll(new BufferedReader(new InputStreamReader(stream))).replace("server-port=", "server-port=" + port).replace("server-ip=", "server-ip=" + host.getAddress().getHostAddress());
stream.close();
file.delete();
PrintWriter writer = new PrintWriter(file, "UTF-8");
writer.write(content);
writer.close();
private void updateDirectory(File from, File to, boolean overwrite) {
if (!to.exists()) {
Directories.copy(from, to);
} else if (from.isDirectory() && !Files.isSymbolicLink(from.toPath())) {
String files[] = from.list();
for (String file : files) {
File srcFile = new File(from, file);
File destFile = new File(to, file);
updateDirectory(srcFile, destFile, overwrite);
}
} else {
try {
if (overwrite && (from.length() != to.length() || !Arrays.equals(generateSHA256(to), generateSHA256(from)))) {
if (to.exists()) {
if (to.isDirectory()) Directories.delete(to);
else to.delete();
}
Files.copy(from.toPath(), to.toPath(), LinkOption.NOFOLLOW_LINKS, StandardCopyOption.REPLACE_EXISTING);
}
} catch (Exception e) {
e.printStackTrace();
}
}
} private byte[] generateSHA256(File file) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
FileInputStream fis = new FileInputStream(file);
byte[] dataBytes = new byte[4096];
int nread;
while ((nread = fis.read(dataBytes)) != -1) {
md.update(dataBytes, 0, nread);
}
fis.close();
return md.digest();
}
}

View File

@ -1,18 +1,18 @@
package net.ME1312.SubServers.Bungee.Host.Internal;
import net.ME1312.Galaxi.Library.Container.Value;
import net.ME1312.Galaxi.Library.Try;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.SubLogFilter;
import net.ME1312.SubServers.Bungee.Host.SubLogger;
import net.ME1312.SubServers.Bungee.Library.Container;
import net.ME1312.SubServers.Bungee.Library.NamedContainer;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.SubAPI;
import net.md_5.bungee.api.ProxyServer;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -21,13 +21,12 @@ import java.util.regex.Pattern;
* Internal Process Logger Class
*/
public class InternalSubLogger extends SubLogger {
protected Process process;
Process process;
private Object handle;
protected String name;
protected Container<Boolean> log;
private List<SubLogFilter> filters = new ArrayList<SubLogFilter>();
private List<LogMessage> messages = new LinkedList<LogMessage>();
protected File file;
String name;
Value<Boolean> log;
private List<SubLogFilter> filters = new CopyOnWriteArrayList<>();
File file;
private PrintWriter writer = null;
private boolean started = false;
private Thread out = null;
@ -42,7 +41,7 @@ public class InternalSubLogger extends SubLogger {
* @param log Console Logging Status
* @param file File to log to (or null for disabled)
*/
protected InternalSubLogger(Process process, Object user, String name, Container<Boolean> log, File file) {
InternalSubLogger(Process process, Object user, String name, Value<Boolean> log, File file) {
this.process = process;
this.handle = user;
this.name = name;
@ -50,6 +49,16 @@ public class InternalSubLogger extends SubLogger {
this.file = file;
}
void init() {
List<SubLogFilter> filters = new ArrayList<SubLogFilter>();
filters.addAll(this.filters);
for (SubLogFilter filter : filters) try {
filter.start();
} catch (Throwable e) {
new InvocationTargetException(e, "Exception while running SubLogger Event").printStackTrace();
}
}
@Override
public void start() {
started = true;
@ -62,15 +71,8 @@ public class InternalSubLogger extends SubLogger {
e.printStackTrace();
}
}
if (out == null) (out = new Thread(() -> start(process.getInputStream(), false))).start();
if (err == null) (err = new Thread(() -> start(process.getErrorStream(), true))).start();
List<SubLogFilter> filters = new ArrayList<SubLogFilter>();
filters.addAll(this.filters);
for (SubLogFilter filter : filters) try {
filter.start();
} catch (Throwable e) {
new InvocationTargetException(e, "Exception while running SubLogger Event").printStackTrace();
}
if (out == null) (out = new Thread(() -> start(process.getInputStream(), false), "SubServers.Bungee::Internal_Log_Spooler(" + name + ')')).start();
if (err == null) (err = new Thread(() -> start(process.getErrorStream(), true), "SubServers.Bungee::Internal_Error_Spooler(" + name + ')')).start();
}
@SuppressWarnings("deprecation")
@ -79,57 +81,7 @@ public class InternalSubLogger extends SubLogger {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null) {
if (!line.startsWith(">")) {
String msg = line;
Level level;
// REGEX Formatting
String type = "";
Matcher matcher = Pattern.compile("^((?:\\s*\\[?([0-9]{2}:[0-9]{2}:[0-9]{2})]?)?[\\s\\/\\\\\\|]*(?:\\[|\\[.*\\/)?(MESSAGE|INFO|WARNING|WARN|ERROR|ERR|SEVERE)\\]?:?(?:\\s*>)?\\s*)").matcher(msg.replaceAll("\u001B\\[[;\\d]*m", ""));
while (matcher.find()) {
type = matcher.group(3).toUpperCase();
}
msg = msg.replaceAll("^((?:\\s*\\[?([0-9]{2}:[0-9]{2}:[0-9]{2})]?)?[\\s\\/\\\\\\|]*(?:\\[|\\[.*\\/)?(MESSAGE|INFO|WARNING|WARN|ERROR|ERR|SEVERE)\\]?:?(?:\\s*>)?\\s*)", "");
// Determine LOG LEVEL
switch (type) {
case "WARNING":
case "WARN":
level = Level.WARNING;
break;
case "SEVERE":
case "ERROR":
case "ERR":
level = Level.SEVERE;
break;
default:
level = Level.INFO;
}
// Filter Message
boolean allow = log.get() && (!SubAPI.getInstance().getInternals().canSudo || SubAPI.getInstance().getInternals().sudo == null || SubAPI.getInstance().getInternals().sudo == getHandler());
List<SubLogFilter> filters = new ArrayList<SubLogFilter>();
filters.addAll(this.filters);
for (SubLogFilter filter : filters)
try {
allow = (filter.log(level, msg) && allow);
} catch (Throwable e) {
new InvocationTargetException(e, "Exception while running SubLogger Event").printStackTrace();
}
// Log to CONSOLE
if (allow) ProxyServer.getInstance().getLogger().log(level, name + " > " + msg);
// Log to MEMORY
messages.add(new LogMessage(level, msg));
// Log to FILE
if (writer != null) {
writer.println(line);
writer.flush();
}
}
log(line);
}
} catch (IOException e) {} finally {
if (isErr) {
@ -138,50 +90,121 @@ public class InternalSubLogger extends SubLogger {
out = null;
}
destroy();
stop();
}
}
private Level level = Level.INFO;
private static final String PATTERN = "^((?:\\s*\\[?([0-9]{2}:[0-9]{2}:[0-9]{2})]?)?[\\s\\/\\\\\\|]*(?:\\[|\\[.*\\/)?(DEBUG|MESSAGE|MSG|" + Pattern.quote(Level.INFO.getLocalizedName()) + "|INFO|" + Pattern.quote(Level.WARNING.getLocalizedName()) + "|WARNING|WARN|ERROR|ERR|" + Pattern.quote(Level.SEVERE.getLocalizedName()) + "|SEVERE)\\]?(?::|\\s*>)?\\s*)";
private void log(String line) {
if (!line.startsWith(">")) {
String msg = line;
// REGEX Formatting
String type = null;
Matcher matcher = Pattern.compile(PATTERN).matcher(msg.replaceAll("\u001B\\[[;\\d]*m", ""));
if (matcher.find()) {
type = matcher.group(3).toUpperCase();
}
msg = msg.replaceAll(PATTERN, "");
// Determine LOG LEVEL
if (type != null) {
if (type.equalsIgnoreCase(Level.INFO.getLocalizedName())) {
level = Level.INFO;
} else if (type.equalsIgnoreCase(Level.WARNING.getLocalizedName())) {
level = Level.WARNING;
} else if (type.equalsIgnoreCase(Level.SEVERE.getLocalizedName())) {
level = Level.SEVERE;
} else switch (type) {
case "WARNING":
case "WARN":
level = Level.WARNING;
break;
case "SEVERE":
case "ERROR":
case "ERR":
level = Level.SEVERE;
break;
default:
level = Level.INFO;
}
}
// Log to FILTER
log(level, msg);
// Log to FILE
if (writer != null) {
writer.println(line);
writer.flush();
}
}
}
void log(Level level, String message) {
// Filter Message
boolean allow = (SubAPI.getInstance().getInternals().sudo == getHandler() && SubAPI.getInstance().getInternals().canSudo) || (log.value() && (SubAPI.getInstance().getInternals().sudo == null || !SubAPI.getInstance().getInternals().canSudo));
List<SubLogFilter> filters = new ArrayList<SubLogFilter>();
filters.addAll(this.filters);
for (SubLogFilter filter : filters) {
try {
allow = (filter.log(level, message) && allow);
} catch (Throwable e) {
new InvocationTargetException(e, "Exception while running SubLogger Event").printStackTrace();
}
}
// Log to CONSOLE
if (allow || !started) {
Logger.get(name).log(level, message);
}
}
@Override
public void stop() {
if (out != null) out.interrupt();
if (err != null) err.interrupt();
destroy();
try {
if (out != null) out.interrupt();
if (err != null) err.interrupt();
level = Level.INFO;
if (started) {
started = false;
if (writer != null) {
PrintWriter writer = this.writer;
this.writer = null;
int l = (("---------- LOG START \u2014 " + name + " ----------").length() - 9) / 2;
String s = "";
while (s.length() < l) s += '-';
if (writer != null) {
writer.println(s + " LOG END " + s);
writer.close();
}
}
}
} catch (NullPointerException e) {}
}
void destroy() {
filters.addAll(this.filters);
for (SubLogFilter filter : filters) try {
filter.stop();
} catch (Throwable e) {
new InvocationTargetException(e, "Exception while running SubLogger Event").printStackTrace();
}
}
@Override
public void registerFilter(SubLogFilter filter) {
if (Util.isNull(filter)) throw new NullPointerException();
Util.nullpo(filter);
filters.add(filter);
}
@Override
public void unregisterFilter(SubLogFilter filter) {
if (Util.isNull(filter)) throw new NullPointerException();
filters.remove(filter);
}
private void destroy() {
if (started) {
started = false;
List<SubLogFilter> filters = new ArrayList<SubLogFilter>();
filters.addAll(this.filters);
for (SubLogFilter filter : filters) try {
filter.stop();
} catch (Throwable e) {
new InvocationTargetException(e, "Exception while running SubLogger Event").printStackTrace();
}
messages.clear();
if (writer != null) {
PrintWriter writer = this.writer;
this.writer = null;
int l = (int) Math.floor((("---------- LOG START \u2014 " + name + " ----------").length() - 9) / 2);
String s = "";
while (s.length() < l) s += '-';
writer.println(s + " LOG END " + s);
writer.close();
}
}
Util.nullpo(filter);
Try.all.run(() -> filters.remove(filter));
}
@Override
@ -196,11 +219,6 @@ public class InternalSubLogger extends SubLogger {
@Override
public boolean isLogging() {
return log.get();
}
@Override
public List<LogMessage> getMessageHistory() {
return new LinkedList<LogMessage>(messages);
return log.value();
}
}

View File

@ -1,20 +1,29 @@
package net.ME1312.SubServers.Bungee.Host.Internal;
import net.ME1312.Galaxi.Library.Container.ContainedPair;
import net.ME1312.Galaxi.Library.Container.Container;
import net.ME1312.Galaxi.Library.Container.Value;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Map.ObjectMapValue;
import net.ME1312.Galaxi.Library.Try;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.Galaxi.Library.Version.Version;
import net.ME1312.SubData.Server.SubDataClient;
import net.ME1312.SubServers.Bungee.Event.*;
import net.ME1312.SubServers.Bungee.Host.*;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLValue;
import net.ME1312.SubServers.Bungee.Library.Container;
import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import net.ME1312.SubServers.Bungee.Library.NamedContainer;
import net.ME1312.SubServers.Bungee.Library.UniversalFile;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.Library.Version.Version;
import net.ME1312.SubServers.Bungee.SubPlugin;
import net.md_5.bungee.BungeeServerInfo;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketOutExEditServer;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketOutExEditServer.Edit;
import net.ME1312.SubServers.Bungee.SubAPI;
import net.ME1312.SubServers.Bungee.SubProxy;
import java.io.*;
import java.lang.reflect.Field;
import net.md_5.bungee.api.ChatColor;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@ -25,13 +34,13 @@ import java.util.jar.JarInputStream;
/**
* Internal SubServer Class
*/
public class InternalSubServer extends SubServerContainer {
public class InternalSubServer extends SubServerImpl {
private InternalHost host;
private boolean enabled;
private Container<Boolean> log;
private Value<Boolean> log;
private String dir;
private File directory;
private Executable executable;
private String executable;
private String stopcmd;
private StopAction stopaction;
private LinkedList<LoggedCommand> history;
@ -58,9 +67,34 @@ public class InternalSubServer extends SubServerContainer {
* @param restricted Restricted Status
* @throws InvalidServerException
*/
public InternalSubServer(InternalHost host, String name, boolean enabled, int port, String motd, boolean log, String directory, Executable executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
public static InternalSubServer construct(InternalHost host, String name, boolean enabled, int port, String motd, boolean log, String directory, String executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
try {
return new InternalSubServer(host, name, enabled, port, motd, log, directory, executable, stopcmd, hidden, restricted);
} catch (NoSuchMethodError e) {
return new InternalSubServer(host, name, enabled, (Integer) port, motd, log, directory, executable, stopcmd, hidden, restricted);
}
}
/**
* Super Method 2 (newest)
* @see #construct(InternalHost, String, boolean, int, String, boolean, String, String, String, boolean, boolean) for method details
*/
protected InternalSubServer(InternalHost host, String name, boolean enabled, int port, String motd, boolean log, String directory, String executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
super(host, name, port, motd, hidden, restricted);
if (Util.isNull(host, name, enabled, port, motd, log, directory, executable, stopcmd, hidden, restricted)) throw new NullPointerException();
init(host, name, enabled, port, motd, log, directory, executable, stopcmd, hidden, restricted);
}
/**
* Super Method 1 (oldest)
* @see #construct(InternalHost, String, boolean, int, String, boolean, String, String, String, boolean, boolean) for method details
*/
protected InternalSubServer(InternalHost host, String name, boolean enabled, Integer port, String motd, boolean log, String directory, String executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
super(host, name, port, motd, hidden, restricted);
init(host, name, enabled, port, motd, log, directory, executable, stopcmd, hidden, restricted);
}
private void init(InternalHost host, String name, boolean enabled, int port, String motd, boolean log, String directory, String executable, String stopcmd, boolean hidden, boolean restricted) throws InvalidServerException {
Util.nullpo(host, name, enabled, port, motd, log, directory, executable, stopcmd, hidden, restricted);
this.host = host;
this.enabled = enabled;
this.log = new Container<Boolean>(log);
@ -74,54 +108,62 @@ public class InternalSubServer extends SubServerContainer {
this.logger = new InternalSubLogger(null, this, getName(), this.log, null);
this.thread = null;
this.command = null;
final File[] locations = new File[] {
new File(this.directory, "plugins/SubServers.Client.jar"),
new File(this.directory, "mods/SubServers.Client.jar")
};
if (new UniversalFile(this.directory, "plugins:SubServers.Client.jar").exists()) {
try {
JarInputStream updated = new JarInputStream(SubPlugin.class.getResourceAsStream("/net/ME1312/SubServers/Bungee/Library/Files/client.jar"));
JarFile existing = new JarFile(new UniversalFile(this.directory, "plugins:SubServers.Client.jar"));
for (File location : locations) {
if (location.exists()) {
try {
JarInputStream updated = new JarInputStream(SubProxy.class.getResourceAsStream("/net/ME1312/SubServers/Bungee/Library/Files/client.jar"));
JarFile existing = new JarFile(location);
if (existing.getManifest().getMainAttributes().getValue("Implementation-Title") != null && existing.getManifest().getMainAttributes().getValue("Implementation-Title").startsWith("SubServers.Client") && existing.getManifest().getMainAttributes().getValue("Specification-Title") != null &&
updated.getManifest().getMainAttributes().getValue("Implementation-Title") != null && updated.getManifest().getMainAttributes().getValue("Implementation-Title").startsWith("SubServers.Client") && updated.getManifest().getMainAttributes().getValue("Specification-Title") != null) {
if (new Version(existing.getManifest().getMainAttributes().getValue("Specification-Title")).compareTo(new Version(updated.getManifest().getMainAttributes().getValue("Specification-Title"))) < 0) {
new UniversalFile(this.directory, "plugins:SubServers.Client.jar").delete();
Util.copyFromJar(SubPlugin.class.getClassLoader(), "net/ME1312/SubServers/Bungee/Library/Files/client.jar", new UniversalFile(this.directory, "plugins:SubServers.Client.jar").getPath());
if (existing.getManifest().getMainAttributes().getValue("Implementation-Title") != null && existing.getManifest().getMainAttributes().getValue("Implementation-Title").startsWith("SubServers.Client") && existing.getManifest().getMainAttributes().getValue("Specification-Title") != null &&
updated.getManifest().getMainAttributes().getValue("Implementation-Title") != null && updated.getManifest().getMainAttributes().getValue("Implementation-Title").startsWith("SubServers.Client") && updated.getManifest().getMainAttributes().getValue("Specification-Title") != null) {
if (new Version(existing.getManifest().getMainAttributes().getValue("Specification-Title")).compareTo(new Version(updated.getManifest().getMainAttributes().getValue("Specification-Title"))) < 0) {
location.delete();
Util.copyFromJar(SubProxy.class.getClassLoader(), "net/ME1312/SubServers/Bungee/Library/Files/client.jar", location.getPath());
}
}
existing.close();
updated.close();
} catch (Throwable e) {
System.out.println("Couldn't auto-update SubServers.Client for subserver: " + name);
e.printStackTrace();
}
existing.close();
updated.close();
} catch (Throwable e) {
System.out.println("Couldn't auto-update SubServers.Client.jar for " + name);
e.printStackTrace();
}
} else if (new UniversalFile(this.directory, "mods:SubServers.Client.jar").exists()) {
try {
JarInputStream updated = new JarInputStream(SubPlugin.class.getResourceAsStream("/net/ME1312/SubServers/Bungee/Library/Files/client.jar"));
JarFile existing = new JarFile(new UniversalFile(this.directory, "mods:SubServers.Client.jar"));
if (existing.getManifest().getMainAttributes().getValue("Implementation-Title") != null && existing.getManifest().getMainAttributes().getValue("Implementation-Title").startsWith("SubServers.Client") && existing.getManifest().getMainAttributes().getValue("Specification-Title") != null &&
updated.getManifest().getMainAttributes().getValue("Implementation-Title") != null && updated.getManifest().getMainAttributes().getValue("Implementation-Title").startsWith("SubServers.Client") && updated.getManifest().getMainAttributes().getValue("Specification-Title") != null) {
if (new Version(existing.getManifest().getMainAttributes().getValue("Specification-Title")).compareTo(new Version(updated.getManifest().getMainAttributes().getValue("Specification-Title"))) < 0) {
new UniversalFile(this.directory, "mods:SubServers.Client.jar").delete();
Util.copyFromJar(SubPlugin.class.getClassLoader(), "net/ME1312/SubServers/Bungee/Library/Files/client.jar", new UniversalFile(this.directory, "mods:SubServers.Client.jar").getPath());
}
}
existing.close();
updated.close();
} catch (Throwable e) {
System.out.println("Couldn't auto-update SubServers.Client.jar for " + name);
e.printStackTrace();
}
}
this.lock = false;
}
void registered(boolean value) {
registered = value;
}
void updating(boolean value) {
updating = value;
}
private void run() {
boolean locked = lock;
allowrestart = true;
stopping = false;
started = false;
try {
process = Runtime.getRuntime().exec(executable.toString(), null, directory);
System.out.println("SubServers > Now starting " + getName());
ProcessBuilder pb = new ProcessBuilder().command(Executable.parse(host.getCreator().getBashDirectory(), executable)).directory(directory);
pb.environment().put("java", System.getProperty("java.home") + File.separator + "bin" + File.separator + "java");
pb.environment().put("name", getName());
pb.environment().put("host", host.getName());
pb.environment().put("address", host.getAddress().getHostAddress());
pb.environment().put("port", Integer.toString(getAddress().getPort()));
logger.init();
process = pb.start();
Logger.get("SubServers").info("Now starting " + getName());
logger.process = process;
logger.start();
lock = locked = false;
command = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
for (LoggedCommand command : history) if (process.isAlive()) {
this.command.write(command.getCommand());
@ -132,25 +174,32 @@ public class InternalSubServer extends SubServerContainer {
if (process.isAlive()) process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
if (locked) lock = false;
allowrestart = false;
}
SubStoppedEvent event = new SubStoppedEvent(this);
host.plugin.getPluginManager().callEvent(event);
System.out.println("SubServers > " + getName() + " has stopped");
logger.destroy();
Logger.get("SubServers").info(getName() + " has stopped");
process = null;
command = null;
started = false;
stopping = false;
history.clear();
if (stopaction == StopAction.REMOVE_SERVER || stopaction == StopAction.DELETE_SERVER) {
SubStoppedEvent event = new SubStoppedEvent(this);
host.plugin.getPluginManager().callEvent(event);
if (stopaction == StopAction.REMOVE_SERVER || stopaction == StopAction.RECYCLE_SERVER || stopaction == StopAction.DELETE_SERVER) {
try {
if (stopaction == StopAction.DELETE_SERVER) {
host.deleteSubServer(getName());
if (stopaction == StopAction.RECYCLE_SERVER) {
host.recycleSubServer(null, getName(), false, false);
} else if (stopaction == StopAction.DELETE_SERVER) {
host.deleteSubServer(null, getName(), false, false);
} else {
try {
if (host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
host.plugin.config.get().getSection("Servers").remove(getName());
host.plugin.config.save();
if (host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
host.plugin.servers.get().getMap("Servers").remove(getName());
host.plugin.servers.save();
}
} catch (IOException e) {
e.printStackTrace();
@ -171,22 +220,24 @@ public class InternalSubServer extends SubServerContainer {
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}, "SubServers.Bungee::Internal_Server_Restart_Handler(" + getName() + ')').start();
}
}
}
@Override
public boolean start(UUID player) {
if (!lock && isEnabled() && !(thread != null && thread.isAlive()) && getCurrentIncompatibilities().size() == 0) {
if (!lock && isAvailable() && isEnabled() && !(thread != null && thread.isAlive()) && getCurrentIncompatibilities().size() == 0) {
lock = true;
SubStartEvent event = new SubStartEvent(player, this);
host.plugin.getPluginManager().callEvent(event);
lock = false;
if (!event.isCancelled()) {
(thread = new Thread(this::run)).start();
(thread = new Thread(this::run, "SubServers.Bungee::Internal_Server_Process_Handler(" + getName() + ')')).start();
return true;
} else return false;
} else {
lock = false;
return false;
}
} else return false;
}
@ -197,6 +248,7 @@ public class InternalSubServer extends SubServerContainer {
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
try {
stopping = true;
allowrestart = false;
history.add(new LoggedCommand(player, stopcmd));
if (process != null && process.isAlive()) {
@ -219,8 +271,9 @@ public class InternalSubServer extends SubServerContainer {
SubStopEvent event = new SubStopEvent(player, this, true);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
stopping = true;
allowrestart = false;
if (process != null && process.isAlive()) process.destroyForcibly();
if (process != null && process.isAlive()) Executable.terminate(process);
return true;
} else return false;
} else return false;
@ -228,13 +281,16 @@ public class InternalSubServer extends SubServerContainer {
@Override
public boolean command(UUID player, String command) {
if (Util.isNull(command)) throw new NullPointerException();
Util.nullpo(command);
if (thread != null && thread.isAlive()) {
SubSendCommandEvent event = new SubSendCommandEvent(player, this, command);
SubSendCommandEvent event = new SubSendCommandEvent(player, this, command, null);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
if (!event.isCancelled() && (player == null || !DISALLOWED_COMMANDS.matcher(command).find())) {
try {
if (event.getCommand().equalsIgnoreCase(stopcmd)) allowrestart = false;
if (event.getCommand().equalsIgnoreCase(stopcmd)) {
stopping = true;
allowrestart = false;
}
history.add(new LoggedCommand(player, event.getCommand()));
if (process != null && process.isAlive()) {
this.command.write(event.getCommand());
@ -250,261 +306,275 @@ public class InternalSubServer extends SubServerContainer {
} else return false;
}
@SuppressWarnings("deprecation")
public int edit(UUID player, YAMLSection edit) {
int c = 0;
boolean state = isRunning();
SubServer forward = null;
YAMLSection pending = edit.clone();
for (String key : edit.getKeys()) {
pending.remove(key);
YAMLValue value = edit.get(key);
SubEditServerEvent event = new SubEditServerEvent(player, this, new NamedContainer<String, YAMLValue>(key, value), true);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
try {
switch (key) {
case "name":
if (value.isString() && host.removeSubServer(player, getName())) {
SubServer server = host.addSubServer(player, value.asRawString(), isEnabled(), getAddress().getPort(), getMotd(), isLogging(), getPath(), getExecutable(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
YAMLSection config = this.host.plugin.config.get().getSection("Servers").getSection(getName());
this.host.plugin.config.get().getSection("Servers").remove(getName());
this.host.plugin.config.get().getSection("Servers").set(server.getName(), config);
this.host.plugin.config.save();
@SuppressWarnings({"deprecation", "unchecked"})
@Override
protected int edit(UUID player, ObjectMap<String> edit, boolean perma) {
if (isAvailable()) {
int c = 0;
boolean state = isRunning();
SubServer forward = null;
ObjectMap<String> pending = edit.clone();
for (String key : edit.getKeys()) {
pending.remove(key);
ObjectMapValue value = edit.get(key);
boolean allowed = true;
if (perma) {
SubEditServerEvent event = new SubEditServerEvent(player, this, new ContainedPair<String, ObjectMapValue>(key, value));
host.plugin.getPluginManager().callEvent(event);
allowed = !event.isCancelled();
}
if (allowed) {
try {
switch (key.toLowerCase()) {
case "name":
if (value.isString() && host.removeSubServer(player, getName())) {
SubServer server = host.constructSubServer(value.asString(), isEnabled(), getAddress().getPort(), getMotd(), isLogging(), getPath(), getExecutable(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
ObjectMap<String> config = this.host.plugin.servers.get().getMap("Servers").getMap(getName());
this.host.plugin.servers.get().getMap("Servers").remove(getName());
this.host.plugin.servers.get().getMap("Servers").set(server.getName(), config);
this.host.plugin.servers.save();
}
forward = server;
c++;
}
forward = server;
c++;
}
}
break;
case "display":
if (value.isString()) {
Field f = ServerContainer.class.getDeclaredField("nick");
f.setAccessible(true);
if (value == null || value.asString().length() == 0 || getName().equals(value)) {
f.set(this, null);
} else {
f.set(this, value.asString());
}
f.setAccessible(false);
logger.name = getDisplayName();
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
if (getName().equals(getDisplayName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).remove("Display");
} else {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Display", getDisplayName());
}
this.host.plugin.config.save();
}
c++;
}
break;
case "enabled":
if (value.isBoolean()) {
enabled = value.asBoolean();
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Enabled", isEnabled());
this.host.plugin.config.save();
}
c++;
}
break;
case "group":
if (value.isList()) {
Field f = ServerContainer.class.getDeclaredField("groups");
f.setAccessible(true);
f.set(this, value.asStringList());
f.setAccessible(false);
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Group", value.asStringList());
this.host.plugin.config.save();
}
c++;
}
break;
case "host":
if (value.isString() && host.removeSubServer(player, getName())) {
SubServer server = this.host.plugin.api.getHost(value.asRawString()).addSubServer(player, getName(), isEnabled(), getAddress().getPort(), getMotd(), isLogging(), getPath(), getExecutable(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Host", server.getHost().getName());
this.host.plugin.config.save();
}
forward = server;
c++;
}
}
break;
case "port":
if (value.isNumber() && host.removeSubServer(player, getName())) {
SubServer server = host.addSubServer(player, getName(), isEnabled(), value.asInt(), getMotd(), isLogging(), getPath(), getExecutable(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Port", server.getAddress().getPort());
this.host.plugin.config.save();
}
forward = server;
c++;
}
}
break;
case "motd":
if (value.isString()) {
Field f = BungeeServerInfo.class.getDeclaredField("motd");
f.setAccessible(true);
f.set(this, value.asColoredString('&'));
f.setAccessible(false);
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Motd", value.asString());
this.host.plugin.config.save();
}
c++;
}
break;
case "log":
if (value.isBoolean()) {
log.set(value.asBoolean());
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Log", isLogging());
this.host.plugin.config.save();
}
c++;
}
break;
case "dir":
if (value.isString()) {
if (isRunning()) {
stop(player);
waitFor();
}
dir = value.asRawString();
directory = new File(getHost().getPath(), value.asRawString());
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Directory", getPath());
this.host.plugin.config.save();
}
c++;
}
break;
case "exec":
if (value.isString()) {
if (isRunning()) {
stop(player);
waitFor();
}
executable = new Executable(value.asRawString());
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Executable", value.asRawString());
this.host.plugin.config.save();
}
c++;
}
break;
case "stop-cmd":
if (value.isString()) {
stopcmd = value.asRawString();
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Stop-Command", getStopCommand());
this.host.plugin.config.save();
}
c++;
}
break;
case "stop-action":
if (value.isString()) {
StopAction action = Util.getDespiteException(() -> StopAction.valueOf(value.asRawString().toUpperCase().replace('-', '_').replace(' ', '_')), null);
if (action != null) {
stopaction = action;
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Stop-Action", getStopAction().toString());
this.host.plugin.config.save();
break;
case "display":
if (value.isString()) {
setDisplayName(value.asString());
logger.name = getDisplayName();
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
if (getName().equals(getDisplayName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).remove("Display");
} else {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Display", getDisplayName());
}
this.host.plugin.servers.save();
}
c++;
}
}
break;
case "state":
if (value.isBoolean()) {
state = value.asBoolean();
}
break;
case "auto-run":
if (value.isBoolean()) {
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Run-On-Launch", value.asBoolean());
this.host.plugin.config.save();
break;
case "enabled":
if (value.isBoolean()) {
enabled = value.asBoolean();
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Enabled", isEnabled());
this.host.plugin.servers.save();
}
c++;
}
c++;
}
break;
case "incompatible":
if (value.isList()) {
for (String oname : value.asStringList()) {
SubServer oserver = host.plugin.api.getSubServer(oname);
if (oserver != null && isCompatible(oserver)) toggleCompatibility(oserver);
break;
case "group":
if (value.isList()) {
Util.reflect(ServerImpl.class.getDeclaredField("groups"), this, value.asStringList());
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Group", value.asStringList());
this.host.plugin.servers.save();
}
c++;
}
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Incompatible", value.asStringList());
this.host.plugin.config.save();
break;
case "host":
if (value.isString() && host.removeSubServer(player, getName())) {
SubServer server = this.host.plugin.api.getHost(value.asString()).constructSubServer(getName(), isEnabled(), getAddress().getPort(), getMotd(), isLogging(), getPath(), getExecutable(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Host", server.getHost().getName());
this.host.plugin.servers.save();
}
forward = server;
c++;
}
}
c++;
}
break;
case "restricted":
if (value.isBoolean()) {
Field f = BungeeServerInfo.class.getDeclaredField("restricted");
f.setAccessible(true);
f.set(this, value.asBoolean());
f.setAccessible(false);
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Restricted", isRestricted());
this.host.plugin.config.save();
break;
case "template":
if (value.isString()) {
setTemplate(value.asString());
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Template", value.asString());
this.host.plugin.servers.save();
}
c++;
}
c++;
}
break;
case "hidden":
if (value.isBoolean()) {
Field f = ServerContainer.class.getDeclaredField("hidden");
f.setAccessible(true);
f.set(this, value.asBoolean());
f.setAccessible(false);
if (this.host.plugin.config.get().getSection("Servers").getKeys().contains(getName())) {
this.host.plugin.config.get().getSection("Servers").getSection(getName()).set("Hidden", isHidden());
this.host.plugin.config.save();
break;
case "port":
if (value.isNumber() && host.removeSubServer(player, getName())) {
SubServer server = host.constructSubServer(getName(), isEnabled(), value.asInt(), getMotd(), isLogging(), getPath(), getExecutable(), getStopCommand(), isHidden(), isRestricted());
if (server != null) {
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Port", server.getAddress().getPort());
this.host.plugin.servers.save();
}
forward = server;
c++;
}
}
c++;
}
break;
}
if (forward != null) {
forward.setStopAction(getStopAction());
if (!getName().equals(getDisplayName())) forward.setDisplayName(getDisplayName());
List<String> groups = new ArrayList<String>();
groups.addAll(getGroups());
for (String group : groups) {
removeGroup(group);
forward.addGroup(group);
break;
case "motd":
if (value.isString()) {
setMotd(ChatColor.translateAlternateColorCodes('&', Util.unescapeJavaString(value.asString())));
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Motd", value.asString());
this.host.plugin.servers.save();
}
c++;
}
break;
case "log":
if (value.isBoolean()) {
log.value(value.asBoolean());
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Log", isLogging());
this.host.plugin.servers.save();
}
c++;
}
break;
case "dir":
case "directory":
if (value.isString()) {
if (isRunning()) {
stop(player);
waitFor();
}
dir = value.asString();
directory = new File(getHost().getPath(), value.asString());
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Directory", getPath());
this.host.plugin.servers.save();
}
c++;
}
break;
case "exec":
case "executable":
if (value.isString()) {
if (isRunning()) {
stop(player);
waitFor();
}
executable = value.asString();
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Executable", value.asString());
this.host.plugin.servers.save();
}
c++;
}
break;
case "stop-cmd":
case "stop-command":
if (value.isString()) {
stopcmd = value.asString();
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Stop-Command", getStopCommand());
this.host.plugin.servers.save();
}
c++;
}
break;
case "stop-action":
if (value.isString()) {
StopAction action = Try.all.get(() -> StopAction.valueOf(value.asString().toUpperCase().replace('-', '_').replace(' ', '_')));
if (action != null) {
stopaction = action;
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Stop-Action", getStopAction().toString());
this.host.plugin.servers.save();
}
c++;
}
}
break;
case "state":
if (value.isBoolean()) {
state = value.asBoolean();
}
break;
case "auto-run":
case "run-on-launch":
if (value.isBoolean()) {
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Run-On-Launch", value.asBoolean());
this.host.plugin.servers.save();
}
c++;
}
break;
case "incompatible":
if (value.isList()) {
for (SubServer oserver : getIncompatibilities()) toggleCompatibility(oserver);
for (String oname : (List<String>) value.asStringList()) {
SubServer oserver = host.plugin.api.getSubServer(oname);
if (oserver != null && isCompatible(oserver)) toggleCompatibility(oserver);
}
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Incompatible", value.asStringList());
this.host.plugin.servers.save();
}
c++;
}
break;
case "restricted":
if (value.isBoolean()) {
setRestricted(value.asBoolean());
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Restricted", isRestricted());
this.host.plugin.servers.save();
}
c++;
}
break;
case "hidden":
if (value.isBoolean()) {
setHidden(value.asBoolean());
if (perma && this.host.plugin.servers.get().getMap("Servers").getKeys().contains(getName())) {
this.host.plugin.servers.get().getMap("Servers").getMap(getName()).set("Hidden", isHidden());
this.host.plugin.servers.save();
}
c++;
}
break;
case "whitelist":
if (value.isList()) {
Util.reflect(ServerImpl.class.getDeclaredField("whitelist"), this, value.asUUIDList());
if (isRegistered()) for (Proxy proxy : SubAPI.getInstance().getProxies().values()) if (proxy.getSubData()[0] != null) {
((SubDataClient) proxy.getSubData()[0]).sendPacket(new PacketOutExEditServer(this, Edit.WHITELIST_SET, value.asUUIDList()));
}
c++;
}
break;
}
for (SubServer server : getIncompatibilities()) {
toggleCompatibility(server);
forward.toggleCompatibility(server);
}
for (String extra : getExtra().getKeys()) forward.addExtra(extra, getExtra(extra));
if (forward != null) {
forward.setStopAction(getStopAction());
if (!getName().equals(getDisplayName())) forward.setDisplayName(getDisplayName());
forward.setTemplate(getTemplate());
List<String> groups = new ArrayList<String>();
groups.addAll(getGroups());
for (String group : groups) {
removeGroup(group);
forward.addGroup(group);
}
for (SubServer server : getIncompatibilities()) {
toggleCompatibility(server);
forward.toggleCompatibility(server);
}
for (String extra : getExtra().getKeys()) forward.addExtra(extra, getExtra(extra));
forward.getHost().addSubServer(player, forward);
if (state) pending.set("state", true);
c += forward.edit(player, pending);
break;
if (state) pending.set("state", true);
c += (perma)?forward.permaEdit(player, pending):forward.edit(player, pending);
break;
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (!isRunning() && forward == null && state) start(player);
return c;
if (!isRunning() && forward == null && state) start(player);
return c;
} else return -1;
}
@Override
@ -516,7 +586,7 @@ public class InternalSubServer extends SubServerContainer {
@Override
public boolean isRunning() {
return process != null && process.isAlive();
return (process != null && process.isAlive()) || lock;
}
@Override
@ -532,26 +602,24 @@ public class InternalSubServer extends SubServerContainer {
@Override
public boolean isEnabled() {
return enabled;
return enabled && host.isEnabled();
}
@Override
public void setEnabled(boolean value) {
if (Util.isNull(value)) throw new NullPointerException();
host.plugin.getPluginManager().callEvent(new SubEditServerEvent(null, this, new NamedContainer<String, Object>("enabled", value), false));
Util.nullpo(value);
enabled = value;
}
@Override
public boolean isLogging() {
return log.get();
return log.value();
}
@Override
public void setLogging(boolean value) {
if (Util.isNull(value)) throw new NullPointerException();
host.plugin.getPluginManager().callEvent(new SubEditServerEvent(null, this, new NamedContainer<String, Object>("log", value), false));
log.set(value);
Util.nullpo(value);
log.value(value);
}
@Override
@ -570,7 +638,7 @@ public class InternalSubServer extends SubServerContainer {
}
@Override
public Executable getExecutable() {
public String getExecutable() {
return executable;
}
@ -581,8 +649,7 @@ public class InternalSubServer extends SubServerContainer {
@Override
public void setStopCommand(String value) {
if (Util.isNull(value)) throw new NullPointerException();
host.plugin.getPluginManager().callEvent(new SubEditServerEvent(null, this, new NamedContainer<String, Object>("stop-cmd", value), false));
Util.nullpo(value);
stopcmd = value;
}
@ -593,8 +660,7 @@ public class InternalSubServer extends SubServerContainer {
@Override
public void setStopAction(StopAction action) {
if (Util.isNull(action)) throw new NullPointerException();
host.plugin.getPluginManager().callEvent(new SubEditServerEvent(null, this, new NamedContainer<String, Object>("stop-action", action), false));
Util.nullpo(action);
stopaction = action;
}
}

View File

@ -1,15 +1,17 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.Galaxi.Library.ExtraDataHandler;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Map.ObjectMapValue;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubData.Server.ClientHandler;
import net.ME1312.SubData.Server.DataClient;
import net.ME1312.SubData.Server.SubDataClient;
import net.ME1312.SubServers.Bungee.Event.SubRemoveProxyEvent;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLValue;
import net.ME1312.SubServers.Bungee.Library.ExtraDataHandler;
import net.ME1312.SubServers.Bungee.Library.NamedContainer;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.Network.Client;
import net.ME1312.SubServers.Bungee.Network.ClientHandler;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketExSyncPlayer;
import net.ME1312.SubServers.Bungee.SubAPI;
import net.ME1312.SubServers.Bungee.SubPlugin;
import net.ME1312.SubServers.Bungee.SubProxy;
import net.md_5.bungee.api.ProxyServer;
import java.util.*;
@ -17,39 +19,70 @@ import java.util.*;
/**
* Proxy Class
*/
public class Proxy implements ClientHandler, ExtraDataHandler {
private YAMLSection extra = new YAMLSection();
public class Proxy implements ClientHandler, ExtraDataHandler<String> {
private final HashMap<Integer, SubDataClient> subdata = new HashMap<Integer, SubDataClient>();
private final ObjectMap<String> extra = new ObjectMap<String>();
private final String signature;
private boolean persistent = true;
private Client client = null;
private boolean persistent = false;
private String nick = null;
private final String name;
@SuppressWarnings("deprecation")
public Proxy(String name) throws IllegalArgumentException {
if (name == null) {
name = Util.getNew(SubAPI.getInstance().getInternals().proxies.keySet(), () -> UUID.randomUUID().toString());
persistent = false;
}
if (name == null) name = Util.getNew(SubAPI.getInstance().getInternals().proxies.keySet(), () -> UUID.randomUUID().toString());
if (name.contains(" ")) throw new IllegalArgumentException("Proxy names cannot have spaces: " + name);
this.name = name;
this.signature = SubAPI.getInstance().signAnonymousObject();
subdata.put(0, null);
}
@Override
public Client getSubData() {
return client;
public DataClient[] getSubData() {
Integer[] keys = subdata.keySet().toArray(new Integer[0]);
DataClient[] channels = new DataClient[keys.length];
Arrays.sort(keys);
for (int i = 0; i < keys.length; ++i) channels[i] = subdata.get(keys[i]);
return channels;
}
@Override
@SuppressWarnings("deprecation")
public void setSubData(Client client) {
this.client = client;
if (client == null && !persistent) {
ProxyServer.getInstance().getPluginManager().callEvent(new SubRemoveProxyEvent(this));
SubAPI.getInstance().getInternals().proxies.remove(getName().toLowerCase());
public void setSubData(SubDataClient client, int channel) {
boolean update = false;
if (channel < 0) throw new IllegalArgumentException("Subchannel ID cannot be less than zero");
if (client != null || channel == 0) {
if (!subdata.containsKey(channel) || (channel == 0 && (client == null || subdata.get(channel) == null))) {
update = true;
subdata.put(channel, client);
if (client != null && (client.getHandler() == null || !equals(client.getHandler()))) client.setHandler(this);
}
} else {
update = true;
subdata.remove(channel);
}
if (client != null && (client.getHandler() == null || !equals(client.getHandler()))) client.setHandler(this);
if (update) {
DataClient[] subdata = getSubData();
if (subdata[0] == null && subdata.length <= 1) {
SubProxy plugin = SubAPI.getInstance().getInternals();
for (UUID id : Util.getBackwards(plugin.rPlayerLinkP, this)) {
plugin.rPlayerLinkS.remove(id);
plugin.rPlayerLinkP.remove(id);
plugin.rPlayers.remove(id);
}
for (Proxy proxy : SubAPI.getInstance().getProxies().values()) if (proxy.getSubData()[0] != null && proxy != this) {
((SubDataClient) proxy.getSubData()[0]).sendPacket(new PacketExSyncPlayer(getName(), null, (RemotePlayer[]) null));
}
if (!persistent) {
ProxyServer.getInstance().getPluginManager().callEvent(new SubRemoveProxyEvent(this));
SubAPI.getInstance().getInternals().proxies.remove(getName().toLowerCase());
}
}
}
}
@Override
public void removeSubData(DataClient client) {
for (Integer channel : Util.getBackwards(subdata, (SubDataClient) client)) setSubData(null, channel);
}
/**
@ -84,34 +117,36 @@ public class Proxy implements ClientHandler, ExtraDataHandler {
}
/**
* Test if the proxy is connected to RedisBungee's server
* Determine if the proxy is the Master Proxy
*
* @return Redis Status
* @return Master Proxy Status
*/
@SuppressWarnings({"deprecation", "unchecked"})
public boolean isRedis() {
SubPlugin plugin = SubAPI.getInstance().getInternals();
return plugin.redis != null && Util.getDespiteException(() -> plugin.redis("getPlayersOnProxy", new NamedContainer<>(String.class, getName())) != null, false);
public boolean isMaster() {
return SubAPI.getInstance().getMasterProxy() == this;
}
/**
* Get the players on this proxy (via RedisBungee)
* Get the players on this proxy
*
* @return Player Collection
* @return Remote Player Collection
*/
@SuppressWarnings({"deprecation", "unchecked"})
public Collection<NamedContainer<String, UUID>> getPlayers() {
List<NamedContainer<String, UUID>> players = new ArrayList<NamedContainer<String, UUID>>();
SubPlugin plugin = SubAPI.getInstance().getInternals();
if (plugin.redis != null) {
try {
for (UUID player : (Set<UUID>) plugin.redis("getPlayersOnProxy", new NamedContainer<>(String.class, getName())))
players.add(new NamedContainer<>((String) plugin.redis("getNameFromUuid", new NamedContainer<>(UUID.class, player)), player));
} catch (Exception e) {}
@SuppressWarnings("deprecation")
public Collection<RemotePlayer> getPlayers() {
SubProxy plugin = SubAPI.getInstance().getInternals();
ArrayList<RemotePlayer> players = new ArrayList<RemotePlayer>();
for (UUID id : Util.getBackwards(plugin.rPlayerLinkP, this)) {
players.add(plugin.rPlayers.get(id));
}
return players;
}
/**
* Makes it so the proxy object will still exist within the server manager even if it is disconnected
*/
public final void persist() {
persistent = true;
}
/**
* Get the Signature of this Object
*
@ -121,52 +156,56 @@ public class Proxy implements ClientHandler, ExtraDataHandler {
return signature;
}
@Override
public boolean equals(Object obj) {
return obj instanceof Proxy && signature.equals(((Proxy) obj).signature);
}
@Override
public void addExtra(String handle, Object value) {
if (Util.isNull(handle, value)) throw new NullPointerException();
Util.nullpo(handle, value);
extra.set(handle, value);
}
@Override
public boolean hasExtra(String handle) {
if (Util.isNull(handle)) throw new NullPointerException();
Util.nullpo(handle);
return extra.getKeys().contains(handle);
}
@Override
public YAMLValue getExtra(String handle) {
if (Util.isNull(handle)) throw new NullPointerException();
public ObjectMapValue getExtra(String handle) {
Util.nullpo(handle);
return extra.get(handle);
}
@Override
public YAMLSection getExtra() {
public ObjectMap<String> getExtra() {
return extra.clone();
}
@Override
public void removeExtra(String handle) {
if (Util.isNull(handle)) throw new NullPointerException();
Util.nullpo(handle);
extra.remove(handle);
}
@Override
public String toString() {
YAMLSection info = new YAMLSection();
public ObjectMap<String> forSubData() {
ObjectMap<String> info = new ObjectMap<String>();
info.set("type", "Proxy");
info.set("name", getName());
info.set("display", getDisplayName());
YAMLSection players = new YAMLSection();
for (NamedContainer<String, UUID> player : getPlayers()) {
YAMLSection pinfo = new YAMLSection();
pinfo.set("name", player.name());
players.set(player.get().toString(), pinfo);
}
ObjectMap<String> players = new ObjectMap<String>();
for (RemotePlayer player : getPlayers())
players.set(player.getUniqueId().toString(), player.getName());
info.set("players", players);
info.set("redis", isRedis());
if (getSubData() != null) info.set("subdata", getSubData().getAddress().toString());
info.set("master", isMaster());
ObjectMap<Integer> subdata = new ObjectMap<Integer>();
for (int channel : this.subdata.keySet()) subdata.set(channel, (this.subdata.get(channel) == null)?null:this.subdata.get(channel).getID());
info.set("subdata", subdata);
info.set("signature", signature);
info.set("extra", getExtra());
return info.toJSON();
return info;
}
}

View File

@ -0,0 +1,314 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.Galaxi.Library.Container.ContainedPair;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubData.Server.SubDataClient;
import net.ME1312.SubData.Server.SubDataSerializable;
import net.ME1312.SubServers.Bungee.Library.Compatibility.RPSI;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketDisconnectPlayer;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketMessagePlayer;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketTransferPlayer;
import net.ME1312.SubServers.Bungee.SubAPI;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.UUID;
import java.util.function.IntConsumer;
/**
* Remote Player Class
*/
public class RemotePlayer implements net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer, SubDataSerializable {
private ProxiedPlayer local;
private UUID id;
private String name;
private InetSocketAddress ip;
private Proxy proxy;
private Server server;
/**
* Translate a Local Player to a Remote Player
*
* @param player Local Player
*/
public RemotePlayer(ProxiedPlayer player) {
this(player, player.getServer().getInfo());
}
/**
* Translate a Local Player to a Remote Player
*
* @param player Local Player
* @param server Server the player is on
*/
public RemotePlayer(ProxiedPlayer player, ServerInfo server) {
Util.nullpo(player);
this.local = player;
this.id = player.getUniqueId();
this.server = (server instanceof Server)? (Server) server : null;
}
/**
* Search for a Remote Player using their ID
*
* @param name Player Name
* @param id Player UUID
* @param proxy Proxy the player is on
* @param server Server the player is on
* @param ip Player IP Address
*/
public RemotePlayer(String name, UUID id, Proxy proxy, ServerInfo server, InetSocketAddress ip) {
Util.nullpo(name, id, proxy, ip);
this.id = id;
this.name = name;
this.ip = ip;
this.proxy = proxy;
this.server = (server instanceof Server)? (Server) server : null;
}
@Override
public ProxiedPlayer get() {
return local;
}
private static ProxiedPlayer get(UUID player) {
return ProxyServer.getInstance().getPlayer(player);
}
@Override
public UUID getUniqueId() {
if (local != null) {
return local.getUniqueId();
} else return id;
}
@Override
public String getName() {
if (local != null) {
return local.getName();
} else return name;
}
@SuppressWarnings("deprecation")
@Override
public InetSocketAddress getAddress() {
if (local != null) {
return local.getAddress();
} else return ip;
}
/**
* Gets the proxy this player is connected to.
*
* @return the proxy this player is connected to
*/
public Proxy getProxy() {
if (local != null) {
return SubAPI.getInstance().getMasterProxy();
} else return proxy;
}
@Override
public String getProxyName() {
Proxy proxy = getProxy();
return (proxy == null)? null : proxy.getName();
}
private SubDataClient getProxyConnection() {
Proxy proxy = getProxy();
return (proxy == null)? null : (SubDataClient) proxy.getSubData()[0];
}
@Override
public Server getServer() {
return server;
}
@Override
public String getServerName() {
Server server = getServer();
return (server == null)? null : server.getName();
}
@Override
public boolean equals(Object obj) {
return obj instanceof RemotePlayer && getUniqueId().equals(((RemotePlayer) obj).getUniqueId());
}
@Override
public ObjectMap<String> forSubData() {
ObjectMap<String> pinfo = new ObjectMap<String>();
pinfo.set("name", getName());
pinfo.set("id", getUniqueId());
pinfo.set("address", getAddress().getAddress().getHostAddress() + ':' + getAddress().getPort());
if (getServer() != null) pinfo.set("server", getServer().getName());
if (getProxy() != null) pinfo.set("proxy", getProxy().getName());
return pinfo;
}
static {
// These overrides provide for the static methods in BungeeCommon
new RPSI() {
@Override
protected void sendMessage(UUID[] players, String[] messages, IntConsumer response) {
StackTraceElement[] origin = new Throwable().getStackTrace();
PacketMessagePlayer.run(Arrays.asList(players), new ContainedPair<>(messages, null), null, i -> {
try {
response.accept(i);
} catch (Throwable e) {
Throwable ew = new InvocationTargetException(e);
ew.setStackTrace(origin);
ew.printStackTrace();
}
});
}
@Override
protected void sendMessage(UUID[] players, BaseComponent[][] messages, IntConsumer response) {
StackTraceElement[] origin = new Throwable().getStackTrace();
PacketMessagePlayer.run(Arrays.asList(players), new ContainedPair<>(null, messages), null, i -> {
try {
response.accept(i);
} catch (Throwable e) {
Throwable ew = new InvocationTargetException(e);
ew.setStackTrace(origin);
ew.printStackTrace();
}
});
}
@Override
protected void transfer(UUID[] players, String server, IntConsumer response) {
StackTraceElement[] origin = new Throwable().getStackTrace();
PacketTransferPlayer.run(Arrays.asList(players), server, i -> {
try {
response.accept(i);
} catch (Throwable e) {
Throwable ew = new InvocationTargetException(e);
ew.setStackTrace(origin);
ew.printStackTrace();
}
});
}
@Override
protected void disconnect(UUID[] players, String reason, IntConsumer response) {
StackTraceElement[] origin = new Throwable().getStackTrace();
PacketDisconnectPlayer.run(Arrays.asList(players), reason, i -> {
try {
response.accept(i);
} catch (Throwable e) {
Throwable ew = new InvocationTargetException(e);
ew.setStackTrace(origin);
ew.printStackTrace();
}
});
}
};
}
// The following methods all redirect to their BungeeCommon counterparts
public static void broadcastMessage(String... messages) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.broadcastMessage(messages);
}
public static void broadcastMessage(String message, IntConsumer response) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.broadcastMessage(message, response);
}
public static void broadcastMessage(String[] messages, IntConsumer response) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.broadcastMessage(messages, response);
}
public static void sendMessage(UUID[] players, String... messages) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.sendMessage(players, messages);
}
public static void sendMessage(UUID[] players, String message, IntConsumer response) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.sendMessage(players, message, response);
}
public static void sendMessage(UUID[] players, String[] messages, IntConsumer response) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.sendMessage(players, messages, response);
}
public static void broadcastMessage(BaseComponent... message) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.broadcastMessage(message);
}
public static void broadcastMessage(BaseComponent message, IntConsumer response) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.broadcastMessage(message, response);
}
public static void broadcastMessage(BaseComponent[] message, IntConsumer response) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.broadcastMessage(message, response);
}
public static void broadcastMessage(BaseComponent[]... messages) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.broadcastMessage(messages);
}
public static void broadcastMessage(BaseComponent[][] messages, IntConsumer response) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.broadcastMessage(messages, response);
}
public static void sendMessage(UUID[] players, BaseComponent... message) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.sendMessage(players, message);
}
public static void sendMessage(UUID[] players, BaseComponent message, IntConsumer response) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.sendMessage(players, message, response);
}
public static void sendMessage(UUID[] players, BaseComponent[] message, IntConsumer response) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.sendMessage(players, message, response);
}
public static void sendMessage(UUID[] players, BaseComponent[]... messages) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.sendMessage(players, messages);
}
public static void sendMessage(UUID[] players, BaseComponent[][] messages, IntConsumer response) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.sendMessage(players, messages, response);
}
public static void transfer(UUID[] players, String server) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.transfer(players, server);
}
public static void transfer(UUID[] players, String server, IntConsumer response) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.transfer(players, server, response);
}
public static void transfer(UUID[] players, ServerInfo server) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.transfer(players, server);
}
public static void transfer(UUID[] players, ServerInfo server, IntConsumer response) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.transfer(players, server, response);
}
public static void disconnect(UUID... players) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.disconnect(players);
}
public static void disconnect(UUID[] players, IntConsumer response) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.disconnect(players, response);
}
public static void disconnect(UUID[] players, String reason) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.disconnect(players, reason);
}
public static void disconnect(UUID[] players, String reason, IntConsumer response) {
net.ME1312.SubServers.Bungee.Library.Compatibility.RemotePlayer.disconnect(players, reason, response);
}
}

View File

@ -1,8 +1,9 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.SubServers.Bungee.Library.ExtraDataHandler;
import net.ME1312.SubServers.Bungee.Library.NamedContainer;
import net.ME1312.SubServers.Bungee.Network.ClientHandler;
import net.ME1312.Galaxi.Library.ExtraDataHandler;
import net.ME1312.SubData.Server.ClientHandler;
import net.ME1312.SubData.Server.DataClient;
import net.md_5.bungee.api.config.ServerInfo;
import java.util.Collection;
@ -12,7 +13,15 @@ import java.util.UUID;
/**
* Server Interface
*/
public interface Server extends ServerInfo, ClientHandler, ExtraDataHandler {
public interface Server extends ServerInfo, ClientHandler, ExtraDataHandler<String> {
/**
* Link a SubData Client to this Object
*
* @param client Client to Link
* @param channel Channel ID
*/
void setSubData(DataClient client, int channel);
/**
* Get the Display Name of this Server
@ -49,12 +58,40 @@ public interface Server extends ServerInfo, ClientHandler, ExtraDataHandler {
*/
void removeGroup(String value);
/**
* Commands the Server
*
* @param player Player who's Commanding
* @param target Player who will Send
* @param command Command to Send
*/
boolean command(UUID player, UUID target, String command);
/**
* Commands the Server
*
* @param player Player who's Commanding
* @param command Command to Send
*/
default boolean command(UUID player, String command) {
return command(player, null, command);
}
/**
* Commands the Server
*
* @param command Command to Send
*/
default boolean command(String command) {
return command(null, command);
}
/**
* Get players on this server across all known proxies
*
* @return Player Collection
* @return Remote Player Collection
*/
Collection<NamedContainer<String, UUID>> getGlobalPlayers();
Collection<RemotePlayer> getRemotePlayers();
/**
* If the server is hidden from players
@ -98,6 +135,40 @@ public interface Server extends ServerInfo, ClientHandler, ExtraDataHandler {
*/
void setRestricted(boolean value);
/**
* Get a copy of the current whitelist
*
* @return Player Whitelist
*/
Collection<UUID> getWhitelist();
/**
* See if a player is whitelisted
*
* @param player Player to check
* @return Whitelisted Status
*/
boolean isWhitelisted(UUID player);
/**
* Add a player to the whitelist (for use with restricted servers)
*
* @param player Player to add
*/
void whitelist(UUID player);
/**
* Remove a player to the whitelist
*
* @param player Player to remove
*/
void unwhitelist(UUID player);
/**
* Makes it so the server object will still exist within the server manager even if it is disconnected
*/
void persist();
/**
* Get the Signature of this Object
*

View File

@ -1,205 +0,0 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.SubServers.Bungee.Event.SubEditServerEvent;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLValue;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import net.ME1312.SubServers.Bungee.Library.NamedContainer;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.Network.Client;
import net.ME1312.SubServers.Bungee.Network.SubDataServer;
import net.ME1312.SubServers.Bungee.SubAPI;
import net.ME1312.SubServers.Bungee.SubPlugin;
import net.md_5.bungee.BungeeServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.util.*;
/**
* Server Class
*/
public class ServerContainer extends BungeeServerInfo implements Server {
private YAMLSection extra = new YAMLSection();
private final String signature;
private Client client = null;
private List<String> groups = new ArrayList<String>();
private String nick = null;
private boolean hidden;
public ServerContainer(String name, InetSocketAddress address, String motd, boolean hidden, boolean restricted) throws InvalidServerException {
super(name, address, motd, restricted);
if (Util.isNull(name, address, motd, hidden, restricted)) throw new NullPointerException();
if (name.contains(" ")) throw new InvalidServerException("Server names cannot have spaces: " + name);
signature = SubAPI.getInstance().signAnonymousObject();
SubDataServer.allowConnection(getAddress().getAddress().getHostAddress());
this.hidden = hidden;
}
@Override
public Client getSubData() {
return client;
}
@Override
public void setSubData(Client client) {
this.client = client;
if (client != null && (client.getHandler() == null || !equals(client.getHandler()))) client.setHandler(this);
}
@Override
public String getDisplayName() {
return (nick == null)?getName():nick;
}
@Override
@SuppressWarnings("deprecation")
public void setDisplayName(String value) {
if (value == null || value.length() == 0 || getName().equals(value)) {
SubAPI.getInstance().getInternals().getPluginManager().callEvent(new SubEditServerEvent(null, this, new NamedContainer<String, Object>("display", getName()), false));
this.nick = null;
} else {
SubAPI.getInstance().getInternals().getPluginManager().callEvent(new SubEditServerEvent(null, this, new NamedContainer<String, Object>("display", value), false));
this.nick = value;
}
}
@Override
public List<String> getGroups() {
return groups;
}
@Override
@SuppressWarnings("deprecation")
public void addGroup(String value) {
if (Util.isNull(value)) throw new NullPointerException();
if (value.length() > 0 && !groups.contains(value)) {
groups.add(value);
Collections.sort(groups);
}
}
@Override
@SuppressWarnings("deprecation")
public void removeGroup(String value) {
if (Util.isNull(value)) throw new NullPointerException();
groups.remove(value);
Collections.sort(groups);
}
@SuppressWarnings({"deprecation", "unchecked"})
@Override
public Collection<NamedContainer<String, UUID>> getGlobalPlayers() {
List<NamedContainer<String, UUID>> players = new ArrayList<NamedContainer<String, UUID>>();
SubPlugin plugin = SubAPI.getInstance().getInternals();
if (plugin.redis != null) {
try {
for (UUID player : (Set<UUID>) plugin.redis("getPlayersOnServer", new NamedContainer<>(String.class, getName()))) players.add(new NamedContainer<>((String) plugin.redis("getNameFromUuid", new NamedContainer<>(UUID.class, player)), player));
} catch (Exception e) {}
} else {
for (ProxiedPlayer player : getPlayers()) players.add(new NamedContainer<>(player.getName(), player.getUniqueId()));
}
return players;
}
@Override
public boolean isHidden() {
return hidden;
}
@Override
@SuppressWarnings("deprecation")
public void setHidden(boolean value) {
if (Util.isNull(value)) throw new NullPointerException();
SubAPI.getInstance().getInternals().getPluginManager().callEvent(new SubEditServerEvent(null, this, new NamedContainer<String, Object>("hidden", value), false));
this.hidden = value;
}
@SuppressWarnings("deprecation")
public void setMotd(String value) {
if (Util.isNull(value)) throw new NullPointerException();
SubAPI.getInstance().getInternals().getPluginManager().callEvent(new SubEditServerEvent(null, this, new NamedContainer<String, Object>("motd", value), false));
try {
Field f = BungeeServerInfo.class.getDeclaredField("motd");
f.setAccessible(true);
f.set(this, value);
f.setAccessible(false);
} catch (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings("deprecation")
public void setRestricted(boolean value) {
if (Util.isNull(value)) throw new NullPointerException();
SubAPI.getInstance().getInternals().getPluginManager().callEvent(new SubEditServerEvent(null, this, new NamedContainer<String, Object>("restricted", value), false));
try {
Field f = BungeeServerInfo.class.getDeclaredField("restricted");
f.setAccessible(true);
f.set(this, value);
f.setAccessible(false);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public final String getSignature() {
return signature;
}
@Override
public void addExtra(String handle, Object value) {
if (Util.isNull(handle, value)) throw new NullPointerException();
extra.set(handle, value);
}
@Override
public boolean hasExtra(String handle) {
if (Util.isNull(handle)) throw new NullPointerException();
return extra.getKeys().contains(handle);
}
@Override
public YAMLValue getExtra(String handle) {
if (Util.isNull(handle)) throw new NullPointerException();
return extra.get(handle);
}
@Override
public YAMLSection getExtra() {
return extra.clone();
}
@Override
public void removeExtra(String handle) {
if (Util.isNull(handle)) throw new NullPointerException();
extra.remove(handle);
}
@Override
public String toString() {
YAMLSection info = new YAMLSection();
info.set("type", "Server");
info.set("name", getName());
info.set("display", getDisplayName());
info.set("group", getGroups());
info.set("address", getAddress().getAddress().getHostAddress() + ':' + getAddress().getPort());
info.set("motd", getMotd());
info.set("restricted", isRestricted());
info.set("hidden", isHidden());
if (getSubData() != null) info.set("subdata", getSubData().getAddress().toString());
YAMLSection players = new YAMLSection();
for (NamedContainer<String, UUID> player : getGlobalPlayers()) {
YAMLSection pinfo = new YAMLSection();
pinfo.set("name", player.name());
players.set(player.get().toString(), pinfo);
}
info.set("players", players);
if (getSubData() != null) info.set("subdata", getSubData().getAddress().toString());
info.set("signature", signature);
info.set("extra", getExtra());
return info.toJSON();
}
}

View File

@ -0,0 +1,344 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Map.ObjectMapValue;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubData.Server.DataClient;
import net.ME1312.SubData.Server.SubDataClient;
import net.ME1312.SubServers.Bungee.Event.SubSendCommandEvent;
import net.ME1312.SubServers.Bungee.Host.SubServer.LoggedCommand;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketExControlPlayer;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketOutExEditServer;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketOutExEditServer.Edit;
import net.ME1312.SubServers.Bungee.SubAPI;
import net.md_5.bungee.BungeeServerInfo;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.*;
/**
* Server Class
*/
public class ServerImpl extends BungeeServerInfo implements Server {
private HashMap<Integer, SubDataClient> subdata = new HashMap<Integer, SubDataClient>();
private ObjectMap<String> extra = new ObjectMap<String>();
private String nick = null;
private List<String> groups = new ArrayList<String>();
private List<UUID> whitelist = new ArrayList<UUID>();
private boolean hidden;
private final String signature = SubAPI.getInstance().signAnonymousObject();
private volatile boolean persistent = true;
/**
* Construct a new Server data type
*
* @param name Server name
* @param address Server Address
* @param motd Server MOTD
* @param hidden Hidden Status
* @param restricted Restricted Status
* @return
*/
public static ServerImpl construct(String name, SocketAddress address, String motd, boolean hidden, boolean restricted) throws InvalidServerException {
try {
return new ServerImpl(name, address, motd, hidden, restricted);
} catch (NoSuchMethodError e) {
return new ServerImpl(name, (InetSocketAddress) address, motd, hidden, restricted);
}
}
/**
* Super Method 2 (newest)
* @see #construct(String, SocketAddress, String, boolean, boolean) for method details
*/
protected ServerImpl(String name, SocketAddress address, String motd, boolean hidden, boolean restricted) throws InvalidServerException {
super(name, address, motd, restricted);
init(name, address, motd, hidden, restricted);
}
/**
* Super Method 1 (oldest)
* @see #construct(String, SocketAddress, String, boolean, boolean) for method details
*/
protected ServerImpl(String name, InetSocketAddress address, String motd, boolean hidden, boolean restricted) throws InvalidServerException {
super(name, address, motd, restricted);
init(name, address, motd, hidden, restricted);
}
@SuppressWarnings("deprecation")
private void init(String name, SocketAddress address, String motd, boolean hidden, boolean restricted) throws InvalidServerException {
Util.nullpo(name, address, motd, hidden, restricted);
if (name.contains(" ")) throw new InvalidServerException("Server names cannot have spaces: " + name);
SubAPI.getInstance().getInternals().subprotocol.whitelist(getAddress().getAddress().getHostAddress());
this.hidden = hidden;
subdata.put(0, null);
}
/**
* Get if this server has been registered
*
* @return Registered status
*/
@SuppressWarnings("deprecation")
protected boolean isRegistered() {
return SubAPI.getInstance().getInternals().exServers.containsKey(getName().toLowerCase());
}
@Override
public DataClient[] getSubData() {
Integer[] keys = subdata.keySet().toArray(new Integer[0]);
DataClient[] channels = new DataClient[keys.length];
Arrays.sort(keys);
for (int i = 0; i < keys.length; ++i) channels[i] = subdata.get(keys[i]);
return channels;
}
public void setSubData(DataClient client, int channel) {
boolean update = false;
if (channel < 0) throw new IllegalArgumentException("Subchannel ID cannot be less than zero");
if (client != null || channel == 0) {
if (!subdata.containsKey(channel) || (channel == 0 && (client == null || subdata.get(channel) == null))) {
update = true;
subdata.put(channel, (SubDataClient) client);
if (client != null && (client.getHandler() == null || !equals(client.getHandler()))) ((SubDataClient) client).setHandler(this);
}
} else {
update = true;
subdata.remove(channel);
}
if (update) {
for (Proxy proxy : SubAPI.getInstance().getProxies().values()) if (proxy.getSubData()[0] != null) {
if (client != null) {
((SubDataClient) proxy.getSubData()[0]).sendPacket(new PacketOutExEditServer(this, Edit.CONNECTED, channel, client.getID()));
} else {
((SubDataClient) proxy.getSubData()[0]).sendPacket(new PacketOutExEditServer(this, Edit.DISCONNECTED, channel));
}
}
if (!persistent) {
DataClient[] subdata = getSubData();
if (subdata[0] == null && subdata.length <= 1) {
SubAPI.getInstance().removeServer(getName());
}
}
}
}
@Override
public void removeSubData(DataClient client) {
for (Integer channel : Util.getBackwards(subdata, (SubDataClient) client)) setSubData(null, channel);
}
@Override
public String getDisplayName() {
return (nick == null)?getName():nick;
}
@Override
@SuppressWarnings("deprecation")
public void setDisplayName(String value) {
if (value == null || value.length() == 0 || getName().equals(value)) {
this.nick = null;
} else {
this.nick = value;
}
for (Proxy proxy : SubAPI.getInstance().getProxies().values()) if (proxy.getSubData()[0] != null) {
((SubDataClient) proxy.getSubData()[0]).sendPacket(new PacketOutExEditServer(this, Edit.DISPLAY_NAME, getDisplayName()));
}
}
@Override
public List<String> getGroups() {
return groups;
}
@Override
@SuppressWarnings("deprecation")
public void addGroup(String value) {
Util.nullpo(value);
if (value.length() > 0 && !groups.contains(value)) {
groups.add(value);
Collections.sort(groups);
}
}
@Override
@SuppressWarnings("deprecation")
public void removeGroup(String value) {
Util.nullpo(value);
groups.remove(value);
Collections.sort(groups);
}
@Override
public boolean command(UUID player, UUID target, String command) {
Util.nullpo(command);
SubDataClient channel = (SubDataClient) getSubData()[0];
if (channel != null) {
SubSendCommandEvent event = new SubSendCommandEvent(player, this, command, target);
ProxyServer.getInstance().getPluginManager().callEvent(event);
if (!event.isCancelled() && (player == null || !SubServerImpl.DISALLOWED_COMMANDS.matcher(command).find())) {
channel.sendPacket(new PacketExControlPlayer(target, command));
return true;
} else return false;
} else return false;
}
@Override
public Collection<RemotePlayer> getRemotePlayers() {
return SubAPI.getInstance().getRemotePlayers(this).values();
}
@Override
public boolean isHidden() {
return hidden;
}
@Override
public void setHidden(boolean value) {
this.hidden = value;
if (isRegistered()) for (Proxy proxy : SubAPI.getInstance().getProxies().values()) if (proxy.getSubData()[0] != null) {
((SubDataClient) proxy.getSubData()[0]).sendPacket(new PacketOutExEditServer(this, Edit.HIDDEN, isHidden()));
}
}
public void setMotd(String value) {
Util.nullpo(value);
try {
Util.reflect(BungeeServerInfo.class.getDeclaredField("motd"), this, value);
for (Proxy proxy : SubAPI.getInstance().getProxies().values()) if (proxy.getSubData()[0] != null) {
((SubDataClient) proxy.getSubData()[0]).sendPacket(new PacketOutExEditServer(this, Edit.MOTD, getMotd()));
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void setRestricted(boolean value) {
Util.nullpo(value);
try {
Util.reflect(BungeeServerInfo.class.getDeclaredField("restricted"), this, value);
if (isRegistered()) for (Proxy proxy : SubAPI.getInstance().getProxies().values()) if (proxy.getSubData()[0] != null) {
((SubDataClient) proxy.getSubData()[0]).sendPacket(new PacketOutExEditServer(this, Edit.RESTRICTED, isRestricted()));
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* See if a player can access this server
*
* @param player Player
* @return Whitelisted Status
*/
@Override
public boolean canAccess(CommandSender player) {
return super.canAccess(player) || (player instanceof ProxiedPlayer && whitelist.contains(((ProxiedPlayer) player).getUniqueId()));
}
@Override
public Collection<UUID> getWhitelist() {
return new ArrayList<UUID>(whitelist);
}
@Override
public boolean isWhitelisted(UUID player) {
return whitelist.contains(player);
}
@Override
public void whitelist(UUID player) {
Util.nullpo(player);
if (!whitelist.contains(player)) whitelist.add(player);
if (isRegistered()) for (Proxy proxy : SubAPI.getInstance().getProxies().values()) if (proxy.getSubData()[0] != null) {
((SubDataClient) proxy.getSubData()[0]).sendPacket(new PacketOutExEditServer(this, Edit.WHITELIST_ADD, player));
}
}
@Override
public void unwhitelist(UUID player) {
Util.nullpo(player);
whitelist.remove(player);
if (isRegistered()) for (Proxy proxy : SubAPI.getInstance().getProxies().values()) if (proxy.getSubData()[0] != null) {
((SubDataClient) proxy.getSubData()[0]).sendPacket(new PacketOutExEditServer(this, Edit.WHITELIST_REMOVE, player));
}
}
@Override
public final void persist() {
persistent = true;
}
@Override
public final String getSignature() {
return signature;
}
@Override
public boolean equals(Object obj) {
return obj instanceof ServerImpl && signature.equals(((ServerImpl) obj).signature);
}
@Override
public void addExtra(String handle, Object value) {
Util.nullpo(handle, value);
extra.set(handle, value);
}
@Override
public boolean hasExtra(String handle) {
Util.nullpo(handle);
return extra.getKeys().contains(handle);
}
@Override
public ObjectMapValue getExtra(String handle) {
Util.nullpo(handle);
return extra.get(handle);
}
@Override
public ObjectMap<String> getExtra() {
return extra.clone();
}
@Override
public void removeExtra(String handle) {
Util.nullpo(handle);
extra.remove(handle);
}
@Override
public ObjectMap<String> forSubData() {
ObjectMap<String> info = new ObjectMap<String>();
info.set("type", "Server");
info.set("name", getName());
info.set("display", getDisplayName());
info.set("group", getGroups());
info.set("address", getAddress().getAddress().getHostAddress() + ':' + getAddress().getPort());
info.set("motd", getMotd());
info.set("whitelist", getWhitelist());
info.set("restricted", isRestricted());
info.set("hidden", isHidden());
ObjectMap<String> players = new ObjectMap<String>();
for (RemotePlayer player : getRemotePlayers())
players.set(player.getUniqueId().toString(), player.getName());
info.set("players", players);
ObjectMap<Integer> subdata = new ObjectMap<Integer>();
for (int channel : this.subdata.keySet()) subdata.set(channel, (this.subdata.get(channel) == null)?null:this.subdata.get(channel).getID());
info.set("subdata", subdata);
info.set("signature", signature);
info.set("extra", getExtra());
return info;
}
}

View File

@ -1,47 +1,60 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.SubServers.Bungee.Library.Callback;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.Galaxi.Library.Version.Version;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidTemplateException;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.Library.Version.Version;
import net.ME1312.SubServers.Bungee.SubAPI;
import com.google.common.collect.Range;
import java.io.File;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.function.Consumer;
/**
* SubCreator Layout Class
*/
public abstract class SubCreator {
public static class ServerTemplate {
private final boolean dynamic;
private String name;
private String nick = null;
private boolean enabled;
private boolean internal;
private String icon;
private File directory;
private ServerType type;
private YAMLSection build;
private YAMLSection options;
private ObjectMap<String> build;
private ObjectMap<String> options;
/**
* Create a SubCreator Template
*
* @param name Template Name
* @param enabled Template Enabled Status
* @param icon Template Item Icon Name
* @param directory Template Directory
* @param build Build Options
* @param options Configuration Options
*/
public ServerTemplate(String name, boolean enabled, String icon, File directory, YAMLSection build, YAMLSection options) {
if (Util.isNull(name, enabled, directory, build, options)) throw new NullPointerException();
public ServerTemplate(String name, boolean enabled, String icon, File directory, ObjectMap<String> build, ObjectMap<String> options) {
this(name, enabled, false, icon, directory, build, options, true);
}
private ServerTemplate(String name, boolean enabled, boolean internal, String icon, File directory, ObjectMap<String> build, ObjectMap<String> options, boolean dynamic) {
Util.nullpo(name, enabled, directory, build, options);
if (name.contains(" ")) throw new InvalidTemplateException("Template names cannot have spaces: " + name);
this.name = name;
this.enabled = enabled;
this.internal = internal;
this.icon = icon;
this.directory = directory;
this.type = (build.contains("Server-Type"))?ServerType.valueOf(build.getRawString("Server-Type").toUpperCase()):ServerType.CUSTOM;
this.type = (build.contains("Server-Type"))?ServerType.valueOf(build.getString("Server-Type").toUpperCase()):ServerType.CUSTOM;
this.build = build;
this.options = options;
this.dynamic = dynamic;
}
/**
@ -93,6 +106,15 @@ public abstract class SubCreator {
enabled = value;
}
/**
* Get if this Template is for Internal use only
*
* @return Internal Status
*/
public boolean isInternal() {
return internal;
}
/**
* Get the Item Icon for this Template
*
@ -129,12 +151,39 @@ public abstract class SubCreator {
return type;
}
/**
* Get whether this Template requires the Version argument
*
* @return Version Requirement
*/
public boolean requiresVersion() {
return getBuildOptions().getBoolean("Require-Version", false);
}
/**
* Get whether this Template can be used to update it's servers
*
* @return Updatable Status
*/
public boolean canUpdate() {
return getBuildOptions().getBoolean("Can-Update", false);
}
/**
* Get whether this Template was generated by a SubCreator instance
*
* @return Dynamic Status
*/
public boolean isDynamic() {
return dynamic;
}
/**
* Get the Build Options for this Template
*
* @return Build Options
*/
public YAMLSection getBuildOptions() {
public ObjectMap<String> getBuildOptions() {
return build;
}
@ -143,19 +192,21 @@ public abstract class SubCreator {
*
* @return Configuration Options
*/
public YAMLSection getConfigOptions() {
public ObjectMap<String> getConfigOptions() {
return options;
}
@Override
public String toString() {
YAMLSection tinfo = new YAMLSection();
public ObjectMap<String> forSubData() {
ObjectMap<String> tinfo = new ObjectMap<String>();
tinfo.set("enabled", isEnabled());
tinfo.set("name", getName());
tinfo.set("display", getDisplayName());
tinfo.set("icon", getIcon());
tinfo.set("type", getType().toString());
return tinfo.toJSON();
tinfo.set("version-req", requiresVersion());
tinfo.set("can-update", canUpdate());
return tinfo;
}
}
public enum ServerType {
@ -177,11 +228,12 @@ public abstract class SubCreator {
* @param player Player Creating
* @param name Server Name
* @param template Server Template
* @param version Server Version
* @param port Server Port Number
* @param version Server Version (may be null)
* @param port Server Port Number (null to auto-select)
* @param callback Callback
* @return Success Status
*/
public abstract boolean create(UUID player, String name, ServerTemplate template, Version version, int port, Callback<SubServer> callback);
public abstract boolean create(UUID player, String name, ServerTemplate template, Version version, Integer port, Consumer<SubServer> callback);
/**
* Create a SubServer
@ -189,11 +241,11 @@ public abstract class SubCreator {
* @param player Player Creating
* @param name Server Name
* @param template Server Template
* @param version Server Version
* @param port Server Port Number
* @param version Server Version (may be null)
* @param port Server Port Number (null to auto-select)
* @return Success Status
*/
public boolean create(UUID player, String name, ServerTemplate template, Version version, int port) {
public boolean create(UUID player, String name, ServerTemplate template, Version version, Integer port) {
return create(player, name, template, version, port, null);
}
@ -202,11 +254,12 @@ public abstract class SubCreator {
*
* @param name Server Name
* @param template Server Template
* @param version Server Version
* @param port Server Port Number
* @param version Server Version (may be null)
* @param port Server Port Number (null to auto-select)
* @param callback Callback
* @return Success Status
*/
public boolean create(String name, ServerTemplate template, Version version, int port, Callback<SubServer> callback) {
public boolean create(String name, ServerTemplate template, Version version, Integer port, Consumer<SubServer> callback) {
return create(null, name, template, version, port, callback);
}
@ -215,14 +268,87 @@ public abstract class SubCreator {
*
* @param name Server Name
* @param template Server Template
* @param version Server Version
* @param port Server Port Number
* @param version Server Version (may be null)
* @param port Server Port Number (null to auto-select)
* @return Success Status
*/
public boolean create(String name, ServerTemplate template, Version version, int port) {
public boolean create(String name, ServerTemplate template, Version version, Integer port) {
return create(null, name, template, version, port);
}
/**
* Update a SubServer
*
* @param player Player Updating
* @param server Server to Update
* @param template Server Template
* @param version Server Version (may be null)
* @param callback Callback
* @return Success Status
*/
public abstract boolean update(UUID player, SubServer server, ServerTemplate template, Version version, Consumer<Boolean> callback);
/**
* Update a SubServer
*
* @param player Player Updating
* @param server Server to Update
* @param template Server Template
* @param version Server Version (may be null)
* @return Success Status
*/
public boolean update(UUID player, SubServer server, ServerTemplate template, Version version) {
return update(player, server, template, version, null);
}
/**
* Update a SubServer
*
* @param server Server to Update
* @param template Server Template
* @param version Server Version (may be null)
* @param callback Callback
* @return Success Status
*/
public boolean update(SubServer server, ServerTemplate template, Version version, Consumer<Boolean> callback) {
return update(null, server, template, version, callback);
}
/**
* Update a SubServer
*
* @param server Server to Update
* @param template Server Template
* @param version Server Version (may be null)
* @return Success Status
*/
public boolean update(SubServer server, ServerTemplate template, Version version) {
return update(null, server, template, version);
}
/**
* Update a SubServer
*
* @param player Player Updating
* @param server Server to Update
* @param version Server Version (may be null)
* @return Success Status
*/
public boolean update(UUID player, SubServer server, Version version) {
return update(player, server, null, version);
}
/**
* Update a SubServer
*
* @param server Server to Update
* @param version Server Version (may be null)
* @return Success Status
*/
public boolean update(SubServer server, Version version) {
return update(null, server, version);
}
/**
* Terminate All SubCreator Instances on this host
*/
@ -257,6 +383,20 @@ public abstract class SubCreator {
*/
public abstract Host getHost();
/**
* Get the range of available port numbers
*
* @return Port Range
*/
public abstract Range getPortRange();
/**
* Get the range of available port numbers
*
* @param value Value
*/
public abstract void setPortRange(Range<Integer> value);
/**
* Gets the Git Bash install directory
*
@ -269,7 +409,7 @@ public abstract class SubCreator {
*
* @return SubCreator Loggers
*/
public abstract List<SubLogger> getLogger();
public abstract List<SubLogger> getLoggers();
/**
* Gets the Logger for a SubCreator Instance
@ -279,6 +419,20 @@ public abstract class SubCreator {
*/
public abstract SubLogger getLogger(String thread);
/**
* If the Creator is Logging to console
*
* @return Logging Status
*/
public abstract boolean isLogging();
/**
* Set if the Creator is Logging
*
* @param value Value
*/
public abstract void setLogging(boolean value);
/**
* Get a list of currently reserved Server names
@ -287,6 +441,13 @@ public abstract class SubCreator {
*/
public abstract List<String> getReservedNames();
/**
* Get a list of currently reserved Server ports
*
* @return Reserved Ports
*/
public abstract List<Integer> getReservedPorts();
/**
* Check if a name has been reserved
*
@ -301,6 +462,20 @@ public abstract class SubCreator {
return reserved;
}
/**
* Check if an address has been reserved
*
* @param address Address to check
* @return Reserved Status
*/
public static boolean isReserved(InetSocketAddress address) {
boolean reserved = false;
for (InetSocketAddress list : getAllReservedAddresses()) {
if (list.equals(address)) reserved = true;
}
return reserved;
}
/**
* Get a list of all currently reserved Server names across all hosts
*
@ -312,6 +487,22 @@ public abstract class SubCreator {
return names;
}
/**
* Get a list of all currently reserved Server names across all hosts
*
* @return All Reserved Names
*/
public static List<InetSocketAddress> getAllReservedAddresses() {
List<InetSocketAddress> addresses = new ArrayList<InetSocketAddress>();
for (Server server : SubAPI.getInstance().getSubServers().values()) {
addresses.add(server.getAddress());
}
for (Host host : SubAPI.getInstance().getHosts().values())
for (int port : host.getCreator().getReservedPorts())
addresses.add(new InetSocketAddress(host.getAddress(), port));
return addresses;
}
/**
* Gets the Templates that can be used in this SubCreator instance
*
@ -327,8 +518,28 @@ public abstract class SubCreator {
*/
public abstract ServerTemplate getTemplate(String name);
/**
* Create a SubCreator Template
*
* @param name Template Name
* @param enabled Template Enabled Status
* @param internal Template Internal Status
* @param icon Template Item Icon Name
* @param directory Template Directory
* @param build Build Options
* @param options Configuration Options
*/
protected ServerTemplate loadTemplate(String name, boolean enabled, boolean internal, String icon, File directory, ObjectMap<String> build, ObjectMap<String> options) {
return new ServerTemplate(name, enabled, internal, icon, directory, build, options, false);
}
/**
* Reload SubCreator
*/
public abstract void reload();
@Override
public boolean equals(Object obj) {
return obj instanceof SubCreator && getHost().getSignature().equals(((SubCreator) obj).getHost().getSignature());
}
}

View File

@ -1,91 +1,9 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.SubServers.Bungee.Library.Util;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
/**
* SubLogger Layout Class
*/
public abstract class SubLogger {
/**
* Log Message Storage Class
*/
public static class LogMessage {
private Date date;
private Level level;
private String message;
/**
* Store a Message
*
* @param message Message
*/
public LogMessage(String message) {
if (Util.isNull(message)) throw new NullPointerException();
this.date = Calendar.getInstance().getTime();
this.level = Level.INFO;
this.message = message;
}
/**
* Store a Message
*
* @param level Log Level
* @param message Message
*/
public LogMessage(Level level, String message) {
if (Util.isNull(level, message)) throw new NullPointerException();
this.date = Calendar.getInstance().getTime();
this.level = level;
this.message = message;
}
/**
* Store a Message
*
* @param date Date
* @param level Log Level
* @param message Message
*/
public LogMessage(Date date, Level level, String message) {
if (Util.isNull(date, level, message)) throw new NullPointerException();
this.date = date;
this.level = level;
this.message = message;
}
/**
* Get the date this message was logged
*
* @return Date
*/
public Date getDate() {
return date;
}
/**
* Get the level this message was logged on
*
* @return Log Level
*/
public Level getLevel() {
return level;
}
/**
* Get the message
*
* @return Message
*/
public String getMessage() {
return message;
}
}
/**
* Gets the Name of the task logging
@ -118,13 +36,6 @@ public abstract class SubLogger {
*/
public abstract boolean isLogging();
/**
* Gets a list of all the messages logged by this logger
*
* @return Log Messages (named by log level)
*/
public abstract List<LogMessage> getMessageHistory();
/**
* Register Filter
*

View File

@ -1,8 +1,9 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Util;
import java.io.File;
import java.util.*;
/**
@ -17,6 +18,7 @@ public interface SubServer extends Server {
NONE,
RESTART,
REMOVE_SERVER,
RECYCLE_SERVER,
DELETE_SERVER;
@Override
@ -39,7 +41,7 @@ public interface SubServer extends Server {
* @param command Command
*/
public LoggedCommand(String command) {
if (Util.isNull(command)) throw new NullPointerException();
Util.nullpo(command);
this.date = Calendar.getInstance().getTime();
this.sender = null;
this.command = command;
@ -52,7 +54,7 @@ public interface SubServer extends Server {
* @param command Command
*/
public LoggedCommand(UUID sender, String command) {
if (Util.isNull(command)) throw new NullPointerException();
Util.nullpo(command);
this.date = Calendar.getInstance().getTime();
this.sender = sender;
this.command = command;
@ -66,7 +68,7 @@ public interface SubServer extends Server {
* @param command Command
*/
public LoggedCommand(Date date, UUID sender, String command) {
if (Util.isNull(date, command)) throw new NullPointerException();
Util.nullpo(date, command);
this.date = date;
this.sender = sender;
this.command = command;
@ -113,7 +115,9 @@ public interface SubServer extends Server {
*
* @return Success Status
*/
boolean start();
default boolean start() {
return start(null);
}
/**
* Stops the Server
@ -128,7 +132,9 @@ public interface SubServer extends Server {
*
* @return Success Status
*/
boolean stop();
default boolean stop() {
return stop(null);
}
/**
* Terminates the Server
@ -143,24 +149,9 @@ public interface SubServer extends Server {
*
* @return Success Status
*/
boolean terminate();
/**
* Commands the Server
*
* @param player Player who Commanded
* @param command Command to Send
* @return Success Status
*/
boolean command(UUID player, String command);
/**
* Commands the Server
*
* @param command Command to Send
* @return Success Status
*/
boolean command(String command);
default boolean terminate() {
return terminate(null);
}
/**
* Edits the Server
@ -169,7 +160,7 @@ public interface SubServer extends Server {
* @param edit Edits
* @return Success Status
*/
default int edit(UUID player, YAMLSection edit) {
default int edit(UUID player, ObjectMap<String> edit) {
return -1;
}
@ -179,10 +170,31 @@ public interface SubServer extends Server {
* @param edit Edits
* @return Success Status
*/
default int edit(YAMLSection edit) {
default int edit(ObjectMap<String> edit) {
return edit(null, edit);
}
/**
* Edits the Server (& Saves Changes)
*
* @param player Player Editing
* @param edit Edits
* @return Success Status
*/
default int permaEdit(UUID player, ObjectMap<String> edit) {
return -1;
}
/**
* Edits the Server (& Saves Changes)
*
* @param edit Edits
* @return Success Status
*/
default int permaEdit(ObjectMap<String> edit) {
return permaEdit(null, edit);
}
/**
* Waits for the Server to Stop
*
@ -197,6 +209,22 @@ public interface SubServer extends Server {
*/
boolean isRunning();
/**
* If the Server is Online<br>
* <b>This method can only be true when a SubData connection is made!</b>
*
* @return Online Status
*/
boolean isOnline();
/**
* If the Server is Stopping<br>
* <b>This method can only be true when the server is stopped through the server manager!</b>
*
* @return Stopping Status
*/
boolean isStopping();
/**
* Grabs the Host of the Server
*
@ -204,6 +232,34 @@ public interface SubServer extends Server {
*/
Host getHost();
/**
* Grabs the Template this Server was created from
*
* @return The Template
*/
SubCreator.ServerTemplate getTemplate();
/**
* Sets the Template this Server was created from
*
* @param value Value
*/
void setTemplate(SubCreator.ServerTemplate value);
/**
* Sets the Template this Server was created from
*
* @param value Value
*/
void setTemplate(String value);
/**
* Is this Host Available?
*
* @return Availability Status
*/
boolean isAvailable();
/**
* If the Server is Enabled
*
@ -221,12 +277,12 @@ public interface SubServer extends Server {
/**
* If the Server is accepting requests to edit()
*
* @see #edit(YAMLSection)
* @see #edit(UUID, YAMLSection)
* @see #permaEdit(ObjectMap<String>)
* @see #permaEdit(UUID, ObjectMap<String>)
* @return Edit Status
*/
default boolean isEditable() {
return edit(new YAMLSection()) >= 0;
return permaEdit(new ObjectMap<String>()) >= 0;
}
/**
@ -267,14 +323,16 @@ public interface SubServer extends Server {
*
* @return Full Server Directory Path
*/
String getFullPath();
default String getFullPath() {
return new File(getHost().getPath(), getPath()).getPath();
}
/**
* Get the Server's Executable String
*
* @return Executable String
*/
Executable getExecutable();
String getExecutable();
/**
* Grab the Command to Stop the Server

View File

@ -1,133 +0,0 @@
package net.ME1312.SubServers.Bungee.Host;
import com.google.gson.Gson;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import net.ME1312.SubServers.Bungee.Library.NamedContainer;
import net.ME1312.SubServers.Bungee.SubAPI;
import java.io.File;
import java.net.InetSocketAddress;
import java.util.*;
/**
* SubServer Layout Class
*/
public abstract class SubServerContainer extends ServerContainer implements SubServer {
private List<NamedContainer<String, String>> incompatibilities = new ArrayList<NamedContainer<String, String>>();
/**
* Creates a SubServer
*
* @param host Host
* @param name Server Name
* @param port Port Number
* @param motd Server MOTD
* @param restricted Players will need a permission to join if true
* @throws InvalidServerException
*/
public SubServerContainer(Host host, String name, int port, String motd, boolean hidden, boolean restricted) throws InvalidServerException {
super(name, new InetSocketAddress(host.getAddress().getHostAddress(), port), motd, hidden, restricted);
}
@Override
public boolean start() {
return start(null);
}
@Override
public boolean stop() {
return stop(null);
}
@Override
public boolean terminate() {
return terminate(null);
}
@Override
public boolean command(String command) {
return command(null, command);
}
@Override
public int edit(YAMLSection edit) {
return edit(null, edit);
}
@Override
public String getFullPath() {
return new File(getHost().getPath(), getPath()).getPath();
}
@Override
public void toggleCompatibility(SubServer... server) {
for (SubServer s : server) {
if (!equals(s)) {
NamedContainer<String, String> info = new NamedContainer<String, String>(s.getHost().getName(), s.getName());
if (isCompatible(s)) {
incompatibilities.add(info);
if (s.isCompatible(this)) toggleCompatibility(this);
} else {
incompatibilities.remove(info);
if (!s.isCompatible(this)) toggleCompatibility(this);
}
}
}
}
@Override
public boolean isCompatible(SubServer server) {
return !incompatibilities.contains(new NamedContainer<String, String>(server.getHost().getName(), server.getName()));
}
@Override
public List<SubServer> getIncompatibilities() {
List<SubServer> servers = new ArrayList<SubServer>();
List<NamedContainer<String, String>> temp = new ArrayList<NamedContainer<String, String>>();
temp.addAll(incompatibilities);
for (NamedContainer<String, String> info : temp) {
try {
SubServer server = SubAPI.getInstance().getHost(info.name()).getSubServer(info.get());
if (server == null) throw new NullPointerException();
servers.add(server);
} catch (Throwable e) {
incompatibilities.remove(info);
}
}
return servers;
}
@Override
public List<SubServer> getCurrentIncompatibilities() {
List<SubServer> servers = new ArrayList<SubServer>();
for (SubServer server : getIncompatibilities()) {
if (server.isRunning()) servers.add(server);
}
return servers;
}
@SuppressWarnings({"deprecation", "unchecked"})
@Override
public String toString() {
YAMLSection sinfo = new YAMLSection(new Gson().fromJson(super.toString(), Map.class));
sinfo.set("type", "SubServer");
sinfo.set("host", getHost().getName());
sinfo.set("enabled", isEnabled());
sinfo.set("editable", isEditable());
sinfo.set("log", isLogging());
sinfo.set("dir", getPath());
sinfo.set("exec", getExecutable());
sinfo.set("running", isRunning());
sinfo.set("stop-cmd", getStopCommand());
sinfo.set("stop-action", getStopAction().toString());
sinfo.set("auto-run", SubAPI.getInstance().getInternals().config.get().getSection("Servers").getSection(getName()).getKeys().contains("Run-On-Launch") && SubAPI.getInstance().getInternals().config.get().getSection("Servers").getSection(getName()).getBoolean("Run-On-Launch"));
List<String> incompatibleCurrent = new ArrayList<String>();
List<String> incompatible = new ArrayList<String>();
for (SubServer server : getCurrentIncompatibilities()) incompatibleCurrent.add(server.getName());
for (SubServer server : getIncompatibilities()) incompatible.add(server.getName());
sinfo.set("incompatible", incompatibleCurrent);
sinfo.set("incompatible-list", incompatible);
return sinfo.toJSON();
}
}

View File

@ -1,15 +1,16 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import java.util.*;
import java.util.LinkedList;
import java.util.UUID;
/**
* API-Safe SubServer Layout Class
*/
public abstract class SubServerController {
private final SubServerContainer control;
private final SubServerImpl control;
/**
* Creates a SubServer
@ -22,132 +23,149 @@ public abstract class SubServerController {
* @throws InvalidServerException
*/
public SubServerController(Host host, String name, int port, String motd, boolean hidden, boolean restricted) throws InvalidServerException {
control = new SubServerContainer(host, name, port, motd, hidden, restricted) {
@Override
public boolean start() {
return SubServerController.this.start();
}
SubServerImpl control;
try {
control = new ControlledSubServer(host, name, port, motd, hidden, restricted);
} catch (NoSuchMethodError e) {
control = new ControlledSubServer(host, name, (Integer) port, motd, hidden, restricted);
}
this.control = control;
}
@Override
public boolean start(UUID player) {
return SubServerController.this.start(player);
}
private final class ControlledSubServer extends SubServerImpl {
public ControlledSubServer(Host host, String name, int port, String motd, boolean hidden, boolean restricted) throws InvalidServerException {
super(host, name, port, motd, hidden, restricted);
}
@Override
public boolean stop() {
return SubServerController.this.stop();
}
public ControlledSubServer(Host host, String name, Integer port, String motd, boolean hidden, boolean restricted) throws InvalidServerException {
super(host, name, port, motd, hidden, restricted);
}
@Override
public boolean stop(UUID player) {
return SubServerController.this.stop(player);
}
@Override
public boolean start() {
if (SubServerController.this.start()) {
started = false;
return true;
} else return false;
}
@Override
public boolean terminate() {
return SubServerController.this.terminate();
}
@Override
public boolean start(UUID player) {
if (SubServerController.this.start(player)) {
started = false;
return true;
} else return false;
}
@Override
public boolean terminate(UUID player) {
return SubServerController.this.terminate(player);
}
@Override
public boolean stop() {
return SubServerController.this.stop();
}
@Override
public boolean command(String command) {
return SubServerController.this.command(command);
}
@Override
public boolean stop(UUID player) {
return SubServerController.this.stop(player);
}
@Override
public boolean command(UUID player, String command) {
return SubServerController.this.command(player, command);
}
@Override
public boolean terminate() {
return SubServerController.this.terminate();
}
@Override
public int edit(YAMLSection edit) {
return SubServerController.this.edit(edit);
}
@Override
public boolean terminate(UUID player) {
return SubServerController.this.terminate(player);
}
@Override
public int edit(UUID player, YAMLSection edit) {
return SubServerController.this.edit(player, edit);
}
@Override
public boolean command(String command) {
return SubServerController.this.command(command);
}
@Override
public void waitFor() throws InterruptedException {
SubServerController.this.waitFor();
}
@Override
public boolean command(UUID player, String command) {
return SubServerController.this.command(player, command);
}
@Override
public boolean isRunning() {
return SubServerController.this.isRunning();
}
@Override
public int edit(UUID player, ObjectMap<String> edit, boolean perma) {
return SubServerController.this.edit(player, edit, perma);
}
@Override
public Host getHost() {
return SubServerController.this.getHost();
}
@Override
public void waitFor() throws InterruptedException {
SubServerController.this.waitFor();
}
@Override
public boolean isEnabled() {
return SubServerController.this.isEnabled();
}
@Override
public boolean isRunning() {
return SubServerController.this.isRunning();
}
@Override
public void setEnabled(boolean value) {
SubServerController.this.setEnabled(value);
}
@Override
public Host getHost() {
return SubServerController.this.getHost();
}
@Override
public boolean isLogging() {
return SubServerController.this.isLogging();
}
@Override
public boolean isEnabled() {
return SubServerController.this.isEnabled();
}
@Override
public void setLogging(boolean value) {
SubServerController.this.setLogging(value);
}
@Override
public void setEnabled(boolean value) {
SubServerController.this.setEnabled(value);
}
@Override
public SubLogger getLogger() {
return SubServerController.this.getLogger();
}
@Override
public boolean isLogging() {
return SubServerController.this.isLogging();
}
@Override
public LinkedList<LoggedCommand> getCommandHistory() {
return SubServerController.this.getCommandHistory();
}
@Override
public void setLogging(boolean value) {
SubServerController.this.setLogging(value);
}
@Override
public String getPath() {
return SubServerController.this.getPath();
}
@Override
public SubLogger getLogger() {
return SubServerController.this.getLogger();
}
@Override
public Executable getExecutable() {
return SubServerController.this.getExecutable();
}
@Override
public LinkedList<LoggedCommand> getCommandHistory() {
return SubServerController.this.getCommandHistory();
}
@Override
public String getStopCommand() {
return SubServerController.this.getStopCommand();
}
@Override
public String getPath() {
return SubServerController.this.getPath();
}
@Override
public void setStopCommand(String value) {
SubServerController.this.setStopCommand(value);
}
@Override
public String getExecutable() {
return SubServerController.this.getExecutable();
}
@Override
public StopAction getStopAction() {
return SubServerController.this.getStopAction();
}
@Override
public String getStopCommand() {
return SubServerController.this.getStopCommand();
}
@Override
public void setStopAction(StopAction action) {
SubServerController.this.setStopAction(action);
}
};
@Override
public void setStopCommand(String value) {
SubServerController.this.setStopCommand(value);
}
@Override
public StopAction getStopAction() {
return SubServerController.this.getStopAction();
}
@Override
public void setStopAction(StopAction action) {
SubServerController.this.setStopAction(action);
}
}
/**
@ -213,7 +231,7 @@ public abstract class SubServerController {
/**
* Commands the Server
*
* @param player Player who Commanded
* @param player Player who's Commanding
* @param command Command to Send
* @return Success Status
*/
@ -234,19 +252,10 @@ public abstract class SubServerController {
*
* @param player Player Editing
* @param edit Edits
* @param perma Saves Changes
* @return Success Status
*/
public int edit(UUID player, YAMLSection edit) {
return -1;
}
/**
* Edits the Server
*
* @param edit Edits
* @return Success Status
*/
public int edit(YAMLSection edit) {
protected int edit(UUID player, ObjectMap<String> edit, boolean perma) {
return -1;
}
@ -323,7 +332,7 @@ public abstract class SubServerController {
*
* @return Executable String
*/
public abstract Executable getExecutable();
public abstract String getExecutable();
/**
* Grab the Command to Stop the Server
@ -352,9 +361,4 @@ public abstract class SubServerController {
* @param action Stop Action
*/
public abstract void setStopAction(SubServer.StopAction action);
@Override
public String toString() {
return control.toString();
}
}

View File

@ -0,0 +1,203 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.Galaxi.Library.Container.ContainedPair;
import net.ME1312.Galaxi.Library.Container.Pair;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import net.ME1312.SubServers.Bungee.SubAPI;
import java.io.File;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.regex.Pattern;
/**
* SubServer Layout Class
*/
public abstract class SubServerImpl extends ServerImpl implements SubServer {
protected static final Pattern DISALLOWED_COMMANDS = Pattern.compile("^/?(?:[^\\s]+:)?sub(?:servers?)?(?:\\s|$)", Pattern.CASE_INSENSITIVE & Pattern.UNICODE_CASE);
private List<Pair<String, String>> incompatibilities = new ArrayList<Pair<String, String>>();
private SubCreator.ServerTemplate templateV = null;
private String templateS = null;
protected boolean registered, started, stopping, updating;
/**
* Creates a SubServer
*
* @param host Host
* @param name Server Name
* @param port Port Number
* @param motd Server MOTD
* @param hidden Hidden Status
* @param restricted Restricted Status
*
* @see ServerImpl#ServerImpl(String, SocketAddress, String, boolean, boolean) Super Method 2
* @throws InvalidServerException
*/
protected SubServerImpl(Host host, String name, int port, String motd, boolean hidden, boolean restricted) throws InvalidServerException {
super(name, (SocketAddress) new InetSocketAddress(host.getAddress().getHostAddress(), port), motd, hidden, restricted);
}
/**
* Creates a SubServer
*
* @param host Host
* @param name Server Name
* @param port Port Number
* @param motd Server MOTD
* @param hidden Hidden Status
* @param restricted Restricted Status
*
* @see ServerImpl#ServerImpl(String, InetSocketAddress, String, boolean, boolean) Super Method 1
* @throws InvalidServerException
*/
protected SubServerImpl(Host host, String name, Integer port, String motd, boolean hidden, boolean restricted) throws InvalidServerException {
super(name, new InetSocketAddress(host.getAddress().getHostAddress(), port), motd, hidden, restricted);
}
public int edit(UUID player, ObjectMap<String> edit) {
return edit(player, edit, false);
}
public int permaEdit(UUID player, ObjectMap<String> edit) {
return edit(player, edit, true);
}
/**
* Edits the Server
*
* @param player Player Editing
* @param edit Edits
* @param perma Saves Changes
* @return Success Status
*/
protected int edit(UUID player, ObjectMap<String> edit, boolean perma) {
return -1;
}
@Override
protected final boolean isRegistered() {
return registered;
}
@Override
public boolean isAvailable() {
return registered && !updating && getHost().isAvailable();
}
@Override
public boolean isOnline() {
return isRunning() && started;
}
@Override
public boolean isStopping() {
return isRunning() && stopping;
}
@Override
public void setTemplate(String template) {
this.templateV = null;
this.templateS = template;
}
@Override
public void setTemplate(SubCreator.ServerTemplate template) {
this.templateV = template;
this.templateS = (template != null)?template.getName():null;
}
@Override
public SubCreator.ServerTemplate getTemplate() {
if (templateV != null) {
return templateV;
} else if (templateS != null && getHost().getCreator().getTemplates().containsKey(templateS.toLowerCase())) {
return getHost().getCreator().getTemplate(templateS.toLowerCase());
} else {
return null;
}
}
@Override
public void toggleCompatibility(SubServer... server) {
for (SubServer s : server) {
if (!equals(s)) {
Pair<String, String> info = new ContainedPair<String, String>(s.getHost().getName(), s.getName());
if (isCompatible(s)) {
incompatibilities.add(info);
if (s.isCompatible(this)) toggleCompatibility(this);
} else {
incompatibilities.remove(info);
if (!s.isCompatible(this)) toggleCompatibility(this);
}
}
}
}
@Override
public boolean isCompatible(SubServer server) {
return !incompatibilities.contains(new ContainedPair<String, String>(server.getHost().getName(), server.getName()));
}
@Override
public List<SubServer> getIncompatibilities() {
List<SubServer> servers = new ArrayList<SubServer>();
List<Pair<String, String>> temp = new ArrayList<Pair<String, String>>();
temp.addAll(incompatibilities);
for (Pair<String, String> info : temp) {
try {
SubServer server = SubAPI.getInstance().getHost(info.key()).getSubServer(info.value());
if (server == null) throw new NullPointerException();
servers.add(server);
} catch (Throwable e) {
incompatibilities.remove(info);
}
}
return servers;
}
@Override
public List<SubServer> getCurrentIncompatibilities() {
List<SubServer> servers = new ArrayList<SubServer>();
for (SubServer server : getIncompatibilities()) {
if (server.isRunning()) servers.add(server);
}
return servers;
}
@Override
public boolean equals(Object obj) {
return obj instanceof SubServerImpl && super.equals(obj);
}
@SuppressWarnings("deprecation")
@Override
public ObjectMap<String> forSubData() {
ObjectMap<String> sinfo = super.forSubData();
sinfo.set("type", "SubServer");
sinfo.set("host", getHost().getName());
sinfo.set("template", (getTemplate() != null)?getTemplate().getName():null);
sinfo.set("available", isAvailable());
sinfo.set("enabled", isEnabled());
sinfo.set("editable", isEditable());
sinfo.set("log", isLogging());
sinfo.set("dir", getPath());
sinfo.set("exec", getExecutable());
sinfo.set("running", isRunning());
sinfo.set("online", isOnline());
sinfo.set("stopping", isStopping());
sinfo.set("stop-cmd", getStopCommand());
sinfo.set("stop-action", getStopAction().toString());
sinfo.set("auto-run", SubAPI.getInstance().getInternals().servers.get().getMap("Servers").getMap(getName(), new ObjectMap<String>()).getBoolean("Run-On-Launch", false));
List<String> incompatibleCurrent = new ArrayList<String>();
List<String> incompatible = new ArrayList<String>();
for (SubServer server : getCurrentIncompatibilities()) incompatibleCurrent.add(server.getName());
for (SubServer server : getIncompatibilities()) incompatible.add(server.getName());
sinfo.set("incompatible", incompatibleCurrent);
sinfo.set("incompatible-list", incompatible);
return sinfo;
}
}

View File

@ -1,11 +1,8 @@
package net.ME1312.SubServers.Bungee;
import net.ME1312.SubServers.Bungee.Library.Container;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.Library.Version.Version;
import net.ME1312.SubServers.Bungee.Library.Version.VersionType;
import net.ME1312.Galaxi.Library.Platform;
import net.ME1312.Galaxi.Library.Try;
import java.lang.reflect.Field;
import java.security.Security;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@ -22,11 +19,13 @@ public final class Launch {
* @param args Launch Arguments
* @throws Exception
*/
@SuppressWarnings("deprecation")
@SuppressWarnings({"deprecation", "unchecked"})
public static void main(String[] args) throws Exception {
System.setProperty("jdk.lang.Process.allowAmbiguousCommands", "true");
System.setProperty("jdk.util.jar.enableMultiRelease", "force");
System.setProperty("apple.laf.useScreenMenuBar", "true");
if (Util.getDespiteException(() -> Class.forName("net.md_5.bungee.BungeeCord") == null, true)) {
if (Try.all.get(() -> Class.forName("net.md_5.bungee.BungeeCord") == null, true)) {
System.out.println("");
System.out.println("*******************************************");
System.out.println("*** Error: BungeeCord.jar Doesn't Exist ***");
@ -48,19 +47,11 @@ public final class Launch {
parser.accepts("noconsole");
joptsimple.OptionSet options = parser.parse(args);
if(options.has("version") || options.has("v")) {
boolean build = false;
try {
Field f = Version.class.getDeclaredField("type");
f.setAccessible(true);
build = f.get(SubPlugin.version) != VersionType.SNAPSHOT && SubPlugin.class.getPackage().getSpecificationTitle() != null;
f.setAccessible(false);
} catch (Exception e) {}
System.out.println("");
System.out.println(System.getProperty("os.name") + " " + System.getProperty("os.version") + ',');
System.out.println("Java " + System.getProperty("java.version") + ",");
System.out.println("BungeeCord" + ((patched)?" [Patched] ":" ") + net.md_5.bungee.Bootstrap.class.getPackage().getImplementationVersion() + ',');
System.out.println("SubServers.Bungee v" + SubPlugin.version.toExtendedString() + ((build)?" (" + SubPlugin.class.getPackage().getSpecificationTitle() + ')':""));
System.out.println(Platform.getSystemName() + ' ' + Platform.getSystemVersion() + ((Platform.getSystemBuild() != null)?" (" + Platform.getSystemBuild() + ')':"") + ((!Platform.getSystemArchitecture().equals("unknown"))?" [" + Platform.getSystemArchitecture() + ']':"") + ',');
System.out.println("Java " + Platform.getJavaVersion() + ((!Platform.getJavaArchitecture().equals("unknown"))?" [" + Platform.getJavaArchitecture() + ']':"") + ',');
System.out.println("BungeeCord " + net.md_5.bungee.Bootstrap.class.getPackage().getImplementationVersion() + ((patched)?" [Patched]":"") + ',');
System.out.println("SubServers.Bungee v" + SubProxy.version.toExtendedString() + ((SubProxy.class.getPackage().getSpecificationTitle() != null)?" (" + SubProxy.class.getPackage().getSpecificationTitle() + ')':""));
System.out.println("");
} else {
System.out.println("");
@ -74,7 +65,7 @@ public final class Launch {
if (net.md_5.bungee.BungeeCord.class.getPackage().getSpecificationVersion() != null) {
Date date = (new SimpleDateFormat("yyyyMMdd")).parse(net.md_5.bungee.BungeeCord.class.getPackage().getSpecificationVersion());
Calendar line = Calendar.getInstance();
line.add(3, -4);
line.add(Calendar.WEEK_OF_YEAR, -8);
if (date.before(line.getTime())) {
System.out.println("*** Warning: BungeeCord is outdated ***");
System.out.println("*** Please download a new build from: ***");
@ -92,16 +83,16 @@ public final class Launch {
}
System.out.println("");
SubPlugin plugin = new SubPlugin(System.out, patched);
SubProxy plugin = new SubProxy(System.out, patched);
net.md_5.bungee.api.ProxyServer.class.getMethod("setInstance", net.md_5.bungee.api.ProxyServer.class).invoke(null, plugin);
plugin.getLogger().info("Enabled " + plugin.getBungeeName() + " version " + plugin.getVersion());
plugin.start();
if (!options.has("noconsole")) {
try {
if (Util.getDespiteException(() -> Class.forName("io.github.waterfallmc.waterfall.console.WaterfallConsole").getMethod("readCommands") != null, false)) {
if (Try.all.get(() -> Class.forName("io.github.waterfallmc.waterfall.console.WaterfallConsole").getMethod("readCommands") != null, false)) { // Waterfall Setup
Class.forName("io.github.waterfallmc.waterfall.console.WaterfallConsole").getMethod("readCommands").invoke(null);
} else if (Util.getDespiteException(() -> Class.forName("io.github.waterfallmc.waterfall.console.WaterfallConsole").getMethod("start") != null, false)) {
} else if (Try.all.get(() -> Class.forName("io.github.waterfallmc.waterfall.console.WaterfallConsole").getMethod("start") != null, false)) {
Class console = Class.forName("io.github.waterfallmc.waterfall.console.WaterfallConsole");
console.getMethod("start").invoke(console.getConstructor().newInstance());
} else {
@ -114,14 +105,13 @@ public final class Launch {
}
} else if (line.equalsIgnoreCase("exit")) {
plugin.sudo = null;
System.out.println("SubServers > Reverting to the BungeeCord Console");
net.ME1312.SubServers.Bungee.Library.Compatibility.Logger.get("SubServers").info("Reverting to the BungeeCord Console");
} else {
plugin.sudo.command(line);
}
}
}
} catch (NoSuchMethodError | NoSuchMethodException e) {
plugin.canSudo = false;
plugin.getLogger().warning("Standard BungeeCord console not found; Console commands may now be disabled.");
}
}

View File

@ -1,13 +0,0 @@
package net.ME1312.SubServers.Bungee.Library;
/**
* Callback Class
*/
public interface Callback<T> {
/**
* Run the Callback
*
* @param obj Object
*/
void run(T obj);
}

View File

@ -1,55 +0,0 @@
package net.ME1312.SubServers.Bungee.Library.Compatibility;
import net.ME1312.SubServers.Bungee.Library.NamedContainer;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
import java.util.List;
/**
* Command Layout Class that implements all possible features (Base Version)
*/
public abstract class CommandX extends Command implements TabExecutor {
/**
* Create a Command
*
* @param name Command Name
*/
public CommandX(String name) {
super(name);
}
/**
* Create a Command
*
* @param name Command Name
* @param permission Command Permission
* @param aliases Command Aliases
*/
public CommandX(String name, String permission, String... aliases) {
super(name, permission, aliases);
}
/**
* Suggest Arguments
*
* @param sender Sender
* @param args Arguments (including the final unfinished one)
* @return An Error Message (if there was one, otherwise null) and a List of Suggestions
*/
public abstract NamedContainer<String, List<String>> suggestArguments(CommandSender sender, String[] args);
/**
* Override the BungeeCord Method of {@link #suggestArguments(CommandSender, String[])}
*
* @param sender Sender
* @param args Arguments (including the final unfinished one)
* @return A Collection of Suggestions
*/
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
return suggestArguments(sender, args).get();
}
}

View File

@ -0,0 +1,75 @@
package net.ME1312.SubServers.Bungee.Library.Compatibility;
import net.ME1312.SubServers.Bungee.SubAPI;
import com.google.common.io.Resources;
import net.md_5.bungee.api.ProxyServer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.logging.Logger;
import static java.util.logging.Level.SEVERE;
/**
* JNA Library Loader Class
*/
public class JNA {
private JNA() {}
private static ClassLoader JNA = null;
private static final String JNA_VERSION = "5.2.0";
private static final String JNA_DOWNLOAD = "https://oss.sonatype.org/service/local/repositories/releases/content/net/java/dev/jna/$1/" + JNA_VERSION + "/$1-" + JNA_VERSION + ".jar";
/**
* Get/Load JNA Library
*
* @return JNA ClassLoader
*/
@SuppressWarnings("deprecation")
public static ClassLoader get() {
if (JNA == null) {
boolean announced = false;
Logger log = ProxyServer.getInstance().getLogger();
File library = new File(SubAPI.getInstance().getInternals().dir, "SubServers/Cache/Libraries");
File jna = new File(library, "jna-" + JNA_VERSION + ".jar");
jna.getParentFile().mkdirs();
if (!jna.exists()) {
announced = true;
log.info(">> Downloading JNA v" + JNA_VERSION);
try (FileOutputStream fin = new FileOutputStream(jna)) {
Resources.copy(new URL(JNA_DOWNLOAD.replace("$1", "jna")), fin);
} catch (Throwable e) {
jna.delete();
e.printStackTrace();
}
}
File platform = new File(library, "jna-platform-" + JNA_VERSION + ".jar");
platform.getParentFile().mkdirs();
if (!platform.exists()) {
if (!announced) log.info(">> Downloading JNA platform v" + JNA_VERSION);
announced = true;
try (FileOutputStream fin = new FileOutputStream(platform)) {
Resources.copy(new URL(JNA_DOWNLOAD.replace("$1", "jna-platform")), fin);
} catch (Throwable e) {
platform.delete();
e.printStackTrace();
}
}
if (jna.exists() && platform.exists()) {
if (announced) log.info(">> JNA download complete");
try {
JNA = new URLClassLoader(new URL[]{jna.toURI().toURL(), platform.toURI().toURL()});
} catch (Throwable e) {
log.log(SEVERE, ">> Couldn't load JNA:", e);
}
} else {
log.log(SEVERE, ">> Couldn't load JNA:", new FileNotFoundException());
}
}
return JNA;
}
}

View File

@ -0,0 +1,51 @@
package net.ME1312.SubServers.Bungee.Library.Compatibility;
import net.ME1312.SubServers.Bungee.SubAPI;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.util.CaseInsensitiveMap;
import java.util.Map;
import java.util.Map.Entry;
/**
* Legacy Server Map Translation Class
*/
public class LegacyServerMap extends CaseInsensitiveMap<ServerInfo> {
public LegacyServerMap() {
}
public LegacyServerMap(Map<String, ServerInfo> map) {
for (Entry<String, ServerInfo> e : map.entrySet()) super.put(e.getKey(), e.getValue());
}
@SuppressWarnings("deprecation")
@Override
public ServerInfo put(String key, ServerInfo value) {
if (value == null) throw new NullPointerException();
ServerInfo n = SubAPI.getInstance().addServer(value.getName(), value.getAddress().getAddress(), value.getAddress().getPort(), value.getMotd(), false, value.isRestricted()),
s = getOrDefault(key, null);
if (n != null)
super.put(n.getName(), n);
return s;
}
@Override
public ServerInfo remove(Object key) {
if (key instanceof String) {
ServerInfo s = getOrDefault(key, null);
if (s != null) {
if (SubAPI.getInstance().removeServer((String) key))
super.remove(key);
return s;
} else return null;
} else return null;
}
@Override
public void clear() {
// Disallow removing all servers
}
}

View File

@ -1,9 +1,9 @@
package net.ME1312.SubServers.Bungee.Library.Compatibility;
public class Plugin extends net.md_5.bungee.api.plugin.Plugin {
public final class Plugin extends net.md_5.bungee.api.plugin.Plugin {
@Override
public void onEnable() {
throw new IllegalStateException("SubServers.Bungee does not run as a plugin, but a wrapper. For more information on how to install, visit this page: https://github.com/ME1312/SubServers-2/wiki/Install");
@Deprecated
public Plugin() {
throw new IllegalStateException("SubServers.Bungee does not run as a plugin, but a wrapper. For more information on how to install, please visit this page: https://github.com/ME1312/SubServers-2/wiki/Installation");
}
}

View File

@ -1,74 +0,0 @@
package net.ME1312.SubServers.Bungee.Library.Compatibility.v1_13;
import net.ME1312.SubServers.Bungee.Library.NamedContainer;
import net.md_5.bungee.api.CommandSender;
import java.util.LinkedList;
import java.util.List;
/**
* Command Layout Class that implements all possible features (1.13 Version)
*/
public class CommandX extends net.ME1312.SubServers.Bungee.Library.Compatibility.CommandX/* implements TabValidator */ {
public final net.ME1312.SubServers.Bungee.Library.Compatibility.CommandX command;
/**
* Create a Command
*
* @param other CommandX from previous version
*/
public CommandX(net.ME1312.SubServers.Bungee.Library.Compatibility.CommandX other) {
super(other.getName());
command = other;
}
/**
* Override BungeeCord Method for the previously used one
*
* @param sender Sender
* @param args Arguments
*/
@Override
public void execute(CommandSender sender, String[] args) {
command.execute(sender, args);
}
@Override
public NamedContainer<String, List<String>> suggestArguments(CommandSender sender, String[] args) {
return command.suggestArguments(sender, args);
}
/**
* Validate a Command (Override for custom)
*
* @param sender Sender
* @param command Command to validate
* @return NamedContainer with a String error message and a Integer that represents where the command was deemed invalid
*/
public NamedContainer<String, Integer> validateCommand(CommandSender sender, String command) {
List<NamedContainer<String, Integer>> split = new LinkedList<NamedContainer<String, Integer>>();
String cmd = command;
int i;
while ((i = cmd.indexOf((int) ' ')) < 0) {
i++;
String arg = cmd.substring(i);
split.add(new NamedContainer<>(arg.contains(" ")?arg.substring(0, arg.indexOf((int) ' ')):arg, i));
cmd = arg;
}
List<String> args = new LinkedList<String>();
NamedContainer<String, Integer> response = null;
i = 0;
for (NamedContainer<String, Integer> arg : split) {
if (i > 0) {
args.add(arg.name());
NamedContainer<String, List<String>> suggestions = suggestArguments(sender, args.toArray(new String[args.size() - 1]));
if (suggestions.name() != null) response = new NamedContainer<>(suggestions.name(), arg.get());
}
i++;
}
return response;
}
// TODO Override the original validator method
}

View File

@ -1,110 +0,0 @@
package net.ME1312.SubServers.Bungee.Library.Config;
import net.ME1312.SubServers.Bungee.Library.Util;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.error.YAMLException;
import java.io.*;
import java.util.LinkedHashMap;
/**
* YAML Config Class
*/
@SuppressWarnings("unused")
public class YAMLConfig {
private File file;
private Yaml yaml;
private YAMLSection config;
/**
* Creates/Loads a YAML Formatted Config
*
* @param file
* @throws IOException
* @throws YAMLException
*/
@SuppressWarnings("unchecked")
public YAMLConfig(File file) throws IOException, YAMLException {
if (Util.isNull(file)) throw new NullPointerException();
this.file = file;
this.yaml = new Yaml(getDumperOptions());
if (file.exists()) {
InputStream stream = new FileInputStream(file);
this.config = new YAMLSection((LinkedHashMap<String, ?>) yaml.loadAs(stream, LinkedHashMap.class), null, null, yaml);
stream.close();
} else {
this.config = new YAMLSection(null, null, null, yaml);
}
}
/**
* Get Config Contents
*
* @return Config Contents
*/
public YAMLSection get() {
return config;
}
/**
* Set Config Contents
*
* @param value Value
*/
public void set(YAMLSection value) {
if (Util.isNull(value)) throw new NullPointerException();
config = value;
}
/**
* Reload Config Contents
*
* @throws IOException
*/
@SuppressWarnings("unchecked")
public void reload() throws IOException {
if (file.exists()) {
InputStream stream = new FileInputStream(file);
this.config = new YAMLSection((LinkedHashMap<String, ?>) yaml.loadAs(stream, LinkedHashMap.class), null, null, yaml);
stream.close();
} else {
this.config = new YAMLSection(null, null, null, yaml);
}
}
/**
* Save Config Contents
*
* @throws IOException
*/
public void save() throws IOException {
if (!file.exists()) file.createNewFile();
FileWriter writer = new FileWriter(file);
yaml.dump(config.map, writer);
writer.close();
}
@Override
public boolean equals(Object object) {
if (object instanceof YAMLConfig) {
return get().equals(((YAMLConfig) object).get());
} else {
return super.equals(object);
}
}
@Override
public String toString() {
return yaml.dump(config.map);
}
protected static DumperOptions getDumperOptions() {
DumperOptions options = new DumperOptions();
options.setAllowUnicode(true);
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
options.setIndent(4);
return options;
}
}

View File

@ -1,372 +0,0 @@
package net.ME1312.SubServers.Bungee.Library.Config;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.md_5.bungee.api.ChatColor;
import org.yaml.snakeyaml.Yaml;
import java.util.*;
/**
* YAML Value Class
*/
@SuppressWarnings({"unchecked", "unused"})
public class YAMLValue {
protected Object obj;
protected String label;
protected YAMLSection up;
private Yaml yaml;
protected YAMLValue(Object obj, YAMLSection up, String label, Yaml yaml) {
this.obj = obj;
this.label = label;
this.yaml = yaml;
this.up = up;
}
/**
* Get the YAML Section this Object was defined in
*
* @return YAML Section
*/
public YAMLSection getDefiningSection() {
return up;
}
/**
* Get Object
*
* @return Object
*/
public Object asObject() {
return obj;
}
/**
* Get Object as List
*
* @return List
*/
public List<?> asObjectList() {
return (List<?>) obj;
}
/**
* Get Object as Boolean
*
* @return Boolean
*/
public Boolean asBoolean() {
return (Boolean) obj;
}
/**
* Get Object as List
*
* @return List
*/
public List<Boolean> asBooleanList() {
return (List<Boolean>) obj;
}
/**
* Get Object as YAML Section
*
* @return YAML Section
*/
public YAMLSection asSection() {
if (obj != null) return new YAMLSection((Map<String, ?>) obj, up, label, yaml);
else return null;
}
/**
* Get Object as YAML Section List
*
* @return YAML Section List
*/
public List<YAMLSection> asSectionList() {
if (obj != null) {
List<YAMLSection> values = new ArrayList<YAMLSection>();
for (Map<String, ?> value : (List<? extends Map<String, ?>>) obj) {
values.add(new YAMLSection(value, null, null, yaml));
}
return values;
} else return null;
}
/**
* Get Object as Double
*
* @return Double
*/
public Double asDouble() {
return ((Number) obj).doubleValue();
}
/**
* Get Object as Double List
*
* @return Double List
*/
public List<Double> asDoubleList() {
return (List<Double>) obj;
}
/**
* Get Object as Float
*
* @return Float
*/
public Float asFloat() {
return ((Number) obj).floatValue();
}
/**
* Get Object as Float List
*
* @return Float List
*/
public List<Float> asFloatList() {
return (List<Float>) obj;
}
/**
* Get Object as Integer
*
* @return Integer
*/
public Integer asInt() {
return ((Number) obj).intValue();
}
/**
* Get Object as Integer List
*
* @return Integer List
*/
public List<Integer> asIntList() {
return (List<Integer>) obj;
}
/**
* Get Object as Long
*
* @return Long
*/
public Long asLong() {
return ((Number) obj).longValue();
}
/**
* Get Object as Long List
*
* @return Long List
*/
public List<Long> asLongList() {
return (List<Long>) obj;
}
/**
* Get a Short by Handle
*
* @return Short
*/
public Short asShort() {
return ((Number) obj).shortValue();
}
/**
* Get a Short List by Handle
*
* @return Short List
*/
public List<Short> asShortList() {
return (List<Short>) obj;
}
/**
* Get Object as Unparsed String
*
* @return Unparsed String
*/
public String asRawString() {
if (obj != null) return obj.toString();
else return null;
}
/**
* Get Object as Unparsed String List
*
* @return Unparsed String List
*/
public List<String> asRawStringList() {
if (obj != null) {
List<String> values = new ArrayList<String>();
for (Object value : (List<?>) obj) {
values.add(value.toString());
}
return values;
} else return null;
}
/**
* Get Object as String
*
* @return String
*/
public String asString() {
if (obj != null) return Util.unescapeJavaString(asRawString());
else return null;
}
/**
* Get Object as String List
*
* @return String List
*/
public List<String> asStringList() {
if (obj != null) {
List<String> values = new ArrayList<String>();
for (String value : asRawStringList()) {
values.add(Util.unescapeJavaString(value));
}
return values;
} else return null;
}
/**
* Get Object as Colored String
*
* @param color Color Char to parse
* @return Colored String
*/
public String asColoredString(char color) {
if (Util.isNull(color)) throw new NullPointerException();
if (obj != null) return ChatColor.translateAlternateColorCodes(color, asString());
else return null;
}
/**
* Get Object as Colored String List
*
* @param color Color Char to parse
* @return Colored String List
*/
public List<String> asColoredStringList(char color) {
if (obj != null) {
if (Util.isNull(color)) throw new NullPointerException();
List<String> values = new ArrayList<String>();
for (String value : asStringList()) {
values.add(ChatColor.translateAlternateColorCodes(color, value));
}
return values;
} else return null;
}
/**
* Get Object as UUID
*
* @return UUID
*/
public UUID asUUID() {
if (obj != null) return UUID.fromString((String) obj);
else return null;
}
/**
* Get Object as UUID List
*
* @return UUID List
*/
public List<UUID> asUUIDList() {
if (obj != null) {
List<UUID> values = new ArrayList<UUID>();
for (String value : (List<String>) obj) {
values.add(UUID.fromString(value));
}
return values;
} else return null;
}
/**
* Check if object is Null
*
* @return Null Status
*/
public boolean isNull() {
return obj == null;
}
/**
* Check if object is a Boolean
*
* @return Boolean Status
*/
public boolean isBoolean() {
return (obj instanceof Boolean);
}
/**
* Check if object is a YAML Section
*
* @return YAML Section Status
*/
public boolean isSection() {
return (obj instanceof Map);
}
/**
* Check if object is a List
*
* @return List Status
*/
public boolean isList() {
return (obj instanceof List);
}
/**
* Check if object is a Number
*
* @return Number Status
*/
public boolean isNumber() {
return (obj instanceof Number);
}
/**
* Check if object is a String
*
* @return String Status
*/
public boolean isString() {
return (obj instanceof String);
}
/**
* Check if object is a UUID
*
* @return UUID Status
*/
public boolean isUUID() {
return (obj instanceof String && !Util.isException(() -> UUID.fromString((String) obj)));
}
@Override
public boolean equals(Object object) {
if (obj == null) {
return object == null;
} else {
if (object instanceof YAMLValue) {
return obj.equals(((YAMLValue) object).obj);
} else {
return obj.equals(object);
}
}
}
@Override
public String toString() {
if (obj != null) return obj.toString();
else return "null";
}
}

View File

@ -0,0 +1,562 @@
package net.ME1312.SubServers.Bungee.Library;
import net.ME1312.Galaxi.Library.Config.YAMLConfig;
import net.ME1312.Galaxi.Library.Config.YAMLSection;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Version.Version;
import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.SubAPI;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* SubServers Configuration Updater
*/
public class ConfigUpdater {
private static final Version UNSIGNED = new Version(new SimpleDateFormat("yy'w'ww'zz'").format(Calendar.getInstance().getTime()));
/**
* Update SubServers' config.yml
*
* @param file File to bring up-to-date
*/
public static void updateConfig(File file) throws IOException {
YAMLConfig config = new YAMLConfig(file);
YAMLSection existing = config.get().clone();
YAMLSection updated = existing.clone();
YAMLSection rewritten = new YAMLSection();
Version was = existing.getMap("Settings", new ObjectMap<>()).getVersion("Version", new Version(0));
Version now = SubAPI.getInstance().getWrapperBuild();
int i = 0;
if (now == null) now = UNSIGNED;
if (!existing.contains("Settings") || !existing.getMap("Settings").contains("Version")) {
YAMLSection hosts = new YAMLSection();
YAMLSection host = new YAMLSection();
host.set("Enabled", true);
host.set("Display", "Default");
hosts.set("~", host);
updated.set("Hosts", hosts);
i++;
Logger.get("SubServers").info("Created ./SubServers/config.yml");
} else {
if (was.compareTo(new Version("19w17a")) <= 0) {
if (existing.getMap("Settings", new YAMLSection()).contains("Log-Creator")) for (String name : existing.getMap("Hosts", new YAMLSection()).getKeys())
updated.getMap("Hosts").getMap(name).safeSet("Log-Creator", existing.getMap("Settings").getBoolean("Log-Creator"));
if (existing.getMap("Settings", new YAMLSection()).contains("SubData") && !existing.getMap("Settings", new YAMLSection()).getMap("SubData").contains("Encryption"))
updated.getMap("Settings").getMap("SubData").set("Encryption", "NONE");
if (existing.contains("Servers")) {
YAMLConfig sc = new YAMLConfig(new File(file.getParentFile(), "servers.yml"));
YAMLSection settings = new YAMLSection();
settings.set("Version", was.toString());
settings.set("Run-On-Launch-Timeout", (existing.getMap("Settings", new YAMLSection()).contains("Run-On-Launch-Timeout"))?existing.getMap("Settings").getInt("Run-On-Launch-Timeout"):0);
sc.get().safeSet("Settings", settings);
sc.get().safeSet("Servers", new YAMLSection());
sc.get().getMap("Servers").safeSetAll(existing.getMap("Servers"));
Logger.get("SubServers").info("Created ./SubServers/servers.yml (using existing data)");
sc.save();
}
existing = updated.clone();
i++;
} if (was.compareTo(new Version("19w35c")) <= 0) {
if (existing.getMap("Settings", new YAMLSection()).contains("SubData")) {
LinkedList<String> whitelist = new LinkedList<>();
LinkedList<String> newWhitelist = new LinkedList<>();
whitelist.addAll(existing.getMap("Settings", new YAMLSection()).getMap("SubData", new YAMLSection()).getStringList("Allowed-Connections", Collections.emptyList()));
whitelist.addAll(existing.getMap("Settings", new YAMLSection()).getMap("SubData", new YAMLSection()).getStringList("Whitelist", Collections.emptyList()));
boolean warnPls = false;
for (String address : whitelist) {
Matcher regAddress = Pattern.compile("^(\\d{1,3}|%)\\.(\\d{1,3}|%)\\.(\\d{1,3}|%)\\.(\\d{1,3}|%)$").matcher(address);
if (regAddress.find()) {
StringBuilder newAddress = new StringBuilder();
int subnet = -1;
boolean warn = false;
for (int o = 1; o <= 4; o++) {
if (o > 1) newAddress.append('.');
if (subnet == -1) {
if (!regAddress.group(o).equals("%")) {
newAddress.append(regAddress.group(o));
} else {
subnet = 8 * (o - 1);
newAddress.append('0');
}
} else {
if (!regAddress.group(o).equals("%")) warn = warnPls = true;
newAddress.append('0');
}
}
if (subnet < 0) subnet = 32;
if (warn) Logger.get("SubServers").warning("Updating non-standard mask: " + address);
newAddress.append('/');
newAddress.append(subnet);
newWhitelist.add(newAddress.toString());
}
}
updated.getMap("Settings").getMap("SubData").set("Whitelist", newWhitelist);
if (warnPls) Logger.get("SubServers").warning("Non-standard masks have been updated. This may expose SubData to unintended networks!");
}
existing = updated.clone();
i++;
} if (was.compareTo(new Version("20w08d")) <= 0) {
if (existing.contains("Hosts")) {
for (String name : existing.getMap("Hosts", new YAMLSection()).getKeys()) {
if (existing.getMap("Hosts").getMap(name).getString("Driver", "BUILT_IN").replace('-', '_').replace(' ', '_').equalsIgnoreCase("BUILT_IN"))
updated.getMap("Hosts").getMap(name).set("Driver", "VIRTUAL");
}
}
existing = updated.clone();
i++;
} if (was.compareTo(new Version("20w34a")) <= 0) {
if (existing.getMap("Settings", new YAMLSection()).contains("Smart-Fallback") && existing.getMap("Settings").isBoolean("Smart-Fallback")) {
YAMLSection smart_fallback = new YAMLSection();
smart_fallback.set("Enabled", existing.getMap("Settings").getBoolean("Smart-Fallback"));
smart_fallback.set("Fallback", existing.getMap("Settings").getBoolean("Smart-Fallback"));
updated.getMap("Settings").set("Smart-Fallback", smart_fallback);
}
if (existing.getMap("Settings", new YAMLSection()).contains("Override-Bungee-Commands") && existing.getMap("Settings").isBoolean("Override-Bungee-Commands")) {
List<String> overrides = new LinkedList<>();
if (!existing.getMap("Settings").getBoolean("Override-Bungee-Commands")) {
overrides.add("/server");
overrides.add("/glist");
}
updated.getMap("Settings").set("Disabled-Overrides", overrides);
}
existing = updated.clone();
i++;
} else if (was.compareTo(new Version("21w27b")) <= 0) {
//existing = updated.clone();
i++;
}// if (was.compareTo(new Version("99w99a")) <= 0) {
// // do something
// existing = updated.clone();
// i++
//}
if (i > 0) Logger.get("SubServers").info("Updated ./SubServers/config.yml (" + i + " pass" + ((i != 1)?"es":"") + ")");
}
if (i > 0) {
YAMLSection settings = new YAMLSection();
settings.set("Version", ((now.compareTo(was) <= 0)?was:now).toString());
if (updated.getMap("Settings", new YAMLSection()).contains("RPEC-Check-Interval")) settings.set("RPEC-Check-Interval", updated.getMap("Settings").getString("RPEC-Check-Interval"));
settings.set("Strict-Server-Linking", updated.getMap("Settings", new YAMLSection()).getBoolean("Strict-Server-Linking", true));
settings.set("Disabled-Overrides", updated.getMap("Settings", new YAMLSection()).getStringList("Disabled-Overrides", Collections.emptyList()));
YAMLSection smart_fallback = new YAMLSection();
smart_fallback.set("Enabled", updated.getMap("Settings", new YAMLSection()).getMap("Smart-Fallback", new YAMLSection()).getBoolean("Enabled", true));
smart_fallback.set("Fallback", updated.getMap("Settings", new YAMLSection()).getMap("Smart-Fallback", new YAMLSection()).getBoolean("Fallback", true));
smart_fallback.set("Reconnect", updated.getMap("Settings", new YAMLSection()).getMap("Smart-Fallback", new YAMLSection()).getBoolean("Reconnect", false));
smart_fallback.set("DNS-Forward", updated.getMap("Settings", new YAMLSection()).getMap("Smart-Fallback", new YAMLSection()).getBoolean("DNS-Forward", false));
settings.set("Smart-Fallback", smart_fallback);
YAMLSection upnp = new YAMLSection();
upnp.set("Forward-Proxy", updated.getMap("Settings", new YAMLSection()).getMap("UPnP", new YAMLSection()).getBoolean("Forward-Proxy", true));
upnp.set("Forward-SubData", updated.getMap("Settings", new YAMLSection()).getMap("UPnP", new YAMLSection()).getBoolean("Forward-SubData", false));
upnp.set("Forward-Servers", updated.getMap("Settings", new YAMLSection()).getMap("UPnP", new YAMLSection()).getBoolean("Forward-Servers", false));
settings.set("UPnP", upnp);
YAMLSection subdata = new YAMLSection();
subdata.set("Address", updated.getMap("Settings", new YAMLSection()).getMap("SubData", new YAMLSection()).getString("Address", "127.0.0.1:4391"));
if (updated.getMap("Settings", new YAMLSection()).getMap("SubData", new YAMLSection()).contains("Password")) subdata.set("Password", updated.getMap("Settings").getMap("SubData").getString("Password"));
subdata.set("Encryption", updated.getMap("Settings", new YAMLSection()).getMap("SubData", new YAMLSection()).getString("Encryption", "RSA/AES"));
subdata.set("Whitelist", updated.getMap("Settings", new YAMLSection()).getMap("SubData", new YAMLSection()).getStringList("Whitelist", Collections.emptyList()));
settings.set("SubData", subdata);
rewritten.set("Settings", settings);
YAMLSection hosts = new YAMLSection();
for (String name : updated.getMap("Hosts", new YAMLSection()).getKeys()) {
YAMLSection host = new YAMLSection();
host.set("Enabled", updated.getMap("Hosts").getMap(name).getBoolean("Enabled", false));
host.set("Display", updated.getMap("Hosts").getMap(name).getString("Display", ""));
host.set("Driver", updated.getMap("Hosts").getMap(name).getString("Driver", "VIRTUAL"));
host.set("Address", updated.getMap("Hosts").getMap(name).getString("Address", "127.0.0.1"));
host.set("Port-Range", updated.getMap("Hosts").getMap(name).getString("Port-Range", "25500-25559"));
host.set("Directory", updated.getMap("Hosts").getMap(name).getString("Directory", (host.getString("Driver").equalsIgnoreCase("VIRTUAL"))?"./SubServers/Servers":"./Servers"));
host.set("Git-Bash", updated.getMap("Hosts").getMap(name).getString("Git-Bash", "%ProgramFiles%\\Git"));
host.set("Log-Creator", updated.getMap("Hosts").getMap(name).getBoolean("Log-Creator", true));
if (updated.getMap("Hosts").getMap(name).contains("Extra")) host.set("Extra", updated.getMap("Hosts").getMap(name).getMap("Extra"));
hosts.set(name, host);
}
rewritten.set("Hosts", hosts);
config.set(rewritten);
config.save();
}
}
/**
* Update SubServers' servers.yml
*
* @param file File to bring up-to-date
*/
public static void updateServers(File file) throws IOException {
YAMLConfig config = new YAMLConfig(file);
YAMLSection existing = config.get().clone();
YAMLSection updated = existing.clone();
YAMLSection rewritten = new YAMLSection();
Version was = existing.getMap("Settings", new ObjectMap<>()).getVersion("Version", new Version(0));
Version now = SubAPI.getInstance().getWrapperBuild();
int i = 0;
if (now == null) now = UNSIGNED;
if (!existing.contains("Settings") || !existing.getMap("Settings").contains("Version")) {
YAMLSection servers = new YAMLSection();
servers.set("Example", new YAMLSection());
updated.set("Servers", servers);
i++;
Logger.get("SubServers").info("Created ./SubServers/servers.yml");
} else {
if (was.compareTo(new Version("19w17a")) <= 0) {
if (existing.contains("Servers")) {
for (String name : existing.getMap("Servers", new YAMLSection()).getKeys()) {
if (existing.getMap("Servers").getMap(name).getBoolean("Auto-Restart", true))
updated.getMap("Servers").getMap(name).safeSet("Stop-Action", "RESTART");
if (existing.getMap("Servers").getMap(name).getString("Stop-Action", "NONE").equalsIgnoreCase("DELETE_SERVER"))
updated.getMap("Servers").getMap(name).set("Stop-Action", "RECYCLE_SERVER");
}
}
existing = updated.clone();
i++;
}// if (was.compareTo(new Version("99w99a")) <= 0) {
// // do something
// i++
//}
if (i > 0) Logger.get("SubServers").info("Updated ./SubServers/servers.yml (" + i + " pass" + ((i != 1)?"es":"") + ")");
}
if (i > 0) {
YAMLSection settings = new YAMLSection();
settings.set("Version", ((now.compareTo(was) <= 0)?was:now).toString());
settings.set("Run-On-Launch-Timeout", updated.getMap("Settings", new YAMLSection()).getInt("Run-On-Launch-Timeout", 0));
rewritten.set("Settings", settings);
YAMLSection servers = new YAMLSection();
for (String name : updated.getMap("Servers", new YAMLSection()).getKeys()) {
YAMLSection server = new YAMLSection();
server.set("Enabled", updated.getMap("Servers").getMap(name).getBoolean("Enabled", false));
server.set("Display", updated.getMap("Servers").getMap(name).getString("Display", ""));
server.set("Host", updated.getMap("Servers").getMap(name).getString("Host", "~"));
if (updated.getMap("Servers").getMap(name).contains("Template")) server.set("Template", updated.getMap("Servers").getMap(name).getString("Template"));
server.set("Group", updated.getMap("Servers").getMap(name).getStringList("Groups", Collections.emptyList()));
server.set("Port", updated.getMap("Servers").getMap(name).getInt("Port", 25567));
server.set("Motd", updated.getMap("Servers").getMap(name).getString("Motd", "Some SubServer"));
server.set("Log", updated.getMap("Servers").getMap(name).getBoolean("Log", true));
server.set("Directory", updated.getMap("Servers").getMap(name).getString("Directory", "." + File.separatorChar));
server.set("Executable", updated.getMap("Servers").getMap(name).getString("Executable", "java -Xmx1024M -Djline.terminal=jline.UnsupportedTerminal -jar Spigot.jar"));
server.set("Stop-Command", updated.getMap("Servers").getMap(name).getString("Stop-Command", "stop"));
server.set("Stop-Action", updated.getMap("Servers").getMap(name).getString("Stop-Action", "NONE"));
server.set("Run-On-Launch", updated.getMap("Servers").getMap(name).getBoolean("Run-On-Launch", false));
server.set("Restricted", updated.getMap("Servers").getMap(name).getBoolean("Restricted", false));
server.set("Incompatible", updated.getMap("Servers").getMap(name).getStringList("Incompatible", Collections.emptyList()));
server.set("Hidden", updated.getMap("Servers").getMap(name).getBoolean("Hidden", false));
if (updated.getMap("Servers").getMap(name).contains("Extra")) server.set("Extra", updated.getMap("Servers").getMap(name).getMap("Extra"));
servers.set(name, server);
}
rewritten.set("Servers", servers);
config.set(rewritten);
config.save();
}
}
/**
* Update SubServers' lang.yml
*
* @param file File to bring up-to-date
*/
public static void updateLang(File file) throws IOException {
YAMLConfig config = new YAMLConfig(file);
YAMLSection existing = config.get().clone();
YAMLSection updated = existing.clone();
YAMLSection rewritten = new YAMLSection();
Version was = existing.getMap("Settings", new ObjectMap<>()).getVersion("Version", new Version(0));
Version now = SubAPI.getInstance().getWrapperBuild();
int i = 0;
if (now == null) now = UNSIGNED;
if (!existing.contains("Settings") || !existing.getMap("Settings").contains("Version")) {
i++;
Logger.get("SubServers").info("Created ./SubServers/lang.yml");
} else {
if (was.compareTo(new Version("19w22b")) <= 0) {
if (existing.contains("Lang")) {
updated.getMap("Lang").remove("Interface.Host-Admin.SubServers");
updated.getMap("Lang").remove("Interface.Server-Admin.Command");
}
existing = updated.clone();
i++;
} if (was.compareTo(new Version("20w08d")) <= 0) {
if (existing.contains("Lang")) {
LinkedList<String> keys = new LinkedList<>(existing.getMap("Lang").getKeys());
for (String key : keys) if (key.startsWith("Command.")) {
updated.getMap("Lang").remove(key);
}
}
existing = updated.clone();
i++;
} if (was.compareTo(new Version("22w07c")) <= 0) {
if (existing.contains("Lang")) {
updated.getMap("Lang").remove("Command.Teleport");
}
existing = updated.clone();
i++;
}// if (was.compareTo(new Version("99w99a")) <= 0) {
// // do something
// i++
//}
if (i > 0) Logger.get("SubServers").info("Updated ./SubServers/lang.yml (" + i + " pass" + ((i != 1)?"es":"") + ")");
}
if (i > 0) {
YAMLSection settings = new YAMLSection();
settings.set("Version", ((now.compareTo(was) <= 0)?was:now).toString());
rewritten.set("Settings", settings);
LinkedHashMap<String, String> def = new LinkedHashMap<String, String>();
def.put("Bungee.Feature.Smart-Fallback", "&6Returning from $str$: &r$msg$");
def.put("Bungee.Feature.Smart-Fallback.Result", "&6You are now on $str$.");
def.put("Bungee.Restricted", "&cYou don't have permission to access this server.");
def.put("Bungee.Ping.Offline", "&6&l[&e&lWarning&6&l] &7Backend server(s) are not running");
def.put("Bungee.Server.Current", "&6You are currently connected to $str$");
def.put("Bungee.Server.Available", "&6You may connect to the following servers at this time:");
def.put("Bungee.Server.List", "&6$str$");
def.put("Bungee.Server.Hover", "$int$ player(s)\\n&oClick to connect to the server");
def.put("Bungee.Server.Divider", "&6, ");
def.put("Bungee.Server.Offline", "&cThe specified server is not currently running.");
def.put("Bungee.Server.Invalid", "&cThe specified server does not exist.");
def.put("Bungee.List.Format", "&a[$str$] &e($int$)&r: ");
def.put("Bungee.List.List", "&f$str$");
def.put("Bungee.List.Divider", "&f, ");
def.put("Bungee.List.Total", "Total players online: $int$");
def.put("Signs.Create", "&aSubServers &2&l\\u00BB&a Server sign activated");
def.put("Signs.Delete", "&aSubServers &2&l\\u00BB&a Server sign removed");
def.put("Signs.Text.Unknown", "&f&oSubServers\\n&3$str$\\n&7Unknown Status\\n&8\\u2022 \\u2022 \\u2022 \\u2022 \\u2022 \\u2022 \\u2022");
def.put("Signs.Text.Offline", "&c&oSubServers\\n&3$str$\\n&4Offline\\n&7Click to Start");
def.put("Signs.Text.Starting", "&e&oSubServers\\n&3$str$\\n&6Starting\\n&8\\u2022 \\u2022 \\u2022 \\u2022 \\u2022 \\u2022 \\u2022");
def.put("Signs.Text.Online", "&a&oSubServers\\n&3$str$\\n&2$int$ Online\\n&7Click to Join");
def.put("Signs.Text.Stopping", "&e&oSubServers\\n&3$str$\\n&6Stopping\\n&8\\u2022 \\u2022 \\u2022 \\u2022 \\u2022 \\u2022 \\u2022");
def.put("Command.Generic.Player-Only", "&cSubServers &4&l\\u00BB&c The console cannot perform this command");
def.put("Command.Generic.Console-Only", "&cSubServers &4&l\\u00BB&c This command is for console use only");
def.put("Command.Generic.Usage", "&7SubServers &8&l\\u00BB&7 Usage: &f$str$");
def.put("Command.Generic.Exception", "&cSubServers &4&l\\u00BB&c An unexpected exception has occurred while parsing this command");
def.put("Command.Generic.Invalid-Subcommand", "&cSubServers &4&l\\u00BB&c Unknown sub-command: &4$str$");
def.put("Command.Generic.Invalid-Permission", "&cSubServers &4&l\\u00BB&c You need &4&n$str$&c to use this command");
def.put("Command.Generic.Invalid-Select-Permission", "&cSubServers &4&l\\u00BB&c You don't have permission to select &4$str$");
def.put("Command.Generic.Unknown-Proxy", "&cSubServers &4&l\\u00BB&c There is no proxy named &4$str$");
def.put("Command.Generic.Unknown-Host", "&cSubServers &4&l\\u00BB&c There is no host named &4$str$");
def.put("Command.Generic.Unknown-Group", "&cSubServers &4&l\\u00BB&c There is no group named &4$str$");
def.put("Command.Generic.Unknown-Server", "&cSubServers &4&l\\u00BB&c There is no server named &4$str$");
def.put("Command.Generic.Unknown-SubServer", "&cSubServers &4&l\\u00BB&c There is no subserver named &4$str$");
def.put("Command.Generic.Unknown-Player", "&cSubServers &4&l\\u00BB&c There is no player named &4$str$");
def.put("Command.Generic.No-Servers-On-Host", "&7SubServers &8&l\\u00BB&7 There are no servers on host &f$str$");
def.put("Command.Generic.No-SubServers-On-Host", "&7SubServers &8&l\\u00BB&7 There are no subservers on host &f$str$");
def.put("Command.Generic.No-Servers-In-Group", "&7SubServers &8&l\\u00BB&7 There are no servers in group &f$str$");
def.put("Command.Generic.No-SubServers-In-Group", "&7SubServers &8&l\\u00BB&7 There are no subservers in group &f$str$");
def.put("Command.Generic.No-Servers-Selected", "&cSubServers &4&l\\u00BB&c No servers were selected");
def.put("Command.Generic.No-SubServers-Selected", "&cSubServers &4&l\\u00BB&c No subservers were selected");
def.put("Command.Help.Header", "&7SubServers &8&l\\u00BB&7 Command Help:");
def.put("Command.Help.Help", " &7Help:&f $str$");
def.put("Command.Help.List", " &7List:&f $str$");
def.put("Command.Help.Version", " &7Version:&f $str$");
def.put("Command.Help.Info", " &7Info:&f $str$");
def.put("Command.Help.Host.Create", " &7Create Server:&f $str$");
def.put("Command.Help.SubServer.Start", " &7Start Server:&f $str$");
def.put("Command.Help.SubServer.Restart", " &7Restart Server:&f $str$");
def.put("Command.Help.SubServer.Stop", " &7Stop Server:&f $str$");
def.put("Command.Help.SubServer.Terminate", " &7Terminate Server:&f $str$");
def.put("Command.Help.SubServer.Command", " &7Command Server:&f $str$");
def.put("Command.Help.SubServer.Update", " &7Update Server:&f $str$");
def.put("Command.Version", "&7SubServers &8&l\\u00BB&7 These are the platforms and versions that are running &f$str$&7:");
def.put("Command.Version.Outdated", "&7$name$ &f$str$ &7is available. You are $int$ version(s) behind.");
def.put("Command.Version.Latest", "&7You are on the latest version.");
def.put("Command.List.Group-Header", "&7SubServers &8&l\\u00BB&7 Group/Server List:");
def.put("Command.List.Host-Header", "&7SubServers &8&l\\u00BB&7 Host/SubServer List:");
def.put("Command.List.Server-Header", "&7SubServers &8&l\\u00BB&7 Server List:");
def.put("Command.List.Proxy-Header", "&7SubServers &8&l\\u00BB&7 Proxy List:");
def.put("Command.List.Header", "&7: ");
def.put("Command.List.Divider", "&7, ");
def.put("Command.List.Empty", "&7(none)");
def.put("Command.Info", "&7SubServers &8&l\\u00BB&7 Info on $str$: &r");
def.put("Command.Info.Unknown", "&cSubServers &4&l\\u00BB&c There is no object with that name");
def.put("Command.Info.Unknown-Type", "&cSubServers &4&l\\u00BB&c There is no object type with that name");
def.put("Command.Info.Unknown-Proxy", "&cSubServers &4&l\\u00BB&c There is no proxy with that name");
def.put("Command.Info.Unknown-Host", "&cSubServers &4&l\\u00BB&c There is no host with that name");
def.put("Command.Info.Unknown-Group", "&cSubServers &4&l\\u00BB&c There is no group with that name");
def.put("Command.Info.Unknown-Server", "&cSubServers &4&l\\u00BB&c There is no server with that name");
def.put("Command.Info.Unknown-Player", "&cSubServers &4&l\\u00BB&c There is no player with that name");
def.put("Command.Info.Format", " -> &7$str$&7: &r");
def.put("Command.Info.List", " - ");
def.put("Command.Start", "&aSubServers &2&l\\u00BB&a Started &2$int$&a subserver(s)");
def.put("Command.Start.Disappeared", "&cSubServers &4&l\\u00BB&c Subserver &4$str$&c has disappeared");
def.put("Command.Start.Host-Unavailable", "&cSubServers &4&l\\u00BB&c The host for &4$str$&c is not available");
def.put("Command.Start.Host-Disabled", "&cSubServers &4&l\\u00BB&c The host for &4$str$&c is not enabled");
def.put("Command.Start.Server-Unavailable", "&cSubServers &4&l\\u00BB&c Subserver &4$str$&c is not available");
def.put("Command.Start.Server-Disabled", "&cSubServers &4&l\\u00BB&c Subserver &4$str$&c is not enabled");
def.put("Command.Start.Server-Incompatible", "&cSubServers &4&l\\u00BB&c Subserver &4$str$&c cannot start while incompatible server(s) are running");
def.put("Command.Start.Running", "&7SubServers &8&l\\u00BB&7 &f$int$&7 subserver(s) were already running");
def.put("Command.Restart", "&aSubServers &2&l\\u00BB&a Restarting &2$int$&a subserver(s)");
def.put("Command.Restart.Disappeared", "&cSubServers &4&l\\u00BB&c Could not restart server: Subserver &4$str$&c has disappeared");
def.put("Command.Restart.Host-Unavailable", "&cSubServers &4&l\\u00BB&c Could not restart server: The host for &4$str$&c is no longer available");
def.put("Command.Restart.Host-Disabled", "&cSubServers &4&l\\u00BB&c Could not restart server: The host for &4$str$&c is no longer enabled");
def.put("Command.Restart.Server-Unavailable", "&cSubServers &4&l\\u00BB&c Could not restart server: Subserver &4$str$&c is no longer available");
def.put("Command.Restart.Server-Disabled", "&cSubServers &4&l\\u00BB&c Could not restart server: Subserver &4$str$&c is no longer enabled");
def.put("Command.Restart.Server-Incompatible", "&cSubServers &4&l\\u00BB&c Could not restart server: Subserver &4$str$&c cannot start while incompatible server(s) are running");
def.put("Command.Stop", "&aSubServers &2&l\\u00BB&a Stopping &2$int$&a subserver(s)");
def.put("Command.Stop.Disappeared", "&cSubServers &4&l\\u00BB&c Subserver &4$str$&c has disappeared");
def.put("Command.Stop.Not-Running", "&7SubServers &8&l\\u00BB&7 &f$int$&7 subserver(s) were already offline");
def.put("Command.Terminate", "&aSubServers &2&l\\u00BB&a Terminated &2$int$&a subserver(s)");
def.put("Command.Terminate.Disappeared", "&cSubServers &4&l\\u00BB&c Subserver &4$str$&c has disappeared");
def.put("Command.Terminate.Not-Running", "&7SubServers &8&l\\u00BB&7 &f$int$&7 subserver(s) were already offline");
def.put("Command.Command", "&aSubServers &2&l\\u00BB&a Sent command to &2$int$&a server(s)");
def.put("Command.Command.Disappeared", "&cSubServers &4&l\\u00BB&c Server &4$str$&c has disappeared");
def.put("Command.Command.No-Command", "&cSubServers &4&l\\u00BB&c No command was entered");
def.put("Command.Command.Not-Running", "&7SubServers &8&l\\u00BB&7 &f$int$&7 server(s) were unavailable");
def.put("Command.Creator", "&aSubServers &2&l\\u00BB&a Creating subserver &2$str$&a");
def.put("Command.Creator.Exists", "&cSubServers &4&l\\u00BB&c There is already a subserver with that name");
def.put("Command.Creator.Unknown-Host", "&cSubServers &4&l\\u00BB&c There is no host with that name");
def.put("Command.Creator.Host-Unavailable", "&cSubServers &4&l\\u00BB&c That host is not available");
def.put("Command.Creator.Host-Disabled", "&cSubServers &4&l\\u00BB&c That host is not enabled");
def.put("Command.Creator.Unknown-Template", "&cSubServers &4&l\\u00BB&c There is no template with that name");
def.put("Command.Creator.Template-Disabled", "&cSubServers &4&l\\u00BB&c That template is not enabled");
def.put("Command.Creator.Template-Invalid", "&cSubServers &4&l\\u00BB&c That template does not support subserver updating");
def.put("Command.Creator.Version-Required", "&cSubServers &4&l\\u00BB&c That template requires a Minecraft version to be specified");
def.put("Command.Creator.Invalid-Port", "&cSubServers &4&l\\u00BB&c Invalid port number");
def.put("Command.Update", "&aSubServers &2&l\\u00BB&a Updating &2$int$&a subserver(s)");
def.put("Command.Update.Disappeared", "&cSubServers &4&l\\u00BB&c Subserver &4$str$&c has disappeared");
def.put("Command.Update.Host-Unavailable", "&cSubServers &4&l\\u00BB&c The host for &4$str$&c is not available");
def.put("Command.Update.Host-Disabled", "&cSubServers &4&l\\u00BB&c The host for &4$str$&c is not enabled");
def.put("Command.Update.Server-Unavailable", "&cSubServers &4&l\\u00BB&c Subserver &4$str$&c is not available");
def.put("Command.Update.Running", "&cSubServers &4&l\\u00BB&c Cannot update &4$str$&c while it is still running");
def.put("Command.Update.Unknown-Template", "&cSubServers &4&l\\u00BB&c We don't know which template created &4$str$");
def.put("Command.Update.Template-Disabled", "&cSubServers &4&l\\u00BB&c The template that created &4$str$&c is not enabled");
def.put("Command.Update.Template-Invalid", "&cSubServers &4&l\\u00BB&c The template that created &4$str$&c does not support subserver updating");
def.put("Command.Update.Version-Required", "&cSubServers &4&l\\u00BB&c The template that created &4$str$&c requires a Minecraft version to be specified");
def.put("Command.Delete.Disappeared", "&cSubServers &4&l\\u00BB&c Subserver &4$str$&c has disappeared");
def.put("Command.Delete.Running", "&cSubServers &4&l\\u00BB&c Cannot delete &4$str$&c while it is still running");
def.put("Command.Delete", "&aSubServers &2&l\\u00BB&a Deleting &2$int$&a subserver(s)");
def.put("Command.Teleport", "&aSubServers &2&l\\u00BB&a Teleporting to &2$str$");
def.put("Command.Teleport.Others", "&aSubServers &2&l\\u00BB&a Teleporting &2$name$&a to &2$str$");
def.put("Command.Teleport.Not-Running", "&cSubServers &4&l\\u00BB&c Subserver &4$str$&c is not running");
def.put("Interface.Generic.Back", "&cBack");
def.put("Interface.Generic.Back-Arrow", "&e&l<--");
def.put("Interface.Generic.Next-Arrow", "&e&l-->");
def.put("Interface.Generic.Undo", "&6Undo");
def.put("Interface.Generic.Downloading", "&7SubServers &8&l\\u00BB&7 Downloading:&f $str$");
def.put("Interface.Generic.Downloading.Title", "Downloading...");
def.put("Interface.Generic.Downloading.Title-Color", "&b");
def.put("Interface.Generic.Downloading.Title-Color-Alt", "&3");
def.put("Interface.Generic.Downloading.Response", "&eWaiting for response");
def.put("Interface.Generic.Invalid-Permission", "&4You need &n$str$");
def.put("Interface.Proxy-Menu.Proxy-Player-Count", "&2$int$ Player(s) Online");
def.put("Interface.Proxy-Menu.Proxy-Master", "&8Master Proxy");
def.put("Interface.Proxy-Menu.Proxy-Disconnected", "&4Disconnected");
def.put("Interface.Host-Menu.Title", "Host Menu");
def.put("Interface.Host-Menu.Host-Unavailable", "&4Unavailable");
def.put("Interface.Host-Menu.Host-Disabled", "&4Disabled");
def.put("Interface.Host-Menu.Host-Server-Count", "&9$int$ Server(s)");
def.put("Interface.Host-Menu.No-Hosts", "&c&oThere are No Hosts");
def.put("Interface.Host-Menu.Group-Menu", "&6&lView Servers by Group");
def.put("Interface.Host-Menu.Server-Menu", "&a&lView Servers");
def.put("Interface.Host-Admin.Title", "Host/$str$");
def.put("Interface.Host-Admin.Creator", "&eCreate a SubServer");
def.put("Interface.Host-Admin.SubServers", "&bView SubServers");
def.put("Interface.Host-Admin.Plugins", "&bPlugins...");
def.put("Interface.Host-Creator.Title", "Host/$str$/Create");
def.put("Interface.Host-Creator.Edit-Name", "Change Name");
def.put("Interface.Host-Creator.Edit-Name.Title", "&eSubCreator\\n&6Enter a Name for this Server");
def.put("Interface.Host-Creator.Edit-Name.Message", "&eSubCreator &6&l\\u00BB&e Enter a Name for this Server via Chat");
def.put("Interface.Host-Creator.Edit-Name.Exists", "&cSubCreator &4&l\\u00BB&c There is already a SubServer with that name");
def.put("Interface.Host-Creator.Edit-Name.Exists-Title", "&eSubCreator\\n&cThere is already a SubServer with that name");
def.put("Interface.Host-Creator.Edit-Name.Invalid", "&cSubCreator &4&l\\u00BB&c Invalid Server Name");
def.put("Interface.Host-Creator.Edit-Name.Invalid-Title", "&eSubCreator\\n&cInvalid Server Name");
def.put("Interface.Host-Creator.Edit-Template", "Change Server Template");
def.put("Interface.Host-Creator.Edit-Template.Title", "Host/$str$/Templates");
def.put("Interface.Host-Creator.Edit-Template.No-Templates", "&c&oThere are No Templates");
def.put("Interface.Host-Creator.Edit-Version", "Change Server Version");
def.put("Interface.Host-Creator.Edit-Version.Title", "&eSubCreator\\n&6Enter a Server Version");
def.put("Interface.Host-Creator.Edit-Version.Message", "&eSubCreator &6&l\\u00BB&e Enter a Server Version via Chat");
def.put("Interface.Host-Creator.Edit-Port", "Change Server Port");
def.put("Interface.Host-Creator.Edit-Port.Title", "&eSubCreator\\n&6Enter a Port Number");
def.put("Interface.Host-Creator.Edit-Port.Message", "&eSubCreator &6&l\\u00BB&e Enter a Port Number via Chat");
def.put("Interface.Host-Creator.Edit-Port.Invalid", "&cSubCreator &4&l\\u00BB&c Invalid Port Number");
def.put("Interface.Host-Creator.Edit-Port.Invalid-Title", "&eSubCreator\\n&cInvalid Port Number");
def.put("Interface.Host-Creator.Submit", "&eCreate SubServer");
def.put("Interface.Host-Creator.Form-Incomplete", "&4Buttons above must be green");
def.put("Interface.Host-Plugin.Title", "Host/$str$/Plugins");
def.put("Interface.Host-Plugin.No-Plugins", "&c&oThere are No Plugins Available");
def.put("Interface.Host-SubServer.Title", "Host/$str$/SubServers");
def.put("Interface.Group-Menu.Title", "Group Menu");
def.put("Interface.Group-Menu.Group-Server-Count", "&9$int$ Server(s)");
def.put("Interface.Group-Menu.Ungrouped", "&7(ungrouped)");
def.put("Interface.Group-Menu.Server-Menu", "&a&lView All Servers");
def.put("Interface.Group-SubServer.Title", "Group/$str$/Servers");
def.put("Interface.Group-SubServer.Title-Ungrouped", "Ungrouped Server Menu");
def.put("Interface.Server-Menu.Title", "Server Menu");
def.put("Interface.Server-Menu.Server-Player-Count", "&2$int$ Player(s) Online");
def.put("Interface.Server-Menu.Server-External", "&7External Server");
def.put("Interface.Server-Menu.SubServer-Temporary", "&9Temporary");
def.put("Interface.Server-Menu.SubServer-Offline", "&6Offline");
def.put("Interface.Server-Menu.SubServer-Incompatible", "&4Incompatible with $str$");
def.put("Interface.Server-Menu.SubServer-Unavailable", "&4Unavailable");
def.put("Interface.Server-Menu.SubServer-Disabled", "&4Disabled");
def.put("Interface.Server-Menu.No-Servers", "&c&oThere are No Servers");
def.put("Interface.Server-Menu.Host-Menu", "&b&lView Hosts");
def.put("Interface.Server-Admin.Title", "Server/$str$");
def.put("Interface.Server-Admin.Start", "&aStart SubServer");
def.put("Interface.Server-Admin.Start.Title", "&aStarting SubServer");
def.put("Interface.Server-Admin.Stop", "&cStop SubServer");
def.put("Interface.Server-Admin.Stop.Title", "&cStopping $str$");
def.put("Interface.Server-Admin.Terminate", "&4Terminate SubServer");
def.put("Interface.Server-Admin.Terminate.Title", "&cTerminating $str$");
def.put("Interface.Server-Admin.Command", "&bSend a Command to the Server");
def.put("Interface.Server-Admin.Command.Title", "&eSubServers\\n&6Enter a Command to send via Chat");
def.put("Interface.Server-Admin.Command.Message", "&eSubServers &6&l\\u00BB&e Enter a Command to send via Chat");
def.put("Interface.Server-Admin.Update", "&eUpdate SubServer");
def.put("Interface.Server-Admin.Update.Title", "&eSubServers\\n&6Enter a Server Version to update to");
def.put("Interface.Server-Admin.Update.Message", "&eSubServers &6&l\\u00BB&e Enter a Server Version to update to via Chat");
def.put("Interface.Server-Admin.Plugins", "&bPlugins...");
def.put("Interface.SubServer-Plugin.Title", "Server/$str$/Plugins");
def.put("Interface.SubServer-Plugin.No-Plugins", "&c&oThere are No Plugins Available");
YAMLSection lang = new YAMLSection();
for (String key : def.keySet()) lang.set(key, updated.getMap("Lang", new YAMLSection()).getString(key, def.get(key)));
rewritten.set("Lang", lang);
config.set(rewritten);
config.save();
}
}
}

View File

@ -1,50 +0,0 @@
package net.ME1312.SubServers.Bungee.Library;
/**
* Container Class
*
* @param <V> Item
*/
public class Container<V> {
private V obj;
/**
* Creates a Container
*
* @param item Object to Store
*/
public Container(V item) {
obj = item;
}
/**
* Grabs the Object
*
* @return The Object
*/
public V get() {
return obj;
}
/**
* Overwrite the Object
*
* @param value Object to Store
*/
public void set(V value) {
obj = value;
}
@Override
public boolean equals(Object object) {
if (object instanceof Container) {
if (obj == null || ((Container) object).get() == null) {
return obj == ((Container) object).get();
} else {
return obj.equals(((Container) object).get());
}
} else {
return super.equals(object);
}
}
}

View File

@ -1,47 +0,0 @@
package net.ME1312.SubServers.Bungee.Library;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLValue;
/**
* Extra Data Handler Layout Class
*/
public interface ExtraDataHandler {
/**
* Add an extra value to this Object
*
* @param handle Handle
* @param value Value
*/
void addExtra(String handle, Object value);
/**
* Determine if an extra value exists
*
* @param handle Handle
* @return Value Status
*/
boolean hasExtra(String handle);
/**
* Get an extra value
*
* @param handle Handle
* @return Value
*/
YAMLValue getExtra(String handle);
/**
* Get the extra value section
*
* @return Extra Value Section
*/
YAMLSection getExtra();
/**
* Remove an extra value from this Object
*
* @param handle Handle
*/
void removeExtra(String handle);
}

View File

@ -0,0 +1,135 @@
package net.ME1312.SubServers.Bungee.Library;
import net.ME1312.Galaxi.Library.Directories;
import java.io.File;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.PrimitiveIterator;
import java.util.regex.Pattern;
/**
* File Scanner Base Class
*/
public abstract class FileScanner {
/**
* Scan a Directory
*
* @param dir Directory
* @param whitelist File Whitelist
*/
protected void scan(File dir, String... whitelist) throws IOException {
List<String> files = Directories.search(dir);
if (files.size() <= 0 || whitelist.length <= 0)
return;
boolean csfs = false;
{
long stamp = Math.round(Math.random() * 100000);
File test1 = new File(dir, '.' + stamp + ".ss_fsc");
File test2 = new File(dir, '.' + stamp + ".SS_FSC");
test1.createNewFile();
if (test2.createNewFile()) {
csfs = true;
test2.delete();
}
test1.delete();
}
LinkedHashMap<Pattern, Boolean> rules = new LinkedHashMap<Pattern, Boolean>();
for (String entry : whitelist) {
boolean mode = !entry.startsWith("!");
if (!mode) entry = entry.substring(1);
String pattern;
if (!entry.startsWith("%")) {
if (entry.startsWith("./"))
entry = entry.substring(1);
StringBuilder rule = new StringBuilder();
if (entry.startsWith("**")) {
entry = entry.substring(2);
rule.append("^.*");
} else if (entry.startsWith("/")) {
rule.append("^");
}
boolean greedyEnding = false;
if (entry.endsWith("**")) {
entry = entry.substring(0, entry.length() - 2);
greedyEnding = true;
} else if (entry.endsWith("/")) {
greedyEnding = true;
}
StringBuilder literal = new StringBuilder();
for (PrimitiveIterator.OfInt i = entry.codePoints().iterator(); i.hasNext(); ) {
int c = i.next();
if ((c == '*' || c == '?' || c == '[') && literal.length() > 0) {
rule.append(Pattern.quote(literal.toString()));
literal = new StringBuilder();
}
switch (c) {
case '[':
for (boolean escaped = false; i.hasNext() && (c != ']' || escaped); c = i.next()) {
if (c == '\\') escaped = !escaped;
else escaped = false;
literal.appendCodePoint(c);
}
if (c == ']' && literal.length() > 1) {
literal.appendCodePoint(c);
rule.append(literal.toString());
}
literal = new StringBuilder();
break;
case '*':
rule.append("[^/]+");
break;
case '?':
rule.append("[^/]");
break;
case '\\':
if (i.hasNext()) c = i.next();
default:
literal.appendCodePoint(c);
break;
}
}
if (literal.length() > 0)
rule.append(Pattern.quote(literal.toString()));
if (greedyEnding)
rule.append(".*");
rule.append("$");
pattern = rule.toString();
} else {
pattern = entry.substring(1);
}
if (csfs) rules.put(Pattern.compile(pattern), mode);
else rules.put(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE), mode);
}
for (String file : files) {
boolean act = false;
for (Map.Entry<Pattern, Boolean> rule : rules.entrySet()) {
if (rule.getKey().matcher('/' + file.replace(File.separatorChar, '/')).find()) act = rule.getValue();
}
if (act) act(dir, file);
}
}
/**
* Perform an action on an included file
*
* @param dir Parent Directory
* @param name File Name
*/
protected abstract void act(File dir, String name) throws IOException;
}

View File

@ -1,54 +0,0 @@
# SubCreator Sponge Build Script
# Usage: "bash build.sh <forge version> <sponge version>"
#
#!/usr/bin/env bash
if [ -z "$1" ] || [ -z "$2" ]
then
echo ERROR: No Build Version Supplied
rm -Rf "$0"
exit 1
fi
function __DL() {
if [ -x "$(command -v wget)" ]; then
wget -O "$1" "$2"; return $?
else
curl -o "$1" "$2"; return $?
fi
}
echo Downloading the Minecraft Forge Installer...
__DL "forge-$1-installer.jar" "http://files.minecraftforge.net/maven/net/minecraftforge/forge/$1/forge-$1-installer.jar"; __RETURN=$?
if [ $__RETURN -eq 0 ]; then
echo Installing Minecraft Forge...
java -jar "forge-$1-installer.jar" --installServer; __RETURN=$?
if [ $__RETURN -eq 0 ]; then
echo Cleaning Up...
rm -Rf "forge-$1-installer.jar"
rm -Rf "forge-$1-installer.jar.log"
mv -f "forge-$1-universal.jar" Forge.jar
if [ ! -d "mods" ]; then
mkdir mods
fi
echo Downloading SpongeForge...
__DL mods/Sponge.jar "https://repo.spongepowered.org/maven/org/spongepowered/spongeforge/$2/spongeforge-$2.jar"; __RETURN=$?
if [ $__RETURN -eq 0 ]; then
echo Cleaning Up...
rm -Rf "$0"
exit 0
else
echo ERROR: Failed downloading Sponge. Is MinecraftForge.net down?
rm -Rf "$0"
exit 5
fi
else
echo ERROR: The Installer exited with an error. Please try again
rm -Rf "forge-$1-installer.jar"
rm -Rf "forge-$1-installer.jar.log"
rm -Rf "$0"
exit 4
fi
else
echo ERROR: Failed downloading Forge. Is MinecraftForge.net down?
rm -Rf "$0"
exit 3
fi
exit 2

View File

@ -1,126 +0,0 @@
# 1.0
#
# # If you need help with the configuration or have any questions related to Sponge,
# # join us at the IRC or drop by our forums and leave a post.
#
# # IRC: #sponge @ irc.esper.net ( http://webchat.esper.net/?channel=sponge )
# # Forums: https://forums.spongepowered.org/
#
sponge {
block-tracking {
# If enabled, adds player tracking support for block positions. Note: This should only be disabled if you do not care who caused a block to change.
enabled=true
}
bungeecord {
# If enabled, allows BungeeCord to forward IP address, UUID, and Game Profile to this server
ip-forwarding=true
}
commands {}
debug {
# Dump chunks in the event of a deadlock
dump-chunks-on-deadlock=false
# Dump the heap in the event of a deadlock
dump-heap-on-deadlock=false
# Dump the server thread on deadlock warning
dump-threads-on-warn=false
# Enable Java's thread contention monitoring for thread dumps
thread-contention-monitoring=false
}
entity {
# Number of colliding entities in one spot before logging a warning. Set to 0 to disable
collision-warn-size=200
# Number of entities in one dimension before logging a warning. Set to 0 to disable
count-warn-size=0
# Number of ticks before a painting is respawned on clients when their art is changed
entity-painting-respawn-delay=2
# Number of ticks before the fake player entry of a human is removed from the tab list (range of 0 to 100 ticks).
human-player-list-remove-delay=10
# Controls the time in ticks for when an item despawns.
item-despawn-rate=6000
# Max size of an entity's bounding box before removing it. Set to 0 to disable
max-bounding-box-size=1000
# Square of the max speed of an entity before removing it. Set to 0 to disable
max-speed=100
}
entity-activation-range {
ambient-activation-range=32
aquatic-activation-range=32
creature-activation-range=32
minecraft {
creature {
entityhorse=true
pig=true
sheep=true
}
enabled=true
misc {
item=true
minecartchest=true
}
monster {
guardian=true
}
}
misc-activation-range=16
monster-activation-range=32
}
general {
# Forces Chunk Loading on provide requests (speedup for mods that don't check if a chunk is loaded)
chunk-load-override=false
# Disable warning messages to server admins
disable-warnings=false
}
logging {
# Log when blocks are broken
block-break=false
# Log when blocks are modified
block-modify=false
# Log when blocks are placed
block-place=false
# Log when blocks are populated in a chunk
block-populate=false
# Log when blocks are placed by players and tracked
block-tracking=false
# Log when chunks are loaded
chunk-load=false
# Log when chunks are unloaded
chunk-unload=false
# Whether to log entity collision/count checks
entity-collision-checks=false
# Log when living entities are destroyed
entity-death=false
# Log when living entities are despawned
entity-despawn=false
# Log when living entities are spawned
entity-spawn=false
# Whether to log entity removals due to speed
entity-speed-removal=false
# Add stack traces to dev logging
log-stacktraces=false
}
modules {
bungeecord=true
entity-activation-range=true
timings=true
}
# Configuration options related to the Sql service, including connection aliases etc
sql {}
timings {
enabled=true
hidden-config-entries=[
"sponge.sql"
]
history-interval=300
history-length=3600
server-name-privacy=false
verbose=false
}
world {
# Lava behaves like vanilla water when source block is removed
flowing-lava-decay=false
# Vanilla water source behavior - is infinite
infinite-water-source=false
}
}

View File

@ -1,35 +0,0 @@
#Minecraft server properties
generator-settings=
op-permission-level=4
allow-nether=true
resource-pack-hash=
level-name=world
enable-query=true
allow-flight=false
announce-player-achievements=false
server-port=
max-world-size=29999984
level-type=DEFAULT
enable-rcon=false
level-seed=
force-gamemode=false
server-ip=
network-compression-threshold=-1
max-build-height=256
spawn-npcs=true
white-list=false
spawn-animals=true
snooper-enabled=true
online-mode=false
resource-pack=
pvp=true
difficulty=1
enable-command-block=true
gamemode=0
player-idle-timeout=0
max-players=20
max-tick-time=60000
spawn-monsters=true
generate-structures=true
view-distance=10
motd=Some SubServer

View File

@ -1,11 +0,0 @@
Version: '2.13a/rv3+'
Template:
Enabled: true
Icon: 'anvil'
Build:
Server-Type: 'Forge'
Use-Cache: false
Shell-Location: 'build.sh'
Permission: '+x'
Settings:
Executable: 'java -Xmx2048M -jar Forge.jar'

View File

@ -1,68 +0,0 @@
# SubCreator Spigot Build Script
# Usage: "bash build.sh <version> [cache]"
#
#!/usr/bin/env bash
if [ -z "$1" ]
then
echo ERROR: No Build Version Supplied
rm -Rf "$0"
exit 1
fi
function __DL() {
if [ -x "$(command -v wget)" ]; then
wget -O "$1" "$2"; return $?
else
curl -o "$1" "$2"; return $?
fi
}
if [ -z "$2" ] || [ ! -f "$2/Spigot-$1.jar" ]; then
echo Downloading Buildtools...
__DL Buildtools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar; __RETURN=$?
if [ $__RETURN -eq 0 ]; then
if [ -d "Buildtools" ]; then
rm -Rf Buildtools
fi
mkdir Buildtools
cd "Buildtools"
echo Launching Buildtools
if [ ! -z "$2" ] && [ -d "$2" ]; then
export __HOME="$HOME"
export HOME="$2"
fi
export MAVEN_OPTS="-Xms2G"
java -Xms2G -jar ../Buildtools.jar --rev "$1"; __RETURN=$?
if [ ! -z "$2" ] && [ ! -z "$__HOME" ] && [ "$2" == "$HOME" ]; then
export HOME="$__HOME"
fi
cd ../
if [ $__RETURN -eq 0 ]; then
echo Copying Finished Jar...
if [ ! -z "$2" ] && [ -d "$2" ]; then
cp Buildtools/spigot-*.jar "$2/Spigot-$1.jar"
fi
cp Buildtools/spigot-*.jar Spigot.jar
echo Cleaning Up...
rm -Rf Buildtools.jar
rm -Rf Buildtools
rm -Rf "$0"
exit 0
else
echo ERROR: Buildtools exited with an error. Please try again
rm -Rf Buildtools.jar
rm -Rf Buildtools
rm -Rf "$0"
exit 4
fi
else
echo ERROR: Failed downloading Buildtools. Is SpigotMC.org down?
rm -Rf "$0"
exit 3
fi
else
echo Copying Cached Jar...
cp "$2/Spigot-$1.jar" Spigot.jar
echo Cleaning Up...
rm -Rf "$0"
exit 0
fi
exit 2

View File

@ -1,35 +0,0 @@
#Minecraft server properties
generator-settings=
op-permission-level=4
allow-nether=true
resource-pack-hash=
level-name=world
enable-query=true
allow-flight=false
announce-player-achievements=false
server-port=
max-world-size=29999984
level-type=DEFAULT
enable-rcon=false
level-seed=
force-gamemode=false
server-ip=
network-compression-threshold=-1
max-build-height=256
spawn-npcs=true
white-list=false
spawn-animals=true
snooper-enabled=true
online-mode=false
resource-pack=
pvp=true
difficulty=1
enable-command-block=true
gamemode=0
player-idle-timeout=0
max-players=20
max-tick-time=60000
spawn-monsters=true
generate-structures=true
view-distance=10
motd=Some SubServer

View File

@ -1,134 +0,0 @@
# This is the main configuration file for Spigot.
# As you can see, there's tons to configure. Some options may impact gameplay, so use
# with caution, and make sure you know what each option does before configuring.
# For a reference for any variable inside this file, check out the Spigot wiki at
# http://www.spigotmc.org/wiki/spigot-configuration/
#
# If you need help with the configuration or have any questions related to Spigot,
# join us at the IRC or drop by our forums and leave a post.
#
# IRC: #spigot @ irc.spi.gt ( http://www.spigotmc.org/pages/irc/ )
# Forums: http://www.spigotmc.org/
config-version: 8
settings:
debug: false
save-user-cache-on-stop-only: false
bungeecord: true
late-bind: false
sample-count: 12
player-shuffle: 0
filter-creative-items: true
user-cache-size: 1000
int-cache-limit: 1024
moved-wrongly-threshold: 0.0625
moved-too-quickly-threshold: 100.0
timeout-time: 60
restart-on-crash: false
restart-script: ./start.sh
netty-threads: 4
attribute:
maxHealth:
max: 2048.0
movementSpeed:
max: 2048.0
attackDamage:
max: 2048.0
commands:
tab-complete: 0
log: true
spam-exclusions:
- /skill
silent-commandblock-console: true
replace-commands:
- setblock
- summon
- testforblock
- tellraw
messages:
whitelist: You are not whitelisted on this server!
unknown-command: Unknown command. Type "/help" for help.
server-full: The server is full!
outdated-client: Outdated client! Please use {0}
outdated-server: Outdated server! I'm still on {0}
restart: Server is restarting
stats:
disable-saving: false
forced-stats: {}
world-settings:
default:
verbose: true
wither-spawn-sound-radius: 0
view-distance: 10
item-despawn-rate: 6000
merge-radius:
item: 2.5
exp: 3.0
arrow-despawn-rate: 1200
enable-zombie-pigmen-portal-spawns: true
zombie-aggressive-towards-villager: true
hanging-tick-frequency: 100
max-bulk-chunks: 10
max-entity-collisions: 8
random-light-updates: false
save-structure-info: true
mob-spawn-range: 4
anti-xray:
enabled: true
engine-mode: 1
hide-blocks:
- 14
- 15
- 16
- 21
- 48
- 49
- 54
- 56
- 73
- 74
- 82
- 129
- 130
replace-blocks:
- 1
- 5
dragon-death-sound-radius: 0
seed-village: 10387312
seed-feature: 14357617
hunger:
walk-exhaustion: 0.2
sprint-exhaustion: 0.8
combat-exhaustion: 0.3
regen-exhaustion: 3.0
max-tnt-per-tick: 100
max-tick-time:
tile: 50
entity: 50
entity-activation-range:
animals: 32
monsters: 32
misc: 16
entity-tracking-range:
players: 48
animals: 48
monsters: 48
misc: 32
other: 64
ticks-per:
hopper-transfer: 8
hopper-check: 8
hopper-amount: 1
growth:
cactus-modifier: 100
cane-modifier: 100
melon-modifier: 100
mushroom-modifier: 100
pumpkin-modifier: 100
sapling-modifier: 100
wheat-modifier: 100
netherwart-modifier: 100
nerf-spawner-mobs: false
chunks-per-tick: 650
clear-tick-list: false

View File

@ -1,10 +0,0 @@
Version: '2.13a/rv2+'
Template:
Enabled: true
Icon: 'lava_bucket'
Build:
Server-Type: 'Spigot'
Shell-Location: 'build.sh'
Permission: '+x'
Settings:
Executable: 'java -Xmx1024M -Dorg.bukkit.craftbukkit.libs.jline.terminal=unix -Djansi.passthrough=true -jar Spigot.jar'

View File

@ -1,29 +0,0 @@
# SubCreator Sponge Build Script
# Usage: "bash build.sh <sponge version>"
#
#!/usr/bin/env bash
if [ -z "$1" ]
then
echo ERROR: No Build Version Supplied
rm -Rf "$0"
exit 1
fi
function __DL() {
if [ -x "$(command -v wget)" ]; then
wget -O "$1" "$2"; return $?
else
curl -o "$1" "$2"; return $?
fi
}
echo Downloading SpongeVanilla...
__DL Sponge.jar "https://repo.spongepowered.org/maven/org/spongepowered/spongevanilla/$1/spongevanilla-$1.jar"; __RETURN=$?
if [ $__RETURN -eq 0 ]; then
echo Cleaning Up...
rm -Rf "$0"
exit 0
else
echo ERROR: Failed downloading Sponge. Is MinecraftForge.net down?
rm -Rf "$0"
exit 3
fi
exit 2

View File

@ -1,126 +0,0 @@
# 1.0
#
# # If you need help with the configuration or have any questions related to Sponge,
# # join us at the IRC or drop by our forums and leave a post.
#
# # IRC: #sponge @ irc.esper.net ( http://webchat.esper.net/?channel=sponge )
# # Forums: https://forums.spongepowered.org/
#
sponge {
block-tracking {
# If enabled, adds player tracking support for block positions. Note: This should only be disabled if you do not care who caused a block to change.
enabled=true
}
bungeecord {
# If enabled, allows BungeeCord to forward IP address, UUID, and Game Profile to this server
ip-forwarding=true
}
commands {}
debug {
# Dump chunks in the event of a deadlock
dump-chunks-on-deadlock=false
# Dump the heap in the event of a deadlock
dump-heap-on-deadlock=false
# Dump the server thread on deadlock warning
dump-threads-on-warn=false
# Enable Java's thread contention monitoring for thread dumps
thread-contention-monitoring=false
}
entity {
# Number of colliding entities in one spot before logging a warning. Set to 0 to disable
collision-warn-size=200
# Number of entities in one dimension before logging a warning. Set to 0 to disable
count-warn-size=0
# Number of ticks before a painting is respawned on clients when their art is changed
entity-painting-respawn-delay=2
# Number of ticks before the fake player entry of a human is removed from the tab list (range of 0 to 100 ticks).
human-player-list-remove-delay=10
# Controls the time in ticks for when an item despawns.
item-despawn-rate=6000
# Max size of an entity's bounding box before removing it. Set to 0 to disable
max-bounding-box-size=1000
# Square of the max speed of an entity before removing it. Set to 0 to disable
max-speed=100
}
entity-activation-range {
ambient-activation-range=32
aquatic-activation-range=32
creature-activation-range=32
minecraft {
creature {
entityhorse=true
pig=true
sheep=true
}
enabled=true
misc {
item=true
minecartchest=true
}
monster {
guardian=true
}
}
misc-activation-range=16
monster-activation-range=32
}
general {
# Forces Chunk Loading on provide requests (speedup for mods that don't check if a chunk is loaded)
chunk-load-override=false
# Disable warning messages to server admins
disable-warnings=false
}
logging {
# Log when blocks are broken
block-break=false
# Log when blocks are modified
block-modify=false
# Log when blocks are placed
block-place=false
# Log when blocks are populated in a chunk
block-populate=false
# Log when blocks are placed by players and tracked
block-tracking=false
# Log when chunks are loaded
chunk-load=false
# Log when chunks are unloaded
chunk-unload=false
# Whether to log entity collision/count checks
entity-collision-checks=false
# Log when living entities are destroyed
entity-death=false
# Log when living entities are despawned
entity-despawn=false
# Log when living entities are spawned
entity-spawn=false
# Whether to log entity removals due to speed
entity-speed-removal=false
# Add stack traces to dev logging
log-stacktraces=false
}
modules {
bungeecord=true
entity-activation-range=true
timings=true
}
# Configuration options related to the Sql service, including connection aliases etc
sql {}
timings {
enabled=true
hidden-config-entries=[
"sponge.sql"
]
history-interval=300
history-length=3600
server-name-privacy=false
verbose=false
}
world {
# Lava behaves like vanilla water when source block is removed
flowing-lava-decay=false
# Vanilla water source behavior - is infinite
infinite-water-source=false
}
}

View File

@ -1,35 +0,0 @@
#Minecraft server properties
generator-settings=
op-permission-level=4
allow-nether=true
resource-pack-hash=
level-name=world
enable-query=true
allow-flight=false
announce-player-achievements=false
server-port=
max-world-size=29999984
level-type=DEFAULT
enable-rcon=false
level-seed=
force-gamemode=false
server-ip=
network-compression-threshold=-1
max-build-height=256
spawn-npcs=true
white-list=false
spawn-animals=true
snooper-enabled=true
online-mode=false
resource-pack=
pvp=true
difficulty=1
enable-command-block=true
gamemode=0
player-idle-timeout=0
max-players=20
max-tick-time=60000
spawn-monsters=true
generate-structures=true
view-distance=10
motd=Some SubServer

View File

@ -1,11 +0,0 @@
Version: '2.13a/rv3+'
Template:
Enabled: true
Icon: 'sponge'
Build:
Server-Type: 'Sponge'
Use-Cache: false
Shell-Location: 'build.sh'
Permission: '+x'
Settings:
Executable: 'java -Xmx1024M -jar Sponge.jar'

View File

@ -1,59 +0,0 @@
# SubCreator Vanilla Build Script
# Usage: "bash build.sh <version> [cache]"
#
#!/usr/bin/env bash
if [ -z "$1" ]
then
echo ERROR: No Build Version Supplied
rm -Rf "$0"
exit 1
fi
function __DL() {
if [ -x "$(command -v wget)" ]; then
wget -O "$1" "$2"; return $?
else
curl -o "$1" "$2"; return $?
fi
}
if [ -z "$2" ] || [ ! -f "$2/Vanilla-$1.jar" ]; then
if [ -d "VanillaCord" ]; then
rm -Rf VanillaCord
fi
mkdir VanillaCord
echo Downloading the VanillaCord Launcher...
__DL VanillaCord/VanillaCord.jar https://src.me1312.net/jenkins/job/VanillaCord/job/master/lastSuccessfulBuild/artifact/artifacts/VanillaCord.jar; __RETURN=$?
if [ $__RETURN -eq 0 ]; then
cd VanillaCord
echo Launching VanillaCord
java -jar VanillaCord.jar "$1"; __RETURN=$?;
if [ $__RETURN -eq 0 ]; then
echo Copying Finished Jar...
cd ../
if [ ! -z "$2" ] && [ -d "$2" ]; then
cp "VanillaCord/out/$1-bungee.jar" "$2/Vanilla-$1.jar"
fi
cp "VanillaCord/out/$1-bungee.jar" Vanilla.jar
echo Cleaning Up...
rm -Rf VanillaCord
rm -Rf "$0"
exit 0
else
echo ERROR: VanillaCord exited with an error. Please try again
rm -Rf VanillaCord
rm -Rf "$0"
exit 4
fi
else
echo ERROR: Failed Downloading Patcher. Is Github.com down?
rm -Rf VanillaCord
rm -Rf "$0"
exit 3
fi
else
echo Copying Cached Jar...
cp "$2/Vanilla-$1.jar" Vanilla.jar
echo Cleaning Up...
rm -Rf "$0"
exit 0
fi
exit 2

View File

@ -1,35 +0,0 @@
#Minecraft server properties
generator-settings=
op-permission-level=4
allow-nether=true
resource-pack-hash=
level-name=world
enable-query=true
allow-flight=false
announce-player-achievements=false
server-port=
max-world-size=29999984
level-type=DEFAULT
enable-rcon=false
level-seed=
force-gamemode=false
server-ip=
network-compression-threshold=-1
max-build-height=256
spawn-npcs=true
white-list=false
spawn-animals=true
snooper-enabled=true
online-mode=false
resource-pack=
pvp=true
difficulty=1
enable-command-block=true
gamemode=0
player-idle-timeout=0
max-players=20
max-tick-time=60000
spawn-monsters=true
generate-structures=true
view-distance=10
motd=Some SubServer

View File

@ -1,10 +0,0 @@
Version: '2.13a/rv3+'
Template:
Enabled: true
Icon: 'bukkit:grass'
Build:
Server-Type: 'Vanilla'
Shell-Location: 'build.sh'
Permission: '+x'
Settings:
Executable: 'java -Xmx1024M -jar Vanilla.jar nogui'

View File

@ -1,36 +0,0 @@
Settings:
Version: '2.11.2a+'
Log-Creator: true
Override-Bungee-Commands: true
SubData:
Address: '127.0.0.1:4391'
Password: 'default'
Encryption: 'AES'
Allowed-Connections: []
Hosts:
'~':
Enabled: true
Display: 'Default'
Driver: 'BUILT-IN'
Address: '127.0.0.1'
Directory: './SubServers/Servers'
Git-Bash: '%ProgramFiles%\Git'
Servers:
'Example':
Enabled: false
Display: ''
Host: '~'
Group: []
Port: 25567
Motd: '&aThis is a SubServer'
Log: true
Directory: './Example'
Executable: 'java -Djline.terminal=jline.UnsupportedTerminal -jar Spigot.jar'
Stop-Command: 'stop'
Stop-Action: 'NONE'
Run-On-Launch: false
Restricted: false
Incompatible: []
Hidden: false

View File

@ -1,163 +0,0 @@
Version: '2.13.1a+'
Lang:
'Bungee.Feature.Return': '&6Returning to $str$: &r$msg$'
'Bungee.Server.Current': '&6You are currently connected to $str$'
'Bungee.Server.Available': '&6You may connect to the following servers at this time:'
'Bungee.Server.List': '&6$str$'
'Bungee.Server.Hover': '$int$ player(s)\n&oClick to connect to the server'
'Bungee.Server.Divider': '&6, '
'Bungee.Server.Invalid': '&cThe specified server does not exist.'
'Bungee.List.Format': '&a[$str$] &e($int$)&r: '
'Bungee.List.List': '&f$str$'
'Bungee.List.Divider': '&f, '
'Bungee.List.Total': 'Total players online: $int$'
'Command.Generic.Player-Only': '&cSubServers &4&l\u00BB&c Console cannot run this command'
'Command.Generic.Console-Only': '&cSubServers &4&l\u00BB&c This command is for console use only'
'Command.Generic.Usage': '&7SubServers &8&l\u00BB&7 Usage: &f$str$'
'Command.Generic.Exception': '&cSubServers &4&l\u00BB&c An unexpected exception has occurred while parsing this command'
'Command.Generic.Invalid-Subcommand': '&cSubServers &4&l\u00BB&c Unknown sub-command: $str$'
'Command.Generic.Invalid-Permission': '&cSubServers &4&l\u00BB&c You need &4&n$str$&c to use this command'
'Command.Generic.Unknown-Proxy': '&cSubServers &4&l\u00BB&c There is no proxy with that name'
'Command.Generic.Unknown-Host': '&cSubServers &4&l\u00BB&c There is no host with that name'
'Command.Generic.Unknown-Group': '&cSubServers &4&l\u00BB&c There is no group with that name'
'Command.Generic.Unknown-Server': '&cSubServers &4&l\u00BB&c There is no server with that name'
'Command.Generic.Unknown-SubServer': '&cSubServers &4&l\u00BB&c There is no subserver with that name'
'Command.Help.Header': '&7SubServers &8&l\u00BB&7 Command Help:'
'Command.Help.Help': ' &7Help:&f $str$'
'Command.Help.List': ' &7List:&f $str$'
'Command.Help.Version': ' &7Version:&f $str$'
'Command.Help.Info': ' &7Info:&f $str$'
'Command.Help.Terminate': ' &7Teleport to Server:&f $str$'
'Command.Help.Host.Create': ' &7Create Server:&f $str$'
'Command.Help.SubServer.Start': ' &7Start Server:&f $str$'
'Command.Help.SubServer.Stop': ' &7Stop Server:&f $str$'
'Command.Help.SubServer.Terminate': ' &7Terminate Server:&f $str$'
'Command.Help.SubServer.Command': ' &7Command Server:&f $str$'
'Command.Version': '&7SubServers &8&l\u00BB&7 These are the platforms and versions that are running &f$str$&7:'
'Command.Version.Outdated': '&7$name$ &f$str$ &7is available. You are $int$ version(s) behind.'
'Command.Version.Latest': '&7You are on the latest version.'
'Command.List.Group-Header': '&7SubServers &8&l\u00BB&7 Group/Server List:'
'Command.List.Host-Header': '&7SubServers &8&l\u00BB&7 Host/SubServer List:'
'Command.List.Server-Header': '&7SubServers &8&l\u00BB&7 Server List:'
'Command.List.Proxy-Header': '&7SubServers &8&l\u00BB&7 Proxy List:'
'Command.List.Header': '&7: '
'Command.List.Divider': '&7, '
'Command.List.Empty': '&7(none)'
'Command.Info': '&7SubServers &8&l\u00BB&7 Info on $str$&7: &r'
'Command.Info.Unknown': '&cSubServers &4&l\u00BB&c There is no object with that name'
'Command.Info.Unknown-Type': '&cSubServers &4&l\u00BB&c There is no object type with that name'
'Command.Info.Unknown-Proxy': '&cSubServers &4&l\u00BB&c There is no proxy with that name'
'Command.Info.Unknown-Host': '&cSubServers &4&l\u00BB&c There is no host with that name'
'Command.Info.Unknown-Group': '&cSubServers &4&l\u00BB&c There is no group with that name'
'Command.Info.Unknown-Server': '&cSubServers &4&l\u00BB&c There is no server with that name'
'Command.Info.Format': ' -> &7$str$&7: &r'
'Command.Info.List': ' - '
'Command.Start': '&aSubServers &2&l\u00BB&a Starting SubServer'
'Command.Start.Unknown': '&cSubServers &4&l\u00BB&c There is no Server with that name'
'Command.Start.Invalid': '&cSubServers &4&l\u00BB&c That Server is not a SubServer'
'Command.Start.Host-Unavailable': '&cSubServers &4&l\u00BB&c That SubServer\u0027s Host is not available'
'Command.Start.Host-Disabled': '&cSubServers &4&l\u00BB&c That SubServer\u0027s Host is not enabled'
'Command.Start.Server-Disabled': '&cSubServers &4&l\u00BB&c That SubServer is not enabled'
'Command.Start.Server-Incompatible': '&cSubServers &4&l\u00BB&c That SubServer cannot start while these server(s) are running: &4$str$'
'Command.Start.Running': '&cSubServers &4&l\u00BB&c That SubServer is already running'
'Command.Stop': '&aSubServers &2&l\u00BB&a Stopping SubServer'
'Command.Stop.Unknown': '&cSubServers &4&l\u00BB&c There is no Server with that name'
'Command.Stop.Invalid': '&cSubServers &4&l\u00BB&c That Server is not a SubServer'
'Command.Stop.Not-Running': '&cSubServers &4&l\u00BB&c That SubServer is not running'
'Command.Terminate': '&aSubServers &2&l\u00BB&a Stopping SubServer'
'Command.Terminate.Unknown': '&cSubServers &4&l\u00BB&c There is no Server with that name'
'Command.Terminate.Invalid': '&cSubServers &4&l\u00BB&c That Server is not a SubServer'
'Command.Terminate.Not-Running': '&cSubServers &4&l\u00BB&c That SubServer is not running'
'Command.Command': '&aSubServers &2&l\u00BB&a Sending command to SubServer'
'Command.Command.Unknown': '&cSubServers &4&l\u00BB&c There is no Server with that name'
'Command.Command.Invalid': '&cSubServers &4&l\u00BB&c That Server is not a SubServer'
'Command.Command.Not-Running': '&cSubServers &4&l\u00BB&c That SubServer is not running'
'Command.Creator': '&aSubServers &2&l\u00BB&a Creating SubServer'
'Command.Creator.Exists': '&cSubServers &4&l\u00BB&c There is already a SubServer with that name'
'Command.Creator.Unknown-Host': '&cSubServers &4&l\u00BB&c There is no Host with that name'
'Command.Creator.Host-Unavailable': '&cSubServers &4&l\u00BB&c That Host is not available'
'Command.Creator.Host-Disabled': '&cSubServers &4&l\u00BB&c That Host is not enabled'
'Command.Creator.Unknown-Template': '&cSubServers &4&l\u00BB&c There is no Template with that name'
'Command.Creator.Template-Disabled': '&cSubServers &4&l\u00BB&c That Template is not enabled'
'Command.Creator.Invalid-Version': '&cSubServers &4&l\u00BB&c SubCreator cannot create servers before Minecraft 1.8'
'Command.Creator.Invalid-Port': '&cSubServers &4&l\u00BB&c Invalid Port Number'
'Interface.Generic.Back': '&cBack'
'Interface.Generic.Back-Arrow': '&e&l<--'
'Interface.Generic.Next-Arrow': '&e&l-->'
'Interface.Generic.Undo': '&6Undo'
'Interface.Generic.Downloading': '&7SubServers &8&l\u00BB&7 Downloading:&f $str$'
'Interface.Generic.Downloading.Title': 'Downloading...'
'Interface.Generic.Downloading.Title-Color': '&b'
'Interface.Generic.Downloading.Title-Color-Alt': '&3'
'Interface.Generic.Downloading.Response': '&eWaiting for response'
'Interface.Generic.Invalid-Permission': '&4You need &n$str$'
'Interface.Proxy-Menu.Proxy-Player-Count': '&2$int$ Player(s) Online'
'Interface.Proxy-Menu.Proxy-Master': '&8Master Proxy'
'Interface.Proxy-Menu.Proxy-SubData': '&9SubData Only'
'Interface.Proxy-Menu.Proxy-Redis': '&7Redis Only'
'Interface.Proxy-Menu.Proxy-Disconnected': '&4Disconnected'
'Interface.Host-Menu.Title': 'Host Menu'
'Interface.Host-Menu.Host-Unavailable': '&4Unavailable'
'Interface.Host-Menu.Host-Disabled': '&4Disabled'
'Interface.Host-Menu.Host-Server-Count': '&9$int$ Server(s)'
'Interface.Host-Menu.No-Hosts': '&c&oThere are No Hosts'
'Interface.Host-Menu.Group-Menu': '&6&lView Servers by Group'
'Interface.Host-Menu.Server-Menu': '&a&lView Servers'
'Interface.Host-Admin.Title': 'Host/$str$'
'Interface.Host-Admin.Creator': '&eCreate a SubServer'
'Interface.Host-Admin.SubServers': '&aView SubServers'
'Interface.Host-Admin.Plugins': '&bPlugins...'
'Interface.Host-Creator.Title': 'Host/$str$/Create'
'Interface.Host-Creator.Edit-Name': 'Change Name'
'Interface.Host-Creator.Edit-Name.Title': '&eSubCreator\n&6Enter a Name for this Server'
'Interface.Host-Creator.Edit-Name.Message': '&eSubCreator &6&l\u00BB&e Enter a Name for this Server via Chat'
'Interface.Host-Creator.Edit-Name.Exists': '&cSubCreator &4&l\u00BB&c There is already a SubServer with that name'
'Interface.Host-Creator.Edit-Name.Exists-Title': '&eSubCreator\n&cThere is already a SubServer with that name'
'Interface.Host-Creator.Edit-Name.Invalid': '&cSubCreator &4&l\u00BB&c Invalid Server Name'
'Interface.Host-Creator.Edit-Name.Invalid-Title': '&eSubCreator\n&cInvalid Server Name'
'Interface.Host-Creator.Edit-Template': 'Change Server Template'
'Interface.Host-Creator.Edit-Template.Title': 'Host/$str$/Templates'
'Interface.Host-Creator.Edit-Template.No-Templates': '&c&oThere are No Templates'
'Interface.Host-Creator.Edit-Version': 'Change Server Version'
'Interface.Host-Creator.Edit-Version.Title': '&eSubCreator\n&6Enter a Server Version'
'Interface.Host-Creator.Edit-Version.Message': '&eSubCreator &6&l\u00BB&e Enter a Server Version via Chat'
'Interface.Host-Creator.Edit-Version.Unavailable': '&cSubCreator &4&l\u00BB&c SubCreator cannot create servers before Minecraft 1.8'
'Interface.Host-Creator.Edit-Version.Unavailable-Title': '&eSubCreator\n&cCannot create servers before MC 1.8'
'Interface.Host-Creator.Edit-Port': 'Change Server Port'
'Interface.Host-Creator.Edit-Port.Title': '&eSubCreator\n&6Enter a Port Number'
'Interface.Host-Creator.Edit-Port.Message': '&eSubCreator &6&l\u00BB&e Enter a Port Number via Chat'
'Interface.Host-Creator.Edit-Port.Invalid': '&cSubCreator &4&l\u00BB&c Invalid Port Number'
'Interface.Host-Creator.Edit-Port.Invalid-Title': '&eSubCreator\n&cInvalid Port Number'
'Interface.Host-Creator.Submit': '&eCreate SubServer'
'Interface.Host-Creator.Form-Incomplete': '&4Buttons above must be green'
'Interface.Host-Plugin.Title': 'Host/$str$/Plugins'
'Interface.Host-Plugin.No-Plugins': '&c&oThere are No Plugins Available'
'Interface.Host-SubServer.Title': 'Host/$str$/SubServers'
'Interface.Group-Menu.Title': 'Group Menu'
'Interface.Group-Menu.Group-Server-Count': '&9$int$ Server(s)'
'Interface.Group-Menu.No-Groups': '&c&oThere are No Groups'
'Interface.Group-Menu.Server-Menu': '&a&lView All Servers'
'Interface.Group-SubServer.Title': 'Group/$str$/Servers'
'Interface.Server-Menu.Title': 'Server Menu'
'Interface.Server-Menu.Server-Player-Count': '&2$int$ Player(s) Online'
'Interface.Server-Menu.Server-External': '&7External Server'
'Interface.Server-Menu.SubServer-Temporary': '&9Temporary'
'Interface.Server-Menu.SubServer-Offline': '&6Offline'
'Interface.Server-Menu.SubServer-Incompatible': '&4Incompatible with $str$'
'Interface.Server-Menu.SubServer-Disabled': '&4Disabled'
'Interface.Server-Menu.SubServer-Invalid': '&4Cannot be managed by SubServers'
'Interface.Server-Menu.No-Servers': '&c&oThere are No Servers'
'Interface.Server-Menu.Host-Menu': '&b&lView Hosts'
'Interface.SubServer-Admin.Title': 'SubServer/$str$'
'Interface.SubServer-Admin.Start': '&aStart SubServer'
'Interface.SubServer-Admin.Start.Title': '&aStarting SubServer'
'Interface.SubServer-Admin.Stop': '&cStop SubServer'
'Interface.SubServer-Admin.Stop.Title': '&cStopping $str$'
'Interface.SubServer-Admin.Terminate': '&4Terminate SubServer'
'Interface.SubServer-Admin.Terminate.Title': '&cTerminating $str$'
'Interface.SubServer-Admin.Command': '&eSend a Command to the SubServer'
'Interface.SubServer-Admin.Command.Title': '&eSubServers\n&6Enter a Command to send via Chat'
'Interface.SubServer-Admin.Command.Message': '&eSubServers &6&l\u00BB&e Enter a Command to send via Chat'
'Interface.SubServer-Admin.Plugins': '&bPlugins...'
'Interface.SubServer-Plugin.Title': 'SubServer/$str$/Plugins'
'Interface.SubServer-Plugin.No-Plugins': '&c&oThere are No Plugins Available'

View File

@ -1,457 +0,0 @@
package net.ME1312.SubServers.Bungee.Library;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import net.ME1312.SubServers.Bungee.SubPlugin;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.GZIPOutputStream;
/**
* bStats collects some data for plugin authors.
*
* Check out https://bStats.org/ to learn more about bStats!
*/
public class Metrics {
static {
// You can use the property to disable the check in your test environment
if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) {
// Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D
final String defaultPackage = new String(
new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'n', 'g', 'e', 'e', 'c', 'o', 'r', 'd'});
final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
// We want to make sure nobody just copy & pastes the example and use the wrong package names
if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) {
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
}
}
}
// The version of this bStats class
public static final int B_STATS_VERSION = 1;
// The url to which the data is sent
private static final String URL = "https://bStats.org/submitData/bungeecord";
// The plugin
private final SubPlugin plugin;
// Is bStats enabled on this server?
private boolean enabled;
// The uuid of the server
private String serverUUID;
// Should failed requests be logged?
private boolean logFailedRequests = false;
// A list with all known metrics class objects including this one
private static final List<Object> knownMetricsInstances = new ArrayList<>();
public Metrics(SubPlugin plugin) {
this.plugin = plugin;
try {
loadConfig();
} catch (IOException e) {
// Failed to load configuration
plugin.getLogger().log(Level.WARNING, "Failed to load bStats config!", e);
return;
}
// We are not allowed to send data about this server :(
if (!enabled) {
return;
}
Class<?> usedMetricsClass = getFirstBStatsClass();
if (usedMetricsClass == null) {
// Failed to get first metrics class
return;
}
if (usedMetricsClass == getClass()) {
// We are the first! :)
linkMetrics(this);
startSubmitting();
} else {
// We aren't the first so we link to the first metrics class
try {
usedMetricsClass.getMethod("linkMetrics", Object.class).invoke(null,this);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
if (logFailedRequests) {
plugin.getLogger().log(Level.WARNING, "Failed to link to first metrics class " + usedMetricsClass.getName() + "!", e);
}
}
}
}
/**
* Links an other metrics class with this class.
* This method is called using Reflection.
*
* @param metrics An object of the metrics class to link.
*/
public static void linkMetrics(Object metrics) {
knownMetricsInstances.add(metrics);
}
/**
* Gets the plugin specific data.
* This method is called using Reflection.
*
* @return The plugin specific data.
*/
public JsonObject getPluginData() {
JsonObject data = new JsonObject();
String pluginName = "SubServers 2";
String pluginVersion = plugin.version.toString();
data.addProperty("pluginName", pluginName);
data.addProperty("pluginVersion", pluginVersion);
JsonArray customCharts = new JsonArray();
customCharts.add(new SingleLineChart("managed_hosts", new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return plugin.api.getHosts().size();
}
}).getRequestJsonObject(plugin.getLogger(), logFailedRequests));
customCharts.add(new SingleLineChart("subdata_connected", new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return (plugin.subdata != null)?plugin.subdata.getClients().size():0;
}
}).getRequestJsonObject(plugin.getLogger(), logFailedRequests));
data.add("customCharts", customCharts);
return data;
}
private void startSubmitting() {
new Timer().schedule( new TimerTask() {
@Override
public void run() {
// The data collection is async, as well as sending the data
// Bungeecord does not have a main thread, everything is async
submitData();
}
}, TimeUnit.MINUTES.toMillis(2), TimeUnit.MINUTES.toMillis(30));
// Submit the data every 30 minutes, first time after 2 minutes to give other plugins enough time to start
// WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
// WARNING: Just don't do it!
}
/**
* Gets the server specific data.
*
* @return The server specific data.
*/
private JsonObject getServerData() {
// Minecraft specific data
int playerAmount = plugin.getOnlineCount();
playerAmount = playerAmount > 500 ? 500 : playerAmount;
int onlineMode = plugin.getConfig().isOnlineMode() ? 1 : 0;
String bungeecordVersion = (plugin.getName().equals("SubServers Platform"))?"SubServers-Bungee-Patched":plugin.getVersion();
int managedServers = plugin.getServers().size();
// OS/Java specific data
String javaVersion = System.getProperty("java.version");
String osName = System.getProperty("os.name");
String osArch = System.getProperty("os.arch");
String osVersion = System.getProperty("os.version");
int coreCount = Runtime.getRuntime().availableProcessors();
JsonObject data = new JsonObject();
data.addProperty("serverUUID", serverUUID);
data.addProperty("playerAmount", playerAmount);
data.addProperty("managedServers", managedServers);
data.addProperty("onlineMode", onlineMode);
data.addProperty("bungeecordVersion", bungeecordVersion);
data.addProperty("javaVersion", javaVersion);
data.addProperty("osName", osName);
data.addProperty("osArch", osArch);
data.addProperty("osVersion", osVersion);
data.addProperty("coreCount", coreCount);
return data;
}
/**
* Collects the data and sends it afterwards.
*/
private void submitData() {
final JsonObject data = getServerData();
final JsonArray pluginData = new JsonArray();
// Search for all other bStats Metrics classes to get their plugin data
for (Object metrics : knownMetricsInstances) {
try {
Object plugin = metrics.getClass().getMethod("getPluginData").invoke(metrics);
if (plugin instanceof JsonObject) {
pluginData.add((JsonObject) plugin);
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { }
}
data.add("plugins", pluginData);
try {
// Send the data
sendData(data);
} catch (Exception e) {
// Something went wrong! :(
if (logFailedRequests) {
plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats!", e);
}
}
}
/**
* Loads the bStats configuration.
*
* @throws IOException If something did not work :(
*/
private void loadConfig() throws IOException {
Path configPath = new File(plugin.dir, "plugins").toPath().resolve("bStats");
configPath.toFile().mkdirs();
File configFile = new File(configPath.toFile(), "config.yml");
if (!configFile.exists()) {
writeFile(configFile,
"#bStats collects some data for plugin authors like how many servers are using their plugins.",
"#To honor their work, you should not disable it.",
"#This has nearly no effect on the server performance!",
"#Check out https://bStats.org/ to learn more :)",
"enabled: true",
"serverUuid: \"" + UUID.randomUUID().toString() + "\"",
"logFailedRequests: false");
}
Configuration configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile);
// Load configuration
enabled = configuration.getBoolean("enabled", true);
serverUUID = configuration.getString("serverUuid");
logFailedRequests = configuration.getBoolean("logFailedRequests", false);
}
/**
* Gets the first bStat Metrics class.
*
* @return The first bStats metrics class.
*/
private Class<?> getFirstBStatsClass() {
Path configPath = new File(plugin.dir, "plugins").toPath().resolve("bStats");
configPath.toFile().mkdirs();
File tempFile = new File(configPath.toFile(), "temp.txt");
try {
String className = readFile(tempFile);
if (className != null) {
try {
// Let's check if a class with the given name exists.
return Class.forName(className);
} catch (ClassNotFoundException ignored) { }
}
writeFile(tempFile, getClass().getName());
return getClass();
} catch (IOException e) {
if (logFailedRequests) {
plugin.getLogger().log(Level.WARNING, "Failed to get first bStats class!", e);
}
return null;
}
}
/**
* Reads the first line of the file.
*
* @param file The file to read. Cannot be null.
* @return The first line of the file or <code>null</code> if the file does not exist or is empty.
* @throws IOException If something did not work :(
*/
private String readFile(File file) throws IOException {
if (!file.exists()) {
return null;
}
try (
FileReader fileReader = new FileReader(file);
BufferedReader bufferedReader = new BufferedReader(fileReader);
) {
return bufferedReader.readLine();
}
}
/**
* Writes a String to a file. It also adds a note for the user,
*
* @param file The file to write to. Cannot be null.
* @param lines The lines to write.
* @throws IOException If something did not work :(
*/
private void writeFile(File file, String... lines) throws IOException {
if (!file.exists()) {
file.createNewFile();
}
try (
FileWriter fileWriter = new FileWriter(file);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)
) {
for (String line : lines) {
bufferedWriter.write(line);
bufferedWriter.newLine();
}
}
}
/**
* Sends the data to the bStats server.
*
* @param data The data to send.
* @throws Exception If the request failed.
*/
private static void sendData(JsonObject data) throws Exception {
if (data == null) {
throw new IllegalArgumentException("Data cannot be null");
}
HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
// Compress the data to save bandwidth
byte[] compressedData = compress(data.toString());
// Add headers
connection.setRequestMethod("POST");
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format
connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
// Send data
connection.setDoOutput(true);
DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.write(compressedData);
outputStream.flush();
outputStream.close();
connection.getInputStream().close(); // We don't care about the response - Just send our data :)
}
/**
* Gzips the given String.
*
* @param str The string to gzip.
* @return The gzipped String.
* @throws IOException If the compression failed.
*/
private static byte[] compress(final String str) throws IOException {
if (str == null) {
return null;
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(outputStream);
gzip.write(str.getBytes("UTF-8"));
gzip.close();
return outputStream.toByteArray();
}
/**
* Represents a custom chart.
*/
private static abstract class CustomChart {
// The id of the chart
private final String chartId;
/**
* Class constructor.
*
* @param chartId The id of the chart.
*/
CustomChart(String chartId) {
if (chartId == null || chartId.isEmpty()) {
throw new IllegalArgumentException("ChartId cannot be null or empty!");
}
this.chartId = chartId;
}
JsonObject getRequestJsonObject(Logger logger, boolean logFailedRequests) {
JsonObject chart = new JsonObject();
chart.addProperty("chartId", chartId);
try {
JsonObject data = getChartData();
if (data == null) {
// If the data is null we don't send the chart.
return null;
}
chart.add("data", data);
} catch (Throwable t) {
if (logFailedRequests) {
logger.log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t);
}
return null;
}
return chart;
}
protected abstract JsonObject getChartData() throws Exception;
}
/**
* Represents a custom single line chart.
*/
private static class SingleLineChart extends CustomChart {
private final Callable<Integer> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SingleLineChart(String chartId, Callable<Integer> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
int value = callable.call();
if (value == 0) {
// Null = skip the chart
return null;
}
data.addProperty("value", value);
return data;
}
}
}

View File

@ -1,52 +0,0 @@
package net.ME1312.SubServers.Bungee.Library;
/**
* Named Container Class
* @param <T> Name
* @param <V> Item
*/
public class NamedContainer<T, V> extends Container<V> {
private T name;
/**
* Creates a TaggedContainer
*
* @param name Tag to Bind
* @param item Object to Store
*/
public NamedContainer(T name, V item) {
super(item);
this.name = name;
}
/**
* Gets the name of the Container
*
* @return Container name
*/
public T name() {
return name;
}
/**
* Renames the Container
*
* @param name New Container Name
*/
public void rename(T name) {
this.name = name;
}
@Override
public boolean equals(Object object) {
if (object instanceof NamedContainer) {
if (name == null || ((NamedContainer) object).name() == null) {
return name == ((NamedContainer) object).name() && super.equals(object);
} else {
return name.equals(((NamedContainer) object).name()) && super.equals(object);
}
} else {
return super.equals(object);
}
}
}

View File

@ -0,0 +1,100 @@
package net.ME1312.SubServers.Bungee.Library;
import net.ME1312.Galaxi.Library.Util;
import java.io.*;
import java.util.*;
/**
* File Replacement Scanner
*/
public class ReplacementScanner extends FileScanner {
private final Map<String, String> replacements = new LinkedHashMap<>();
public ReplacementScanner(Map<String, String> replacements) {
TreeMap<Integer, LinkedList<String>> order = new TreeMap<Integer, LinkedList<String>>(Comparator.reverseOrder());
for (String key : replacements.keySet()) {
int length = key.length();
if (!order.containsKey(length)) order.put(length, new LinkedList<>());
order.get(length).add(key);
}
for (Integer length : order.keySet()) {
for (String key : order.get(length)) {
this.replacements.put(key, replacements.get(key));
}
}
}
/**
* Get the replacements
*
* @return Replacement Map
*/
public Map<String, String> getReplacements() {
return new HashMap<>(replacements);
}
/**
* Make replacements in a File or Directory
*
* @param dir File or Directory
* @param whitelist File Whitelist
*/
public void replace(File dir, String... whitelist) throws IOException {
super.scan(dir, whitelist);
}
protected void act(File dir, String name) throws IOException {
File file = new File(dir, name);
FileInputStream stream = new FileInputStream(file);
String string = Util.readAll(new InputStreamReader(stream));
stream.close();
boolean update = false;
for (Map.Entry<String, String> replacement : replacements.entrySet()) {
String placeholder = "SubServers::" + replacement.getKey();
if (string.contains(placeholder)) {
string = string.replace(placeholder, replacement.getValue());
update = true;
}
}
if (update) {
FileWriter writer = new FileWriter(file, false);
writer.write(string);
writer.close();
}
}
/**
* Make replacements in an Object
*
* @param value Map, Collection, Array, or String
* @return Object with replaced variables
*/
public Object replace(Object value) {
if (value instanceof Map) {
List<String> list = new ArrayList<String>();
list.addAll(((Map<String, Object>) value).keySet());
for (String key : list) ((Map<String, Object>) value).put(key, replace(((Map<String, Object>) value).get(key)));
return value;
} else if (value instanceof Collection) {
List<Object> list = new ArrayList<Object>();
for (Object val : (Collection<Object>) value) list.add(replace(val));
return list;
} else if (value.getClass().isArray()) {
List<Object> list = new ArrayList<Object>();
for (int i = 0; i < ((Object[]) value).length; i++) list.add(replace(((Object[]) value)[i]));
return list;
} else if (value instanceof String) {
return replaceObj((String) value);
} else {
return value;
}
} private String replaceObj(String string) {
for (Map.Entry<String, String> replacement : replacements.entrySet()) string = string.replace('$' + replacement.getKey() + '$', replacement.getValue());
return string;
}
}

View File

@ -1,70 +0,0 @@
package net.ME1312.SubServers.Bungee.Library;
import java.io.File;
/**
* Universal File Class
*/
public class UniversalFile extends File {
/**
* Creates a File Link. Path names are separated by ':'
*
* @param pathname Path name
*/
public UniversalFile(String pathname) {
super(pathname.replace(".:", System.getProperty("user.dir") + ":").replace(':', File.separatorChar));
}
/**
* Creates a File Link. Path names are separated by the divider
*
* @param pathname Path name
* @param divider Divider to use
*/
public UniversalFile(String pathname, char divider) {
super(pathname.replace("." + divider, System.getProperty("user.dir") + divider).replace(divider, File.separatorChar));
}
/**
* Creates a File Link.
*
* @see File
* @param file File
*/
public UniversalFile(File file) {
super(file.getPath());
}
/**
* Creates a File. Path names are separated by the ':'
*
* @see File
* @param parent Parent File
* @param child Path name
*/
public UniversalFile(File parent, String child) {
super(parent, child.replace(':', File.separatorChar));
}
/**
* Creates a File. Path names are separated by the divider
*
* @see File
* @param parent Parent File
* @param child Path name
* @param divider Divider to use
*/
public UniversalFile(File parent, String child, char divider) {
super(parent, child.replace(divider, File.separatorChar));
}
/**
* Gets the Universal File Path (separated by ':')
*
* @return
*/
public String getUniversalPath() {
return getPath().replace(File.separatorChar, ':');
}
}

View File

@ -1,400 +0,0 @@
package net.ME1312.SubServers.Bungee.Library;
import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
* SubServers Utility Class
*/
public final class Util {
private Util(){}
public interface ExceptionReturnRunnable<R> {
R run() throws Throwable;
}
public interface ExceptionRunnable {
void run() throws Throwable;
}
public interface ReturnRunnable<R> {
R run();
}
/**
* Checks values to make sure they're not null
*
* @param values Values to check
* @return If any are null
*/
public static boolean isNull(Object... values) {
boolean ret = false;
for (Object value : values) {
if (value == null) ret = true;
}
return ret;
}
/**
* Get keys by value from map
*
* @param map Map to search
* @param value Value to search for
* @param <K> Key
* @param <V> Value
* @return Search results
*/
public static <K, V> List<K> getBackwards(Map<K, V> map, V value) {
List<K> values = new ArrayList<K>();
for (K key : map.keySet()) {
if (map.get(key).equals(value)) {
values.add(key);
}
}
return values;
}
/**
* Get an item from a map ignoring case
*
* @param map Map to search
* @param key Key to search with
* @param <V> Value
* @return Search Result
*/
public static <V> V getCaseInsensitively(Map<String, V> map, String key) {
HashMap<String, String> insensitivity = new HashMap<String, String>();
for (String item : map.keySet()) if (!insensitivity.keySet().contains(item.toLowerCase())) insensitivity.put(item.toLowerCase(), item);
if (insensitivity.keySet().contains(key.toLowerCase())) {
return map.get(insensitivity.get(key.toLowerCase()));
} else {
return null;
}
}
/**
* Gets a new Variable that doesn't match the existing Variables
*
* @param existing Existing Variables
* @param generator Variable Generator
* @param <V> Variable Type
* @return Variable
*/
public static <V> V getNew(Collection<? extends V> existing, ReturnRunnable<V> generator) {
V result = null;
while (result == null) {
V tmp = generator.run();
if (!existing.contains(tmp)) result = tmp;
}
return result;
}
/**
* Read Everything from Reader
*
* @param rd Reader
* @return Reader Contents
* @throws IOException
*/
public static String readAll(Reader rd) throws IOException {
StringBuilder sb = new StringBuilder();
int cp;
while ((cp = rd.read()) != -1) {
sb.append((char) cp);
}
return sb.toString();
}
/**
* Copy from the Class Loader
*
* @param loader ClassLoader
* @param resource Location From
* @param destination Location To
*/
public static void copyFromJar(ClassLoader loader, String resource, String destination) {
InputStream resStreamIn = loader.getResourceAsStream(resource);
File resDestFile = new File(destination);
try {
OutputStream resStreamOut = new FileOutputStream(resDestFile);
int readBytes;
byte[] buffer = new byte[4096];
while ((readBytes = resStreamIn.read(buffer)) > 0) {
resStreamOut.write(buffer, 0, readBytes);
}
resStreamOut.close();
resStreamIn.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* Get a variable from a method which may throw an exception
*
* @param runnable Runnable
* @param def Default value when an exception is thrown
* @param <R> Variable Type
* @return Returns value or default depending on if an exception is thrown
*/
public static <R> R getDespiteException(ExceptionReturnRunnable<R> runnable, R def) {
try {
return runnable.run();
} catch (Throwable e) {
return def;
}
}
/**
* Determines if an Exception will occur
*
* @param runnable Runnable
* @return If an Exception occured
*/
public static boolean isException(ExceptionRunnable runnable) {
try {
runnable.run();
return false;
} catch (Throwable e) {
return true;
}
}
/**
* Delete Directory
*
* @param folder Location
*/
public static void deleteDirectory(File folder) {
File[] files = folder.listFiles();
if(files!=null) {
for(File f: files) {
if(f.isDirectory()) {
deleteDirectory(f);
} else {
f.delete();
}
}
}
folder.delete();
}
/**
* Copy a Directory
*
* @param from Source
* @param to Destination
*/
public static void copyDirectory(File from, File to) {
if (from.isDirectory()) {
if (!to.exists()) {
to.mkdirs();
}
String files[] = from.list();
for (String file : files) {
File srcFile = new File(from, file);
File destFile = new File(to, file);
copyDirectory(srcFile, destFile);
}
} else {
if (to.exists()) {
to.delete();
}
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(from);
out = new FileOutputStream(to, false);
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
in.close();
out.close();
} catch (Exception e) {
try {
if (in != null) in.close();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
if (out != null) out.close();
} catch (IOException e2) {
e2.printStackTrace();
}
}
}
}
private static List<String> zipsearch(File origin, File file) {
List<String> list = new LinkedList<String>();
if (file.isFile()) {
list.add(file.getAbsoluteFile().toString().substring(origin.getAbsoluteFile().toString().length()+1, file.getAbsoluteFile().toString().length()));
}
if (file.isDirectory()) for (File next : file.listFiles()) {
list.addAll(zipsearch(origin, next));
}
return list;
}
public static void zip(File file, OutputStream zip) {
byte[] buffer = new byte[1024];
try{
ZipOutputStream zos = new ZipOutputStream(zip);
for(String next : zipsearch(file, file)){
ZipEntry ze= new ZipEntry(next);
zos.putNextEntry(ze);
FileInputStream in = new FileInputStream(file.getAbsolutePath() + File.separator + next);
int len;
while ((len = in.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
in.close();
}
zos.closeEntry();
zos.close();
} catch(IOException ex){
ex.printStackTrace();
}
}
public static void unzip(InputStream zip, File dir) {
byte[] buffer = new byte[1024];
try{
ZipInputStream zis = new ZipInputStream(zip);
ZipEntry ze;
while ((ze = zis.getNextEntry()) != null) {
File newFile = new File(dir + File.separator + ze.getName());
if (newFile.exists()) {
if (newFile.isDirectory()) {
Util.deleteDirectory(newFile);
} else {
newFile.delete();
}
}
if (ze.isDirectory()) {
newFile.mkdirs();
continue;
} else if (!newFile.getParentFile().exists()) {
newFile.getParentFile().mkdirs();
}
FileOutputStream fos = new FileOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
}
zis.closeEntry();
zis.close();
} catch(IOException ex) {
ex.printStackTrace();
}
}
/**
* Get a Random Integer
*
* @param min Minimum Value
* @param max Maximum Value
* @return Random Integer
*/
public static int random(int min, int max) {
return new Random().nextInt((max - min) + 1) + min;
}
/**
* Parse escapes in a Java String
*
* @param str String
* @return Unescaped String
*/
public static String unescapeJavaString(String str) {
StringBuilder sb = new StringBuilder(str.length());
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if (ch == '\\') {
char nextChar = (i == str.length() - 1) ? '\\' : str
.charAt(i + 1);
// Octal escape?
if (nextChar >= '0' && nextChar <= '7') {
String code = "" + nextChar;
i++;
if ((i < str.length() - 1) && str.charAt(i + 1) >= '0'
&& str.charAt(i + 1) <= '7') {
code += str.charAt(i + 1);
i++;
if ((i < str.length() - 1) && str.charAt(i + 1) >= '0'
&& str.charAt(i + 1) <= '7') {
code += str.charAt(i + 1);
i++;
}
}
sb.append((char) Integer.parseInt(code, 8));
continue;
}
switch (nextChar) {
case '\\':
ch = '\\';
break;
case 'b':
ch = '\b';
break;
case 'f':
ch = '\f';
break;
case 'n':
ch = '\n';
break;
case 'r':
ch = '\r';
break;
case 't':
ch = '\t';
break;
case '\"':
ch = '\"';
break;
case '\'':
ch = '\'';
break;
// Hex Unicode: u????
case 'u':
if (i >= str.length() - 5) {
ch = 'u';
break;
}
int code = Integer.parseInt(
"" + str.charAt(i + 2) + str.charAt(i + 3)
+ str.charAt(i + 4) + str.charAt(i + 5), 16);
sb.append(Character.toChars(code));
i += 5;
continue;
}
i++;
}
sb.append(ch);
}
return sb.toString();
}
}

View File

@ -1,411 +0,0 @@
package net.ME1312.SubServers.Bungee.Library.Version;
import net.ME1312.SubServers.Bungee.Library.Util;
import java.io.Serializable;
import java.util.Collections;
import java.util.LinkedList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Version Class
*/
@SuppressWarnings("serial")
public class Version implements Serializable, Comparable<Version> {
private final Version parent;
private final VersionType type;
private final String string;
/**
* Creates a Version
*
* @param string Version String
*/
public Version(String string) {
this(VersionType.RELEASE, string);
}
/**
* Creates a Version
*
* @param type Version Type
* @param string Version String
*/
public Version(VersionType type, String string) {
this(null, type, string);
}
/**
* Creates a Version (Appending the parent)
*
* @param parent Parent Version
* @param string Version String
*/
public Version(Version parent, String string) {
this(parent, VersionType.RELEASE, string);
}
/**
* Creates a Version (Appending the parent)
*
* @param parent Parent Version
* @param type Version Type
* @param string Version String
*/
public Version(Version parent, VersionType type, String string) {
if (Util.isNull(string, type)) throw new NullPointerException();
this.parent = parent;
this.type = type;
this.string = string;
}
/**
* Creates a Version
*
* @param ints Version Numbers (Will be separated with dots)
*/
public Version(int... ints) {
this(VersionType.RELEASE, ints);
}
/**
* Creates a Version
*
* @param type Version Type
* @param ints Version Numbers (Will be separated with dots)
*/
public Version(VersionType type, int... ints) {
this(null, type, ints);
}
/**
* Creates a Version (Appending the parent)
*
* @param parent Parent Version
* @param ints Version Numbers (Will be separated with dots)
*/
public Version(Version parent, int... ints) {
this(parent, VersionType.RELEASE, ints);
}
/**
* Creates a Version (Appending the parent)
*
* @param parent Parent Version
* @param type Version Type
* @param ints Version Numbers (Will be separated with dots)
*/
public Version(Version parent, VersionType type, int... ints) {
if (Util.isNull(type)) throw new NullPointerException();
this.parent = parent;
this.type = type;
String string = Integer.toString(ints[0]);
int i = 0;
if (ints.length != 1) {
do {
i++;
string = string + "." + ints[i];
} while ((i + 1) != ints.length);
}
this.string = string;
}
/**
* Parse a Version from a string
*
* @param string String to parse
* @see #toFullString() <b>#toFullString()</b> returns a valid string
* @see #toFullString() <b>#toString()</b> returns a valid string
*/
public static Version fromString(String string) {
Matcher regex = Pattern.compile("(rv|p?[abrv]|[su])?([^/]+)", Pattern.CASE_INSENSITIVE).matcher(string);
Version current = null;
while (regex.find()) {
try {
VersionType type = VersionType.VERSION;
if (regex.group(1) != null) switch (regex.group(1).toLowerCase()) {
case "pa":
type = VersionType.PRE_ALPHA;
break;
case "a":
type = VersionType.ALPHA;
break;
case "pv":
type = VersionType.PREVIEW;
break;
case "pb":
type = VersionType.PRE_BETA;
break;
case "b":
type = VersionType.BETA;
break;
case "s":
type = VersionType.SNAPSHOT;
break;
case "pr":
type = VersionType.PRE_RELEASE;
break;
case "r":
type = VersionType.RELEASE;
break;
case "rv":
type = VersionType.REVISION;
break;
case "u":
type = VersionType.UPDATE;
break;
}
current = new Version(current, type, regex.group(2));
} catch (Throwable e) {}
}
if (current == null) throw new IllegalArgumentException("Could not find version in string: " + string);
return current;
}
/**
* The default toString() method<br>
* <br>
* <b style="font-family: consolas">new Version(new Version("1.0.0"), VersionType.PRE_ALPHA, "7")</b> would return:<br>
* <b style="font-family: consolas">1.0.0/pa7</b>
*
* @return Version as a String
*/
@Override
public String toString() {
return ((parent == null)?"":parent.toString()+'/'+type.shortname) + string;
}
/**
* The full toString() method<br>
* <br>
* <b style="font-family: consolas">new Version(new Version("1.0.0"), VersionType.PRE_ALPHA, "7")</b> would return:<br>
* <b style="font-family: consolas">r1.0.0/pa7</b>
*
* @return Version as a String
*/
public String toFullString() {
return ((parent == null)?"":parent.toFullString()+'/') + type.shortname + string;
}
/**
* The extended toString() method<br>
* <br>
* <b style="font-family: consolas">new Version(new Version("1.0.0"), VersionType.PRE_ALPHA, "7")</b> would return:<br>
* <b style="font-family: consolas">1.0.0 pre-alpha 7</b>
*
* @return Version as a String
*/
public String toExtendedString() {
return ((parent == null)?"":parent.toExtendedString()+' '+type.longname+' ') + string;
}
/**
* The full extended toString() method<br>
* <br>
* <b style="font-family: consolas">new Version(new Version("1.0.0"), VersionType.PRE_ALPHA, "7")</b> would return:<br>
* <b style="font-family: consolas">release 1.0.0 pre-alpha 7</b>
*
* @return Version as a String
*/
public String toFullExtendedString() {
return ((parent == null)?"":parent.toFullExtendedString()+' ') + type.longname + ' ' + string;
}
@Override
public boolean equals(Object object) {
if (object instanceof Version) {
return equals((Version) object);
} else {
return super.equals(object);
}
}
/**
* See if Versions are Equal
*
* @param version Version to Compare to
* @return
*/
public boolean equals(Version version) {
return compareTo(version) == 0;
}
/*
* Returns 1 if Greater than
* Returns 0 if Equal
* Returns -1 if Less than
*//**
*
* Compare Versions
*
* @param version Version to Compare to
*/
public int compareTo(Version version) {
return compare(this, version);
}
/**
* See if Versions are Equal
*
* @param ver1 Version to Compare
* @param ver2 Version to Compare
* @return
*/
public static boolean equals(Version ver1, Version ver2) {
return compare(ver1, ver2) == 0;
}
/*
* Returns 1 if Greater than
* Returns 0 if Equal
* Returns -1 if Less than
*//**
* Compare Versions
*
* @param ver1 Version to Compare
* @param ver2 Version to Compare
*/
public static int compare(Version ver1, Version ver2) {
if (ver1 == null && ver2 == null) {
// Both versions are null
return 0;
}
if (ver1 == null) {
// Version one is null
return -1;
}
if (ver2 == null) {
// Version two is null
return 1;
}
LinkedList<Version> stack1 = new LinkedList<Version>();
stack1.add(ver1);
while (ver1.parent != null) {
ver1 = ver1.parent;
stack1.add(ver1);
}
Collections.reverse(stack1);
LinkedList<Version> stack2 = new LinkedList<Version>();
stack2.add(ver2);
while (ver2.parent != null) {
ver2 = ver2.parent;
stack2.add(ver2);
}
Collections.reverse(stack2);
int id;
for (id = 0; id < stack1.size(); id++) {
if (id >= stack2.size()) {
// Version one still has children when version two does not...
if (stack1.get(id).type.stageid < 0) {
// ...making version two the official version
return -1;
} else {
// ...however the direct child of version one has a stageid higher than or equal to a release
return 1;
}
}
int result = stack1.get(id).compare(stack2.get(id));
if (result != 0) {
// Versions are not the same, return the result
return result;
}
}
if (id < stack2.size()) {
// Version one does not children when version two still does...
if (stack2.get(id).type.stageid < 0) {
// ...making version one the official version
return 1;
} else {
// ...however the direct child of version two has a stageid higher than or equal to a release
return -1;
}
}
return 0;
}
/*
* Compares versions ignoring parent/child relationships
*/
private int compare(Version version) {
if (this.type.stageid > version.type.stageid) {
// Version one has a type of a later stage than version two
return 1;
}
if (this.type.stageid < version.type.stageid) {
// Version one has a type of an earlier stage than version two
return -1;
}
VersionTokenizer tokenizer1 = new VersionTokenizer(string);
VersionTokenizer tokenizer2 = new VersionTokenizer(version.string);
int number1, number2;
String suffix1, suffix2;
while (tokenizer1.MoveNext()) {
if (!tokenizer2.MoveNext()) {
do {
number1 = tokenizer1.getNumber();
suffix1 = tokenizer1.getSuffix();
if (number1 != 0 || suffix1.length() != 0) {
// Version one is longer than number two, and non-zero
return 1;
}
}
while (tokenizer1.MoveNext());
// Version one is longer than version two, but zero
return 0;
}
number1 = tokenizer1.getNumber();
suffix1 = tokenizer1.getSuffix();
number2 = tokenizer2.getNumber();
suffix2 = tokenizer2.getSuffix();
if (number1 < number2) {
// Number one is less than number two
return -1;
}
if (number1 > number2) {
// Number one is greater than number two
return 1;
}
boolean empty1 = suffix1.length() == 0;
boolean empty2 = suffix2.length() == 0;
if (empty1 && empty2) continue; // No suffixes
if (empty1) return 1; // First suffix is empty (1.2 > 1.2b)
if (empty2) return -1; // Second suffix is empty (1.2a < 1.2)
// Lexical comparison of suffixes
int result = suffix1.compareTo(suffix2);
if (result != 0) return result;
}
if (tokenizer2.MoveNext()) {
do {
number2 = tokenizer2.getNumber();
suffix2 = tokenizer2.getSuffix();
if (number2 != 0 || suffix2.length() != 0) {
// Version one is longer than version two, and non-zero
return -1;
}
}
while (tokenizer2.MoveNext());
// Version two is longer than version one, but zero
return 0;
}
return 0;
}
}

Some files were not shown because too many files have changed in this diff Show More