Compare commits

..

509 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
ME1312 e5ba821754
Re-Add fallback functionality 2018-10-03 19:18:16 -04:00
ME1312 261a08d014
Extract source for default templates & Fix wget 2018-10-01 17:44:37 -04:00
ME1312 82849ef3c7
Add compatability for another revision of the WaterfallConsole 2018-09-16 15:43:27 -04:00
ME1312 a2e481efe7
Patch in GalaxiEngine by default
This is to remove the confusion of what versions are compatable with eachother (it's not quite as easy as it is with BungeeCord)
2018-09-14 21:05:39 -04:00
ME1312 a687a2d1cb
Seperate SubServers.Host from the GalaxiEngine (Step 2) 2018-09-08 18:06:21 -04:00
ME1312 bc5acab41d
Replace Auto-Restart and Temporary Flags with Stop Actions
Stop Actions will is the replacement for both the Auto Restart and Temporary flags. To define that the server should restart on stop, use the RESTART keyword. To get the same result that you would get using the temporary flag, use the REMOVE_SERVER keyword.

Additionally, there is now a DELETE_SERVER keyword. This keyword does the same thing as the REMOVE_SERVER keyword, except it deletes the directory on the server ran from.

If you would like nothing special to happen when the server stops, use the NONE keyword.
2018-08-29 21:55:59 -04:00
ME1312 a781370fbb
Allow raw binary to be sent over SubData
This allows files to be transfered faster over the new system.
2018-08-23 23:35:22 -04:00
ME1312 7cd9c9bc4c
Switch SubData Packets from JSON to MessagePack encoding
This is a change to how packets are transferred; the API has not been changed.

While the difference may be unnoticable when using unencrypted packets, because of MessagePack's compact size and better handling of byte values encrypted packets should transfer faster.
2018-08-23 22:32:49 -04:00
ME1312 9f88bb5099
Remove temporary servers from the config when finished 2018-08-20 17:50:27 -04:00
ME1312 811cc891a0
Make the Client UI API naming scheme a little less confusing 2018-08-12 17:23:21 -04:00
ME1312 cb7b3964f2
Send off reload packet only when api.ready 2018-08-10 15:58:17 -04:00
ME1312 215097976c
Rewrite the info command
The info command can now display information about proxies, hosts and servers (not just SubServers)
2018-08-10 00:50:10 -04:00
ME1312 545565512b
Restructure the Download packet group
The Download group of packets was in desperate need for a restructuring.

Now, instead of using `DownloadServerList` to list everything, different object types now are downloaded through their own seperate packets. (Improving network efficiency)
2018-08-09 14:54:56 -04:00
ME1312 86fbb2c2b6
Update error messages 2018-08-07 17:54:57 -04:00
ME1312 ed1b45fccb
Make UI elements consistant 2018-08-06 22:39:29 -04:00
ME1312 e74178e21c
Slight configuration change 2018-08-06 02:08:55 -04:00
ME1312 38eec66a4b
Further define proxy status colors
The proxies section of the list command now functions like the rest. You can hover over proxies in-game to get more status information on them.

The colors shown are as follows:
Green (Optimal): Proxy is connected to both Redis and SubData
Blue (Available): Proxy is connected to SubData only
White (External): Proxy is connected to Redis only
Red (Disabled): Proxy is offline
2018-08-05 22:07:18 -04:00
ME1312 a7e9185ce4
Fix slight lang issue 2018-08-05 17:51:18 -04:00
ME1312 4aa943953f
Flesh out the Proxy API
- Proxies connected to Redis are downloaded on startup/reload
- Named proxies are no longer removed on disconnect
- Proxies now show up in `/sub list`
- Proxies now have Add/Remove events in the API
- Proxies are included in the response of the `DownloadServerList` packet
2018-08-05 17:41:17 -04:00
ME1312 b8ee251011
Add options to sync commonly altered BungeeCord values 2018-08-04 23:29:52 -04:00
ME1312 65b29e666d
Move Bungee Chat API methods to seperate class 2018-08-03 23:22:53 -04:00
ME1312 7f94e2115e
Use old Gson location if needed 2018-08-03 20:43:02 -04:00
ME1312 cc88e6b6ea
Correct version dection for SpongeAPI 8 2018-07-30 12:29:36 -04:00
ME1312 d4f4a1cf01
Correct changes from last commit 2018-07-29 19:05:50 -04:00
ME1312 d69840f439
Lock the start method for event usage 2018-07-29 19:01:36 -04:00
ME1312 97c73bf738
Implement a simalar namespaced key system in subdata
This was a change I made to the Lang API a while back, and now it has made it's way into SubData.

Packets are now tied to channels (`n`) and then handles (`h`) within those channels.
2018-07-29 14:39:42 -04:00
ME1312 98ac26750f
Fix changes from the last commit 2018-07-28 23:02:47 -04:00
ME1312 319618fe71
Create a more straightforward way for interacting with unstable methods 2018-07-28 22:09:47 -04:00
ME1312 ae1a9b990d
Finalize v2.13a 2018-07-28 13:01:28 -04:00
ME1312 47a9ae4ced
Fix the update notification 2018-07-27 15:36:51 -04:00
ME1312 c742490956
Add javadoc hub 2018-07-26 22:41:21 -04:00
ME1312 3f0cb45aa3
Update vanilla patch locations 2018-07-26 21:29:26 -04:00
ME1312 337ee5d33c
Update download page 2018-07-26 18:37:08 -04:00
ME1312 7937be9699
Update README.md 2018-07-26 17:03:04 -04:00
ME1312 409f1e0cde
Remove redundant call to invoker 2018-07-26 16:14:32 -04:00
ME1312 86135ffe52
Maven-ify the repo (Part 2) 2018-07-26 15:09:27 -04:00
ME1312 4ed23e28f1
Merge branch 'master' of https://github.com/ME1312/SubServers-2 2018-07-26 13:34:44 -04:00
ME1312 55f97338f8
Seperate Sponge from Forge
The sponge template now builds SpongeVanilla, and a new template called `Forge` will continue to build SpongeForge
2018-07-26 13:34:31 -04:00
ME1312 c6d662eae8
Update README.md 2018-07-22 23:48:13 -04:00
ME1312 4813be645d
Add a Sponge version of SubServers.Client
This version of SubServers.Client has the same features as the Bukkit version, minus the chest interface.

This feature may be added in the future once the documentation surrounding chest interfaces becomes more thorough.
2018-07-22 23:44:20 -04:00
ME1312 716875f999
Fix version detection for older BungeeCord builds 2018-07-22 01:35:04 -04:00
ME1312 08a7d6d176
Misc changes 2018-07-19 15:34:58 -04:00
ME1312 6eb82f27bc
Update SubServers.Client Auto-Updater
SubServers.Bungee & SubServers.Host now use the more standardised build signature system when deciding on if it should update SubServers.Client. This means it can also differentiate two snapshot builds of the same version from eachother.
2018-07-17 03:10:17 -04:00
ME1312 0ade35f544
Allow old Material names using bukkit:name
Spigot 1.13 has a compatabilty layer for old bukkit names, this will allow you to take advantage of that.

1.12: `bukkit:grass` -> `minecraft:grass`
1.13: `bukkit:grass` -> `minecraft:grass_block`
1.13: `grass` -> `minecraft:grass`
2018-07-15 14:07:22 -04:00
ME1312 8f6d3e5527
Quick fixes 2018-07-15 02:07:15 -04:00
ME1312 c1a35ff266
Finalize Pre-Release 4 2018-07-15 01:23:11 -04:00
ME1312 35c2e43192
Quick fix to add SubData Connection ID to the new API 2018-07-05 23:01:38 -04:00
ME1312 27b1d6b51a
Extend SubAPI to wrap the SubData packet centered APIs
Simple requests like those used to list hosts or servers shouldn't require messing around trying to keep up with the SubData Direct protocol. It should be easy, right?

Now, SubAPI includes methods simalar to those seen in SubServers.Bungee for accessing data for Hosts, Servers, SubServers, Proxies, & Players easily. Requests the SubData Packet API is already capable of making will be included as methods in these variables.
2018-06-30 23:46:58 -04:00
ME1312 959e444aea
Add some escapes for use in SubServers.Host commands 2018-06-25 20:51:14 -04:00
ME1312 483ae51cd5
Create PULL_REQUEST_TEMPLATE.md 2018-06-25 18:05:02 -04:00
ME1312 7490c58699 Re-add issue templates 2018-06-25 18:00:48 -04:00
ME1312 fab347f4b1
Minor changes to SubCreator's Scripts
These are optional changes to SubCreator's Scripts that are intended to improve compatability. To get these changes, remove your Templates folder for it to be regenerated upon startup.
2018-06-25 17:02:31 -04:00
ME1312 465fb34bf1
Use the new VanillaCord Launcher
The Buildtools style launcher will make it so I don't have to update SubServers every time Mojang releases something that breaks the patcher.
2018-06-20 04:38:00 -04:00
ME1312 15713d58b4
Use the VanillaCord repo for vanilla builds 2018-06-19 21:24:16 -04:00
ME1312 2cabdf85ab
Print the fuller version list for debugging in /sub version 2018-06-09 12:19:25 -04:00
ME1312 9f2618778f
Sign all builds with a Snapshot ID
All builds of commonly updated SubServers apps are now auto-signed with a unique Snapshot ID simalar to the ones Mojang uses. This will replace the beta version number for unreleased builds.
2018-06-02 15:02:03 -04:00
ME1312 705660980c
Finalize Pre-Release 3 2018-05-24 16:24:58 -04:00
ME1312 82b5cd6aae
Keep BungeeCord versioning intact when patched 2018-05-24 14:52:47 -04:00
ME1312 c35a31f803
Add direct support for newer waterfall versions 2018-05-24 01:05:54 -04:00
ME1312 5f69459e62
Add more ways to detect minecraft version 2018-05-23 22:27:20 -04:00
ME1312 30b776da86
Merge branch 'master' of https://github.com/ME1312/SubServers-2 2018-05-23 00:26:34 -04:00
ME1312 1ff9a5cf41
Add placeholders/warnings for when minecraft versions cannot be detected 2018-05-23 00:26:03 -04:00
ME1312 ceeb3e8881
Update README.md 2018-05-05 21:16:40 -04:00
ME1312 0e87345a8b
All future commits from @me1312 should now be signed 2018-04-14 23:50:14 -04:00
ME1312 9515652b82
Add a way to get a SubServers.Host API plugin's ClassLoader 2018-04-14 23:38:54 -04:00
ME1312 75b9b688cc Rewrite SubData API for JSON dependancy changes
This commit removes the org.JSON library where alternatives are already provided (Bungee & Bukkit provide Gson). This change was made to improve compatability with BungeeCord plugins and reduce file sizes.

This means big changes to the SubData API, which heavily relied on org.JSON. Now we submit our data through YAMLSection to be converted and sent over the network.
2018-04-14 21:53:51 -04:00
ME1312 03505996a7 Correct dependency versions 2018-04-12 20:48:33 -04:00
ME1312 99910b2249 Correct Dependancies 2018-04-10 02:28:39 -04:00
ME1312 ebe9474a70
Add the illusive ConsoleStream.java 2018-04-10 02:21:07 -04:00
ME1312 05825bcbce Mark maven source directories 2018-04-10 02:11:52 -04:00
ME1312 046c987a31 Attempt to make contributing a little easier
This commit is to maven-ify this repo into something a little more usable to anyone who isn't me
2018-04-10 01:48:18 -04:00
ME1312 dae819ae19 Have the code reflect the patch tool updates 2018-04-09 23:29:06 -04:00
ME1312 339144e5cc Update old vanilla patch tool for Java 9 and above 2018-04-09 23:21:27 -04:00
ME1312 6c29bc4885 Update vanilla patch tool for Java 9 and above 2018-04-09 23:19:59 -04:00
ME1312 ce84fd2216 Finalize Pre-Release 2 2018-04-07 20:38:57 -04:00
ME1312 69bb3d299a Fix cache bug when spaces are in the file path 2018-04-07 16:42:09 -04:00
ME1312 74ddbc9bd4 Fix template updater 2018-04-07 15:21:56 -04:00
ME1312 f4011f419c SubCreator now caches finished jars 2018-04-07 15:04:55 -04:00
ME1312 a5847b9219 Use updated patch locations
The last three commits were changes to the way Vanilla-Patch.jar is downloaded. For compatability reasons, the old system will remain in place for now.
2018-04-07 00:59:22 -04:00
ME1312 801858a421 ...but keep support for old patch locations 2018-04-06 20:54:38 -04:00
ME1312 b8f7aa8b39 Update patch locations... 2018-04-06 20:54:18 -04:00
ME1312 a136422487 Merge branch 'master' of https://github.com/ME1312/SubServers-2 2018-04-06 20:10:35 -04:00
ME1312 573184ff91 Add bungee.yml for installation instruction 2018-04-06 20:10:25 -04:00
ME1312 56c2f0c58a
Update README.md 2018-03-27 16:38:03 -04:00
ME1312 265ac4b253 Host/Client now send Metrics data
https://bstats.org/plugin/bungeecord/SubServers%202
https://bstats.org/plugin/other/SubServers%20Host
https://bstats.org/plugin/bungeecord/SubServers%20Sync
https://bstats.org/plugin/bukkit/SubServers%20Client
2018-03-27 00:31:38 -04:00
ME1312 56070001a6 Minor changes 2018-03-21 16:45:59 -04:00
ME1312 ce51a991a0 Add more VersionTypes 2018-03-16 18:25:02 -04:00
ME1312 eb9bf034b4 Add a way to parse (non-extended) layered versions 2018-03-15 22:45:54 -04:00
ME1312 12a74b3474 Rewrite what compares layered versions 2018-03-14 17:50:15 -04:00
ME1312 bb7cfa9e57 Fix /sub delete permission error on windows 2018-03-14 03:01:44 -04:00
ME1312 bddbb692cd Make the version system layered
The versioning system just got more complex (on the backend of course)
2018-03-13 23:38:26 -04:00
ME1312 56f8d3dfba Remove package.xml requirement for SubServers.Host 2018-02-19 17:59:51 -05:00
ME1312 92c649eabe Make `Name` field optional for SubServers.Client
SubServers.Bungee can now link servers to subdata clients via connection address and port number.

Since this still has the chance to fail, the `Name` field will appear if no servers were found this way, and will be used the same as before. SubCreator made servers will still have the `Name` value present and filled out for assurance.
2018-01-29 01:04:36 -05:00
ME1312 754b418e7d Register SubServers.Sync Proxies to name for API access 2018-01-22 10:01:33 -05:00
ME1312 cc1f86c4d1 Update Dependancies 2018-01-21 21:49:18 -05:00
ME1312 eb18c01b22 Rewrite Launch & PluginLoader for SubServers.Host
This commit changes the way SubServers.Host launches itself and loads it's plugins. Overall loading plugins this way is more efficient, faster, and can cause less problems than before.

Plugins will still use the package.xml & @SubPlugin annotation system to be loaded.

Also, there are some changes to the logger that better support async logging.
2018-01-21 15:45:27 -05:00
ME1312 e5ad3f55d2 Allow PacketIn to accept multiple oncoming packet versions 2018-01-13 16:22:13 -05:00
ME1312 b72103c0f0 Make Server API use existing fields from BungeeServerInfo 2018-01-12 16:56:22 -05:00
ME1312 7a5eac83fd Update Libraries 2018-01-05 17:30:01 -05:00
ME1312 00d56c1167 Add the SubData Cipher API
This adds a simplistic API for the encryption/decryption of incoming/outgoing packets, replacing the old Encryption enum.
2018-01-05 15:37:23 -05:00
ME1312 562072df3f Lang API Rewrite // Add TabCompletes to Sync 2018-01-02 17:29:25 -05:00
ME1312 b3a40311a1 Simplify YAMLSection methods 2017-12-21 18:37:39 -05:00
ME1312 6bb7b1ef17 Allow YAMLSection to be converted to Map<String, ?> 2017-12-21 11:02:47 -05:00
ME1312 580fe41ad9 Allow hosts to be added with invalid/unregistered drivers 2017-12-17 16:04:05 -05:00
ME1312 c9afe48674 Correct config loading issue
This solves a 'file in use' error on windows
2017-12-14 19:50:39 -05:00
ME1312 ada14c0889 Add reload packet for ExHosts and Servers using Client 2017-12-13 19:04:58 -05:00
ME1312 36ee42a1ab Implement the proposed TabValidator API
This is how SubServers will implement the Validator API that I suggested. I had to make some assumptions though (like how I don't expect BungeeCord's api to have a setTabValidator() method).
2017-12-13 12:29:50 -05:00
ME1312 2e3525a31a Hide menu buttons when their linked menu is unused 2017-12-11 18:27:18 -05:00
ME1312 54c61207a5 Fix bugs with server edit() with a network host 2017-12-11 12:52:35 -05:00
ME1312 617297b5b6 Finalize RedisBungee support 2017-12-10 09:14:49 -05:00
ME1312 91ca559e4a Host & Server objects are now signed (prevents desyncs across apps) 2017-12-09 19:30:06 -05:00
ME1312 0bf5f16e09 /sub reload can now perform soft reloads
/sub reload - can now perform soft reloads
/greload - still performs hard resets

Soft Reloads mean that SubServers will load new data from the config and attempt to merge it with what is already in memory.

This is good if you need to make some quick changes, since it will only stop servers if a major change has been made to them.

However, this has the potential to cause issues, which is why the Hard Reset will continue to be tied to bungeecord command.
2017-12-09 03:43:29 -05:00
ME1312 556d947981 Add Proper RedisBungee Support 2017-12-08 02:35:50 -05:00
ME1312 5050baedf8 Assume 1.13 Material enum values // Correct Patched Signatures 2017-12-07 17:51:06 -05:00
ME1312 ce895cdecd Prepare UI Elements for 1.13 // Add SubData Whitelist Wildcards 2017-12-07 12:22:36 -05:00
ME1312 a8bbd09e9d Add some force quit padding // Rewrite group system internals 2017-12-06 17:34:47 -05:00
ME1312 a019383bc3 Preserve YAML element order 2017-11-22 16:58:33 -05:00
ME1312 affac1cd56 Default lang.yml update 2017-10-07 12:49:36 -04:00
ME1312 9a219a7d0f Queue packets until subdata connection is authorized 2017-09-23 23:19:22 -04:00
ME1312 f2f01576df SubServers Console v2.12.1a 2017-08-30 20:12:26 -04:00
ME1312 b6ff93a37f Add Javadoc & Source jar files 2017-08-27 22:40:35 -04:00
ME1312 e3ddd4c93b Revert & Indirectly refrence Server methods
Revert last commit in favor of a different way to solve that issue
2017-08-27 14:37:25 -04:00
ME1312 44b838ee34 Indirectly overrides BungeeServerInfo methods 2017-08-26 23:56:15 -04:00
ME1312 ba09bab93a Add Server Grouping 2017-08-26 01:19:59 -04:00
ME1312 53d57cada9 Generate difference list 2017-08-24 10:28:00 -04:00
ME1312 1dfdc494f3 Better Patch Logging 2017-08-23 10:48:42 -04:00
ME1312 185ce70cd9 SubServers BungeeCord Patcher
Add a way to patch a build of BungeeCord into SubServers.Bungee/SubServers.Sync
2017-08-23 09:49:41 -04:00
ME1312 bb1a25fc3f SubServers Client v2.12.1d 2017-08-22 17:32:57 -04:00
ME1312 336aab1e6a Merge branch 'master' of https://github.com/ME1312/SubServers-2 2017-08-22 09:14:59 -04:00
ME1312 148abc67cf Fix .gitignore 2017-08-22 09:14:57 -04:00
ME1312 fe8f6ba0cb Update README.md 2017-08-22 09:04:30 -04:00
ME1312 41e77e124c SubServers, Host, Sync & Client v2.12.1d/2.12.1c/2.12.1a/2.12.1c 2017-08-22 09:02:23 -04:00
ME1312 1624271edc Add extra charts 2017-08-18 08:48:14 -04:00
ME1312 837331a542 SubServers, Host & Client v2.12.1c/2.12.1b/2.12.1b 2017-08-18 05:58:06 -04:00
ME1312 ebe1ba0c4c SubServers v2.12.1b 2017-08-16 19:29:02 -04:00
ME1312 ac1df7a30a SubServers, Host, & Client v2.12.1a 2017-08-15 05:58:48 -04:00
ME1312 3ac1c8dec3 Swap EventPriority for EventOrder
EventPriority is a fixed enum, where EventOrder is a short value (with predefined settings for ease of use) allowing for more fine tuning on when your events should be run
2017-08-09 02:25:56 -04:00
ME1312 65002c767d Add broadcastPacket method to clients 2017-08-07 15:51:11 -04:00
ME1312 693b6e8394 Don't recreate default templates 2017-07-29 20:41:02 -04:00
ME1312 f6274317d6 Fix template nullpointer 2017-07-25 19:47:38 -04:00
ME1312 c34b097676 SubServers, Host, & Client v2.12c/2.12d/2.12c 2017-07-25 19:23:41 -04:00
ME1312 e766f7fa22 Minor Changes 2017-07-25 15:27:40 -04:00
ME1312 8b65ec04dd SubServers Console v2.12b 2017-07-25 01:37:25 -04:00
ME1312 c02db9890c SubServers Console v2.12a 2017-07-23 17:05:33 -04:00
ME1312 df9797496a SubServers, Host, & Client v2.12b/2.12c/2.12b 2017-07-23 14:21:05 -04:00
ME1312 829e81fd9d Update vanilla server patcher 2017-07-23 12:27:23 -04:00
ME1312 09c5a8251a SubServers, Host, Client Beta v2.12b;3/2.12c;3/2.12b;3 2017-07-23 00:32:57 -04:00
ME1312 e058b3f655 SubServers, Host, & Client Beta v2.12b;2/2.12c;2/2.12b;2
Servers can now be incompatable with each other.
2017-07-21 16:45:41 -04:00
ME1312 f2589b649c Merge branch 'master' of https://github.com/ME1312/SubServers-2 2017-07-18 19:30:08 -04:00
ME1312 5bddfbed0b SubServers, Host, & Client Beta v2.12b;1/2.12c;1/2.12b;1 2017-07-18 19:28:59 -04:00
ME1312 224066d24f Update README.md 2017-07-05 23:39:21 -04:00
ME1312 56605aa3a2 SubServers, Host, & Client v2.12a 2017-06-30 09:36:16 -04:00
ME1312 9b5a2d59e3 SubServers, Host, & Client v2.11.2m/2.11.2c/2.11.2h 2017-05-30 15:38:51 -04:00
ME1312 4529501023 SubServers & Client v2.11.2m/2.11.2h Beta 1 2017-05-29 01:00:02 -04:00
ME1312 e238add62c SubServers v2.11.2l 2017-05-25 15:55:47 -04:00
ME1312 2b1f355a6c SubServers.Bungee 2.11.2l BETA 2 2017-04-24 13:16:57 -04:00
ME1312 0364568c23 Merge pull request #7 from Mammothskier/master
Allow usage of "*" to signify run command on all online subservers
2017-04-24 12:28:42 -04:00
ME1312 357ef0c874 Merge recent changes 2017-04-24 12:28:16 -04:00
Kyle Melton 1270fc1bec Removing unused conditional statement 2017-04-23 14:10:22 -06:00
Kyle Melton e802d4f467 Switching do while to a for loop 2017-04-23 14:06:46 -06:00
Kyle Melton 958bc190a2 Allowing commands to be run on all servers using '*' identifier 2017-04-23 13:56:09 -06:00
ME1312 418d1a380e Update Javadoc 2017-04-16 13:02:14 -04:00
ME1312 db8470a331 Update README.md 2017-04-14 14:10:57 -04:00
ME1312 467bb8adf3 SubServers 2 & SubServers.Host v2.11.2k/2.11.2b 2017-04-13 22:39:51 -04:00
ME1312 21dbe876d4 Fix '/Sub Delete' for internally hosted servers 2017-04-10 12:25:33 -04:00
ME1312 98187137c4 Make SubData Reconnections Async 2017-04-09 23:39:28 -04:00
ME1312 34a947e5ea Update README.md 2017-04-03 15:13:05 -04:00
ME1312 12f75b9de5 Clean up some log messages 2017-04-03 13:52:28 -04:00
ME1312 e22e669b78 SubServers v2.11.2i & SubServers.Host v1.11.2a 2017-04-03 13:08:00 -04:00
ME1312 78cb8f9d39 Add Commands to SubServers.Host 2017-04-01 16:31:57 -04:00
ME1312 8e0172302e Various fixes to the last build 2017-04-01 12:50:09 -04:00
ME1312 7821c1f88e SubServers.Host Alpha 2
This update to SubServers.Host adds the core functions to the program.
It can now be used to host and create servers on other machines. API
while available is quite limited right now. This is also a very early
build, so it's probably not so stable just yet fyi.
2017-04-01 01:37:48 -04:00
ME1312 af398c48cc SubServers.Host Internal/API Changes
This update changes the internals and API methods for SubServers.Host.
Namely, the arguments for @SubPlugin and the Logger API.
2017-02-07 19:39:18 -05:00
ME1312 3dcbd8252e SubServers.Host API Additions 2017-02-05 17:03:17 -05:00
ME1312 8458acb255 Auto-Update SubServers.Client 2017-01-30 22:04:37 -05:00
ME1312 b7a8fbc8b5 Changes to the Plugin Loader 2017-01-30 19:33:30 -05:00
ME1312 df837bf1cb Remove YAML from JavaDoc 2017-01-30 15:37:21 -05:00
ME1312 7b3e7ae9e8 Start SubServers.Host & SubAPI Null Checks
This marks the beginning of SubServers.Host. As of now it is just a
simple plugin loading API, but it is planned to become a way to host
servers on other machines.

Also, SubAPI now checks to make sure variables aren't null in many
places.
2017-01-30 15:22:36 -05:00
ME1312 dcd2ad8aa6 SubServers Release v2.11.2h 2017-01-26 17:19:48 -05:00
ME1312 96743ddecf SubServers Release v2.11.2b 2017-01-21 11:49:37 -05:00
ME1312 9aeb835ed7 Minor Fixes 2017-01-12 16:42:32 -05:00
ME1312 86647430de SubServers Release v2.11.2f 2017-01-12 16:04:59 -05:00
ME1312 085e2d0518 Update README.md 2017-01-11 22:39:16 -05:00
ME1312 16e438727e Update README.md 2017-01-11 22:22:34 -05:00
ME1312 6f9466492b Update README.md 2017-01-11 22:15:42 -05:00
ME1312 01a7d49780 Console Bugfixes/Additons 2017-01-11 17:07:03 -05:00
ME1312 5e8293a8f5 Quick Fixes 2017-01-10 22:29:31 -05:00
ME1312 39fa66c828 SubCreator Console Support & Aethstetic Changes
You can now popout SubCreator with SubServers.Console: /popoutc
2017-01-10 22:23:29 -05:00
ME1312 8133970000 Some quick fixes 2017-01-09 15:15:43 -05:00
ME1312 d59bb7d4cc SubServers.Console & Re-add LogFilter API
SubServers Console is a simple bungeecord plugin that pops your
subservers out into their own console window. No configuration
required, one simple command: /popout
2017-01-09 14:37:57 -05:00
ME1312 f0f5da7816 SubServers Release v2.11.2e 2017-01-08 14:42:40 -05:00
ME1312 6010edb868 API Additions & Launch Changes 2017-01-07 21:30:03 -05:00
ME1312 bdb11b1ea6 Better Document SubServers.Bungee 2017-01-07 14:06:54 -05:00
ME1312 aec6282ee4 Update README.md 2017-01-06 16:12:43 -05:00
ME1312 bef900cf87 Fix links 2017-01-06 16:11:52 -05:00
ME1312 279f414944 Use repo.ME1312.net 2017-01-06 16:03:33 -05:00
ME1312 67a2541897 Create CNAME 2017-01-06 15:56:31 -05:00
ME1312 ae587deaf0 Allow multiple packets to be registered with the name name
It's sorta experimental, but in theory: multiple packets should be able
to write to the same handle and multiple packets should be able to read
from the same handle.
2017-01-06 15:44:34 -05:00
ME1312 8255e2464a Remove JavaDoc Timestamps 2017-01-03 18:17:13 -05:00
ME1312 6b875c812d Clean up commit 2017-01-03 18:16:10 -05:00
ME1312 4a00c15b7f Rename JavaDoc/SubServers.Bungee/allclasses-frame.html to Javadoc/SubServers.Bungee/allclasses-frame.html 2017-01-03 18:13:30 -05:00
ME1312 140c216569 Update README.md 2017-01-03 12:58:14 -05:00
ME1312 249b95fa69 Update README.md 2017-01-03 12:57:10 -05:00
ME1312 4c417a2fef Set theme jekyll-theme-cayman 2017-01-03 12:53:20 -05:00
ME1312 0a055e156b SubServers Release v2.11.2d 2017-01-02 11:54:03 -05:00
ME1312 319d60fd1e Update README.md 2017-01-01 20:00:26 -05:00
ME1312 733a146d06 Update README.md 2017-01-01 19:44:24 -05:00
ME1312 1b48657d92 Update README.md 2017-01-01 19:43:22 -05:00
ME1312 41712a1840 Add Dependancies to JavaDoc 2017-01-01 19:30:14 -05:00
ME1312 91cf5d88b4 Remove unusable methods from JavaDoc 2017-01-01 18:06:38 -05:00
ME1312 fa27a80c69 Add JavaDoc 2017-01-01 16:38:51 -05:00
ME1312 147ae38e8c Set theme jekyll-theme-cayman 2017-01-01 16:35:47 -05:00
ME1312 ae0ce737f9 SubServers Release v2.11.2c 2017-01-01 14:34:46 -05:00
486 changed files with 57693 additions and 9210 deletions

17
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View File

@ -0,0 +1,17 @@
---
name: Bug Report
about: Report an issue with SubServers
---
### Platform Information
Paste in the version information from the SubServers app in question here. To get this info, run the `/sub version` command where applicable or launch SubServers with the `-v` argument. Make sure the app name matches the one you are reporting this bug for.
### What Happened
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 the problem happens to everyone else too.
### Additional Information
Here you can provide any extra details you may think useful for solving the problem.

View File

@ -0,0 +1,14 @@
---
name: Feature Request
about: Suggest something to add to SubServers
---
### What Should Be Added
Describe what you'd like to see added here.
### Why It Should be Added
Tell us why you think it should be added. Be sure to include reasons why everyone else would find it useful as well.
### What's The Alternative
Describe alternative methods that may already exist right now that accomplish the same goal, and why they suck.

5
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,5 @@
### What's Been Changed
Describe what your pull request changes here. Features, Bugfixes, and references to issues are all good things to include.
### Why It Was Changed
Now it's time do describe why these changes were made, and why they should also be in the official version of SubServers.

47
.gitignore vendored
View File

@ -1,34 +1,17 @@
# SubServers 2 Ignored Files
*.iml
## Directory-based project format:
.idea/
## File-based project format:
*.ipr
*.iws
## Plugin-specific files:
# 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
/Artifacts/SubServers.Host.jar
/SubServers.Host/
# Hide Others
.idea/
*.iml
.DS_STORE
.alias
# Hide Unfinished Projects
/SubServers.Test/
# Hide Compiled Artifacts
/Artifacts/*
/BungeeCord/
/Javadoc/
# Show Interpreted Artifacts
!/Artifacts/Download/
!/Artifacts/SubServers.Patcher.sh

View File

@ -0,0 +1,348 @@
<!doctype html>
<html>
<head>
<title>Download SubServers</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<style>
* {
font-family: Avenir;
}
html {
min-height: 100%;
position: relative;
}
body {
background: #eeeeee;
background: -webkit-linear-gradient(#eeeeee 0%, #dddddd 100%);
background: -o-linear-gradient(#eeeeee 0%, #dddddd 100%);
background: linear-gradient(#eeeeee 0%, #dddddd 100%);
width: 100%;
height: 100%;
margin: 0px !important;
}
.page .page-title {
display: table;
vertical-align: middle;
margin: 0.83em auto;
margin-bottom: 0px;
font-size: 1.5em;
font-weight: bold;
}
.page .page-subtitle {
display: block;
margin: 0px;
margin-right: 12px;
font-size: 0.5em;
color: #777;
font-weight: normal;
font-style: italic;
text-align: right;
text-decoration: none;
}
.page a.page-subtitle:hover {
text-decoration: underline;
}
.page .options {
display: flex;
}
.page .options > .desktop-spacer {
flex-basis: 25%;
}
.page .options > div-option {
padding: 26px 13px;
flex-basis: 100%;
border-right: 2px solid #CCC;
}
.page .options > div-option:last-of-type {
border-right: none;
}
.page .options > div-option > form > input,
.page .options > div-option > button,
.page .options > div-option > a {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
-ms-touch-action: manipulation;
touch-action: manipulation;
background-image: none;
border: none;
white-space: nowrap;
padding: 8px 16px;
font-size: 1.125em;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
text-decoration: none;
text-transform: uppercase;
-webkit-box-shadow: 1px 1px 4px rgba(0,0,0,0.4);
box-shadow: 1px 1px 4px rgba(0,0,0,0.4);
-webkit-transition: all 0.4s;
-o-transition: all 0.4s;
transition: all 0.4s;
}
.page .options > div-option > form > input {
padding-left: 0px;
padding-right: 0px;
}
.page .options > .option-1 > a {
color: #ffffff;
background-color: #4caf50;
border-color: transparent
}
.page .options > .option-1 > a:hover {
background-color: #439a46;
border-color: rgba(0,0,0,0);
}
.page .options > .option-2 > form {
display: inline-block;
background-color: #DDD;
border-bottom: 2px solid #CCC;
padding-left: 16px;
font-size: 1.125em;
cursor: text;
}
.page .options > .option-2 > form > input {
background-color: transparent;
border: none;
width: 82px;
padding-bottom: 6px;
outline: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
font-size: 1em;
text-align: left;
}
.page .options > .option-2 > form > input:focus {
outline: none;
}
.page .options > .option-2 > button {
color: #fff;
background-color: #2196f3;
cursor: pointer;
}
.page .options > .option-2 > button:hover {
background-color: #0d87e9;
}
.page .options > .option-3 > a {
color: #fff;
background-color: #ff9800;
}
.page .options > .option-3 > a:hover {
color: #fff;
background-color: #e08600;
}
.page .options > div-option > span,
.page .options > div-option > span > a {
color: #777;
font-size: 0.8em;
text-decoration: none;
}
.page .options > div-option > span > a {
font-size: 1em;
}
.page .options > div-option > span > a:hover {
text-decoration: underline;
}
.page .options > div-option > p {
margin-left: 13px;
margin-right: 13px;
}
.footer {
margin-bottom: 0px;
padding: 8px;
padding-top: 0px;
position: absolute;
bottom: 0px;
left: 0px;
right: 0px;
}
.footer > div {
height: 32px;
float: right;
}
.footer img {
height: 32px;
float: left;
}
.footer > div > a {
padding-left: 8px;
padding-right: 8px;
vertical-align: middle;
line-height: 32px;
font-size: 14px;
color: #333;
text-decoration: none;
}
.footer > div > a:hover,
.footer > div > a:active {
color: #555;
text-decoration: underline;
}
@media only screen and (max-width:875px),
only screen and (max-height:493px) {
.page .options {
display: inline-block;
}
.page .options > .desktop-spacer {
display: none;
}
.page .options > div-option {
display: block;
padding: 25px 0px;
margin: 0px 25px;
border-right: none;
border-bottom: 2px solid #CCC;
}
.page .options > div-option:last-of-type {
border-bottom: none;
}
}
@media only screen and (max-width:543px),
only screen and (max-height:306px) {
.app-version > span.full {
display: none;
}
}
@font-face {
font-family: Avenir;
src: url("https://raw.githubusercontent.com/ME1312/SubServers-2/master/SubServers.Console/Avenir-Book.ttf");
}
</style>
<div class="download"><center>
<div class="page">
<span class="page-title">You're about to download <span class="full-app-name">&lt;unknown&gt;</span><br><a class="page-subtitle" href="%commit_source%" target="_blank" draggable="false">from <span class="app-version">&lt;unknown&gt;</span></a></span><hr style="margin: 0.5em 8px;">
Thank you for downloading <span class="app-name">&lt;unknown&gt;</span>. Choose how you would like to get your file:<br><br>
<div class="options">
<div class="desktop-spacer"></div>
<div-option class="option-1">
<a href="%adfly_app_download%" draggable="false">Watch a Quick AD</a>
<br><span><a href="https://adf.ly" draggable="false">through adf.ly</a></span>
<p>It only takes 5 seconds to support the developer these days. Then we'll take you straight to your download.</p>
</div-option>
<div-option class="option-2">
<form id="donate" action="https://www.paypal.com/cgi-bin/webscr" method="get" target="_blank"><!--
--><input type="hidden" name="cmd" value="_xclick" /><!--
--><input type="hidden" name="business" value="4S5QNFZGEFJN2" /><!--
--><input type="hidden" name="lc" value="US" /><!--
--><input type="hidden" name="item_name" value="SubServers%202%20Donation" /><!--
-->$<input type="number" name="amount" step="0.01" min="1" value="15.00" /><!--
--><input type="hidden" name="currency_code" value="USD" /><!--
--><input type="hidden" name="button_subtype" value="services" /><!--
--><input type="hidden" name="bn" value="PP%2dBuyNowBF%3abtn_buynowCC_LG%2egif%3aNonHosted" /><!--
--></form><button form="donate" type="submit">Donate</button>
<br><span>and download after</span>
<p>I'd appreciate any donation, even if it's just a dollar.</p>
</div-option>
<div-option class="option-3">
<a id="download" href="%app_download%" download="%" draggable="false">Direct Download</a>
<br><span>SubServers is always free to use</span>
<p>You don't have to do that stuff to use SubServers, but it's always appreciated.</p>
</div-option>
<div class="desktop-spacer"></div>
</div>
</div>
</center></div>
<br>
<br>
<br>
<br>
<div class="footer">
<hr>
<a href="https://www.ME1312.net" target="_blank" draggable="false"><img src="https://src.ME1312.net/img/me1312.net.inverted.png" draggable="false" /></a>
<div><a href="https://src.me1312.net/jenkins/job/SubServers%20Platform/" target="_blank" draggable="false">Download not working?</a></div>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
var hash = getHash();
function getHash() {
var hash = window.location.hash.substring(1);
var params = {}
hash.split('&').map(hk => {
let temp = hk.split('=');
params[temp[0]] = temp[1];
});
return params;
}
if (hash.hasOwnProperty("app")) {
$('.full-app-name').html(hash.app);
$('.app-name').html(hash.app.replace(/^(.+?)\.([^.]*)$/, '$1'));
document.title = "Download " + hash.app.replace(/^(.+?)\.([^.]*)$/, '$1');
if (hash.hasOwnProperty("commit")) {
if (hash.hasOwnProperty("build")) {
$('.app-version').html('build ' + hash.build + '</span>');
} else {
$('.app-version').html('commit ' + hash.commit.substring(0, 7) + '<span class="full">' + hash.commit.substring(7) + '</span>');
}
$('a').each(function() {
var a = $(this);
if (a.attr('download') == '%')
a.attr('download', hash.app);
switch (a.attr("href").toLowerCase()) {
case "%adfly_app_download%":
if (hash.hasOwnProperty("build")) {
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://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);
}
break;
case "%commit_page%":
a.attr("href", "https://github.com/ME1312/SubServers-2/commit/" + hash.commit.toLowerCase());
break;
case "%commit_source%":
a.attr("href", "https://github.com/ME1312/SubServers-2/tree/" + hash.commit.toLowerCase());
break;
}
});
}
}
</script>
</body>
</html>

Binary file not shown.

View File

@ -0,0 +1,116 @@
# SubServers Library Patcher
#
# Can be used to combine the following into one jar file:
# -> BungeeCord and SubServers.Bungee
# -> BungeeCord and SubServers.Sync
# -> GalaxiEngine and SubServers.Host
#
# Usage: "bash SubServers.Patcher.sh <Platform.jar> <SubServers.jar>"
#
#!/usr/bin/env bash
if [ -z "$1" ]
then
echo "SubServers Library Patcher"
echo ""
echo "Can be used to combine the following into one jar file:"
echo " -> BungeeCord and SubServers.Bungee"
echo " -> BungeeCord and SubServers.Sync"
echo " -> GalaxiEngine and SubServers.Host"
echo ""
echo "Usage: bash $0 <Platform.jar> <SubServers.jar>"
exit 1
fi
if [ ! -f "$1" ]
then
echo ERROR: Cannot find $1
exit 2
fi
if [ -z "$2" ]
then
echo ERROR: No SubServers File Supplied
exit 1
fi
if [ ! -f "$2" ]
then
echo ERROR: Cannot find $2
exit 2
fi
if [ -d "SubServers.Patcher" ]; then
rm -Rf SubServers.Patcher
fi
echo ">> Extracting $1..."
mkdir SubServers.Patcher
mkdir SubServers.Patcher/Patched.jar
cd SubServers.Patcher/Patched.jar
jar xvf "../../$1"; __RETURN=$?;
if [ $__RETURN -eq 0 ]
then
if [ -f "LICENSE.txt" ]; then
rm -Rf LICENSE.txt
fi
if [ -f "LICENSE" ]; then
rm -Rf LICENSE
fi
if [ -f "META-INF/MANIFEST.MF" ]; then
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
if [ -f "MODIFICATIONS" ]; then
mv -f MODIFICATIONS ../MODIFICATIONS
fi
echo ">> Extracting $2..."
mkdir ../Original.jar
cd ../Original.jar
jar xvf "../../$2"; __RETURN=$?;
if [ $__RETURN -eq 0 ]
then
echo ">> Writing Changes..."
if [ -f "META-INF/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
fi
fi
if [ -f "MODIFICATIONS" ]; then
cat MODIFICATIONS >> ../MODIFICATIONS
fi
yes | cp -rf . ../Patched.jar
cd ../
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.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
cp -f MODIFICATIONS Patched.jar
cd Patched.jar
echo ">> Recompiling..."
if [ -f "../../SubServers.Patched.jar" ]; then
rm -Rf ../../SubServers.Patched.jar
fi
jar cvfm ../../SubServers.Patched.jar META-INF/MANIFEST.MF .; __RETURN=$?;
if [ $__RETURN -eq 0 ]
then
echo ">> Cleaning Up..."
cd ../../
rm -Rf SubServers.Patcher
exit 0;
else
echo ">> Error Recomiling Files"
exit 4
fi
else
echo ">> Error Decompiling $2"
exit 3
fi
else
echo ">> Error Decompiling $1"
exit 3
fi

1
CNAME Normal file
View File

@ -0,0 +1 @@
subservers.me1312.net

View File

@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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,29 +1,37 @@
# SubServers 2 [BETA]
SubServers 2 is a rewrite of SubServers, the Server Management Plugin.
# ![https://s3.postimg.cc/dikyxlz5v/Sub_Banner.png](https://s3.postimg.cc/dikyxlz5v/Sub_Banner.png)
[![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>
> [https://www.spigotmc.org/resources/subservers-sync.46124/](https://www.spigotmc.org/resources/subservers-sync.46124/)<br>
> [https://www.spigotmc.org/resources/subservers-console.37341/](https://www.spigotmc.org/resources/subservers-console.37341/)<br>
> [https://www.spigotmc.org/resources/subservers-client-bukkit.15506/](https://www.spigotmc.org/resources/subservers-client-bukkit.15506/)
## Notable Improvements (Over SubServers v1)
* Hosts (and Host Driver API)
* SubData Direct (and API)
* Names arn't case sensitive
* The Proxy hosts the Servers (instead of the Servers hosting the Proxy)
* Just about everything your players will see either looks like BungeeCord or is Customizable
## Quick Links
These are some quick links for common resources of SubServers 2.
## How to Install/Update SubServers.Bungee
1. Download BungeeCord ([Link](https://www.spigotmc.org/link-forums/bungeecord.28/))
2. Download your favorite commit of SubServers.Bungee ([Click Here](https://github.com/ME1312/SubServers-2/tree/master/Artifacts) for the latest commit)
3. Put them both in a folder together. It should now look like this:
![Example Folder](https://s30.postimg.org/qhcx95jep/Screen_Shot_2016_12_15_at_4_30_15_PM.png)
4. If you are updating, make sure to update the files in `~/SubServers`, they wont reset themselves.
5. You can now launch SubServers via your terminal: `java -jar SubServers.Bungee.jar`
6. All SubServers.Bungee commands can be accessed in console using `sub help`
### How to Install
> [https://github.com/ME1312/SubServers-2/wiki/Install](https://github.com/ME1312/SubServers-2/wiki/Installation)
## How to Install/Update SubServers.Client
1. Download your favorite commit of SubServers.Client ([Click Here](https://github.com/ME1312/SubServers-2/tree/master/Artifacts) for the latest commit)
2. Put SubServers.Client into your server's plugins
3. If you are updating, make sure to update the files in `~/plugins/SubServers`, they wont reset themselves.
4. Start, then stop your server
5. Open config.yml
6. Change `Settings > SubData > Name` to whatever you named this server in BungeeCord/SubServers
7. Make sure SubData Client can connect to your SubData Server (using the ip and password in the config)
8. You can now startup your server
9. All SubServers.Client commands can be accessed in-game by using `sub help`
### Snapshot Downloads
> [https://dev.me1312.net/jenkins/job/SubServers Platform](https://dev.me1312.net/jenkins/job/SubServers%20Platform)
### Javadocs for Developers
> [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

@ -1,4 +0,0 @@
Manifest-Version: 1.0
Class-Path: BungeeCord.jar
Main-Class: net.ME1312.SubServers.Bungee.Launch

Binary file not shown.

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

@ -15,9 +15,12 @@ permissions:
groups: {}
servers:
Lobby:
display: ''
group: []
motd: '&1Just another BungeeCord - Forced Host'
address: 127.0.0.1:25566
restricted: false
hidden: false
timeout: 30000
listeners:
- query_port: 25564
@ -32,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

@ -0,0 +1,7 @@
package net.ME1312.SubServers.Bungee.Library;
/**
* SubEvent Layout Class
*/
public interface SubEvent {
}

177
SubServers.Bungee/pom.xml Normal file
View File

@ -0,0 +1,177 @@
<?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</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.SubServers</groupId>
<artifactId>SubServers.Bungee.Common</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<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>
<build>
<directory>../out/compile/target/SubServers.Bungee</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>
<id>process</id>
<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" />
<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>
<version>2.2-beta-5</version>
<configuration>
<finalName>SubServers.Bungee</finalName>
<outputDirectory>../Artifacts</outputDirectory>
<archive>
<manifestFile>src/META-INF/MANIFEST.MF</manifestFile>
</archive>
<descriptors>
<descriptor>../SubServers.Client/Common/jar-with-some-dependencies.xml</descriptor>
</descriptors>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</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</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>
</plugin>
</plugins>
</build>
</project>

View File

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

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

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

View File

@ -0,0 +1,61 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.Host;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* Host Add Event
*/
public class SubAddHostEvent extends Event implements SubEvent, Cancellable {
private boolean cancelled = false;
private UUID player;
private Host host;
/**
* Host Add Event
*
* @param player Player Adding Server
* @param host Host Being Added
*/
public SubAddHostEvent(UUID player, Host host) {
Util.nullpo(host);
this.player = player;
this.host = host;
}
/**
* Gets the Host to be Added
*
* @return The Host to be Added
*/
public Host getHost() { return host; }
/**
* Gets the player that triggered the Event
*
* @return The Player that triggered this Event or null if Console
*/
public UUID getPlayer() { return player; }
/**
* Gets the Cancelled Status
*
* @return Cancelled Status
*/
public boolean isCancelled() {
return cancelled;
}
/**
* Sets the Cancelled Status
*/
public void setCancelled(boolean value) {
cancelled = value;
}
}

View File

@ -0,0 +1,31 @@
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.md_5.bungee.api.plugin.Event;
/**
* Proxy Add Event
*/
public class SubAddProxyEvent extends Event implements SubEvent {
private Proxy proxy;
/**
* Proxy Add Event
*
* @param proxy Host Being Added
*/
public SubAddProxyEvent(Proxy proxy) {
Util.nullpo(proxy);
this.proxy = proxy;
}
/**
* Gets the Proxy to be Added
*
* @return The Proxy to be Added
*/
public Proxy getProxy() { return proxy; }
}

View File

@ -1,13 +1,18 @@
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.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* Server Add Event
*/
public class SubAddServerEvent extends Event implements SubEvent, Cancellable {
private boolean cancelled = false;
private UUID player;
@ -18,9 +23,11 @@ public class SubAddServerEvent extends Event implements SubEvent, Cancellable {
* Server Add Event
*
* @param player Player Adding Server
* @param host Host of SubServer (or null for normal Server)
* @param server Server Starting
*/
public SubAddServerEvent(UUID player, Host host, Server server) {
Util.nullpo(server);
this.player = player;
this.host = host;
this.server = server;
@ -28,6 +35,7 @@ public class SubAddServerEvent extends Event implements SubEvent, Cancellable {
/**
* Gets the Server to be Added
*
* @return The Server to be Added
*/
public Server getServer() { return server; }
@ -43,12 +51,14 @@ public class SubAddServerEvent extends Event implements SubEvent, Cancellable {
/**
* Gets the player that triggered the Event
*
* @return The Player that triggered this Event or null if Console
*/
public UUID getPlayer() { return player; }
/**
* Gets the Cancelled Status
*
* @return Cancelled Status
*/
public boolean isCancelled() {

View File

@ -1,22 +1,28 @@
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.Version.Version;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* Server Create Event
*/
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.ServerType type;
private SubCreator.ServerTemplate template;
private Version version;
private int memory;
private int port;
/**
@ -25,21 +31,39 @@ public class SubCreateEvent extends Event implements SubEvent, Cancellable {
* @param player Player Creating
* @param host Potential Host
* @param name Server Name
* @param type Server Type
* @param template Server Template
* @param version Server Version
* @param memory Server RAM Amount
* @param port Server Port Number
*/
public SubCreateEvent(UUID player, Host host, String name, SubCreator.ServerType type, Version version, int memory, int port) {
public SubCreateEvent(UUID player, Host host, String name, SubCreator.ServerTemplate template, Version version, int port) {
Util.nullpo(host, name, template);
this.player = player;
this.host = host;
this.name = name;
this.type = type;
this.template = template;
this.version = version;
this.memory = memory;
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
*
@ -49,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
*
@ -59,21 +101,21 @@ public class SubCreateEvent extends Event implements SubEvent, Cancellable {
}
/**
* Get the type of Server to create
* Get the Template to Use
*
* @return Server Type
* @return Server Template
*/
public SubCreator.ServerType getType() {
return type;
public SubCreator.ServerTemplate getTemplate() {
return template;
}
/**
* Set the Type of Server to Create
* Set the Template to Use
*
* @param value Value
*/
public void setType(SubCreator.ServerType value) {
this.type = value;
public void setTemplate(SubCreator.ServerTemplate value) {
this.template = value;
}
/**
@ -94,24 +136,6 @@ public class SubCreateEvent extends Event implements SubEvent, Cancellable {
this.version = value;
}
/**
* Get the Server RAM Amount (in MB)
*
* @return RAM Amount
*/
public int getMemory() {
return memory;
}
/**
* Set the Server RAM Amount (in MB)
*
* @param value Value
*/
public void setMemory(int value) {
this.memory = value;
}
/**
* Get the Port the Server will use
*
@ -123,12 +147,14 @@ public class SubCreateEvent extends Event implements SubEvent, Cancellable {
/**
* Gets the player that triggered the Event
*
* @return The Player that triggered this Event or null if Console
*/
public UUID getPlayer() { return player; }
/**
* Gets the Cancelled Status
*
* @return Cancelled Status
*/
public boolean isCancelled() {

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,52 +0,0 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.ME1312.SubServers.Bungee.Library.Version.Version;
import net.md_5.bungee.api.plugin.Event;
import org.json.JSONObject;
public class SubDataRecieveGenericInfoEvent extends Event implements SubEvent{
private String handle;
private Version version;
private JSONObject content;
/**
* SubData Generic Info Event
*
* @param handle Content Handle
* @param version Content Version
* @param content Content
*/
public SubDataRecieveGenericInfoEvent(String handle, Version version, JSONObject content) {
this.handle = handle;
this.version = version;
this.content = content;
}
/**
* Get Content Handle
*
* @return Content Handle
*/
public String getHandle() {
return handle;
}
/**
* Get Content Version
*
* @return Content Version
*/
public Version getVersion() {
return version;
}
/**
* Get Content
*
* @return Content
*/
public JSONObject getContent() {
return content;
}
}

View File

@ -0,0 +1,79 @@
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.SubEvent;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* Server Edit Event
*/
public class SubEditServerEvent extends Event implements SubEvent, Cancellable {
private boolean cancelled = false;
private UUID player;
private Server server;
private Pair<String, ObjectMapValue> edit;
/**
* Server Edit Event
*
* @param player Player Adding Server
* @param server Server to be Edited
* @param edit Edit to make
*/
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 ContainedPair<String, ObjectMapValue>(edit.key(), section.get("."));
}
/**
* Gets the Server to be Edited
*
* @return The Server to be Edited
*/
public Server getServer() { return server; }
/**
* Gets the player that triggered the Event
*
* @return The Player that triggered this Event or null if Console
*/
public UUID getPlayer() { return player; }
/**
* Gets the edit to be made
*
* @return Edit to be made
*/
public Pair<String, ObjectMapValue> getEdit() {
return edit;
}
/**
* Gets the Cancelled Status
*
* @return Cancelled Status
*/
public boolean isCancelled() {
return cancelled;
}
/**
* Sets the Cancelled Status
*/
public void setCancelled(boolean value) {
cancelled = value;
}
}

View File

@ -0,0 +1,61 @@
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.Cancellable;
import net.md_5.bungee.api.plugin.Event;
/**
* SubData Network Connect Event
*/
public class SubNetworkConnectEvent extends Event implements SubEvent, Cancellable {
private boolean cancelled = false;
private DataServer network;
private DataClient client;
/**
* SubData Network Connect Event
*/
public SubNetworkConnectEvent(DataServer network, DataClient client) {
Util.nullpo(network, client);
this.network = network;
this.client = client;
}
/**
* Get the network the client is trying to connect to
*
* @return SubData Network
*/
public DataServer getNetwork() {
return network;
}
/**
* Get the connecting client
*
* @return Client
*/
public DataClient getClient() {
return client;
}
/**
* Gets the Cancelled Status
*
* @return Cancelled Status
*/
public boolean isCancelled() {
return cancelled;
}
/**
* Sets the Cancelled Status
*/
public void setCancelled(boolean value) {
cancelled = value;
}
}

View File

@ -0,0 +1,55 @@
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.md_5.bungee.api.plugin.Event;
/**
* SubData Network Disconnect Event
*/
public class SubNetworkDisconnectEvent extends Event implements SubEvent {
private DataServer network;
private DataClient client;
private DisconnectReason reason;
/**
* SubData Network Disconnect Event
*/
public SubNetworkDisconnectEvent(DataServer network, DataClient client, DisconnectReason reason) {
Util.nullpo(network, client, reason);
this.network = network;
this.client = client;
this.reason = reason;
}
/**
* Get the network the client is disconnecting from
*
* @return SubData Network
*/
public DataServer getNetwork() {
return network;
}
/**
* Get the disconnecting client
*
* @return Client
*/
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

@ -0,0 +1,61 @@
package net.ME1312.SubServers.Bungee.Event;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubServers.Bungee.Host.Host;
import net.ME1312.SubServers.Bungee.Library.SubEvent;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* Host Remove Event
*/
public class SubRemoveHostEvent extends Event implements SubEvent, Cancellable {
private boolean cancelled = false;
private UUID player;
private Host host;
/**
* Host Remove Event
*
* @param player Player Adding Server
* @param host Host to be added
*/
public SubRemoveHostEvent(UUID player, Host host) {
Util.nullpo(host);
this.player = player;
this.host = host;
}
/**
* Gets the Host to be Removed
*
* @return The Host to be Removed
*/
public Host getHost() { return host; }
/**
* Gets the player that triggered the Event
*
* @return The Player that triggered this Event or null if Console
*/
public UUID getPlayer() { return player; }
/**
* Gets the Cancelled Status
*
* @return Cancelled Status
*/
public boolean isCancelled() {
return cancelled;
}
/**
* Sets the Cancelled Status
*/
public void setCancelled(boolean value) {
cancelled = value;
}
}

View File

@ -0,0 +1,31 @@
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.md_5.bungee.api.plugin.Event;
/**
* Proxy Remove Event
*/
public class SubRemoveProxyEvent extends Event implements SubEvent {
private Proxy proxy;
/**
* Proxy Remove Event
*
* @param proxy Host Being Added
*/
public SubRemoveProxyEvent(Proxy proxy) {
Util.nullpo(proxy);
this.proxy = proxy;
}
/**
* Gets the Proxy to be Removed
*
* @return The Proxy to be Removed
*/
public Proxy getProxy() { return proxy; }
}

View File

@ -1,13 +1,18 @@
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.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* Server Remove Event
*/
public class SubRemoveServerEvent extends Event implements SubEvent, Cancellable {
private boolean cancelled = false;
private UUID player;
@ -15,20 +20,22 @@ public class SubRemoveServerEvent extends Event implements SubEvent, Cancellable
private Server server;
/**
* Server Add Event
* Server Remove Event
*
* @param player Player Adding Server
* @param host Host of SubServer (or null for normal Server)
* @param server Server Starting
*/
public SubRemoveServerEvent(UUID player, Host host, Server server) {
Util.nullpo(server);
this.player = player;
this.host = host;
this.server = server;
}
/**
* Gets the Server to be Added
* @return The Server to be Added
* Gets the Server to be Removed
* @return The Server to be Removed
*/
public Server getServer() { return server; }
@ -43,12 +50,14 @@ public class SubRemoveServerEvent extends Event implements SubEvent, Cancellable
/**
* Gets the player that triggered the Event
*
* @return The Player that triggered this Event or null if Console
*/
public UUID getPlayer() { return player; }
/**
* Gets the Cancelled Status
*
* @return Cancelled Status
*/
public boolean isCancelled() {

View File

@ -1,38 +1,50 @@
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.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* Server Command Event
*/
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) {
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;
}
/**
* Gets the Server Effected
*
* @return The Server Effected
*/
public SubServer getServer() { return server; }
public Server getServer() { return server; }
/**
* Gets the player that triggered the Event
*
* @return The Player that triggered this Event or null if Console
*/
public UUID getPlayer() { return player; }
@ -55,8 +67,18 @@ 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
*
* @return Cancelled Status
*/
public boolean isCancelled() {

View File

@ -1,12 +1,17 @@
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.Cancellable;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* Server Start Event
*/
public class SubStartEvent extends Event implements SubEvent, Cancellable {
private boolean cancelled = false;
private UUID player;
@ -19,24 +24,28 @@ public class SubStartEvent extends Event implements SubEvent, Cancellable {
* @param server Server Starting
*/
public SubStartEvent(UUID player, SubServer server) {
Util.nullpo(server);
this.player = player;
this.server = server;
}
/**
* Gets the Server Effected
*
* @return The Server Effected
*/
public SubServer getServer() { return server; }
/**
* Gets the player that triggered the Event
*
* @return The Player that triggered this Event or null if Console
*/
public UUID getPlayer() { return player; }
/**
* Gets the Cancelled Status
*
* @return Cancelled Status
*/
public boolean isCancelled() {

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,12 +1,17 @@
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.Cancellable;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* Server Stop Event
*/
public class SubStopEvent extends Event implements SubEvent, Cancellable {
private boolean cancelled = false;
private UUID player;
@ -21,6 +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) {
Util.nullpo(server, force);
this.player = player;
this.server = server;
this.force = force;
@ -28,12 +34,14 @@ public class SubStopEvent extends Event implements SubEvent, Cancellable {
/**
* Gets the Server Effected
*
* @return The Server Effected
*/
public SubServer getServer() { return server; }
/**
* Gets the player that triggered the Event
*
* @return The Player that triggered this Event or null if Console
*/
public UUID getPlayer() { return player; }
@ -49,6 +57,7 @@ public class SubStopEvent extends Event implements SubEvent, Cancellable {
/**
* Gets the Cancelled Status
*
* @return Cancelled Status
*/
public boolean isCancelled() {

View File

@ -1,9 +1,14 @@
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 Shell Exit Event
*/
public class SubStoppedEvent extends Event implements SubEvent {
private SubServer server;
@ -13,11 +18,13 @@ public class SubStoppedEvent extends Event implements SubEvent {
* @param server Server that Stopped
*/
public SubStoppedEvent(SubServer server) {
Util.nullpo(server);
this.server = server;
}
/**
* Gets the Server Effected
*
* @return The Server Effected
*/
public SubServer getServer() { return server; }

View File

@ -1,64 +1,121 @@
package net.ME1312.SubServers.Bungee.Host;
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
*
* @author ME1312
* Executable Handler Class
*/
@SuppressWarnings("serial")
public class Executable implements Serializable {
public 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 (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) {
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;
}
/**
* Get Executable File
*
* @return File or Null if Executable isn't a file
*/
public File toFile() {
return File;
}
}

View File

@ -0,0 +1,328 @@
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.Host;
import net.ME1312.SubServers.Bungee.Host.SubCreator;
import net.ME1312.SubServers.Bungee.Host.SubServer;
import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
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.PacketOutExReset;
import net.ME1312.SubServers.Bungee.SubProxy;
import com.google.common.collect.Range;
import java.net.InetAddress;
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;
private LinkedList<PacketOut> queue;
private boolean clean;
SubProxy plugin;
/**
* Creates an External Host
*
* @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(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.creator = new ExternalSubCreator(this, ports, log, gitBash);
this.directory = directory;
this.queue = new LinkedList<PacketOut>();
this.clean = false;
subdata.put(0, null);
}
@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) {
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 removeSubData(DataClient client) {
for (Integer channel : Util.getBackwards(subdata, (SubDataClient) client)) setSubData(null, channel);
}
void queue(PacketOut... packet) {
for (PacketOut p : packet) if (getSubData()[0] == null || !available) {
queue.add(p);
} else {
((SubDataClient) getSubData()[0]).sendPacket(p);
}
}
private void requeue() {
SubDataClient client = (SubDataClient) getSubData()[0];
if (!clean) {
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()) {
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);
}));
}
}
client.sendPacket(payload);
available = true;
while (this.queue.size() != 0) {
client.sendPacket(this.queue.remove(0));
}
}
@Override
public boolean isAvailable() {
return available;
}
@Override
public boolean isEnabled() {
return enabled;
}
@Override
public void setEnabled(boolean value) {
this.enabled = value;
}
@Override
public InetAddress getAddress() {
return address;
}
@Override
public String getPath() {
return directory;
}
@Override
public String getName() {
return name;
}
@Override
public SubCreator getCreator() {
return creator;
}
@Override
public Map<String, ? extends SubServer> getSubServers() {
return new TreeMap<String, SubServer>(servers);
}
@Override
public SubServer getSubServer(String name) {
if (Util.isNull(name)) return null;
return servers.get(name.toLowerCase());
}
@Override
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(((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 false;
}
}
@Override
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, server);
plugin.getPluginManager().callEvent(event);
if (forced || !event.isCancelled()) {
server.registered(false);
if (server.isRunning()) {
server.stop();
server.waitFor();
}
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;
} else return false;
}
@Override
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, s);
plugin.getPluginManager().callEvent(event);
if (forced || !event.isCancelled()) {
s.registered(false);
if (s.isRunning()) {
s.stop();
s.waitFor();
}
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("Moving Files...");
queue(new PacketExDeleteServer(server, info, true, 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
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 (forced || !event.isCancelled()) {
s.registered(false);
if (s.isRunning()) {
s.stop();
s.waitFor();
}
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

@ -0,0 +1,367 @@
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.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
*/
@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, Pair<Integer, ExternalSubLogger>> thread;
/**
* Creates an External SubCreator
*
* @param host Host
* @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, 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, Pair<Integer, ExternalSubLogger>>();
reload();
}
@Override
public void reload() {
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() && !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) {
Logger.get(host.getName()).severe("Couldn't load template: " + file.getName());
e.printStackTrace();
}
}
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, 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(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;
} else {
thread.remove(name.toLowerCase());
return false;
}
} else return false;
} 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);
}
}
@Override
public void terminate() {
HashMap<String, Pair<Integer, ExternalSubLogger>> thread = new HashMap<String, Pair<Integer, ExternalSubLogger>>();
thread.putAll(this.thread);
for (String i : thread.keySet()) {
terminate(i);
}
}
@Override
public void terminate(String name) {
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, Pair<Integer, ExternalSubLogger>> thread = new HashMap<String, Pair<Integer, ExternalSubLogger>>();
thread.putAll(this.thread);
for (String i : thread.keySet()) {
waitFor(i);
}
}
@Override
public void waitFor(String name) throws InterruptedException {
while (this.thread.containsKey(name.toLowerCase()) && host.getSubData()[0] != null) {
Thread.sleep(250);
}
}
@Override
public Host getHost() {
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> 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()).value();
}
@Override
public boolean isLogging() {
return log.value();
}
@Override
public void setLogging(boolean value) {
Util.nullpo(value);
log.value(value);
}
@Override
public List<String> getReservedNames() {
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() {
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) {
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

@ -0,0 +1,177 @@
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.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketInExLogMessage;
import net.ME1312.SubServers.Bungee.SubAPI;
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.Calendar;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
/**
* External Process Logger Class
*/
public class ExternalSubLogger extends SubLogger {
private Object handle;
UUID id = null;
String name;
Value<Boolean> log;
private List<SubLogFilter> filters = new CopyOnWriteArrayList<>();
File file;
private PrintWriter writer = null;
private boolean started = false;
/**
* Creates a new External Logger
*
* @param user Object using this logger (or null)
* @param name Prefix
* @param log Console Logging Status
* @param file File to log to (or null for disabled)
*/
ExternalSubLogger(Object user, String name, Value<Boolean> log, File file) {
this.handle = user;
this.name = name;
this.log = log;
this.file = file;
}
@Override
public void start() {
id = PacketInExLogMessage.register(this);
started = true;
if (file != null && writer == null) {
try {
this.writer = new PrintWriter(file, "UTF-8");
this.writer.println("---------- LOG START \u2014 " + name + " ----------");
this.writer.flush();
} catch (UnsupportedEncodingException | FileNotFoundException e) {
e.printStackTrace();
}
}
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();
}
}
@SuppressWarnings("deprecation")
private void log(int type, String msg) {
if (started) {
Level level;
// Determine LOG LEVEL
switch (type) {
case 80:
level = Level.FINE;
break;
case 40:
level = Level.WARNING;
break;
case 30:
case 20:
level = Level.SEVERE;
break;
default:
level = Level.INFO;
}
// 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, msg) && allow);
} catch (Throwable e) {
new InvocationTargetException(e, "Exception while running SubLogger Event").printStackTrace();
}
// Log to CONSOLE
if (allow) Logger.get(name).log(level, msg);
// Log to FILE
if (writer != null) {
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) {
Util.nullpo(filter);
filters.add(filter);
}
@Override
public void unregisterFilter(SubLogFilter filter) {
Util.nullpo(filter);
Try.all.run(() -> filters.remove(filter));
}
@Override
public void stop() {
if (started) {
id = null;
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();
}
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 += '-';
writer.println(s + " LOG END " + s);
writer.close();
}
}
}
@Override
public Object getHandler() {
return handle;
}
@Override
public String getName() {
return name;
}
@Override
public boolean isLogging() {
return log.value();
}
}

View File

@ -0,0 +1,604 @@
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.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
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.api.ChatColor;
import java.io.IOException;
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 SubServerImpl {
private ExternalHost host;
private boolean enabled;
private Value<Boolean> log;
private String dir;
String exec;
private String stopcmd;
private StopAction stopaction;
private LinkedList<LoggedCommand> history;
private ExternalSubLogger logger;
private boolean running;
private boolean lock;
/**
* Creates an External SubServer
*
* @param host Host
* @param name Name
* @param enabled Enabled Status
* @param port Port Number
* @param motd MOTD
* @param log Logging Status
* @param directory Directory
* @param executable Executable
* @param stopcmd Stop Command
* @param hidden Hidden Status
* @param restricted Restricted Status
* @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);
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);
this.dir = directory;
this.exec = executable;
this.stopcmd = stopcmd;
this.stopaction = StopAction.NONE;
this.history = new LinkedList<LoggedCommand>();
this.logger = new ExternalSubLogger(this, getName(), this.log, null);
this.running = false;
this.lock = false;
}
void registered(boolean value) {
registered = value;
}
void updating(boolean value) {
updating = value;
}
@Override
public boolean start(UUID player) {
if (!lock && isAvailable() && isEnabled() && !running && getCurrentIncompatibilities().size() == 0) {
lock = true;
SubStartEvent event = new SubStartEvent(player, this);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
Logger.get("SubServers").info("Now starting " + getName());
started(null);
host.queue(new PacketExControlServer(this, Action.START, logger.getExternalAddress().toString()));
return true;
} 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() {
Logger.get("SubServers").info("Couldn't start " + getName() + " - See the " + host.getName() + " console for more details");
running = false;
logger.stop();
}
@Override
public boolean stop(UUID player) {
if (running) {
SubStopEvent event = new SubStopEvent(player, this, false);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
history.add(new LoggedCommand(player, stopcmd));
host.queue(new PacketExControlServer(this, Action.STOP));
stopping = true;
return true;
} else return false;
} else return false;
}
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.RECYCLE_SERVER || stopaction == StopAction.DELETE_SERVER) {
try {
if (stopaction == StopAction.RECYCLE_SERVER) {
host.recycleSubServer(getName());
} else if (stopaction == StopAction.DELETE_SERVER) {
host.deleteSubServer(getName());
} else {
try {
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();
}
host.removeSubServer(getName());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} else if (stopaction == StopAction.RESTART) {
if (allowrestart) {
new Thread(() -> {
try {
Thread.sleep(250);
start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "SubServers.Bungee::External_Server_Restart_Handler(" + getName() + ')').start();
}
}
}
@Override
public boolean terminate(UUID player) {
if (running) {
SubStopEvent event = new SubStopEvent(player, this, true);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
host.queue(new PacketExControlServer(this, Action.TERMINATE));
stopping = true;
return true;
} else return false;
} else return false;
}
@Override
public boolean command(UUID player, String command) {
Util.nullpo(command);
if (running) {
SubSendCommandEvent event = new SubSendCommandEvent(player, this, command, null);
host.plugin.getPluginManager().callEvent(event);
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 PacketExControlServer(this, Action.STOP));
stopping = true;
} else {
host.queue(new PacketExControlServer(this, Action.COMMAND, event.getCommand()));
}
return true;
} else return false;
} else return false;
}
@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++;
}
}
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 "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++;
}
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++;
}
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++;
}
}
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++;
}
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++;
}
}
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;
}
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 += (perma)?forward.permaEdit(player, pending):forward.edit(player, pending);
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
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.getSubData()[0] != null) {
Thread.sleep(250);
}
}
@Override
public boolean isRunning() {
return running || lock;
}
@Override
public void setDisplayName(String value) {
super.setDisplayName(value);
logger.name = getDisplayName();
}
@Override
public Host getHost() {
return host;
}
@Override
public boolean isEnabled() {
return enabled && host.isEnabled();
}
@Override
public void setEnabled(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.value();
}
@Override
public void setLogging(boolean value) {
Util.nullpo(value);
if (log.value() != value) host.queue(new PacketExControlServer(this, Action.SET_LOGGING, (Boolean) value));
log.value(value);
}
@Override
public SubLogger getLogger() {
return logger;
}
@Override
public LinkedList<LoggedCommand> getCommandHistory() {
return new LinkedList<LoggedCommand>(history);
}
@Override
public String getPath() {
return dir;
}
@Override
public String getExecutable() {
return exec;
}
@Override
public String getStopCommand() {
return stopcmd;
}
@Override
public void setStopCommand(String value) {
Util.nullpo(value);
if (!stopcmd.equals(value)) host.queue(new PacketExControlServer(this, Action.SET_STOP_COMMAND, value));
stopcmd = value;
}
@Override
public StopAction getStopAction() {
return stopaction;
}
@Override
public void setStopAction(StopAction action) {
Util.nullpo(action);
stopaction = action;
}
}

View File

@ -1,33 +1,60 @@
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.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.NamedContainer;
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
*
* @author ME1312
*/
public abstract class Host {
public abstract class Host implements ExtraDataHandler<String> {
private final ObjectMap<String> extra = new ObjectMap<String>();
private final String signature;
private String nick = null;
/**
* This constructor is required to launch your host from the drivers list. Do not add or remove any arguments.
*
* @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();
SubAPI.getInstance().getInternals().subprotocol.whitelist(address.getHostAddress());
}
/**
* Is this Host Available?
*
* @return Availability Status
*/
public boolean isAvailable() {
return true;
}
/**
@ -52,11 +79,11 @@ public abstract class Host {
public abstract InetAddress getAddress();
/**
* Get the Directory of this Host
* Get the host Directory Path
*
* @return Host Directory
* @return Host Directory Path
*/
public abstract String getDirectory();
public abstract String getPath();
/**
* Get the Name of this Host
@ -65,6 +92,54 @@ public abstract class Host {
*/
public abstract String getName();
/**
* Get the Display Name of this Host
*
* @return Display Name
*/
public String getDisplayName() {
return (nick == null)?getName():nick;
}
/**
* Sets the Display Name for this Host
*
* @param value Value (or null to reset)
*/
public void setDisplayName(String value) {
if (value == null || value.length() == 0 || getName().equals(value)) {
this.nick = null;
} else {
this.nick = value;
}
}
/**
* 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
*
@ -82,7 +157,13 @@ public abstract class Host {
* @param servers Servers
* @return Success Status
*/
public abstract int start(UUID player, String... servers);
public int start(UUID player, String... servers) {
int i = 0;
for (String server : servers) {
if (getSubServer(server.toLowerCase()).start(player)) i++;
}
return i;
}
/**
* Stops the Servers Specified
@ -101,7 +182,13 @@ public abstract class Host {
* @param servers Servers
* @return Success Status
*/
public abstract int stop(UUID player, String... servers);
public int stop(UUID player, String... servers) {
int i = 0;
for (String server : servers) {
if (getSubServer(server.toLowerCase()).stop(player)) i++;
}
return i;
}
/**
* Terminates the Servers Specified
@ -120,7 +207,13 @@ public abstract class Host {
* @param servers Servers
* @return Success Status
*/
public abstract int terminate(UUID player, String... servers);
public int terminate(UUID player, String... servers) {
int i = 0;
for (String server : servers) {
if (getSubServer(server.toLowerCase()).terminate(player)) i++;
}
return i;
}
/**
* Commands the Servers Specified
@ -141,7 +234,13 @@ public abstract class Host {
* @param servers Servers
* @return Success Status
*/
public abstract int command(UUID player, String command, String... servers);
public int command(UUID player, String command, String... servers) {
int i = 0;
for (String server : servers) {
if (getSubServer(server.toLowerCase()).command(player, command)) i++;
}
return i;
}
/**
* Gets the SubCreator Instance for this Host
@ -166,25 +265,22 @@ public abstract class Host {
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 restart Auto Restart Status
* @param hidden if the server should be hidden from players
* @param restricted Players will need a permission to join if true
* @param temporary Temporary Status
* @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 start, boolean restart, boolean hidden, boolean restricted, boolean temporary) 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
@ -195,19 +291,58 @@ public abstract class Host {
* @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 restart Auto Restart Status
* @param hidden if the server should be hidden from players
* @param restricted Players will need a permission to join if true
* @param temporary Temporary Status
* @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 start, boolean restart, boolean hidden, boolean restricted, boolean temporary) throws InvalidServerException {
return addSubServer(null, name, enabled, port, motd, log, directory, executable, stopcmd, start, restart, hidden, restricted, temporary);
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
*
@ -217,7 +352,7 @@ public abstract class Host {
*/
public boolean removeSubServer(String name) throws InterruptedException {
return removeSubServer(null, name);
};
}
/**
* Removes a SubServer
@ -227,14 +362,28 @@ public abstract class Host {
* @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) {
public boolean forceRemoveSubServer(String name) throws InterruptedException {
return forceRemoveSubServer(null, name);
}
@ -243,7 +392,206 @@ public abstract class Host {
*
* @param player Player Removing
* @param name SubServer Name
* @return Success Status
*/
public abstract boolean forceRemoveSubServer(UUID player, String name);
public boolean forceRemoveSubServer(UUID player, String name) throws InterruptedException {
return removeSubServer(player, name, true);
}
/**
* 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
*/
public boolean deleteSubServer(String name) throws InterruptedException {
return deleteSubServer(null, name);
}
/**
* Deletes a SubServer
*
* @param player Player Deleting
* @param name SubServer Name
* @return Success Status
*/
public boolean deleteSubServer(UUID player, String name) throws InterruptedException {
return deleteSubServer(player, name, false);
}
/**
* 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 forceDeleteSubServer(null, name);
}
/**
* Forces the Deletion of a SubServer
*
* @param player Player Deleting
* @param name SubServer Name
* @return Success Status
*/
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
*
* @return Object Signature
*/
public final String getSignature() {
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) {
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);
}
public ObjectMap<String> forSubData() {
ObjectMap<String> hinfo = new ObjectMap<String>();
hinfo.set("type", "Host");
hinfo.set("name", getName());
hinfo.set("display", getDisplayName());
hinfo.set("available", isAvailable());
hinfo.set("enabled", isEnabled());
hinfo.set("address", getAddress().getHostAddress());
hinfo.set("dir", getPath());
ObjectMap<String> cinfo = new ObjectMap<String>();
ObjectMap<String> templates = new ObjectMap<String>();
for (SubCreator.ServerTemplate template : getCreator().getTemplates().values())
templates.set(template.getName(), template.forSubData());
cinfo.set("templates", templates);
hinfo.set("creator", cinfo);
ObjectMap<String> servers = new ObjectMap<String>();
for (SubServer server : getSubServers().values()) {
servers.set(server.getName(), server.forSubData());
}
hinfo.set("servers", servers);
hinfo.set("signature", signature);
hinfo.set("extra", getExtra());
return hinfo;
}
}

View File

@ -1,38 +1,60 @@
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.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.NamedContainer;
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;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;
import java.util.*;
/**
* Internal Host Class
*/
public class InternalHost extends Host {
HashMap<String, SubServer> servers = new HashMap<String, SubServer>();
public static final boolean DRM_ALLOW = System.getProperty("RM.subservers", "true").equalsIgnoreCase("true");
private HashMap<String, SubServer> servers = new HashMap<String, SubServer>();
private String name;
private boolean enabled;
private InetAddress address;
private InternalSubCreator creator;
private SubCreator creator;
private String directory;
SubPlugin plugin;
SubProxy plugin;
public InternalHost(SubPlugin plugin, String name, Boolean enabled, InetAddress address, String directory, String gitBash) {
super(plugin, name, enabled, address, directory, gitBash);
/**
* Creates an Internal Host
*
* @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(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");
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;
}
@ -52,7 +74,7 @@ public class InternalHost extends Host {
}
@Override
public String getDirectory() {
public String getPath() {
return directory;
}
@ -61,42 +83,6 @@ public class InternalHost extends Host {
return name;
}
@Override
public int start(UUID player, String... servers) {
int i = 0;
for (String server : servers) {
if (this.servers.get(server.toLowerCase()).start(player)) i++;
}
return i;
}
@Override
public int stop(UUID player, String... servers) {
int i = 0;
for (String server : servers) {
if (this.servers.get(server.toLowerCase()).stop(player)) i++;
}
return i;
}
@Override
public int terminate(UUID player, String... servers) {
int i = 0;
for (String server : servers) {
if (this.servers.get(server.toLowerCase()).terminate(player)) i++;
}
return i;
}
@Override
public int command(UUID player, String command, String... servers) {
int i = 0;
for (String server : servers) {
if (this.servers.get(server.toLowerCase()).command(player, command)) i++;
}
return i;
}
@Override
public SubCreator getCreator() {
return creator;
@ -109,46 +95,156 @@ public class InternalHost extends Host {
@Override
public SubServer getSubServer(String name) {
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 start, boolean restart, boolean hidden, boolean restricted, boolean temporary) 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, start, restart, hidden, restricted, temporary);
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 {
SubRemoveServerEvent event = new SubRemoveServerEvent(player, this, getSubServer(name));
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(name).isRunning()) {
getSubServer(name).stop();
getSubServer(name).waitFor();
if (forced || !event.isCancelled()) {
server.registered(false);
if (server.isRunning()) {
server.stop();
server.waitFor();
}
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) {
SubRemoveServerEvent event = new SubRemoveServerEvent(player, this, getSubServer(name));
plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
if (getSubServer(name).isRunning()) {
getSubServer(name).terminate();
}
servers.remove(name.toLowerCase());
protected boolean recycleSubServer(UUID player, String name, boolean forced) throws InterruptedException {
return recycleSubServer(player, name, forced, true);
}
/**
* 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, forced)) {
Runnable method = () -> {
File to = new File(plugin.dir, "SubServers/Recently Deleted/" + server.toLowerCase());
try {
if (from.exists()) {
Logger.get("SubServers").info("Moving Files...");
if (to.exists()) {
if (to.isDirectory()) Directories.delete(to);
else to.delete();
}
to.mkdirs();
Directories.copy(from, to);
Directories.delete(from);
}
} catch (Exception e) {
e.printStackTrace();
}
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.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(new Gson().toJson(info.get()));
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
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,111 +1,224 @@
package net.ME1312.SubServers.Bungee.Host.Internal;
import net.ME1312.SubServers.Bungee.Library.Container;
import net.md_5.bungee.api.ProxyServer;
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.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.SubAPI;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class InternalSubLogger {
private Process process;
private String name;
private Container<Boolean> log;
/**
* Internal Process Logger Class
*/
public class InternalSubLogger extends SubLogger {
Process process;
private Object handle;
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;
private Thread err = null;
InternalSubLogger(Process process, String name, Container<Boolean> log, File file) {
/**
* Creates a new Internal Process Logger
*
* @param process Process
* @param user Object using this logger (or null)
* @param name Prefix
* @param log Console Logging Status
* @param file File to log to (or null for disabled)
*/
InternalSubLogger(Process process, Object user, String name, Value<Boolean> log, File file) {
this.process = process;
this.handle = user;
this.name = name;
this.log = log;
if (file != null)
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;
if (file != null && writer == null) {
try {
this.writer = new PrintWriter(file, "UTF-8");
this.writer.println("---------- LOG START \u2014 " + name + " ----------");
this.writer.flush();
} catch (UnsupportedEncodingException | FileNotFoundException e) {
e.printStackTrace();
}
}
public void start() {
started = true;
if (writer != null) {
this.writer.println("---------- LOG START: " + name + " ----------");
this.writer.flush();
}
new Thread(() -> {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
if (!line.startsWith(">")) {
if (log.get()) {
String msg = line;
// REGEX Formatting
String type = "INFO";
Matcher matcher = Pattern.compile("^((?:\\s*\\[?[0-9]{2}:[0-9]{2}:[0-9]{2}]?)?\\s*(?:\\[|\\[.*\\/)?(INFO|WARN|WARNING|ERROR|ERR|SEVERE)\\]:?\\s*)").matcher(msg);
while (matcher.find()) {
type = matcher.group(2);
}
msg = msg.replaceAll("^((?:\\s*\\[?[0-9]{2}:[0-9]{2}:[0-9]{2}]?)?\\s*(?:\\[|\\[.*\\/)?(INFO|WARN|WARNING|ERROR|ERR|SEVERE)\\]:?\\s*)", "");
switch (type) {
case "INFO":
ProxyServer.getInstance().getLogger().info(name + " > " + msg);
break;
case "WARNING":
case "WARN":
ProxyServer.getInstance().getLogger().warning(name + " > " + msg);
break;
case "SEVERE":
case "ERROR":
case "ERR":
ProxyServer.getInstance().getLogger().severe(name + " > " + msg);
break;
}
}
if (writer != null) {
writer.println(line);
writer.flush();
}
}
}
} catch (IOException ioe) {
} finally {
stop();
}
}).start();
new Thread(() -> {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line;
while ((line = br.readLine()) != null) {
if (!line.startsWith(">")) {
if (log.get()) {
String msg = line;
msg = msg.replaceAll("^((?:\\s*\\[?[0-9]{2}:[0-9]{2}:[0-9]{2}]?)?\\s*(?:\\[|\\[.*\\/)?(INFO|WARN|WARNING|ERROR|ERR|SEVERE)\\]:?\\s*)", "");
ProxyServer.getInstance().getLogger().severe(name + " > " + msg);
}
if (writer != null) {
writer.println(line);
writer.flush();
}
}
}
} catch (IOException ioe) {
} finally {
stop();
}
}).start();
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();
}
private void stop() {
if (started) {
started = false;
@SuppressWarnings("deprecation")
private void start(InputStream in, boolean isErr) {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null) {
log(line);
}
} catch (IOException e) {} finally {
if (isErr) {
err = null;
} else {
out = null;
}
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("---------- END LOG ----------");
writer.close();
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() {
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) {
Util.nullpo(filter);
filters.add(filter);
}
@Override
public void unregisterFilter(SubLogFilter filter) {
Util.nullpo(filter);
Try.all.run(() -> filters.remove(filter));
}
@Override
public Object getHandler() {
return handle;
}
@Override
public String getName() {
return name;
}
@Override
public boolean isLogging() {
return log.value();
}
}

View File

@ -1,118 +1,261 @@
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.Executable;
import net.ME1312.SubServers.Bungee.Library.Container;
import net.ME1312.SubServers.Bungee.Host.*;
import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import net.ME1312.SubServers.Bungee.Host.Host;
import net.ME1312.SubServers.Bungee.Host.SubServer;
import net.ME1312.SubServers.Bungee.Library.NamedContainer;
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 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;
import java.util.UUID;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
public class InternalSubServer extends SubServer {
/**
* Internal SubServer Class
*/
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;
private Process process;
private InternalSubLogger logger;
private Thread thread;
private BufferedWriter command;
private boolean restart;
private boolean allowrestart;
private boolean temporary;
private boolean lock;
public InternalSubServer(Host host, String name, boolean enabled, int port, String motd, boolean log, String directory, Executable executable, String stopcmd, boolean start, boolean restart, boolean hidden, boolean restricted, boolean temporary) throws InvalidServerException {
/**
* Creates an Internal SubServer
*
* @param host Host
* @param name Name
* @param enabled Enabled Status
* @param port Port Number
* @param motd MOTD
* @param log Logging Status
* @param directory Directory
* @param executable Executable String
* @param stopcmd Stop Command
* @param hidden Hidden Status
* @param restricted Restricted Status
* @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);
this.host = (InternalHost) host;
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);
this.directory = new File(host.getDirectory(), directory);
this.dir = directory;
this.directory = new File(host.getPath(), directory);
this.executable = executable;
this.stopcmd = stopcmd;
this.stopaction = StopAction.NONE;
this.history = new LinkedList<LoggedCommand>();
this.process = null;
this.logger = new InternalSubLogger(null, this, getName(), this.log, null);
this.thread = null;
this.command = null;
this.restart = restart;
this.temporary = temporary;
final File[] locations = new File[] {
new File(this.directory, "plugins/SubServers.Client.jar"),
new File(this.directory, "mods/SubServers.Client.jar")
};
if (start || temporary) start();
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) {
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();
}
}
}
this.lock = false;
}
void registered(boolean value) {
registered = value;
}
void updating(boolean value) {
updating = value;
}
private void run() {
(thread = new Thread(() -> {
allowrestart = true;
try {
process = Runtime.getRuntime().exec(executable.toString(), null, directory);
System.out.println("SubServers > Now starting " + getName());
final InternalSubLogger read = new InternalSubLogger(process, getName(), log, null);
read.start();
command = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
try {
process.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
allowrestart = false;
boolean locked = lock;
allowrestart = true;
stopping = false;
started = false;
try {
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());
this.command.newLine();
this.command.flush();
}
SubStoppedEvent event = new SubStoppedEvent(this);
host.plugin.getPluginManager().callEvent(event);
System.out.println("SubServers > " + getName() + " has stopped");
process = null;
command = null;
if (process.isAlive()) process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
if (locked) lock = false;
allowrestart = false;
}
if (temporary) {
try {
host.removeSubServer(getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
if (restart && allowrestart) {
logger.destroy();
Logger.get("SubServers").info(getName() + " has stopped");
process = null;
command = null;
started = false;
stopping = false;
history.clear();
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.RECYCLE_SERVER) {
host.recycleSubServer(null, getName(), false, false);
} else if (stopaction == StopAction.DELETE_SERVER) {
host.deleteSubServer(null, getName(), false, false);
} else {
try {
Thread.sleep(2500);
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();
}
host.removeSubServer(getName());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} else if (stopaction == StopAction.RESTART) {
if (allowrestart) {
new Thread(() -> {
try {
while (thread != null && thread.isAlive()) {
Thread.sleep(250);
}
start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "SubServers.Bungee::Internal_Server_Restart_Handler(" + getName() + ')').start();
}
})).start();
}
}
@Override
public boolean start(UUID player) {
if (enabled && !isRunning()) {
if (!lock && isAvailable() && isEnabled() && !(thread != null && thread.isAlive()) && getCurrentIncompatibilities().size() == 0) {
lock = true;
SubStartEvent event = new SubStartEvent(player, this);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
run();
(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;
}
@Override
public boolean stop(UUID player) {
if (isRunning()) {
if (thread != null && thread.isAlive()) {
SubStopEvent event = new SubStopEvent(player, this, false);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
try {
stopping = true;
allowrestart = false;
command.write(stopcmd);
command.newLine();
command.flush();
history.add(new LoggedCommand(player, stopcmd));
if (process != null && process.isAlive()) {
command.write(stopcmd);
command.newLine();
command.flush();
}
return true;
} catch (IOException e) {
e.printStackTrace();
@ -124,12 +267,13 @@ public class InternalSubServer extends SubServer {
@Override
public boolean terminate(UUID player) {
if (isRunning()) {
if (thread != null && thread.isAlive()) {
SubStopEvent event = new SubStopEvent(player, this, true);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
stopping = true;
allowrestart = false;
process.destroyForcibly();
if (process != null && process.isAlive()) Executable.terminate(process);
return true;
} else return false;
} else return false;
@ -137,15 +281,22 @@ public class InternalSubServer extends SubServer {
@Override
public boolean command(UUID player, String command) {
if (isRunning()) {
SubSendCommandEvent event = new SubSendCommandEvent(player, this, command);
Util.nullpo(command);
if (thread != null && thread.isAlive()) {
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;
this.command.write(event.getCommand());
this.command.newLine();
this.command.flush();
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());
this.command.newLine();
this.command.flush();
}
return true;
} catch (IOException e) {
e.printStackTrace();
@ -155,6 +306,277 @@ public class InternalSubServer extends SubServer {
} else return false;
}
@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++;
}
}
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 "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++;
}
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++;
}
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++;
}
}
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++;
}
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++;
}
}
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;
}
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 += (perma)?forward.permaEdit(player, pending):forward.edit(player, pending);
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (!isRunning() && forward == null && state) start(player);
return c;
} else return -1;
}
@Override
public void waitFor() throws InterruptedException {
while (thread != null && thread.isAlive()) {
@ -164,7 +586,13 @@ public class InternalSubServer extends SubServer {
@Override
public boolean isRunning() {
return process != null && process.isAlive();
return (process != null && process.isAlive()) || lock;
}
@Override
public void setDisplayName(String value) {
super.setDisplayName(value);
logger.name = getDisplayName();
}
@Override
@ -174,22 +602,44 @@ public class InternalSubServer extends SubServer {
@Override
public boolean isEnabled() {
return enabled;
return enabled && host.isEnabled();
}
@Override
public void setEnabled(boolean value) {
Util.nullpo(value);
enabled = value;
}
@Override
public boolean isLogging() {
return log.get();
return log.value();
}
@Override
public void setLogging(boolean value) {
log.set(value);
Util.nullpo(value);
log.value(value);
}
@Override
public SubLogger getLogger() {
return logger;
}
@Override
public LinkedList<LoggedCommand> getCommandHistory() {
return new LinkedList<LoggedCommand>(history);
}
@Override
public String getPath() {
return dir;
}
@Override
public String getExecutable() {
return executable;
}
@Override
@ -199,21 +649,18 @@ public class InternalSubServer extends SubServer {
@Override
public void setStopCommand(String value) {
Util.nullpo(value);
stopcmd = value;
}
@Override
public boolean willAutoRestart() {
return restart;
public StopAction getStopAction() {
return stopaction;
}
@Override
public void setAutoRestart(boolean value) {
restart = value;
}
@Override
public boolean isTemporary() {
return temporary;
public void setStopAction(StopAction action) {
Util.nullpo(action);
stopaction = action;
}
}

View File

@ -0,0 +1,211 @@
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.Network.Packet.PacketExSyncPlayer;
import net.ME1312.SubServers.Bungee.SubAPI;
import net.ME1312.SubServers.Bungee.SubProxy;
import net.md_5.bungee.api.ProxyServer;
import java.util.*;
/**
* Proxy Class
*/
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 = false;
private String nick = null;
private final String name;
public Proxy(String name) throws IllegalArgumentException {
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 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;
}
@SuppressWarnings("deprecation")
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 (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);
}
/**
* Get the Name of this Proxy
*
* @return Name
*/
public String getName() {
return name;
}
/**
* Get the Display Name of this Proxy
*
* @return Display Name
*/
public String getDisplayName() {
return (nick == null)?getName():nick;
}
/**
* Sets the Display Name for this Proxy
*
* @param value Value (or null to reset)
*/
public void setDisplayName(String value) {
if (value == null || value.length() == 0 || getName().equals(value)) {
this.nick = null;
} else {
this.nick = value;
}
}
/**
* Determine if the proxy is the Master Proxy
*
* @return Master Proxy Status
*/
public boolean isMaster() {
return SubAPI.getInstance().getMasterProxy() == this;
}
/**
* Get the players on this proxy
*
* @return Remote Player Collection
*/
@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
*
* @return Object Signature
*/
public final String getSignature() {
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) {
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", "Proxy");
info.set("name", getName());
info.set("display", getDisplayName());
ObjectMap<String> players = new ObjectMap<String>();
for (RemotePlayer player : getPlayers())
players.set(player.getUniqueId().toString(), player.getName());
info.set("players", players);
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;
}
}

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,100 +1,178 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import net.ME1312.SubServers.Bungee.Network.Client;
import net.ME1312.SubServers.Bungee.Network.ClientHandler;
import net.md_5.bungee.BungeeServerInfo;
import net.md_5.bungee.api.ChatColor;
import net.ME1312.Galaxi.Library.ExtraDataHandler;
import net.ME1312.SubData.Server.ClientHandler;
import net.ME1312.SubData.Server.DataClient;
import java.net.InetSocketAddress;
import net.md_5.bungee.api.config.ServerInfo;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
/**
* Server Class
*
* @author ME1312
* Server Interface
*/
public class Server extends BungeeServerInfo implements ClientHandler {
private Client client = null;
private String motd;
private boolean restricted;
private boolean hidden;
public interface Server extends ServerInfo, ClientHandler, ExtraDataHandler<String> {
public Server(String name, InetSocketAddress address, String motd, boolean hidden, boolean restricted) throws InvalidServerException {
super(name, address, ChatColor.translateAlternateColorCodes('&', motd), restricted);
if (name.contains(" ")) throw new InvalidServerException("Server names cannot have spaces: " + name);
this.motd = motd;
this.restricted = restricted;
this.hidden = hidden;
/**
* 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
*
* @return Display Name
*/
String getDisplayName();
/**
* Sets the Display Name for this Server
*
* @param value Value (or null to reset)
*/
void setDisplayName(String value);
/**
* Get this Server's Groups
*
* @return Group names
*/
List<String> getGroups();
/**
* Add this Server to a Group
*
* @param value Group name
*/
void addGroup(String value);
/**
* Remove this Server from a Group
*
* @param value value Group name
*/
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);
}
@Override
public Client getSubDataClient() {
return client;
/**
* Commands the Server
*
* @param command Command to Send
*/
default boolean command(String command) {
return command(null, command);
}
@Override
public void linkSubDataClient(Client client) {
if (this.client == null) {
client.setHandler(this);
this.client = client;
} else if (client == null) {
this.client = null;
} else throw new IllegalStateException("A SubData Client is already linked to Server: " + getName());
}
/**
* Get players on this server across all known proxies
*
* @return Remote Player Collection
*/
Collection<RemotePlayer> getRemotePlayers();
/**
* If the server is hidden from players
*
* @return Hidden Status
*/
public boolean isHidden() {
return hidden;
}
boolean isHidden();
/**
* Set if the server is hidden from players
*
* @param value Value
*/
public void setHidden(boolean value) {
this.hidden = value;
}
void setHidden(boolean value);
/**
* Gets the MOTD of the Server
*
* @return Server MOTD
*/
@Override
public String getMotd() {
return motd;
}
String getMotd();
/**
* Sets the MOTD of the Server
*
* @param value Value
*/
public void setMotd(String value) {
this.motd = value;
}
void setMotd(String value);
/**
* Gets if the Server is Restricted
*
* @return Restricted Status
*/
@Override
public boolean isRestricted() {
return restricted;
}
boolean isRestricted();
/**
* Sets if the Server is Restricted
*
* @param value Value
*/
public void setRestricted(boolean value) {
this.restricted = value;
}
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
*
* @return Object Signature
*/
String getSignature();
}

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,19 +1,225 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.SubServers.Bungee.Library.Version.Version;
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.SubAPI;
import java.util.UUID;
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
*
* @author ME1312
*/
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 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, 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.getString("Server-Type").toUpperCase()):ServerType.CUSTOM;
this.build = build;
this.options = options;
this.dynamic = dynamic;
}
/**
* Get the Name of this Template
*
* @return Template Name
*/
public String getName() {
return name;
}
/**
* Get the Display Name of this Template
*
* @return Display Name
*/
public String getDisplayName() {
return (nick == null)?getName():nick;
}
/**
* Sets the Display Name for this Template
*
* @param value Value (or null to reset)
*/
public void setDisplayName(String value) {
if (value == null || value.length() == 0 || getName().equals(value)) {
this.nick = null;
} else {
this.nick = value;
}
}
/**
* Get the Enabled Status of this Template
*
* @return Enabled Status
*/
public boolean isEnabled() {
return enabled;
}
/**
* Set the Enabled Status of this Template
*
* @param value Value
*/
public void setEnabled(boolean value) {
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
*
* @return Item Icon Name/ID
*/
public String getIcon() {
return icon;
}
/**
* Set the Item Icon for this Template
*
* @param value Value
*/
public void setIcon(String value) {
icon = value;
}
/**
* Get the Directory for this Template
*
* @return Directory
*/
public File getDirectory() {
return directory;
}
/**
* Get the Type of this Template
*
* @return Template Type
*/
public ServerType getType() {
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 ObjectMap<String> getBuildOptions() {
return build;
}
/**
* Get the Configuration Options for this Template
*
* @return Configuration Options
*/
public ObjectMap<String> getConfigOptions() {
return options;
}
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());
tinfo.set("version-req", requiresVersion());
tinfo.set("can-update", canUpdate());
return tinfo;
}
}
public enum ServerType {
SPIGOT,
VANILLA,
FORGE,
SPONGE,
CUSTOM;
@Override
public String toString() {
return super.toString().substring(0, 1).toUpperCase()+super.toString().substring(1).toLowerCase();
}
}
/**
@ -21,40 +227,155 @@ public abstract class SubCreator {
*
* @param player Player Creating
* @param name Server Name
* @param type Server Type
* @param version Server Version
* @param memory Server Memory Amount (in MB)
* @param port Server Port Number
* @param template Server Template
* @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, ServerType type, Version version, int memory, int port);
public abstract boolean create(UUID player, String name, ServerTemplate template, Version version, Integer port, Consumer<SubServer> callback);
/**
* Create a SubServer
*
* @param player Player Creating
* @param name Server Name
* @param template Server Template
* @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, Integer port) {
return create(player, name, template, version, port, null);
}
/**
* Create a SubServer
*
* @param name Server Name
* @param type Server Type
* @param version Server Version
* @param memory Server Memory Amount (in MB)
* @param port Server Port Number
* @param template Server Template
* @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, ServerType type, Version version, int memory, int port) {
return create(null, name, type, version, memory, port);
public boolean create(String name, ServerTemplate template, Version version, Integer port, Consumer<SubServer> callback) {
return create(null, name, template, version, port, callback);
}
/**
* Terminate SubCreator
* Create a SubServer
*
* @param name Server Name
* @param template Server Template
* @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, 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
*/
public abstract void terminate();
/**
* Wait for SubCreator to Finish
* Terminate a SubCreator Instance
*
* @param name Name of current creating server
*/
public abstract void terminate(String name);
/**
* Wait for All SubCreator Instances to Finish
*
* @throws InterruptedException
*/
public abstract void waitFor() throws InterruptedException;
/**
* Wait for SubCreator to Finish
*
* @param name Name of current creating server
* @throws InterruptedException
*/
public abstract void waitFor(String name) throws InterruptedException;
/**
* Gets the host this creator belongs to
*
@ -62,17 +383,163 @@ 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
*
* @return Git Bash Directory
*/
public abstract String getGitBashDirectory();
public abstract String getBashDirectory();
/**
* Gets the status of SubCreator
* Gets all loggers for All SubCreator Instances
*
* @return SubCreator Status
* @return SubCreator Loggers
*/
public abstract boolean isBusy();
public abstract List<SubLogger> getLoggers();
/**
* Gets the Logger for a SubCreator Instance
*
* @param thread Thread ID
* @return SubCreator Logger
*/
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
*
* @return Reserved Names
*/
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
*
* @param name Name to check
* @return Reserved Status
*/
public static boolean isReserved(String name) {
boolean reserved = false;
for (List<String> list : getAllReservedNames().values()) for (String reserve : list) {
if (reserve.equalsIgnoreCase(name)) reserved = true;
}
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
*
* @return All Reserved Names
*/
public static Map<Host, List<String>> getAllReservedNames() {
HashMap<Host, List<String>> names = new HashMap<Host, List<String>>();
for (Host host : SubAPI.getInstance().getHosts().values()) names.put(host, host.getCreator().getReservedNames());
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
*
* @return Template Map
*/
public abstract Map<String, ServerTemplate> getTemplates();
/**
* Gets a SubCreator Template by name
*
* @param name Template Name
* @return Template
*/
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

@ -0,0 +1,28 @@
package net.ME1312.SubServers.Bungee.Host;
import java.util.logging.Level;
/**
* SubServer Log Filter Layout Class
*/
public interface SubLogFilter {
/**
* Called when the logging has started
*/
void start();
/**
* Determine if this message should be logged
*
* @param level Log Level
* @param message Message to Log
* @return If this message should be logged
*/
boolean log(Level level, String message);
/**
* Called when the logging has stopped
*/
void stop();
}

View File

@ -0,0 +1,52 @@
package net.ME1312.SubServers.Bungee.Host;
/**
* SubLogger Layout Class
*/
public abstract class SubLogger {
/**
* Gets the Name of the task logging
*
* @return Log Task Name
*/
public abstract String getName();
/**
* Gets the Object using this Logger
*
* @return Object
*/
public abstract Object getHandler();
/**
* Start Logger
*/
public abstract void start();
/**
* Stop Logger
*/
public abstract void stop();
/**
* Get if the Logger is currently logging
*
* @return Logging Status
*/
public abstract boolean isLogging();
/**
* Register Filter
*
* @param filter Filter
*/
public abstract void registerFilter(SubLogFilter filter);
/**
* Unregister Filter
*
* @param filter Filter
*/
public abstract void unregisterFilter(SubLogFilter filter);
}

View File

@ -1,30 +1,105 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import net.ME1312.SubServers.Bungee.Library.NamedContainer;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Util;
import java.net.InetSocketAddress;
import java.util.UUID;
import java.io.File;
import java.util.*;
/**
* SubServer Layout Class
*
* @author ME1312
* SubServer Interface
*/
public abstract class SubServer extends Server {
public interface SubServer extends Server {
/**
* 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
* SubServer Stop Action Class
*/
public SubServer(Host host, String name, int port, String motd, boolean hidden, boolean restricted) throws InvalidServerException {
super(name, InetSocketAddress.createUnresolved(host.getAddress().getHostAddress(), port), motd, hidden, restricted);
enum StopAction {
NONE,
RESTART,
REMOVE_SERVER,
RECYCLE_SERVER,
DELETE_SERVER;
@Override
public String toString() {
return super.toString().substring(0, 1).toUpperCase()+super.toString().substring(1).toLowerCase().replace('_', ' ');
}
}
/**
* Command Storage Class
*/
class LoggedCommand {
private Date date;
private UUID sender;
private String command;
/**
* Store a Command
*
* @param command Command
*/
public LoggedCommand(String command) {
Util.nullpo(command);
this.date = Calendar.getInstance().getTime();
this.sender = null;
this.command = command;
}
/**
* Store a Command
*
* @param sender Command Sender (null for CONSOLE)
* @param command Command
*/
public LoggedCommand(UUID sender, String command) {
Util.nullpo(command);
this.date = Calendar.getInstance().getTime();
this.sender = sender;
this.command = command;
}
/**
* Store a Command
*
* @param date Date
* @param sender Command Sender (null for CONSOLE)
* @param command Command
*/
public LoggedCommand(Date date, UUID sender, String command) {
Util.nullpo(date, command);
this.date = date;
this.sender = sender;
this.command = command;
}
/**
* Get the date this command was logged
*
* @return Date
*/
public Date getDate() {
return date;
}
/**
* Get the command sender
*
* @return Command Sender (null if CONSOLE)
*/
public UUID getSender() {
return sender;
}
/**
* Get the command
*
* @return Command
*/
public String getCommand() {
return command;
}
}
/**
@ -33,14 +108,14 @@ public abstract class SubServer extends Server {
* @param player Player who Started
* @return Success Status
*/
public abstract boolean start(UUID player);
boolean start(UUID player);
/**
* Starts the Server
*
* @return Success Status
*/
public boolean start() {
default boolean start() {
return start(null);
}
@ -50,14 +125,14 @@ public abstract class SubServer extends Server {
* @param player Player who Stopped
* @return Success Status
*/
public abstract boolean stop(UUID player);
boolean stop(UUID player);
/**
* Stops the Server
*
* @return Success Status
*/
public boolean stop() {
default boolean stop() {
return stop(null);
}
@ -67,34 +142,57 @@ public abstract class SubServer extends Server {
* @param player Player who Terminated
* @return Success Status
*/
public abstract boolean terminate(UUID player);
boolean terminate(UUID player);
/**
* Terminates the Server
*
* @return Success Status
*/
public boolean terminate() {
default boolean terminate() {
return terminate(null);
}
/**
* Commands the Server
* Edits the Server
*
* @param player Player who Commanded
* @param command Command to Send
* @param player Player Editing
* @param edit Edits
* @return Success Status
*/
public abstract boolean command(UUID player, String command);
default int edit(UUID player, ObjectMap<String> edit) {
return -1;
}
/**
* Commands the Server
* Edits the Server
*
* @param command Command to Send
* @param edit Edits
* @return Success Status
*/
public boolean command(String command) {
return command(null, command);
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);
}
/**
@ -102,84 +200,194 @@ public abstract class SubServer extends Server {
*
* @throws InterruptedException
*/
public abstract void waitFor() throws InterruptedException;
void waitFor() throws InterruptedException;
/**
* If the Server is Running
*
* @return Running Status
*/
public abstract boolean isRunning();
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
*
* @return The Host
*/
public abstract Host getHost();
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
*
* @return Enabled Status
*/
public abstract boolean isEnabled();
boolean isEnabled();
/**
* Set if the Server is Enabled
*
* @param value Value
*/
public abstract void setEnabled(boolean value);
void setEnabled(boolean value);
/**
* If the Server is accepting requests to edit()
*
* @see #permaEdit(ObjectMap<String>)
* @see #permaEdit(UUID, ObjectMap<String>)
* @return Edit Status
*/
default boolean isEditable() {
return permaEdit(new ObjectMap<String>()) >= 0;
}
/**
* If the Server is Logging
*
* @return Logging Status
*/
public abstract boolean isLogging();
boolean isLogging();
/**
* Set if the Server is Logging
*
* @param value Value
*/
public abstract void setLogging(boolean value);
void setLogging(boolean value);
/**
* Get Process Logger
*/
SubLogger getLogger();
/**
* Gets all the commands that were sent to this Server successfully
*
* @return Command History
*/
LinkedList<LoggedCommand> getCommandHistory();
/**
* Get the Server Directory Path
*
* @return Server Directory Path
*/
String getPath();
/**
* Get the Full Server Directory Path
*
* @return Full Server Directory Path
*/
default String getFullPath() {
return new File(getHost().getPath(), getPath()).getPath();
}
/**
* Get the Server's Executable String
*
* @return Executable String
*/
String getExecutable();
/**
* Grab the Command to Stop the Server
*
* @return Stop Command
*/
public abstract String getStopCommand();
String getStopCommand();
/**
* Set the Command that Stops the Server
*
* @param value Value
*/
public abstract void setStopCommand(String value);
void setStopCommand(String value);
/**
* If the Server will Auto Restart on unexpected shutdowns
* Get the action the Server will take when it stops
*
* @return Auto Restart Status
* @return Stop Action
*/
public abstract boolean willAutoRestart();
StopAction getStopAction();
/**
* Set if the Server will Auto Restart on unexpected shutdowns
* Set the action the Server will take when it stops
*
* @param value Value
* @param action Stop Action
*/
public abstract void setAutoRestart(boolean value);
void setStopAction(StopAction action);
/**
* If the Server is Temporary
* Toggles compatibility with other Servers
*
* @return Temporary Status
* @param server SubServers to toggle
*/
public abstract boolean isTemporary();
void toggleCompatibility(SubServer... server);
/**
* Checks if a Server is compatible
*
* @param server Server to check
* @return Compatible Status
*/
boolean isCompatible(SubServer server);
/**
* Get all listed incompatibilities for this Server
*
* @return Incompatibility List
*/
List<SubServer> getIncompatibilities();
/**
* Get incompatibility issues this server currently has
*
* @return Current Incompatibility List
*/
List<SubServer> getCurrentIncompatibilities();
}

View File

@ -0,0 +1,364 @@
package net.ME1312.SubServers.Bungee.Host;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException;
import java.util.LinkedList;
import java.util.UUID;
/**
* API-Safe SubServer Layout Class
*/
public abstract class SubServerController {
private final SubServerImpl control;
/**
* 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 SubServerController(Host host, String name, int port, String motd, boolean hidden, boolean restricted) throws InvalidServerException {
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;
}
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);
}
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 start() {
if (SubServerController.this.start()) {
started = false;
return true;
} else return false;
}
@Override
public boolean start(UUID player) {
if (SubServerController.this.start(player)) {
started = false;
return true;
} else return false;
}
@Override
public boolean stop() {
return SubServerController.this.stop();
}
@Override
public boolean stop(UUID player) {
return SubServerController.this.stop(player);
}
@Override
public boolean terminate() {
return SubServerController.this.terminate();
}
@Override
public boolean terminate(UUID player) {
return SubServerController.this.terminate(player);
}
@Override
public boolean command(String command) {
return SubServerController.this.command(command);
}
@Override
public boolean command(UUID player, String command) {
return SubServerController.this.command(player, command);
}
@Override
public int edit(UUID player, ObjectMap<String> edit, boolean perma) {
return SubServerController.this.edit(player, edit, perma);
}
@Override
public void waitFor() throws InterruptedException {
SubServerController.this.waitFor();
}
@Override
public boolean isRunning() {
return SubServerController.this.isRunning();
}
@Override
public Host getHost() {
return SubServerController.this.getHost();
}
@Override
public boolean isEnabled() {
return SubServerController.this.isEnabled();
}
@Override
public void setEnabled(boolean value) {
SubServerController.this.setEnabled(value);
}
@Override
public boolean isLogging() {
return SubServerController.this.isLogging();
}
@Override
public void setLogging(boolean value) {
SubServerController.this.setLogging(value);
}
@Override
public SubLogger getLogger() {
return SubServerController.this.getLogger();
}
@Override
public LinkedList<LoggedCommand> getCommandHistory() {
return SubServerController.this.getCommandHistory();
}
@Override
public String getPath() {
return SubServerController.this.getPath();
}
@Override
public String getExecutable() {
return SubServerController.this.getExecutable();
}
@Override
public String getStopCommand() {
return SubServerController.this.getStopCommand();
}
@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);
}
}
/**
* Get the SubServer that is being controlled
*
* @return SubServer
*/
public SubServer get() {
return control;
}
/**
* Starts the Server
*
* @param player Player who Started
* @return Success Status
*/
public abstract boolean start(UUID player);
/**
* Starts the Server
*
* @return Success Status
*/
public boolean start() {
return start(null);
}
/**
* Stops the Server
*
* @param player Player who Stopped
* @return Success Status
*/
public abstract boolean stop(UUID player);
/**
* Stops the Server
*
* @return Success Status
*/
public boolean stop() {
return stop(null);
}
/**
* Terminates the Server
*
* @param player Player who Terminated
* @return Success Status
*/
public abstract boolean terminate(UUID player);
/**
* Terminates the Server
*
* @return Success Status
*/
public boolean terminate() {
return terminate(null);
}
/**
* Commands the Server
*
* @param player Player who's Commanding
* @param command Command to Send
* @return Success Status
*/
public abstract boolean command(UUID player, String command);
/**
* Commands the Server
*
* @param command Command to Send
* @return Success Status
*/
public boolean command(String command) {
return command(null, command);
}
/**
* 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;
}
/**
* Waits for the Server to Stop
*
* @throws InterruptedException
*/
public abstract void waitFor() throws InterruptedException;
/**
* If the Server is Running
*
* @return Running Status
*/
public abstract boolean isRunning();
/**
* Grabs the Host of the Server
*
* @return The Host
*/
public abstract Host getHost();
/**
* If the Server is Enabled
*
* @return Enabled Status
*/
public abstract boolean isEnabled();
/**
* Set if the Server is Enabled
*
* @param value Value
*/
public abstract void setEnabled(boolean value);
/**
* If the Server is Logging
*
* @return Logging Status
*/
public abstract boolean isLogging();
/**
* Set if the Server is Logging
*
* @param value Value
*/
public abstract void setLogging(boolean value);
/**
* Get Process Logger
*/
public abstract SubLogger getLogger();
/**
* Gets all the commands that were sent to this Server successfully
*
* @return Command History
*/
public abstract LinkedList<SubServer.LoggedCommand> getCommandHistory();
/**
* Get the Server Directory Path
*
* @return Server Directory Path
*/
public abstract String getPath();
/**
* Get the Server's Executable String
*
* @return Executable String
*/
public abstract String getExecutable();
/**
* Grab the Command to Stop the Server
*
* @return Stop Command
*/
public abstract String getStopCommand();
/**
* Set the Command that Stops the Server
*
* @param value Value
*/
public abstract void setStopCommand(String value);
/**
* Get the action the Server will take when it stops
*
* @return Stop Action
*/
public abstract SubServer.StopAction getStopAction();
/**
* Set the action the Server will take when it stops
*
* @param action Stop Action
*/
public abstract void setStopAction(SubServer.StopAction action);
}

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,91 +1,121 @@
package net.ME1312.SubServers.Bungee;
import net.ME1312.Galaxi.Library.Platform;
import net.ME1312.Galaxi.Library.Try;
import java.security.Security;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import net.md_5.bungee.Bootstrap;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.command.ConsoleCommandSender;
/**
* SubServers/BungeeCord Class
*
* @author ME1312
* SubServers/BungeeCord Launch Class
*/
public final class Launch {
/**
* Launch SubServers/BungeeCord
*
* @param args
* @param args Launch Arguments
* @throws Exception
*/
@SuppressWarnings("deprecation")
@SuppressWarnings({"deprecation", "unchecked"})
public static void main(String[] args) throws Exception {
System.out.println("");
System.out.println("*******************************************");
System.out.println("*** Warning, this build is Unofficial ***");
System.out.println("*** ***");
System.out.println("*** Please report all issues to ME1312, ***");
System.out.println("*** NOT the Spigot Staff! Thank You! ***");
System.out.println("*******************************************");
System.out.println("");
System.setProperty("jdk.lang.Process.allowAmbiguousCommands", "true");
System.setProperty("jdk.util.jar.enableMultiRelease", "force");
System.setProperty("apple.laf.useScreenMenuBar", "true");
Security.setProperty("networkaddress.cache.ttl", "30");
Security.setProperty("networkaddress.cache.negative.ttl", "10");
OptionParser parser = new OptionParser();
parser.allowsUnrecognizedOptions();
parser.accepts("v");
parser.accepts("version");
parser.accepts("noconsole");
OptionSet options = parser.parse(args);
if(options.has("version") || options.has("v")) {
System.out.println(Bootstrap.class.getPackage().getImplementationVersion());
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 ***");
System.out.println("*** ***");
System.out.println("*** Please download a build from: ***");
System.out.println("*** http://ci.md-5.net/job/BungeeCord ***");
System.out.println("*******************************************");
System.out.println("");
System.exit(1);
} else {
try {
if (BungeeCord.class.getPackage().getSpecificationVersion() != null) {
Date bungee = (new SimpleDateFormat("yyyyMMdd")).parse(BungeeCord.class.getPackage().getSpecificationVersion());
Calendar line = Calendar.getInstance();
line.add(3, -4);
if (bungee.before(line.getTime())) {
System.out.println("*******************************************");
System.out.println("*** Warning, this build is outdated ***");
System.out.println("*** Please download a new build from: ***");
System.out.println("*** http://ci.md-5.net/job/BungeeCord ***");
System.out.println("*** Errors may arise on older versions! ***");
System.out.println("*******************************************");
System.out.println("");
}
} else throw new NullPointerException();
} catch (Exception e) {
System.out.println("*******************************************");
System.out.println("*** Problem checking BungeeCord Version ***");
System.out.println("*** This build could be outdated. ***");
System.out.println("*** ***");
System.out.println("*** Errors may arise on older versions! ***");
System.out.println("*******************************************");
Security.setProperty("networkaddress.cache.ttl", "30");
Security.setProperty("networkaddress.cache.negative.ttl", "10");
final boolean patched = net.md_5.bungee.BungeeCord.class.getPackage().getImplementationTitle() != null && net.md_5.bungee.BungeeCord.class.getPackage().getImplementationTitle().equals("SubServers.Bungee");
joptsimple.OptionParser parser = new joptsimple.OptionParser();
parser.allowsUnrecognizedOptions();
parser.accepts("v");
parser.accepts("version");
parser.accepts("noconsole");
joptsimple.OptionSet options = parser.parse(args);
if(options.has("version") || options.has("v")) {
System.out.println("");
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("");
System.out.println("*******************************************");
System.out.println("*** Warning: this build is unofficial ***");
System.out.println("*** ***");
System.out.println("*** Please report all issues to ME1312, ***");
System.out.println("*** NOT the Spigot Team. Thank You! ***");
System.out.println("*******************************************");
try {
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(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: ***");
System.out.println("*** http://ci.md-5.net/job/BungeeCord ***");
System.out.println("*** Errors may arise on older versions! ***");
System.out.println("*******************************************");
}
} else throw new Exception();
} catch (Exception e) {
System.out.println("*** Problem checking BungeeCord version ***");
System.out.println("*** BungeeCord could be outdated. ***");
System.out.println("*** ***");
System.out.println("*** Errors may arise on older versions! ***");
System.out.println("*******************************************");
}
System.out.println("");
}
SubPlugin bungee = new SubPlugin();
ProxyServer.setInstance(bungee);
bungee.getLogger().info("Enabled BungeeCord version " + bungee.getVersion());
bungee.start();
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();
String line;
if(!options.has("noconsole")) {
while(bungee.isRunning && (line = bungee.getConsoleReader().readLine(">")) != null) {
if(!bungee.getPluginManager().dispatchCommand(ConsoleCommandSender.getInstance(), line)) {
bungee.getConsole().sendMessage(ChatColor.RED + "Command not found");
if (!options.has("noconsole")) {
try {
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 (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 {
plugin.canSudo = true;
String line;
while (plugin.isRunning && (line = plugin.getConsoleReader().readLine(">")) != null) {
if (plugin.sudo == null) {
if (!plugin.getPluginManager().dispatchCommand(net.md_5.bungee.command.ConsoleCommandSender.class.cast(net.md_5.bungee.command.ConsoleCommandSender.class.getMethod("getInstance").invoke(null)), line)) {
plugin.getConsole().sendMessage(net.md_5.bungee.api.ChatColor.RED + "Command not found");
}
} else if (line.equalsIgnoreCase("exit")) {
plugin.sudo = null;
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.getLogger().warning("Standard BungeeCord console not found; Console commands may now be disabled.");
}
}
}
}
}
}

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

@ -0,0 +1,9 @@
package net.ME1312.SubServers.Bungee.Library.Compatibility;
public final class Plugin extends net.md_5.bungee.api.plugin.Plugin {
@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,65 +0,0 @@
package net.ME1312.SubServers.Bungee.Library.Config;
import org.json.JSONObject;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.error.YAMLException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
@SuppressWarnings("unused")
public class YAMLConfig {
private File file;
private Yaml yaml;
private YAMLSection config;
@SuppressWarnings("unchecked")
public YAMLConfig(File file) throws IOException, YAMLException {
if (file.exists()) {
this.config = new YAMLSection((Map<String, ?>) (this.yaml = new Yaml(getDumperOptions())).load(new FileInputStream(this.file = file)), null, null, yaml);
} else {
this.config = new YAMLSection(null, null, null, yaml);
}
}
public YAMLSection get() {
return config;
}
public void set(YAMLSection yaml) {
config = yaml;
}
@SuppressWarnings("unchecked")
public void reload() throws IOException {
config = new YAMLSection((Map<String, Object>) yaml.load(new FileInputStream(file)), null, null, yaml);
}
public void save() throws IOException {
FileWriter writer = new FileWriter(file);
yaml.dump(config.map, writer);
writer.close();
}
@Override
public String toString() {
return yaml.dump(config.map);
}
public JSONObject toJSON() {
return new JSONObject(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,473 +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.json.JSONObject;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.error.YAMLException;
import java.io.InputStream;
import java.io.Reader;
import java.util.*;
@SuppressWarnings({"unchecked", "unused"})
public class YAMLSection {
protected Map<String, Object> map;
protected String label = null;
protected YAMLSection up = null;
private Yaml yaml;
public YAMLSection() {
this.map = new HashMap<>();
this.yaml = new Yaml(YAMLConfig.getDumperOptions());
}
public YAMLSection(InputStream io) throws YAMLException {
this.map = (Map<String, Object>) (this.yaml = new Yaml(YAMLConfig.getDumperOptions())).load(io);
}
public YAMLSection(Reader reader) throws YAMLException {
this.map = (Map<String, Object>) (this.yaml = new Yaml(YAMLConfig.getDumperOptions())).load(reader);
}
public YAMLSection(JSONObject json) {
this.map = (Map<String, Object>) (this.yaml = new Yaml(YAMLConfig.getDumperOptions())).load(json.toString(4));
}
public YAMLSection(String yaml) throws YAMLException {
this.map = (Map<String, Object>) (this.yaml = new Yaml(YAMLConfig.getDumperOptions())).load(yaml);
}
protected YAMLSection(Map<String, ?> map, YAMLSection up, String label, Yaml yaml) {
this.map = new HashMap<String, Object>();
this.yaml = yaml;
this.label = label;
this.up = up;
if (map != null) {
for (String key : map.keySet()) {
this.map.put(key, map.get(key));
}
}
}
public Set<String> getKeys() {
return map.keySet();
}
public Collection<YAMLValue> getValues() {
List<YAMLValue> values = new ArrayList<YAMLValue>();
for (String value : map.keySet()) {
values.add(new YAMLValue(map.get(value), this, value, yaml));
}
return values;
}
public boolean contains(String label) {
return map.keySet().contains(label);
}
public void remove(String label) {
map.remove(label);
}
public void clear() {
map.clear();
}
public void set(String label, Object value) {
if (value instanceof YAMLConfig) { // YAML Handler Values
((YAMLConfig) value).get().up = this;
((YAMLConfig) value).get().label = label;
map.put(label, ((YAMLConfig) value).get().map);
} else if (value instanceof YAMLSection) {
((YAMLSection) value).up = this;
((YAMLSection) value).label = label;
map.put(label, ((YAMLSection) value).map);
} else if (value instanceof YAMLValue) {
map.put(label, ((YAMLValue) value).asObject());
} else if (value instanceof UUID) {
map.put(label, ((UUID) value).toString());
} else {
map.put(label, value);
}
if (this.label != null && this.up != null) {
this.up.set(this.label, this);
}
}
public void setAll(Map<String, ?> values) {
for (String value : values.keySet()) {
set(value, values.get(value));
}
}
public void setAll(YAMLSection values) {
for (String value : values.map.keySet()) {
set(value, values.map.get(value));
}
}
public YAMLSection superSection() {
return up;
}
@Override
public String toString() {
return yaml.dump(map);
}
public JSONObject toJSON() {
return new JSONObject(map);
}
public YAMLValue get(String label) {
return (map.get(label) != null)?(new YAMLValue(map.get(label), this, label, yaml)):null;
}
public YAMLValue get(String label, Object def) {
return new YAMLValue((map.get(label) != null)?map.get(label):def, this, label, yaml);
}
public YAMLValue get(String label, YAMLValue def) {
return (map.get(label) != null) ? (new YAMLValue(map.get(label), this, label, yaml)) : def;
}
public List<YAMLValue> getList(String label) {
if (map.get(label) != null) {
List<YAMLValue> values = new ArrayList<YAMLValue>();
for (Object value : (List<?>) map.get(label)) {
values.add(new YAMLValue(value, null, null, yaml));
}
return values;
} else {
return null;
}
}
public List<YAMLValue> getList(String label, Collection<?> def) {
if (map.get(label) != null) {
return getList(label);
} else {
List<YAMLValue> values = new ArrayList<YAMLValue>();
for (Object value : def) {
values.add(new YAMLValue(value, null, null, yaml));
}
return values;
}
}
public List<YAMLValue> getList(String label, List<? extends YAMLValue> def) {
if (map.get(label) != null) {
return getList(label);
} else {
List<YAMLValue> values = new ArrayList<YAMLValue>();
for (YAMLValue value : def) {
values.add(value);
}
return values;
}
}
public Object getObject(String label) {
return map.get(label);
}
public Object getObject(String label, Object def) {
return (map.get(label) != null)?map.get(label):def;
}
public List<?> getObjectList(String label) {
return (List<?>) map.get(label);
}
public List<?> getObjectList(String label, List<?> def) {
return (List<?>) ((map.get(label) != null)?map.get(label):def);
}
public boolean getBoolean(String label) {
return (boolean) map.get(label);
}
public boolean getBoolean(String label, boolean def) {
return (boolean) ((map.get(label) != null)?map.get(label):def);
}
public List<Boolean> getBooleanList(String label) {
return (List<Boolean>) map.get(label);
}
public List<Boolean> getBooleanList(String label, List<Boolean> def) {
return (List<Boolean>) ((map.get(label) != null)?map.get(label):def);
}
public YAMLSection getSection(String label) {
return (map.get(label) != null)?(new YAMLSection((Map<String, Object>) map.get(label), this, label, yaml)):null;
}
public YAMLSection getSection(String label, Map<String, ?> def) {
return new YAMLSection((Map<String, Object>) ((map.get(label) != null)?map.get(label):def), this, label, yaml);
}
public YAMLSection getSection(String label, YAMLSection def) {
return (map.get(label) != null)?(new YAMLSection((Map<String, Object>) map.get(label), this, label, yaml)):def;
}
public List<YAMLSection> getSectionList(String label) {
if (map.get(label) != null) {
List<YAMLSection> values = new ArrayList<YAMLSection>();
for (Map<String, ?> value : (List<? extends Map<String, ?>>) map.get(label)) {
values.add(new YAMLSection(value, null, null, yaml));
}
return values;
} else {
return null;
}
}
public List<YAMLSection> getSectionList(String label, Collection<? extends Map<String, ?>> def) {
if (map.get(label) != null) {
return getSectionList(label);
} else {
List<YAMLSection> values = new ArrayList<YAMLSection>();
for (Map<String, ?> value : def) {
values.add(new YAMLSection(value, null, null, yaml));
}
return values;
}
}
public List<YAMLSection> getSectionList(String label, List<? extends YAMLSection> def) {
if (map.get(label) != null) {
return getSectionList(label);
} else {
List<YAMLSection> values = new ArrayList<YAMLSection>();
for (YAMLSection value : def) {
values.add(value);
}
return values;
}
}
public double getDouble(String label) {
return (double) map.get(label);
}
public double getDouble(String label, double def) {
return (double) ((map.get(label) != null)?map.get(label):def);
}
public List<Double> getDoubleList(String label) {
return (List<Double>) map.get(label);
}
public List<Double> getDoubleList(String label, List<Double> def) {
return (List<Double>) ((map.get(label) != null)?map.get(label):def);
}
public float getFloat(String label) {
return (float) map.get(label);
}
public float getFloat(String label, float def) {
return (float) ((map.get(label) != null)?map.get(label):def);
}
public List<Float> getFloatList(String label) {
return (List<Float>) map.get(label);
}
public List<Float> getFloatList(String label, float def) {
return (List<Float>) ((map.get(label) != null)?map.get(label):def);
}
public int getInt(String label) {
return (int) map.get(label);
}
public int getInt(String label, int def) {
return (int) ((map.get(label) != null)?map.get(label):def);
}
public List<Integer> getIntList(String label) {
return (List<Integer>) map.get(label);
}
public List<Integer> getIntList(String label, List<Integer> def) {
return (List<Integer>) ((map.get(label) != null)?map.get(label):def);
}
public long getLong(String label) {
return (long) map.get(label);
}
public long getLong(String label, long def) {
return (long) ((map.get(label) != null)?map.get(label):def);
}
public List<Long> getLongList(String label) {
return (List<Long>) map.get(label);
}
public List<Long> getLongList(String label, List<Long> def) {
return (List<Long>) ((map.get(label) != null)?map.get(label):def);
}
public short getShort(String label) {
return (short) map.get(label);
}
public short getShort(String label, short def) {
return (short) ((map.get(label) != null)?map.get(label):def);
}
public List<Short> getShortList(String label) {
return (List<Short>) map.get(label);
}
public List<Short> getShortList(String label, List<Short> def) {
return (List<Short>) ((map.get(label) != null)?map.get(label):def);
}
public String getRawString(String label) {
return (String) map.get(label);
}
public String getRawString(String label, String def) {
return (String) ((map.get(label) != null)?map.get(label):def);
}
public List<String> getRawStringList(String label) {
return (List<String>) map.get(label);
}
public List<String> getRawStringList(String label, List<String> def) {
return (List<String>) ((map.get(label) != null)?map.get(label):def);
}
public String getString(String label) {
return (map.get(label) != null)?Util.unescapeJavaString((String) map.get(label)):null;
}
public String getString(String label, String def) {
return Util.unescapeJavaString((String) ((map.get(label) != null) ? map.get(label) : def));
}
public List<String> getStringList(String label) {
if (map.get(label) != null) {
List<String> values = new ArrayList<String>();
for (String value : (List<String>) map.get(label)) {
values.add(Util.unescapeJavaString(value));
}
return values;
} else {
return null;
}
}
public List<String> getStringList(String label, List<String> def) {
if (map.get(label) != null) {
return getStringList(label);
} else {
List<String> values = new ArrayList<String>();
for (String value : def) {
values.add(Util.unescapeJavaString(value));
}
return values;
}
}
public String getColoredString(String label, char color) {
return (map.get(label) != null)? ChatColor.translateAlternateColorCodes(color, Util.unescapeJavaString((String) map.get(label))):null;
}
public String getColoredString(String label, String def, char color) {
return ChatColor.translateAlternateColorCodes(color, Util.unescapeJavaString((String) ((map.get(label) != null) ? map.get(label) : def)));
}
public List<String> getColoredStringList(String label, char color) {
if (map.get(label) != null) {
List<String> values = new ArrayList<String>();
for (String value : (List<String>) map.get(label)) {
values.add(ChatColor.translateAlternateColorCodes(color, Util.unescapeJavaString(value)));
}
return values;
} else {
return null;
}
}
public List<String> getColoredStringList(String label, List<String> def, char color) {
if (map.get(label) != null) {
return getColoredStringList(label, color);
} else {
List<String> values = new ArrayList<String>();
for (String value : def) {
values.add(ChatColor.translateAlternateColorCodes(color, Util.unescapeJavaString(value)));
}
return values;
}
}
public UUID getUUID(String label) {
return (map.get(label) != null)?UUID.fromString((String) map.get(label)):null;
}
public UUID getUUID(String label, UUID def) {
return UUID.fromString((String) ((map.get(label) != null) ? map.get(label) : def));
}
public List<UUID> getUUIDList(String label) {
if (map.get(label) != null) {
List<UUID> values = new ArrayList<UUID>();
for (String value : (List<String>) map.get(label)) {
values.add(UUID.fromString(value));
}
return values;
} else {
return null;
}
}
public List<UUID> getUUIDList(String label, List<UUID> def) {
if (map.get(label) != null) {
return getUUIDList(label);
} else {
return def;
}
}
public boolean isBoolean(String label) {
return (map.get(label) instanceof Boolean);
}
public boolean isSection(String label) {
return (map.get(label) instanceof Map);
}
public boolean isDouble(String label) {
return (map.get(label) instanceof Double);
}
public boolean isFloat(String label) {
return (map.get(label) instanceof Float);
}
public boolean isInt(String label) {
return (map.get(label) instanceof Integer);
}
public boolean isList(String label) {
return (map.get(label) instanceof List);
}
public boolean isLong(String label) {
return (map.get(label) instanceof Long);
}
public boolean isString(String label) {
return (map.get(label) instanceof String);
}
}

View File

@ -1,170 +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.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings({"unchecked", "unused"})
public class YAMLValue {
protected Object obj;
protected String label;
protected YAMLSection up;
private Yaml yaml;
public YAMLValue(Object obj, YAMLSection up, String label, Yaml yaml) {
this.obj = obj;
this.label = label;
this.yaml = yaml;
this.up = up;
}
public YAMLSection getDefiningSection() {
return up;
}
public Object asObject() {
return obj;
}
public List<?> asObjectList() {
return (List<?>) obj;
}
public boolean asBoolean() {
return (boolean) obj;
}
public List<Boolean> asBooleanList() {
return (List<Boolean>) obj;
}
public YAMLSection asSection() {
return new YAMLSection((Map<String, ?>) obj, up, label, yaml);
}
public List<YAMLSection> asSectionList() {
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;
}
public double asDouble() {
return (double) obj;
}
public List<Double> asDoubleList() {
return (List<Double>) obj;
}
public float asFloat() {
return (float) obj;
}
public List<Float> asFloatList() {
return (List<Float>) obj;
}
public int asInt() {
return (int) obj;
}
public List<Integer> asIntList() {
return (List<Integer>) obj;
}
public long asLong() {
return (long) obj;
}
public List<Long> asLongList() {
return (List<Long>) obj;
}
public String asRawString() {
return (String) obj;
}
public List<String> asRawStringList() {
return (List<String>) obj;
}
public String asString() {
return Util.unescapeJavaString((String) obj);
}
public List<String> asStringList() {
List<String> values = new ArrayList<String>();
for (String value : (List<String>) obj) {
values.add(Util.unescapeJavaString(value));
}
return values;
}
public String asColoredString(char color) {
return ChatColor.translateAlternateColorCodes(color, Util.unescapeJavaString((String) obj));
}
public List<String> asColoredStringList(char color) {
List<String> values = new ArrayList<String>();
for (String value : (List<String>) obj) {
values.add(ChatColor.translateAlternateColorCodes(color, Util.unescapeJavaString(value)));
}
return values;
}
public UUID asUUID() {
return UUID.fromString((String) obj);
}
public List<UUID> asUUIDList() {
List<UUID> values = new ArrayList<UUID>();
for (String value : (List<String>) obj) {
values.add(UUID.fromString(value));
}
return values;
}
public boolean isBoolean() {
return (obj instanceof Boolean);
}
public boolean isSection() {
return (obj instanceof Map);
}
public boolean isDouble() {
return (obj instanceof Double);
}
public boolean isFloat(String path) {
return (obj instanceof Float);
}
public boolean isInt() {
return (obj instanceof Integer);
}
public boolean isList() {
return (obj instanceof List);
}
public boolean isLong() {
return (obj instanceof Long);
}
public boolean isString() {
return (obj instanceof String);
}
@Override
public String toString() {
return obj.toString();
}
}

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,37 +0,0 @@
package net.ME1312.SubServers.Bungee.Library;
/**
* Container Class
*
* @author ME1312
*/
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;
}
}

View File

@ -1,5 +1,8 @@
package net.ME1312.SubServers.Bungee.Library.Exception;
/**
* Illegal Packet Exception
*/
public class IllegalPacketException extends IllegalStateException {
public IllegalPacketException() {}
public IllegalPacketException(String s) {

View File

@ -1,5 +1,8 @@
package net.ME1312.SubServers.Bungee.Library.Exception;
/**
* Invalid Driver Exception
*/
public class InvalidDriverException extends IllegalStateException {
public InvalidDriverException() {}
public InvalidDriverException(String s) {

View File

@ -1,5 +1,8 @@
package net.ME1312.SubServers.Bungee.Library.Exception;
/**
* Invalid Host Exception
*/
public class InvalidHostException extends IllegalStateException {
public InvalidHostException() {}
public InvalidHostException(String s) {

View File

@ -1,5 +1,8 @@
package net.ME1312.SubServers.Bungee.Library.Exception;
/**
* Invalid Server Exception
*/
public class InvalidServerException extends IllegalStateException {
public InvalidServerException() {}
public InvalidServerException(String s) {

View File

@ -0,0 +1,11 @@
package net.ME1312.SubServers.Bungee.Library.Exception;
/**
* Invalid Template Exception
*/
public class InvalidTemplateException extends IllegalStateException {
public InvalidTemplateException() {}
public InvalidTemplateException(String s) {
super(s);
}
}

View File

@ -0,0 +1,11 @@
package net.ME1312.SubServers.Bungee.Library.Exception;
/**
* Invalid Template Exception
*/
public class SubCreatorException extends IllegalStateException {
public SubCreatorException() {}
public SubCreatorException(String s) {
super(s);
}
}

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,160 +0,0 @@
# Version: 2.11.2b+
#
# SubCreator Build Script
# Usage: "bash build.sh <version> <software> [jre]"
#
#!/usr/bin/env bash
if [ -z "$1" ]
then
echo ERROR: No Build Version Supplied
rm -Rf $0
exit 1
fi
if [ -z "$2" ]
then
echo ERROR: No Server Software Supplied
rm -Rf $0
exit 1
fi
if [ $2 == bukkit ] || [ $2 == spigot ]
then
echo Downloading Buildtools...
curl -o BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar; retvalb=$?
if ! [ $retvalb -eq 0 ]; then
echo ERROR: Failed Downloading Buildtools. Is SpigotMC.org down?
rm -Rf $0
exit 3
fi
if [ -d "Buildtools" ]
then
rm -Rf Buildtools
fi
mkdir Buildtools
cd "Buildtools"
echo Launching BuildTools.jar
export MAVEN_OPTS="-Xms2G"
if [ -z "$3" ]
then
java -Xms2G -jar ../BuildTools.jar --rev $1; retvalc=$?
else
HOME=$3 java -Xms2G -jar ../BuildTools.jar --rev $1; retvalc=$?
fi
cd ../
if [ $retvalc -eq 0 ]; then
echo Copying Final Jar...
if [ $2 == "spigot" ]; then
cp Buildtools/spigot-*.jar Spigot.jar
else
cp Buildtools/craftbukkit-*.jar Craftbukkit.jar
fi
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
if [ $2 == "vanilla" ]; then
if [ -d "Buildtools" ]
then
rm -Rf Buildtools
fi
mkdir Buildtools
mkdir Buildtools/Vanilla
echo Downloading Vanilla Jar...
curl -o Buildtools/Vanilla/minecraft_server.$1.jar https://s3.amazonaws.com/Minecraft.Download/versions/$1/minecraft_server.$1.jar; retvald=$?
if [ $retvald -eq 0 ]; then
echo Downloading Vanilla Patches...
curl -o Buildtools/Vanilla/bungee-patch.jar https://raw.githubusercontent.com/ME1312/SubServers-2/master/SubServers.Bungee/Vanilla-Patch.jar; retvale=$?
if [ $retvale -eq 0 ]; then
echo Patching Vanilla for BungeeCord Support
cd Buildtools/Vanilla
if [ -z "$3" ]
then
java -jar bungee-patch.jar $1; retvalf=$?;
else
HOME=$3 java -jar bungee-patch.jar $1; retvalf=$?;
fi
if [ $retvalf -eq 0 ]; then
echo Copying Final Jar...
cd ../../
cp Buildtools/Vanilla/out/$1-bungee.jar Buildtools/vanilla-$1.jar
cp Buildtools/Vanilla/out/$1-bungee.jar Vanilla.jar
echo Cleaning Up...
rm -Rf Buildtools
rm -Rf $0
exit 0
else
echo ERROR: Failed Applying Patch.
rm -Rf Buildtools
rm -Rf $0
exit 5
fi
else
echo ERROR: Failed Downloading Patch. Is Github.com down?
rm -Rf Buildtools
rm -Rf $0
exit 4
fi
else
echo ERROR: Failed Downloading Jarfile. Is Minecraft.net down?
rm -Rf Buildtools
rm -Rf $0
exit 3
fi
else
if [ $2 == "sponge" ]; then
IFS='::' read -r -a version <<< "$1"
sversion=$(echo ${version[@]:1} | tr -d ' ')
echo Downloading Minecraft Forge...
curl -o forge-${version[0]}-installer.jar http://files.minecraftforge.net/maven/net/minecraftforge/forge/${version[0]}/forge-${version[0]}-installer.jar; retvalg=$?
if [ $retvalg -eq 0 ]; then
echo Installing Minecraft Forge Server...
if [ -z "$3" ]
then
java -jar ./forge-${version[0]}-installer.jar --installServer; retvalh=$?
else
HOME=$3 java -jar ./forge-${version[0]}-installer.jar --installServer; retvalh=$?
fi
if [ $retvalh -eq 0 ]; then
mkdir ./mods
echo Downloading SpongeForge...
curl -o mods/Sponge.jar http://files.minecraftforge.net/maven/org/spongepowered/spongeforge/$sversion/spongeforge-$sversion.jar; retvali=$?
if [ $retvali -eq 0 ]; then
echo Cleaning Up...
rm -Rf forge-${version[0]}-installer.jar
rm -Rf forge-${version[0]}-installer.jar.log
mv -f forge-${version[0]}-universal.jar Forge.jar
rm -Rf $0
exit 0
else
echo ERROR: Failed Downloading Jarfile. Is MinecraftForge.net down?
rm -Rf forge-${version[0]}-installer.jar
rm -Rf forge-${version[0]}-installer.jar.log
rm -Rf forge-${version[0]}-universal.jar
rm -Rf $0
exit 5
fi
else
echo ERROR: Failed Installing Forge.
rm -Rf forge-${version[0]}-installer.jar
rm -Rf forge-${version[0]}-installer.jar.log
rm -Rf $0
exit 4
fi
else
echo ERROR: Failed Downloading Jarfile. Is MinecraftForge.net down?
rm -Rf $0
exit 3
fi
fi
fi
fi
echo ERROR: Unknown Server Software
exit 2

View File

@ -1,30 +0,0 @@
Settings:
Version: '2.11.2a+'
Log-Creator: true
SubData:
Address: '127.0.0.1:4391'
Password: ''
Allowed-Connections: []
Hosts:
'~':
Enabled: true
Driver: 'BUILT-IN'
Address: '127.0.0.1'
Directory: './'
Git-Bash: 'C:\Program Files\Git'
Servers:
'Example':
Enabled: false
Host: '~'
Port: 25567
Motd: '&aThis is a SubServer'
Log: true
Directory: './Example'
Executable: 'java -Djline.terminal=jline.UnsupportedTerminal -jar Spigot.jar'
Stop-Command: 'stop'
Run-On-Launch: false
Auto-Restart: false
Restricted: false
Hidden: false

View File

@ -1,135 +0,0 @@
Version: '2.11.2a+'
Lang:
'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$): '
'Bungee.List.List': '&f$str$'
'Bungee.List.Divider': '&f, '
'Bungee.List.Total': 'Total players online: $int$'
'Command.Generic.Player-Only': '&4SubServers \u00BB Console cannot run this command'
'Command.Generic.Console-Only': '&4SubServers \u00BB This command is for console use only'
'Command.Generic.Usage': '&7SubServers \u00BB Usage: &f$str$'
'Command.Generic.Invalid-Subcommand': '&4SubServers \u00BB Unknown sub-command: $str$'
'Command.Generic.Invalid-Permission': '&4SubServers \u00BB You need &n$str$&4 to use this command'
'Command.Help.Header': '&7SubServers \u00BB Command Help:'
'Command.Help.Help': ' &7Help:&f $str$'
'Command.Help.List': ' &7List:&f $str$'
'Command.Help.Version': ' &7Version:&f $str$'
'Command.Help.Terminate': ' &7Teleport to Server:&f $str$'
'Command.Help.Host.Create': ' &7Create Server:&f $str$'
'Command.Help.Server.Teleport': ' &7Teleport to 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 \u00BB SubServers is running version &f$str$'
'Command.List.Host-Header': '&7SubServers \u00BB Host List:'
'Command.List.Server-Header': '&7SubServers \u00BB Server List:'
'Command.List.Divider': '&7, '
'Command.Start': '&aSubServers \u00BB Starting SubServer'
'Command.Start.Unknown': '&cSubServers \u00BB There is no server with that name'
'Command.Start.Invalid': '&cSubServers \u00BB That Server is not a SubServer'
'Command.Start.Host-Disabled': '&cSubServers \u00BB That SubServer\u0027s Host is not enabled'
'Command.Start.Server-Disabled': '&cSubServers \u00BB That SubServer is not enabled'
'Command.Start.Running': '&cSubServers \u00BB That SubServer is already running'
'Command.Stop': '&aSubServers \u00BB Stopping SubServer'
'Command.Stop.Unknown': '&cSubServers \u00BB There is no server with that name'
'Command.Stop.Invalid': '&cSubServers \u00BB That Server is not a SubServer'
'Command.Stop.Not-Running': '&cSubServers \u00BB That SubServer is not running'
'Command.Terminate': '&aSubServers \u00BB Stopping SubServer'
'Command.Terminate.Unknown': '&cSubServers \u00BB There is no server with that name'
'Command.Terminate.Invalid': '&cSubServers \u00BB That Server is not a SubServer'
'Command.Terminate.Not-Running': '&cSubServers \u00BB That SubServer is not running'
'Command.Command': '&aSubServers \u00BB Sending command to SubServer'
'Command.Command.Unknown': '&cSubServers \u00BB There is no server with that name'
'Command.Command.Invalid': '&cSubServers \u00BB That Server is not a SubServer'
'Command.Command.Not-Running': '&cSubServers \u00BB That SubServer is not running'
'Command.Teleport': '&aSubServers \u00BB Teleporting...'
'Command.Teleport.Offline': '&cSubServers \u00BB There is no player online with that name'
'Command.Teleport.Invalid': '&cSubServers \u00BB There is no server with that name'
'Command.Creator': '&aSubServers \u00BB Creating SubServer'
'Command.Creator.Exists': '&cSubServers \u00BB There is already a SubServer with that name'
'Command.Creator.Unknown-Host': '&cSubServers \u00BB There is no host with that name'
'Command.Creator.Running': '&cSubServers \u00BB The SubCreator instance on that host is already running'
'Command.Creator.Invalid-Type': '&cSubServers \u00BB There is no server type with that name'
'Command.Creator.Invalid-Version': '&cSubServers \u00BB SubCreator cannot create servers before Minecraft 1.8'
'Command.Creator.Invalid-Port': '&cSubServers \u00BB Invalid Port Number'
'Command.Creator.Invalid-Memory': '&cSubServers \u00BB Invalid RAM Amount'
'Interface.Generic.Back': '&cBack'
'Interface.Generic.Back-Arrow': '&e&l<--'
'Interface.Generic.Next-Arrow': '&e&l-->'
'Interface.Generic.Undo': '&6Undo'
'Interface.Generic.Downloading': '&bSubServers \u00BB Downloading - $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.Host-Menu.Title': 'Host Menu'
'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.SubServer-Menu': '&a&lSubServer Menu'
'Interface.Host-Admin.Title': 'Host/$str$'
'Interface.Host-Admin.Creator': '&eCreate a SubServer'
'Interface.Host-Admin.Creator-Busy': '&4SubCreator is already running'
'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 \u00BB Enter a Name for this Server via Chat'
'Interface.Host-Creator.Edit-Name.Exists': '&cSubCreator \u00BB 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 \u00BB Invalid Server Name'
'Interface.Host-Creator.Edit-Name.Invalid-Title': '&eSubCreator\n&cInvalid Server Name'
'Interface.Host-Creator.Edit-Type': 'Change Server Type'
'Interface.Host-Creator.Edit-Type.Title': '&eSubCreator\n&6Enter a Type of Server'
'Interface.Host-Creator.Edit-Type.Message': '&eSubCreator \u00BB Enter a Type of Server via Chat'
'Interface.Host-Creator.Edit-Type.Invalid': '&cSubCreator \u00BB There is no server type with that name'
'Interface.Host-Creator.Edit-Type.Invalid-Title': '&eSubCreator\n&cThere is no server type with that name'
'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 \u00BB Enter a Server Version via Chat'
'Interface.Host-Creator.Edit-Version.Unavailable': '&cSubCreator \u00BB 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 \u00BB Enter a Port Number via Chat'
'Interface.Host-Creator.Edit-Port.Invalid': '&cSubCreator \u00BB Invalid Port Number'
'Interface.Host-Creator.Edit-Port.Invalid-Title': '&eSubCreator\n&cInvalid Port Number'
'Interface.Host-Creator.Edit-RAM': 'Change Server Memory Amount'
'Interface.Host-Creator.Edit-RAM.Title': '&eSubCreator\n&6Enter a RAM Amount'
'Interface.Host-Creator.Edit-RAM.Message': '&eSubCreator \u00BB Enter a RAM Amount via Chat'
'Interface.Host-Creator.Edit-RAM.Invalid': '&cSubCreator \u00BB Invalid Ram Amount'
'Interface.Host-Creator.Edit-RAM.Invalid-Title': '&eSubCreator\n&cInvalid Ram Amount'
'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.SubServer-Menu.Title': 'SubServer Menu'
'Interface.SubServer-Menu.SubServer-Player-Count': '&2$int$ Player(s) Online'
'Interface.SubServer-Menu.SubServer-External': '&7External Server'
'Interface.SubServer-Menu.SubServer-Temporary': '&9Temporary'
'Interface.SubServer-Menu.SubServer-Offline': '&6Offline'
'Interface.SubServer-Menu.SubServer-Disabled': '&4Disabled'
'Interface.SubServer-Menu.No-SubServers': '&c&oThere are No SubServers'
'Interface.SubServer-Menu.Host-Menu': '&b&lHost Menu'
'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 \u00BB 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,6 +0,0 @@
version: 2
modules:
- jenkins://cmd_alert
- jenkins://cmd_find
- jenkins://cmd_send
- jenkins://reconnect_yaml

View File

@ -1,7 +0,0 @@
package net.ME1312.SubServers.Bungee.Library;
import org.json.JSONObject;
public interface JSONCallback {
void run(JSONObject json);
}

View File

@ -1,34 +0,0 @@
package net.ME1312.SubServers.Bungee.Library;
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;
}
}

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,72 +0,0 @@
package net.ME1312.SubServers.Bungee.Library;
import java.io.File;
/**
* Universal File Class
*
* @author ME1312
*/
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,111 +0,0 @@
package net.ME1312.SubServers.Bungee.Library;
import java.io.*;
public final class Util {
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();
}
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();
}
}
public static boolean isException(Runnable runnable) {
try {
runnable.run();
return false;
} catch (Throwable e) {
return true;
}
}
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,224 +0,0 @@
package net.ME1312.SubServers.Bungee.Library.Version;
import java.io.Serializable;
/**
* Version Class
*
* @author ME1312
*/
@SuppressWarnings("serial")
public class Version implements Serializable, Comparable<Version> {
private String string;
/**
* Creates a Version
*
* @param string Version String
*/
public Version(String string) {
this.string = string;
}
/**
* Creates a Version
*
* @param ints Version Numbers (Will be separated with dots)
*/
public Version(Integer... ints) {
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;
}
@Override
public String toString() {
return string;
}
/**
* See if Versions are Equal
*
* @param version Version to Compare
* @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 The version to compare to
*/
public int compareTo(Version version) {
String version1 = this.string;
String version2 = version.toString();
VersionTokenizer tokenizer1 = new VersionTokenizer(version1);
VersionTokenizer tokenizer2 = new VersionTokenizer(version2);
int number1 = 0, number2 = 0;
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;
}
/**
* See if Versions are Equal
*
* @param ver1 Version to Compare
* @param ver2 Version to Compare
* @return
*/
public static boolean isEqual(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) {
String version1 = ver1.toString();
String version2 = ver2.toString();
VersionTokenizer tokenizer1 = new VersionTokenizer(version1);
VersionTokenizer tokenizer2 = new VersionTokenizer(version2);
int number1 = 0, number2 = 0;
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;
}
}

View File

@ -1,64 +0,0 @@
package net.ME1312.SubServers.Bungee.Library.Version;
public final class VersionTokenizer {
private final String _versionString;
private final int _length;
private int _position;
private int _number;
private String _suffix;
private boolean _hasValue;
protected int getNumber() {
return _number;
}
protected String getSuffix() {
return _suffix;
}
protected boolean hasValue() {
return _hasValue;
}
protected VersionTokenizer(String versionString) {
if (versionString == null)
throw new IllegalArgumentException("versionString is null");
_versionString = versionString;
_length = versionString.length();
}
protected boolean MoveNext() {
_number = 0;
_suffix = "";
_hasValue = false;
// No more characters
if (_position >= _length)
return false;
_hasValue = true;
while (_position < _length) {
char c = _versionString.charAt(_position);
if (c < '0' || c > '9') break;
_number = _number * 10 + (c - '0');
_position++;
}
int suffixStart = _position;
while (_position < _length) {
char c = _versionString.charAt(_position);
if (c == '.') break;
_position++;
}
_suffix = _versionString.substring(suffixStart, _position);
if (_position < _length) _position++;
return true;
}
}

View File

@ -1,183 +0,0 @@
package net.ME1312.SubServers.Bungee.Network;
import net.ME1312.SubServers.Bungee.Library.Exception.IllegalPacketException;
import net.ME1312.SubServers.Bungee.Network.Packet.PacketAuthorization;
import net.ME1312.SubServers.Bungee.SubPlugin;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.util.Timer;
import java.util.TimerTask;
/**
* Network Client Class
*
* @author ME1312
*/
public final class Client {
private Socket socket;
private InetSocketAddress address;
private ClientHandler handler;
private PrintWriter writer;
private Timer authorized;
private SubPlugin plugin;
private Client instance;
/**
* Network Client
*
* @param plugin SubPlugin
* @param client Socket to Bind
*/
public Client(SubPlugin plugin, Socket client) throws IOException {
this.plugin = plugin;
socket = client;
writer = new PrintWriter(client.getOutputStream(), true);
address = new InetSocketAddress(client.getInetAddress(), client.getPort());
instance = this;
authorized = new Timer("auth" + client.getRemoteSocketAddress().toString());
authorized.schedule(new TimerTask() {
@Override
public void run() {
if (!socket.isClosed()) try {
plugin.subdata.removeClient(instance);
} catch (IOException e) {
e.printStackTrace();
}
}
}, 15000);
loop();
}
/**
* Network Loop
*/
protected void loop() {
new Thread(() -> {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String input;
while ((input = in.readLine()) != null) {
try {
JSONObject json = new JSONObject(input);
PacketIn packet = SubDataServer.decodePacket(json);
if (authorized == null || packet instanceof PacketAuthorization) {
try {
packet.execute(instance, (json.keySet().contains("c")) ? json.getJSONObject("c") : null);
} catch (Exception e) {
new InvocationTargetException(e, "Exception while executing PacketIn").printStackTrace();
}
}
} catch (IllegalPacketException e) {
e.printStackTrace();
} catch (JSONException e) {
new IllegalPacketException("Unknown Packet Format: " + input).printStackTrace();
}
}
try {
plugin.subdata.removeClient(instance);
} catch (IOException e1) {
e1.printStackTrace();
}
} catch (Exception e) {
if (!(e instanceof SocketException)) e.printStackTrace();
try {
plugin.subdata.removeClient(instance);
} catch (IOException e1) {
e1.printStackTrace();
}
}
}).start();
}
/**
* Authorize Connection
*/
public void authorize() {
if (authorized != null) {
authorized.cancel();
System.out.println("SubData > " + socket.getRemoteSocketAddress().toString() + " logged in");
}
authorized = null;
}
/**
* Send Packet to Client
*
* @param packet Packet to send
*/
public void sendPacket(PacketOut packet) {
try {
writer.println(SubDataServer.encodePacket(packet));
} catch (IllegalPacketException e) {
e.printStackTrace();
}
}
/**
* Get Raw Connection
*
* @return Socket
*/
public Socket getConnection() {
return socket;
}
/**
* Get Remote Address
*
* @return Address
*/
public InetSocketAddress getAddress() {
return address;
}
/**
* If the connection is authorized
*
* @return Authorization Status
*/
public boolean isAuthorized() {
return authorized == null;
}
/**
* Gets the Linked Handler
*
* @return Handler
*/
public ClientHandler getHandler() {
return handler;
}
/**
* Sets the Handler
* <b>Warning:</b> This method should only be called by ClientHandler methods
*
* @see ClientHandler
* @param obj Handler
*/
public void setHandler(ClientHandler obj) {
handler = obj;
}
/**
* Disconnects the Client
*
* @throws IOException
*/
protected void disconnect() throws IOException {
if (!socket.isClosed()) getConnection().close();
if (handler != null) handler.linkSubDataClient(null);
handler = null;
}
}

View File

@ -1,22 +0,0 @@
package net.ME1312.SubServers.Bungee.Network;
/**
* Client Handler Layout Class
*
* @author ME1312
*/
public interface ClientHandler {
/**
* Gets the SubData Client
*
* @return SubData Client (or null if not linked)
*/
Client getSubDataClient();
/**
* Link a SubData Client to this Object
*
* @param client Client to Link
*/
void linkSubDataClient(Client client);
}

View File

@ -0,0 +1,90 @@
package net.ME1312.SubServers.Bungee.Network.Packet;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubData.Server.Protocol.PacketObjectIn;
import net.ME1312.SubData.Server.Protocol.PacketObjectOut;
import net.ME1312.SubData.Server.SubDataClient;
import net.ME1312.SubServers.Bungee.SubProxy;
import net.md_5.bungee.api.ChatColor;
import java.net.InetAddress;
import java.util.Map;
import java.util.UUID;
/**
* Add Server Packet
*/
public class PacketAddServer implements PacketObjectIn<Integer>, PacketObjectOut<Integer> {
private SubProxy plugin;
private int response;
private int status;
private UUID tracker;
/**
* New PacketAddServer (In)
*
* @param plugin SubPlugin
*/
public PacketAddServer(SubProxy plugin) {
this.plugin = Util.nullpo(plugin);
}
/**
* New PacketEditServer (Out)
*
* @param response Response ID
* @param tracker Receiver ID
*/
public PacketAddServer(int response, UUID tracker) {
this.response = response;
this.tracker = tracker;
}
@Override
public ObjectMap<Integer> send(SubDataClient client) {
ObjectMap<Integer> json = new ObjectMap<Integer>();
if (tracker != null) json.set(0x0000, tracker);
json.set(0x0001, response);
json.set(0x0002, status);
return json;
}
@SuppressWarnings("unchecked")
@Override
public void receive(SubDataClient client, ObjectMap<Integer> data) {
UUID tracker = (data.contains(0x0000)?data.getUUID(0x0000):null);
try {
String name = data.getString(0x0001);
boolean subserver = data.getBoolean(0x0002);
ObjectMap<String> opt = new ObjectMap<>((Map<String, ?>)data.getObject(0x0003));
UUID player = (data.contains(0x0004)?data.getUUID(0x0004):null);
if (plugin.api.getServers().containsKey(name.toLowerCase())) {
client.sendPacket(new PacketAddServer(3, tracker));
} else {
if (!subserver) {
if (plugin.api.addServer(player, name, InetAddress.getByName(opt.getString("address").split(":")[0]), Integer.parseInt(opt.getString("address").split(":")[1]),
ChatColor.translateAlternateColorCodes('&', Util.unescapeJavaString(opt.getString("motd"))), opt.getBoolean("hidden"), opt.getBoolean("restricted")) != null) {
client.sendPacket(new PacketAddServer(0, tracker));
} else {
client.sendPacket(new PacketAddServer(1, tracker));
}
} else if (!plugin.api.getHosts().containsKey(opt.getString("host").toLowerCase())) {
client.sendPacket(new PacketAddServer(4, tracker));
} else {
if (plugin.api.getHost(opt.getString("host")).addSubServer(player, name, opt.getBoolean("enabled"), opt.getInt("port"), ChatColor.translateAlternateColorCodes('&', Util.unescapeJavaString(opt.getString("motd"))),
opt.getBoolean("log"), opt.getString("dir"), opt.getString("exec"), opt.getString("stop-cmd"), opt.getBoolean("hidden"), opt.getBoolean("restricted")) != null) {
client.sendPacket(new PacketAddServer(0, tracker));
} else {
client.sendPacket(new PacketAddServer(1, tracker));
}
}
}
} catch (Throwable e) {
client.sendPacket(new PacketAddServer(2, tracker));
e.printStackTrace();
}
}
}

View File

@ -1,50 +0,0 @@
package net.ME1312.SubServers.Bungee.Network.Packet;
import net.ME1312.SubServers.Bungee.Library.Version.Version;
import net.ME1312.SubServers.Bungee.Network.Client;
import net.ME1312.SubServers.Bungee.Network.PacketIn;
import net.ME1312.SubServers.Bungee.Network.PacketOut;
import net.ME1312.SubServers.Bungee.SubPlugin;
import org.json.JSONObject;
public class PacketAuthorization implements PacketIn, PacketOut {
private SubPlugin plugin;
private int response;
private String message;
public PacketAuthorization(SubPlugin plugin) {
this.plugin = plugin;
}
public PacketAuthorization(int response, String message) {
this.response = response;
this.message = message;
}
@Override
public JSONObject generate() {
JSONObject json = new JSONObject();
json.put("r", response);
json.put("m", message);
return json;
}
@Override
public void execute(Client client, JSONObject data) {
try {
if (data.getString("password").equals(plugin.config.get().getSection("Settings").getSection("SubData").getRawString("Password"))) {
client.authorize();
client.sendPacket(new PacketAuthorization(0, "Successfully Logged in"));
} else {
client.sendPacket(new PacketAuthorization(2, "Invalid Password"));
}
} catch (Exception e) {
client.sendPacket(new PacketAuthorization(1, e.getClass().getCanonicalName() + ": " + e.getMessage()));
}
}
@Override
public Version getVersion() {
return new Version("2.11.0a");
}
}

View File

@ -0,0 +1,55 @@
package net.ME1312.SubServers.Bungee.Network.Packet;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Util;
import net.ME1312.SubData.Server.Protocol.PacketObjectIn;
import net.ME1312.SubData.Server.Protocol.PacketObjectOut;
import net.ME1312.SubData.Server.SubDataClient;
import java.util.HashMap;
import java.util.UUID;
import java.util.function.Consumer;
/**
* Check Permission Packet
*/
public class PacketCheckPermission implements PacketObjectIn<Integer>, PacketObjectOut<Integer> {
static HashMap<UUID, Consumer<Boolean>[]> callbacks = new HashMap<UUID, Consumer<Boolean>[]>();
private UUID player;
private String permission;
private UUID tracker;
/**
* New PacketCheckPermission (In)
*/
public PacketCheckPermission() {}
/**
* New PacketCheckPermission (Out)
*
* @param player Player to check on
* @param permission Permission to check
* @param callback Callbacks
*/
@SafeVarargs
public PacketCheckPermission(UUID player, String permission, Consumer<Boolean>... callback) {
this.player = player;
this.permission = permission;
this.tracker = Util.getNew(callbacks.keySet(), UUID::randomUUID);
callbacks.put(tracker, callback);
}
@Override
public ObjectMap<Integer> send(SubDataClient client) throws Throwable {
ObjectMap<Integer> data = new ObjectMap<Integer>();
data.set(0x0000, tracker);
data.set(0x0001, player);
data.set(0x0002, permission);
return data;
}
@Override
public void receive(SubDataClient client, ObjectMap<Integer> data) throws Throwable {
client.sendPacket(new PacketCheckPermissionResponse(data.getUUID(0x0001), data.getString(0x0002), (data.contains(0x0000))?data.getUUID(0x0000):null));
}
}

View File

@ -0,0 +1,53 @@
package net.ME1312.SubServers.Bungee.Network.Packet;
import net.ME1312.Galaxi.Library.Map.ObjectMap;
import net.ME1312.Galaxi.Library.Try;
import net.ME1312.SubData.Server.Protocol.PacketObjectIn;
import net.ME1312.SubData.Server.Protocol.PacketObjectOut;
import net.ME1312.SubData.Server.SubDataClient;
import net.md_5.bungee.api.ProxyServer;
import java.util.UUID;
import java.util.function.Consumer;
import static net.ME1312.SubServers.Bungee.Network.Packet.PacketCheckPermission.callbacks;
/**
* Check Permission Response Packet
*/
public class PacketCheckPermissionResponse implements PacketObjectIn<Integer>, PacketObjectOut<Integer> {
private boolean result;
private UUID tracker;
/**
* New PacketCheckPermissionResponse (In)
*/
public PacketCheckPermissionResponse() {}
/**
* New PacketCheckPermissionResponse (Out)
*
* @param player Player to check on
* @param permission Permission to check
* @param tracker Receiver ID
*/
public PacketCheckPermissionResponse(UUID player, String permission, UUID tracker) {
this.result = Try.all.get(() -> ProxyServer.getInstance().getPlayer(player).hasPermission(permission), false);
this.tracker = tracker;
}
@Override
public ObjectMap<Integer> send(SubDataClient client) throws Throwable {
ObjectMap<Integer> data = new ObjectMap<Integer>();
data.set(0x0000, tracker);
data.set(0x0001, result);
return data;
}
@Override
public void receive(SubDataClient client, ObjectMap<Integer> data) throws Throwable {
for (Consumer<Boolean> callback : callbacks.remove(data.getUUID(0x0000))) callback.accept(data.getBoolean(0x0001));
}
}

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